GPU/HW: Add 'Scaled Interlacing' option

Disabling this option causes rendering to skip N lines instead of 1
line, where N is the internal resolution multiplier.
This commit is contained in:
Stenzek 2025-03-22 00:21:03 +10:00
parent d176109d3b
commit 62d7a73381
No known key found for this signature in database
12 changed files with 78 additions and 26 deletions

View File

@ -486,10 +486,9 @@ static constexpr const std::array s_ps_button_mapping{
};
static constexpr std::array s_theme_names = {
FSUI_NSTR("Automatic"), FSUI_NSTR("Dark"), FSUI_NSTR("Light"),
FSUI_NSTR("AMOLED"), FSUI_NSTR("Cobalt Sky"), FSUI_NSTR("Grey Matter"),
FSUI_NSTR("Green Giant"), FSUI_NSTR("Pinky Pals"), FSUI_NSTR("Dark Ruby"),
FSUI_NSTR("Purple Rain")};
FSUI_NSTR("Automatic"), FSUI_NSTR("Dark"), FSUI_NSTR("Light"), FSUI_NSTR("AMOLED"),
FSUI_NSTR("Cobalt Sky"), FSUI_NSTR("Grey Matter"), FSUI_NSTR("Green Giant"), FSUI_NSTR("Pinky Pals"),
FSUI_NSTR("Dark Ruby"), FSUI_NSTR("Purple Rain")};
static constexpr std::array s_theme_values = {"", "Dark", "Light", "AMOLED", "CobaltSky",
"GreyMatter", "GreenGiant", "PinkyPals", "DarkRuby", "PurpleRain"};
@ -5231,7 +5230,12 @@ void FullscreenUI::DrawGraphicsSettingsPage()
bsi, FSUI_ICONSTR(ICON_FA_TINT_SLASH, "Scaled Dithering"),
FSUI_CSTR("Scales the dithering pattern with the internal rendering resolution, making it less noticeable. "
"Usually safe to enable."),
"GPU", "ScaledDithering", true, !true_color_enabled);
"GPU", "ScaledDithering", true, !true_color_enabled && resolution_scale > 1);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TINT_SLASH, "Scaled Interlacing"),
FSUI_CSTR("Scales line skipping in interlaced rendering to the internal resolution, making it "
"less noticeable. Usually safe to enable."),
"GPU", "ScaledInterlacing", true, resolution_scale > 1);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_FILL, "Accurate Blending"),
FSUI_CSTR("Forces blending to be done in the shader at 16-bit precision, when not using true "
@ -9106,6 +9110,7 @@ TRANSLATE_NOOP("FullscreenUI", "GitHub Repository");
TRANSLATE_NOOP("FullscreenUI", "Global Slot {0} - {1}##global_slot_{0}");
TRANSLATE_NOOP("FullscreenUI", "Global Slot {0}##global_slot_{0}");
TRANSLATE_NOOP("FullscreenUI", "Graphics Settings");
TRANSLATE_NOOP("FullscreenUI", "Green Giant");
TRANSLATE_NOOP("FullscreenUI", "Grey Matter");
TRANSLATE_NOOP("FullscreenUI", "Hardcore Mode");
TRANSLATE_NOOP("FullscreenUI", "Hardcore mode will be enabled on next game restart.");
@ -9318,7 +9323,9 @@ TRANSLATE_NOOP("FullscreenUI", "Save State On Shutdown");
TRANSLATE_NOOP("FullscreenUI", "Saved {:%c}");
TRANSLATE_NOOP("FullscreenUI", "Saves state periodically so you can rewind any mistakes while playing.");
TRANSLATE_NOOP("FullscreenUI", "Scaled Dithering");
TRANSLATE_NOOP("FullscreenUI", "Scaled Interlacing");
TRANSLATE_NOOP("FullscreenUI", "Scales internal VRAM resolution by the specified multiplier. Some games require 1x VRAM resolution.");
TRANSLATE_NOOP("FullscreenUI", "Scales line skipping in interlaced rendering to the internal resolution, making it less noticeable. Usually safe to enable.");
TRANSLATE_NOOP("FullscreenUI", "Scales the dithering pattern with the internal rendering resolution, making it less noticeable. Usually safe to enable.");
TRANSLATE_NOOP("FullscreenUI", "Scaling");
TRANSLATE_NOOP("FullscreenUI", "Scan For New Games");

View File

@ -40,7 +40,7 @@ namespace GameDatabase {
enum : u32
{
GAME_DATABASE_CACHE_SIGNATURE = 0x45434C48,
GAME_DATABASE_CACHE_VERSION = 22,
GAME_DATABASE_CACHE_VERSION = 23,
};
static const Entry* GetEntryForId(std::string_view code);
@ -89,6 +89,7 @@ static constexpr const std::array<const char*, static_cast<size_t>(Trait::MaxCou
"DisableTextureFiltering",
"DisableSpriteTextureFiltering",
"DisableScaledDithering",
"DisableScaledInterlacing",
"DisableWidescreen",
"DisablePGXP",
"DisablePGXPCulling",
@ -118,6 +119,7 @@ static constexpr const std::array<const char*, static_cast<size_t>(Trait::MaxCou
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Texture Filtering", "GameDatabase::Trait"),
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Sprite Texture Filtering", "GameDatabase::Trait"),
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Scaled Dithering", "GameDatabase::Trait"),
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Scaled Interlacing", "GameDatabase::Trait"),
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Widescreen", "GameDatabase::Trait"),
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable PGXP", "GameDatabase::Trait"),
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable PGXP Culling", "GameDatabase::Trait"),
@ -566,11 +568,22 @@ void GameDatabase::Entry::ApplySettings(Settings& settings, bool display_osd_mes
if (HasTrait(Trait::DisableScaledDithering))
{
if (display_osd_messages && settings.gpu_scaled_dithering)
APPEND_MESSAGE(TRANSLATE_SV("GameDatabase", "Scaled dithering."));
APPEND_MESSAGE(TRANSLATE_SV("GameDatabase", "Scaled dithering disabled."));
settings.gpu_scaled_dithering = false;
}
if (HasTrait(Trait::DisableScaledInterlacing))
{
if (display_osd_messages && settings.gpu_scaled_interlacing &&
settings.display_deinterlacing_mode != DisplayDeinterlacingMode::Progressive)
{
APPEND_MESSAGE(TRANSLATE_SV("GameDatabase", "Scaled interlacing disabled."));
}
settings.gpu_scaled_interlacing = false;
}
if (HasTrait(Trait::DisableWidescreen))
{
if (display_osd_messages && settings.gpu_widescreen_hack)

View File

@ -47,6 +47,7 @@ enum class Trait : u32
DisableTextureFiltering,
DisableSpriteTextureFiltering,
DisableScaledDithering,
DisableScaledInterlacing,
DisableWidescreen,
DisablePGXP,
DisablePGXPCulling,

View File

@ -457,7 +457,8 @@ bool GPU_HW::UpdateSettings(const GPUSettings& old_settings, Error* error)
(old_settings.display_deinterlacing_mode == DisplayDeinterlacingMode::Progressive) !=
(g_gpu_settings.display_deinterlacing_mode == DisplayDeinterlacingMode::Progressive) ||
(multisamples > 1 && g_gpu_settings.gpu_per_sample_shading != old_settings.gpu_per_sample_shading) ||
(resolution_scale > 1 && g_gpu_settings.gpu_scaled_dithering != old_settings.gpu_scaled_dithering) ||
(resolution_scale > 1 && (g_gpu_settings.gpu_scaled_dithering != old_settings.gpu_scaled_dithering ||
g_gpu_settings.gpu_scaled_interlacing != old_settings.gpu_scaled_interlacing)) ||
(resolution_scale > 1 && g_gpu_settings.gpu_texture_filter == GPUTextureFilter::Nearest &&
g_gpu_settings.gpu_force_round_texcoords != old_settings.gpu_force_round_texcoords) ||
g_gpu_settings.IsUsingAccurateBlending() != old_settings.IsUsingAccurateBlending() ||
@ -847,6 +848,9 @@ void GPU_HW::PrintSettingsToLog()
"");
INFO_LOG("Dithering: {}", m_true_color ? "Disabled" : "Enabled",
(!m_true_color && g_gpu_settings.gpu_scaled_dithering));
INFO_LOG("Deinterlacing: {}{}",
Settings::GetDisplayDeinterlacingModeDisplayName(g_gpu_settings.display_deinterlacing_mode),
(m_resolution_scale > 1 && g_gpu_settings.gpu_scaled_interlacing) ? " (scaled)" : "");
INFO_LOG("Force round texture coordinates: {}",
(m_resolution_scale > 1 && g_gpu_settings.gpu_force_round_texcoords) ? "Enabled" : "Disabled");
INFO_LOG("Texture Filtering: {}/{}", Settings::GetTextureFilterDisplayName(m_texture_filtering),
@ -1052,6 +1056,7 @@ bool GPU_HW::CompilePipelines(Error* error)
(upscaled && m_texture_filtering == GPUTextureFilter::Nearest && g_gpu_settings.gpu_force_round_texcoords);
const bool true_color = g_gpu_settings.gpu_true_color;
const bool scaled_dithering = (!m_true_color && upscaled && g_gpu_settings.gpu_scaled_dithering);
const bool scaled_interlacing = (upscaled && g_gpu_settings.gpu_scaled_interlacing);
const bool disable_color_perspective = (features.noperspective_interpolation && ShouldDisableColorPerspective());
const bool needs_page_texture = m_use_texture_cache;
const bool force_progressive_scan =
@ -1258,8 +1263,8 @@ bool GPU_HW::CompilePipelines(Error* error)
shader_texmode, sprite ? m_sprite_texture_filtering : m_texture_filtering, upscaled, msaa,
per_sample_shading, uv_limits, !sprite && force_round_texcoords, true_color,
ConvertToBoolUnchecked(dithering), scaled_dithering, disable_color_perspective,
ConvertToBoolUnchecked(interlacing), ConvertToBoolUnchecked(check_mask), m_write_mask_as_depth,
use_rov, needs_rov_depth, rov_depth_test, rov_depth_write);
ConvertToBoolUnchecked(interlacing), scaled_interlacing, ConvertToBoolUnchecked(check_mask),
m_write_mask_as_depth, use_rov, needs_rov_depth, rov_depth_test, rov_depth_write);
if (!(batch_fragment_shaders[depth_test][render_mode][transparency_mode][texture_mode][check_mask]
[dithering][interlacing] = g_gpu_device->CreateShader(

View File

@ -732,8 +732,8 @@ std::string GPU_HW_ShaderGen::GenerateBatchFragmentShader(
GPU_HW::BatchRenderMode render_mode, GPUTransparencyMode transparency, GPU_HW::BatchTextureMode texture_mode,
GPUTextureFilter texture_filtering, bool upscaled, bool msaa, bool per_sample_shading, bool uv_limits,
bool force_round_texcoords, bool true_color, bool dithering, bool scaled_dithering, bool disable_color_perspective,
bool interlacing, bool check_mask, bool write_mask_as_depth, bool use_rov, bool use_rov_depth, bool rov_depth_test,
bool rov_depth_write) const
bool interlacing, bool scaled_interlacing, bool check_mask, bool write_mask_as_depth, bool use_rov,
bool use_rov_depth, bool rov_depth_test, bool rov_depth_write) const
{
DebugAssert(!true_color || !dithering); // Should not be doing dithering+true color.
@ -766,6 +766,7 @@ std::string GPU_HW_ShaderGen::GenerateBatchFragmentShader(
DefineMacro(ss, "DITHERING", dithering);
DefineMacro(ss, "DITHERING_SCALED", dithering && scaled_dithering);
DefineMacro(ss, "INTERLACING", interlacing);
DefineMacro(ss, "INTERLACING_SCALED", interlacing && scaled_interlacing);
DefineMacro(ss, "TRUE_COLOR", true_color);
DefineMacro(ss, "TEXTURE_FILTERING", texture_filtering != GPUTextureFilter::Nearest);
DefineMacro(ss, "UV_LIMITS", uv_limits);
@ -992,8 +993,13 @@ float4 SampleFromVRAM(TEXPAGE_VALUE texpage, float2 coords)
float oalpha;
#if INTERLACING
if ((fragpos.y & 1u) == u_interlaced_displayed_field)
discard;
#if INTERLACING_SCALED || !UPSCALED
if ((fragpos.y & 1u) == u_interlaced_displayed_field)
discard;
#else
if ((uint(v_pos.y * u_rcp_resolution_scale) & 1u) == u_interlaced_displayed_field)
discard;
#endif
#endif
#if TEXTURED

View File

@ -23,8 +23,9 @@ public:
bool upscaled, bool msaa, bool per_sample_shading, bool uv_limits,
bool force_round_texcoords, bool true_color, bool dithering,
bool scaled_dithering, bool disable_color_perspective, bool interlacing,
bool check_mask, bool write_mask_as_depth, bool use_rov, bool use_rov_depth,
bool rov_depth_test, bool rov_depth_write) const;
bool scaled_interlacing, bool check_mask, bool write_mask_as_depth,
bool use_rov, bool use_rov_depth, bool rov_depth_test,
bool rov_depth_write) const;
std::string GenerateWireframeGeometryShader() const;
std::string GenerateWireframeFragmentShader() const;
std::string GenerateVRAMReadFragmentShader(u32 resolution_scale, u32 multisamples) const;

View File

@ -231,6 +231,7 @@ void Settings::Load(const SettingsInterface& si, const SettingsInterface& contro
gpu_use_software_renderer_for_readbacks = si.GetBoolValue("GPU", "UseSoftwareRendererForReadbacks", false);
gpu_true_color = si.GetBoolValue("GPU", "TrueColor", true);
gpu_scaled_dithering = si.GetBoolValue("GPU", "ScaledDithering", true);
gpu_scaled_interlacing = si.GetBoolValue("GPU", "ScaledInterlacing", true);
gpu_force_round_texcoords = si.GetBoolValue("GPU", "ForceRoundTextureCoordinates", false);
gpu_accurate_blending = si.GetBoolValue("GPU", "AccurateBlending", false);
gpu_texture_filter =
@ -588,6 +589,7 @@ void Settings::Save(SettingsInterface& si, bool ignore_base) const
si.SetBoolValue("GPU", "UseSoftwareRendererForReadbacks", gpu_use_software_renderer_for_readbacks);
si.SetBoolValue("GPU", "TrueColor", gpu_true_color);
si.SetBoolValue("GPU", "ScaledDithering", gpu_scaled_dithering);
si.SetBoolValue("GPU", "ScaledInterlacing", gpu_scaled_interlacing);
si.SetBoolValue("GPU", "ForceRoundTextureCoordinates", gpu_force_round_texcoords);
si.SetBoolValue("GPU", "AccurateBlending", gpu_accurate_blending);
si.SetStringValue("GPU", "TextureFilter", GetTextureFilterName(gpu_texture_filter));
@ -991,6 +993,7 @@ void Settings::FixIncompatibleSettings(const SettingsInterface& si, bool display
g_settings.gpu_per_sample_shading = false;
g_settings.gpu_true_color = false;
g_settings.gpu_scaled_dithering = false;
g_settings.gpu_scaled_interlacing = false;
g_settings.gpu_force_round_texcoords = false;
g_settings.gpu_texture_filter = GPUTextureFilter::Nearest;
g_settings.gpu_sprite_texture_filter = GPUTextureFilter::Nearest;

View File

@ -106,6 +106,7 @@ struct GPUSettings
bool gpu_per_sample_shading : 1 = false;
bool gpu_true_color : 1 = true;
bool gpu_scaled_dithering : 1 = true;
bool gpu_scaled_interlacing : 1 = true;
bool gpu_force_round_texcoords : 1 = false;
bool gpu_accurate_blending : 1 = false;
bool gpu_widescreen_hack : 1 = false;

View File

@ -5,4 +5,4 @@
#include "common/types.h"
static constexpr u32 SHADER_CACHE_VERSION = 28;
static constexpr u32 SHADER_CACHE_VERSION = 29;

View File

@ -4473,6 +4473,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
old_settings.gpu_use_software_renderer_for_readbacks ||
g_settings.gpu_true_color != old_settings.gpu_true_color ||
g_settings.gpu_scaled_dithering != old_settings.gpu_scaled_dithering ||
g_settings.gpu_scaled_interlacing != old_settings.gpu_scaled_interlacing ||
g_settings.gpu_force_round_texcoords != old_settings.gpu_force_round_texcoords ||
g_settings.gpu_accurate_blending != old_settings.gpu_accurate_blending ||
g_settings.gpu_texture_filter != old_settings.gpu_texture_filter ||

View File

@ -147,7 +147,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.maxQueuedFrames, "GPU", "MaxQueuedFrames",
Settings::DEFAULT_GPU_MAX_QUEUED_FRAMES);
connect(m_ui.gpuThread, &QCheckBox::checkStateChanged, this, &GraphicsSettingsWidget::onGPUThreadChanged);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.scaledDithering, "GPU", "ScaledDithering", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.scaledDithering, "GPU", "ScaledDithering", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.scaledInterlacing, "GPU", "ScaledInterlacing", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useSoftwareRendererForReadbacks, "GPU",
"UseSoftwareRendererForReadbacks", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.forceRoundedTexcoords, "GPU", "ForceRoundTextureCoordinates",
@ -156,6 +157,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
SettingWidgetBinder::SetAvailability(m_ui.scaledDithering,
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableScaledDithering));
SettingWidgetBinder::SetAvailability(m_ui.scaledInterlacing,
!m_dialog->hasGameTrait(GameDatabase::Trait::DisableScaledInterlacing));
// PGXP Tab
@ -468,6 +471,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
m_ui.scaledDithering, tr("Scaled Dithering"), tr("Checked"),
tr("Scales the dither pattern to the resolution scale of the emulated GPU. This makes the dither pattern much less "
"obvious at higher resolutions. Usually safe to enable."));
dialog->registerWidgetHelp(m_ui.scaledInterlacing, tr("Scaled Interlacing"), tr("Checked"),
tr("Scales line skipping in interlaced rendering to the internal resolution. This makes "
"the combing less obvious at higher resolutions. Usually safe to enable."));
dialog->registerWidgetHelp(
m_ui.useSoftwareRendererForReadbacks, tr("Software Renderer Readbacks"), tr("Unchecked"),
tr("Runs the software renderer in parallel for VRAM readbacks. On some systems, this may result in greater "
@ -853,6 +859,7 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
m_ui.gpuWireframeMode->setEnabled(is_hardware);
m_ui.gpuWireframeModeLabel->setEnabled(is_hardware);
m_ui.scaledDithering->setEnabled(is_hardware && !m_dialog->hasGameTrait(GameDatabase::Trait::DisableScaledDithering));
m_ui.scaledInterlacing->setEnabled(is_hardware && !m_dialog->hasGameTrait(GameDatabase::Trait::DisableScaledInterlacing));
m_ui.useSoftwareRendererForReadbacks->setEnabled(is_hardware);
m_ui.forceRoundedTexcoords->setEnabled(is_hardware);
m_ui.accurateBlending->setEnabled(is_hardware);

View File

@ -354,13 +354,20 @@
</property>
</widget>
</item>
<item row="1" column="0">
<item row="1" column="1">
<widget class="QCheckBox" name="blitSwapChain">
<property name="text">
<string>Use Blit Swap Chain</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="useSoftwareRendererForReadbacks">
<property name="text">
<string>Software Renderer Readbacks</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
@ -421,13 +428,6 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="useSoftwareRendererForReadbacks">
<property name="text">
<string>Software Renderer Readbacks</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="scaledDithering">
<property name="text">
@ -467,6 +467,13 @@
</item>
</layout>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="scaledInterlacing">
<property name="text">
<string>Scaled Interlacing</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>