From 57bc919e7cbd17c04bae2e70f404eb11746c48ef Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sat, 20 Jun 2026 17:34:25 +0200 Subject: [PATCH] Latte: Simplify code --- src/Cafe/HW/Latte/Core/Latte.h | 18 +- src/Cafe/HW/Latte/Core/LatteBufferData.cpp | 184 +++--------------- .../HW/Latte/Core/LatteCommandProcessor.cpp | 5 + src/Cafe/HW/Latte/Core/LatteConst.h | 2 +- .../HW/Latte/Renderer/Metal/MetalRenderer.cpp | 5 +- .../Renderer/OpenGL/OpenGLRendererCore.cpp | 3 +- .../OpenGL/OpenGLRendererUniformData.cpp | 2 +- .../HW/Latte/Renderer/Vulkan/VulkanRenderer.h | 2 +- .../Renderer/Vulkan/VulkanRendererCore.cpp | 33 ++-- 9 files changed, 61 insertions(+), 193 deletions(-) diff --git a/src/Cafe/HW/Latte/Core/Latte.h b/src/Cafe/HW/Latte/Core/Latte.h index 2a11c412..fae9e51f 100644 --- a/src/Cafe/HW/Latte/Core/Latte.h +++ b/src/Cafe/HW/Latte/Core/Latte.h @@ -76,12 +76,12 @@ struct LatteDrawcallContext { bool isFirst{}; // first _execute() in current sequence // these are only valid if isFirst is false: - mutable uint32 vertexBufferDirtyMask{}; // mask of vertex buffer indices which have been modified since last draw execute. It's the responsibility of the backend to unset bits - mutable uint32 vsUniformBufferDirtyMask{}; // mask of uniform buffer indices which have been modified (changed address or size) since last draw execute. It's the responsibility of the backend to unset bits - mutable uint32 psUniformBufferDirtyMask{}; - mutable uint32 gsUniformBufferDirtyMask{}; - mutable bool aluConstVSDirty{}; - mutable bool aluConstPSDirty{}; + mutable uint32 vertexBufferDirtyMask{}; // mask of vertex buffer indices which have been modified since last draw execute + uint32 vsUniformBufferDirtyMask{}; // mask of uniform buffer indices which have been modified (changed address or size) since last draw execute + uint32 psUniformBufferDirtyMask{}; + uint32 gsUniformBufferDirtyMask{}; + bool aluConstVSDirty{}; + bool aluConstPSDirty{}; }; // texture @@ -168,10 +168,8 @@ void LatteCP_ProcessRingbuffer(); // buffer cache -bool LatteBufferCache_Sync(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount); -void LatteBufferCache_SyncIncremental(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount, const LatteDrawcallContext& drawcallContext, uint8& stageUniformModifiedMask); -void LatteBufferCache_LoadRemappedUniforms(struct LatteDecompilerShader* shader, float* uniformData); -bool LatteBufferCache_LoadRemappedUniformsIncremental(LatteDecompilerShader* shader, float* uniformData, const LatteDrawcallContext& drawcallContext); +void LatteBufferCache_Sync(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount, uint32 attribBufferDirtyMask, uint32 vsUniformBufferDirtyMask, uint32 psUniformBufferDirtyMask, uint32 gsUniformBufferDirtyMask, uint8& stageUniformModifiedMask, bool isIncremental = false); +bool LatteBufferCache_LoadRemappedUniforms(struct LatteDecompilerShader* shader, float* uniformData, bool aluConstDirty, uint32 uniformBufferDirtyMask); void LatteRenderTarget_updateViewport(); diff --git a/src/Cafe/HW/Latte/Core/LatteBufferData.cpp b/src/Cafe/HW/Latte/Core/LatteBufferData.cpp index 09210267..17a781d5 100644 --- a/src/Cafe/HW/Latte/Core/LatteBufferData.cpp +++ b/src/Cafe/HW/Latte/Core/LatteBufferData.cpp @@ -70,101 +70,32 @@ void rectGenerate4thVertex(uint32be* output, uint32be* input0, uint32be* input1, output[f] = _swapEndianU32(output[f]); } -void LatteBufferCache_LoadRemappedUniforms(LatteDecompilerShader* shader, float* uniformData) -{ - uint32 shaderAluConst; - uint32 shaderUniformRegisterOffset; - - switch (shader->shaderType) - { - case LatteConst::ShaderType::Vertex: - shaderAluConst = 0x400; - shaderUniformRegisterOffset = mmSQ_VTX_UNIFORM_BLOCK_START; - break; - case LatteConst::ShaderType::Pixel: - shaderAluConst = 0; - shaderUniformRegisterOffset = mmSQ_PS_UNIFORM_BLOCK_START; - break; - case LatteConst::ShaderType::Geometry: - shaderAluConst = 0; // geometry shader has no ALU const - shaderUniformRegisterOffset = mmSQ_GS_UNIFORM_BLOCK_START; - break; - default: - UNREACHABLE; - } - - // sourced from uniform registers - uint32* aluConstBase = LatteGPUState.contextRegister + mmSQ_ALU_CONSTANT0_0 + shaderAluConst; - for (auto it : shader->list_remappedUniformEntries_register) - { - uint64* uniformRegData = (uint64*)(aluConstBase + it.indexOffset / 4); - uint64* regDest = (uint64*)((uint8*)uniformData + it.mappedIndexOffset); - regDest[0] = uniformRegData[0]; - regDest[1] = uniformRegData[1]; - } - // sourced from uniform buffers - for (auto& bufferGroup : shader->list_remappedUniformEntries_bufferGroups) - { - MPTR physicalAddr = LatteGPUState.contextRegister[shaderUniformRegisterOffset + bufferGroup.kcacheBankIdOffset / 4]; - if (physicalAddr) - { - uint8* __restrict uniformBase = memory_base + physicalAddr; - for (auto& it : bufferGroup.entries) - { - uint64* __restrict regDest = (uint64*)((uint8*)uniformData + it.mappedIndexOffset); - uint64* __restrict uniformEntrySrc = (uint64*)(uniformBase + it.indexOffset); - memcpy(regDest, uniformEntrySrc, 16); - } - } - else - { - for (auto& it : bufferGroup.entries) - { - uint64* regDest = (uint64*)((uint8*)uniformData + it.mappedIndexOffset); - regDest[0] = 0; - regDest[1] = 0; - } - } - } -} - -// like LatteBufferCache_LoadRemappedUniforms but only updates data that is flagged as dirty in drawcallContext, returns true if any uniform value was updated. -bool LatteBufferCache_LoadRemappedUniformsIncremental(LatteDecompilerShader* shader, float* uniformData, const LatteDrawcallContext& drawcallContext) +bool LatteBufferCache_LoadRemappedUniforms(LatteDecompilerShader* shader, float* uniformData, bool aluConstDirty, uint32 uniformBufferDirtyMask) { bool hasChange = false; uint32 shaderAluConst; uint32 shaderUniformRegisterOffset; - bool hasDirtyAluConst = false; - uint32 uniformBufferDirtyMask = 0; switch (shader->shaderType) { case LatteConst::ShaderType::Vertex: shaderAluConst = 0x400; shaderUniformRegisterOffset = mmSQ_VTX_UNIFORM_BLOCK_START; - hasDirtyAluConst = drawcallContext.aluConstVSDirty; - uniformBufferDirtyMask = drawcallContext.vsUniformBufferDirtyMask; - drawcallContext.vsUniformBufferDirtyMask = 0; break; case LatteConst::ShaderType::Pixel: shaderAluConst = 0; shaderUniformRegisterOffset = mmSQ_PS_UNIFORM_BLOCK_START; - hasDirtyAluConst = drawcallContext.aluConstPSDirty; - uniformBufferDirtyMask = drawcallContext.psUniformBufferDirtyMask; - drawcallContext.psUniformBufferDirtyMask = 0; break; case LatteConst::ShaderType::Geometry: shaderAluConst = 0; // geometry shader has no ALU const shaderUniformRegisterOffset = mmSQ_GS_UNIFORM_BLOCK_START; - uniformBufferDirtyMask = drawcallContext.gsUniformBufferDirtyMask; - drawcallContext.gsUniformBufferDirtyMask = 0; break; default: UNREACHABLE; } // sourced from uniform registers - if (hasDirtyAluConst) + if (aluConstDirty) { uint32* aluConstBase = LatteGPUState.contextRegister + mmSQ_ALU_CONSTANT0_0 + shaderAluConst; for (auto it : shader->list_remappedUniformEntries_register) @@ -238,112 +169,52 @@ bool LatteBufferCache_syncGPUUniformBuffers(LatteDecompilerShader* shader, const static sint32 s_vtxStateMaxIndex{}; static sint32 s_vtxStateMaxInstance{}; -// upload vertex and uniform buffers -bool LatteBufferCache_Sync(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount) +void LatteBufferCache_ProcessQueues() { static uint32 s_syncBufferCounter = 0; - s_vtxStateMaxIndex = maxIndex; - s_vtxStateMaxInstance = baseInstance + instanceCount - 1; s_syncBufferCounter++; - if (s_syncBufferCounter >= 20) + if (s_syncBufferCounter >= 25) { LatteBufferCache_incrementalCleanup(); s_syncBufferCounter = 0; } - LatteBufferCache_processDCFlushQueue(); // process queued deallocations from previous drawcall LatteBufferCache_processDeallocations(); - - // sync and bind vertex buffers - LatteFetchShader* parsedFetchShader = LatteSHRC_GetActiveFetchShader(); - if (!parsedFetchShader) - return false; - uint32* __restrict bufferRegStartPtr = LatteGPUState.contextRegister + mmSQ_VTX_ATTRIBUTE_BLOCK_START; - for (auto& bufferGroup : parsedFetchShader->bufferGroups) - { - uint32 bufferIndex = bufferGroup.attributeBufferIndex; - uint32* __restrict bufferRegs = bufferRegStartPtr + bufferIndex * 7; - MPTR bufferAddress = bufferRegs[0]; - /* uint32 bufferSize = bufferRegs[1] + 1; */ - uint32 bufferStride = (bufferRegs[2] >> 11) & 0xFFFF; - - if (bufferAddress == MPTR_NULL) [[unlikely]] - { - g_renderer->buffer_bindVertexBuffer(bufferIndex, 0, 0); - continue; - } - - // dont rely on buffer size given by game - uint32 fixedBufferSize = 0; - if (bufferGroup.hasVtxIndexAccess) - fixedBufferSize = bufferStride * (maxIndex + 1) + bufferGroup.maxOffset; - if (bufferGroup.hasInstanceIndexAccess) - { - uint32 fixedBufferSizeInstance = bufferStride * ((baseInstance + instanceCount) + 1) + bufferGroup.maxOffset; - fixedBufferSize = std::max(fixedBufferSize, fixedBufferSizeInstance); - } - if (fixedBufferSize == 0 || bufferStride == 0) - fixedBufferSize += 128; - - -#if BOOST_OS_MACOS && defined(ENABLE_VULKAN) - if(bufferStride % 4 != 0) - { - if (g_renderer->GetType() == RendererAPI::Vulkan) - { - if (VulkanRenderer* vkRenderer = VulkanRenderer::GetInstance()) - { - auto fixedBuffer = vkRenderer->buffer_genStrideWorkaroundVertexBuffer(bufferAddress, fixedBufferSize, bufferStride); - vkRenderer->buffer_bindVertexStrideWorkaroundBuffer(fixedBuffer.first, fixedBuffer.second, bufferIndex, fixedBufferSize); - continue; - } - } - } -#endif - - uint32 bindOffset = LatteBufferCache_retrieveDataInCache(bufferAddress, fixedBufferSize); - g_renderer->buffer_bindVertexBuffer(bufferIndex, bindOffset, fixedBufferSize); - } - // sync uniform buffers - LatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader(); - LatteDecompilerShader* geometryShader = LatteSHRC_GetActiveGeometryShader(); - LatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader(); - if (vertexShader && vertexShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK) - LatteBufferCache_syncGPUUniformBuffers(vertexShader, mmSQ_VTX_UNIFORM_BLOCK_START, LatteConst::ShaderType::Vertex, 0xFFFFFFFF); - if (pixelShader && pixelShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK) - LatteBufferCache_syncGPUUniformBuffers(pixelShader, mmSQ_PS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Pixel, 0xFFFFFFFF); - if (geometryShader && geometryShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK) - LatteBufferCache_syncGPUUniformBuffers(geometryShader, mmSQ_GS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Geometry, 0xFFFFFFFF); - return true; } -// similar to LatteBufferCache_SyncIncremental but updates only the bindings that are marked in the dirty masks -void LatteBufferCache_SyncIncremental(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount, const LatteDrawcallContext& drawcallContext, uint8& stageUniformModifiedMask) +// upload vertex and uniform buffers and update bindings +void LatteBufferCache_Sync(uint32 minIndex, uint32 maxIndex, uint32 baseInstance, uint32 instanceCount, uint32 attribBufferDirtyMask, uint32 vsUniformBufferDirtyMask, uint32 psUniformBufferDirtyMask, uint32 gsUniformBufferDirtyMask, uint8& stageUniformModifiedMask, bool isIncremental) { - // uint32 attribBufferDirtyMask, uint32 uniformBufferVSDirtyMask, uint32 uniformBufferPSDirtyMask, uint32 uniformBufferGSDirtyMask LatteFetchShader* parsedFetchShader = LatteSHRC_GetActiveFetchShader(); cemu_assert_debug(parsedFetchShader); - uint32 attribBufferDirtyMask = drawcallContext.vertexBufferDirtyMask; - if ( maxIndex > s_vtxStateMaxIndex ) + // todo - vertex attribute offsets may eventually be allowed to change between incremental draws, we should set the attrib dirty bits in that case + if (isIncremental) { - attribBufferDirtyMask = 0xFFFFFFFF; - // todo - if the fetch shader can change between incremental calls, then we should also mark all of drawcallContext.vertexBufferDirtyMask as dirty. Or we could track the count per-buffer instead of as max index and max instance - // but for simplicity sake we should disallow fetch shader changes that use a differing set of buffers (this is already the case) - s_vtxStateMaxIndex = maxIndex; + // dont process flush queue and dont process deallocations yet, we are in the middle of a sequence of drawcalls that (most likely) reuse previous bindings + if ( maxIndex > s_vtxStateMaxIndex ) + { + attribBufferDirtyMask = 0xFFFFFFFF; + s_vtxStateMaxIndex = maxIndex; + } + uint32 maxInstance = baseInstance + instanceCount - 1; + if ( maxInstance > s_vtxStateMaxInstance ) + { + attribBufferDirtyMask = 0xFFFFFFFF; + s_vtxStateMaxInstance = maxInstance; + } } - uint32 maxInstance = baseInstance + instanceCount - 1; - if ( maxInstance > s_vtxStateMaxInstance ) + else { - attribBufferDirtyMask = 0xFFFFFFFF; + LatteBufferCache_ProcessQueues(); + s_vtxStateMaxIndex = maxIndex; + uint32 maxInstance = baseInstance + instanceCount - 1; s_vtxStateMaxInstance = maxInstance; } attribBufferDirtyMask &= parsedFetchShader->attributeBufferMask; - // dont process flush queue and dont process deallocations yet, we are in the middle of a sequence of drawcalls that (most likely) reuse previous bindings - // sync and bind dirty vertex buffers if (attribBufferDirtyMask != 0) { @@ -353,7 +224,6 @@ void LatteBufferCache_SyncIncremental(uint32 minIndex, uint32 maxIndex, uint32 b uint32 bufferIndex = bufferGroup.attributeBufferIndex; if ((attribBufferDirtyMask&(1<> 11) & 0xFFFF; @@ -403,17 +273,17 @@ void LatteBufferCache_SyncIncremental(uint32 minIndex, uint32 maxIndex, uint32 b // todo - if we AND the shader uniform buffer mask and the dirty mask we can completely skip calling syncGPUUniformBuffers if no relevant buffer was updated if (vertexShader && vertexShader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK) { - if (LatteBufferCache_syncGPUUniformBuffers(vertexShader, mmSQ_VTX_UNIFORM_BLOCK_START, LatteConst::ShaderType::Vertex, drawcallContext.vsUniformBufferDirtyMask)) + if (LatteBufferCache_syncGPUUniformBuffers(vertexShader, mmSQ_VTX_UNIFORM_BLOCK_START, LatteConst::ShaderType::Vertex, vsUniformBufferDirtyMask)) stageUniformModifiedMask |= (1<uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK) { - if (LatteBufferCache_syncGPUUniformBuffers(pixelShader, mmSQ_PS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Pixel, drawcallContext.psUniformBufferDirtyMask)) + if (LatteBufferCache_syncGPUUniformBuffers(pixelShader, mmSQ_PS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Pixel, psUniformBufferDirtyMask)) stageUniformModifiedMask |= (1<uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CBANK) { - if ( LatteBufferCache_syncGPUUniformBuffers(geometryShader, mmSQ_GS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Geometry, drawcallContext.gsUniformBufferDirtyMask) ) + if ( LatteBufferCache_syncGPUUniformBuffers(geometryShader, mmSQ_GS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Geometry, gsUniformBufferDirtyMask) ) stageUniformModifiedMask |= (1<uniform.loc_remapped >= 0) { - LatteBufferCache_LoadRemappedUniforms(shader, GET_UNIFORM_DATA_PTR(shader->uniform.loc_remapped)); + LatteBufferCache_LoadRemappedUniforms(shader, GET_UNIFORM_DATA_PTR(shader->uniform.loc_remapped), true, (1<uniform.loc_uniformRegister >= 0) { diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp index 74d93190..56d7a8aa 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp @@ -975,7 +975,8 @@ void OpenGLRenderer::draw_genericDrawHandler(uint32 baseVertex, uint32 baseInsta endPerfMonProfiling(performanceMonitor.gpuTime_dcStageIndexMgr); // synchronize vertex and uniform buffers - LatteBufferCache_Sync(indexState.minIndex + baseVertex, indexState.maxIndex + baseVertex, baseInstance, instanceCount); + uint8 stageUniformModifiedMask = 0; + LatteBufferCache_Sync(indexState.minIndex + baseVertex, indexState.maxIndex + baseVertex, baseInstance, instanceCount, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, stageUniformModifiedMask); _setupVertexAttributes(); diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererUniformData.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererUniformData.cpp index 656536df..e3d85215 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererUniformData.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererUniformData.cpp @@ -36,7 +36,7 @@ void OpenGLRenderer::uniformData_update() auto& list_uniformMapping = shader->list_remappedUniformEntries; cemu_assert_debug(list_uniformMapping.size() <= 256); sint32 remappedArraySize = (sint32)list_uniformMapping.size(); - LatteBufferCache_LoadRemappedUniforms(shader, (float*)(_gl_remappedUniformData)); + LatteBufferCache_LoadRemappedUniforms(shader, (float*)(_gl_remappedUniformData), true, (1< 0) { diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h index 94c94f67..dc90eb09 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h @@ -563,7 +563,7 @@ private: // uniform uint32 uniformData_uploadUniformDataBufferGetOffset(std::span data); void uniformData_updateUniformVars(uint32 shaderStageIndex, LatteDecompilerShader* shader, float* __restrict uniformBuf); - void uniformData_updateUniformVarsIncremental(uint32 shaderStageIndex, LatteDecompilerShader* shader, const LatteDrawcallContext& drawcallContext, uint8& stageUniformModifiedMask, float* __restrict uniformBuf); + void uniformData_updateUniformVarsIncremental(uint32 shaderStageIndex, LatteDecompilerShader* shader, uint8& stageUniformModifiedMask, float* __restrict uniformBuf, bool aluConstDirty, uint32 uniformBufferDirtyMask); // misc void CreatePipelineCache(); diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp index f9b1f714..11314581 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp @@ -405,7 +405,7 @@ void VulkanRenderer::uniformData_updateUniformVars(uint32 shaderStageIndex, Latt } if (shader->uniform.loc_remapped >= 0) { - LatteBufferCache_LoadRemappedUniforms(shader, GET_UNIFORM_DATA_PTR(shader->uniform.loc_remapped)); + LatteBufferCache_LoadRemappedUniforms(shader, GET_UNIFORM_DATA_PTR(shader->uniform.loc_remapped), true, (1<uniform.loc_uniformRegister >= 0) { @@ -454,7 +454,7 @@ void VulkanRenderer::uniformData_updateUniformVars(uint32 shaderStageIndex, Latt dynamicOffsetInfo.uniformVarBufferOffset[shaderStageIndex] = uniformData_uploadUniformDataBufferGetOffset({(uint8*)uniformBuf, shader->uniform.uniformRangeSize}); } -void VulkanRenderer::uniformData_updateUniformVarsIncremental(uint32 shaderStageIndex, LatteDecompilerShader* shader, const LatteDrawcallContext& drawcallContext, uint8& stageUniformModifiedMask, float* __restrict uniformBuf) +void VulkanRenderer::uniformData_updateUniformVarsIncremental(uint32 shaderStageIndex, LatteDecompilerShader* shader, uint8& stageUniformModifiedMask, float* __restrict uniformBuf, bool aluConstDirty, uint32 uniformBufferDirtyMask) { // similar to uniformData_updateUniformVars, but checks only the fields that can change during a fast draw sequence auto GET_UNIFORM_DATA_PTR = [&uniformBuf](size_t index) { return uniformBuf + (index / 4); }; @@ -470,22 +470,19 @@ void VulkanRenderer::uniformData_updateUniformVarsIncremental(uint32 shaderStage if (shader->uniform.loc_remapped >= 0) { cemu_assert_debug(shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_REMAPPED); - hasChange = LatteBufferCache_LoadRemappedUniformsIncremental(shader, GET_UNIFORM_DATA_PTR(shader->uniform.loc_remapped), drawcallContext); + hasChange = LatteBufferCache_LoadRemappedUniforms(shader, GET_UNIFORM_DATA_PTR(shader->uniform.loc_remapped), aluConstDirty, uniformBufferDirtyMask); } - if (shader->uniform.loc_uniformRegister >= 0) + if (shader->uniform.loc_uniformRegister >= 0 && aluConstDirty) { cemu_assert_debug(shader->uniformMode == LATTE_DECOMPILER_UNIFORM_MODE_FULL_CFILE); - bool isDirty = false; sint32 shaderAluConst; switch (shader->shaderType) { case LatteConst::ShaderType::Vertex: shaderAluConst = 0x400; - isDirty = drawcallContext.aluConstVSDirty; break; case LatteConst::ShaderType::Pixel: shaderAluConst = 0; - isDirty = drawcallContext.aluConstPSDirty; break; case LatteConst::ShaderType::Geometry: cemu_assert_suspicious(); @@ -495,12 +492,9 @@ void VulkanRenderer::uniformData_updateUniformVarsIncremental(uint32 shaderStage default: UNREACHABLE; } - if (isDirty) - { - hasChange = true; - uint32* uniformRegData = (uint32*)(LatteGPUState.contextRegister + mmSQ_ALU_CONSTANT0_0 + shaderAluConst); - memcpy(GET_UNIFORM_DATA_PTR(shader->uniform.loc_uniformRegister), uniformRegData, shader->uniform.count_uniformRegister * 16); - } + hasChange = true; + uint32* uniformRegData = (uint32*)(LatteGPUState.contextRegister + mmSQ_ALU_CONSTANT0_0 + shaderAluConst); + memcpy(GET_UNIFORM_DATA_PTR(shader->uniform.loc_uniformRegister), uniformRegData, shader->uniform.count_uniformRegister * 16); } if (hasChange) { @@ -1417,7 +1411,8 @@ void VulkanRenderer::draw_execute_first(uint32 baseVertex, uint32 baseInstance, else { // synchronize vertex and uniform cache and update buffer bindings - LatteBufferCache_Sync(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount); + uint8 stageUniformModifiedMask = 0; + LatteBufferCache_Sync(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, stageUniformModifiedMask); } PipelineInfo* pipeline_info = draw_getOrCreateGraphicsPipeline(count); @@ -1529,13 +1524,11 @@ void VulkanRenderer::draw_execute_continued(uint32 baseVertex, uint32 baseInstan uint8 stageUniformModifiedMask = 0; // one bit for each stage (using SHADER_STAGE_INDEX_* as bit index). Set if any uniform data has been modified and needs to be reuploaded if (vertexShader) - uniformData_updateUniformVarsIncremental(VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX, vertexShader, drawcallContext, stageUniformModifiedMask, s_vkUniformDataVS); + uniformData_updateUniformVarsIncremental(VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX, vertexShader, stageUniformModifiedMask, s_vkUniformDataVS, drawcallContext.aluConstVSDirty, drawcallContext.vsUniformBufferDirtyMask); if (pixelShader) - uniformData_updateUniformVarsIncremental(VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT, pixelShader, drawcallContext, stageUniformModifiedMask, s_vkUniformDataPS); + uniformData_updateUniformVarsIncremental(VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT, pixelShader, stageUniformModifiedMask, s_vkUniformDataPS, drawcallContext.aluConstPSDirty, drawcallContext.psUniformBufferDirtyMask); if (geometryShader) - uniformData_updateUniformVarsIncremental(VulkanRendererConst::SHADER_STAGE_INDEX_GEOMETRY, geometryShader, drawcallContext, stageUniformModifiedMask, s_vkUniformDataGS); - drawcallContext.aluConstVSDirty = false; - drawcallContext.aluConstPSDirty = false; + uniformData_updateUniformVarsIncremental(VulkanRendererConst::SHADER_STAGE_INDEX_GEOMETRY, geometryShader, stageUniformModifiedMask, s_vkUniformDataGS, false, drawcallContext.gsUniformBufferDirtyMask); // store where the read pointer should go after command buffer execution m_cmdBufferUniformRingbufIndices[m_commandBufferIndex] = m_uniformVarBufferWriteIndex; @@ -1587,7 +1580,7 @@ void VulkanRenderer::draw_execute_continued(uint32 baseVertex, uint32 baseInstan else { // synchronize vertex and uniform cache and update buffer bindings - LatteBufferCache_SyncIncremental(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount, drawcallContext, stageUniformModifiedMask); + LatteBufferCache_Sync(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount, drawcallContext.vertexBufferDirtyMask, drawcallContext.vsUniformBufferDirtyMask, drawcallContext.psUniformBufferDirtyMask, drawcallContext.gsUniformBufferDirtyMask, stageUniformModifiedMask, true); } m_state.descriptorSetsChanged = false;