From 954f93046fec2caf8adc3beb90e4c100b5403b67 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 3 May 2018 07:05:36 -0700 Subject: [PATCH] Vulkan: Keep state on Clear cmds when used later. This also removes duplicate state - for example our UI has some duplicate Scissor commands. --- ext/native/thin3d/VulkanQueueRunner.cpp | 7 +++ ext/native/thin3d/VulkanQueueRunner.h | 1 + ext/native/thin3d/VulkanRenderManager.cpp | 75 ++++++++++++++++++++++- 3 files changed, 82 insertions(+), 1 deletion(-) diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 2737ff59ee..8ecbdbba86 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -611,6 +611,10 @@ void VulkanQueueRunner::LogRenderPass(const VKRStep &pass) { ILOG("RenderPass Begin(%x)", fb); for (auto &cmd : pass.commands) { switch (cmd.cmd) { + case VKRRenderCommand::REMOVED: + ILOG(" REMOVED"); + break; + case VKRRenderCommand::BIND_PIPELINE: ILOG(" BindPipeline(%x)", (int)(intptr_t)cmd.pipeline.pipeline); break; @@ -733,6 +737,9 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c for (const auto &c : commands) { switch (c.cmd) { + case VKRRenderCommand::REMOVED: + break; + case VKRRenderCommand::BIND_PIPELINE: if (c.pipeline.pipeline != lastPipeline) { vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.pipeline.pipeline); diff --git a/ext/native/thin3d/VulkanQueueRunner.h b/ext/native/thin3d/VulkanQueueRunner.h index d743bda730..8d5b229139 100644 --- a/ext/native/thin3d/VulkanQueueRunner.h +++ b/ext/native/thin3d/VulkanQueueRunner.h @@ -16,6 +16,7 @@ enum { }; enum class VKRRenderCommand : uint8_t { + REMOVED, BIND_PIPELINE, STENCIL, BLEND, diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 9e965ed3f4..a68467b04a 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -1,3 +1,4 @@ +#include #include #include "Common/Log.h" @@ -612,6 +613,70 @@ bool VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) { return true; } +static void RemoveDrawCommands(std::vector *cmds) { + // Here we remove any DRAW type commands when we hit a CLEAR. + cmds->erase(std::remove_if(cmds->begin(), cmds->end(), [](const VkRenderData &data) { + return data.cmd == VKRRenderCommand::DRAW || data.cmd == VKRRenderCommand::DRAW_INDEXED; + }), cmds->end()); +} + +static void CleanupRenderCommands(std::vector *cmds) { + size_t lastCommand[256]; + memset(lastCommand, -1, sizeof(lastCommand)); + + // Find any duplicate state commands (likely from RemoveDrawCommands.) + for (size_t i = 0; i < cmds->size(); ++i) { + auto &c = cmds->at(i); + auto &lastOfCmd = lastCommand[(uint8_t)c.cmd]; + + switch (c.cmd) { + case VKRRenderCommand::REMOVED: + // Ignore, in case some other code starts using this. + continue; + + case VKRRenderCommand::BIND_PIPELINE: + case VKRRenderCommand::VIEWPORT: + case VKRRenderCommand::SCISSOR: + case VKRRenderCommand::BLEND: + case VKRRenderCommand::STENCIL: + if (lastOfCmd != -1) { + cmds->at(lastOfCmd).cmd = VKRRenderCommand::REMOVED; + } + break; + + case VKRRenderCommand::PUSH_CONSTANTS: + // TODO: For now, we have to keep this one (it has an offset.) Still update lastCommand. + break; + + case VKRRenderCommand::CLEAR: + // Ignore, doesn't participate in state. + continue; + + case VKRRenderCommand::DRAW_INDEXED: + case VKRRenderCommand::DRAW: + default: + // Boundary - must keep state before this. + memset(lastCommand, -1, sizeof(lastCommand)); + continue; + } + + lastOfCmd = i; + } + + // At this point, anything in lastCommand can be cleaned up too. + // Note that it's safe to remove the last unused PUSH_CONSTANTS here. + for (size_t i = 0; i < ARRAY_SIZE(lastCommand); ++i) { + auto &lastOfCmd = lastCommand[i]; + if (lastOfCmd != -1) { + cmds->at(lastOfCmd).cmd = VKRRenderCommand::REMOVED; + } + } + + cmds->erase(std::remove_if(cmds->begin(), cmds->end(), [](const VkRenderData &data) { + return data.cmd == VKRRenderCommand::REMOVED; + }), cmds->end()); +} + void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearStencil, int clearMask) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); if (!clearMask) @@ -628,7 +693,7 @@ void VulkanRenderManager::Clear(uint32_t clearColor, float clearZ, int clearSten // In case there were commands already. curRenderStep_->render.numDraws = 0; - curRenderStep_->commands.clear(); + RemoveDrawCommands(&curRenderStep_->commands); } else { VkRenderData data{ VKRRenderCommand::CLEAR }; data.clear.clearColor = clearColor; @@ -738,6 +803,14 @@ VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, in void VulkanRenderManager::Finish() { curRenderStep_ = nullptr; + + // Let's do just a bit of cleanup on render commands now. + for (auto &step : steps_) { + if (step->stepType == VKRStepType::RENDER) { + CleanupRenderCommands(&step->commands); + } + } + int curFrame = vulkan_->GetCurFrame(); FrameData &frameData = frameData_[curFrame]; if (!useThread_) {