From 0b0d3a4ac34c40010db0b8b4ba6e8be53c099d3f Mon Sep 17 00:00:00 2001 From: GPUCode <47210458+GPUCode@users.noreply.github.com> Date: Mon, 11 Sep 2023 00:30:06 +0300 Subject: [PATCH] gpu: Correct display transfer output with vertical flip+crop lines (#6952) --- src/core/hw/gpu.cpp | 10 +++++++++- src/video_core/rasterizer_cache/rasterizer_cache.h | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 6525605da6..156fb4b14b 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -128,7 +128,7 @@ static void MemoryFill(const Regs::MemoryFillConfig& config) { static void DisplayTransfer(const Regs::DisplayTransferConfig& config) { const PAddr src_addr = config.GetPhysicalInputAddress(); - const PAddr dst_addr = config.GetPhysicalOutputAddress(); + PAddr dst_addr = config.GetPhysicalOutputAddress(); // TODO: do hwtest with these cases if (!g_memory->IsValidPhysicalAddress(src_addr)) { @@ -164,6 +164,14 @@ static void DisplayTransfer(const Regs::DisplayTransferConfig& config) { if (VideoCore::g_renderer->Rasterizer()->AccelerateDisplayTransfer(config)) return; + // Using flip_vertically alongside crop_input_lines produces skewed output on hardware. + // We have to emulate this because some games rely on this behaviour to render correctly. + if (config.flip_vertically && config.crop_input_lines && + config.input_width > config.output_width) { + dst_addr += (config.input_width - config.output_width) * (config.output_height - 1) * + GPU::Regs::BytesPerPixel(config.output_format); + } + u8* src_pointer = g_memory->GetPhysicalPointer(src_addr); u8* dst_pointer = g_memory->GetPhysicalPointer(dst_addr); diff --git a/src/video_core/rasterizer_cache/rasterizer_cache.h b/src/video_core/rasterizer_cache/rasterizer_cache.h index 37abcae144..cebf543776 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache.h @@ -272,6 +272,14 @@ bool RasterizerCache::AccelerateDisplayTransfer(const GPU::Regs::DisplayTrans dst_params.pixel_format = PixelFormatFromGPUPixelFormat(config.output_format); dst_params.UpdateParams(); + // Using flip_vertically alongside crop_input_lines produces skewed output on hardware. + // We have to emulate this because some games rely on this behaviour to render correctly. + if (config.flip_vertically && config.crop_input_lines && + config.input_width > config.output_width) { + dst_params.addr += (config.input_width - config.output_width) * (config.output_height - 1) * + GPU::Regs::BytesPerPixel(config.output_format); + } + auto [src_surface_id, src_rect] = GetSurfaceSubRect(src_params, ScaleMatch::Ignore, true); if (!src_surface_id) { return false;