Vulkan: Keep state on Clear cmds when used later.

This also removes duplicate state - for example our UI has some duplicate
Scissor commands.
This commit is contained in:
Unknown W. Brackets 2018-05-03 07:05:36 -07:00
parent 73d6446d72
commit 954f93046f
3 changed files with 82 additions and 1 deletions

View file

@ -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);

View file

@ -16,6 +16,7 @@ enum {
};
enum class VKRRenderCommand : uint8_t {
REMOVED,
BIND_PIPELINE,
STENCIL,
BLEND,

View file

@ -1,3 +1,4 @@
#include <algorithm>
#include <cstdint>
#include "Common/Log.h"
@ -612,6 +613,70 @@ bool VulkanRenderManager::InitDepthStencilBuffer(VkCommandBuffer cmd) {
return true;
}
static void RemoveDrawCommands(std::vector<VkRenderData> *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<VkRenderData> *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_) {