mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Vulkan: Don't have renderpasses store/load depth buffers when we don't use them
This commit is contained in:
parent
594139885e
commit
8e30a7ccfc
5 changed files with 60 additions and 48 deletions
|
@ -326,29 +326,33 @@ static VkAttachmentStoreOp ConvertStoreAction(VKRRenderPassStoreAction action) {
|
|||
// Self-dependency: https://github.com/gpuweb/gpuweb/issues/442#issuecomment-547604827
|
||||
// Also see https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies
|
||||
|
||||
VkRenderPass CreateRP(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType) {
|
||||
bool selfDependency = rpType == RP_TYPE_COLOR_DEPTH_INPUT;
|
||||
VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType) {
|
||||
bool selfDependency = rpType == RP_TYPE_COLOR_INPUT || rpType == RP_TYPE_COLOR_DEPTH_INPUT;
|
||||
bool isBackbuffer = rpType == RP_TYPE_BACKBUFFER;
|
||||
bool hasDepth = rpType == RP_TYPE_BACKBUFFER || rpType == RP_TYPE_COLOR_DEPTH || rpType == RP_TYPE_COLOR_DEPTH_INPUT;
|
||||
|
||||
VkAttachmentDescription attachments[2] = {};
|
||||
attachments[0].format = rpType == RP_TYPE_BACKBUFFER ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM;
|
||||
attachments[0].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM;
|
||||
attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[0].loadOp = ConvertLoadAction(key.colorLoadAction);
|
||||
attachments[0].storeOp = ConvertStoreAction(key.colorStoreAction);
|
||||
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
attachments[0].initialLayout = rpType == RP_TYPE_BACKBUFFER ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[0].finalLayout = rpType == RP_TYPE_BACKBUFFER ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[0].initialLayout = isBackbuffer ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[0].finalLayout = isBackbuffer ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachments[0].flags = 0;
|
||||
|
||||
attachments[1].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat;
|
||||
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[1].loadOp = ConvertLoadAction(key.depthLoadAction);
|
||||
attachments[1].storeOp = ConvertStoreAction(key.depthStoreAction);
|
||||
attachments[1].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction);
|
||||
attachments[1].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction);
|
||||
attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[1].flags = 0;
|
||||
if (hasDepth) {
|
||||
attachments[1].format = vulkan->GetDeviceInfo().preferredDepthStencilFormat;
|
||||
attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachments[1].loadOp = ConvertLoadAction(key.depthLoadAction);
|
||||
attachments[1].storeOp = ConvertStoreAction(key.depthStoreAction);
|
||||
attachments[1].stencilLoadOp = ConvertLoadAction(key.stencilLoadAction);
|
||||
attachments[1].stencilStoreOp = ConvertStoreAction(key.stencilStoreAction);
|
||||
attachments[1].initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachments[1].flags = 0;
|
||||
}
|
||||
|
||||
VkAttachmentReference color_reference{};
|
||||
color_reference.attachment = 0;
|
||||
|
@ -371,7 +375,9 @@ VkRenderPass CreateRP(VulkanContext *vulkan, const RPKey &key, RenderPassType rp
|
|||
subpass.colorAttachmentCount = 1;
|
||||
subpass.pColorAttachments = &color_reference;
|
||||
subpass.pResolveAttachments = nullptr;
|
||||
subpass.pDepthStencilAttachment = &depth_reference;
|
||||
if (hasDepth) {
|
||||
subpass.pDepthStencilAttachment = &depth_reference;
|
||||
}
|
||||
subpass.preserveAttachmentCount = 0;
|
||||
subpass.pPreserveAttachments = nullptr;
|
||||
|
||||
|
@ -380,12 +386,12 @@ VkRenderPass CreateRP(VulkanContext *vulkan, const RPKey &key, RenderPassType rp
|
|||
size_t numDeps = 0;
|
||||
|
||||
VkRenderPassCreateInfo rp{ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
|
||||
rp.attachmentCount = 2;
|
||||
rp.attachmentCount = hasDepth ? 2 : 1;
|
||||
rp.pAttachments = attachments;
|
||||
rp.subpassCount = 1;
|
||||
rp.pSubpasses = &subpass;
|
||||
|
||||
if (rpType == RP_TYPE_BACKBUFFER) {
|
||||
if (isBackbuffer) {
|
||||
deps[numDeps].srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||
deps[numDeps].dstSubpass = 0;
|
||||
deps[numDeps].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
|
@ -424,7 +430,7 @@ VkRenderPass VKRRenderPass::Get(VulkanContext *vulkan, RenderPassType rpType) {
|
|||
// practical later when referring to it. Could change to on-demand if it feels motivated
|
||||
// but I think the render pass objects are cheap.
|
||||
if (!pass[(int)rpType]) {
|
||||
pass[(int)rpType] = CreateRP(vulkan, key_, (RenderPassType)rpType);
|
||||
pass[(int)rpType] = CreateRenderPass(vulkan, key_, (RenderPassType)rpType);
|
||||
}
|
||||
return pass[(int)rpType];
|
||||
}
|
||||
|
@ -873,8 +879,10 @@ std::string VulkanQueueRunner::StepToString(const VKRStep &step) const {
|
|||
const char *renderCmd;
|
||||
switch (step.render.renderPassType) {
|
||||
case RP_TYPE_BACKBUFFER: renderCmd = "BACKBUF"; break;
|
||||
case RP_TYPE_COLOR_DEPTH: renderCmd = "RENDER"; break;
|
||||
case RP_TYPE_COLOR_DEPTH_INPUT: renderCmd = "RENDER_INPUT"; break;
|
||||
case RP_TYPE_COLOR: renderCmd = "RENDER"; break;
|
||||
case RP_TYPE_COLOR_DEPTH: renderCmd = "RENDER_DEPTH"; break;
|
||||
case RP_TYPE_COLOR_INPUT: renderCmd = "RENDER_INPUT"; break;
|
||||
case RP_TYPE_COLOR_DEPTH_INPUT: renderCmd = "RENDER_DEPTH_INPUT"; break;
|
||||
default: renderCmd = "N/A";
|
||||
}
|
||||
snprintf(buffer, sizeof(buffer), "%s %s (draws: %d, %dx%d/%dx%d, fb: %p, )", renderCmd, step.tag, step.render.numDraws, actual_w, actual_h, w, h, step.render.framebuffer);
|
||||
|
@ -1153,7 +1161,7 @@ void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout
|
|||
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(false, "GetRenderPass: Unexpected color layout %d", (int)colorLayout);
|
||||
_dbg_assert_msg_(false, "TransitionToOptimal: Unexpected color layout %d", (int)colorLayout);
|
||||
break;
|
||||
}
|
||||
recordBarrier->TransitionImage(
|
||||
|
@ -1189,7 +1197,7 @@ void TransitionToOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayout
|
|||
srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(false, "GetRenderPass: Unexpected depth layout %d", (int)depthStencilLayout);
|
||||
_dbg_assert_msg_(false, "TransitionToOptimal: Unexpected depth layout %d", (int)depthStencilLayout);
|
||||
break;
|
||||
}
|
||||
recordBarrier->TransitionImage(
|
||||
|
@ -1236,7 +1244,7 @@ void TransitionFromOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayou
|
|||
// Nothing to do.
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(false, "GetRenderPass: Unexpected final color layout %d", (int)colorLayout);
|
||||
_dbg_assert_msg_(false, "TransitionFromOptimal: Unexpected final color layout %d", (int)colorLayout);
|
||||
break;
|
||||
}
|
||||
barrier[0].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
@ -1275,7 +1283,7 @@ void TransitionFromOptimal(VkCommandBuffer cmd, VkImage colorImage, VkImageLayou
|
|||
// Nothing to do.
|
||||
break;
|
||||
default:
|
||||
_dbg_assert_msg_(false, "GetRenderPass: Unexpected final depth layout %d", (int)depthStencilLayout);
|
||||
_dbg_assert_msg_(false, "TransitionFromOptimal: Unexpected final depth layout %d", (int)depthStencilLayout);
|
||||
break;
|
||||
}
|
||||
barrier[barrierCount].oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
|
|
@ -43,18 +43,19 @@ enum class VKRRenderCommand : uint8_t {
|
|||
|
||||
enum class PipelineFlags {
|
||||
NONE = 0,
|
||||
USES_LINES = (1 << 2),
|
||||
USES_BLEND_CONSTANT = (1 << 3),
|
||||
USES_DEPTH_STENCIL = (1 << 4), // Reads or writes the depth buffer.
|
||||
USES_DEPTH_STENCIL = (1 << 4), // Reads or writes the depth or stencil buffers.
|
||||
USES_INPUT_ATTACHMENT = (1 << 5),
|
||||
};
|
||||
ENUM_CLASS_BITOPS(PipelineFlags);
|
||||
|
||||
// Pipelines need to be created for the right type of render pass.
|
||||
enum RenderPassType {
|
||||
RP_TYPE_BACKBUFFER,
|
||||
RP_TYPE_BACKBUFFER, // For the backbuffer we can always use CLEAR/DONT_CARE, so bandwidth cost for a depth channel is negligible.
|
||||
RP_TYPE_COLOR_DEPTH,
|
||||
RP_TYPE_COLOR_DEPTH_INPUT,
|
||||
RP_TYPE_COLOR,
|
||||
RP_TYPE_COLOR_INPUT,
|
||||
// Later will add pure-color render passes.
|
||||
RP_TYPE_COUNT,
|
||||
};
|
||||
|
|
|
@ -158,33 +158,37 @@ VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRe
|
|||
// We create the actual framebuffer objects on demand, because some combinations might not make sense.
|
||||
}
|
||||
|
||||
VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPassType renderPassType) {
|
||||
if (framebuf[(int)renderPassType]) {
|
||||
return framebuf[(int)renderPassType];
|
||||
VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType) {
|
||||
if (framebuf[(int)rpType]) {
|
||||
return framebuf[(int)rpType];
|
||||
}
|
||||
|
||||
VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
|
||||
VkImageView views[2]{};
|
||||
|
||||
fbci.renderPass = compatibleRenderPass->Get(vulkan_, renderPassType);
|
||||
fbci.attachmentCount = 2;
|
||||
fbci.pAttachments = views;
|
||||
bool hasDepth = rpType == RP_TYPE_BACKBUFFER || rpType == RP_TYPE_COLOR_DEPTH || rpType == RP_TYPE_COLOR_DEPTH_INPUT;
|
||||
|
||||
views[0] = color.imageView;
|
||||
views[1] = depth.imageView;
|
||||
if (hasDepth) {
|
||||
views[1] = depth.imageView;
|
||||
}
|
||||
fbci.renderPass = compatibleRenderPass->Get(vulkan_, rpType);
|
||||
fbci.attachmentCount = hasDepth ? 2 : 1;
|
||||
fbci.pAttachments = views;
|
||||
fbci.width = width;
|
||||
fbci.height = height;
|
||||
fbci.layers = 1;
|
||||
|
||||
VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[(int)renderPassType]);
|
||||
VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[(int)rpType]);
|
||||
_assert_(res == VK_SUCCESS);
|
||||
|
||||
if (!tag_.empty() && vulkan_->Extensions().EXT_debug_utils) {
|
||||
vulkan_->SetDebugName(color.image, VK_OBJECT_TYPE_IMAGE, StringFromFormat("fb_color_%s", tag_.c_str()).c_str());
|
||||
vulkan_->SetDebugName(depth.image, VK_OBJECT_TYPE_IMAGE, StringFromFormat("fb_depth_%s", tag_.c_str()).c_str());
|
||||
vulkan_->SetDebugName(framebuf[(int)renderPassType], VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag_.c_str()).c_str());
|
||||
vulkan_->SetDebugName(framebuf[(int)rpType], VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag_.c_str()).c_str());
|
||||
}
|
||||
|
||||
return framebuf[(int)renderPassType];
|
||||
return framebuf[(int)rpType];
|
||||
}
|
||||
|
||||
VKRFramebuffer::~VKRFramebuffer() {
|
||||
|
@ -656,15 +660,16 @@ void VulkanRenderManager::EndCurRenderStep() {
|
|||
curRenderStep_->render.colorLoad, curRenderStep_->render.depthLoad, curRenderStep_->render.stencilLoad,
|
||||
curRenderStep_->render.colorStore, curRenderStep_->render.depthStore, curRenderStep_->render.stencilStore,
|
||||
};
|
||||
RenderPassType rpType = RP_TYPE_COLOR_DEPTH;
|
||||
// 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.
|
||||
curRenderStep_->render.pipelineFlags = curPipelineFlags_;
|
||||
bool depthStencil = (curPipelineFlags_ & PipelineFlags::USES_DEPTH_STENCIL) != 0;
|
||||
RenderPassType rpType = depthStencil ? RP_TYPE_COLOR_DEPTH : RP_TYPE_COLOR;
|
||||
if (!curRenderStep_->render.framebuffer) {
|
||||
rpType = RP_TYPE_BACKBUFFER;
|
||||
} else if (curPipelineFlags_ & PipelineFlags::USES_INPUT_ATTACHMENT) {
|
||||
// Not allowed on backbuffers.
|
||||
rpType = RP_TYPE_COLOR_DEPTH_INPUT;
|
||||
rpType = depthStencil ? RP_TYPE_COLOR_INPUT : RP_TYPE_COLOR_DEPTH_INPUT;
|
||||
}
|
||||
// TODO: Also add render pass types for depth/stencil-less.
|
||||
|
||||
|
|
|
@ -170,8 +170,8 @@ static std::string CutFromMain(std::string str) {
|
|||
}
|
||||
|
||||
static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager, VkPipelineCache pipelineCache,
|
||||
VkPipelineLayout layout, PipelineFlags pipelineFlags, const VulkanPipelineRasterStateKey &key,
|
||||
const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, u32 variantBitmask) {
|
||||
VkPipelineLayout layout, PipelineFlags pipelineFlags, const VulkanPipelineRasterStateKey &key,
|
||||
const DecVtxFormat *decFmt, VulkanVertexShader *vs, VulkanFragmentShader *fs, bool useHwTransform, u32 variantBitmask) {
|
||||
VulkanPipeline *vulkanPipeline = new VulkanPipeline();
|
||||
VKRGraphicsPipelineDesc *desc = &vulkanPipeline->desc;
|
||||
desc->pipelineCache = pipelineCache;
|
||||
|
@ -221,7 +221,7 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
|
|||
VkDynamicState *dynamicStates = &desc->dynamicStates[0];
|
||||
int numDyn = 0;
|
||||
if (key.blendEnable &&
|
||||
(UsesBlendConstant(key.srcAlpha) || UsesBlendConstant(key.srcColor) || UsesBlendConstant(key.destAlpha) || UsesBlendConstant(key.destColor))) {
|
||||
(UsesBlendConstant(key.srcAlpha) || UsesBlendConstant(key.srcColor) || UsesBlendConstant(key.destAlpha) || UsesBlendConstant(key.destColor))) {
|
||||
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_BLEND_CONSTANTS;
|
||||
useBlendConstant = true;
|
||||
}
|
||||
|
@ -232,12 +232,12 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
|
|||
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK;
|
||||
dynamicStates[numDyn++] = VK_DYNAMIC_STATE_STENCIL_REFERENCE;
|
||||
}
|
||||
|
||||
|
||||
VkPipelineDynamicStateCreateInfo &ds = desc->ds;
|
||||
ds.flags = 0;
|
||||
ds.pDynamicStates = dynamicStates;
|
||||
ds.dynamicStateCount = numDyn;
|
||||
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo &rs = desc->rs;
|
||||
rs.flags = 0;
|
||||
rs.depthBiasEnable = false;
|
||||
|
@ -299,10 +299,9 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
|
|||
VKRGraphicsPipeline *pipeline = renderManager->CreateGraphicsPipeline(desc, variantBitmask, "game");
|
||||
|
||||
vulkanPipeline->pipeline = pipeline;
|
||||
if (useBlendConstant)
|
||||
if (useBlendConstant) {
|
||||
pipelineFlags |= PipelineFlags::USES_BLEND_CONSTANT;
|
||||
if (key.topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST || key.topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP)
|
||||
pipelineFlags |= PipelineFlags::USES_LINES;
|
||||
}
|
||||
if (dss.depthTestEnable || dss.stencilTestEnable) {
|
||||
pipelineFlags |= PipelineFlags::USES_DEPTH_STENCIL;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,6 @@ struct VulkanPipeline {
|
|||
PipelineFlags pipelineFlags; // PipelineFlags enum above.
|
||||
|
||||
bool UsesBlendConstant() const { return (pipelineFlags & PipelineFlags::USES_BLEND_CONSTANT) != 0; }
|
||||
bool UsesLines() const { return (pipelineFlags & PipelineFlags::USES_LINES) != 0; }
|
||||
bool UsesDepthStencil() const { return (pipelineFlags & PipelineFlags::USES_DEPTH_STENCIL) != 0; }
|
||||
bool UsesInputAttachment() const { return (pipelineFlags & PipelineFlags::USES_INPUT_ATTACHMENT) != 0; }
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue