If the first renderpass is an empty clear, merge it into the next one that touches the same framebuffer. Works around #10723 in Wipeout.

This commit is contained in:
Henrik Rydgård
2018-03-16 13:44:56 +01:00
parent 3cd92b4d90
commit df8dac4aae
2 changed files with 36 additions and 2 deletions
+35 -2
View File
@@ -255,11 +255,39 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(VKRRenderPassAction colorLoadActio
void VulkanQueueRunner::RunSteps(VkCommandBuffer cmd, const std::vector<VKRStep *> &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<VKRStep
case VKRStepType::READBACK_IMAGE:
PerformReadbackImage(step, cmd);
break;
case VKRStepType::RENDER_SKIP:
break;
}
delete steps[i];
}
@@ -303,6 +333,9 @@ void VulkanQueueRunner::LogSteps(const std::vector<VKRStep *> &steps) {
case VKRStepType::READBACK_IMAGE:
LogReadbackImage(step);
break;
case VKRStepType::RENDER_SKIP:
ILOG("(skipped render pass)");
break;
}
}
}