GPUDevice: Add support for VRR and relaxed vsync

This commit is contained in:
Stenzek
2024-03-03 12:25:37 +10:00
parent d9e496284f
commit a1d7d214cf
27 changed files with 474 additions and 364 deletions

View File

@ -51,8 +51,13 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.renderer, "GPU", "Renderer", &Settings::ParseRendererName,
&Settings::GetRendererName, Settings::DEFAULT_GPU_RENDERER);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vsync, "Display", "VSync", false);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.resolutionScale, "GPU", "ResolutionScale", 1);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.textureFiltering, "GPU", "TextureFilter",
&Settings::ParseTextureFilterName, &Settings::GetTextureFilterName,
Settings::DEFAULT_GPU_TEXTURE_FILTER);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.gpuDownsampleMode, "GPU", "DownsampleMode",
&Settings::ParseDownsampleModeName, &Settings::GetDownsampleModeName,
Settings::DEFAULT_GPU_DOWNSAMPLE_MODE);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayAspectRatio, "Display", "AspectRatio",
&Settings::ParseDisplayAspectRatio, &Settings::GetDisplayAspectRatioName,
Settings::DEFAULT_DISPLAY_ASPECT_RATIO);
@ -67,13 +72,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayScaling, "Display", "Scaling",
&Settings::ParseDisplayScaling, &Settings::GetDisplayScalingName,
Settings::DEFAULT_DISPLAY_SCALING);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.resolutionScale, "GPU", "ResolutionScale", 1);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.textureFiltering, "GPU", "TextureFilter",
&Settings::ParseTextureFilterName, &Settings::GetTextureFilterName,
Settings::DEFAULT_GPU_TEXTURE_FILTER);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.gpuDownsampleMode, "GPU", "DownsampleMode",
&Settings::ParseDownsampleModeName, &Settings::GetDownsampleModeName,
Settings::DEFAULT_GPU_DOWNSAMPLE_MODE);
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displaySyncMode, "Display", "SyncMode",
&Settings::ParseDisplaySyncMode, &Settings::GetDisplaySyncModeName,
Settings::DEFAULT_DISPLAY_SYNC_MODE);
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gpuDownsampleScale, "GPU", "DownsampleScale", 1);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.trueColor, "GPU", "TrueColor", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableInterlacing, "GPU", "DisableInterlacing", true);
@ -243,9 +244,23 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
"renderers. <br>This option is only supported in Direct3D and Vulkan. OpenGL will always use the default "
"device."));
dialog->registerWidgetHelp(
m_ui.vsync, tr("VSync"), tr("Unchecked"),
tr("Enable this option to match DuckStation's refresh rate with your current monitor or screen. "
"VSync is automatically disabled when it is not possible (e.g. running at non-100% speed)."));
m_ui.resolutionScale, tr("Internal Resolution"), "1x",
tr("Setting this beyond 1x will enhance the resolution of rendered 3D polygons and lines. Only applies "
"to the hardware backends. <br>This option is usually safe, with most games looking fine at "
"higher resolutions. Higher resolutions require a more powerful GPU."));
dialog->registerWidgetHelp(
m_ui.gpuDownsampleMode, tr("Down-Sampling"), tr("Disabled"),
tr("Downsamples the rendered image prior to displaying it. Can improve overall image quality in mixed 2D/3D games, "
"but should be disabled for pure 3D games. Only applies to the hardware renderers."));
dialog->registerWidgetHelp(m_ui.gpuDownsampleScale, tr("Down-Sampling Display Scale"), tr("1x"),
tr("Selects the resolution scale that will be applied to the final image. 1x will "
"downsample to the original console resolution."));
dialog->registerWidgetHelp(
m_ui.textureFiltering, tr("Texture Filtering"),
QString::fromUtf8(Settings::GetTextureFilterDisplayName(Settings::DEFAULT_GPU_TEXTURE_FILTER)),
tr("Smooths out the blockiness of magnified textures on 3D object by using filtering. <br>Will have a "
"greater effect on higher resolution scales. Only applies to the hardware renderers. <br>The JINC2 and "
"especially xBR filtering modes are very demanding, and may not be worth the speed penalty."));
dialog->registerWidgetHelp(
m_ui.displayAspectRatio, tr("Aspect Ratio"),
QString::fromUtf8(Settings::GetDisplayAspectRatioDisplayName(Settings::DEFAULT_DISPLAY_ASPECT_RATIO)),
@ -261,27 +276,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
m_ui.displayScaling, tr("Scaling"), tr("Bilinear (Smooth)"),
tr("Determines how the emulated console's output is upscaled or downscaled to your monitor's resolution."));
dialog->registerWidgetHelp(
m_ui.resolutionScale, tr("Internal Resolution"), "1x",
tr("Setting this beyond 1x will enhance the resolution of rendered 3D polygons and lines. Only applies "
"to the hardware backends. <br>This option is usually safe, with most games looking fine at "
"higher resolutions. Higher resolutions require a more powerful GPU."));
dialog->registerWidgetHelp(
m_ui.msaaMode, tr("Multi-Sampling"), tr("Disabled"),
tr("Uses multi-sampled anti-aliasing when rendering 3D polygons. Can improve visuals with a lower performance "
"requirement compared to upscaling, <strong>but often introduces rendering errors.</strong>"));
dialog->registerWidgetHelp(
m_ui.gpuDownsampleMode, tr("Down-Sampling"), tr("Disabled"),
tr("Downsamples the rendered image prior to displaying it. Can improve overall image quality in mixed 2D/3D games, "
"but should be disabled for pure 3D games. Only applies to the hardware renderers."));
dialog->registerWidgetHelp(m_ui.gpuDownsampleScale, tr("Down-Sampling Display Scale"), tr("1x"),
tr("Selects the resolution scale that will be applied to the final image. 1x will "
"downsample to the original console resolution."));
dialog->registerWidgetHelp(
m_ui.textureFiltering, tr("Texture Filtering"),
QString::fromUtf8(Settings::GetTextureFilterDisplayName(Settings::DEFAULT_GPU_TEXTURE_FILTER)),
tr("Smooths out the blockiness of magnified textures on 3D object by using filtering. <br>Will have a "
"greater effect on higher resolution scales. Only applies to the hardware renderers. <br>The JINC2 and "
"especially xBR filtering modes are very demanding, and may not be worth the speed penalty."));
m_ui.displaySyncMode, tr("VSync"), tr("Unchecked"),
tr("Enable this option to match DuckStation's refresh rate with your current monitor or screen. "
"VSync is automatically disabled when it is not possible (e.g. running at non-100% speed)."));
dialog->registerWidgetHelp(
m_ui.trueColor, tr("True Color Rendering"), tr("Checked"),
tr("Forces the precision of colours output to the console's framebuffer to use the full 8 bits of precision per "
@ -354,9 +351,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
QString::fromUtf8(Settings::GetLineDetectModeName(Settings::DEFAULT_GPU_LINE_DETECT_MODE)),
tr("Attempts to detect one pixel high/wide lines that rely on non-upscaled rasterization "
"behavior, filling in gaps introduced by upscaling."));
dialog->registerWidgetHelp(m_ui.gpuWireframeMode, tr("Wireframe Mode"), tr("Disabled"),
tr("Draws a wireframe outline of the triangles rendered by the console's GPU, either as a "
"replacement or an overlay."));
dialog->registerWidgetHelp(
m_ui.msaaMode, tr("Multi-Sampling"), tr("Disabled"),
tr("Uses multi-sampled anti-aliasing when rendering 3D polygons. Can improve visuals with a lower performance "
"requirement compared to upscaling, <strong>but often introduces rendering errors.</strong>"));
dialog->registerWidgetHelp(
m_ui.debanding, tr("True Color Debanding"), tr("Unchecked"),
tr("Applies modern dithering techniques to further smooth out gradients when true color is enabled. "
@ -473,6 +471,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
// Debugging Tab
dialog->registerWidgetHelp(m_ui.gpuWireframeMode, tr("Wireframe Mode"), tr("Disabled"),
tr("Draws a wireframe outline of the triangles rendered by the console's GPU, either as a "
"replacement or an overlay."));
dialog->registerWidgetHelp(
m_ui.useDebugDevice, tr("Use Debug Device"), tr("Unchecked"),
tr("Enable debugging when supported by the host's renderer API. <strong>Only for developer use.</strong>"));
@ -505,6 +507,18 @@ void GraphicsSettingsWidget::setupAdditionalUi()
m_ui.renderer->addItem(QString::fromUtf8(Settings::GetRendererDisplayName(static_cast<GPURenderer>(i))));
}
for (u32 i = 0; i < static_cast<u32>(GPUTextureFilter::Count); i++)
{
m_ui.textureFiltering->addItem(
QString::fromUtf8(Settings::GetTextureFilterDisplayName(static_cast<GPUTextureFilter>(i))));
}
for (u32 i = 0; i < static_cast<u32>(GPUDownsampleMode::Count); i++)
{
m_ui.gpuDownsampleMode->addItem(
QString::fromUtf8(Settings::GetDownsampleModeDisplayName(static_cast<GPUDownsampleMode>(i))));
}
for (u32 i = 0; i < static_cast<u32>(DisplayAspectRatio::Count); i++)
{
m_ui.displayAspectRatio->addItem(
@ -523,26 +537,10 @@ void GraphicsSettingsWidget::setupAdditionalUi()
QString::fromUtf8(Settings::GetDisplayScalingDisplayName(static_cast<DisplayScalingMode>(i))));
}
for (u32 i = 0; i < static_cast<u32>(DisplaySyncMode::Count); i++)
{
if (m_dialog->isPerGameSettings())
m_ui.msaaMode->addItem(tr("Use Global Setting"));
m_ui.msaaMode->addItem(tr("Disabled"), GetMSAAModeValue(1, false));
for (uint i = 2; i <= 32; i *= 2)
m_ui.msaaMode->addItem(tr("%1x MSAA").arg(i), GetMSAAModeValue(i, false));
for (uint i = 2; i <= 32; i *= 2)
m_ui.msaaMode->addItem(tr("%1x SSAA").arg(i), GetMSAAModeValue(i, true));
}
for (u32 i = 0; i < static_cast<u32>(GPUTextureFilter::Count); i++)
{
m_ui.textureFiltering->addItem(
QString::fromUtf8(Settings::GetTextureFilterDisplayName(static_cast<GPUTextureFilter>(i))));
}
for (u32 i = 0; i < static_cast<u32>(GPUDownsampleMode::Count); i++)
{
m_ui.gpuDownsampleMode->addItem(
QString::fromUtf8(Settings::GetDownsampleModeDisplayName(static_cast<GPUDownsampleMode>(i))));
m_ui.displaySyncMode->addItem(
QString::fromUtf8(Settings::GetDisplaySyncModeDisplayName(static_cast<DisplaySyncMode>(i))));
}
// Advanced Tab
@ -559,18 +557,22 @@ void GraphicsSettingsWidget::setupAdditionalUi()
QString::fromUtf8(Settings::GetDisplayAlignmentDisplayName(static_cast<DisplayAlignment>(i))));
}
{
if (m_dialog->isPerGameSettings())
m_ui.msaaMode->addItem(tr("Use Global Setting"));
m_ui.msaaMode->addItem(tr("Disabled"), GetMSAAModeValue(1, false));
for (uint i = 2; i <= 32; i *= 2)
m_ui.msaaMode->addItem(tr("%1x MSAA").arg(i), GetMSAAModeValue(i, false));
for (uint i = 2; i <= 32; i *= 2)
m_ui.msaaMode->addItem(tr("%1x SSAA").arg(i), GetMSAAModeValue(i, true));
}
for (u32 i = 0; i < static_cast<u32>(GPULineDetectMode::Count); i++)
{
m_ui.gpuLineDetectMode->addItem(
QString::fromUtf8(Settings::GetLineDetectModeDisplayName(static_cast<GPULineDetectMode>(i))));
}
for (u32 i = 0; i < static_cast<u32>(GPUWireframeMode::Count); i++)
{
m_ui.gpuWireframeMode->addItem(
QString::fromUtf8(Settings::GetGPUWireframeModeDisplayName(static_cast<GPUWireframeMode>(i))));
}
// Capture Tab
for (u32 i = 0; i < static_cast<u32>(DisplayScreenshotMode::Count); i++)
@ -584,6 +586,14 @@ void GraphicsSettingsWidget::setupAdditionalUi()
m_ui.screenshotFormat->addItem(
QString::fromUtf8(Settings::GetDisplayScreenshotFormatDisplayName(static_cast<DisplayScreenshotFormat>(i))));
}
// Debugging Tab
for (u32 i = 0; i < static_cast<u32>(GPUWireframeMode::Count); i++)
{
m_ui.gpuWireframeMode->addItem(
QString::fromUtf8(Settings::GetGPUWireframeModeDisplayName(static_cast<GPUWireframeMode>(i))));
}
}
void GraphicsSettingsWidget::removePlatformSpecificUi()

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>584</width>
<height>446</height>
<height>434</height>
</rect>
</property>
<property name="windowTitle">
@ -50,18 +50,7 @@
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="1,0">
<item>
<widget class="QComboBox" name="adapter"/>
</item>
<item>
<widget class="QCheckBox" name="vsync">
<property name="text">
<string>VSync</string>
</property>
</widget>
</item>
</layout>
<widget class="QComboBox" name="adapter"/>
</item>
</layout>
</widget>
@ -98,74 +87,13 @@
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Aspect Ratio:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0,0,0">
<item>
<widget class="QComboBox" name="displayAspectRatio"/>
</item>
<item>
<widget class="QSpinBox" name="customAspectRatioNumerator">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="customAspectRatioSeparator">
<property name="text">
<string>:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="customAspectRatioDenominator">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Crop:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="displayCropMode"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Scaling:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="displayScaling"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="resolutionScaleLabel">
<property name="text">
<string>Internal Resolution:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="0" column="1">
<widget class="QComboBox" name="resolutionScale">
<item>
<property name="text">
@ -254,27 +182,115 @@
</item>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="msaaModeLabel">
<item row="1" column="0">
<widget class="QLabel" name="gpuDownsampleLabel">
<property name="text">
<string>Multi-Sampling:</string>
<string>Down-Sampling:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="msaaMode"/>
<item row="1" column="1">
<layout class="QHBoxLayout" name="gpuDownsampleLayout" stretch="1,0">
<item>
<widget class="QComboBox" name="gpuDownsampleMode"/>
</item>
<item>
<widget class="QSpinBox" name="gpuDownsampleScale">
<property name="suffix">
<string>x</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>16</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0">
<item row="2" column="0">
<widget class="QLabel" name="textureFilteringLabel">
<property name="text">
<string>Texture Filtering:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<item row="2" column="1">
<widget class="QComboBox" name="textureFiltering"/>
</item>
<item row="8" column="0" colspan="2">
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Aspect Ratio:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0,0,0">
<item>
<widget class="QComboBox" name="displayAspectRatio"/>
</item>
<item>
<widget class="QSpinBox" name="customAspectRatioNumerator">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="customAspectRatioSeparator">
<property name="text">
<string>:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="customAspectRatioDenominator">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>9999</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Crop:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="displayCropMode"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Scaling:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="displayScaling"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>VSync:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="displaySyncMode"/>
</item>
<item row="7" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="0">
<widget class="QCheckBox" name="pgxpEnable">
@ -283,6 +299,13 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="trueColor">
<property name="text">
<string>True Color Rendering</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="pgxpDepthBuffer">
<property name="text">
@ -304,20 +327,6 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="trueColor">
<property name="text">
<string>True Color Rendering</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="forceNTSCTimings">
<property name="text">
<string>Force NTSC Timings</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="disableInterlacing">
<property name="text">
@ -332,30 +341,10 @@
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QLabel" name="gpuDownsampleLabel">
<property name="text">
<string>Down-Sampling:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="gpuDownsampleLayout" stretch="1,0">
<item>
<widget class="QComboBox" name="gpuDownsampleMode"/>
</item>
<item>
<widget class="QSpinBox" name="gpuDownsampleScale">
<property name="suffix">
<string>x</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>16</number>
<item row="3" column="1">
<widget class="QCheckBox" name="forceNTSCTimings">
<property name="text">
<string>Force NTSC Timings</string>
</property>
</widget>
</item>
@ -477,6 +466,16 @@
<string>Rendering Options</string>
</property>
<layout class="QFormLayout" name="formLayout_6">
<item row="1" column="0">
<widget class="QLabel" name="gpuLineDetectModeLabel">
<property name="text">
<string>Line Detection:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="gpuLineDetectMode"/>
</item>
<item row="2" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="1">
@ -503,24 +502,14 @@
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="gpuLineDetectModeLabel">
<widget class="QLabel" name="msaaModeLabel">
<property name="text">
<string>Line Detection:</string>
<string>Multi-Sampling:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="gpuLineDetectMode"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="gpuWireframeModeLabel">
<property name="text">
<string>Wireframe Mode:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="gpuWireframeMode"/>
<widget class="QComboBox" name="msaaMode"/>
</item>
</layout>
</widget>
@ -1035,6 +1024,25 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_11">
<property name="title">
<string>Rendering Options</string>
</property>
<layout class="QFormLayout" name="formLayout_11">
<item row="0" column="0">
<widget class="QLabel" name="gpuWireframeModeLabel">
<property name="text">
<string>Wireframe Mode:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="gpuWireframeMode"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_9">
<property name="title">

View File

@ -1529,7 +1529,7 @@ void EmuThread::run()
if (g_gpu_device)
{
System::PresentDisplay(false);
if (!g_gpu_device->IsVsyncEnabled())
if (!g_gpu_device->IsVSyncActive())
g_gpu_device->ThrottlePresentation();
}
}