From 869329ee68fdb06280a6d400084cb9a1f198e796 Mon Sep 17 00:00:00 2001 From: nmzik Date: Wed, 5 Aug 2026 19:08:18 +0200 Subject: [PATCH] renderer: minor optimizations --- .../renderer/pipeline/descriptors.cpp | 15 ++- src/graphics/host_gpu/renderer/renderDraw.cpp | 119 ++++++++++++------ 2 files changed, 85 insertions(+), 49 deletions(-) diff --git a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp index 00af65141..10af3274d 100644 --- a/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/descriptors.cpp @@ -924,22 +924,21 @@ RenderExecutor::PrepareGraphicsBindings(CommandBuffer& buffer, const ShaderStage return bindings; } -static void RetainBindings(CommandBuffer& buffer, - const DescriptorCache::NativeDescriptors& resources) { +static void RetainBindings(CommandBuffer& buffer, DescriptorCache::NativeDescriptors& resources) { if (resources.flattened_srt.owner != nullptr) { - buffer.RetainResourceUntilFence(resources.flattened_srt.owner); + buffer.RetainResourceUntilFence(std::move(resources.flattened_srt.owner)); } if (resources.user_data.owner != nullptr) { - buffer.RetainResourceUntilFence(resources.user_data.owner); + buffer.RetainResourceUntilFence(std::move(resources.user_data.owner)); } - for (const auto& view: resources.buffers) { + for (auto& view: resources.buffers) { if (view.owner != nullptr) { - buffer.RetainResourceUntilFence(view.owner); + buffer.RetainResourceUntilFence(std::move(view.owner)); } } - for (const auto& view: resources.addresses) { + for (auto& view: resources.addresses) { if (view.owner != nullptr) { - buffer.RetainResourceUntilFence(view.owner); + buffer.RetainResourceUntilFence(std::move(view.owner)); } } } diff --git a/src/graphics/host_gpu/renderer/renderDraw.cpp b/src/graphics/host_gpu/renderer/renderDraw.cpp index 147c76048..70e13320f 100644 --- a/src/graphics/host_gpu/renderer/renderDraw.cpp +++ b/src/graphics/host_gpu/renderer/renderDraw.cpp @@ -684,11 +684,24 @@ struct VertexBufferRange { [[nodiscard]] uint64_t RequestedSize() const { return requested_end - base_address; } }; -static std::vector AcquireVertexBuffers(RenderCommandBuffer& buffer, - const ShaderVertexInputInfo& vs_input_info) { +struct PreparedVertexBuffers { + static constexpr uint32_t MaxBuffers = ShaderVertexInputInfo::RES_MAX; + + std::array buffers {}; + std::array offsets {}; + std::array, MaxBuffers> owners {}; + uint32_t count = 0; + uint32_t owner_count = 0; +}; + +static PreparedVertexBuffers AcquireVertexBuffers(RenderCommandBuffer& buffer, + const ShaderVertexInputInfo& vs_input_info) { + EXIT_IF(vs_input_info.buffers_num < 0 || + vs_input_info.buffers_num > ShaderVertexInputInfo::RES_MAX); + // Collect the non-empty guest vertex ranges. - std::vector ranges; - ranges.reserve(vs_input_info.buffers_num); + 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); @@ -699,27 +712,31 @@ static std::vector AcquireVertexBuffers(RenderCommandBuffer& EXIT("invalid vertex buffer range: addr=0x%016" PRIx64 " size=0x%016" PRIx64 "\n", vertex.addr, size); } - ranges.push_back({vertex.addr, vertex.addr + size}); + ranges[range_count++] = {vertex.addr, vertex.addr + size}; } - std::ranges::sort(ranges, [](const VertexBufferRange& left, const VertexBufferRange& right) { - return left.base_address < right.base_address; - }); + std::sort(ranges.begin(), ranges.begin() + range_count, + [](const VertexBufferRange& left, const VertexBufferRange& right) { + return left.base_address < right.base_address; + }); // Merge overlapping or touching ranges before acquiring host buffers. - std::vector merged_ranges; - merged_ranges.reserve(ranges.size()); - for (const auto& range: ranges) { - if (!merged_ranges.empty() && merged_ranges.back().requested_end >= range.base_address) { - merged_ranges.back().requested_end = - std::max(merged_ranges.back().requested_end, range.requested_end); + std::array merged_ranges {}; + uint32_t merged_count = 0; + for (uint32_t i = 0; i < range_count; i++) { + const auto& range = ranges[i]; + if (merged_count != 0 && + merged_ranges[merged_count - 1].requested_end >= range.base_address) { + merged_ranges[merged_count - 1].requested_end = + std::max(merged_ranges[merged_count - 1].requested_end, range.requested_end); continue; } - merged_ranges.push_back(range); + merged_ranges[merged_count++] = {range.base_address, range.requested_end}; } auto& cache = buffer.GetContext().GetBufferCache(); - for (auto& range: merged_ranges) { + for (uint32_t i = 0; i < merged_count; i++) { + auto& range = merged_ranges[i]; // PPSA20298 const auto size = Libs::LibKernel::Memory::ClampRangeSize(range.base_address, range.RequestedSize()); @@ -728,30 +745,47 @@ static std::vector AcquireVertexBuffers(RenderCommandBuffer& } // Rebuild slot bindings, offsetting non-empty slots into their acquired merged range. - std::vector bindings; - bindings.reserve(vs_input_info.buffers_num); + PreparedVertexBuffers prepared; + prepared.count = static_cast(vs_input_info.buffers_num); + std::shared_ptr null_owner; + 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); if (size == 0) { - auto owner = cache.ObtainNullBuffer(); - bindings.push_back({owner, owner->Handle(), 0}); + if (null_owner == nullptr) { + null_owner = cache.ObtainNullBuffer(); + null_buffer = null_owner->Handle(); + } + prepared.buffers[i] = null_buffer; + prepared.offsets[i] = 0; continue; } - const auto range = std::ranges::find_if(merged_ranges, [&](const VertexBufferRange& value) { - return vertex.addr >= value.base_address && vertex.addr < value.acquired_end; - }); - if (range == merged_ranges.end()) { + const auto range = std::find_if(merged_ranges.begin(), merged_ranges.begin() + merged_count, + [&](const VertexBufferRange& value) { + return vertex.addr >= value.base_address && + vertex.addr < value.acquired_end; + }); + if (range == merged_ranges.begin() + merged_count) { EXIT("vertex buffer address is outside the acquired range: addr=0x%016" PRIx64 "\n", vertex.addr); } - auto binding = range->binding; - binding.offset += vertex.addr - range->base_address; - bindings.push_back(std::move(binding)); + prepared.buffers[i] = range->binding.buffer; + prepared.offsets[i] = range->binding.offset + vertex.addr - range->base_address; } - return bindings; + + if (null_owner != nullptr) { + prepared.owners[prepared.owner_count++] = std::move(null_owner); + } + for (uint32_t i = 0; i < merged_count; i++) { + if (merged_ranges[i].binding.owner != nullptr) { + EXIT_IF(prepared.owner_count >= PreparedVertexBuffers::MaxBuffers); + prepared.owners[prepared.owner_count++] = std::move(merged_ranges[i].binding.owner); + } + } + return prepared; } static void SetDrawDebugPhase(RenderCommandBuffer& buffer, uint64_t submit_id, @@ -883,10 +917,9 @@ static void RefreshShaders(RenderCommandBuffer& buffer, const DrawCallInfo& draw } } -static std::vector PrepareVertexBuffers(uint64_t submit_id, - RenderCommandBuffer& buffer, - const DrawCallInfo& draw, - const ShaderVertexInputInfo& vs_input_info) { +static PreparedVertexBuffers PrepareVertexBuffers(uint64_t submit_id, RenderCommandBuffer& buffer, + const DrawCallInfo& draw, + const ShaderVertexInputInfo& vs_input_info) { EXIT_IF(draw.name == nullptr); (void)submit_id; @@ -920,24 +953,28 @@ static PreparedIndexBuffer PrepareIndexBuffer(RenderCommandBuffer& buffe } static void CommitVertexBuffers(RenderCommandBuffer& buffer, vk::CommandBuffer vk_buffer, - std::vector& bindings) { - for (uint32_t slot = 0; slot < bindings.size(); slot++) { - auto& binding = bindings[slot]; - if (binding.owner != nullptr) { - buffer.RetainResourceUntilFence(binding.owner); + PreparedVertexBuffers& prepared) { + for (uint32_t i = 0; i < prepared.owner_count; i++) { + if (prepared.owners[i] != nullptr) { + buffer.RetainResourceUntilFence(std::move(prepared.owners[i])); } - EXIT_IF(binding.buffer == nullptr); - vk_buffer.bindVertexBuffers(slot, 1, &binding.buffer, &binding.offset); + } + for (uint32_t i = 0; i < prepared.count; i++) { + EXIT_IF(prepared.buffers[i] == nullptr); + } + if (prepared.count != 0) { + vk_buffer.bindVertexBuffers(0, prepared.count, prepared.buffers.data(), + prepared.offsets.data()); } } static void CommitIndexBuffer(RenderCommandBuffer& buffer, vk::CommandBuffer vk_buffer, - const PreparedIndexBuffer& prepared) { + PreparedIndexBuffer& prepared) { if (prepared.size == 0) { return; } if (prepared.owner != nullptr) { - buffer.RetainResourceUntilFence(prepared.owner); + buffer.RetainResourceUntilFence(std::move(prepared.owner)); } EXIT_IF(prepared.buffer == nullptr); vk_buffer.bindIndexBuffer(prepared.buffer, prepared.offset, prepared.type);