From 57a46c69f1ae65902c3937bbfedc6ffa9f8ecf47 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 27 Sep 2019 16:10:45 -0400 Subject: Fermi2D: limit blit area to only available area Normaly OpenGL does not care if the areas exceed the texture regions but other backends such as Vulkan do care about the limits of this areas. This PR crops the areas of the blit in order that they don't surpass the limits of the textures. This should help Vulkan and faulty OpenGL drivers --- src/video_core/engines/fermi_2d.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index 7ff44f06d..c2d4dcc09 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp @@ -47,10 +47,20 @@ void Fermi2D::HandleSurfaceCopy() { src_blit_x2 = static_cast((regs.blit_src_x >> 32) + regs.blit_dst_width); src_blit_y2 = static_cast((regs.blit_src_y >> 32) + regs.blit_dst_height); } - const Common::Rectangle src_rect{src_blit_x1, src_blit_y1, src_blit_x2, src_blit_y2}; - const Common::Rectangle dst_rect{regs.blit_dst_x, regs.blit_dst_y, - regs.blit_dst_x + regs.blit_dst_width, - regs.blit_dst_y + regs.blit_dst_height}; + const u32 dst_blit_x2 = regs.blit_dst_x + regs.blit_dst_width; + const u32 dst_blit_y2 = regs.blit_dst_x + regs.blit_dst_height; + const u32 excess_src_x2 = std::max(0, dst_blit_x2 - regs.dst.width); + const u32 excess_src_y2 = std::max(0, dst_blit_y2 - regs.dst.height); + const u32 excess_dst_x2 = std::max(0, src_blit_x2 - regs.src.width); + const u32 excess_dst_y2 = std::max(0, src_blit_y2 - regs.src.height); + + const Common::Rectangle src_rect{ + src_blit_x1, src_blit_y1, std::min(regs.src.width, src_blit_x2) - excess_src_x2, + std::min(regs.src.height, src_blit_y2) - excess_src_y2}; + const Common::Rectangle dst_rect{ + regs.blit_dst_x, regs.blit_dst_y, + std::min(regs.dst.width, dst_blit_x2) - excess_dst_x2, + std::min(regs.dst.height, dst_blit_y2) - excess_dst_y2}; Config copy_config; copy_config.operation = regs.operation; copy_config.filter = regs.blit_control.filter; -- cgit v1.2.3 From c0eb1aecfd6579409a23e56dc5cea8f19aa7e064 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 17 Oct 2019 18:21:01 -0400 Subject: Fermi2D: Use a different formula for delimiting blit areas. --- src/video_core/engines/fermi_2d.cpp | 42 ++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index c2d4dcc09..85d308e26 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp @@ -28,6 +28,13 @@ void Fermi2D::CallMethod(const GPU::MethodCall& method_call) { } } +std::pair DelimitLine(u32 src_1, u32 src_2, u32 dst_1, u32 dst_2, u32 src_line) { + const u32 line_a = src_2 - src_1; + const u32 line_b = dst_2 - dst_1; + const u32 excess = std::max(0, line_a - src_line + src_1); + return {line_b - (excess * line_b) / line_a, excess}; +} + void Fermi2D::HandleSurfaceCopy() { LOG_DEBUG(HW_GPU, "Requested a surface copy with operation {}", static_cast(regs.operation)); @@ -47,20 +54,27 @@ void Fermi2D::HandleSurfaceCopy() { src_blit_x2 = static_cast((regs.blit_src_x >> 32) + regs.blit_dst_width); src_blit_y2 = static_cast((regs.blit_src_y >> 32) + regs.blit_dst_height); } - const u32 dst_blit_x2 = regs.blit_dst_x + regs.blit_dst_width; - const u32 dst_blit_y2 = regs.blit_dst_x + regs.blit_dst_height; - const u32 excess_src_x2 = std::max(0, dst_blit_x2 - regs.dst.width); - const u32 excess_src_y2 = std::max(0, dst_blit_y2 - regs.dst.height); - const u32 excess_dst_x2 = std::max(0, src_blit_x2 - regs.src.width); - const u32 excess_dst_y2 = std::max(0, src_blit_y2 - regs.src.height); - - const Common::Rectangle src_rect{ - src_blit_x1, src_blit_y1, std::min(regs.src.width, src_blit_x2) - excess_src_x2, - std::min(regs.src.height, src_blit_y2) - excess_src_y2}; - const Common::Rectangle dst_rect{ - regs.blit_dst_x, regs.blit_dst_y, - std::min(regs.dst.width, dst_blit_x2) - excess_dst_x2, - std::min(regs.dst.height, dst_blit_y2) - excess_dst_y2}; + u32 dst_blit_x2 = regs.blit_dst_x + regs.blit_dst_width; + u32 dst_blit_y2 = regs.blit_dst_y + regs.blit_dst_height; + const auto [new_dst_w, src_excess_x] = + DelimitLine(src_blit_x1, src_blit_x2, regs.blit_dst_x, dst_blit_x2, regs.src.width); + const auto [new_dst_h, src_excess_y] = + DelimitLine(src_blit_y1, src_blit_y2, regs.blit_dst_y, dst_blit_y2, regs.src.height); + dst_blit_x2 = new_dst_w + regs.blit_dst_x; + src_blit_x2 = src_blit_x2 - src_excess_x; + dst_blit_y2 = new_dst_h + regs.blit_dst_y; + src_blit_y2 = src_blit_y2 - src_excess_y; + const auto [new_src_w, dst_excess_x] = + DelimitLine(regs.blit_dst_x, dst_blit_x2, src_blit_x1, src_blit_x2, regs.dst.width); + const auto [new_src_h, dst_excess_y] = + DelimitLine(regs.blit_dst_y, dst_blit_y2, src_blit_y1, src_blit_y2, regs.dst.height); + src_blit_x2 = new_src_w + src_blit_x1; + dst_blit_x2 = dst_blit_x2 - dst_excess_x; + src_blit_y2 = new_src_h + src_blit_y1; + dst_blit_y2 = dst_blit_y2 - dst_excess_y; + const Common::Rectangle src_rect{src_blit_x1, src_blit_y1, src_blit_x2, src_blit_y2}; + const Common::Rectangle dst_rect{regs.blit_dst_x, regs.blit_dst_y, dst_blit_x2, + dst_blit_y2}; Config copy_config; copy_config.operation = regs.operation; copy_config.filter = regs.blit_control.filter; -- cgit v1.2.3