Latte: Very minor optimization for vertex buffer binding

This commit is contained in:
Exzap
2026-09-18 10:54:56 +02:00
parent c12284f1da
commit fc0a841c9b
8 changed files with 37 additions and 35 deletions

View File

@@ -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; i<bindBufferArraySize; i++)
{
auto& boundBuf = bindBufferArray[i];
g_renderer->buffer_bindVertexBuffer(boundBuf.index, boundBuf.bindOffset, boundBuf.bindSize);
}
g_renderer->buffer_bindVertexBuffers({bindBufferArray, bindBufferArraySize});
}
// sync uniform buffers
LatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader();

View File

@@ -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<BindBufferParam> 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)

View File

@@ -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<BindBufferParam> bindings) override;
void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) override;
// shader

View File

@@ -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<BindBufferParam> bindings) override;
void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) override;
void _setupVertexAttributes();

View File

@@ -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<BindBufferParam> 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;

View File

@@ -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<BindBufferParam> bindings) = 0;
virtual void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) = 0;
// shader

View File

@@ -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<BindBufferParam> 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)

View File

@@ -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<BindBufferParam> bindings) override;
void buffer_bindVertexStrideWorkaroundBuffer(VkBuffer fixedBuffer, uint32 offset, uint32 bufferIndex, uint32 size);
std::pair<VkBuffer, uint32> buffer_genStrideWorkaroundVertexBuffer(MPTR buffer, uint32 size, uint32 oldStride);
void buffer_bindUniformBuffer(LatteConst::ShaderType shaderType, uint32 bufferIndex, uint32 offset, uint32 size) override;