From 9e8ff3969e46fc72dbf2670e26fb29b1eb1cd5dc Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 2 Sep 2023 19:22:29 +1000 Subject: [PATCH] GPU: Clamp UVs to active rect when presenting --- src/core/gpu.cpp | 26 ++++++++++++++++++-------- src/core/gpu_shadergen.cpp | 19 ++++++++++++------- src/core/gpu_shadergen.h | 2 +- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 8c538c4d6..30d14efc8 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -1571,11 +1571,14 @@ bool GPU::CompileDisplayPipeline() fs = shadergen.GenerateDisplaySharpBilinearFragmentShader(); break; - case DisplayScalingMode::Nearest: case DisplayScalingMode::BilinearSmooth: + fs = shadergen.GenerateDisplayFragmentShader(true); + break; + + case DisplayScalingMode::Nearest: case DisplayScalingMode::NearestInteger: default: - fs = shadergen.GenerateDisplayFragmentShader(); + fs = shadergen.GenerateDisplayFragmentShader(false); break; } @@ -1659,6 +1662,7 @@ bool GPU::RenderDisplay(GPUFramebuffer* target, const Common::Rectangle& dr { float src_rect[4]; float src_size[4]; + float clamp_rect[4]; float params[4]; } uniforms; std::memset(uniforms.params, 0, sizeof(uniforms.params)); @@ -1718,14 +1722,20 @@ bool GPU::RenderDisplay(GPUFramebuffer* target, const Common::Rectangle& dr g_gpu_device->SetTextureSampler( 0, m_display_texture, texture_filter_linear ? g_gpu_device->GetLinearSampler() : g_gpu_device->GetNearestSampler()); - const float position_adjust = bilinear_adjust ? 0.5f : 0.0f; - const float size_adjust = bilinear_adjust ? 1.0f : 0.0f; + // For bilinear, clamp to 0.5/SIZE-0.5 to avoid bleeding from the adjacent texels in VRAM. This is because + // 1.0 in UV space is not the bottom-right texel, but a mix of the bottom-right and wrapped/next texel. const float rcp_width = 1.0f / static_cast(m_display_texture->GetWidth()); const float rcp_height = 1.0f / static_cast(m_display_texture->GetHeight()); - uniforms.src_rect[0] = (static_cast(m_display_texture_view_x) + position_adjust) * rcp_width; - uniforms.src_rect[1] = (static_cast(m_display_texture_view_y) + position_adjust) * rcp_height; - uniforms.src_rect[2] = (static_cast(m_display_texture_view_width) - size_adjust) * rcp_width; - uniforms.src_rect[3] = (static_cast(m_display_texture_view_height) - size_adjust) * rcp_height; + uniforms.src_rect[0] = static_cast(m_display_texture_view_x) * rcp_width; + uniforms.src_rect[1] = static_cast(m_display_texture_view_y) * rcp_height; + uniforms.src_rect[2] = static_cast(m_display_texture_view_width) * rcp_width; + uniforms.src_rect[3] = static_cast(m_display_texture_view_height) * rcp_height; + uniforms.clamp_rect[0] = (static_cast(m_display_texture_view_x) + 0.5f) * rcp_width; + uniforms.clamp_rect[1] = (static_cast(m_display_texture_view_y) + 0.5f) * rcp_height; + uniforms.clamp_rect[2] = + (static_cast(m_display_texture_view_x + m_display_texture_view_width) - 0.5f) * rcp_width; + uniforms.clamp_rect[3] = + (static_cast(m_display_texture_view_y + m_display_texture_view_height) - 0.5f) * rcp_height; uniforms.src_size[0] = static_cast(m_display_texture->GetWidth()); uniforms.src_size[1] = static_cast(m_display_texture->GetHeight()); uniforms.src_size[2] = rcp_width; diff --git a/src/core/gpu_shadergen.cpp b/src/core/gpu_shadergen.cpp index 94d3d8269..138b26a38 100644 --- a/src/core/gpu_shadergen.cpp +++ b/src/core/gpu_shadergen.cpp @@ -12,7 +12,12 @@ GPUShaderGen::~GPUShaderGen() = default; void GPUShaderGen::WriteDisplayUniformBuffer(std::stringstream& ss) { - DeclareUniformBuffer(ss, {"float4 u_src_rect", "float4 u_src_size", "float4 u_params"}, true); + DeclareUniformBuffer(ss, {"float4 u_src_rect", "float4 u_src_size", "float4 u_clamp_rect", "float4 u_params"}, true); + + ss << R"( +float2 ClampUV(float2 uv) { + return clamp(uv, u_clamp_rect.xy, u_clamp_rect.zw); +})"; } std::string GPUShaderGen::GenerateDisplayVertexShader() @@ -35,17 +40,17 @@ std::string GPUShaderGen::GenerateDisplayVertexShader() return ss.str(); } -std::string GPUShaderGen::GenerateDisplayFragmentShader() +std::string GPUShaderGen::GenerateDisplayFragmentShader(bool clamp_uv) { std::stringstream ss; WriteHeader(ss); WriteDisplayUniformBuffer(ss); DeclareTexture(ss, "samp0", 0); DeclareFragmentEntryPoint(ss, 0, 1, {}, false, 1); - ss << R"( -{ - o_col0 = float4(SAMPLE_TEXTURE(samp0, v_tex0).rgb, 1.0f); -})"; + if (clamp_uv) + ss << "{\n o_col0 = float4(SAMPLE_TEXTURE(samp0, ClampUV(v_tex0)).rgb, 1.0f);\n }"; + else + ss << "{\n o_col0 = float4(SAMPLE_TEXTURE(samp0, v_tex0).rgb, 1.0f);\n }"; return ss.str(); } @@ -72,7 +77,7 @@ std::string GPUShaderGen::GenerateDisplaySharpBilinearFragmentShader() float2 f = (center_dist - clamp(center_dist, -region_range, region_range)) * scale + 0.5; float2 mod_texel = texel_floored + f; - o_col0 = float4(SAMPLE_TEXTURE(samp0, mod_texel * u_src_size.zw).rgb, 1.0f); + o_col0 = float4(SAMPLE_TEXTURE(samp0, ClampUV(mod_texel * u_src_size.zw)).rgb, 1.0f); })"; return ss.str(); diff --git a/src/core/gpu_shadergen.h b/src/core/gpu_shadergen.h index 55b73231b..2ccd13b7a 100644 --- a/src/core/gpu_shadergen.h +++ b/src/core/gpu_shadergen.h @@ -12,7 +12,7 @@ public: ~GPUShaderGen(); std::string GenerateDisplayVertexShader(); - std::string GenerateDisplayFragmentShader(); + std::string GenerateDisplayFragmentShader(bool clamp_uv); std::string GenerateDisplaySharpBilinearFragmentShader(); private: