Permalink
Browse files

If the first renderpass is an empty clear, merge it into the next one…

… that touches the same framebuffer. Works around #10723 in Wipeout.
  • Loading branch information...
hrydgard committed Mar 16, 2018
1 parent 3cd92b4 commit df8dac4aae74e52aae1eeb3d7ede5ce81fbffa03
Showing with 36 additions and 2 deletions.
  1. +35 −2 ext/native/thin3d/VulkanQueueRunner.cpp
  2. +1 −0 ext/native/thin3d/VulkanQueueRunner.h
@@ -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;
}
}
}
@@ -82,6 +82,7 @@ struct VkRenderData {
enum class VKRStepType : uint8_t {
RENDER,
RENDER_SKIP,
COPY,
BLIT,
READBACK,

0 comments on commit df8dac4

Please sign in to comment.