summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon
diff options
context:
space:
mode:
authorTillmann Karras <tilkax@gmail.com>2025-12-25 11:09:39 +0000
committerTillmann Karras <tilkax@gmail.com>2026-03-28 03:05:08 +0000
commit51e488e84a2498808684adb40d50cd85a57d0bd6 (patch)
tree9225043da28e29a052b8a4445d615aa54f9ed8bc /Source/Core/VideoCommon
parent932769c4e21052257c6014267ab32c2abb4f4290 (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.cpp123
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);
+ }
}
}
}