From fc0a841c9b9a7cc5fc11b6a4384e1d453dcf5152 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Fri, 18 Sep 2026 10:54:56 +0200 Subject: [PATCH] Latte: Very minor optimization for vertex buffer binding --- src/Cafe/HW/Latte/Core/LatteBufferData.cpp | 17 ++++------------- .../HW/Latte/Renderer/Metal/MetalRenderer.cpp | 10 ++++++---- .../HW/Latte/Renderer/Metal/MetalRenderer.h | 2 +- .../HW/Latte/Renderer/OpenGL/OpenGLRenderer.h | 2 +- .../Renderer/OpenGL/OpenGLRendererCore.cpp | 10 +++++----- src/Cafe/HW/Latte/Renderer/Renderer.h | 10 +++++++++- .../Latte/Renderer/Vulkan/VulkanRenderer.cpp | 19 ++++++++++--------- .../HW/Latte/Renderer/Vulkan/VulkanRenderer.h | 2 +- 8 files changed, 37 insertions(+), 35 deletions(-) diff --git a/src/Cafe/HW/Latte/Core/LatteBufferData.cpp b/src/Cafe/HW/Latte/Core/LatteBufferData.cpp index b4c8379e..04181114 100644 --- a/src/Cafe/HW/Latte/Core/LatteBufferData.cpp +++ b/src/Cafe/HW/Latte/Core/LatteBufferData.cpp @@ -224,14 +224,8 @@ void LatteBufferCache_Sync(uint32 maxVtxIndex, uint32 baseInstance, uint32 insta { uint32* __restrict bufferRegStartPtr = LatteGPUState.contextRegister + mmSQ_VTX_ATTRIBUTE_BLOCK_START; - struct BindBufferParam - { - uint8 index; - uint32 bindOffset; - uint32 bindSize; - }; - BindBufferParam bindBufferArray[32]; - sint32 bindBufferArraySize = 0; + Renderer::BindBufferParam bindBufferArray[32]; + size_t bindBufferArraySize = 0; cemu_assert_debug(parsedFetchShader->bufferGroups.size() < 32); // fetch shader generation should guarantee for (auto& bufferGroup : parsedFetchShader->bufferGroups) @@ -242,6 +236,7 @@ void LatteBufferCache_Sync(uint32 maxVtxIndex, uint32 baseInstance, uint32 insta uint32* __restrict bufferRegs = bufferRegStartPtr + bufferIndex * 7; MPTR bufferAddress = bufferRegs[0]; uint32 bufferStride = (bufferRegs[2] >> 11) & 0xFFFF; + bindBufferArray[bindBufferArraySize].stride = bufferStride; // todo - respect buffer max size if (bufferAddress == MPTR_NULL) [[unlikely]] @@ -287,11 +282,7 @@ void LatteBufferCache_Sync(uint32 maxVtxIndex, uint32 baseInstance, uint32 insta bindBufferArraySize++; } // update vertex buffer bindings - for (uint32 i=0; ibuffer_bindVertexBuffer(boundBuf.index, boundBuf.bindOffset, boundBuf.bindSize); - } + g_renderer->buffer_bindVertexBuffers({bindBufferArray, bindBufferArraySize}); } // sync uniform buffers LatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader(); diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index edc4016d..6966b13b 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -1019,12 +1019,14 @@ void MetalRenderer::bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint CopyBufferToBuffer(GetXfbRingBuffer(), srcOffset, m_memoryManager->GetBufferCache(), dstOffset, size, MTL::RenderStageVertex | MTL::RenderStageMesh, ALL_MTL_RENDER_STAGES); } -void MetalRenderer::buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size) +void MetalRenderer::buffer_bindVertexBuffers(std::span bindings) { cemu_assert_debug(!m_memoryManager->UseHostMemoryForCache()); - cemu_assert_debug(bufferIndex < LATTE_MAX_VERTEX_BUFFERS); - - m_state.m_vertexBufferOffsets[bufferIndex] = offset; + for (const auto& binding : bindings) + { + cemu_assert_debug(binding.index < LATTE_MAX_VERTEX_BUFFERS); + m_state.m_vertexBufferOffsets[binding.index] = binding.bindOffset; + } } void MetalRenderer::buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h index c75f12bf..81d9f4ad 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h @@ -232,7 +232,7 @@ public: void bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size) override; void bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size) override; - void buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size) override; + void buffer_bindVertexBuffers(std::span bindings) override; void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) override; // shader diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h index 435ea427..3cbdb8ea 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h @@ -111,7 +111,7 @@ public: void bufferCache_upload(uint8* buffer, sint32 size, uint32 bufferOffset) override; void bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size) override; - void buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size) override; + void buffer_bindVertexBuffers(std::span bindings) override; void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) override; void _setupVertexAttributes(); diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp index d2161636..24a40010 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp @@ -576,9 +576,12 @@ void LatteDrawGL_doDraw(_INDEX_TYPE indexType, uint32 baseVertex, uint32 baseIns uint32 _glVertexBufferOffset[Latte::GPU_LIMITS::NUM_VERTEX_BUFFERS] = { 0 }; -void OpenGLRenderer::buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size) +void OpenGLRenderer::buffer_bindVertexBuffers(std::span bindings) { - _glVertexBufferOffset[bufferIndex] = offset; + for (const auto& binding : bindings) + { + _glVertexBufferOffset[binding.index] = binding.bindOffset; + } } void OpenGLRenderer::buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) @@ -633,9 +636,6 @@ void OpenGLRenderer::_setupVertexAttributes() sint32 attributeDataIndex = 0; uint32 vboDataOffset = 0; - bool tfBufferIsBound = false; - sint32 maxReallocAttemptLimit = 1; - for(auto& bufferGroup : parsedFetchShader->bufferGroups) { uint32 bufferIndex = bufferGroup.attributeBufferIndex; diff --git a/src/Cafe/HW/Latte/Renderer/Renderer.h b/src/Cafe/HW/Latte/Renderer/Renderer.h index bc9e6360..fa77fd90 100644 --- a/src/Cafe/HW/Latte/Renderer/Renderer.h +++ b/src/Cafe/HW/Latte/Renderer/Renderer.h @@ -130,7 +130,15 @@ public: virtual void bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size) = 0; virtual void bufferCache_copyStreamoutToMainBuffer(uint32 srcOffset, uint32 dstOffset, uint32 size) = 0; - virtual void buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size) = 0; + struct BindBufferParam + { + uint8 index; + uint16 stride; + uint32 bindOffset; + uint32 bindSize; + }; + + virtual void buffer_bindVertexBuffers(std::span bindings) = 0; virtual void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) = 0; // shader diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp index 6e2e8b10..deadd47b 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.cpp @@ -3786,17 +3786,18 @@ void VulkanRenderer::streamout_rendererFinishDrawcall() m_streamoutState.buffer[3].enabled = false; } - -void VulkanRenderer::buffer_bindVertexBuffer(uint32 bufferIndex, uint32 offset, uint32 size) +void VulkanRenderer::buffer_bindVertexBuffers(std::span bindings) { cemu_assert_debug(!m_useHostMemoryForCache); - if (m_state.currentVertexBinding[bufferIndex].offset == offset) - return; - cemu_assert_debug(bufferIndex < Latte::GPU_LIMITS::NUM_VERTEX_BUFFERS); - m_state.currentVertexBinding[bufferIndex].offset = offset; - VkBuffer attrBuffer = m_bufferCache; - VkDeviceSize attrOffset = offset; - vkCmdBindVertexBuffers(m_state.currentCommandBuffer, bufferIndex, 1, &attrBuffer, &attrOffset); + VkBuffer buffer = m_bufferCache; + for (auto& binding : bindings) + { + if (m_state.currentVertexBinding[binding.index].offset == binding.bindOffset) + continue; + m_state.currentVertexBinding[binding.index].offset = binding.bindOffset; + VkDeviceSize bindOffset = binding.bindOffset; + vkCmdBindVertexBuffers(m_state.currentCommandBuffer, binding.index, 1, &buffer, &bindOffset); + } } void VulkanRenderer::buffer_bindVertexStrideWorkaroundBuffer(VkBuffer fixedBuffer, uint32 offset, uint32 bufferIndex, uint32 size) diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h index 1bdac166..d975e116 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h @@ -337,7 +337,7 @@ public: void bufferCache_upload(uint8* buffer, sint32 size, uint32 bufferOffset) override; void bufferCache_copy(uint32 srcOffset, uint32 dstOffset, uint32 size) override; - void buffer_bindVertexBuffer(uint32 bufferIndex, uint32 buffer, uint32 size) override; + void buffer_bindVertexBuffers(std::span bindings) override; void buffer_bindVertexStrideWorkaroundBuffer(VkBuffer fixedBuffer, uint32 offset, uint32 bufferIndex, uint32 size); std::pair buffer_genStrideWorkaroundVertexBuffer(MPTR buffer, uint32 size, uint32 oldStride); void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) override;