From 45eedb4cd3e03719e0b3754f6642a9a4547ea7c6 Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Mon, 15 Jun 2026 21:12:45 +0200 Subject: [PATCH] Vulkan: Separate function for continued drawcalls --- src/Cafe/HW/Latte/Core/Latte.h | 9 + .../HW/Latte/Core/LatteCommandProcessor.cpp | 14 +- .../HW/Latte/Renderer/Metal/MetalRenderer.cpp | 2 +- .../HW/Latte/Renderer/Metal/MetalRenderer.h | 2 +- .../HW/Latte/Renderer/OpenGL/OpenGLRenderer.h | 2 +- .../Renderer/OpenGL/OpenGLRendererCore.cpp | 4 +- src/Cafe/HW/Latte/Renderer/Renderer.h | 2 +- .../HW/Latte/Renderer/Vulkan/VulkanRenderer.h | 6 +- .../Renderer/Vulkan/VulkanRendererCore.cpp | 216 +++++++++++++++--- 9 files changed, 215 insertions(+), 42 deletions(-) diff --git a/src/Cafe/HW/Latte/Core/Latte.h b/src/Cafe/HW/Latte/Core/Latte.h index b6ff6ba0..9a243eae 100644 --- a/src/Cafe/HW/Latte/Core/Latte.h +++ b/src/Cafe/HW/Latte/Core/Latte.h @@ -70,6 +70,15 @@ struct LatteGPUState_t extern LatteGPUState_t LatteGPUState; +// drawcall context + +struct LatteDrawcallContext +{ + bool isFirst{}; // first _execute() in current sequence + // these are only valid if isFirst is false: + // todo +}; + // texture #include "Cafe/HW/Latte/Core/LatteTexture.h" diff --git a/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp b/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp index 4a5fd480..32c7f387 100644 --- a/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp +++ b/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp @@ -1,10 +1,8 @@ #include "Cafe/HW/Latte/ISA/RegDefines.h" #include "Cafe/OS/libs/gx2/GX2.h" // for write gatherer and special state. Get rid of dependency -#include "Cafe/OS/libs/gx2/GX2_Misc.h" // for GX2::sGX2MainCoreIndex. Legacy dependency #include "Cafe/OS/libs/gx2/GX2_Event.h" // for notification callbacks #include "Cafe/HW/Latte/Renderer/Renderer.h" #include "Cafe/HW/Latte/Core/Latte.h" -#include "Cafe/HW/Latte/Core/LatteDraw.h" #include "Cafe/HW/Latte/Core/LatteShader.h" #include "Cafe/HW/Latte/Core/LatteAsyncCommands.h" #include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h" @@ -53,7 +51,7 @@ public: void beginDrawPass() { m_drawPassActive = true; - m_isFirstDraw = true; + m_drawcallContext.isFirst = true; m_vertexBufferChanged = true; m_uniformBufferChanged = true; g_renderer->draw_beginSequence(); @@ -71,16 +69,16 @@ public: if (physIndices == MPTR_NULL) return; auto indexType = LatteGPUState.contextNew.VGT_DMA_INDEX_TYPE.get_INDEX_TYPE(); - g_renderer->draw_execute(baseVertex, baseInstance, numInstances, count, physIndices, indexType, m_isFirstDraw); + g_renderer->draw_execute(baseVertex, baseInstance, numInstances, count, physIndices, indexType, m_drawcallContext); } else { - g_renderer->draw_execute(baseVertex, baseInstance, numInstances, count, MPTR_NULL, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE::AUTO, m_isFirstDraw); + g_renderer->draw_execute(baseVertex, baseInstance, numInstances, count, MPTR_NULL, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE::AUTO, m_drawcallContext); } performanceMonitor.cycle[performanceMonitor.cycleIndex].drawCallCounter++; - if (!m_isFirstDraw) + if (!m_drawcallContext.isFirst) performanceMonitor.cycle[performanceMonitor.cycleIndex].fastDrawCallCounter++; - m_isFirstDraw = false; + m_drawcallContext.isFirst = false; m_vertexBufferChanged = false; m_uniformBufferChanged = false; } @@ -121,7 +119,7 @@ public: private: bool m_drawPassActive{ false }; - bool m_isFirstDraw{false}; + LatteDrawcallContext m_drawcallContext{}; bool m_vertexBufferChanged{ false }; bool m_uniformBufferChanged{ false }; boost::container::static_vector m_queuePosStack; diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp index b27e3aeb..a8f0a8f1 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.cpp @@ -1067,7 +1067,7 @@ void MetalRenderer::draw_beginSequence() m_state.m_skipDrawSequence = true; } -void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) +void MetalRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, const LatteDrawcallContext& drawcallContext) { if (m_state.m_skipDrawSequence) { diff --git a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h index e905b834..eadad94f 100644 --- a/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h @@ -250,7 +250,7 @@ public: // core drawing logic void draw_beginSequence() override; - void draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) override; + void draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, const LatteDrawcallContext& drawcallContext) override; void draw_endSequence() override; void draw_updateVertexBuffersDirectAccess(); diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h index 5b9ccd41..f691d8da 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRenderer.h @@ -159,7 +159,7 @@ public: void draw_init(); void draw_beginSequence() override; - void draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) override; + void draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, const LatteDrawcallContext& drawcallContext) override; void draw_endSequence() override; template diff --git a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp index c9437353..74d93190 100644 --- a/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp +++ b/src/Cafe/HW/Latte/Renderer/OpenGL/OpenGLRendererCore.cpp @@ -1148,9 +1148,9 @@ void OpenGLRenderer::draw_beginSequence() // no-op } -void OpenGLRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) +void OpenGLRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, const LatteDrawcallContext& drawcallContext) { - bool isMinimal = !isFirst; + bool isMinimal = !drawcallContext.isFirst; if (isMinimal) draw_genericDrawHandler(baseVertex, baseInstance, instanceCount, count, indexDataMPTR, indexType); else diff --git a/src/Cafe/HW/Latte/Renderer/Renderer.h b/src/Cafe/HW/Latte/Renderer/Renderer.h index 01a6d3b2..6a792fa2 100644 --- a/src/Cafe/HW/Latte/Renderer/Renderer.h +++ b/src/Cafe/HW/Latte/Renderer/Renderer.h @@ -140,7 +140,7 @@ public: // core drawing logic virtual void draw_beginSequence() = 0; - virtual void draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) = 0; + virtual void draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, const LatteDrawcallContext& drawcallContext) = 0; virtual void draw_endSequence() = 0; // index diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h index b44e7232..d6b1f889 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h @@ -530,7 +530,7 @@ private: void draw_endRenderPass(); void draw_beginSequence() override; - void draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) override; + void draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, const LatteDrawcallContext& drawcallContext) override; void draw_endSequence() override; void draw_updateVertexBuffersDirectAccess(); @@ -663,6 +663,10 @@ private: uint32 m_submitThreshold{}; // submit current buffer if recordedDrawcalls exceeds this number bool m_submitOnIdle{}; // submit current buffer if Latte command processor goes into idle state (no more commands or waiting for externally signaled condition) + // drawcall handling + void draw_execute_first(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, const LatteDrawcallContext& drawcallContext); + void draw_execute_continued(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, const LatteDrawcallContext& drawcallContext); + // tracking for dynamic offsets struct { diff --git a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp index e32fdb78..25a1a70e 100644 --- a/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp +++ b/src/Cafe/HW/Latte/Renderer/Vulkan/VulkanRendererCore.cpp @@ -1302,11 +1302,177 @@ void VulkanRenderer::draw_beginSequence() m_state.drawSequenceSkip = true; } -void VulkanRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, bool isFirst) +void VulkanRenderer::draw_execute_first(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, const LatteDrawcallContext& drawcallContext) +{ + if (m_state.drawSequenceSkip) + { + return; + } + + // fast clear color as depth + if (LatteGPUState.contextNew.GetSpecialStateValues()[8] != 0) + { + LatteDraw_handleSpecialState8_clearAsDepth(); + return; + } + else if (LatteGPUState.contextNew.GetSpecialStateValues()[5] != 0) + { + draw_handleSpecialState5(); + return; + } + + // prepare streamout + m_streamoutState.verticesPerInstance = count; + LatteStreamout_PrepareDrawcall(count, instanceCount); + + // update uniform vars + LatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader(); + LatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader(); + LatteDecompilerShader* geometryShader = LatteSHRC_GetActiveGeometryShader(); + + if (vertexShader) + uniformData_updateUniformVars(VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX, vertexShader); + if (pixelShader) + uniformData_updateUniformVars(VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT, pixelShader); + if (geometryShader) + uniformData_updateUniformVars(VulkanRendererConst::SHADER_STAGE_INDEX_GEOMETRY, geometryShader); + // store where the read pointer should go after command buffer execution + m_cmdBufferUniformRingbufIndices[m_commandBufferIndex] = m_uniformVarBufferWriteIndex; + + // process index data + const LattePrimitiveMode primitiveMode = static_cast(LatteGPUState.contextRegister[mmVGT_PRIMITIVE_TYPE]); + + Renderer::INDEX_TYPE hostIndexType; + uint32 hostIndexCount; + uint32 indexMin = 0; + uint32 indexMax = 0; + Renderer::IndexAllocation indexAllocation; + LatteIndices_decode(memory_getPointerFromVirtualOffset(indexDataMPTR), indexType, count, primitiveMode, indexMin, indexMax, hostIndexType, hostIndexCount, indexAllocation); + VKRSynchronizedHeapAllocator::AllocatorReservation* indexReservation = (VKRSynchronizedHeapAllocator::AllocatorReservation*)indexAllocation.rendererInternal; + // update index binding + if (hostIndexType != INDEX_TYPE::NONE) + { + uint32 indexBufferIndex = indexReservation->bufferIndex; + uint32 indexBufferOffset = indexReservation->bufferOffset; + if (m_state.activeIndexBufferOffset != indexBufferOffset || m_state.activeIndexBufferIndex != indexBufferIndex || m_state.activeIndexType != hostIndexType) + { + m_state.activeIndexType = hostIndexType; + m_state.activeIndexBufferOffset = indexBufferOffset; + m_state.activeIndexBufferIndex = indexBufferIndex; + VkIndexType vkType; + if (hostIndexType == INDEX_TYPE::U16) + vkType = VK_INDEX_TYPE_UINT16; + else if (hostIndexType == INDEX_TYPE::U32) + vkType = VK_INDEX_TYPE_UINT32; + else + cemu_assert(false); + vkCmdBindIndexBuffer(m_state.currentCommandBuffer, indexReservation->vkBuffer, indexBufferOffset, vkType); + } + } + + if (m_useHostMemoryForCache) + { + // direct memory access (Wii U memory space imported as a Vulkan buffer), update buffer bindings + draw_updateVertexBuffersDirectAccess(); + LatteDecompilerShader* vertexShader = LatteSHRC_GetActiveVertexShader(); + if (vertexShader) + draw_updateUniformBuffersDirectAccess(vertexShader, mmSQ_VTX_UNIFORM_BLOCK_START, LatteConst::ShaderType::Vertex); + LatteDecompilerShader* geometryShader = LatteSHRC_GetActiveGeometryShader(); + if (geometryShader) + draw_updateUniformBuffersDirectAccess(geometryShader, mmSQ_GS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Geometry); + LatteDecompilerShader* pixelShader = LatteSHRC_GetActivePixelShader(); + if (pixelShader) + draw_updateUniformBuffersDirectAccess(pixelShader, mmSQ_PS_UNIFORM_BLOCK_START, LatteConst::ShaderType::Pixel); + } + else + { + // synchronize vertex and uniform cache and update buffer bindings + LatteBufferCache_Sync(indexMin + baseVertex, indexMax + baseVertex, baseInstance, instanceCount); + } + + PipelineInfo* pipeline_info = draw_getOrCreateGraphicsPipeline(count); + m_state.activePipelineInfo = pipeline_info; + + auto vkObjPipeline = pipeline_info->m_vkrObjPipeline; + if (vkObjPipeline->GetPipeline() == VK_NULL_HANDLE) + { + // invalid/uninitialized pipeline + m_state.activeVertexDS = nullptr; + return; + } + + VkDescriptorSetInfo *vertexDS = nullptr, *pixelDS = nullptr, *geometryDS = nullptr; + draw_prepareDescriptorSets(pipeline_info, vertexDS, pixelDS, geometryDS); + m_state.activeVertexDS = vertexDS; + m_state.activePixelDS = pixelDS; + m_state.activeGeometryDS = geometryDS; + m_state.descriptorSetsChanged = true; + + draw_setRenderPass(); + + if (m_state.currentPipeline != vkObjPipeline->GetPipeline()) + { + vkCmdBindPipeline(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vkObjPipeline->GetPipeline()); + vkObjPipeline->flagForCurrentCommandBuffer(); + m_state.currentPipeline = vkObjPipeline->GetPipeline(); + // depth bias + if (pipeline_info->usesDepthBias) + draw_updateDepthBias(true); + } + else + { + if (pipeline_info->usesDepthBias) + draw_updateDepthBias(false); + } + // update blend constants + if (pipeline_info->usesBlendConstants) + draw_updateVkBlendConstants(); + // update descriptor sets + uint32_t dynamicOffsets[17 * 2]; + if (vertexDS && pixelDS) + { + // update vertex and pixel descriptor set in a single call to vkCmdBindDescriptorSets + sint32 numDynOffsetsVS; + sint32 numDynOffsetsPS; + draw_prepareDynamicOffsetsForDescriptorSet(VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX, dynamicOffsets, numDynOffsetsVS, pipeline_info); + draw_prepareDynamicOffsetsForDescriptorSet(VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT, dynamicOffsets + numDynOffsetsVS, numDynOffsetsPS, pipeline_info); + + VkDescriptorSet dsArray[2]; + dsArray[0] = vertexDS->m_vkObjDescriptorSet->descriptorSet; + dsArray[1] = pixelDS->m_vkObjDescriptorSet->descriptorSet; + + vkCmdBindDescriptorSets(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vkObjPipeline->m_pipelineLayout, 0, 2, dsArray, numDynOffsetsVS + numDynOffsetsPS, dynamicOffsets); + } + else if (vertexDS) + { + sint32 numDynOffsets; + draw_prepareDynamicOffsetsForDescriptorSet(VulkanRendererConst::SHADER_STAGE_INDEX_VERTEX, dynamicOffsets, numDynOffsets, pipeline_info); + vkCmdBindDescriptorSets(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vkObjPipeline->m_pipelineLayout, 0, 1, &vertexDS->m_vkObjDescriptorSet->descriptorSet, numDynOffsets, dynamicOffsets); + } + else if (pixelDS) + { + sint32 numDynOffsets; + draw_prepareDynamicOffsetsForDescriptorSet(VulkanRendererConst::SHADER_STAGE_INDEX_FRAGMENT, dynamicOffsets, numDynOffsets, pipeline_info); + vkCmdBindDescriptorSets(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vkObjPipeline->m_pipelineLayout, 1, 1, &pixelDS->m_vkObjDescriptorSet->descriptorSet, numDynOffsets, dynamicOffsets); + } + if (geometryDS) + { + sint32 numDynOffsets; + draw_prepareDynamicOffsetsForDescriptorSet(VulkanRendererConst::SHADER_STAGE_INDEX_GEOMETRY, dynamicOffsets, numDynOffsets, pipeline_info); + vkCmdBindDescriptorSets(m_state.currentCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, vkObjPipeline->m_pipelineLayout, 2, 1, &geometryDS->m_vkObjDescriptorSet->descriptorSet, numDynOffsets, dynamicOffsets); + } + // draw + if (hostIndexType != INDEX_TYPE::NONE) + vkCmdDrawIndexed(m_state.currentCommandBuffer, hostIndexCount, instanceCount, 0, baseVertex, baseInstance); + else + vkCmdDraw(m_state.currentCommandBuffer, count, instanceCount, baseVertex, baseInstance); + LatteStreamout_FinishDrawcall(m_useHostMemoryForCache); +} + +void VulkanRenderer::draw_execute_continued(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, const LatteDrawcallContext& drawcallContext) { if (m_state.drawSequenceSkip) { - LatteGPUState.drawCallCounter++; return; } @@ -1314,13 +1480,11 @@ void VulkanRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 if (LatteGPUState.contextNew.GetSpecialStateValues()[8] != 0) { LatteDraw_handleSpecialState8_clearAsDepth(); - LatteGPUState.drawCallCounter++; return; } else if (LatteGPUState.contextNew.GetSpecialStateValues()[5] != 0) { draw_handleSpecialState5(); - LatteGPUState.drawCallCounter++; return; } @@ -1394,31 +1558,23 @@ void VulkanRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 } PipelineInfo* pipeline_info; - - if (!isFirst) + // recalculate the part of the pipeline hash that can change during fast draws + if (m_state.activePipelineInfo->minimalStateHash != draw_calculateMinimalGraphicsPipelineHash(vertexShader->compatibleFetchShader, LatteGPUState.contextNew)) { - if (m_state.activePipelineInfo->minimalStateHash != draw_calculateMinimalGraphicsPipelineHash(vertexShader->compatibleFetchShader, LatteGPUState.contextNew)) - { - // pipeline changed - pipeline_info = draw_getOrCreateGraphicsPipeline(count); - m_state.activePipelineInfo = pipeline_info; - } - else - { - pipeline_info = m_state.activePipelineInfo; -#ifdef CEMU_DEBUG_ASSERT - auto pipeline_info2 = draw_getOrCreateGraphicsPipeline(count); - if (pipeline_info != pipeline_info2) - { - cemu_assert_debug(false); - } -#endif - } + // pipeline changed + pipeline_info = draw_getOrCreateGraphicsPipeline(count); + m_state.activePipelineInfo = pipeline_info; } else { - pipeline_info = draw_getOrCreateGraphicsPipeline(count); - m_state.activePipelineInfo = pipeline_info; + pipeline_info = m_state.activePipelineInfo; +#ifdef CEMU_DEBUG_ASSERT + auto pipeline_info2 = draw_getOrCreateGraphicsPipeline(count); + if (pipeline_info != pipeline_info2) + { + cemu_assert_debug(false); + } +#endif } auto vkObjPipeline = pipeline_info->m_vkrObjPipeline; @@ -1429,9 +1585,8 @@ void VulkanRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 return; } - VkDescriptorSetInfo *vertexDS = nullptr, *pixelDS = nullptr, *geometryDS = nullptr; - if (!isFirst && m_state.activeVertexDS) + if (m_state.activeVertexDS) { vertexDS = m_state.activeVertexDS; pixelDS = m_state.activePixelDS; @@ -1510,7 +1665,14 @@ void VulkanRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 vkCmdDraw(m_state.currentCommandBuffer, count, instanceCount, baseVertex, baseInstance); LatteStreamout_FinishDrawcall(m_useHostMemoryForCache); +} +void VulkanRenderer::draw_execute(uint32 baseVertex, uint32 baseInstance, uint32 instanceCount, uint32 count, MPTR indexDataMPTR, Latte::LATTE_VGT_DMA_INDEX_TYPE::E_INDEX_TYPE indexType, const LatteDrawcallContext& drawcallContext) +{ + if (drawcallContext.isFirst) + draw_execute_first(baseVertex, baseInstance, instanceCount, count, indexDataMPTR, indexType, drawcallContext); + else + draw_execute_continued(baseVertex, baseInstance, instanceCount, count, indexDataMPTR, indexType, drawcallContext); LatteGPUState.drawCallCounter++; }