diff options
| author | Tillmann Karras <tilkax@gmail.com> | 2025-12-25 11:09:39 +0000 |
|---|---|---|
| committer | Tillmann Karras <tilkax@gmail.com> | 2026-03-28 03:05:08 +0000 |
| commit | 51e488e84a2498808684adb40d50cd85a57d0bd6 (patch) | |
| tree | 9225043da28e29a052b8a4445d615aa54f9ed8bc /Source/Core/VideoCommon | |
| parent | 932769c4e21052257c6014267ab32c2abb4f4290 (diff) | |
VideoCommon: ignore zero-stride EFB/XFB copies
just clear if requested
Diffstat (limited to 'Source/Core/VideoCommon')
| -rw-r--r-- | Source/Core/VideoCommon/BPStructs.cpp | 123 |
1 files changed, 63 insertions, 60 deletions
diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp index 9518fd0446..180bc86151 100644 --- a/Source/Core/VideoCommon/BPStructs.cpp +++ b/Source/Core/VideoCommon/BPStructs.cpp @@ -298,75 +298,78 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager, XFStateManager& const u32 copy_width = srcRect.GetWidth(); const u32 copy_height = srcRect.GetHeight(); - // Check if we are to copy from the EFB or draw to the XFB - if (PE_copy.copy_to_xfb == 0) + if (destStride != 0) { - // bpmem.zcontrol.pixel_format to PixelFormat::Z24 is when the game wants to copy from ZBuffer - // (Zbuffer uses 24-bit Format) - bool is_depth_copy = bpmem.zcontrol.pixel_format == PixelFormat::Z24; - g_texture_cache->CopyRenderTargetToTexture( - destAddr, PE_copy.tp_realFormat(), copy_width, copy_height, destStride, is_depth_copy, - srcRect, PE_copy.intensity_fmt && PE_copy.auto_conv, PE_copy.half_scale, 1.0f, - s_gammaLUT[PE_copy.gamma], bpmem.triggerEFBCopy.clamp_top, - bpmem.triggerEFBCopy.clamp_bottom, bpmem.copyfilter.GetCoefficients()); - } - else - { - // We should be able to get away with deactivating the current bbox tracking - // here. Not sure if there's a better spot to put this. - // the number of lines copied is determined by the y scale * source efb height - g_bounding_box->Disable(pixel_shader_manager); - - float yScale; - if (PE_copy.scale_invert) - yScale = 256.0f / static_cast<float>(bpmem.dispcopyyscale); + // Check if we are to copy from the EFB or draw to the XFB + if (PE_copy.copy_to_xfb == 0) + { + // bpmem.zcontrol.pixel_format to PixelFormat::Z24 is when the game wants to copy from + // ZBuffer (Zbuffer uses 24-bit Format) + bool is_depth_copy = bpmem.zcontrol.pixel_format == PixelFormat::Z24; + g_texture_cache->CopyRenderTargetToTexture( + destAddr, PE_copy.tp_realFormat(), copy_width, copy_height, destStride, is_depth_copy, + srcRect, PE_copy.intensity_fmt && PE_copy.auto_conv, PE_copy.half_scale, 1.0f, + s_gammaLUT[PE_copy.gamma], bpmem.triggerEFBCopy.clamp_top, + bpmem.triggerEFBCopy.clamp_bottom, bpmem.copyfilter.GetCoefficients()); + } else - yScale = static_cast<float>(bpmem.dispcopyyscale) / 256.0f; + { + // We should be able to get away with deactivating the current bbox tracking + // here. Not sure if there's a better spot to put this. + // the number of lines copied is determined by the y scale * source efb height + g_bounding_box->Disable(pixel_shader_manager); - float num_xfb_lines = 1.0f + bpmem.copyTexSrcWH.y * yScale; + float yScale; + if (PE_copy.scale_invert) + yScale = 256.0f / static_cast<float>(bpmem.dispcopyyscale); + else + yScale = static_cast<float>(bpmem.dispcopyyscale) / 256.0f; - u32 height = static_cast<u32>(num_xfb_lines); + float num_xfb_lines = 1.0f + bpmem.copyTexSrcWH.y * yScale; - DEBUG_LOG_FMT(VIDEO, - "RenderToXFB: destAddr: {:08x} | srcRect [{} {} {} {}] | fbWidth: {} | " - "fbStride: {} | fbHeight: {} | yScale: {}", - destAddr, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom, - bpmem.copyTexSrcWH.x + 1, destStride, height, yScale); + u32 height = static_cast<u32>(num_xfb_lines); - bool is_depth_copy = bpmem.zcontrol.pixel_format == PixelFormat::Z24; - g_texture_cache->CopyRenderTargetToTexture( - destAddr, EFBCopyFormat::XFB, copy_width, height, destStride, is_depth_copy, srcRect, - false, false, yScale, s_gammaLUT[PE_copy.gamma], bpmem.triggerEFBCopy.clamp_top, - bpmem.triggerEFBCopy.clamp_bottom, bpmem.copyfilter.GetCoefficients()); + DEBUG_LOG_FMT(VIDEO, + "RenderToXFB: destAddr: {:08x} | srcRect [{} {} {} {}] | fbWidth: {} | " + "fbStride: {} | fbHeight: {} | yScale: {}", + destAddr, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom, + bpmem.copyTexSrcWH.x + 1, destStride, height, yScale); - auto& system = Core::System::GetInstance(); + bool is_depth_copy = bpmem.zcontrol.pixel_format == PixelFormat::Z24; + g_texture_cache->CopyRenderTargetToTexture( + destAddr, EFBCopyFormat::XFB, copy_width, height, destStride, is_depth_copy, srcRect, + false, false, yScale, s_gammaLUT[PE_copy.gamma], bpmem.triggerEFBCopy.clamp_top, + bpmem.triggerEFBCopy.clamp_bottom, bpmem.copyfilter.GetCoefficients()); - // This is as closest as we have to an "end of the frame" - // It works 99% of the time. - // But sometimes games want to render an XFB larger than the EFB's 640x528 pixel resolution - // (especially when using the 3xMSAA mode, which cuts EFB resolution to 640x264). So they - // render multiple sub-frames and arrange the XFB copies in next to each-other in main memory - // so they form a single completed XFB. - // See https://dolphin-emu.org/blog/2017/11/19/hybridxfb/ for examples and more detail. - system.GetVideoEvents().after_frame_event.Trigger(system); - - // Note: Theoretically, in the future we could track the VI configuration and try to detect - // when an XFB is the last XFB copy of a frame. Not only would we get a clean "end of - // the frame", but we would also be able to use ImmediateXFB even for these games. - // Might also clean up some issues with games doing XFB copies they don't intend to - // display. - - if (g_ActiveConfig.bImmediateXFB) - { - // below div two to convert from bytes to pixels - it expects width, not stride - g_presenter->ImmediateSwap(destAddr, destStride / 2, destStride, height); - } - else - { - if (system.GetFifoPlayer().IsRunningWithFakeVideoInterfaceUpdates()) + auto& system = Core::System::GetInstance(); + + // This is as closest as we have to an "end of the frame" + // It works 99% of the time. + // But sometimes games want to render an XFB larger than the EFB's 640x528 pixel resolution + // (especially when using the 3xMSAA mode, which cuts EFB resolution to 640x264). So they + // render multiple sub-frames and arrange the XFB copies in next to each-other in main + // memory so they form a single completed XFB. See + // https://dolphin-emu.org/blog/2017/11/19/hybridxfb/ for examples and more detail. + system.GetVideoEvents().after_frame_event.Trigger(system); + + // Note: Theoretically, in the future we could track the VI configuration and try to detect + // when an XFB is the last XFB copy of a frame. Not only would we get a clean "end of + // the frame", but we would also be able to use ImmediateXFB even for these games. + // Might also clean up some issues with games doing XFB copies they don't intend to + // display. + + if (g_ActiveConfig.bImmediateXFB) { - auto& vi = system.GetVideoInterface(); - vi.FakeVIUpdate(destAddr, srcRect.GetWidth(), destStride, height); + // below div two to convert from bytes to pixels - it expects width, not stride + g_presenter->ImmediateSwap(destAddr, destStride / 2, destStride, height); + } + else + { + if (system.GetFifoPlayer().IsRunningWithFakeVideoInterfaceUpdates()) + { + auto& vi = system.GetVideoInterface(); + vi.FakeVIUpdate(destAddr, srcRect.GetWidth(), destStride, height); + } } } } |
