mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 23:55:40 +00:00
GPU: Add chroma smoothing for 24-bit display enhancement
This commit is contained in:
parent
d102b2facd
commit
ae1e4b1b8f
|
@ -54,6 +54,7 @@ bool GPU_HW::Initialize(HostDisplay* host_display)
|
||||||
m_scaled_dithering = g_settings.gpu_scaled_dithering;
|
m_scaled_dithering = g_settings.gpu_scaled_dithering;
|
||||||
m_texture_filtering = g_settings.gpu_texture_filter;
|
m_texture_filtering = g_settings.gpu_texture_filter;
|
||||||
m_using_uv_limits = ShouldUseUVLimits();
|
m_using_uv_limits = ShouldUseUVLimits();
|
||||||
|
m_chroma_smoothing = g_settings.gpu_24bit_chroma_smoothing;
|
||||||
PrintSettingsToLog();
|
PrintSettingsToLog();
|
||||||
|
|
||||||
if (m_multisamples != g_settings.gpu_multisamples)
|
if (m_multisamples != g_settings.gpu_multisamples)
|
||||||
|
@ -111,10 +112,11 @@ void GPU_HW::UpdateHWSettings(bool* framebuffer_changed, bool* shaders_changed)
|
||||||
const bool use_uv_limits = ShouldUseUVLimits();
|
const bool use_uv_limits = ShouldUseUVLimits();
|
||||||
|
|
||||||
*framebuffer_changed = (m_resolution_scale != resolution_scale || m_multisamples != multisamples);
|
*framebuffer_changed = (m_resolution_scale != resolution_scale || m_multisamples != multisamples);
|
||||||
*shaders_changed = (m_resolution_scale != resolution_scale || m_multisamples != multisamples ||
|
*shaders_changed =
|
||||||
|
(m_resolution_scale != resolution_scale || m_multisamples != multisamples ||
|
||||||
m_true_color != g_settings.gpu_true_color || m_per_sample_shading != per_sample_shading ||
|
m_true_color != g_settings.gpu_true_color || m_per_sample_shading != per_sample_shading ||
|
||||||
m_scaled_dithering != g_settings.gpu_scaled_dithering ||
|
m_scaled_dithering != g_settings.gpu_scaled_dithering || m_texture_filtering != g_settings.gpu_texture_filter ||
|
||||||
m_texture_filtering != g_settings.gpu_texture_filter || m_using_uv_limits != use_uv_limits);
|
m_using_uv_limits != use_uv_limits || m_chroma_smoothing != g_settings.gpu_24bit_chroma_smoothing);
|
||||||
|
|
||||||
if (m_resolution_scale != resolution_scale)
|
if (m_resolution_scale != resolution_scale)
|
||||||
{
|
{
|
||||||
|
@ -147,6 +149,7 @@ void GPU_HW::UpdateHWSettings(bool* framebuffer_changed, bool* shaders_changed)
|
||||||
m_scaled_dithering = g_settings.gpu_scaled_dithering;
|
m_scaled_dithering = g_settings.gpu_scaled_dithering;
|
||||||
m_texture_filtering = g_settings.gpu_texture_filter;
|
m_texture_filtering = g_settings.gpu_texture_filter;
|
||||||
m_using_uv_limits = use_uv_limits;
|
m_using_uv_limits = use_uv_limits;
|
||||||
|
m_chroma_smoothing = g_settings.gpu_24bit_chroma_smoothing;
|
||||||
PrintSettingsToLog();
|
PrintSettingsToLog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -276,6 +276,7 @@ protected:
|
||||||
bool m_true_color = true;
|
bool m_true_color = true;
|
||||||
bool m_scaled_dithering = false;
|
bool m_scaled_dithering = false;
|
||||||
GPUTextureFilter m_texture_filtering = GPUTextureFilter::Nearest;
|
GPUTextureFilter m_texture_filtering = GPUTextureFilter::Nearest;
|
||||||
|
bool m_chroma_smoothing = false;
|
||||||
bool m_supports_per_sample_shading = false;
|
bool m_supports_per_sample_shading = false;
|
||||||
bool m_supports_dual_source_blend = false;
|
bool m_supports_dual_source_blend = false;
|
||||||
bool m_using_uv_limits = false;
|
bool m_using_uv_limits = false;
|
||||||
|
|
|
@ -525,8 +525,9 @@ bool GPU_HW_D3D11::CompileShaders()
|
||||||
{
|
{
|
||||||
for (u8 interlacing = 0; interlacing < 3; interlacing++)
|
for (u8 interlacing = 0; interlacing < 3; interlacing++)
|
||||||
{
|
{
|
||||||
const std::string ps = shadergen.GenerateDisplayFragmentShader(ConvertToBoolUnchecked(depth_24bit),
|
const std::string ps = shadergen.GenerateDisplayFragmentShader(
|
||||||
static_cast<InterlacedRenderMode>(interlacing));
|
ConvertToBoolUnchecked(depth_24bit), static_cast<InterlacedRenderMode>(interlacing),
|
||||||
|
ConvertToBoolUnchecked(depth_24bit) && m_chroma_smoothing);
|
||||||
m_display_pixel_shaders[depth_24bit][interlacing] = shader_cache.GetPixelShader(m_device.Get(), ps);
|
m_display_pixel_shaders[depth_24bit][interlacing] = shader_cache.GetPixelShader(m_device.Get(), ps);
|
||||||
if (!m_display_pixel_shaders[depth_24bit][interlacing])
|
if (!m_display_pixel_shaders[depth_24bit][interlacing])
|
||||||
return false;
|
return false;
|
||||||
|
@ -669,14 +670,15 @@ void GPU_HW_D3D11::UpdateDisplay()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
const u32 resolution_scale = m_GPUSTAT.display_area_color_depth_24 ? 1 : m_resolution_scale;
|
||||||
const u32 vram_offset_x = m_crtc_state.display_vram_left;
|
const u32 vram_offset_x = m_crtc_state.display_vram_left;
|
||||||
const u32 vram_offset_y = m_crtc_state.display_vram_top;
|
const u32 vram_offset_y = m_crtc_state.display_vram_top;
|
||||||
const u32 scaled_vram_offset_x = vram_offset_x * m_resolution_scale;
|
const u32 scaled_vram_offset_x = vram_offset_x * resolution_scale;
|
||||||
const u32 scaled_vram_offset_y = vram_offset_y * m_resolution_scale;
|
const u32 scaled_vram_offset_y = vram_offset_y * resolution_scale;
|
||||||
const u32 display_width = m_crtc_state.display_vram_width;
|
const u32 display_width = m_crtc_state.display_vram_width;
|
||||||
const u32 display_height = m_crtc_state.display_vram_height;
|
const u32 display_height = m_crtc_state.display_vram_height;
|
||||||
const u32 scaled_display_width = display_width * m_resolution_scale;
|
const u32 scaled_display_width = display_width * resolution_scale;
|
||||||
const u32 scaled_display_height = display_height * m_resolution_scale;
|
const u32 scaled_display_height = display_height * resolution_scale;
|
||||||
const InterlacedRenderMode interlaced = GetInterlacedRenderMode();
|
const InterlacedRenderMode interlaced = GetInterlacedRenderMode();
|
||||||
|
|
||||||
if (IsDisplayDisabled())
|
if (IsDisplayDisabled())
|
||||||
|
@ -699,8 +701,8 @@ void GPU_HW_D3D11::UpdateDisplay()
|
||||||
m_context->PSSetShaderResources(0, 1, m_vram_texture.GetD3DSRVArray());
|
m_context->PSSetShaderResources(0, 1, m_vram_texture.GetD3DSRVArray());
|
||||||
|
|
||||||
const u32 reinterpret_field_offset = (interlaced != InterlacedRenderMode::None) ? GetInterlacedDisplayField() : 0;
|
const u32 reinterpret_field_offset = (interlaced != InterlacedRenderMode::None) ? GetInterlacedDisplayField() : 0;
|
||||||
const u32 reinterpret_start_x = m_crtc_state.regs.X * m_resolution_scale;
|
const u32 reinterpret_start_x = m_crtc_state.regs.X * resolution_scale;
|
||||||
const u32 reinterpret_crop_left = (m_crtc_state.display_vram_left - m_crtc_state.regs.X) * m_resolution_scale;
|
const u32 reinterpret_crop_left = (m_crtc_state.display_vram_left - m_crtc_state.regs.X) * resolution_scale;
|
||||||
const u32 uniforms[4] = {reinterpret_start_x, scaled_vram_offset_y + reinterpret_field_offset,
|
const u32 uniforms[4] = {reinterpret_start_x, scaled_vram_offset_y + reinterpret_field_offset,
|
||||||
reinterpret_crop_left, reinterpret_field_offset};
|
reinterpret_crop_left, reinterpret_field_offset};
|
||||||
ID3D11PixelShader* display_pixel_shader =
|
ID3D11PixelShader* display_pixel_shader =
|
||||||
|
|
|
@ -455,8 +455,8 @@ bool GPU_HW_OpenGL::CompilePrograms()
|
||||||
for (u8 interlaced = 0; interlaced < 3; interlaced++)
|
for (u8 interlaced = 0; interlaced < 3; interlaced++)
|
||||||
{
|
{
|
||||||
const std::string vs = shadergen.GenerateScreenQuadVertexShader();
|
const std::string vs = shadergen.GenerateScreenQuadVertexShader();
|
||||||
const std::string fs = shadergen.GenerateDisplayFragmentShader(ConvertToBoolUnchecked(depth_24bit),
|
const std::string fs = shadergen.GenerateDisplayFragmentShader(
|
||||||
static_cast<InterlacedRenderMode>(interlaced));
|
ConvertToBoolUnchecked(depth_24bit), static_cast<InterlacedRenderMode>(interlaced), m_chroma_smoothing);
|
||||||
|
|
||||||
std::optional<GL::Program> prog =
|
std::optional<GL::Program> prog =
|
||||||
shader_cache.GetProgram(vs, {}, fs, [this, use_binding_layout](GL::Program& prog) {
|
shader_cache.GetProgram(vs, {}, fs, [this, use_binding_layout](GL::Program& prog) {
|
||||||
|
@ -673,14 +673,15 @@ void GPU_HW_OpenGL::UpdateDisplay()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
const u32 resolution_scale = m_GPUSTAT.display_area_color_depth_24 ? 1 : m_resolution_scale;
|
||||||
const u32 vram_offset_x = m_crtc_state.display_vram_left;
|
const u32 vram_offset_x = m_crtc_state.display_vram_left;
|
||||||
const u32 vram_offset_y = m_crtc_state.display_vram_top;
|
const u32 vram_offset_y = m_crtc_state.display_vram_top;
|
||||||
const u32 scaled_vram_offset_x = vram_offset_x * m_resolution_scale;
|
const u32 scaled_vram_offset_x = vram_offset_x * resolution_scale;
|
||||||
const u32 scaled_vram_offset_y = vram_offset_y * m_resolution_scale;
|
const u32 scaled_vram_offset_y = vram_offset_y * resolution_scale;
|
||||||
const u32 display_width = m_crtc_state.display_vram_width;
|
const u32 display_width = m_crtc_state.display_vram_width;
|
||||||
const u32 display_height = m_crtc_state.display_vram_height;
|
const u32 display_height = m_crtc_state.display_vram_height;
|
||||||
const u32 scaled_display_width = display_width * m_resolution_scale;
|
const u32 scaled_display_width = display_width * resolution_scale;
|
||||||
const u32 scaled_display_height = display_height * m_resolution_scale;
|
const u32 scaled_display_height = display_height * resolution_scale;
|
||||||
const InterlacedRenderMode interlaced = GetInterlacedRenderMode();
|
const InterlacedRenderMode interlaced = GetInterlacedRenderMode();
|
||||||
|
|
||||||
if (IsDisplayDisabled())
|
if (IsDisplayDisabled())
|
||||||
|
@ -710,8 +711,8 @@ void GPU_HW_OpenGL::UpdateDisplay()
|
||||||
const u32 reinterpret_field_offset = (interlaced != InterlacedRenderMode::None) ? GetInterlacedDisplayField() : 0;
|
const u32 reinterpret_field_offset = (interlaced != InterlacedRenderMode::None) ? GetInterlacedDisplayField() : 0;
|
||||||
const u32 scaled_flipped_vram_offset_y = m_vram_texture.GetHeight() - scaled_vram_offset_y -
|
const u32 scaled_flipped_vram_offset_y = m_vram_texture.GetHeight() - scaled_vram_offset_y -
|
||||||
reinterpret_field_offset - (scaled_display_height >> height_div2);
|
reinterpret_field_offset - (scaled_display_height >> height_div2);
|
||||||
const u32 reinterpret_start_x = m_crtc_state.regs.X * m_resolution_scale;
|
const u32 reinterpret_start_x = m_crtc_state.regs.X * resolution_scale;
|
||||||
const u32 reinterpret_crop_left = (m_crtc_state.display_vram_left - m_crtc_state.regs.X) * m_resolution_scale;
|
const u32 reinterpret_crop_left = (m_crtc_state.display_vram_left - m_crtc_state.regs.X) * resolution_scale;
|
||||||
const u32 uniforms[4] = {reinterpret_start_x, scaled_flipped_vram_offset_y, reinterpret_crop_left,
|
const u32 uniforms[4] = {reinterpret_start_x, scaled_flipped_vram_offset_y, reinterpret_crop_left,
|
||||||
reinterpret_field_offset};
|
reinterpret_field_offset};
|
||||||
UploadUniformBuffer(uniforms, sizeof(uniforms));
|
UploadUniformBuffer(uniforms, sizeof(uniforms));
|
||||||
|
|
|
@ -990,19 +990,35 @@ std::string GPU_HW_ShaderGen::GenerateInterlacedFillFragmentShader()
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GPU_HW_ShaderGen::GenerateDisplayFragmentShader(bool depth_24bit,
|
std::string GPU_HW_ShaderGen::GenerateDisplayFragmentShader(bool depth_24bit,
|
||||||
GPU_HW::InterlacedRenderMode interlace_mode)
|
GPU_HW::InterlacedRenderMode interlace_mode,
|
||||||
|
bool smooth_chroma)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
WriteHeader(ss);
|
WriteHeader(ss);
|
||||||
DefineMacro(ss, "DEPTH_24BIT", depth_24bit);
|
DefineMacro(ss, "DEPTH_24BIT", depth_24bit);
|
||||||
DefineMacro(ss, "INTERLACED", interlace_mode != GPU_HW::InterlacedRenderMode::None);
|
DefineMacro(ss, "INTERLACED", interlace_mode != GPU_HW::InterlacedRenderMode::None);
|
||||||
DefineMacro(ss, "INTERLEAVED", interlace_mode == GPU_HW::InterlacedRenderMode::InterleavedFields);
|
DefineMacro(ss, "INTERLEAVED", interlace_mode == GPU_HW::InterlacedRenderMode::InterleavedFields);
|
||||||
|
DefineMacro(ss, "SMOOTH_CHROMA", smooth_chroma);
|
||||||
|
|
||||||
WriteCommonFunctions(ss);
|
WriteCommonFunctions(ss);
|
||||||
DeclareUniformBuffer(ss, {"uint2 u_vram_offset", "uint u_crop_left", "uint u_field_offset"}, true);
|
DeclareUniformBuffer(ss, {"uint2 u_vram_offset", "uint u_crop_left", "uint u_field_offset"}, true);
|
||||||
DeclareTexture(ss, "samp0", 0, UsingMSAA());
|
DeclareTexture(ss, "samp0", 0, UsingMSAA());
|
||||||
|
|
||||||
ss << R"(
|
ss << R"(
|
||||||
|
float3 RGBToYUV(float3 rgb)
|
||||||
|
{
|
||||||
|
return float3(dot(rgb.rgb, float3(0.299f, 0.587f, 0.114f)),
|
||||||
|
dot(rgb.rgb, float3(-0.14713f, -0.28886f, 0.436f)),
|
||||||
|
dot(rgb.rgb, float3(0.615f, -0.51499f, -0.10001f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 YUVToRGB(float3 yuv)
|
||||||
|
{
|
||||||
|
return float3(dot(yuv, float3(1.0f, 0.0f, 1.13983f)),
|
||||||
|
dot(yuv, float3(1.0f, -0.39465f, -0.58060f)),
|
||||||
|
dot(yuv, float3(1.0f, 2.03211f, 0.0f)));
|
||||||
|
}
|
||||||
|
|
||||||
float4 LoadVRAM(int2 coords)
|
float4 LoadVRAM(int2 coords)
|
||||||
{
|
{
|
||||||
#if MULTISAMPLING
|
#if MULTISAMPLING
|
||||||
|
@ -1015,12 +1031,61 @@ float4 LoadVRAM(int2 coords)
|
||||||
return LOAD_TEXTURE(samp0, coords, 0);
|
return LOAD_TEXTURE(samp0, coords, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float3 SampleVRAM24(uint2 icoords)
|
||||||
|
{
|
||||||
|
// load adjacent 16-bit texels
|
||||||
|
uint2 clamp_size = uint2(1024, 512);
|
||||||
|
|
||||||
|
// relative to start of scanout
|
||||||
|
uint2 vram_coords = u_vram_offset + uint2((icoords.x * 3u) / 2u, icoords.y);
|
||||||
|
uint s0 = RGBA8ToRGBA5551(LoadVRAM(int2((vram_coords % clamp_size) * RESOLUTION_SCALE)));
|
||||||
|
uint s1 = RGBA8ToRGBA5551(LoadVRAM(int2(((vram_coords + uint2(1, 0)) % clamp_size) * RESOLUTION_SCALE)));
|
||||||
|
|
||||||
|
// select which part of the combined 16-bit texels we are currently shading
|
||||||
|
uint s1s0 = ((s1 << 16) | s0) >> ((icoords.x & 1u) * 8u);
|
||||||
|
|
||||||
|
// extract components and normalize
|
||||||
|
return float3(float(s1s0 & 0xFFu) / 255.0, float((s1s0 >> 8u) & 0xFFu) / 255.0,
|
||||||
|
float((s1s0 >> 16u) & 0xFFu) / 255.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 SampleVRAMAverage2x2(uint2 icoords)
|
||||||
|
{
|
||||||
|
float3 value = SampleVRAM24(icoords);
|
||||||
|
value += SampleVRAM24(icoords + uint2(0, 1));
|
||||||
|
value += SampleVRAM24(icoords + uint2(1, 0));
|
||||||
|
value += SampleVRAM24(icoords + uint2(1, 1));
|
||||||
|
return value * 0.25;
|
||||||
|
}
|
||||||
|
|
||||||
|
float3 SampleVRAM24Smoothed(uint2 icoords)
|
||||||
|
{
|
||||||
|
int2 base = int2(icoords) - 1;
|
||||||
|
uint2 low = uint2(max(base & ~1, int2(0, 0)));
|
||||||
|
uint2 high = low + 2u;
|
||||||
|
float2 coeff = vec2(base & 1) * 0.5 + 0.25;
|
||||||
|
|
||||||
|
float3 p = SampleVRAM24(icoords);
|
||||||
|
float3 p00 = SampleVRAMAverage2x2(low);
|
||||||
|
float3 p01 = SampleVRAMAverage2x2(uint2(low.x, high.y));
|
||||||
|
float3 p10 = SampleVRAMAverage2x2(uint2(high.x, low.y));
|
||||||
|
float3 p11 = SampleVRAMAverage2x2(high);
|
||||||
|
|
||||||
|
float3 s = lerp(lerp(p00, p10, coeff.x),
|
||||||
|
lerp(p01, p11, coeff.x),
|
||||||
|
coeff.y);
|
||||||
|
|
||||||
|
float y = RGBToYUV(p).x;
|
||||||
|
float2 uv = RGBToYUV(s).yz;
|
||||||
|
return YUVToRGB(float3(y, uv));
|
||||||
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
DeclareFragmentEntryPoint(ss, 0, 1, {}, true, 1);
|
DeclareFragmentEntryPoint(ss, 0, 1, {}, true, 1);
|
||||||
ss << R"(
|
ss << R"(
|
||||||
{
|
{
|
||||||
uint2 icoords = uint2(v_pos.xy);
|
uint2 icoords = uint2(v_pos.xy) + uint2(u_crop_left, 0u);
|
||||||
|
|
||||||
#if INTERLACED
|
#if INTERLACED
|
||||||
if ((fixYCoord(icoords.y) & 1u) != u_field_offset)
|
if ((fixYCoord(icoords.y) & 1u) != u_field_offset)
|
||||||
|
@ -1034,24 +1099,13 @@ float4 LoadVRAM(int2 coords)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if DEPTH_24BIT
|
#if DEPTH_24BIT
|
||||||
// relative to start of scanout
|
#if SMOOTH_CHROMA
|
||||||
uint relative_x = (icoords.x + u_crop_left) / RESOLUTION_SCALE;
|
o_col0 = float4(SampleVRAM24Smoothed(icoords), 1.0);
|
||||||
uint2 vram_coords = u_vram_offset + uint2(((relative_x * 3u) / 2u) * RESOLUTION_SCALE, icoords.y);
|
|
||||||
|
|
||||||
// load adjacent 16-bit texels
|
|
||||||
uint s0 = RGBA8ToRGBA5551(LoadVRAM(int2(vram_coords % VRAM_SIZE)));
|
|
||||||
uint s1 = RGBA8ToRGBA5551(LoadVRAM(int2((vram_coords + uint2(RESOLUTION_SCALE, 0)) % VRAM_SIZE)));
|
|
||||||
|
|
||||||
// select which part of the combined 16-bit texels we are currently shading
|
|
||||||
uint s1s0 = ((s1 << 16) | s0) >> ((relative_x & 1u) * 8u);
|
|
||||||
|
|
||||||
// extract components and normalize
|
|
||||||
o_col0 = float4(float(s1s0 & 0xFFu) / 255.0, float((s1s0 >> 8u) & 0xFFu) / 255.0,
|
|
||||||
float((s1s0 >> 16u) & 0xFFu) / 255.0, 1.0);
|
|
||||||
#else
|
#else
|
||||||
// load and return
|
o_col0 = float4(SampleVRAM24(icoords), 1.0);
|
||||||
uint2 vram_coords = u_vram_offset + uint2(icoords.x + u_crop_left, icoords.y);
|
#endif
|
||||||
o_col0 = LoadVRAM(int2(vram_coords % VRAM_SIZE));
|
#else
|
||||||
|
o_col0 = float4(LoadVRAM(int2((icoords + u_vram_offset) % VRAM_SIZE)).rgb, 1.0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
|
@ -14,7 +14,8 @@ public:
|
||||||
std::string GenerateBatchFragmentShader(GPU_HW::BatchRenderMode transparency, GPU::TextureMode texture_mode,
|
std::string GenerateBatchFragmentShader(GPU_HW::BatchRenderMode transparency, GPU::TextureMode texture_mode,
|
||||||
bool dithering, bool interlacing);
|
bool dithering, bool interlacing);
|
||||||
std::string GenerateInterlacedFillFragmentShader();
|
std::string GenerateInterlacedFillFragmentShader();
|
||||||
std::string GenerateDisplayFragmentShader(bool depth_24bit, GPU_HW::InterlacedRenderMode interlace_mode);
|
std::string GenerateDisplayFragmentShader(bool depth_24bit, GPU_HW::InterlacedRenderMode interlace_mode,
|
||||||
|
bool smooth_chroma);
|
||||||
std::string GenerateVRAMReadFragmentShader();
|
std::string GenerateVRAMReadFragmentShader();
|
||||||
std::string GenerateVRAMWriteFragmentShader(bool use_ssbo);
|
std::string GenerateVRAMWriteFragmentShader(bool use_ssbo);
|
||||||
std::string GenerateVRAMCopyFragmentShader();
|
std::string GenerateVRAMCopyFragmentShader();
|
||||||
|
|
|
@ -888,7 +888,7 @@ bool GPU_HW_Vulkan::CompilePipelines()
|
||||||
for (u8 interlace_mode = 0; interlace_mode < 3; interlace_mode++)
|
for (u8 interlace_mode = 0; interlace_mode < 3; interlace_mode++)
|
||||||
{
|
{
|
||||||
VkShaderModule fs = g_vulkan_shader_cache->GetFragmentShader(shadergen.GenerateDisplayFragmentShader(
|
VkShaderModule fs = g_vulkan_shader_cache->GetFragmentShader(shadergen.GenerateDisplayFragmentShader(
|
||||||
ConvertToBoolUnchecked(depth_24), static_cast<InterlacedRenderMode>(interlace_mode)));
|
ConvertToBoolUnchecked(depth_24), static_cast<InterlacedRenderMode>(interlace_mode), m_chroma_smoothing));
|
||||||
if (fs == VK_NULL_HANDLE)
|
if (fs == VK_NULL_HANDLE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -991,14 +991,15 @@ void GPU_HW_Vulkan::UpdateDisplay()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
const u32 resolution_scale = m_GPUSTAT.display_area_color_depth_24 ? 1 : m_resolution_scale;
|
||||||
const u32 vram_offset_x = m_crtc_state.display_vram_left;
|
const u32 vram_offset_x = m_crtc_state.display_vram_left;
|
||||||
const u32 vram_offset_y = m_crtc_state.display_vram_top;
|
const u32 vram_offset_y = m_crtc_state.display_vram_top;
|
||||||
const u32 scaled_vram_offset_x = vram_offset_x * m_resolution_scale;
|
const u32 scaled_vram_offset_x = vram_offset_x * resolution_scale;
|
||||||
const u32 scaled_vram_offset_y = vram_offset_y * m_resolution_scale;
|
const u32 scaled_vram_offset_y = vram_offset_y * resolution_scale;
|
||||||
const u32 display_width = m_crtc_state.display_vram_width;
|
const u32 display_width = m_crtc_state.display_vram_width;
|
||||||
const u32 display_height = m_crtc_state.display_vram_height;
|
const u32 display_height = m_crtc_state.display_vram_height;
|
||||||
const u32 scaled_display_width = display_width * m_resolution_scale;
|
const u32 scaled_display_width = display_width * resolution_scale;
|
||||||
const u32 scaled_display_height = display_height * m_resolution_scale;
|
const u32 scaled_display_height = display_height * resolution_scale;
|
||||||
const InterlacedRenderMode interlaced = GetInterlacedRenderMode();
|
const InterlacedRenderMode interlaced = GetInterlacedRenderMode();
|
||||||
|
|
||||||
if (IsDisplayDisabled())
|
if (IsDisplayDisabled())
|
||||||
|
@ -1020,8 +1021,8 @@ void GPU_HW_Vulkan::UpdateDisplay()
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
|
|
||||||
const u32 reinterpret_field_offset = (interlaced != InterlacedRenderMode::None) ? GetInterlacedDisplayField() : 0;
|
const u32 reinterpret_field_offset = (interlaced != InterlacedRenderMode::None) ? GetInterlacedDisplayField() : 0;
|
||||||
const u32 reinterpret_start_x = m_crtc_state.regs.X * m_resolution_scale;
|
const u32 reinterpret_start_x = m_crtc_state.regs.X * resolution_scale;
|
||||||
const u32 reinterpret_crop_left = (m_crtc_state.display_vram_left - m_crtc_state.regs.X) * m_resolution_scale;
|
const u32 reinterpret_crop_left = (m_crtc_state.display_vram_left - m_crtc_state.regs.X) * resolution_scale;
|
||||||
const u32 uniforms[4] = {reinterpret_start_x, scaled_vram_offset_y + reinterpret_field_offset,
|
const u32 uniforms[4] = {reinterpret_start_x, scaled_vram_offset_y + reinterpret_field_offset,
|
||||||
reinterpret_crop_left, reinterpret_field_offset};
|
reinterpret_crop_left, reinterpret_field_offset};
|
||||||
|
|
||||||
|
|
|
@ -438,6 +438,7 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si)
|
||||||
si.SetBoolValue("GPU", "DisableInterlacing", false);
|
si.SetBoolValue("GPU", "DisableInterlacing", false);
|
||||||
si.SetBoolValue("GPU", "ForceNTSCTimings", false);
|
si.SetBoolValue("GPU", "ForceNTSCTimings", false);
|
||||||
si.SetBoolValue("GPU", "WidescreenHack", false);
|
si.SetBoolValue("GPU", "WidescreenHack", false);
|
||||||
|
si.SetBoolValue("GPU", "ChromaSmoothing24Bit", false);
|
||||||
si.SetBoolValue("GPU", "PGXPEnable", false);
|
si.SetBoolValue("GPU", "PGXPEnable", false);
|
||||||
si.SetBoolValue("GPU", "PGXPCulling", true);
|
si.SetBoolValue("GPU", "PGXPCulling", true);
|
||||||
si.SetBoolValue("GPU", "PGXPTextureCorrection", true);
|
si.SetBoolValue("GPU", "PGXPTextureCorrection", true);
|
||||||
|
@ -634,6 +635,7 @@ void HostInterface::CheckForSettingsChanges(const Settings& old_settings)
|
||||||
g_settings.gpu_texture_filter != old_settings.gpu_texture_filter ||
|
g_settings.gpu_texture_filter != old_settings.gpu_texture_filter ||
|
||||||
g_settings.gpu_disable_interlacing != old_settings.gpu_disable_interlacing ||
|
g_settings.gpu_disable_interlacing != old_settings.gpu_disable_interlacing ||
|
||||||
g_settings.gpu_force_ntsc_timings != old_settings.gpu_force_ntsc_timings ||
|
g_settings.gpu_force_ntsc_timings != old_settings.gpu_force_ntsc_timings ||
|
||||||
|
g_settings.gpu_24bit_chroma_smoothing != old_settings.gpu_24bit_chroma_smoothing ||
|
||||||
g_settings.display_crop_mode != old_settings.display_crop_mode ||
|
g_settings.display_crop_mode != old_settings.display_crop_mode ||
|
||||||
g_settings.display_aspect_ratio != old_settings.display_aspect_ratio ||
|
g_settings.display_aspect_ratio != old_settings.display_aspect_ratio ||
|
||||||
g_settings.gpu_pgxp_enable != old_settings.gpu_pgxp_enable ||
|
g_settings.gpu_pgxp_enable != old_settings.gpu_pgxp_enable ||
|
||||||
|
|
|
@ -148,6 +148,7 @@ void Settings::Load(SettingsInterface& si)
|
||||||
gpu_disable_interlacing = si.GetBoolValue("GPU", "DisableInterlacing", false);
|
gpu_disable_interlacing = si.GetBoolValue("GPU", "DisableInterlacing", false);
|
||||||
gpu_force_ntsc_timings = si.GetBoolValue("GPU", "ForceNTSCTimings", false);
|
gpu_force_ntsc_timings = si.GetBoolValue("GPU", "ForceNTSCTimings", false);
|
||||||
gpu_widescreen_hack = si.GetBoolValue("GPU", "WidescreenHack", false);
|
gpu_widescreen_hack = si.GetBoolValue("GPU", "WidescreenHack", false);
|
||||||
|
gpu_24bit_chroma_smoothing = si.GetBoolValue("GPU", "ChromaSmoothing24Bit", false);
|
||||||
gpu_pgxp_enable = si.GetBoolValue("GPU", "PGXPEnable", false);
|
gpu_pgxp_enable = si.GetBoolValue("GPU", "PGXPEnable", false);
|
||||||
gpu_pgxp_culling = si.GetBoolValue("GPU", "PGXPCulling", true);
|
gpu_pgxp_culling = si.GetBoolValue("GPU", "PGXPCulling", true);
|
||||||
gpu_pgxp_texture_correction = si.GetBoolValue("GPU", "PGXPTextureCorrection", true);
|
gpu_pgxp_texture_correction = si.GetBoolValue("GPU", "PGXPTextureCorrection", true);
|
||||||
|
@ -277,6 +278,7 @@ void Settings::Save(SettingsInterface& si) const
|
||||||
si.SetBoolValue("GPU", "DisableInterlacing", gpu_disable_interlacing);
|
si.SetBoolValue("GPU", "DisableInterlacing", gpu_disable_interlacing);
|
||||||
si.SetBoolValue("GPU", "ForceNTSCTimings", gpu_force_ntsc_timings);
|
si.SetBoolValue("GPU", "ForceNTSCTimings", gpu_force_ntsc_timings);
|
||||||
si.SetBoolValue("GPU", "WidescreenHack", gpu_widescreen_hack);
|
si.SetBoolValue("GPU", "WidescreenHack", gpu_widescreen_hack);
|
||||||
|
si.SetBoolValue("GPU", "ChromaSmoothing24Bit", gpu_24bit_chroma_smoothing);
|
||||||
si.SetBoolValue("GPU", "PGXPEnable", gpu_pgxp_enable);
|
si.SetBoolValue("GPU", "PGXPEnable", gpu_pgxp_enable);
|
||||||
si.SetBoolValue("GPU", "PGXPCulling", gpu_pgxp_culling);
|
si.SetBoolValue("GPU", "PGXPCulling", gpu_pgxp_culling);
|
||||||
si.SetBoolValue("GPU", "PGXPTextureCorrection", gpu_pgxp_texture_correction);
|
si.SetBoolValue("GPU", "PGXPTextureCorrection", gpu_pgxp_texture_correction);
|
||||||
|
|
|
@ -113,6 +113,7 @@ struct Settings
|
||||||
s16 display_active_end_offset = 0;
|
s16 display_active_end_offset = 0;
|
||||||
DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::R4_3;
|
DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::R4_3;
|
||||||
bool display_force_4_3_for_24bit = false;
|
bool display_force_4_3_for_24bit = false;
|
||||||
|
bool gpu_24bit_chroma_smoothing = false;
|
||||||
bool display_linear_filtering = true;
|
bool display_linear_filtering = true;
|
||||||
bool display_integer_scaling = false;
|
bool display_integer_scaling = false;
|
||||||
bool display_post_processing = false;
|
bool display_post_processing = false;
|
||||||
|
|
|
@ -457,7 +457,7 @@ void LibretroHostInterface::OnSystemDestroyed()
|
||||||
m_using_hardware_renderer = false;
|
m_using_hardware_renderer = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::array<retro_core_option_definition, 41> s_option_definitions = {{
|
static std::array<retro_core_option_definition, 42> s_option_definitions = {{
|
||||||
{"duckstation_Console.Region",
|
{"duckstation_Console.Region",
|
||||||
"Console Region",
|
"Console Region",
|
||||||
"Determines which region/hardware to emulate. Auto-Detect will use the region of the disc inserted.",
|
"Determines which region/hardware to emulate. Auto-Detect will use the region of the disc inserted.",
|
||||||
|
@ -604,6 +604,12 @@ static std::array<retro_core_option_definition, 41> s_option_definitions = {{
|
||||||
"Switches back to 4:3 display aspect ratio when displaying 24-bit content, usually FMVs.",
|
"Switches back to 4:3 display aspect ratio when displaying 24-bit content, usually FMVs.",
|
||||||
{{"true", "Enabled"}, {"false", "Disabled"}},
|
{{"true", "Enabled"}, {"false", "Disabled"}},
|
||||||
"false"},
|
"false"},
|
||||||
|
{"duckstation_GPU.ChromaSmoothing24Bit",
|
||||||
|
"Chroma Smoothing For 24-Bit Display",
|
||||||
|
"Smooths out blockyness between colour transitions in 24-bit content, usually FMVs. Only applies to the hardware "
|
||||||
|
"renderers.",
|
||||||
|
{{"true", "Enabled"}, {"false", "Disabled"}},
|
||||||
|
"false"},
|
||||||
{"duckstation_GPU.TextureFilter",
|
{"duckstation_GPU.TextureFilter",
|
||||||
"Texture Filtering",
|
"Texture Filtering",
|
||||||
"Smooths out the blockyness of magnified textures on 3D object by using bilinear filtering. Will have a "
|
"Smooths out the blockyness of magnified textures on 3D object by using bilinear filtering. Will have a "
|
||||||
|
|
|
@ -18,6 +18,8 @@ EnhancementSettingsWidget::EnhancementSettingsWidget(QtHostInterface* host_inter
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.disableInterlacing, "GPU", "DisableInterlacing");
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.disableInterlacing, "GPU", "DisableInterlacing");
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.forceNTSCTimings, "GPU", "ForceNTSCTimings");
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.forceNTSCTimings, "GPU", "ForceNTSCTimings");
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.force43For24Bit, "Display", "Force4_3For24Bit");
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.force43For24Bit, "Display", "Force4_3For24Bit");
|
||||||
|
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.chromaSmoothingFor24Bit, "GPU",
|
||||||
|
"ChromaSmoothing24Bit");
|
||||||
SettingWidgetBinder::BindWidgetToEnumSetting(
|
SettingWidgetBinder::BindWidgetToEnumSetting(
|
||||||
m_host_interface, m_ui.textureFiltering, "GPU", "TextureFilter", &Settings::ParseTextureFilterName,
|
m_host_interface, m_ui.textureFiltering, "GPU", "TextureFilter", &Settings::ParseTextureFilterName,
|
||||||
&Settings::GetTextureFilterDisplayName, Settings::DEFAULT_GPU_TEXTURE_FILTER);
|
&Settings::GetTextureFilterDisplayName, Settings::DEFAULT_GPU_TEXTURE_FILTER);
|
||||||
|
@ -75,6 +77,9 @@ EnhancementSettingsWidget::EnhancementSettingsWidget(QtHostInterface* host_inter
|
||||||
dialog->registerWidgetHelp(
|
dialog->registerWidgetHelp(
|
||||||
m_ui.force43For24Bit, tr("Force 4:3 For 24-bit Display"), tr("Unchecked"),
|
m_ui.force43For24Bit, tr("Force 4:3 For 24-bit Display"), tr("Unchecked"),
|
||||||
tr("Switches back to 4:3 display aspect ratio when displaying 24-bit content, usually FMVs."));
|
tr("Switches back to 4:3 display aspect ratio when displaying 24-bit content, usually FMVs."));
|
||||||
|
dialog->registerWidgetHelp(m_ui.chromaSmoothingFor24Bit, tr("Chroma Smoothing For 24-Bit Display"), tr("Unchecked"),
|
||||||
|
tr("Smooths out blockyness between colour transitions in 24-bit content, usually FMVs. "
|
||||||
|
"Only applies to the hardware renderers."));
|
||||||
dialog->registerWidgetHelp(
|
dialog->registerWidgetHelp(
|
||||||
m_ui.textureFiltering, tr("Texture Filtering"),
|
m_ui.textureFiltering, tr("Texture Filtering"),
|
||||||
qApp->translate("GPUTextureFilter", Settings::GetTextureFilterDisplayName(GPUTextureFilter::Nearest)),
|
qApp->translate("GPUTextureFilter", Settings::GetTextureFilterDisplayName(GPUTextureFilter::Nearest)),
|
||||||
|
|
|
@ -113,6 +113,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="chromaSmoothingFor24Bit">
|
||||||
|
<property name="text">
|
||||||
|
<string>Chroma Smoothing For 24-Bit Display (reduce FMV color blockyness)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -1017,6 +1017,7 @@ void SDLHostInterface::DrawQuickSettingsMenu()
|
||||||
settings_changed |= ImGui::MenuItem("Disable Interlacing", nullptr, &m_settings_copy.gpu_disable_interlacing);
|
settings_changed |= ImGui::MenuItem("Disable Interlacing", nullptr, &m_settings_copy.gpu_disable_interlacing);
|
||||||
settings_changed |= ImGui::MenuItem("Widescreen Hack", nullptr, &m_settings_copy.gpu_widescreen_hack);
|
settings_changed |= ImGui::MenuItem("Widescreen Hack", nullptr, &m_settings_copy.gpu_widescreen_hack);
|
||||||
settings_changed |= ImGui::MenuItem("Force NTSC Timings", nullptr, &m_settings_copy.gpu_force_ntsc_timings);
|
settings_changed |= ImGui::MenuItem("Force NTSC Timings", nullptr, &m_settings_copy.gpu_force_ntsc_timings);
|
||||||
|
settings_changed |= ImGui::MenuItem("24-Bit Chroma Smoothing", nullptr, &m_settings_copy.gpu_24bit_chroma_smoothing);
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
|
@ -1545,6 +1546,7 @@ void SDLHostInterface::DrawSettingsWindow()
|
||||||
settings_changed |= ImGui::Checkbox("Widescreen Hack", &m_settings_copy.gpu_widescreen_hack);
|
settings_changed |= ImGui::Checkbox("Widescreen Hack", &m_settings_copy.gpu_widescreen_hack);
|
||||||
settings_changed |=
|
settings_changed |=
|
||||||
ImGui::Checkbox("Force 4:3 For 24-Bit Display", &m_settings_copy.display_force_4_3_for_24bit);
|
ImGui::Checkbox("Force 4:3 For 24-Bit Display", &m_settings_copy.display_force_4_3_for_24bit);
|
||||||
|
settings_changed |= ImGui::Checkbox("24-Bit Chroma Smoothing", &m_settings_copy.gpu_24bit_chroma_smoothing);
|
||||||
|
|
||||||
settings_changed |= ImGui::Checkbox("PGXP Enabled", &m_settings_copy.gpu_pgxp_enable);
|
settings_changed |= ImGui::Checkbox("PGXP Enabled", &m_settings_copy.gpu_pgxp_enable);
|
||||||
settings_changed |= ImGui::Checkbox("PGXP Culling", &m_settings_copy.gpu_pgxp_culling);
|
settings_changed |= ImGui::Checkbox("PGXP Culling", &m_settings_copy.gpu_pgxp_culling);
|
||||||
|
|
Loading…
Reference in a new issue