mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-25 23:25:41 +00:00
GPU: Clamp UVs to active rect when presenting
This commit is contained in:
parent
4588f9ee9f
commit
9e8ff3969e
|
@ -1571,11 +1571,14 @@ bool GPU::CompileDisplayPipeline()
|
||||||
fs = shadergen.GenerateDisplaySharpBilinearFragmentShader();
|
fs = shadergen.GenerateDisplaySharpBilinearFragmentShader();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DisplayScalingMode::Nearest:
|
|
||||||
case DisplayScalingMode::BilinearSmooth:
|
case DisplayScalingMode::BilinearSmooth:
|
||||||
|
fs = shadergen.GenerateDisplayFragmentShader(true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DisplayScalingMode::Nearest:
|
||||||
case DisplayScalingMode::NearestInteger:
|
case DisplayScalingMode::NearestInteger:
|
||||||
default:
|
default:
|
||||||
fs = shadergen.GenerateDisplayFragmentShader();
|
fs = shadergen.GenerateDisplayFragmentShader(false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1659,6 +1662,7 @@ bool GPU::RenderDisplay(GPUFramebuffer* target, const Common::Rectangle<s32>& dr
|
||||||
{
|
{
|
||||||
float src_rect[4];
|
float src_rect[4];
|
||||||
float src_size[4];
|
float src_size[4];
|
||||||
|
float clamp_rect[4];
|
||||||
float params[4];
|
float params[4];
|
||||||
} uniforms;
|
} uniforms;
|
||||||
std::memset(uniforms.params, 0, sizeof(uniforms.params));
|
std::memset(uniforms.params, 0, sizeof(uniforms.params));
|
||||||
|
@ -1718,14 +1722,20 @@ bool GPU::RenderDisplay(GPUFramebuffer* target, const Common::Rectangle<s32>& dr
|
||||||
g_gpu_device->SetTextureSampler(
|
g_gpu_device->SetTextureSampler(
|
||||||
0, m_display_texture, texture_filter_linear ? g_gpu_device->GetLinearSampler() : g_gpu_device->GetNearestSampler());
|
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;
|
// For bilinear, clamp to 0.5/SIZE-0.5 to avoid bleeding from the adjacent texels in VRAM. This is because
|
||||||
const float size_adjust = bilinear_adjust ? 1.0f : 0.0f;
|
// 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<float>(m_display_texture->GetWidth());
|
const float rcp_width = 1.0f / static_cast<float>(m_display_texture->GetWidth());
|
||||||
const float rcp_height = 1.0f / static_cast<float>(m_display_texture->GetHeight());
|
const float rcp_height = 1.0f / static_cast<float>(m_display_texture->GetHeight());
|
||||||
uniforms.src_rect[0] = (static_cast<float>(m_display_texture_view_x) + position_adjust) * rcp_width;
|
uniforms.src_rect[0] = static_cast<float>(m_display_texture_view_x) * rcp_width;
|
||||||
uniforms.src_rect[1] = (static_cast<float>(m_display_texture_view_y) + position_adjust) * rcp_height;
|
uniforms.src_rect[1] = static_cast<float>(m_display_texture_view_y) * rcp_height;
|
||||||
uniforms.src_rect[2] = (static_cast<float>(m_display_texture_view_width) - size_adjust) * rcp_width;
|
uniforms.src_rect[2] = static_cast<float>(m_display_texture_view_width) * rcp_width;
|
||||||
uniforms.src_rect[3] = (static_cast<float>(m_display_texture_view_height) - size_adjust) * rcp_height;
|
uniforms.src_rect[3] = static_cast<float>(m_display_texture_view_height) * rcp_height;
|
||||||
|
uniforms.clamp_rect[0] = (static_cast<float>(m_display_texture_view_x) + 0.5f) * rcp_width;
|
||||||
|
uniforms.clamp_rect[1] = (static_cast<float>(m_display_texture_view_y) + 0.5f) * rcp_height;
|
||||||
|
uniforms.clamp_rect[2] =
|
||||||
|
(static_cast<float>(m_display_texture_view_x + m_display_texture_view_width) - 0.5f) * rcp_width;
|
||||||
|
uniforms.clamp_rect[3] =
|
||||||
|
(static_cast<float>(m_display_texture_view_y + m_display_texture_view_height) - 0.5f) * rcp_height;
|
||||||
uniforms.src_size[0] = static_cast<float>(m_display_texture->GetWidth());
|
uniforms.src_size[0] = static_cast<float>(m_display_texture->GetWidth());
|
||||||
uniforms.src_size[1] = static_cast<float>(m_display_texture->GetHeight());
|
uniforms.src_size[1] = static_cast<float>(m_display_texture->GetHeight());
|
||||||
uniforms.src_size[2] = rcp_width;
|
uniforms.src_size[2] = rcp_width;
|
||||||
|
|
|
@ -12,7 +12,12 @@ GPUShaderGen::~GPUShaderGen() = default;
|
||||||
|
|
||||||
void GPUShaderGen::WriteDisplayUniformBuffer(std::stringstream& ss)
|
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()
|
std::string GPUShaderGen::GenerateDisplayVertexShader()
|
||||||
|
@ -35,17 +40,17 @@ std::string GPUShaderGen::GenerateDisplayVertexShader()
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GPUShaderGen::GenerateDisplayFragmentShader()
|
std::string GPUShaderGen::GenerateDisplayFragmentShader(bool clamp_uv)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
WriteHeader(ss);
|
WriteHeader(ss);
|
||||||
WriteDisplayUniformBuffer(ss);
|
WriteDisplayUniformBuffer(ss);
|
||||||
DeclareTexture(ss, "samp0", 0);
|
DeclareTexture(ss, "samp0", 0);
|
||||||
DeclareFragmentEntryPoint(ss, 0, 1, {}, false, 1);
|
DeclareFragmentEntryPoint(ss, 0, 1, {}, false, 1);
|
||||||
ss << R"(
|
if (clamp_uv)
|
||||||
{
|
ss << "{\n o_col0 = float4(SAMPLE_TEXTURE(samp0, ClampUV(v_tex0)).rgb, 1.0f);\n }";
|
||||||
o_col0 = float4(SAMPLE_TEXTURE(samp0, v_tex0).rgb, 1.0f);
|
else
|
||||||
})";
|
ss << "{\n o_col0 = float4(SAMPLE_TEXTURE(samp0, v_tex0).rgb, 1.0f);\n }";
|
||||||
|
|
||||||
return ss.str();
|
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 f = (center_dist - clamp(center_dist, -region_range, region_range)) * scale + 0.5;
|
||||||
float2 mod_texel = texel_floored + f;
|
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();
|
return ss.str();
|
||||||
|
|
|
@ -12,7 +12,7 @@ public:
|
||||||
~GPUShaderGen();
|
~GPUShaderGen();
|
||||||
|
|
||||||
std::string GenerateDisplayVertexShader();
|
std::string GenerateDisplayVertexShader();
|
||||||
std::string GenerateDisplayFragmentShader();
|
std::string GenerateDisplayFragmentShader(bool clamp_uv);
|
||||||
std::string GenerateDisplaySharpBilinearFragmentShader();
|
std::string GenerateDisplaySharpBilinearFragmentShader();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in a new issue