mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
Track and accumulate pipeline flags for render passes.
(Information that will later let us make some interesting optimizations)
This commit is contained in:
parent
4ff059d3d8
commit
5ece3de8ba
@ -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;
|
||||
@ -143,6 +151,7 @@ struct VKRStep {
|
||||
int numReads;
|
||||
VkImageLayout finalColorLayout;
|
||||
VkImageLayout finalDepthStencilLayout;
|
||||
u32 pipelineFlags;
|
||||
} render;
|
||||
struct {
|
||||
VKRFramebuffer *src;
|
||||
|
@ -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.
|
||||
@ -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.
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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 };
|
||||
@ -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.
|
||||
@ -975,6 +992,8 @@ void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect,
|
||||
}
|
||||
}
|
||||
|
||||
EndCurRenderStep();
|
||||
|
||||
VKRStep *step = new VKRStep{ VKRStepType::COPY };
|
||||
|
||||
step->copy.aspectMask = aspectMask;
|
||||
@ -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) {
|
||||
@ -1019,6 +1037,8 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect,
|
||||
}
|
||||
}
|
||||
|
||||
EndCurRenderStep();
|
||||
|
||||
VKRStep *step = new VKRStep{ VKRStepType::BLIT };
|
||||
|
||||
step->blit.aspectMask = aspectMask;
|
||||
@ -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) {
|
||||
@ -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_) {
|
||||
|
@ -104,11 +104,12 @@ public:
|
||||
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);
|
||||
}
|
||||
|
||||
@ -265,6 +266,8 @@ public:
|
||||
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);
|
||||
@ -328,6 +331,8 @@ private:
|
||||
VKRStep *curRenderStep_ = nullptr;
|
||||
bool curStepHasViewport_ = false;
|
||||
bool curStepHasScissor_ = false;
|
||||
u32 curPipelineFlags_ = 0;
|
||||
|
||||
std::vector<VKRStep *> steps_;
|
||||
bool splitSubmit_ = false;
|
||||
|
||||
|
@ -245,7 +245,7 @@ public:
|
||||
|
||||
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_];
|
||||
}
|
||||
@ -274,6 +274,8 @@ public:
|
||||
|
||||
VkPipeline backbufferPipeline = VK_NULL_HANDLE;
|
||||
VkPipeline framebufferPipeline = VK_NULL_HANDLE;
|
||||
|
||||
PipelineFlags flags;
|
||||
int stride[4]{};
|
||||
int dynamicUniformSize = 0;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -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;
|
||||
|
@ -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,
|
||||
@ -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;
|
||||
|
@ -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 } });
|
||||
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user