GPU: Add chroma smoothing for 24-bit display enhancement

This commit is contained in:
Connor McLaughlin 2020-11-03 14:17:51 +10:00
parent d102b2facd
commit ae1e4b1b8f
14 changed files with 136 additions and 48 deletions

View File

@ -54,6 +54,7 @@ bool GPU_HW::Initialize(HostDisplay* host_display)
m_scaled_dithering = g_settings.gpu_scaled_dithering;
m_texture_filtering = g_settings.gpu_texture_filter;
m_using_uv_limits = ShouldUseUVLimits();
m_chroma_smoothing = g_settings.gpu_24bit_chroma_smoothing;
PrintSettingsToLog();
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();
*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_scaled_dithering != g_settings.gpu_scaled_dithering ||
m_texture_filtering != g_settings.gpu_texture_filter || m_using_uv_limits != use_uv_limits);
m_scaled_dithering != g_settings.gpu_scaled_dithering || m_texture_filtering != g_settings.gpu_texture_filter ||
m_using_uv_limits != use_uv_limits || m_chroma_smoothing != g_settings.gpu_24bit_chroma_smoothing);
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_texture_filtering = g_settings.gpu_texture_filter;
m_using_uv_limits = use_uv_limits;
m_chroma_smoothing = g_settings.gpu_24bit_chroma_smoothing;
PrintSettingsToLog();
}

View File

@ -276,6 +276,7 @@ protected:
bool m_true_color = true;
bool m_scaled_dithering = false;
GPUTextureFilter m_texture_filtering = GPUTextureFilter::Nearest;
bool m_chroma_smoothing = false;
bool m_supports_per_sample_shading = false;
bool m_supports_dual_source_blend = false;
bool m_using_uv_limits = false;

View File

@ -525,8 +525,9 @@ bool GPU_HW_D3D11::CompileShaders()
{
for (u8 interlacing = 0; interlacing < 3; interlacing++)
{
const std::string ps = shadergen.GenerateDisplayFragmentShader(ConvertToBoolUnchecked(depth_24bit),
static_cast<InterlacedRenderMode>(interlacing));
const std::string ps = shadergen.GenerateDisplayFragmentShader(
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);
if (!m_display_pixel_shaders[depth_24bit][interlacing])
return false;
@ -669,14 +670,15 @@ void GPU_HW_D3D11::UpdateDisplay()
}
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_y = m_crtc_state.display_vram_top;
const u32 scaled_vram_offset_x = vram_offset_x * m_resolution_scale;
const u32 scaled_vram_offset_y = vram_offset_y * m_resolution_scale;
const u32 scaled_vram_offset_x = vram_offset_x * 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_height = m_crtc_state.display_vram_height;
const u32 scaled_display_width = display_width * m_resolution_scale;
const u32 scaled_display_height = display_height * m_resolution_scale;
const u32 scaled_display_width = display_width * resolution_scale;
const u32 scaled_display_height = display_height * resolution_scale;
const InterlacedRenderMode interlaced = GetInterlacedRenderMode();
if (IsDisplayDisabled())
@ -699,8 +701,8 @@ void GPU_HW_D3D11::UpdateDisplay()
m_context->PSSetShaderResources(0, 1, m_vram_texture.GetD3DSRVArray());
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_crop_left = (m_crtc_state.display_vram_left - 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) * resolution_scale;
const u32 uniforms[4] = {reinterpret_start_x, scaled_vram_offset_y + reinterpret_field_offset,
reinterpret_crop_left, reinterpret_field_offset};
ID3D11PixelShader* display_pixel_shader =

View File

@ -455,8 +455,8 @@ bool GPU_HW_OpenGL::CompilePrograms()
for (u8 interlaced = 0; interlaced < 3; interlaced++)
{
const std::string vs = shadergen.GenerateScreenQuadVertexShader();
const std::string fs = shadergen.GenerateDisplayFragmentShader(ConvertToBoolUnchecked(depth_24bit),
static_cast<InterlacedRenderMode>(interlaced));
const std::string fs = shadergen.GenerateDisplayFragmentShader(
ConvertToBoolUnchecked(depth_24bit), static_cast<InterlacedRenderMode>(interlaced), m_chroma_smoothing);
std::optional<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
{
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_y = m_crtc_state.display_vram_top;
const u32 scaled_vram_offset_x = vram_offset_x * m_resolution_scale;
const u32 scaled_vram_offset_y = vram_offset_y * m_resolution_scale;
const u32 scaled_vram_offset_x = vram_offset_x * 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_height = m_crtc_state.display_vram_height;
const u32 scaled_display_width = display_width * m_resolution_scale;
const u32 scaled_display_height = display_height * m_resolution_scale;
const u32 scaled_display_width = display_width * resolution_scale;
const u32 scaled_display_height = display_height * resolution_scale;
const InterlacedRenderMode interlaced = GetInterlacedRenderMode();
if (IsDisplayDisabled())
@ -710,8 +711,8 @@ void GPU_HW_OpenGL::UpdateDisplay()
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 -
reinterpret_field_offset - (scaled_display_height >> height_div2);
const u32 reinterpret_start_x = m_crtc_state.regs.X * m_resolution_scale;
const u32 reinterpret_crop_left = (m_crtc_state.display_vram_left - 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) * resolution_scale;
const u32 uniforms[4] = {reinterpret_start_x, scaled_flipped_vram_offset_y, reinterpret_crop_left,
reinterpret_field_offset};
UploadUniformBuffer(uniforms, sizeof(uniforms));

View File

@ -990,19 +990,35 @@ std::string GPU_HW_ShaderGen::GenerateInterlacedFillFragmentShader()
}
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;
WriteHeader(ss);
DefineMacro(ss, "DEPTH_24BIT", depth_24bit);
DefineMacro(ss, "INTERLACED", interlace_mode != GPU_HW::InterlacedRenderMode::None);
DefineMacro(ss, "INTERLEAVED", interlace_mode == GPU_HW::InterlacedRenderMode::InterleavedFields);
DefineMacro(ss, "SMOOTH_CHROMA", smooth_chroma);
WriteCommonFunctions(ss);
DeclareUniformBuffer(ss, {"uint2 u_vram_offset", "uint u_crop_left", "uint u_field_offset"}, true);
DeclareTexture(ss, "samp0", 0, UsingMSAA());
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)
{
#if MULTISAMPLING
@ -1015,12 +1031,61 @@ float4 LoadVRAM(int2 coords)
return LOAD_TEXTURE(samp0, coords, 0);
#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);
ss << R"(
{
uint2 icoords = uint2(v_pos.xy);
uint2 icoords = uint2(v_pos.xy) + uint2(u_crop_left, 0u);
#if INTERLACED
if ((fixYCoord(icoords.y) & 1u) != u_field_offset)
@ -1034,24 +1099,13 @@ float4 LoadVRAM(int2 coords)
#endif
#if DEPTH_24BIT
// relative to start of scanout
uint relative_x = (icoords.x + u_crop_left) / RESOLUTION_SCALE;
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);
#if SMOOTH_CHROMA
o_col0 = float4(SampleVRAM24Smoothed(icoords), 1.0);
#else
// load and return
uint2 vram_coords = u_vram_offset + uint2(icoords.x + u_crop_left, icoords.y);
o_col0 = LoadVRAM(int2(vram_coords % VRAM_SIZE));
o_col0 = float4(SampleVRAM24(icoords), 1.0);
#endif
#else
o_col0 = float4(LoadVRAM(int2((icoords + u_vram_offset) % VRAM_SIZE)).rgb, 1.0);
#endif
}
)";

View File

@ -14,7 +14,8 @@ public:
std::string GenerateBatchFragmentShader(GPU_HW::BatchRenderMode transparency, GPU::TextureMode texture_mode,
bool dithering, bool interlacing);
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 GenerateVRAMWriteFragmentShader(bool use_ssbo);
std::string GenerateVRAMCopyFragmentShader();

View File

@ -888,7 +888,7 @@ bool GPU_HW_Vulkan::CompilePipelines()
for (u8 interlace_mode = 0; interlace_mode < 3; interlace_mode++)
{
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)
return false;
@ -991,14 +991,15 @@ void GPU_HW_Vulkan::UpdateDisplay()
}
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_y = m_crtc_state.display_vram_top;
const u32 scaled_vram_offset_x = vram_offset_x * m_resolution_scale;
const u32 scaled_vram_offset_y = vram_offset_y * m_resolution_scale;
const u32 scaled_vram_offset_x = vram_offset_x * 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_height = m_crtc_state.display_vram_height;
const u32 scaled_display_width = display_width * m_resolution_scale;
const u32 scaled_display_height = display_height * m_resolution_scale;
const u32 scaled_display_width = display_width * resolution_scale;
const u32 scaled_display_height = display_height * resolution_scale;
const InterlacedRenderMode interlaced = GetInterlacedRenderMode();
if (IsDisplayDisabled())
@ -1020,8 +1021,8 @@ void GPU_HW_Vulkan::UpdateDisplay()
EndRenderPass();
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_crop_left = (m_crtc_state.display_vram_left - 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) * resolution_scale;
const u32 uniforms[4] = {reinterpret_start_x, scaled_vram_offset_y + reinterpret_field_offset,
reinterpret_crop_left, reinterpret_field_offset};

View File

@ -438,6 +438,7 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si)
si.SetBoolValue("GPU", "DisableInterlacing", false);
si.SetBoolValue("GPU", "ForceNTSCTimings", false);
si.SetBoolValue("GPU", "WidescreenHack", false);
si.SetBoolValue("GPU", "ChromaSmoothing24Bit", false);
si.SetBoolValue("GPU", "PGXPEnable", false);
si.SetBoolValue("GPU", "PGXPCulling", 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_disable_interlacing != old_settings.gpu_disable_interlacing ||
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_aspect_ratio != old_settings.display_aspect_ratio ||
g_settings.gpu_pgxp_enable != old_settings.gpu_pgxp_enable ||

View File

@ -148,6 +148,7 @@ void Settings::Load(SettingsInterface& si)
gpu_disable_interlacing = si.GetBoolValue("GPU", "DisableInterlacing", false);
gpu_force_ntsc_timings = si.GetBoolValue("GPU", "ForceNTSCTimings", 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_culling = si.GetBoolValue("GPU", "PGXPCulling", 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", "ForceNTSCTimings", gpu_force_ntsc_timings);
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", "PGXPCulling", gpu_pgxp_culling);
si.SetBoolValue("GPU", "PGXPTextureCorrection", gpu_pgxp_texture_correction);

View File

@ -113,6 +113,7 @@ struct Settings
s16 display_active_end_offset = 0;
DisplayAspectRatio display_aspect_ratio = DisplayAspectRatio::R4_3;
bool display_force_4_3_for_24bit = false;
bool gpu_24bit_chroma_smoothing = false;
bool display_linear_filtering = true;
bool display_integer_scaling = false;
bool display_post_processing = false;

View File

@ -457,7 +457,7 @@ void LibretroHostInterface::OnSystemDestroyed()
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",
"Console Region",
"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.",
{{"true", "Enabled"}, {"false", "Disabled"}},
"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",
"Texture Filtering",
"Smooths out the blockyness of magnified textures on 3D object by using bilinear filtering. Will have a "

View File

@ -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.forceNTSCTimings, "GPU", "ForceNTSCTimings");
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.force43For24Bit, "Display", "Force4_3For24Bit");
SettingWidgetBinder::BindWidgetToBoolSetting(m_host_interface, m_ui.chromaSmoothingFor24Bit, "GPU",
"ChromaSmoothing24Bit");
SettingWidgetBinder::BindWidgetToEnumSetting(
m_host_interface, m_ui.textureFiltering, "GPU", "TextureFilter", &Settings::ParseTextureFilterName,
&Settings::GetTextureFilterDisplayName, Settings::DEFAULT_GPU_TEXTURE_FILTER);
@ -75,6 +77,9 @@ EnhancementSettingsWidget::EnhancementSettingsWidget(QtHostInterface* host_inter
dialog->registerWidgetHelp(
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."));
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(
m_ui.textureFiltering, tr("Texture Filtering"),
qApp->translate("GPUTextureFilter", Settings::GetTextureFilterDisplayName(GPUTextureFilter::Nearest)),

View File

@ -113,6 +113,13 @@
</property>
</widget>
</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>
</widget>
</item>

View File

@ -1017,6 +1017,7 @@ void SDLHostInterface::DrawQuickSettingsMenu()
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("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();
@ -1545,6 +1546,7 @@ void SDLHostInterface::DrawSettingsWindow()
settings_changed |= ImGui::Checkbox("Widescreen Hack", &m_settings_copy.gpu_widescreen_hack);
settings_changed |=
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 Culling", &m_settings_copy.gpu_pgxp_culling);