From 41d8da16123648774acde7135e9bc94b358cee1d Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Wed, 30 Sep 2026 00:47:14 -0400 Subject: [PATCH] Remove deferred clears --- .../renderer_opengl/gl_texture_cache.h | 2 - src/video_core/renderer_vulkan/blit_image.cpp | 28 +++++ .../renderer_vulkan/vk_graphics_pipeline.cpp | 3 + .../renderer_vulkan/vk_query_cache.cpp | 4 + .../renderer_vulkan/vk_query_cache.h | 2 + .../renderer_vulkan/vk_rasterizer.cpp | 87 +++++++------ .../renderer_vulkan/vk_scheduler.cpp | 119 ++++++------------ src/video_core/renderer_vulkan/vk_scheduler.h | 28 +---- .../renderer_vulkan/vk_texture_cache.cpp | 4 - .../renderer_vulkan/vk_texture_cache.h | 2 - src/video_core/texture_cache/texture_cache.h | 2 - 11 files changed, 122 insertions(+), 159 deletions(-) diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 7c7ee14580..19a1b79cf8 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -75,8 +75,6 @@ public: void Finish(); - void FlushDeferredClear() {} - StagingBufferMap UploadStagingBuffer(size_t size); StagingBufferMap DownloadStagingBuffer(size_t size, bool deferred = false); diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 7b0b784ac6..6821ae9550 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -476,6 +476,23 @@ void RecordShaderReadBarrier(Scheduler& scheduler, const ImageView& image_view) }); } +void DiscardCoveredAttachments(Scheduler& scheduler, const Framebuffer* framebuffer, + const Region2D& region, bool writes_stencil) { + const VkExtent2D area = framebuffer->RenderArea(); + if ((std::min)(region.start.x, region.end.x) > 0 || + (std::min)(region.start.y, region.end.y) > 0 || + (std::max)(region.start.x, region.end.x) < static_cast(area.width) || + (std::max)(region.start.y, region.end.y) < static_cast(area.height) || + framebuffer->Attachments().layers != 1) { + return; + } + u32 attachments = 1u | Scheduler::DEPTH_ATTACHMENT_BIT; + if (writes_stencil) { + attachments |= Scheduler::STENCIL_ATTACHMENT_BIT; + } + scheduler.OverrideLoadOps(framebuffer, attachments, VK_ATTACHMENT_LOAD_OP_DONT_CARE, {}); +} + [[nodiscard]] VkSampleCountFlagBits SampleCountFlag(u32 num_samples) { switch (num_samples) { case 2: @@ -661,6 +678,7 @@ void BlitImageHelper::BlitImpl(const Framebuffer* dst_framebuffer, } RecordShaderReadBarrier(scheduler, src_image_view); + DiscardCoveredAttachments(scheduler, dst_framebuffer, dst_region, blit_stencil); scheduler.RequestRenderpass(dst_framebuffer); scheduler.Record([this, dst_region, src_region, pipeline, layout, sampler, src_view, src_stencil_view, blit_stencil](vk::CommandBuffer cmdbuf) { @@ -1067,8 +1085,13 @@ void BlitImageHelper::Convert(VkPipeline pipeline, const Framebuffer* dst_frameb const VkImageView src_view = src_image_view.Handle(Shader::TextureType::Color2D); const VkSampler sampler = *nearest_sampler; const VkExtent2D extent = GetConversionExtent(src_image_view); + const Region2D region{ + .start = {0, 0}, + .end = {static_cast(extent.width), static_cast(extent.height)}, + }; RecordShaderReadBarrier(scheduler, src_image_view); + DiscardCoveredAttachments(scheduler, dst_framebuffer, region, false); scheduler.RequestRenderpass(dst_framebuffer); scheduler.Record([pipeline, layout, sampler, src_view, extent, this](vk::CommandBuffer cmdbuf) { const VkOffset2D offset{ @@ -1112,8 +1135,13 @@ void BlitImageHelper::ConvertDepthStencil(VkPipeline pipeline, const Framebuffer const VkImageView src_stencil_view = src_image_view.StencilView(); const VkSampler sampler = *nearest_sampler; const VkExtent2D extent = GetConversionExtent(src_image_view); + const Region2D region{ + .start = {0, 0}, + .end = {static_cast(extent.width), static_cast(extent.height)}, + }; RecordShaderReadBarrier(scheduler, src_image_view); + DiscardCoveredAttachments(scheduler, dst_framebuffer, region, false); scheduler.RequestRenderpass(dst_framebuffer); scheduler.Record([pipeline, layout, sampler, src_depth_view, src_stencil_view, extent, this](vk::CommandBuffer cmdbuf) { diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 0a8a2af973..5f6f525d1d 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -143,6 +143,9 @@ struct AttachmentAccess { AttachmentAccess MakeAttachmentAccess(const Maxwell& regs) { AttachmentAccess access{}; + if (regs.rasterize_enable == 0) { + return access; + } for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) { size_t mask_index = index; if (regs.color_mask_common) { diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 8b545b327d..5a574e289a 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -1402,6 +1402,10 @@ void QueryCacheRuntime::ResumeHostConditionalRendering() { impl->is_hcr_running = true; } +bool QueryCacheRuntime::IsHostConditionalRenderingSet() const noexcept { + return impl->hcr_is_set; +} + void QueryCacheRuntime::HostConditionalRenderingCompareValueImpl(VideoCommon::LookupData object, bool is_equal) { { diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h index bbb5234e11..f89038f8b7 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.h +++ b/src/video_core/renderer_vulkan/vk_query_cache.h @@ -48,6 +48,8 @@ public: void ResumeHostConditionalRendering(); + [[nodiscard]] bool IsHostConditionalRenderingSet() const noexcept; + bool HostConditionalRenderingCompareValue(VideoCommon::LookupData object_1, bool qc_dirty); bool HostConditionalRenderingCompareValues(VideoCommon::LookupData object_1, diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 4bc513172e..27332f8129 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -445,15 +445,10 @@ void RasterizerVulkan::Clear(u32 layer_count) { const Framebuffer* const framebuffer = texture_cache.GetFramebuffer(); const VkExtent2D render_area = framebuffer->RenderArea(); - constexpr bool ENABLE_DEFERRED_CLEAR = true; const bool color_full_channels = regs.clear_surface.R && regs.clear_surface.G && regs.clear_surface.B && regs.clear_surface.A; const bool stencil_partial = use_stencil && framebuffer->HasAspectStencilBit() && regs.stencil_front_mask != 0xFF && regs.stencil_front_mask != 0; - const bool ds_used = use_depth || use_stencil; - const bool ds_deferrable = - !ds_used || ((!framebuffer->HasAspectDepthBit() || use_depth) && - (!framebuffer->HasAspectStencilBit() || use_stencil) && !stencil_partial); u32 up_scale = 1; u32 down_shift = 0; if (texture_cache.IsRescaling()) { @@ -519,17 +514,16 @@ void RasterizerVulkan::Clear(u32 layer_count) { clear_rect.rect.offset.x == 0 && clear_rect.rect.offset.y == 0 && clear_rect.rect.extent.width >= render_area.width && clear_rect.rect.extent.height >= render_area.height; - const bool can_defer_clear = ENABLE_DEFERRED_CLEAR && (!regs.clear_control.use_scissor || clear_covers_render_area) && - regs.clear_surface.layer == 0 && - layer_count >= framebuffer->Attachments().layers && - !scheduler.IsRenderPassActive() && - (!use_color || color_full_channels) && ds_deferrable; - if (!can_defer_clear) { + const bool clear_on_load = (!regs.clear_control.use_scissor || clear_covers_render_area) && + regs.clear_surface.layer == 0 && + layer_count >= framebuffer->Attachments().layers && + !query_cache_runtime.IsHostConditionalRenderingSet(); + const auto request_renderpass = [&] { scheduler.RequestRenderpass(framebuffer); query_cache.NotifySegment(true); query_cache.CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, maxwell3d->regs.zpass_pixel_count_enable); - } + }; UpdateViewportsState(regs); const u32 color_attachment = regs.clear_surface.RT; @@ -549,26 +543,26 @@ void RasterizerVulkan::Clear(u32 layer_count) { clear_value.color.int32[i] = s32(f32(s64(int_size - 1) << 1) * (regs.clear_color[i] - 0.5f)); } - if (color_full_channels) { - if (can_defer_clear) { - scheduler.DeferColorClear(framebuffer, color_attachment, clear_value); - } else { - scheduler.Record([color_attachment, clear_value, clear_rect](vk::CommandBuffer cmdbuf) { - const VkClearAttachment attachment{ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .colorAttachment = color_attachment, - .clearValue = clear_value, - }; - cmdbuf.ClearAttachments(attachment, clear_rect); - }); - } - } else { + if (!color_full_channels) { u8 color_mask = u8(regs.clear_surface.R | regs.clear_surface.G << 1 | regs.clear_surface.B << 2 | regs.clear_surface.A << 3); Region2D dst_region = { Offset2D{.x = clear_rect.rect.offset.x, .y = clear_rect.rect.offset.y}, Offset2D{.x = clear_rect.rect.offset.x + s32(clear_rect.rect.extent.width), .y = clear_rect.rect.offset.y + s32(clear_rect.rect.extent.height)}}; + request_renderpass(); blit_image.ClearColor(framebuffer, color_mask, regs.clear_color, dst_region); + } else if (!clear_on_load || + !scheduler.OverrideLoadOps(framebuffer, 1u << color_attachment, + VK_ATTACHMENT_LOAD_OP_CLEAR, clear_value)) { + request_renderpass(); + scheduler.Record([color_attachment, clear_value, clear_rect](vk::CommandBuffer cmdbuf) { + const VkClearAttachment attachment{ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .colorAttachment = color_attachment, + .clearValue = clear_value, + }; + cmdbuf.ClearAttachments(attachment, clear_rect); + }); } } @@ -576,41 +570,46 @@ void RasterizerVulkan::Clear(u32 layer_count) { return; } VkImageAspectFlags aspect_flags = 0; + u32 ds_attachments = 0; if (use_depth && framebuffer->HasAspectDepthBit()) { aspect_flags |= VK_IMAGE_ASPECT_DEPTH_BIT; + ds_attachments |= Scheduler::DEPTH_ATTACHMENT_BIT; } if (use_stencil && framebuffer->HasAspectStencilBit()) { aspect_flags |= VK_IMAGE_ASPECT_STENCIL_BIT; + ds_attachments |= Scheduler::STENCIL_ATTACHMENT_BIT; } if (aspect_flags == 0) { return; } - if (use_stencil && framebuffer->HasAspectStencilBit() && regs.stencil_front_mask != 0xFF && - regs.stencil_front_mask != 0) { + if (stencil_partial) { Region2D dst_region = { Offset2D{.x = clear_rect.rect.offset.x, .y = clear_rect.rect.offset.y}, Offset2D{.x = clear_rect.rect.offset.x + s32(clear_rect.rect.extent.width), .y = clear_rect.rect.offset.y + s32(clear_rect.rect.extent.height)}}; + request_renderpass(); blit_image.ClearDepthStencil(framebuffer, use_depth, regs.clear_depth, u8(regs.stencil_front_mask), regs.clear_stencil, regs.stencil_front_func_mask, dst_region); - } else if (can_defer_clear) { - VkClearValue ds_value{}; - ds_value.depthStencil.depth = regs.clear_depth; - ds_value.depthStencil.stencil = regs.clear_stencil; - scheduler.DeferDepthStencilClear(framebuffer, ds_value); - } else { - scheduler.Record([clear_depth = regs.clear_depth, clear_stencil = regs.clear_stencil, - clear_rect, aspect_flags](vk::CommandBuffer cmdbuf) { - VkClearAttachment attachment; - attachment.aspectMask = aspect_flags; - attachment.colorAttachment = 0; - attachment.clearValue.depthStencil.depth = clear_depth; - attachment.clearValue.depthStencil.stencil = clear_stencil; - cmdbuf.ClearAttachments(attachment, clear_rect); - }); + return; } + VkClearValue ds_value{}; + ds_value.depthStencil.depth = regs.clear_depth; + ds_value.depthStencil.stencil = regs.clear_stencil; + if (clear_on_load && scheduler.OverrideLoadOps(framebuffer, ds_attachments, + VK_ATTACHMENT_LOAD_OP_CLEAR, ds_value)) { + return; + } + request_renderpass(); + scheduler.Record([ds_value, clear_rect, aspect_flags](vk::CommandBuffer cmdbuf) { + const VkClearAttachment attachment{ + .aspectMask = aspect_flags, + .colorAttachment = 0, + .clearValue = ds_value, + }; + cmdbuf.ClearAttachments(attachment, clear_rect); + }); } void RasterizerVulkan::DispatchCompute() { @@ -1014,7 +1013,7 @@ void RasterizerVulkan::FlushWork() { draw_counter = 0; return; } - if ((draw_counter & CHECK_MASK) == CHECK_MASK) { + if ((draw_counter & CHECK_MASK) == CHECK_MASK && !scheduler.IsRenderPassActive()) { scheduler.DispatchWork(); } } diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 22debf0b28..b23a6f0c88 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -120,11 +120,12 @@ void Scheduler::DispatchWork() { } } -void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer, - const RenderingAttachments& attachments) { +void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer) { + const RenderingAttachments& attachments = framebuffer->Attachments(); PublishComputeWrites(); state.framebuffer_id = framebuffer->Id(); ++renderpass_serial; + renderpass_pristine = true; attachments_touched = 0; attachments_written = 0; @@ -149,91 +150,48 @@ void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer, framebuffer->MarkResolveShadowsUpToDate(); } -void Scheduler::RealizeDeferredClear() { - if (deferred_clear.framebuffer == nullptr) { - return; - } - const DeferredClear dc = deferred_clear; - deferred_clear = {}; - - RenderingAttachments attachments = dc.framebuffer->Attachments(); - for (u32 slot = 0; slot < attachments.num_colors; ++slot) { - if ((dc.color_clear_mask & (1u << slot)) == 0) { - continue; - } - VkRenderingAttachmentInfo& attachment = attachments.colors[slot]; - attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachment.clearValue = dc.color_values[slot]; - if (dc.framebuffer->DiscardsMsaaColor()) { - attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - } - } - if (dc.depth_stencil) { - for (VkRenderingAttachmentInfo* const attachment : - {&attachments.depth, &attachments.stencil}) { - attachment->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachment->clearValue = dc.depth_stencil_value; - if (dc.framebuffer->DiscardsMsaaDepthStencil()) { - attachment->storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - } - } - } - EndRenderPass(); - BeginRenderPassImpl(dc.framebuffer, attachments); - if (dc.depth_stencil) { - attachments_written |= DEPTH_ATTACHMENT_BIT | STENCIL_ATTACHMENT_BIT; - } -} - -bool Scheduler::DeferColorClear(const Framebuffer* framebuffer, u32 rt_slot, - const VkClearValue& value) { - if (IsRenderPassActive()) { - return false; - } - if (deferred_clear.framebuffer != nullptr && deferred_clear.framebuffer != framebuffer) { - RealizeDeferredClear(); - EndRenderPass(); - } - deferred_clear.framebuffer = framebuffer; - deferred_clear.color_clear_mask |= 1u << rt_slot; - deferred_clear.color_values[rt_slot] = value; - return true; -} - -bool Scheduler::DeferDepthStencilClear(const Framebuffer* framebuffer, const VkClearValue& value) { - if (IsRenderPassActive()) { - return false; - } - if (deferred_clear.framebuffer != nullptr && deferred_clear.framebuffer != framebuffer) { - RealizeDeferredClear(); - EndRenderPass(); - } - deferred_clear.framebuffer = framebuffer; - deferred_clear.depth_stencil = true; - deferred_clear.depth_stencil_value = value; - return true; -} - -void Scheduler::FlushDeferredClear() { - if (deferred_clear.framebuffer == nullptr) { - return; - } - RealizeDeferredClear(); - EndRenderPass(); -} - void Scheduler::RequestRenderpass(const Framebuffer* framebuffer, u32 touched, u32 written) { - if (deferred_clear.framebuffer == framebuffer) { - RealizeDeferredClear(); - } else if (framebuffer->Id() != state.framebuffer_id) { - // Ends any active pass and realizes a deferred clear + if (framebuffer->Id() != state.framebuffer_id) { EndRenderPass(); - BeginRenderPassImpl(framebuffer, framebuffer->Attachments()); + BeginRenderPassImpl(framebuffer); } + renderpass_pristine = false; attachments_touched |= touched; attachments_written |= written; } +bool Scheduler::OverrideLoadOps(const Framebuffer* framebuffer, u32 attachments, + VkAttachmentLoadOp load_op, const VkClearValue& value) { + if (framebuffer->Id() != state.framebuffer_id) { + EndRenderPass(); + BeginRenderPassImpl(framebuffer); + } + if (!renderpass_pristine || recorded_attachments == nullptr) { + return false; + } + const auto set_load_op = [&](VkRenderingAttachmentInfo& attachment, bool discards_msaa) { + attachment.loadOp = load_op; + attachment.clearValue = value; + if (discards_msaa && load_op == VK_ATTACHMENT_LOAD_OP_CLEAR) { + attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + } + }; + for (u32 slot = 0; slot < recorded_attachments->num_colors; ++slot) { + if ((attachments & (1u << slot)) != 0) { + set_load_op(recorded_attachments->colors[slot], framebuffer->DiscardsMsaaColor()); + } + } + if ((attachments & DEPTH_ATTACHMENT_BIT) != 0) { + set_load_op(recorded_attachments->depth, framebuffer->DiscardsMsaaDepthStencil()); + } + if ((attachments & STENCIL_ATTACHMENT_BIT) != 0) { + set_load_op(recorded_attachments->stencil, framebuffer->DiscardsMsaaDepthStencil()); + } + attachments_touched |= attachments; + attachments_written |= attachments; + return true; +} + void Scheduler::RequestOutsideRenderPassOperationContext() { EndRenderPass(); PublishComputeWrites(); @@ -457,7 +415,6 @@ void Scheduler::EndPendingOperations() { void Scheduler::EndRenderPass() { - RealizeDeferredClear(); if (state.framebuffer_id == 0) { return; } diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index a4bd593f40..21385549ee 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -66,14 +66,8 @@ public: void RequestRenderpass(const Framebuffer* framebuffer, u32 touched = ALL_ATTACHMENTS, u32 written = ALL_ATTACHMENTS); - /// Defers a full-attachment color clear so it becomes the next render pass. - bool DeferColorClear(const Framebuffer* framebuffer, u32 rt_slot, const VkClearValue& value); - - /// Defers a full depth/stencil clear so it becomes the next render pass. - bool DeferDepthStencilClear(const Framebuffer* framebuffer, const VkClearValue& value); - - /// Realizes any pending deferred clear before its framebuffer can be moved or freed. - void FlushDeferredClear(); + bool OverrideLoadOps(const Framebuffer* framebuffer, u32 attachments, + VkAttachmentLoadOp load_op, const VkClearValue& value); /// Requests the current execution context to be able to execute operations only allowed outside /// of a renderpass. @@ -302,20 +296,7 @@ private: bool descriptor_buffer_bound = false; }; - struct DeferredClear { - const Framebuffer* framebuffer = nullptr; - u32 color_clear_mask = 0; - std::array color_values{}; - bool depth_stencil = false; - VkClearValue depth_stencil_value{}; - }; - - /// Begins a render pass for the given framebuffer, optionally with clear values. - void BeginRenderPassImpl(const Framebuffer* framebuffer, - const RenderingAttachments& attachments); - - /// If a deferred clear is pending. - void RealizeDeferredClear(); + void BeginRenderPassImpl(const Framebuffer* framebuffer); void WorkerThread(std::stop_token stop_token); @@ -344,8 +325,6 @@ private: vk::CommandBuffer current_cmdbuf; vk::CommandBuffer current_upload_cmdbuf; - DeferredClear deferred_clear; - std::unique_ptr chunk; std::function on_submit; @@ -354,6 +333,7 @@ private: u64 renderpass_serial = 0; u64 wfi_serial = 0; bool renderpass_writes = false; + bool renderpass_pristine = false; bool compute_writes = false; u32 attachments_touched = 0; u32 attachments_written = 0; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 51aedac099..55b3b7e81d 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -1884,10 +1884,6 @@ bool TextureCacheRuntime::CanReportMemoryUsage() const { return device.CanReportMemoryUsage(); } -void TextureCacheRuntime::FlushDeferredClear() { - scheduler.FlushDeferredClear(); -} - VkImage TextureCacheRuntime::AcquireMsaaScratchImage(const VkImageCreateInfo& image_ci) { const MsaaScratchKey key{ .format = image_ci.format, diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index c41583dcb4..adce1678f7 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -58,8 +58,6 @@ public: void TickFrame(); - void FlushDeferredClear(); - u64 GetDeviceLocalMemory() const; u64 GetDeviceMemoryUsage() const; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index a38fbd4dbc..5c5ec5ace9 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -453,7 +453,6 @@ FramebufferId TextureCache

::GetFramebufferId(const RenderTargets& key) { return id ? &slot_image_views[id] : nullptr; }); ImageView* const depth_buffer = key.depth_buffer_id ? &slot_image_views[key.depth_buffer_id] : nullptr; - runtime.FlushDeferredClear(); framebuffer_id = slot_framebuffers.insert(runtime, color_buffers, depth_buffer, key); return framebuffer_id; } @@ -2236,7 +2235,6 @@ void TextureCache

::RemoveImageViewReferences(std::span rem template void TextureCache

::RemoveFramebuffers(std::span removed_views) { - runtime.FlushDeferredClear(); auto it = framebuffers.begin(); while (it != framebuffers.end()) { if (it->first.Contains(removed_views)) {