From d646fd92d185e27c34c24fb880d6f5f224f6ba30 Mon Sep 17 00:00:00 2001 From: Romain Hedouin Date: Thu, 24 Sep 2026 19:02:23 +0200 Subject: [PATCH] graphics: hoist loop-invariant checks out of draw/attrib hot paths (#807) * graphics: hoist loop-invariant checks out of draw/attrib hot paths DrawIndirectMulti recomputed the index_type_and_size switch on every sub-draw of a multi-draw-indirect call, and ShaderApplyAttribSemantics re-checked the debug-dump config flag on every vertex attribute. Both values are invariant across their respective loops, so compute them once before iterating instead. Co-Authored-By: Claude Sonnet 5 * graphics: cache vertex buffer descriptor size in AcquireVertexBuffers VertexBufferDescriptorSize was computed twice per vertex-buffer slot on every draw call: once while collecting guest ranges, and again while rebuilding slot bindings. Both calls use identical inputs, so cache the first pass's result and reuse it in the second. Co-Authored-By: Claude Sonnet 5 --------- Co-authored-by: Claude Sonnet 5 --- src/graphics/guest_gpu/graphicsRun.cpp | 18 ++++++++++-------- src/graphics/host_gpu/renderer/renderDraw.cpp | 4 +++- src/graphics/shader/shader.cpp | 4 +++- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/graphics/guest_gpu/graphicsRun.cpp b/src/graphics/guest_gpu/graphicsRun.cpp index a8ce0e9d6..af897547b 100644 --- a/src/graphics/guest_gpu/graphicsRun.cpp +++ b/src/graphics/guest_gpu/graphicsRun.cpp @@ -976,6 +976,16 @@ void CommandProcessor::DrawIndirectMulti(uint32_t data_offset, uint32_t max_coun const auto args_size = indexed ? sizeof(DrawIndexedIndirectArgs) : sizeof(DrawIndirectArgs); EXIT_NOT_IMPLEMENTED(stride_in_bytes < args_size); + uint64_t index_size = 0; + if (indexed) { + switch (m_index_type_and_size) { + case 0: index_size = 2; break; + case 1: index_size = 4; break; + case 2: index_size = 1; break; + default: EXIT("unknown index_type_and_size: %u\n", m_index_type_and_size); + } + } + for (uint32_t i = 0; i < draw_count; i++) { const auto args_addr = m_draw_indirect_args_base_addr + data_offset + static_cast(i) * stride_in_bytes; @@ -993,14 +1003,6 @@ void CommandProcessor::DrawIndirectMulti(uint32_t data_offset, uint32_t max_coun auto* args = reinterpret_cast(args_addr); - uint64_t index_size = 0; - switch (m_index_type_and_size) { - case 0: index_size = 2; break; - case 1: index_size = 4; break; - case 2: index_size = 1; break; - default: EXIT("unknown index_type_and_size: %u\n", m_index_type_and_size); - } - auto* index_addr = reinterpret_cast( m_index_base_addr + static_cast(args->start_index_location) * index_size); diff --git a/src/graphics/host_gpu/renderer/renderDraw.cpp b/src/graphics/host_gpu/renderer/renderDraw.cpp index e24ab9fc2..e08be150f 100644 --- a/src/graphics/host_gpu/renderer/renderDraw.cpp +++ b/src/graphics/host_gpu/renderer/renderDraw.cpp @@ -686,11 +686,13 @@ static PreparedVertexBuffers AcquireVertexBuffers(CommandBuffer& b vs_input_info.buffers_num > ShaderVertexInputInfo::RES_MAX); // Collect the non-empty guest vertex ranges. + std::array sizes {}; std::array ranges {}; uint32_t range_count = 0; for (int i = 0; i < vs_input_info.buffers_num; i++) { const auto& vertex = vs_input_info.buffers[i]; const auto size = VertexBufferDescriptorSize(vertex, vs_input_info); + sizes[i] = size; if (size == 0) { continue; } @@ -739,7 +741,7 @@ static PreparedVertexBuffers AcquireVertexBuffers(CommandBuffer& b vk::Buffer null_buffer = nullptr; for (int i = 0; i < vs_input_info.buffers_num; i++) { const auto& vertex = vs_input_info.buffers[i]; - const auto size = VertexBufferDescriptorSize(vertex, vs_input_info); + const auto size = sizes[i]; if (size == 0) { if (null_buffer == nullptr) { null_buffer = cache.GetBuffer(NULL_BUFFER_ID).Handle(); diff --git a/src/graphics/shader/shader.cpp b/src/graphics/shader/shader.cpp index 8739984ec..24e1d6629 100644 --- a/src/graphics/shader/shader.cpp +++ b/src/graphics/shader/shader.cpp @@ -388,6 +388,8 @@ static void ShaderApplyAttribSemantics(ShaderVertexInputInfo& info, EXIT_IF(attrib == nullptr || buffer == nullptr); + const bool debug_dump = Config::GraphicsDebugDumpEnabled(); + for (uint32_t i = 0; i < num_input_semantics; i++) { const auto& in = input_semantics[i]; @@ -396,7 +398,7 @@ static void ShaderApplyAttribSemantics(ShaderVertexInputInfo& info, uint32_t reg = in.hardware_mapping; uint32_t size = in.size_in_elements; - if (Config::GraphicsDebugDumpEnabled()) { + if (debug_dump) { LOGF("reg = %u, size = %u, va[%u] = 0x%08" PRIx32 "\n", reg, size, i, attrib[in.semantic]); }