diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 235000821f..fdeafcd6b2 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -255,11 +255,39 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadActio void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, const std::vector &steps) { // Optimizes renderpasses, then sequences them. // Planned optimizations: - // * Push down empty "Clear/Store" renderpasses, and merge them with the first "Load/Store" to the same framebuffer. - // (These happen in Wipeout) // * Create copies of render target that are rendered to multiple times and textured from in sequence, and push those render passes // as early as possible in the frame (Wipeout billboards). + // Push down empty "Clear/Store" renderpasses, and merge them with the first "Load/Store" to the same framebuffer. + // Actually let's just bother with the first one for now. This affects Wipeout Pure. + if (steps.size() > 1 && steps[0]->stepType == VKRStepType::RENDER && + steps[0]->render.numDraws == 0 && + steps[0]->render.color == VKRRenderPassAction::CLEAR && + steps[0]->render.stencil == VKRRenderPassAction::CLEAR && + steps[0]->render.depth == VKRRenderPassAction::CLEAR) { + // Drop the first step, and merge it into the next step that touches the same framebuffer. + for (size_t i = 1; i < steps.size(); i++) { + if (steps[i]->stepType == VKRStepType::RENDER && + steps[i]->render.framebuffer == steps[0]->render.framebuffer) { + if (steps[i]->render.color != VKRRenderPassAction::CLEAR) { + steps[i]->render.color = VKRRenderPassAction::CLEAR; + steps[i]->render.clearColor = steps[0]->render.clearColor; + } + if (steps[i]->render.depth != VKRRenderPassAction::CLEAR) { + steps[i]->render.depth = VKRRenderPassAction::CLEAR; + steps[i]->render.clearDepth = steps[0]->render.clearDepth; + } + if (steps[i]->render.stencil != VKRRenderPassAction::CLEAR) { + steps[i]->render.stencil = VKRRenderPassAction::CLEAR; + steps[i]->render.clearStencil = steps[0]->render.clearStencil; + } + // Cheaply skip the first step. + steps[0]->stepType = VKRStepType::RENDER_SKIP; + break; + } + } + } + for (size_t i = 0; i < steps.size(); i++) { const VKRStep &step = *steps[i]; switch (step.stepType) { @@ -278,6 +306,8 @@ void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, const std::vector &steps) { case VKRStepType::READBACK_IMAGE: LogReadbackImage(step); break; + case VKRStepType::RENDER_SKIP: + ILOG("(skipped render pass)"); + break; } } } diff --git a/ext/native/thin3d/VulkanQueueRunner.h b/ext/native/thin3d/VulkanQueueRunner.h index 8257fa450a..f10326ff95 100644 --- a/ext/native/thin3d/VulkanQueueRunner.h +++ b/ext/native/thin3d/VulkanQueueRunner.h @@ -82,6 +82,7 @@ struct VkRenderData { enum class VKRStepType : uint8_t { RENDER, + RENDER_SKIP, COPY, BLIT, READBACK,