diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 1fb3581e50..29470e8ce9 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -516,8 +516,10 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe textureCache_->ForgetLastTexture(); shaderManager_->DirtyLastShader(); - // Copy depth pixel value from the read framebuffer to the draw framebuffer if (prevVfb) { + // Copy depth value from the previously bound framebuffer to the current one. + // TODO: We should only do this if they are actually pointing to the same depth buffer address, surely.. + bool hasNewerDepth = prevVfb->last_frame_depth_render != 0 && prevVfb->last_frame_depth_render >= vfb->last_frame_depth_updated; if (!prevVfb->fbo || !vfb->fbo || !useBufferedRendering_ || !hasNewerDepth || isClearingDepth) { // If depth wasn't updated, then we're at least "two degrees" away from the data. @@ -1068,11 +1070,11 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, } shaderManager_->DirtyLastShader(); - char name[256]; - snprintf(name, sizeof(name), "%08x_%08x", vfb->fb_address, vfb->z_address); - vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth, name }); + char tag[256]; + snprintf(tag, sizeof(tag), "%08x_%08x_%dx%d", vfb->fb_address, vfb->z_address, w, h); + vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth, tag }); if (old.fbo) { - INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %d x %d x %d", vfb->fb_address, w, h, vfb->format); + INFO_LOG(FRAMEBUF, "Resizing FBO for %08x : %dx%dx%s", vfb->fb_address, w, h, GeBufferFormatToString(vfb->format)); if (vfb->fbo) { draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }, "ResizeFramebufFBO"); if (!skipCopy) { @@ -1088,7 +1090,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, } if (!vfb->fbo) { - ERROR_LOG(FRAMEBUF, "Error creating FBO during resize! %d x %d", vfb->renderWidth, vfb->renderHeight); + ERROR_LOG(FRAMEBUF, "Error creating FBO during resize! %dx%d", vfb->renderWidth, vfb->renderHeight); vfb->last_frame_failed = gpuStats.numFlips; } } diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index b3d39f7289..6a5d2415f9 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -141,7 +141,7 @@ void GPU_Vulkan::LoadCache(std::string filename) { } fclose(f); if (!result) { - WARN_LOG(G3D, "Bad Vulkan pipeline cache"); + WARN_LOG(G3D, "Incompatible Vulkan pipeline cache - rebuilding."); // Bad cache file for this GPU/Driver/etc. Delete it. File::Delete(filename); } else { diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 520ea6305b..df8446b6bb 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -583,6 +583,8 @@ struct StoredVulkanPipelineKey { } }; +// If you're looking for how to invalidate the cache, it's done in ShaderManagerVulkan, look for CACHE_VERSION and increment it. +// (Header of the same file this is stored in). void PipelineManagerVulkan::SaveCache(FILE *file, bool saveRawPipelineCache, ShaderManagerVulkan *shaderManager, Draw::DrawContext *drawContext) { VulkanRenderManager *rm = (VulkanRenderManager *)drawContext->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); VulkanQueueRunner *queueRunner = rm->GetQueueRunner(); diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 373e514a4b..79547ef39b 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -238,7 +238,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) { attachments[1].initialLayout = VK_IMAGE_LAYOUT_GENERAL; attachments[1].finalLayout = VK_IMAGE_LAYOUT_GENERAL; #else - attachments[1].initialLayout = key.prevDepthLayout; + attachments[1].initialLayout = key.prevDepthStencilLayout; attachments[1].finalLayout = key.finalDepthStencilLayout; #endif attachments[1].flags = 0; @@ -294,7 +294,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) { break; } - switch (key.prevDepthLayout) { + switch (key.prevDepthStencilLayout) { case VK_IMAGE_LAYOUT_UNDEFINED: // No need to specify stage or access. break; @@ -314,7 +314,7 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) { deps[numDeps].srcStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; break; default: - _dbg_assert_msg_(false, "GetRenderPass: Unexpected depth layout %d", (int)key.prevDepthLayout); + _dbg_assert_msg_(false, "GetRenderPass: Unexpected depth layout %d", (int)key.prevDepthStencilLayout); break; } @@ -730,6 +730,16 @@ void VulkanQueueRunner::ApplySonicHack(std::vector &steps) { } } +const char *AspectToString(VkImageAspectFlags aspect) { + switch (aspect) { + case VK_IMAGE_ASPECT_COLOR_BIT: return "COLOR"; + case VK_IMAGE_ASPECT_DEPTH_BIT: return "DEPTH"; + case VK_IMAGE_ASPECT_STENCIL_BIT: return "STENCIL"; + case VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT: return "DEPTHSTENCIL"; + default: return "UNUSUAL"; + } +} + std::string VulkanQueueRunner::StepToString(const VKRStep &step) const { char buffer[256]; switch (step.stepType) { @@ -737,23 +747,23 @@ std::string VulkanQueueRunner::StepToString(const VKRStep &step) const { { int w = step.render.framebuffer ? step.render.framebuffer->width : vulkan_->GetBackbufferWidth(); int h = step.render.framebuffer ? step.render.framebuffer->height : vulkan_->GetBackbufferHeight(); - snprintf(buffer, sizeof(buffer), "RenderPass %s (draws: %d, %dx%d, fb: %p, )", step.tag, step.render.numDraws, w, h, step.render.framebuffer); + snprintf(buffer, sizeof(buffer), "RENDER %s (draws: %d, %dx%d, fb: %p, )", step.tag, step.render.numDraws, w, h, step.render.framebuffer); break; } case VKRStepType::COPY: - snprintf(buffer, sizeof(buffer), "Copy '%s' (%dx%d)", step.tag, step.copy.srcRect.extent.width, step.copy.srcRect.extent.height); + 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)); break; case VKRStepType::BLIT: - snprintf(buffer, sizeof(buffer), "Blit '%s' (%dx%d->%dx%d)", step.tag, step.blit.srcRect.extent.width, step.blit.srcRect.extent.height, step.blit.dstRect.extent.width, step.blit.dstRect.extent.height); + 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)); break; case VKRStepType::READBACK: - snprintf(buffer, sizeof(buffer), "Readback '%s' (%dx%d, fb: %p)", step.tag, step.readback.srcRect.extent.width, step.readback.srcRect.extent.height, step.readback.src); + 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)); break; case VKRStepType::READBACK_IMAGE: - snprintf(buffer, sizeof(buffer), "ReadbackImage '%s' (%dx%d)", step.tag, step.readback_image.srcRect.extent.width, step.readback_image.srcRect.extent.height); + snprintf(buffer, sizeof(buffer), "READBACK_IMAGE '%s' (%dx%d)", step.tag, step.readback_image.srcRect.extent.width, step.readback_image.srcRect.extent.height); break; case VKRStepType::RENDER_SKIP: - snprintf(buffer, sizeof(buffer), "(SKIPPED RenderPass) %s", step.tag); + snprintf(buffer, sizeof(buffer), "(RENDER_SKIP) %s", step.tag); break; default: buffer[0] = 0; @@ -849,14 +859,13 @@ void VulkanQueueRunner::ApplyRenderPassMerge(std::vector &steps) { } } -void VulkanQueueRunner::LogSteps(const std::vector &steps) { - INFO_LOG(G3D, "======================================="); +void VulkanQueueRunner::LogSteps(const std::vector &steps, bool verbose) { + INFO_LOG(G3D, "=================== FRAME ===================="); for (size_t i = 0; i < steps.size(); i++) { const VKRStep &step = *steps[i]; - INFO_LOG(G3D, "%s", StepToString(step).c_str()); switch (step.stepType) { case VKRStepType::RENDER: - LogRenderPass(step); + LogRenderPass(step, verbose); break; case VKRStepType::COPY: LogCopy(step); @@ -875,6 +884,7 @@ void VulkanQueueRunner::LogSteps(const std::vector &steps) { break; } } + INFO_LOG(G3D, "------------------- SUBMIT ------------------"); } const char *RenderPassActionName(VKRRenderPassAction a) { @@ -889,10 +899,37 @@ const char *RenderPassActionName(VKRRenderPassAction a) { return "?"; } -void VulkanQueueRunner::LogRenderPass(const VKRStep &pass) { +const char *ImageLayoutToString(VkImageLayout layout) { + switch (layout) { + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: return "COLOR_ATTACHMENT"; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: return "DEPTH_STENCIL_ATTACHMENT"; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: return "SHADER_READ_ONLY"; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: return "TRANSFER_SRC"; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: return "TRANSFER_DST"; + case VK_IMAGE_LAYOUT_GENERAL: return "GENERAL"; + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: return "PRESENT_SRC_KHR"; + case VK_IMAGE_LAYOUT_UNDEFINED: return "UNDEFINED"; + default: return "(unknown)"; + } +} + +void VulkanQueueRunner::LogRenderPass(const VKRStep &pass, bool verbose) { const auto &r = pass.render; - int fb = (int)(intptr_t)(r.framebuffer ? r.framebuffer->framebuf : 0); - INFO_LOG(G3D, "RenderPass Begin(%x, %s, %s, %s)", fb, RenderPassActionName(r.color), RenderPassActionName(r.depth), RenderPassActionName(r.stencil)); + const char *framebuf = r.framebuffer ? r.framebuffer->tag.c_str() : "backbuffer"; + int w = r.framebuffer ? r.framebuffer->width : vulkan_->GetBackbufferWidth(); + int h = r.framebuffer ? r.framebuffer->height : vulkan_->GetBackbufferHeight(); + + INFO_LOG(G3D, "RENDER Begin(%s, draws: %d, %dx%d, %s, %s, %s)", framebuf, r.numDraws, w, h, RenderPassActionName(r.color), RenderPassActionName(r.depth), RenderPassActionName(r.stencil)); + // TODO: Log these in detail. + for (int i = 0; i < 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)); + } + + if (!verbose) { + INFO_LOG(G3D, "RENDER End(%s) - %d commands executed", framebuf, (int)pass.commands.size()); + return; + } + for (auto &cmd : pass.commands) { switch (cmd.cmd) { case VKRRenderCommand::REMOVED: @@ -931,7 +968,7 @@ void VulkanQueueRunner::LogRenderPass(const VKRStep &pass) { break; } } - INFO_LOG(G3D, "RenderPass End(%x)", fb); + INFO_LOG(G3D, "RENDER End(%s)", framebuf); } void VulkanQueueRunner::LogCopy(const VKRStep &step) { @@ -952,6 +989,7 @@ void VulkanQueueRunner::LogReadbackImage(const VKRStep &step) { void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer cmd) { // TODO: If there are multiple, we can transition them together. + for (const auto &iter : step.preTransitions) { if (iter.aspect == VK_IMAGE_ASPECT_COLOR_BIT && iter.fb->color.layout != iter.targetLayout) { VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; @@ -1044,6 +1082,10 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c // Don't execute empty renderpasses that keep the contents. if (step.commands.empty() && step.render.color == VKRRenderPassAction::KEEP && step.render.depth == VKRRenderPassAction::KEEP && step.render.stencil == VKRRenderPassAction::KEEP) { // Nothing to do. + + // TODO: Though - a later step might have used this step's finalColorLayout etc to get things in a layout it expects. + // Should we just do a barrier? Or just let the later step deal with not having things in its preferred layout, like now? + return; } @@ -1084,10 +1126,12 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c } if (stage) { vkCmdPipelineBarrier(cmd, stage, stage, 0, 0, nullptr, 0, nullptr, n, barriers); + // No need to modify the image layouts here - it's just an execution barrier. } } // This is supposed to bind a vulkan render pass to the command buffer. + // This reads the layout of the color and depth images, and chooses a render pass using them. PerformBindFramebufferAsRenderTarget(step, cmd); int curWidth = step.render.framebuffer ? step.render.framebuffer->width : vulkan_->GetBackbufferWidth(); @@ -1355,7 +1399,7 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { } } - // We can't copy only depth or only stencil unfortunately. + // We can't copy only depth or only stencil unfortunately - or can we?. if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { if (src->depth.layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { SetupTransitionToTransferSrc(src->depth, srcBarriers[srcCount++], srcStage, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); @@ -1378,16 +1422,8 @@ void VulkanQueueRunner::PerformCopy(const VKRStep &step, VkCommandBuffer cmd) { vkCmdCopyImage(cmd, src->color.image, src->color.layout, dst->color.image, dst->color.layout, 1, ©); } if (step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - copy.srcSubresource.aspectMask = 0; - copy.dstSubresource.aspectMask = 0; - if (step.copy.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) { - copy.srcSubresource.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - copy.dstSubresource.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - } - if (step.copy.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) { - copy.srcSubresource.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - copy.dstSubresource.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - } + copy.srcSubresource.aspectMask = step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); + copy.dstSubresource.aspectMask = step.copy.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT); vkCmdCopyImage(cmd, src->depth.image, src->depth.layout, dst->depth.image, dst->depth.layout, 1, ©); } } diff --git a/ext/native/thin3d/VulkanQueueRunner.h b/ext/native/thin3d/VulkanQueueRunner.h index a89951af3b..660d406da9 100644 --- a/ext/native/thin3d/VulkanQueueRunner.h +++ b/ext/native/thin3d/VulkanQueueRunner.h @@ -182,7 +182,7 @@ public: // RunSteps can modify steps but will leave it in a valid state. void RunSteps(VkCommandBuffer cmd, std::vector &steps, QueueProfileContext *profile); - void LogSteps(const std::vector &steps); + void LogSteps(const std::vector &steps, bool verbose); std::string StepToString(const VKRStep &step) const; @@ -210,7 +210,7 @@ public: VKRRenderPassAction depthLoadAction; VKRRenderPassAction stencilLoadAction; VkImageLayout prevColorLayout; - VkImageLayout prevDepthLayout; + VkImageLayout prevDepthStencilLayout; VkImageLayout finalColorLayout; VkImageLayout finalDepthStencilLayout; }; @@ -250,7 +250,7 @@ private: void PerformReadback(const VKRStep &pass, VkCommandBuffer cmd); void PerformReadbackImage(const VKRStep &pass, VkCommandBuffer cmd); - void LogRenderPass(const VKRStep &pass); + void LogRenderPass(const VKRStep &pass, bool verbose); void LogCopy(const VKRStep &pass); void LogBlit(const VKRStep &pass); void LogReadback(const VKRStep &pass); diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index cc4d3a1497..4960b5c045 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -19,8 +19,57 @@ #define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL #endif +VKRFramebuffer::VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VkRenderPass renderPass, int _width, int _height, const char *tag) : vulkan_(vk) { + width = _width; + height = _height; -void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color) { + 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); + + VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; + VkImageView views[2]{}; + + fbci.renderPass = renderPass; + fbci.attachmentCount = 2; + fbci.pAttachments = views; + views[0] = color.imageView; + views[1] = depth.imageView; + fbci.width = width; + fbci.height = height; + fbci.layers = 1; + + vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf); + if (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, VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag).c_str()); + } + + if (tag) { + this->tag = tag; + } +} + +VKRFramebuffer::~VKRFramebuffer() { + if (color.image) + vulkan_->Delete().QueueDeleteImage(color.image); + if (depth.image) + vulkan_->Delete().QueueDeleteImage(depth.image); + if (color.imageView) + vulkan_->Delete().QueueDeleteImageView(color.imageView); + if (depth.imageView) + vulkan_->Delete().QueueDeleteImageView(depth.imageView); + if (depth.depthSampleView) + vulkan_->Delete().QueueDeleteImageView(depth.depthSampleView); + if (color.memory) + vulkan_->Delete().QueueDeleteDeviceMemory(color.memory); + if (depth.memory) + vulkan_->Delete().QueueDeleteDeviceMemory(depth.memory); + if (framebuf) + vulkan_->Delete().QueueDeleteFramebuffer(framebuf); +} + +void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag) { VkImageCreateInfo ici{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; ici.arrayLayers = 1; ici.mipLevels = 1; @@ -111,6 +160,7 @@ void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int img.layout = initialLayout; img.format = format; + img.tag = tag ? tag : "N/A"; } VulkanRenderManager::VulkanRenderManager(VulkanContext *vulkan) : vulkan_(vulkan), queueRunner_(vulkan) { diff --git a/ext/native/thin3d/VulkanRenderManager.h b/ext/native/thin3d/VulkanRenderManager.h index 9bac655676..50657051ef 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/ext/native/thin3d/VulkanRenderManager.h @@ -21,62 +21,25 @@ // Simple independent framebuffer image. Gets its own allocation, we don't have that many framebuffers so it's fine // to let them have individual non-pooled allocations. Until it's not fine. We'll see. struct VKRImage { + // These four are "immutable". VkImage image; VkImageView imageView; VkImageView depthSampleView; VkDeviceMemory memory; - VkImageLayout layout; VkFormat format; + + // This one is used by QueueRunner's Perform functions to keep track. CANNOT be used anywhere else due to sync issues. + VkImageLayout layout; + + // For debugging. + std::string tag; }; -void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color); +void CreateImage(VulkanContext *vulkan, VkCommandBuffer cmd, VKRImage &img, int width, int height, VkFormat format, VkImageLayout initialLayout, bool color, const char *tag); class VKRFramebuffer { public: - VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VkRenderPass renderPass, int _width, int _height, const char *tag) : vulkan_(vk) { - width = _width; - height = _height; - - CreateImage(vulkan_, initCmd, color, width, height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true); - CreateImage(vulkan_, initCmd, depth, width, height, vulkan_->GetDeviceInfo().preferredDepthStencilFormat, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false); - - VkFramebufferCreateInfo fbci{ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO }; - VkImageView views[2]{}; - - fbci.renderPass = renderPass; - fbci.attachmentCount = 2; - fbci.pAttachments = views; - views[0] = color.imageView; - views[1] = depth.imageView; - fbci.width = width; - fbci.height = height; - fbci.layers = 1; - - vkCreateFramebuffer(vulkan_->GetDevice(), &fbci, nullptr, &framebuf); - if (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, VK_OBJECT_TYPE_FRAMEBUFFER, StringFromFormat("fb_%s", tag).c_str()); - } - } - - ~VKRFramebuffer() { - if (color.image) - vulkan_->Delete().QueueDeleteImage(color.image); - if (depth.image) - vulkan_->Delete().QueueDeleteImage(depth.image); - if (color.imageView) - vulkan_->Delete().QueueDeleteImageView(color.imageView); - if (depth.imageView) - vulkan_->Delete().QueueDeleteImageView(depth.imageView); - if (depth.depthSampleView) - vulkan_->Delete().QueueDeleteImageView(depth.depthSampleView); - if (color.memory) - vulkan_->Delete().QueueDeleteDeviceMemory(color.memory); - if (depth.memory) - vulkan_->Delete().QueueDeleteDeviceMemory(depth.memory); - if (framebuf) - vulkan_->Delete().QueueDeleteFramebuffer(framebuf); - } + VKRFramebuffer(VulkanContext *vk, VkCommandBuffer initCmd, VkRenderPass renderPass, int _width, int _height, const char *tag); + ~VKRFramebuffer(); int numShadows = 1; // TODO: Support this. @@ -87,6 +50,7 @@ public: int height = 0; VulkanContext *vulkan_; + std::string tag; }; enum class VKRRunType {