diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index c10f7ac653..f829829389 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -141,7 +141,7 @@ bool FramebufferManagerCommon::UpdateSize() { void FramebufferManagerCommon::BeginFrame() { DecimateFBOs(); - currentRenderVfb_ = 0; + currentRenderVfb_ = nullptr; updateVRAM_ = !(g_Config.iRenderingMode == FB_NON_BUFFERED_MODE || g_Config.iRenderingMode == FB_BUFFERED_MODE); } @@ -1043,6 +1043,11 @@ void FramebufferManagerCommon::CopyDisplayToOutput() { void FramebufferManagerCommon::DecimateFBOs() { currentRenderVfb_ = 0; + for (auto iter : fbosToDelete_) { + delete iter; + } + fbosToDelete_.clear(); + for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *vfb = vfbs_[i]; int age = frameLastFramebufUsed_ - std::max(vfb->last_frame_render, vfb->last_frame_used); @@ -1153,7 +1158,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w, BlitFramebuffer(vfb, 0, 0, &old, 0, 0, std::min(vfb->bufferWidth, vfb->width), std::min(vfb->height, vfb->bufferHeight), 0); } } - delete old.fbo; + fbosToDelete_.push_back(old.fbo); if (needGLESRebinds_) { draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP }); } diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h index 2fd39d9a0d..62befe6913 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferCommon.h @@ -190,7 +190,7 @@ public: virtual ~FramebufferManagerCommon(); virtual void Init(); - void BeginFrame(); + virtual void BeginFrame(); void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format); void DestroyFramebuf(VirtualFramebuffer *v); @@ -209,6 +209,8 @@ public: FramebufferHeuristicParams inputs; GetFramebufferHeuristicInputs(&inputs, gstate); VirtualFramebuffer *vfb = DoSetRenderFrameBuffer(inputs, skipDrawReason); + _dbg_assert_msg_(G3D, vfb, "DoSetRenderFramebuffer must return a valid framebuffer."); + _dbg_assert_msg_(G3D, currentRenderVfb_, "DoSetRenderFramebuffer must set a valid framebuffer."); return vfb; } } @@ -412,6 +414,8 @@ protected: std::map tempFBOs_; + std::vector fbosToDelete_; + // Aggressively delete unused FBOs to save gpu memory. enum { FBO_OLD_AGE = 5, diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 53b39e6d32..852c37b615 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -1083,6 +1083,8 @@ void GPUCommon::ProcessEvent(GPUEvent ev) { break; case GPU_EVENT_COPY_DISPLAY_TO_OUTPUT: + // Ending the frame will unbind the framebuffer. Better finish any outstanding draw calls... + drawEngineCommon_->DispatchFlush(); CopyDisplayToOutputInternal(); break; diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index f9c6946e97..5cf7ab2cbd 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -93,6 +93,9 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw, Vulk vulkan2D_(vulkan) { InitDeviceObjects(); + + // After a blit we do need to rebind for the VulkanRenderManager to know what to do. + needGLESRebinds_ = true; } FramebufferManagerVulkan::~FramebufferManagerVulkan() { diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index 6a058eeed7..d8dd08ad3f 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -580,6 +580,9 @@ void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, step->copy.srcRect = srcRect; step->copy.dst = dst; step->copy.dstPos = dstPos; + + // TODO: Validate or clip copy-rectangles here. + std::unique_lock lock(mutex_); steps_.push_back(step); curRenderStep_ = nullptr; @@ -593,6 +596,9 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, step->blit.dst = dst; step->blit.dstRect = dstRect; step->blit.filter = filter; + + // TODO: Validate blit-rectangles here. + std::unique_lock lock(mutex_); steps_.push_back(step); curRenderStep_ = nullptr; @@ -985,6 +991,9 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; break; + default: + Crash(); + break; } TransitionImageLayout2(cmd, fb->color.image, VK_IMAGE_ASPECT_COLOR_BIT, @@ -1009,6 +1018,9 @@ void VulkanRenderManager::PerformBindFramebufferAsRenderTarget(const VKRStep &st srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; srcStage = VK_PIPELINE_STAGE_TRANSFER_BIT; break; + default: + Crash(); + break; } TransitionImageLayout2(cmd, fb->color.image, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, fb->color.layout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, @@ -1130,9 +1142,8 @@ void VulkanRenderManager::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) VKRFramebuffer *src = step.blit.src; VKRFramebuffer *dst = step.blit.dst; - int srcCount = 0; - int dstCount = 0; - + // If any validation needs to be performed here, it should probably have been done + // already when the blit was queued. So don't validate here. VkImageBlit blit{}; blit.srcOffsets[0].x = step.blit.srcRect.offset.x; blit.srcOffsets[0].y = step.blit.srcRect.offset.y; @@ -1153,6 +1164,10 @@ void VulkanRenderManager::PerformBlit(const VKRStep &step, VkCommandBuffer cmd) VkPipelineStageFlags srcStage = 0; VkPipelineStageFlags dstStage = 0; + + int srcCount = 0; + int dstCount = 0; + // First source barriers. if (step.blit.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { if (src->color.layout != VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) { diff --git a/ext/native/thin3d/VulkanRenderManager.h b/ext/native/thin3d/VulkanRenderManager.h index 6f4ffb5bff..4f45e0e6d4 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/ext/native/thin3d/VulkanRenderManager.h @@ -212,7 +212,6 @@ public: // Bad for performance but sometimes necessary for synchronous CPU readbacks (screenshots and whatnot). void Sync(); - void BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRRenderPassAction color, VKRRenderPassAction depth, uint32_t clearColor, float clearDepth, uint8_t clearStencil); VkImageView BindFramebufferAsTexture(VKRFramebuffer *fb, int binding, int aspectBit, int attachment); @@ -364,7 +363,6 @@ private: int curHeight_; bool insideFrame_ = false; VKRStep *curRenderStep_; - VKRFramebuffer *boundFramebuffer_; std::vector steps_; // Execution time state