mirror of
https://github.com/encounter/aurora.git
synced 2026-07-09 18:19:33 -07:00
Merge branch 'main' into pipeline-cache
# Conflicts: # cmake/aurora_gx.cmake # lib/gfx/common.cpp
This commit is contained in:
+1
-1
@@ -111,7 +111,7 @@ add_library(aurora::shared ALIAS aurora_shared)
|
||||
target_compile_definitions(aurora_shared PUBLIC AURORA TARGET_PC)
|
||||
target_include_directories(aurora_shared PUBLIC include)
|
||||
target_link_libraries(aurora_shared PUBLIC ${AURORA_SDL3_TARGET} fmt::fmt xxhash)
|
||||
target_link_libraries(aurora_shared PRIVATE absl::btree absl::flat_hash_map)
|
||||
target_link_libraries(aurora_shared PRIVATE absl::btree absl::flat_hash_map TracyClient)
|
||||
|
||||
if (AURORA_ENABLE_DVD)
|
||||
target_sources(aurora_shared PRIVATE lib/dolphin/dvd/dvd.cpp)
|
||||
|
||||
@@ -9,7 +9,7 @@ add_library(aurora::core ALIAS aurora_core)
|
||||
target_compile_definitions(aurora_core PUBLIC AURORA TARGET_PC)
|
||||
target_include_directories(aurora_core PUBLIC include)
|
||||
target_link_libraries(aurora_core PUBLIC ${AURORA_SDL3_TARGET} fmt::fmt xxhash)
|
||||
target_link_libraries(aurora_core PRIVATE absl::btree absl::flat_hash_map sqlite3)
|
||||
target_link_libraries(aurora_core PRIVATE absl::btree absl::flat_hash_map sqlite3 TracyClient)
|
||||
if (AURORA_ENABLE_GX AND AURORA_CACHE_USE_ZSTD)
|
||||
target_compile_definitions(aurora_core PRIVATE AURORA_CACHE_USE_ZSTD)
|
||||
target_link_libraries(aurora_core PRIVATE libzstd_static)
|
||||
|
||||
@@ -36,7 +36,7 @@ add_library(aurora_gx STATIC
|
||||
add_library(aurora::gx ALIAS aurora_gx)
|
||||
|
||||
target_link_libraries(aurora_gx PUBLIC aurora::core xxhash)
|
||||
target_link_libraries(aurora_gx PRIVATE absl::btree absl::flat_hash_map sqlite3)
|
||||
target_link_libraries(aurora_gx PRIVATE absl::btree absl::flat_hash_map sqlite3 TracyClient)
|
||||
if (EMSCRIPTEN)
|
||||
target_link_options(aurora_gx PUBLIC -sUSE_WEBGPU=1 -sASYNCIFY -sEXIT_RUNTIME)
|
||||
target_compile_definitions(aurora_gx PRIVATE ENABLE_BACKEND_WEBGPU)
|
||||
|
||||
Vendored
+20
@@ -161,3 +161,23 @@ if (AURORA_ENABLE_GX)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (NOT TARGET TracyClient)
|
||||
message(STATUS "aurora: Fetching Tracy")
|
||||
|
||||
# Default to off, users can enable the cache variable if they want to use it.
|
||||
set(TRACY_ENABLE OFF CACHE BOOL "Enable Tracy profiling")
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
tracy
|
||||
URL https://github.com/wolfpld/tracy/archive/refs/tags/v0.13.1.tar.gz
|
||||
URL_HASH SHA256=d4efc50ebcb0bfcfdbba148995aeb75044c0d80f5d91223aebfaa8fa9e563d2b
|
||||
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
|
||||
)
|
||||
FetchContent_MakeAvailable(tracy)
|
||||
|
||||
if (NOT TARGET TracyClient)
|
||||
message(FATAL_ERROR "Failed to make TracyClient available")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <SDL3/SDL_filesystem.h>
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
namespace aurora {
|
||||
AuroraConfig g_config;
|
||||
uint32_t g_sdlCustomEventsStart;
|
||||
@@ -167,6 +169,7 @@ void shutdown() noexcept {
|
||||
}
|
||||
|
||||
const AuroraEvent* update() noexcept {
|
||||
ZoneScoped;
|
||||
if (g_initialFrame) {
|
||||
g_initialFrame = false;
|
||||
input::initialize();
|
||||
@@ -175,6 +178,7 @@ const AuroraEvent* update() noexcept {
|
||||
}
|
||||
|
||||
bool begin_frame() noexcept {
|
||||
ZoneScoped;
|
||||
#ifdef AURORA_ENABLE_GX
|
||||
if (!g_surface) {
|
||||
webgpu::refresh_surface(true);
|
||||
@@ -205,6 +209,7 @@ bool begin_frame() noexcept {
|
||||
Log.error("Failed to get surface texture: {}", magic_enum::enum_name(surfaceTexture.status));
|
||||
return false;
|
||||
}
|
||||
|
||||
imgui::new_frame(window::get_window_size());
|
||||
gfx::begin_frame();
|
||||
#endif
|
||||
@@ -212,6 +217,7 @@ bool begin_frame() noexcept {
|
||||
}
|
||||
|
||||
void end_frame() noexcept {
|
||||
ZoneScoped;
|
||||
#ifdef AURORA_ENABLE_GX
|
||||
gx::fifo::drain();
|
||||
const auto encoderDescriptor = wgpu::CommandEncoderDescriptor{
|
||||
@@ -258,6 +264,23 @@ void end_frame() noexcept {
|
||||
Log.warn("Surface present failed: {}", static_cast<int>(presentStatus));
|
||||
}
|
||||
g_currentView = {};
|
||||
|
||||
TracyPlotConfig("aurora: lastVertSize", tracy::PlotFormatType::Memory, false, true, 0);
|
||||
TracyPlotConfig("aurora: lastUniformSize", tracy::PlotFormatType::Memory, false, true, 0);
|
||||
TracyPlotConfig("aurora: lastIndexSize", tracy::PlotFormatType::Memory, false, true, 0);
|
||||
TracyPlotConfig("aurora: lastStorageSize", tracy::PlotFormatType::Memory, false, true, 0);
|
||||
TracyPlotConfig("aurora: lastTextureUploadSize", tracy::PlotFormatType::Memory, false, true, 0);
|
||||
|
||||
TracyPlot("aurora: queuedPipelines", static_cast<int64_t>(gfx::g_stats.queuedPipelines));
|
||||
TracyPlot("aurora: createdPipelines", static_cast<int64_t>(gfx::g_stats.createdPipelines));
|
||||
TracyPlot("aurora: drawCallCount", static_cast<int64_t>(gfx::g_stats.drawCallCount));
|
||||
TracyPlot("aurora: mergedDrawCallCount", static_cast<int64_t>(gfx::g_stats.mergedDrawCallCount));
|
||||
TracyPlot("aurora: lastVertSize", static_cast<int64_t>(gfx::g_stats.lastVertSize));
|
||||
TracyPlot("aurora: lastUniformSize", static_cast<int64_t>(gfx::g_stats.lastUniformSize));
|
||||
TracyPlot("aurora: lastIndexSize", static_cast<int64_t>(gfx::g_stats.lastIndexSize));
|
||||
TracyPlot("aurora: lastStorageSize", static_cast<int64_t>(gfx::g_stats.lastStorageSize));
|
||||
TracyPlot("aurora: lastTextureUploadSize", static_cast<int64_t>(gfx::g_stats.lastTextureUploadSize));
|
||||
|
||||
#endif
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -281,10 +281,6 @@ void GXFlush() {
|
||||
if (__gx->dirtyState) {
|
||||
__GXSetDirtyState();
|
||||
}
|
||||
for (u32 i = 32; i > 0; i--) {
|
||||
GX_WRITE_U8(0);
|
||||
}
|
||||
// PPCSync();
|
||||
}
|
||||
|
||||
void GXPixModeSync() {
|
||||
|
||||
@@ -8,11 +8,14 @@
|
||||
|
||||
#include <absl/container/flat_hash_map.h>
|
||||
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
using namespace aurora::gfx;
|
||||
|
||||
extern "C" {
|
||||
void GXInitTexObj(GXTexObj* obj_, const void* data, u16 width, u16 height, GXTexFmt format, GXTexWrapMode wrapS,
|
||||
GXTexWrapMode wrapT, GXBool mipmap) {
|
||||
ZoneScopedS(3);
|
||||
if (reinterpret_cast<GXTexObj_*>(obj_)->ref)
|
||||
Log.fatal("Texture object already has a reference");
|
||||
memset(obj_, 0, sizeof(GXTexObj));
|
||||
@@ -40,6 +43,7 @@ void GXInitTexObj(GXTexObj* obj_, const void* data, u16 width, u16 height, GXTex
|
||||
|
||||
void GXInitTexObjCI(GXTexObj* obj_, const void* data, u16 width, u16 height, GXCITexFmt format, GXTexWrapMode wrapS,
|
||||
GXTexWrapMode wrapT, GXBool mipmap, u32 tlut) {
|
||||
ZoneScopedS(3);
|
||||
if (reinterpret_cast<GXTexObj_*>(obj_)->ref)
|
||||
Log.fatal("Texture object already has a reference");
|
||||
memset(obj_, 0, sizeof(GXTexObj));
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "clear.hpp"
|
||||
|
||||
#include "../webgpu/gpu.hpp"
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
namespace {
|
||||
wgpu::ColorWriteMask clear_write_mask(bool clearColor, bool clearAlpha) {
|
||||
@@ -21,6 +22,7 @@ using webgpu::g_device;
|
||||
using webgpu::g_graphicsConfig;
|
||||
|
||||
wgpu::RenderPipeline create_pipeline(const PipelineConfig& config) {
|
||||
ZoneScoped;
|
||||
wgpu::ShaderSourceWGSL sourceDescriptor{};
|
||||
sourceDescriptor.code = R"""(
|
||||
struct VertexOutput {
|
||||
|
||||
+29
-19
@@ -16,6 +16,8 @@
|
||||
#include <absl/container/flat_hash_map.h>
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
namespace aurora::gfx {
|
||||
static Module Log("aurora::gfx");
|
||||
|
||||
@@ -72,11 +74,11 @@ namespace aurora {
|
||||
// we create specialized methods to handle them. Note that these are highly dependent on
|
||||
// the structure definition, which could easily change with Dawn updates.
|
||||
template <>
|
||||
inline HashType xxh3_hash(const wgpu::BindGroupDescriptor& input, HashType seed) {
|
||||
constexpr auto offset = offsetof(wgpu::BindGroupDescriptor, layout); // skip nextInChain, label
|
||||
inline HashType xxh3_hash(const WGPUBindGroupDescriptor& input, HashType seed) {
|
||||
constexpr auto offset = offsetof(WGPUBindGroupDescriptor, layout); // skip nextInChain, label
|
||||
const auto hash = xxh3_hash_s(reinterpret_cast<const u8*>(&input) + offset,
|
||||
sizeof(wgpu::BindGroupDescriptor) - offset - sizeof(void*) /* skip entries */, seed);
|
||||
return xxh3_hash_s(input.entries, sizeof(wgpu::BindGroupEntry) * input.entryCount, hash);
|
||||
sizeof(WGPUBindGroupDescriptor) - offset - sizeof(void*) /* skip entries */, seed);
|
||||
return xxh3_hash_s(input.entries, sizeof(WGPUBindGroupEntry) * input.entryCount, hash);
|
||||
}
|
||||
template <>
|
||||
inline HashType xxh3_hash(const wgpu::SamplerDescriptor& input, HashType seed) {
|
||||
@@ -222,7 +224,7 @@ void push_draw_command(clear::DrawData data) {
|
||||
}
|
||||
|
||||
template <>
|
||||
PipelineRef pipeline_ref(clear::PipelineConfig config) {
|
||||
PipelineRef pipeline_ref(const clear::PipelineConfig& config) {
|
||||
return find_pipeline(ShaderType::Clear, config, [=] { return create_pipeline(config); });
|
||||
}
|
||||
|
||||
@@ -349,6 +351,7 @@ static OffscreenCacheEntry get_offscreen_textures(uint32_t width, uint32_t heigh
|
||||
}
|
||||
|
||||
void begin_offscreen(uint32_t width, uint32_t height) {
|
||||
ZoneScoped;
|
||||
CHECK(g_currentRenderPass != UINT32_MAX, "begin_offscreen called outside of a frame");
|
||||
|
||||
// If the current EFB pass has no resolve target, its output is unobservable.
|
||||
@@ -391,6 +394,7 @@ void begin_offscreen(uint32_t width, uint32_t height) {
|
||||
}
|
||||
|
||||
void end_offscreen() {
|
||||
ZoneScoped;
|
||||
CHECK(g_inOffscreen, "end_offscreen called without begin_offscreen");
|
||||
|
||||
g_inOffscreen = false;
|
||||
@@ -419,7 +423,7 @@ void push_draw_command(gx::DrawData data) {
|
||||
}
|
||||
|
||||
template <>
|
||||
PipelineRef pipeline_ref(gx::PipelineConfig config) {
|
||||
PipelineRef pipeline_ref(const gx::PipelineConfig& config) {
|
||||
return find_pipeline(ShaderType::GX, config, [=] { return create_pipeline(config); });
|
||||
}
|
||||
|
||||
@@ -504,8 +508,12 @@ void map_staging_buffer() {
|
||||
}
|
||||
|
||||
void begin_frame() {
|
||||
while (!bufferMapped) {
|
||||
g_instance.ProcessEvents();
|
||||
ZoneScoped;
|
||||
{
|
||||
ZoneScopedN("Wait for buffer map");
|
||||
while (!bufferMapped) {
|
||||
g_instance.ProcessEvents();
|
||||
}
|
||||
}
|
||||
size_t bufferOffset = 0;
|
||||
const auto& stagingBuf = g_stagingBuffers[currentStagingBuffer];
|
||||
@@ -537,13 +545,14 @@ void begin_frame() {
|
||||
}
|
||||
|
||||
void end_frame(const wgpu::CommandEncoder& cmd) {
|
||||
ZoneScoped;
|
||||
ASSERT(!g_inOffscreen, "end_frame called while offscreen rendering is active");
|
||||
uint64_t bufferOffset = 0;
|
||||
const auto writeBuffer = [&](ByteBuffer& buf, wgpu::Buffer& out, uint64_t size, std::string_view label) {
|
||||
const auto writeSize = buf.size(); // Only need to copy this many bytes
|
||||
if (writeSize > 0) {
|
||||
cmd.CopyBufferToBuffer(g_stagingBuffers[currentStagingBuffer], bufferOffset, out, 0, ALIGN(writeSize, 4));
|
||||
buf.clear();
|
||||
cmd.CopyBufferToBuffer(g_stagingBuffers[currentStagingBuffer], bufferOffset, out, 0, AURORA_ALIGN(writeSize, 4));
|
||||
buf.release();
|
||||
}
|
||||
bufferOffset += size;
|
||||
return writeSize;
|
||||
@@ -561,7 +570,7 @@ void end_frame(const wgpu::CommandEncoder& cmd) {
|
||||
.layout =
|
||||
wgpu::TexelCopyBufferLayout{
|
||||
.offset = item.layout.offset + bufferOffset,
|
||||
.bytesPerRow = ALIGN(item.layout.bytesPerRow, 256),
|
||||
.bytesPerRow = AURORA_ALIGN(item.layout.bytesPerRow, 256),
|
||||
.rowsPerImage = item.layout.rowsPerImage,
|
||||
},
|
||||
.buffer = g_stagingBuffers[currentStagingBuffer],
|
||||
@@ -569,7 +578,7 @@ void end_frame(const wgpu::CommandEncoder& cmd) {
|
||||
cmd.CopyBufferToTexture(&buf, &item.tex, &item.size);
|
||||
}
|
||||
g_textureUploads.clear();
|
||||
g_textureUpload.clear();
|
||||
g_textureUpload.release();
|
||||
}
|
||||
currentStagingBuffer = (currentStagingBuffer + 1) % g_stagingBuffers.size();
|
||||
map_staging_buffer();
|
||||
@@ -584,6 +593,7 @@ void end_frame(const wgpu::CommandEncoder& cmd) {
|
||||
uint32_t current_frame() noexcept { return g_frameIndex; }
|
||||
|
||||
void render(wgpu::CommandEncoder& cmd) {
|
||||
ZoneScoped;
|
||||
for (u32 i = 0; i < g_renderPasses.size(); ++i) {
|
||||
const auto& passInfo = g_renderPasses[i];
|
||||
for (const auto& conv : passInfo.paletteConvs) {
|
||||
@@ -807,7 +817,7 @@ Range push_storage(const uint8_t* data, size_t length) {
|
||||
}
|
||||
Range push_texture_data(const uint8_t* data, size_t length, u32 bytesPerRow, u32 rowsPerImage) {
|
||||
// For CopyBufferToTexture, we need an alignment of 256 per row (see Dawn kTextureBytesPerRowAlignment)
|
||||
const auto copyBytesPerRow = ALIGN(bytesPerRow, 256);
|
||||
const auto copyBytesPerRow = AURORA_ALIGN(bytesPerRow, 256);
|
||||
const auto range = map(g_textureUpload, copyBytesPerRow * rowsPerImage, 0);
|
||||
u8* dst = g_textureUpload.data() + range.offset;
|
||||
for (u32 i = 0; i < rowsPerImage; ++i) {
|
||||
@@ -835,21 +845,21 @@ std::pair<ByteBuffer, Range> map_storage(size_t length) {
|
||||
}
|
||||
|
||||
// TODO: should we avoid caching bind groups altogether?
|
||||
BindGroupRef bind_group_ref(const wgpu::BindGroupDescriptor& descriptor) {
|
||||
BindGroupRef bind_group_ref(const WGPUBindGroupDescriptor& descriptor) {
|
||||
#ifdef EMSCRIPTEN
|
||||
const auto bg = g_device.CreateBindGroup(&descriptor);
|
||||
const auto bg = wgpuDeviceCreateBindGroup(g_device.Get(), &descriptor);
|
||||
BindGroupRef id = reinterpret_cast<BindGroupRef>(bg.Get());
|
||||
g_cachedBindGroups.try_emplace(id, bg);
|
||||
#else
|
||||
const auto id = xxh3_hash(descriptor);
|
||||
if (!g_cachedBindGroups.contains(id)) {
|
||||
g_cachedBindGroups.try_emplace(id, g_device.CreateBindGroup(&descriptor));
|
||||
g_cachedBindGroups.try_emplace(id, wgpuDeviceCreateBindGroup(g_device.Get(), &descriptor));
|
||||
}
|
||||
#endif
|
||||
return id;
|
||||
}
|
||||
|
||||
wgpu::BindGroup find_bind_group(BindGroupRef id) {
|
||||
wgpu::BindGroup& find_bind_group(BindGroupRef id) {
|
||||
#ifdef EMSCRIPTEN
|
||||
return g_cachedBindGroups[id];
|
||||
#else
|
||||
@@ -859,7 +869,7 @@ wgpu::BindGroup find_bind_group(BindGroupRef id) {
|
||||
#endif
|
||||
}
|
||||
|
||||
wgpu::Sampler sampler_ref(const wgpu::SamplerDescriptor& descriptor) {
|
||||
wgpu::Sampler& sampler_ref(const wgpu::SamplerDescriptor& descriptor) {
|
||||
const auto id = xxh3_hash(descriptor);
|
||||
auto it = g_cachedSamplers.find(id);
|
||||
if (it == g_cachedSamplers.end()) {
|
||||
@@ -868,7 +878,7 @@ wgpu::Sampler sampler_ref(const wgpu::SamplerDescriptor& descriptor) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
uint32_t align_uniform(uint32_t value) { return ALIGN(value, g_cachedLimits.minUniformBufferOffsetAlignment); }
|
||||
uint32_t align_uniform(uint32_t value) { return AURORA_ALIGN(value, g_cachedLimits.minUniformBufferOffsetAlignment); }
|
||||
|
||||
void insert_debug_marker(std::string label) {
|
||||
#if defined(AURORA_GFX_DEBUG_GROUPS)
|
||||
|
||||
+13
-5
@@ -109,7 +109,7 @@ public:
|
||||
m_length += size;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
void release() {
|
||||
if (m_data != nullptr && m_owned) {
|
||||
free(m_data);
|
||||
}
|
||||
@@ -119,6 +119,10 @@ public:
|
||||
m_owned = true;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
void reserve_extra(size_t size) { resize(m_length + size, true); }
|
||||
|
||||
private:
|
||||
@@ -141,6 +145,10 @@ private:
|
||||
if (!m_owned) {
|
||||
abort();
|
||||
}
|
||||
// Exponential expansion to avoid O(n^2) time complexity.
|
||||
if (size < m_capacity * 2) {
|
||||
size = m_capacity * 2;
|
||||
}
|
||||
m_data = static_cast<uint8_t*>(realloc(m_data, size));
|
||||
if (zeroed) {
|
||||
memset(m_data + m_capacity, 0, size - m_capacity);
|
||||
@@ -272,13 +280,13 @@ template <typename DrawData>
|
||||
DrawData* get_last_draw_command();
|
||||
|
||||
template <typename PipelineConfig>
|
||||
PipelineRef pipeline_ref(PipelineConfig config);
|
||||
PipelineRef pipeline_ref(const PipelineConfig& config);
|
||||
bool bind_pipeline(PipelineRef ref, const wgpu::RenderPassEncoder& pass);
|
||||
|
||||
BindGroupRef bind_group_ref(const wgpu::BindGroupDescriptor& descriptor);
|
||||
wgpu::BindGroup find_bind_group(BindGroupRef id);
|
||||
BindGroupRef bind_group_ref(const WGPUBindGroupDescriptor& descriptor);
|
||||
wgpu::BindGroup& find_bind_group(BindGroupRef id);
|
||||
|
||||
wgpu::Sampler sampler_ref(const wgpu::SamplerDescriptor& descriptor);
|
||||
wgpu::Sampler& sampler_ref(const wgpu::SamplerDescriptor& descriptor);
|
||||
|
||||
uint32_t align_uniform(uint32_t value);
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include <magic_enum.hpp>
|
||||
#include <webgpu/webgpu_cpp.h>
|
||||
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
namespace aurora::gfx {
|
||||
using webgpu::g_device;
|
||||
using webgpu::g_queue;
|
||||
@@ -141,6 +143,7 @@ static bool setup_swizzle(wgpu::TextureComponentSwizzleDescriptor& swizzle, u32
|
||||
|
||||
TextureHandle new_dynamic_texture_2d(uint32_t width, uint32_t height, uint32_t mips, u32 gxFormat,
|
||||
const char* label) noexcept {
|
||||
ZoneScopedS(3);
|
||||
const auto wgpuFormat = to_wgpu(gxFormat);
|
||||
const wgpu::Extent3D size{
|
||||
.width = width,
|
||||
|
||||
+102
-39
@@ -14,6 +14,8 @@
|
||||
#include "dolphin/gx/GXAurora.h"
|
||||
#include <limits>
|
||||
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
namespace aurora::gx::fifo {
|
||||
static Module Log("aurora::gx::fifo");
|
||||
|
||||
@@ -104,20 +106,35 @@ static constexpr u8 CP_OPCODE_MASK = GX_OPCODE_MASK;
|
||||
static constexpr u8 CP_VAT_MASK = GX_VAT_MASK;
|
||||
|
||||
// Read helpers for big/little endian
|
||||
#if _MSC_VER
|
||||
template<typename T>
|
||||
__forceinline // Yes, this was necessary.
|
||||
inline T unaligned_load(const T* ptr) {
|
||||
return *static_cast<const __unaligned T*>(ptr);
|
||||
}
|
||||
#else
|
||||
template<typename T>
|
||||
inline T unaligned_load(const T* ptr) {
|
||||
T copy;
|
||||
memcpy(©, ptr, sizeof(T));
|
||||
return copy;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline u16 read_u16(const u8* ptr, bool bigEndian) {
|
||||
const u16 val = unaligned_load(reinterpret_cast<const u16*>(ptr));
|
||||
if (bigEndian) {
|
||||
return static_cast<u16>(ptr[0] << 8 | ptr[1]);
|
||||
return bswap(val);
|
||||
}
|
||||
return static_cast<u16>(ptr[1] << 8 | ptr[0]);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline u32 read_u32(const u8* ptr, bool bigEndian) {
|
||||
const u32 val = unaligned_load(reinterpret_cast<const u32*>(ptr));
|
||||
if (bigEndian) {
|
||||
return static_cast<u32>(ptr[0]) << 24 | static_cast<u32>(ptr[1]) << 16 | static_cast<u32>(ptr[2]) << 8 |
|
||||
static_cast<u32>(ptr[3]);
|
||||
return bswap(val);
|
||||
}
|
||||
return static_cast<u32>(ptr[3]) << 24 | static_cast<u32>(ptr[2]) << 16 | static_cast<u32>(ptr[1]) << 8 |
|
||||
static_cast<u32>(ptr[0]);
|
||||
return val;
|
||||
}
|
||||
|
||||
static u32 bp_get(u32 reg, u32 size, u32 shift);
|
||||
@@ -317,6 +334,7 @@ static void handle_draw(u8 cmd, const u8* data, u32& pos, u32 size, bool bigEndi
|
||||
static void handle_aurora(const u8* data, u32& pos, u32 size, bool bigEndian);
|
||||
|
||||
void process(const u8* data, u32 size, bool bigEndian) {
|
||||
ZoneScoped;
|
||||
u32 pos = 0;
|
||||
|
||||
while (pos < size) {
|
||||
@@ -354,6 +372,7 @@ void process(const u8* data, u32 size, bool bigEndian) {
|
||||
case CP_CMD_LOAD_INDX_B:
|
||||
case CP_CMD_LOAD_INDX_C:
|
||||
case CP_CMD_LOAD_INDX_D: {
|
||||
ZoneScopedN("LOAD_INDX");
|
||||
// Indexed XF load: 4 bytes of data
|
||||
CHECK(pos + 4 <= size, "indexed XF read overrun");
|
||||
u32 arrayType = GX_POS_MTX_ARRAY + (opcode - (CP_CMD_LOAD_INDX_A / 0x08));
|
||||
@@ -426,10 +445,11 @@ void process(const u8* data, u32 size, bool bigEndian) {
|
||||
}
|
||||
|
||||
// Helper to extract bit fields from a 32-bit register
|
||||
static u32 bp_get(u32 reg, u32 size, u32 shift) { return reg >> shift & (1u << size) - 1; }
|
||||
inline static u32 bp_get(u32 reg, u32 size, u32 shift) { return reg >> shift & (1u << size) - 1; }
|
||||
|
||||
// BP register handler - decodes BP (RAS/pixel engine) register writes and updates g_gxState
|
||||
static void handle_bp(u32 value, bool bigEndian) {
|
||||
ZoneScoped;
|
||||
u32 regId = (value >> 24) & 0xFF;
|
||||
// Mask off the register ID from the value for field extraction
|
||||
// (the regId is stored in bits 24-31, data is in bits 0-23)
|
||||
@@ -1012,6 +1032,7 @@ static void handle_bp(u32 value, bool bigEndian) {
|
||||
|
||||
// CP register handler - decodes CP register writes and updates g_gxState
|
||||
static void handle_cp(u8 addr, u32 value, bool bigEndian) {
|
||||
ZoneScoped;
|
||||
switch (addr) {
|
||||
// VCD low (0x50)
|
||||
case 0x50: {
|
||||
@@ -1030,6 +1051,7 @@ static void handle_cp(u8 addr, u32 value, bool bigEndian) {
|
||||
vd[GX_VA_CLR0] = static_cast<GXAttrType>(bp_get(value, 2, 13));
|
||||
vd[GX_VA_CLR1] = static_cast<GXAttrType>(bp_get(value, 2, 15));
|
||||
g_gxState.stateDirty = true;
|
||||
g_gxState.clearVtxSizeCache();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1045,6 +1067,7 @@ static void handle_cp(u8 addr, u32 value, bool bigEndian) {
|
||||
vd[GX_VA_TEX6] = static_cast<GXAttrType>(bp_get(value, 2, 12));
|
||||
vd[GX_VA_TEX7] = static_cast<GXAttrType>(bp_get(value, 2, 14));
|
||||
g_gxState.stateDirty = true;
|
||||
g_gxState.clearVtxSizeCache();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1086,6 +1109,7 @@ static void handle_cp(u8 addr, u32 value, bool bigEndian) {
|
||||
vf.attrs[GX_VA_TEX0].type = static_cast<GXCompType>(bp_get(value, 3, 22));
|
||||
vf.attrs[GX_VA_TEX0].frac = static_cast<u8>(bp_get(value, 5, 25));
|
||||
g_gxState.stateDirty = true;
|
||||
g_gxState.clearVtxSizeCache();
|
||||
}
|
||||
// VAT B registers (0x80-0x87)
|
||||
else if (addr >= 0x80 && addr <= 0x87) {
|
||||
@@ -1104,6 +1128,7 @@ static void handle_cp(u8 addr, u32 value, bool bigEndian) {
|
||||
vf.attrs[GX_VA_TEX4].type = static_cast<GXCompType>(bp_get(value, 3, 28));
|
||||
// TEX4 frac is in VAT C
|
||||
g_gxState.stateDirty = true;
|
||||
g_gxState.clearVtxSizeCache();
|
||||
}
|
||||
// VAT C registers (0x90-0x97)
|
||||
else if (addr >= 0x90 && addr <= 0x97) {
|
||||
@@ -1120,6 +1145,7 @@ static void handle_cp(u8 addr, u32 value, bool bigEndian) {
|
||||
vf.attrs[GX_VA_TEX7].type = static_cast<GXCompType>(bp_get(value, 3, 24));
|
||||
vf.attrs[GX_VA_TEX7].frac = static_cast<u8>(bp_get(value, 5, 27));
|
||||
g_gxState.stateDirty = true;
|
||||
g_gxState.clearVtxSizeCache();
|
||||
}
|
||||
// Array base addresses (0xA0-0xAF)
|
||||
else if (addr >= 0xA0 && addr <= 0xAF) {
|
||||
@@ -1143,6 +1169,7 @@ static void handle_cp(u8 addr, u32 value, bool bigEndian) {
|
||||
|
||||
// XF register handler - decodes XF (transform unit) register writes and updates g_gxState
|
||||
static void handle_xf(const u8* data, u32& pos, u32 size, bool bigEndian) {
|
||||
ZoneScoped;
|
||||
CHECK(pos + 4 <= size, "XF header read overrun");
|
||||
u32 header = read_u32(data + pos, bigEndian);
|
||||
pos += 4;
|
||||
@@ -1362,16 +1389,24 @@ static void handle_xf(const u8* data, u32& pos, u32 size, bool bigEndian) {
|
||||
pos += dataBytes;
|
||||
}
|
||||
|
||||
static void handle_draw_overrun [[noreturn]] (u32 totalVtxBytes, const u8* data, const u32& pos, u32 size) {
|
||||
// Hex dump around the draw command for debugging
|
||||
u32 cmdPos = pos - 2 - 1; // opcode byte position (before vtxCount and pos++)
|
||||
u32 dumpStart = (cmdPos > 16) ? cmdPos - 16 : 0;
|
||||
u32 dumpEnd = (cmdPos + 32 < size) ? cmdPos + 32 : size;
|
||||
std::string hex;
|
||||
for (u32 i = dumpStart; i < dumpEnd; i++) {
|
||||
if (i == cmdPos)
|
||||
hex += fmt::format("[{:02x}]", data[i]);
|
||||
else
|
||||
hex += fmt::format(" {:02x}", data[i]);
|
||||
}
|
||||
Log.error(" hex dump around draw cmd (pos {}-{}):{}", dumpStart, dumpEnd - 1, hex);
|
||||
FATAL("draw vertex data overrun: need {} bytes at pos {}, have {}", totalVtxBytes, pos, size);
|
||||
}
|
||||
|
||||
// Draw command handler - parses vertices inline and caches results
|
||||
static void handle_draw(u8 cmd, const u8* data, u32& pos, u32 size, bool bigEndian) {
|
||||
u8 opcode = cmd & CP_OPCODE_MASK;
|
||||
GXVtxFmt fmt = static_cast<GXVtxFmt>(cmd & CP_VAT_MASK);
|
||||
GXPrimitive prim = static_cast<GXPrimitive>(opcode);
|
||||
|
||||
CHECK(pos + 2 <= size, "draw vtxCount read overrun");
|
||||
u16 vtxCount = read_u16(data + pos, bigEndian);
|
||||
pos += 2;
|
||||
|
||||
static u32 calculate_last_vtx_size(GXVtxFmt fmt) {
|
||||
u32 vtxSize = 0;
|
||||
const auto& vtxFmt = g_gxState.vtxFmts[fmt];
|
||||
for (int i = GX_VA_PNMTXIDX; i <= GX_VA_TEX7; ++i) {
|
||||
@@ -1392,38 +1427,53 @@ static void handle_draw(u8 cmd, const u8* data, u32& pos, u32 size, bool bigEndi
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_gxState.lastVtxFmt = fmt;
|
||||
g_gxState.lastVtxSize = vtxSize;
|
||||
|
||||
return vtxSize;
|
||||
}
|
||||
|
||||
static void handle_draw_unmerged(GXPrimitive prim, GXVtxFmt fmt, u16 vtxCount, gfx::Range vertRange);
|
||||
|
||||
// Draw command handler - parses vertices inline and caches results
|
||||
static ByteBuffer handle_draw_idx_buf;
|
||||
|
||||
static void handle_draw(u8 cmd, const u8* data, u32& pos, u32 size, bool bigEndian) {
|
||||
ZoneScoped;
|
||||
u8 opcode = cmd & CP_OPCODE_MASK;
|
||||
GXVtxFmt fmt = static_cast<GXVtxFmt>(cmd & CP_VAT_MASK);
|
||||
GXPrimitive prim = static_cast<GXPrimitive>(opcode);
|
||||
|
||||
CHECK(pos + 2 <= size, "draw vtxCount read overrun");
|
||||
u16 vtxCount = read_u16(data + pos, bigEndian);
|
||||
pos += 2;
|
||||
|
||||
u32 vtxSize;
|
||||
if (g_gxState.lastVtxFmt == fmt) LIKELY {
|
||||
vtxSize = g_gxState.lastVtxSize;
|
||||
} else UNLIKELY {
|
||||
vtxSize = calculate_last_vtx_size(fmt);
|
||||
}
|
||||
|
||||
u32 totalVtxBytes = vtxCount * vtxSize;
|
||||
if (pos + totalVtxBytes > size) {
|
||||
// Hex dump around the draw command for debugging
|
||||
u32 cmdPos = pos - 2 - 1; // opcode byte position (before vtxCount and pos++)
|
||||
u32 dumpStart = (cmdPos > 16) ? cmdPos - 16 : 0;
|
||||
u32 dumpEnd = (cmdPos + 32 < size) ? cmdPos + 32 : size;
|
||||
std::string hex;
|
||||
for (u32 i = dumpStart; i < dumpEnd; i++) {
|
||||
if (i == cmdPos)
|
||||
hex += fmt::format("[{:02x}]", data[i]);
|
||||
else
|
||||
hex += fmt::format(" {:02x}", data[i]);
|
||||
}
|
||||
Log.error(" hex dump around draw cmd (pos {}-{}):{}", dumpStart, dumpEnd - 1, hex);
|
||||
FATAL("draw vertex data overrun: need {} bytes at pos {}, have {}", totalVtxBytes, pos, size);
|
||||
if (pos + totalVtxBytes > size) UNLIKELY {
|
||||
handle_draw_overrun(totalVtxBytes, data, pos, size);
|
||||
}
|
||||
|
||||
// Push raw vertex data to buffer
|
||||
gfx::Range vertRange = gfx::push_verts(data + pos, totalVtxBytes);
|
||||
pos += totalVtxBytes;
|
||||
|
||||
u32 numIndices = 0;
|
||||
gfx::Range idxRange;
|
||||
// Try to merge with previous draw call
|
||||
if (!g_gxState.stateDirty) {
|
||||
if (!g_gxState.stateDirty) LIKELY {
|
||||
auto* lastDraw = gfx::get_last_draw_command<DrawData>();
|
||||
// Only if the previous draw call was a single instance draw (no lines/points handling)
|
||||
if (lastDraw != nullptr && prim != GX_LINES && prim != GX_LINESTRIP && prim != GX_POINTS &&
|
||||
lastDraw->instanceCount == 1) {
|
||||
ByteBuffer idxBuf;
|
||||
numIndices = prepare_idx_buffer(idxBuf, prim, lastDraw->vtxCount, vtxCount);
|
||||
idxRange = gfx::push_indices(idxBuf.data(), idxBuf.size());
|
||||
lastDraw->instanceCount == 1) LIKELY {
|
||||
u32 numIndices = prepare_idx_buffer(handle_draw_idx_buf, prim, lastDraw->vtxCount, vtxCount);
|
||||
gfx::Range idxRange = gfx::push_indices(handle_draw_idx_buf.data(), handle_draw_idx_buf.size());
|
||||
handle_draw_idx_buf.clear();
|
||||
CHECK(lastDraw->vertRange.offset + lastDraw->vertRange.size == vertRange.offset,
|
||||
"Non-consecutive vertex ranges ({} < {})", lastDraw->vertRange.offset + lastDraw->vertRange.size,
|
||||
vertRange.offset);
|
||||
@@ -1439,10 +1489,22 @@ static void handle_draw(u8 cmd, const u8* data, u32& pos, u32 size, bool bigEndi
|
||||
}
|
||||
}
|
||||
|
||||
handle_draw_unmerged(prim, fmt, vtxCount, vertRange);
|
||||
}
|
||||
|
||||
static ByteBuffer handle_draw_unmerged_idxBuf;
|
||||
|
||||
static void handle_draw_unmerged(GXPrimitive prim, GXVtxFmt fmt, u16 vtxCount, gfx::Range vertRange) {
|
||||
ZoneScoped;
|
||||
u32 numIndices = 0;
|
||||
gfx::Range idxRange;
|
||||
|
||||
{
|
||||
ByteBuffer idxBuf;
|
||||
numIndices = prepare_idx_buffer(idxBuf, prim, 0, vtxCount);
|
||||
idxRange = gfx::push_indices(idxBuf.data(), idxBuf.size());
|
||||
auto& realBuf = vtxCount < 1000 ? handle_draw_unmerged_idxBuf : idxBuf;
|
||||
numIndices = prepare_idx_buffer(realBuf, prim, 0, vtxCount);
|
||||
idxRange = gfx::push_indices(realBuf.data(), realBuf.size());
|
||||
realBuf.clear();
|
||||
}
|
||||
|
||||
// Build pipeline, bind groups, and push draw command
|
||||
@@ -1501,6 +1563,7 @@ std::string read_string(const u8* data, u32& pos, u32 size, bool bigEndian) {
|
||||
}
|
||||
|
||||
void handle_aurora(const u8* data, u32& pos, u32 size, bool bigEndian) {
|
||||
ZoneScoped;
|
||||
CHECK(pos + 2 <= size, "Aurora cmd read overrun");
|
||||
u16 subCmd = read_u16(data + pos, bigEndian);
|
||||
pos += 2;
|
||||
|
||||
+28
-23
@@ -12,6 +12,8 @@
|
||||
#include <cfloat>
|
||||
#include <mutex>
|
||||
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
static aurora::Module Log("aurora::gx");
|
||||
|
||||
namespace aurora::gx {
|
||||
@@ -186,6 +188,7 @@ static inline wgpu::PrimitiveState to_primitive_state(GXCullMode gx_cullMode) {
|
||||
|
||||
wgpu::RenderPipeline build_pipeline(const PipelineConfig& config, ArrayRef<wgpu::VertexBufferLayout> vtxBuffers,
|
||||
wgpu::ShaderModule shader, const char* label) noexcept {
|
||||
ZoneScoped;
|
||||
const wgpu::DepthStencilState depthStencil{
|
||||
.format = g_graphicsConfig.depthFormat,
|
||||
.depthWriteEnabled = config.depthCompare && config.depthUpdate,
|
||||
@@ -439,11 +442,13 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi
|
||||
const BindGroupRanges& ranges) noexcept {
|
||||
const auto layouts = build_bind_group_layouts(config);
|
||||
|
||||
std::array<wgpu::BindGroupEntry, MaxIndexAttr + 3> uniformEntries;
|
||||
// Using C WGPU types instead of C++ wrappers to avoid destructor overhead
|
||||
std::array<WGPUBindGroupEntry, MaxIndexAttr + 3> uniformEntries{};
|
||||
uniformEntries[0].binding = 0;
|
||||
uniformEntries[0].buffer = gfx::g_vertexBuffer;
|
||||
uniformEntries[0].buffer = gfx::g_vertexBuffer.Get();
|
||||
uniformEntries[0].size = WGPU_WHOLE_SIZE;
|
||||
uniformEntries[1].binding = 1;
|
||||
uniformEntries[1].buffer = gfx::g_uniformBuffer;
|
||||
uniformEntries[1].buffer = gfx::g_uniformBuffer.Get();
|
||||
uniformEntries[1].size = info.uniformSize;
|
||||
u32 uniformBindIdx = 2;
|
||||
for (u32 i = 0; i < MaxIndexAttr; ++i) {
|
||||
@@ -451,46 +456,46 @@ GXBindGroups build_bind_groups(const ShaderInfo& info, const ShaderConfig& confi
|
||||
if (range.size <= 0) {
|
||||
continue;
|
||||
}
|
||||
wgpu::BindGroupEntry& entry = uniformEntries[uniformBindIdx];
|
||||
WGPUBindGroupEntry& entry = uniformEntries[uniformBindIdx];
|
||||
entry.binding = uniformBindIdx;
|
||||
entry.buffer = gfx::g_storageBuffer;
|
||||
entry.buffer = gfx::g_storageBuffer.Get();
|
||||
entry.size = range.size;
|
||||
++uniformBindIdx;
|
||||
}
|
||||
|
||||
std::array<wgpu::BindGroupEntry, MaxTextures> samplerEntries;
|
||||
std::array<wgpu::BindGroupEntry, MaxTextures> textureEntries;
|
||||
std::array<WGPUBindGroupEntry, MaxTextures> samplerEntries{};
|
||||
std::array<WGPUBindGroupEntry, MaxTextures> textureEntries{};
|
||||
u32 textureCount = 0;
|
||||
for (u32 i = 0; i < MaxTextures; ++i) {
|
||||
const auto& tex = g_gxState.textures[i];
|
||||
wgpu::BindGroupEntry& samplerEntry = samplerEntries[textureCount];
|
||||
wgpu::BindGroupEntry& textureEntry = textureEntries[textureCount];
|
||||
WGPUBindGroupEntry& samplerEntry = samplerEntries[textureCount];
|
||||
WGPUBindGroupEntry& textureEntry = textureEntries[textureCount];
|
||||
samplerEntry.binding = textureCount;
|
||||
textureEntry.binding = textureCount;
|
||||
if (tex) {
|
||||
samplerEntry.sampler = gfx::sampler_ref(tex.get_descriptor());
|
||||
textureEntry.textureView = tex.texObj.ref->sampleTextureView;
|
||||
if (tex && (info.sampledTextures[i] || info.sampledIndTextures[i])) {
|
||||
samplerEntry.sampler = gfx::sampler_ref(tex.get_descriptor()).Get();
|
||||
textureEntry.textureView = tex.texObj.ref->sampleTextureView.Get();
|
||||
} else {
|
||||
samplerEntry.sampler = sEmptySampler;
|
||||
textureEntry.textureView = sEmptyTextureView;
|
||||
samplerEntry.sampler = sEmptySampler.Get();
|
||||
textureEntry.textureView = sEmptyTextureView.Get();
|
||||
}
|
||||
++textureCount;
|
||||
}
|
||||
const wgpu::BindGroupDescriptor uniformBindGroupDescriptor{
|
||||
.label = "GX Uniform Bind Group",
|
||||
.layout = layouts.uniformLayout,
|
||||
const WGPUBindGroupDescriptor uniformBindGroupDescriptor{
|
||||
.label = {"GX Uniform Bind Group", WGPU_STRLEN},
|
||||
.layout = layouts.uniformLayout.Get(),
|
||||
.entryCount = uniformBindIdx,
|
||||
.entries = uniformEntries.data(),
|
||||
};
|
||||
const wgpu::BindGroupDescriptor samplerBindGroupDescriptor{
|
||||
.label = "GX Sampler Bind Group",
|
||||
.layout = layouts.samplerLayout,
|
||||
const WGPUBindGroupDescriptor samplerBindGroupDescriptor{
|
||||
.label = {"GX Sampler Bind Group", WGPU_STRLEN},
|
||||
.layout = layouts.samplerLayout.Get(),
|
||||
.entryCount = textureCount,
|
||||
.entries = samplerEntries.data(),
|
||||
};
|
||||
const wgpu::BindGroupDescriptor textureBindGroupDescriptor{
|
||||
.label = "GX Texture Bind Group",
|
||||
.layout = layouts.textureLayout,
|
||||
const WGPUBindGroupDescriptor textureBindGroupDescriptor{
|
||||
.label = {"GX Texture Bind Group", WGPU_STRLEN},
|
||||
.layout = layouts.textureLayout.Get(),
|
||||
.entryCount = textureCount,
|
||||
.entries = textureEntries.data(),
|
||||
};
|
||||
|
||||
@@ -315,6 +315,8 @@ struct GXState {
|
||||
std::array<Mat3x4<float>, MaxPTTexMtx> ptTexMtxs;
|
||||
std::array<TcgConfig, MaxTexCoord> tcgs;
|
||||
std::array<TexCoordScale, MaxTexCoord> texCoordScales;
|
||||
u16 lastVtxSize = 0;
|
||||
GXVtxFmt lastVtxFmt = GX_MAX_VTXFMT;
|
||||
std::array<GXAttrType, MaxVtxAttr> vtxDesc;
|
||||
std::array<VtxFmt, MaxVtxFmt> vtxFmts;
|
||||
std::array<TevSwap, MaxTevSwap> tevSwapTable{
|
||||
@@ -358,6 +360,10 @@ struct GXState {
|
||||
bool stateDirty = true;
|
||||
std::array<u32, 0x100> bpRegCache;
|
||||
GXState() { bpRegCache[0xFE] = 0x00FFFFFF; }
|
||||
|
||||
void clearVtxSizeCache() {
|
||||
lastVtxFmt = GX_MAX_VTXFMT;
|
||||
}
|
||||
};
|
||||
extern GXState g_gxState;
|
||||
|
||||
|
||||
@@ -3,11 +3,13 @@
|
||||
#include "../webgpu/gpu.hpp"
|
||||
#include "gx_fmt.hpp"
|
||||
#include "shader_info.hpp"
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
namespace aurora::gx {
|
||||
static Module Log("aurora::gx");
|
||||
|
||||
wgpu::RenderPipeline create_pipeline(const PipelineConfig& config) {
|
||||
ZoneScoped;
|
||||
const auto shader = build_shader(config.shaderConfig);
|
||||
return build_pipeline(config, {}, shader, "GX Pipeline");
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
namespace aurora::gx {
|
||||
using namespace fmt::literals;
|
||||
using namespace std::string_literals;
|
||||
@@ -680,6 +682,7 @@ auto lighting_func(const ShaderConfig& config, const ColorChannelConfig& cc, u8
|
||||
}
|
||||
|
||||
wgpu::ShaderModule build_shader(const ShaderConfig& config) noexcept {
|
||||
ZoneScoped;
|
||||
const auto hash = xxh3_hash(config);
|
||||
{
|
||||
std::lock_guard lock{g_gxCachedShadersMutex};
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "backends/imgui_impl_sdl3.h"
|
||||
#include "backends/imgui_impl_sdlrenderer3.h"
|
||||
#include "backends/imgui_impl_wgpu.h"
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
namespace aurora::imgui {
|
||||
static float g_scale;
|
||||
@@ -36,6 +37,7 @@ void create_context() noexcept {
|
||||
}
|
||||
|
||||
void initialize() noexcept {
|
||||
ZoneScoped;
|
||||
SDL_Renderer* renderer = window::get_sdl_renderer();
|
||||
ImGui_ImplSDL3_InitForSDLRenderer(window::get_sdl_window(), renderer);
|
||||
g_useSdlRenderer = renderer != nullptr;
|
||||
@@ -50,6 +52,7 @@ void initialize() noexcept {
|
||||
}
|
||||
|
||||
void shutdown() noexcept {
|
||||
ZoneScoped;
|
||||
if (g_useSdlRenderer) {
|
||||
ImGui_ImplSDLRenderer3_Shutdown();
|
||||
} else {
|
||||
@@ -69,6 +72,7 @@ void process_event(const SDL_Event& event) noexcept {
|
||||
}
|
||||
|
||||
void new_frame(const AuroraWindowSize& size) noexcept {
|
||||
ZoneScoped;
|
||||
const float framebufferScaleX =
|
||||
size.width > 0 ? static_cast<float>(size.native_fb_width) / static_cast<float>(size.width) : 1.0f;
|
||||
const float framebufferScaleY =
|
||||
@@ -98,6 +102,7 @@ void new_frame(const AuroraWindowSize& size) noexcept {
|
||||
}
|
||||
|
||||
void render(const wgpu::RenderPassEncoder& pass) noexcept {
|
||||
ZoneScoped;
|
||||
ImGui::Render();
|
||||
|
||||
auto* data = ImGui::GetDrawData();
|
||||
|
||||
+1
-3
@@ -80,9 +80,7 @@ auto underlying(T value) -> std::underlying_type_t<T> {
|
||||
return static_cast<std::underlying_type_t<T>>(value);
|
||||
}
|
||||
|
||||
#ifndef ALIGN
|
||||
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
|
||||
#endif
|
||||
#define AURORA_ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
|
||||
|
||||
#define POINTER_ADD_TYPE(type_, ptr_, offset_) ((type_)((uintptr_t)(ptr_) + (uintptr_t)(offset_)))
|
||||
#define POINTER_ADD(ptr_, offset_) POINTER_ADD_TYPE(decltype(ptr_), ptr_, offset_)
|
||||
|
||||
@@ -56,6 +56,7 @@ if (AURORA_ENABLE_GX)
|
||||
absl::flat_hash_map
|
||||
absl::btree
|
||||
dawn::dawncpp_headers
|
||||
TracyClient
|
||||
${AURORA_SDL3_TARGET}
|
||||
)
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ void set_scissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) noexcept {}
|
||||
// --- Pipeline/draw command stubs ---
|
||||
namespace aurora::gfx {
|
||||
template <>
|
||||
PipelineRef pipeline_ref<clear::PipelineConfig>(clear::PipelineConfig config) {
|
||||
PipelineRef pipeline_ref<clear::PipelineConfig>(const clear::PipelineConfig& config) {
|
||||
return 0;
|
||||
}
|
||||
template <>
|
||||
@@ -105,7 +105,7 @@ void push_draw_command<clear::DrawData>(clear::DrawData data) {
|
||||
// No-op
|
||||
}
|
||||
template <>
|
||||
PipelineRef pipeline_ref<gx::PipelineConfig>(gx::PipelineConfig config) {
|
||||
PipelineRef pipeline_ref<gx::PipelineConfig>(const gx::PipelineConfig& config) {
|
||||
return 0;
|
||||
}
|
||||
template <>
|
||||
|
||||
Reference in New Issue
Block a user