Skip to content

Commit

Permalink
Track and accumulate pipeline flags for render passes.
Browse files Browse the repository at this point in the history
(Information that will later let us make some interesting optimizations)
  • Loading branch information
hrydgard committed Oct 11, 2020
1 parent 4ff059d commit 5ece3de
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 34 deletions.
9 changes: 9 additions & 0 deletions Common/GPU/Vulkan/VulkanQueueRunner.h
Expand Up @@ -32,11 +32,19 @@ enum class VKRRenderCommand : uint8_t {
NUM_RENDER_COMMANDS,
};

enum PipelineFlags {
PIPELINE_FLAG_NONE = 0,
PIPELINE_FLAG_USES_LINES = (1 << 2),
PIPELINE_FLAG_USES_BLEND_CONSTANT = (1 << 3),
PIPELINE_FLAG_USES_DEPTH_STENCIL = (1 << 4), // Reads or writes the depth buffer.
};

struct VkRenderData {
VKRRenderCommand cmd;
union {
struct {
VkPipeline pipeline;
PipelineFlags flags;
} pipeline;
struct {
VkPipelineLayout pipelineLayout;
Expand Down Expand Up @@ -143,6 +151,7 @@ struct VKRStep {
int numReads;
VkImageLayout finalColorLayout;
VkImageLayout finalDepthStencilLayout;
u32 pipelineFlags;
} render;
struct {
VKRFramebuffer *src;
Expand Down
51 changes: 35 additions & 16 deletions Common/GPU/Vulkan/VulkanRenderManager.cpp
Expand Up @@ -524,6 +524,18 @@ VkCommandBuffer VulkanRenderManager::GetInitCmd() {
return frameData_[curFrame].initCmd;
}

void VulkanRenderManager::EndCurRenderStep() {
// Save the accumulated pipeline flags so we can use that to configure the render pass.
// We'll often be able to avoid loading/saving the depth/stencil buffer.
if (curRenderStep_) {
curRenderStep_->render.pipelineFlags = curPipelineFlags_;

// We no longer have a current render step.
curRenderStep_ = nullptr;
curPipelineFlags_ = 0;
}
}

void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, VKRRenderPassAction stencil, uint32_t clearColor, float clearDepth, uint8_t clearStencil, const char *tag) {
_dbg_assert_(insideFrame_);
// Eliminate dupes, instantly convert to a clear if possible.
Expand Down Expand Up @@ -568,15 +580,19 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR
}

// More redundant bind elimination.
if (curRenderStep_ && curRenderStep_->commands.size() == 0 && curRenderStep_->render.color != VKRRenderPassAction::CLEAR && curRenderStep_->render.depth != VKRRenderPassAction::CLEAR && curRenderStep_->render.stencil != VKRRenderPassAction::CLEAR) {
// Can trivially kill the last empty render step.
_dbg_assert_(steps_.back() == curRenderStep_);
delete steps_.back();
steps_.pop_back();
curRenderStep_ = nullptr;
}
if (curRenderStep_ && curRenderStep_->commands.size() == 0) {
VLOG("Empty render step. Usually happens after uploading pixels..");
if (curRenderStep_) {
if (curRenderStep_->commands.empty()) {
if (curRenderStep_->render.color != VKRRenderPassAction::CLEAR && curRenderStep_->render.depth != VKRRenderPassAction::CLEAR && curRenderStep_->render.stencil != VKRRenderPassAction::CLEAR) {
// Can trivially kill the last empty render step.
_dbg_assert_(steps_.back() == curRenderStep_);
delete steps_.back();
steps_.pop_back();
curRenderStep_ = nullptr;
}
VLOG("Empty render step. Usually happens after uploading pixels..");
}

EndCurRenderStep();
}

// Older Mali drivers have issues with depth and stencil don't match load/clear/etc.
Expand Down Expand Up @@ -649,6 +665,8 @@ bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, VkIma
}
}

EndCurRenderStep();

VKRStep *step = new VKRStep{ VKRStepType::READBACK };
step->readback.aspectMask = aspectBits;
step->readback.src = src;
Expand All @@ -658,8 +676,6 @@ bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, VkIma
step->tag = tag;
steps_.push_back(step);

curRenderStep_ = nullptr;

FlushSync();

Draw::DataFormat srcFormat = Draw::DataFormat::UNDEFINED;
Expand Down Expand Up @@ -704,6 +720,9 @@ bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, VkIma

void VulkanRenderManager::CopyImageToMemorySync(VkImage image, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag) {
_dbg_assert_(insideFrame_);

EndCurRenderStep();

VKRStep *step = new VKRStep{ VKRStepType::READBACK_IMAGE };
step->readback_image.image = image;
step->readback_image.srcRect.offset = { x, y };
Expand All @@ -712,8 +731,6 @@ void VulkanRenderManager::CopyImageToMemorySync(VkImage image, int mipLevel, int
step->tag = tag;
steps_.push_back(step);

curRenderStep_ = nullptr;

FlushSync();

// Need to call this after FlushSync so the pixels are guaranteed to be ready in CPU-accessible VRAM.
Expand Down Expand Up @@ -975,6 +992,8 @@ void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect,
}
}

EndCurRenderStep();

VKRStep *step = new VKRStep{ VKRStepType::COPY };

step->copy.aspectMask = aspectMask;
Expand All @@ -990,7 +1009,6 @@ void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect,

std::unique_lock<std::mutex> lock(mutex_);
steps_.push_back(step);
curRenderStep_ = nullptr;
}

void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkImageAspectFlags aspectMask, VkFilter filter, const char *tag) {
Expand Down Expand Up @@ -1019,6 +1037,8 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect,
}
}

EndCurRenderStep();

VKRStep *step = new VKRStep{ VKRStepType::BLIT };

step->blit.aspectMask = aspectMask;
Expand All @@ -1035,7 +1055,6 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect,

std::unique_lock<std::mutex> lock(mutex_);
steps_.push_back(step);
curRenderStep_ = nullptr;
}

VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, VkImageAspectFlags aspectBit, int attachment) {
Expand Down Expand Up @@ -1078,7 +1097,7 @@ VkImageView VulkanRenderManager::BindFramebufferAsTexture(VKRFramebuffer *fb, in
}

void VulkanRenderManager::Finish() {
curRenderStep_ = nullptr;
EndCurRenderStep();

// Let's do just a bit of cleanup on render commands now.
for (auto &step : steps_) {
Expand Down
7 changes: 6 additions & 1 deletion Common/GPU/Vulkan/VulkanRenderManager.h
Expand Up @@ -104,11 +104,12 @@ class VulkanRenderManager {
void CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, VkImageAspectFlags aspectMask, const char *tag);
void BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkRect2D dstRect, VkImageAspectFlags aspectMask, VkFilter filter, const char *tag);

void BindPipeline(VkPipeline pipeline) {
void BindPipeline(VkPipeline pipeline, PipelineFlags flags) {
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);
_dbg_assert_(pipeline != VK_NULL_HANDLE);
VkRenderData data{ VKRRenderCommand::BIND_PIPELINE };
data.pipeline.pipeline = pipeline;
curPipelineFlags_ |= flags;
curRenderStep_->commands.push_back(data);
}

Expand Down Expand Up @@ -265,6 +266,8 @@ class VulkanRenderManager {
private:
bool InitBackbufferFramebuffers(int width, int height);
bool InitDepthStencilBuffer(VkCommandBuffer cmd); // Used for non-buffered rendering.
void EndCurRenderStep();

void BeginSubmitFrame(int frame);
void EndSubmitFrame(int frame);
void Submit(int frame, bool triggerFence);
Expand Down Expand Up @@ -328,6 +331,8 @@ class VulkanRenderManager {
VKRStep *curRenderStep_ = nullptr;
bool curStepHasViewport_ = false;
bool curStepHasScissor_ = false;
u32 curPipelineFlags_ = 0;

std::vector<VKRStep *> steps_;
bool splitSubmit_ = false;

Expand Down
17 changes: 13 additions & 4 deletions Common/GPU/Vulkan/thin3d_vulkan.cpp
Expand Up @@ -245,7 +245,7 @@ class VKInputLayout : public InputLayout {

class VKPipeline : public Pipeline {
public:
VKPipeline(VulkanContext *vulkan, size_t size) : vulkan_(vulkan) {
VKPipeline(VulkanContext *vulkan, size_t size, PipelineFlags _flags) : vulkan_(vulkan), flags(_flags) {
uboSize_ = (int)size;
ubo_ = new uint8_t[uboSize_];
}
Expand Down Expand Up @@ -274,6 +274,8 @@ class VKPipeline : public Pipeline {

VkPipeline backbufferPipeline = VK_NULL_HANDLE;
VkPipeline framebufferPipeline = VK_NULL_HANDLE;

PipelineFlags flags;
int stride[4]{};
int dynamicUniformSize = 0;

Expand Down Expand Up @@ -1014,11 +1016,18 @@ VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) {
}

Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
VKPipeline *pipeline = new VKPipeline(vulkan_, desc.uniformDesc ? desc.uniformDesc->uniformBufferSize : 16 * sizeof(float));
VKInputLayout *input = (VKInputLayout *)desc.inputLayout;
VKBlendState *blend = (VKBlendState *)desc.blend;
VKDepthStencilState *depth = (VKDepthStencilState *)desc.depthStencil;
VKRasterState *raster = (VKRasterState *)desc.raster;

u32 pipelineFlags = 0;
if (depth->info.depthTestEnable || depth->info.stencilTestEnable) {
pipelineFlags |= PIPELINE_FLAG_USES_DEPTH_STENCIL;
}

VKPipeline *pipeline = new VKPipeline(vulkan_, desc.uniformDesc ? desc.uniformDesc->uniformBufferSize : 16 * sizeof(float), (PipelineFlags)pipelineFlags);

for (int i = 0; i < (int)input->bindings.size(); i++) {
pipeline->stride[i] = input->bindings[i].stride;
}
Expand Down Expand Up @@ -1336,9 +1345,9 @@ void VKContext::DrawUP(const void *vdata, int vertexCount) {
void VKContext::BindCompatiblePipeline() {
VkRenderPass renderPass = renderManager_.GetCompatibleRenderPass();
if (renderPass == renderManager_.GetBackbufferRenderPass()) {
renderManager_.BindPipeline(curPipeline_->backbufferPipeline);
renderManager_.BindPipeline(curPipeline_->backbufferPipeline, curPipeline_->flags);
} else {
renderManager_.BindPipeline(curPipeline_->framebufferPipeline);
renderManager_.BindPipeline(curPipeline_->framebufferPipeline, curPipeline_->flags);
}
}

Expand Down
4 changes: 2 additions & 2 deletions GPU/Vulkan/DrawEngineVulkan.cpp
Expand Up @@ -839,7 +839,7 @@ void DrawEngineVulkan::DoFlush() {
lastRenderStepId_ = curRenderStepId;
}

renderManager->BindPipeline(pipeline->pipeline);
renderManager->BindPipeline(pipeline->pipeline, (PipelineFlags)pipeline->flags);
if (pipeline != lastPipeline_) {
if (lastPipeline_ && !(lastPipeline_->UsesBlendConstant() && pipeline->UsesBlendConstant())) {
gstate_c.Dirty(DIRTY_BLEND_STATE);
Expand Down Expand Up @@ -964,7 +964,7 @@ void DrawEngineVulkan::DoFlush() {
lastRenderStepId_ = curRenderStepId;
}

renderManager->BindPipeline(pipeline->pipeline);
renderManager->BindPipeline(pipeline->pipeline, (PipelineFlags)pipeline->flags);
if (pipeline != lastPipeline_) {
if (lastPipeline_ && !lastPipeline_->UsesBlendConstant() && pipeline->UsesBlendConstant()) {
gstate_c.Dirty(DIRTY_BLEND_STATE);
Expand Down
2 changes: 1 addition & 1 deletion GPU/Vulkan/FramebufferManagerVulkan.cpp
Expand Up @@ -225,7 +225,7 @@ void FramebufferManagerVulkan::DrawActiveTexture(float x, float y, float w, floa
VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(view, (flags & DRAWTEX_LINEAR) ? linearSampler_ : nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE);
VkBuffer vbuffer;
VkDeviceSize offset = push_->Push(vtx, sizeof(vtx), &vbuffer);
renderManager->BindPipeline(cur2DPipeline_);
renderManager->BindPipeline(cur2DPipeline_, (PipelineFlags)0);
renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, vbuffer, offset, 4);
}

Expand Down
6 changes: 4 additions & 2 deletions GPU/Vulkan/PipelineManagerVulkan.cpp
Expand Up @@ -325,6 +325,9 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip
vulkanPipeline->flags |= PIPELINE_FLAG_USES_BLEND_CONSTANT;
if (key.topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST || key.topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP)
vulkanPipeline->flags |= PIPELINE_FLAG_USES_LINES;
if (dss.depthTestEnable || dss.stencilTestEnable) {
vulkanPipeline->flags |= PIPELINE_FLAG_USES_DEPTH_STENCIL;
}
return vulkanPipeline;
}

Expand Down Expand Up @@ -550,7 +553,7 @@ void PipelineManagerVulkan::SetLineWidth(float lineWidth) {

// Wipe all line-drawing pipelines.
pipelines_.Iterate([&](const VulkanPipelineKey &key, VulkanPipeline *value) {
if (value->UsesLines()) {
if (value->flags & PIPELINE_FLAG_USES_LINES) {
if (value->pipeline)
vulkan_->Delete().QueueDeletePipeline(value->pipeline);
delete value;
Expand Down Expand Up @@ -619,7 +622,6 @@ void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, Sha
// Make sure the set of pipelines we write is "unique".
std::set<StoredVulkanPipelineKey> keys;

// TODO: Use derivative pipelines when possible, helps Mali driver pipeline creation speed at least.
pipelines_.Iterate([&](const VulkanPipelineKey &pkey, VulkanPipeline *value) {
if (failed)
return;
Expand Down
9 changes: 3 additions & 6 deletions GPU/Vulkan/PipelineManagerVulkan.h
Expand Up @@ -25,6 +25,8 @@
#include "GPU/Vulkan/VulkanUtil.h"
#include "GPU/Vulkan/StateMappingVulkan.h"

#include "GPU/Vulkan/VulkanQueueRunner.h"

// PSP vertex format.
enum class PspAttributeLocation {
POSITION = 0,
Expand Down Expand Up @@ -56,19 +58,14 @@ struct VulkanPipelineKey {
std::string GetDescription(DebugShaderStringType stringType) const;
};

enum PipelineFlags {
PIPELINE_FLAG_USES_LINES = (1 << 2),
PIPELINE_FLAG_USES_BLEND_CONSTANT = (1 << 3),
};

// Simply wraps a Vulkan pipeline, providing some metadata.
struct VulkanPipeline {
VkPipeline pipeline;
int flags; // PipelineFlags enum above.

// Convenience.
bool UsesBlendConstant() const { return (flags & PIPELINE_FLAG_USES_BLEND_CONSTANT) != 0; }
bool UsesLines() const { return (flags & PIPELINE_FLAG_USES_LINES) != 0; }
bool UsesDepthStencil() const { return (flags & PIPELINE_FLAG_USES_DEPTH_STENCIL) != 0; }
};

class VulkanContext;
Expand Down
2 changes: 1 addition & 1 deletion GPU/Vulkan/StencilBufferVulkan.cpp
Expand Up @@ -180,7 +180,7 @@ bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, StencilUp
}

VkPipeline pipeline = vulkan2D_->GetPipeline(rp, stencilVs_, stencilFs_, false, Vulkan2D::VK2DDepthStencilMode::STENCIL_REPLACE_ALWAYS);
renderManager->BindPipeline(pipeline);
renderManager->BindPipeline(pipeline, PIPELINE_FLAG_USES_DEPTH_STENCIL);
renderManager->SetViewport({ 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f });
renderManager->SetScissor({ { 0, 0, },{ (uint32_t)w, (uint32_t)h } });

Expand Down
2 changes: 1 addition & 1 deletion GPU/Vulkan/TextureCacheVulkan.cpp
Expand Up @@ -635,7 +635,7 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer

VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(fbo, samplerNearest_, clutTexture->GetImageView(), samplerNearest_);
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
renderManager->BindPipeline(depalShader->pipeline);
renderManager->BindPipeline(depalShader->pipeline, (PipelineFlags)0);

if (depth) {
DepthScaleFactors scaleFactors = GetDepthScaleFactors();
Expand Down

0 comments on commit 5ece3de

Please sign in to comment.