Create framebuffer variants on demand

This commit is contained in:
Henrik Rydgård committed 2022-09-08 00:38:28 +02:00
1 parent e828df9f25
commit 80ca822bf2
4 files changed
+69 -50

No files matched your search

+18 -18
View File
@@ -615,13 +615,13 @@ std::string VulkanQueueRunner::StepToString(const VKRStep &step) const {
break;
}
case VKRStepType::COPY:
snprintf(buffer, sizeof(buffer), "COPY '%s' %s -> %s (%dx%d, %s)", step.tag, step.copy.src->tag.c_str(), step.copy.dst->tag.c_str(), step.copy.srcRect.extent.width, step.copy.srcRect.extent.height, AspectToString(step.copy.aspectMask));
snprintf(buffer, sizeof(buffer), "COPY '%s' %s -> %s (%dx%d, %s)", step.tag, step.copy.src->Tag(), step.copy.dst->Tag(), step.copy.srcRect.extent.width, step.copy.srcRect.extent.height, AspectToString(step.copy.aspectMask));
break;
case VKRStepType::BLIT:
snprintf(buffer, sizeof(buffer), "BLIT '%s' %s -> %s (%dx%d->%dx%d, %s)", step.tag, step.copy.src->tag.c_str(), step.copy.dst->tag.c_str(), step.blit.srcRect.extent.width, step.blit.srcRect.extent.height, step.blit.dstRect.extent.width, step.blit.dstRect.extent.height, AspectToString(step.blit.aspectMask));
snprintf(buffer, sizeof(buffer), "BLIT '%s' %s -> %s (%dx%d->%dx%d, %s)", step.tag, step.copy.src->Tag(), step.copy.dst->Tag(), step.blit.srcRect.extent.width, step.blit.srcRect.extent.height, step.blit.dstRect.extent.width, step.blit.dstRect.extent.height, AspectToString(step.blit.aspectMask));
break;
case VKRStepType::READBACK:
snprintf(buffer, sizeof(buffer), "READBACK '%s' %s (%dx%d, %s)", step.tag, step.readback.src->tag.c_str(), step.readback.srcRect.extent.width, step.readback.srcRect.extent.height, AspectToString(step.readback.aspectMask));
snprintf(buffer, sizeof(buffer), "READBACK '%s' %s (%dx%d, %s)", step.tag, step.readback.src->Tag(), step.readback.srcRect.extent.width, step.readback.srcRect.extent.height, AspectToString(step.readback.aspectMask));
break;
case VKRStepType::READBACK_IMAGE:
snprintf(buffer, sizeof(buffer), "READBACK_IMAGE '%s' (%dx%d)", step.tag, step.readback_image.srcRect.extent.width, step.readback_image.srcRect.extent.height);
@@ -780,14 +780,14 @@ const char *ImageLayoutToString(VkImageLayout layout) {
void VulkanQueueRunner::LogRenderPass(const VKRStep &pass, bool verbose) {
const auto &r = pass.render;
const char *framebuf = r.framebuffer ? r.framebuffer->tag.c_str() : "backbuffer";
const char *framebuf = r.framebuffer ? r.framebuffer->Tag() : "backbuffer";
int w = r.framebuffer ? r.framebuffer->width : vulkan_->GetBackbufferWidth();
int h = r.framebuffer ? r.framebuffer->height : vulkan_->GetBackbufferHeight();
INFO_LOG(G3D, "RENDER %s Begin(%s, draws: %d, %dx%d, %s, %s, %s)", pass.tag, framebuf, r.numDraws, w, h, RenderPassActionName(r.colorLoad), RenderPassActionName(r.depthLoad), RenderPassActionName(r.stencilLoad));
// TODO: Log these in detail.
for (int i = 0; i < (int)pass.preTransitions.size(); i++) {
INFO_LOG(G3D, " PRETRANSITION: %s %s -> %s", pass.preTransitions[i].fb->tag.c_str(), AspectToString(pass.preTransitions[i].aspect), ImageLayoutToString(pass.preTransitions[i].targetLayout));
INFO_LOG(G3D, " PRETRANSITION: %s %s -> %s", pass.preTransitions[i].fb->Tag(), AspectToString(pass.preTransitions[i].aspect), ImageLayoutToString(pass.preTransitions[i].targetLayout));
}
if (verbose) {
@@ -1317,8 +1317,14 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step
_dbg_assert_(step.render.finalColorLayout != VK_IMAGE_LAYOUT_UNDEFINED);
_dbg_assert_(step.render.finalDepthStencilLayout != VK_IMAGE_LAYOUT_UNDEFINED);
RPKey key{
step.render.colorLoad, step.render.depthLoad, step.render.stencilLoad,
step.render.colorStore, step.render.depthStore, step.render.stencilStore,
};
renderPass = GetRenderPass(key);
VKRFramebuffer *fb = step.render.framebuffer;
framebuf = fb->framebuf[step.render.renderPassType];
framebuf = fb->Get(renderPass, step.render.renderPassType);
w = fb->width;
h = fb->height;
@@ -1340,12 +1346,6 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step
TransitionToOptimal(cmd, fb->color.image, fb->color.layout, fb->depth.image, fb->depth.layout, &recordBarrier_);
RPKey key{
step.render.colorLoad, step.render.depthLoad, step.render.stencilLoad,
step.render.colorStore, step.render.depthStore, step.render.stencilStore,
};
renderPass = GetRenderPass(key);
// The transition from the optimal format happens after EndRenderPass, now that we don't
// do it as part of the renderpass itself anymore.
@@ -1359,18 +1359,18 @@ void VulkanQueueRunner::PerformBindFramebufferAsRenderTarget(const VKRStep &step
numClearVals = 2;
}
} else {
framebuf = backbuffer_;
// Raw, rotated backbuffer size.
w = vulkan_->GetBackbufferWidth();
h = vulkan_->GetBackbufferHeight();
RPKey key{
VKRRenderPassLoadAction::CLEAR, VKRRenderPassLoadAction::CLEAR, VKRRenderPassLoadAction::CLEAR,
VKRRenderPassStoreAction::STORE, VKRRenderPassStoreAction::DONT_CARE, VKRRenderPassStoreAction::DONT_CARE,
};
renderPass = GetRenderPass(key);
framebuf = backbuffer_;
// Raw, rotated backbuffer size.
w = vulkan_->GetBackbufferWidth();
h = vulkan_->GetBackbufferHeight();
Uint8x4ToFloat4(clearVal[0].color.float32, step.render.clearColor);
numClearVals = 2; // We don't bother with a depth buffer here.
clearVal[1].depthStencil.depth = 0.0f;
+29 -22
View File
@@ -129,36 +129,43 @@ bool VKRComputePipeline::Create(VulkanContext *vulkan) {
return success;
}
VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, const char *tag) : vulkan_(vk) {
VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, const char *tag) : vulkan_(vk), tag_(tag) {
width = _width;
height = _height;
CreateImage(vulkan_, initCmd, color, width, height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, tag);
CreateImage(vulkan_, initCmd, depth, width, height, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false, tag);
for (int i = 0; i < RP_TYPE_COUNT; i++) {
VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
VkImageView views[2]{};
// We create the actual framebuffer objects on demand, because some combinations might not make sense.
}
fbci.renderPass = compatibleRenderPass->pass[i];
fbci.attachmentCount = 2;
fbci.pAttachments = views;
views[0] = color.imageView;
views[1] = depth.imageView;
fbci.width = width;
fbci.height = height;
fbci.layers = 1;
VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[i]);
_assert_(res == VK_SUCCESS);
if (tag && vk->Extensions().EXT_debug_utils) {
vk->SetDebugName(color.image, VK_OBJECT_TYPE_IMAGE, StringFromFormat("fb_color_%s", tag).c_str());
vk->SetDebugName(depth.image, VK_OBJECT_TYPE_IMAGE, StringFromFormat("fb_depth_%s", tag).c_str());
vk->SetDebugName(framebuf[i], VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag).c_str());
this->tag = tag;
}
VkFramebuffer VKRFramebuffer::Get(VKRRenderPass *compatibleRenderPass, RenderPassType renderPassType) {
if (framebuf[(int)renderPassType]) {
return framebuf[(int)renderPassType];
}
VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
VkImageView views[2]{};
fbci.renderPass = compatibleRenderPass->pass[(int)renderPassType];
fbci.attachmentCount = 2;
fbci.pAttachments = views;
views[0] = color.imageView;
views[1] = depth.imageView;
fbci.width = width;
fbci.height = height;
fbci.layers = 1;
VkResult res = vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf[(int)renderPassType]);
_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());
}
return framebuf[(int)renderPassType];
}
VKRFramebuffer::~VKRFramebuffer() {
+18 -8
View File
@@ -46,14 +46,23 @@ public:
VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VKRRenderPass *compatibleRenderPass, int _width, int _height, const char *tag);
~VKRFramebuffer();
VkFramebuffer framebuf[RP_TYPE_COUNT]{};
VKRImage color{};
VKRImage depth{};
VkFramebuffer Get(VKRRenderPass *compatibleRenderPass, RenderPassType rpType);
int width = 0;
int height = 0;
VKRImage color{};
VKRImage depth{};
const char *Tag() const {
return tag_.c_str();
}
// TODO: Hide.
VulkanContext *vulkan_;
std::string tag;
private:
VkFramebuffer framebuf[RP_TYPE_COUNT]{};
std::string tag_;
};
enum class VKRRunType {
@@ -124,8 +133,8 @@ struct VKRGraphicsPipelineDesc {
VkPipelineMultisampleStateCreateInfo ms{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
// Replaced the ShaderStageInfo with promises here so we can wait for compiles to finish.
Promise<VkShaderModule> *vertexShader;
Promise<VkShaderModule> *fragmentShader;
Promise<VkShaderModule> *vertexShader = nullptr;
Promise<VkShaderModule> *fragmentShader = nullptr;
VkPipelineInputAssemblyStateCreateInfo inputAssembly{ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
VkVertexInputAttributeDescription attrs[8]{};
@@ -133,11 +142,11 @@ struct VKRGraphicsPipelineDesc {
VkPipelineVertexInputStateCreateInfo vis{ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
VkPipelineViewportStateCreateInfo views{ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
VkPipelineLayout pipelineLayout;
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
// Does not include the render pass type, it's passed in separately since the
// desc is persistent.
RPKey rpKey;
RPKey rpKey{};
};
// All the data needed to create a compute pipeline.
@@ -239,6 +248,7 @@ public:
// Deferred creation, like in GL. Unlike GL though, the purpose is to allow background creation and avoiding
// stalling the emulation thread as much as possible.
// We delay creating pipelines until the end of the current render pass, so we can create the right type immediately.
// WARNING: desc must stick around! It's not enough to build it on the stack.
VKRGraphicsPipeline *CreateGraphicsPipeline(VKRGraphicsPipelineDesc *desc) {
VKRGraphicsPipeline *pipeline = new VKRGraphicsPipeline();
_dbg_assert_(desc->vertexShader);
+4 -2
View File
@@ -273,6 +273,7 @@ public:
}
VKRGraphicsPipeline *pipeline = nullptr;
VKRGraphicsPipelineDesc vkrDesc;
PipelineFlags flags;
int stride[4]{};
@@ -1041,7 +1042,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
VKPipeline *pipeline = new VKPipeline(&renderManager_, desc.uniformDesc ? desc.uniformDesc->uniformBufferSize : 16 * sizeof(float), (PipelineFlags)pipelineFlags);
VKRGraphicsPipelineDesc gDesc{};
VKRGraphicsPipelineDesc &gDesc = pipeline->vkrDesc;
std::vector<VkPipelineShaderStageCreateInfo> stages;
stages.resize(desc.shaders.size());
@@ -1079,6 +1080,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
gDesc.blend0 = blend->attachments[0];
gDesc.cbs = blend->info;
gDesc.cbs.pAttachments = &gDesc.blend0;
gDesc.dss = depth->info;
@@ -1090,7 +1092,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
// We treat the three stencil states as a unit in other places, so let's do that here too.
const VkDynamicState dynamics[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK };
gDesc.ds.dynamicStateCount = depth->info.stencilTestEnable ? ARRAY_SIZE(dynamics) : 2;
for (int i = 0; i < gDesc.ds.dynamicStateCount; i++) {
for (size_t i = 0; i < gDesc.ds.dynamicStateCount; i++) {
gDesc.dynamicStates[i] = dynamics[i];
}
gDesc.ds.pDynamicStates = gDesc.dynamicStates;