GPUDevice: Add support for VRR and relaxed vsync
This commit is contained in:
parent
d9e496284f
commit
a1d7d214cf
|
@ -3879,10 +3879,11 @@ void FullscreenUI::DrawDisplaySettingsPage()
|
|||
"GPU", "UseSoftwareRendererForReadbacks", false);
|
||||
}
|
||||
|
||||
DrawToggleSetting(
|
||||
bsi, FSUI_CSTR("Enable VSync"),
|
||||
DrawEnumSetting(
|
||||
bsi, FSUI_CSTR("VSync"),
|
||||
FSUI_CSTR("Synchronizes presentation of the console's frames to the host. Enable for smoother animations."),
|
||||
"Display", "VSync", Settings::DEFAULT_VSYNC_VALUE);
|
||||
"Display", "SyncMode", Settings::DEFAULT_DISPLAY_SYNC_MODE, &Settings::ParseDisplaySyncMode,
|
||||
&Settings::GetDisplaySyncModeName, &Settings::GetDisplaySyncModeDisplayName, DisplaySyncMode::Count);
|
||||
|
||||
DrawToggleSetting(
|
||||
bsi, FSUI_CSTR("Sync To Host Refresh Rate"),
|
||||
|
|
|
@ -265,15 +265,13 @@ bool Host::CreateGPUDevice(RenderAPI api)
|
|||
if (g_settings.gpu_disable_texture_copy_to_self)
|
||||
disabled_features |= GPUDevice::FEATURE_MASK_TEXTURE_COPY_TO_SELF;
|
||||
|
||||
// TODO: FSUI should always use vsync..
|
||||
Error error;
|
||||
const bool vsync = System::IsValid() ? System::ShouldUseVSync() : g_settings.video_sync_enabled;
|
||||
if (!g_gpu_device || !g_gpu_device->Create(g_settings.gpu_adapter,
|
||||
g_settings.gpu_disable_shader_cache ? std::string_view() :
|
||||
std::string_view(EmuFolders::Cache),
|
||||
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, vsync,
|
||||
g_settings.gpu_threaded_presentation, exclusive_fullscreen_control,
|
||||
static_cast<GPUDevice::FeatureMask>(disabled_features), &error))
|
||||
if (!g_gpu_device || !g_gpu_device->Create(
|
||||
g_settings.gpu_adapter,
|
||||
g_settings.gpu_disable_shader_cache ? std::string_view() : std::string_view(EmuFolders::Cache),
|
||||
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, System::GetEffectiveDisplaySyncMode(),
|
||||
g_settings.gpu_threaded_presentation, exclusive_fullscreen_control,
|
||||
static_cast<GPUDevice::FeatureMask>(disabled_features), &error))
|
||||
{
|
||||
Log_ErrorPrintf("Failed to create GPU device.");
|
||||
if (g_gpu_device)
|
||||
|
|
|
@ -243,6 +243,10 @@ void Settings::Load(SettingsInterface& si)
|
|||
display_scaling =
|
||||
ParseDisplayScaling(si.GetStringValue("Display", "Scaling", GetDisplayScalingName(DEFAULT_DISPLAY_SCALING)).c_str())
|
||||
.value_or(DEFAULT_DISPLAY_SCALING);
|
||||
display_sync_mode =
|
||||
ParseDisplaySyncMode(
|
||||
si.GetStringValue("Display", "SyncMode", GetDisplaySyncModeName(DEFAULT_DISPLAY_SYNC_MODE)).c_str())
|
||||
.value_or(DEFAULT_DISPLAY_SYNC_MODE);
|
||||
display_exclusive_fullscreen_control =
|
||||
ParseDisplayExclusiveFullscreenControl(
|
||||
si.GetStringValue("Display", "ExclusiveFullscreenControl",
|
||||
|
@ -279,7 +283,6 @@ void Settings::Load(SettingsInterface& si)
|
|||
display_show_enhancements = si.GetBoolValue("Display", "ShowEnhancements", false);
|
||||
display_all_frames = si.GetBoolValue("Display", "DisplayAllFrames", false);
|
||||
display_stretch_vertically = si.GetBoolValue("Display", "StretchVertically", false);
|
||||
video_sync_enabled = si.GetBoolValue("Display", "VSync", DEFAULT_VSYNC_VALUE);
|
||||
display_max_fps = si.GetFloatValue("Display", "MaxFPS", DEFAULT_DISPLAY_MAX_FPS);
|
||||
display_osd_scale = si.GetFloatValue("Display", "OSDScale", DEFAULT_OSD_SCALE);
|
||||
|
||||
|
@ -504,6 +507,7 @@ void Settings::Save(SettingsInterface& si) const
|
|||
si.SetStringValue("Display", "AspectRatio", GetDisplayAspectRatioName(display_aspect_ratio));
|
||||
si.SetStringValue("Display", "Alignment", GetDisplayAlignmentName(display_alignment));
|
||||
si.SetStringValue("Display", "Scaling", GetDisplayScalingName(display_scaling));
|
||||
si.SetStringValue("Display", "SyncMode", GetDisplaySyncModeName(display_sync_mode));
|
||||
si.SetStringValue("Display", "ExclusiveFullscreenControl",
|
||||
GetDisplayExclusiveFullscreenControlName(display_exclusive_fullscreen_control));
|
||||
si.SetStringValue("Display", "ScreenshotMode", GetDisplayScreenshotModeName(display_screenshot_mode));
|
||||
|
@ -524,7 +528,6 @@ void Settings::Save(SettingsInterface& si) const
|
|||
si.SetBoolValue("Display", "ShowEnhancements", display_show_enhancements);
|
||||
si.SetBoolValue("Display", "DisplayAllFrames", display_all_frames);
|
||||
si.SetBoolValue("Display", "StretchVertically", display_stretch_vertically);
|
||||
si.SetBoolValue("Display", "VSync", video_sync_enabled);
|
||||
si.SetFloatValue("Display", "MaxFPS", display_max_fps);
|
||||
si.SetFloatValue("Display", "OSDScale", display_osd_scale);
|
||||
|
||||
|
@ -1357,6 +1360,43 @@ const char* Settings::GetDisplayScalingDisplayName(DisplayScalingMode mode)
|
|||
return Host::TranslateToCString("DisplayScalingMode", s_display_scaling_display_names[static_cast<int>(mode)]);
|
||||
}
|
||||
|
||||
static constexpr const std::array s_display_sync_mode_names = {
|
||||
"Disabled",
|
||||
"VSync",
|
||||
"VSyncRelaxed",
|
||||
"VRR",
|
||||
};
|
||||
static constexpr const std::array s_display_sync_mode_display_names = {
|
||||
TRANSLATE_NOOP("Settings", "Disabled"),
|
||||
TRANSLATE_NOOP("Settings", "VSync"),
|
||||
TRANSLATE_NOOP("Settings", "Relaxed VSync"),
|
||||
TRANSLATE_NOOP("Settings", "VRR/FreeSync/GSync"),
|
||||
};
|
||||
|
||||
std::optional<DisplaySyncMode> Settings::ParseDisplaySyncMode(const char* str)
|
||||
{
|
||||
int index = 0;
|
||||
for (const char* name : s_display_sync_mode_names)
|
||||
{
|
||||
if (StringUtil::Strcasecmp(name, str) == 0)
|
||||
return static_cast<DisplaySyncMode>(index);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const char* Settings::GetDisplaySyncModeName(DisplaySyncMode mode)
|
||||
{
|
||||
return s_display_sync_mode_names[static_cast<size_t>(mode)];
|
||||
}
|
||||
|
||||
const char* Settings::GetDisplaySyncModeDisplayName(DisplaySyncMode mode)
|
||||
{
|
||||
return Host::TranslateToCString("Settings", s_display_sync_mode_display_names[static_cast<size_t>(mode)]);
|
||||
}
|
||||
|
||||
static constexpr const std::array s_display_exclusive_fullscreen_mode_names = {
|
||||
"Automatic",
|
||||
"Disallowed",
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "types.h"
|
||||
|
||||
#include "util/audio_stream.h"
|
||||
#include "util/gpu_types.h"
|
||||
|
||||
#include "common/log.h"
|
||||
#include "common/settings_interface.h"
|
||||
|
@ -18,8 +19,6 @@
|
|||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
enum class RenderAPI : u32;
|
||||
|
||||
struct SettingInfo
|
||||
{
|
||||
enum class Type
|
||||
|
@ -134,6 +133,7 @@ struct Settings
|
|||
DisplayAspectRatio display_aspect_ratio = DEFAULT_DISPLAY_ASPECT_RATIO;
|
||||
DisplayAlignment display_alignment = DEFAULT_DISPLAY_ALIGNMENT;
|
||||
DisplayScalingMode display_scaling = DEFAULT_DISPLAY_SCALING;
|
||||
DisplaySyncMode display_sync_mode = DEFAULT_DISPLAY_SYNC_MODE;
|
||||
DisplayExclusiveFullscreenControl display_exclusive_fullscreen_control = DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL;
|
||||
DisplayScreenshotMode display_screenshot_mode = DEFAULT_DISPLAY_SCREENSHOT_MODE;
|
||||
DisplayScreenshotFormat display_screenshot_format = DEFAULT_DISPLAY_SCREENSHOT_FORMAT;
|
||||
|
@ -159,7 +159,6 @@ struct Settings
|
|||
bool display_show_enhancements : 1 = false;
|
||||
bool display_all_frames : 1 = false;
|
||||
bool display_stretch_vertically : 1 = false;
|
||||
bool video_sync_enabled = DEFAULT_VSYNC_VALUE;
|
||||
float display_osd_scale = 100.0f;
|
||||
float display_max_fps = DEFAULT_DISPLAY_MAX_FPS;
|
||||
float gpu_pgxp_tolerance = -1.0f;
|
||||
|
@ -411,6 +410,10 @@ struct Settings
|
|||
static const char* GetDisplayScalingName(DisplayScalingMode mode);
|
||||
static const char* GetDisplayScalingDisplayName(DisplayScalingMode mode);
|
||||
|
||||
static std::optional<DisplaySyncMode> ParseDisplaySyncMode(const char* str);
|
||||
static const char* GetDisplaySyncModeName(DisplaySyncMode mode);
|
||||
static const char* GetDisplaySyncModeDisplayName(DisplaySyncMode mode);
|
||||
|
||||
static std::optional<DisplayExclusiveFullscreenControl> ParseDisplayExclusiveFullscreenControl(const char* str);
|
||||
static const char* GetDisplayExclusiveFullscreenControlName(DisplayExclusiveFullscreenControl mode);
|
||||
static const char* GetDisplayExclusiveFullscreenControlDisplayName(DisplayExclusiveFullscreenControl mode);
|
||||
|
@ -484,6 +487,7 @@ struct Settings
|
|||
static constexpr DisplayAspectRatio DEFAULT_DISPLAY_ASPECT_RATIO = DisplayAspectRatio::Auto;
|
||||
static constexpr DisplayAlignment DEFAULT_DISPLAY_ALIGNMENT = DisplayAlignment::Center;
|
||||
static constexpr DisplayScalingMode DEFAULT_DISPLAY_SCALING = DisplayScalingMode::BilinearSmooth;
|
||||
static constexpr DisplaySyncMode DEFAULT_DISPLAY_SYNC_MODE = DisplaySyncMode::Disabled;
|
||||
static constexpr DisplayExclusiveFullscreenControl DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL =
|
||||
DisplayExclusiveFullscreenControl::Automatic;
|
||||
static constexpr DisplayScreenshotMode DEFAULT_DISPLAY_SCREENSHOT_MODE = DisplayScreenshotMode::ScreenResolution;
|
||||
|
@ -525,13 +529,11 @@ struct Settings
|
|||
#ifndef __ANDROID__
|
||||
static constexpr bool DEFAULT_SAVE_STATE_COMPRESSION = true;
|
||||
static constexpr bool DEFAULT_SAVE_STATE_BACKUPS = true;
|
||||
static constexpr bool DEFAULT_VSYNC_VALUE = false;
|
||||
static constexpr bool DEFAULT_FAST_BOOT_VALUE = false;
|
||||
static constexpr float DEFAULT_DISPLAY_MAX_FPS = 0.0f;
|
||||
#else
|
||||
static constexpr bool DEFAULT_SAVE_STATE_COMPRESSION = true;
|
||||
static constexpr bool DEFAULT_SAVE_STATE_BACKUPS = false;
|
||||
static constexpr bool DEFAULT_VSYNC_VALUE = false;
|
||||
static constexpr bool DEFAULT_FAST_BOOT_VALUE = true;
|
||||
static constexpr float DEFAULT_DISPLAY_MAX_FPS = 60.0f;
|
||||
#endif
|
||||
|
|
|
@ -1849,6 +1849,12 @@ void System::FrameDone()
|
|||
SaveRunaheadState();
|
||||
}
|
||||
|
||||
// TODO: Kick cmdbuffer early
|
||||
const DisplaySyncMode sync_mode = g_gpu_device->GetSyncMode();
|
||||
const bool throttle_after_present = (sync_mode == DisplaySyncMode::Disabled);
|
||||
if (!throttle_after_present && s_throttler_enabled && !IsExecutionInterrupted())
|
||||
Throttle();
|
||||
|
||||
const Common::Timer::Value current_time = Common::Timer::GetCurrentValue();
|
||||
if (current_time < s_next_frame_time || s_display_all_frames || s_last_frame_skipped)
|
||||
{
|
||||
|
@ -1860,7 +1866,7 @@ void System::FrameDone()
|
|||
s_last_frame_skipped = true;
|
||||
}
|
||||
|
||||
if (s_throttler_enabled && !IsExecutionInterrupted())
|
||||
if (throttle_after_present && s_throttler_enabled && !IsExecutionInterrupted())
|
||||
Throttle();
|
||||
|
||||
// Input poll already done above
|
||||
|
@ -2638,10 +2644,14 @@ void System::UpdateSpeedLimiterState()
|
|||
}
|
||||
|
||||
// When syncing to host and using vsync, we don't need to sleep.
|
||||
if (s_syncing_to_host && ShouldUseVSync() && s_display_all_frames)
|
||||
if (s_syncing_to_host && s_display_all_frames)
|
||||
{
|
||||
Log_InfoPrintf("Using host vsync for throttling.");
|
||||
s_throttler_enabled = false;
|
||||
const DisplaySyncMode effective_sync_mode = GetEffectiveDisplaySyncMode();
|
||||
if (effective_sync_mode == DisplaySyncMode::VSync || effective_sync_mode == DisplaySyncMode::VSyncRelaxed)
|
||||
{
|
||||
Log_InfoPrintf("Using host vsync for throttling.");
|
||||
s_throttler_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
Log_VerbosePrintf("Target speed: %f%%", s_target_speed * 100.0f);
|
||||
|
@ -2674,21 +2684,25 @@ void System::UpdateSpeedLimiterState()
|
|||
|
||||
void System::UpdateDisplaySync()
|
||||
{
|
||||
const bool video_sync_enabled = ShouldUseVSync();
|
||||
const bool syncing_to_host_vsync = (s_syncing_to_host && video_sync_enabled && s_display_all_frames);
|
||||
const DisplaySyncMode display_sync_mode = GetEffectiveDisplaySyncMode();
|
||||
const bool syncing_to_host_vsync =
|
||||
(s_syncing_to_host &&
|
||||
(display_sync_mode == DisplaySyncMode::VSync || display_sync_mode == DisplaySyncMode::VSyncRelaxed) &&
|
||||
s_display_all_frames);
|
||||
const float max_display_fps = (s_throttler_enabled || s_syncing_to_host) ? 0.0f : g_settings.display_max_fps;
|
||||
Log_VerbosePrintf("Using vsync: %s%s", video_sync_enabled ? "YES" : "NO",
|
||||
Log_VerbosePrintf("Display sync: %s%s", Settings::GetDisplaySyncModeDisplayName(display_sync_mode),
|
||||
syncing_to_host_vsync ? " (for throttling)" : "");
|
||||
Log_VerbosePrintf("Max display fps: %f (%s)", max_display_fps,
|
||||
s_display_all_frames ? "displaying all frames" : "skipping displaying frames when needed");
|
||||
|
||||
g_gpu_device->SetDisplayMaxFPS(max_display_fps);
|
||||
g_gpu_device->SetVSync(video_sync_enabled);
|
||||
g_gpu_device->SetSyncMode(display_sync_mode);
|
||||
}
|
||||
|
||||
bool System::ShouldUseVSync()
|
||||
DisplaySyncMode System::GetEffectiveDisplaySyncMode()
|
||||
{
|
||||
return g_settings.video_sync_enabled && !IsRunningAtNonStandardSpeed();
|
||||
// Disable vsync if running outside 100%.
|
||||
return (IsValid() && IsRunningAtNonStandardSpeed()) ? DisplaySyncMode::Disabled : g_settings.display_sync_mode;
|
||||
}
|
||||
|
||||
bool System::IsFastForwardEnabled()
|
||||
|
@ -3737,7 +3751,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
|
|||
DMA::SetHaltTicks(g_settings.dma_halt_ticks);
|
||||
|
||||
if (g_settings.audio_backend != old_settings.audio_backend ||
|
||||
g_settings.video_sync_enabled != old_settings.video_sync_enabled ||
|
||||
g_settings.display_sync_mode != old_settings.display_sync_mode ||
|
||||
g_settings.increase_timer_resolution != old_settings.increase_timer_resolution ||
|
||||
g_settings.emulation_speed != old_settings.emulation_speed ||
|
||||
g_settings.fast_forward_speed != old_settings.fast_forward_speed ||
|
||||
|
|
|
@ -455,7 +455,7 @@ void ToggleWidescreen();
|
|||
bool IsRunningAtNonStandardSpeed();
|
||||
|
||||
/// Returns true if vsync should be used.
|
||||
bool ShouldUseVSync();
|
||||
DisplaySyncMode GetEffectiveDisplaySyncMode();
|
||||
|
||||
/// Quick switch between software and hardware rendering.
|
||||
void ToggleSoftwareRendering();
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ add_library(util
|
|||
gpu_shader_cache.h
|
||||
gpu_texture.cpp
|
||||
gpu_texture.h
|
||||
gpu_types.h
|
||||
host.cpp
|
||||
host.h
|
||||
http_downloader.cpp
|
||||
|
|
|
@ -233,7 +233,8 @@ bool D3D11Device::CreateSwapChain()
|
|||
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
swap_chain_desc.SwapEffect = m_using_flip_model_swap_chain ? DXGI_SWAP_EFFECT_FLIP_DISCARD : DXGI_SWAP_EFFECT_DISCARD;
|
||||
|
||||
m_using_allow_tearing = (m_allow_tearing_supported && m_using_flip_model_swap_chain && !m_is_exclusive_fullscreen);
|
||||
m_using_allow_tearing =
|
||||
(m_allow_tearing_supported && m_using_flip_model_swap_chain && !m_is_exclusive_fullscreen);
|
||||
if (m_using_allow_tearing)
|
||||
swap_chain_desc.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
||||
|
||||
|
@ -600,11 +601,6 @@ bool D3D11Device::GetHostRefreshRate(float* refresh_rate)
|
|||
return GPUDevice::GetHostRefreshRate(refresh_rate);
|
||||
}
|
||||
|
||||
void D3D11Device::SetVSync(bool enabled)
|
||||
{
|
||||
m_vsync_enabled = enabled;
|
||||
}
|
||||
|
||||
bool D3D11Device::BeginPresent(bool skip_present)
|
||||
{
|
||||
if (skip_present)
|
||||
|
@ -633,7 +629,7 @@ bool D3D11Device::BeginPresent(bool skip_present)
|
|||
// This blows our our GPU usage number considerably, so read the timestamp before the final blit
|
||||
// in this configuration. It does reduce accuracy a little, but better than seeing 100% all of
|
||||
// the time, when it's more like a couple of percent.
|
||||
if (m_vsync_enabled && m_gpu_timing_enabled)
|
||||
if ((m_sync_mode == DisplaySyncMode::VSync || m_sync_mode == DisplaySyncMode::VSyncRelaxed) && m_gpu_timing_enabled)
|
||||
PopTimestampQuery();
|
||||
|
||||
static constexpr float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
|
@ -650,13 +646,16 @@ void D3D11Device::EndPresent()
|
|||
{
|
||||
DebugAssert(m_num_current_render_targets == 0 && !m_current_depth_target);
|
||||
|
||||
if (!m_vsync_enabled && m_gpu_timing_enabled)
|
||||
if (m_sync_mode != DisplaySyncMode::VSync && m_sync_mode != DisplaySyncMode::VSyncRelaxed && m_gpu_timing_enabled)
|
||||
PopTimestampQuery();
|
||||
|
||||
if (!m_vsync_enabled && m_using_allow_tearing)
|
||||
// DirectX has no concept of tear-or-sync. I guess if we measured times ourselves, we could implement it.
|
||||
if (m_sync_mode == DisplaySyncMode::VSync || m_sync_mode == DisplaySyncMode::VSyncRelaxed)
|
||||
m_swap_chain->Present(BoolToUInt32(1), 0);
|
||||
else if (m_using_allow_tearing) // Disabled or VRR, VRR requires the allow tearing flag :/
|
||||
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||
else
|
||||
m_swap_chain->Present(BoolToUInt32(m_vsync_enabled), 0);
|
||||
m_swap_chain->Present(0, 0);
|
||||
|
||||
if (m_gpu_timing_enabled)
|
||||
KickTimestampQuery();
|
||||
|
|
|
@ -98,8 +98,6 @@ public:
|
|||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
void SetVSync(bool enabled) override;
|
||||
|
||||
bool BeginPresent(bool skip_present) override;
|
||||
void EndPresent() override;
|
||||
|
||||
|
|
|
@ -1060,11 +1060,6 @@ std::string D3D12Device::GetDriverInfo() const
|
|||
return ret;
|
||||
}
|
||||
|
||||
void D3D12Device::SetVSync(bool enabled)
|
||||
{
|
||||
m_vsync_enabled = enabled;
|
||||
}
|
||||
|
||||
bool D3D12Device::BeginPresent(bool frame_skip)
|
||||
{
|
||||
if (InRenderPass())
|
||||
|
@ -1112,10 +1107,13 @@ void D3D12Device::EndPresent()
|
|||
|
||||
SubmitCommandList(false);
|
||||
|
||||
if (!m_vsync_enabled && m_using_allow_tearing)
|
||||
// DirectX has no concept of tear-or-sync. I guess if we measured times ourselves, we could implement it.
|
||||
if (m_sync_mode == DisplaySyncMode::VSync || m_sync_mode == DisplaySyncMode::VSyncRelaxed)
|
||||
m_swap_chain->Present(BoolToUInt32(1), 0);
|
||||
else if (m_using_allow_tearing) // Disabled or VRR, VRR requires the allow tearing flag :/
|
||||
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||
else
|
||||
m_swap_chain->Present(static_cast<UINT>(m_vsync_enabled), 0);
|
||||
m_swap_chain->Present(0, 0);
|
||||
|
||||
TrimTexturePool();
|
||||
}
|
||||
|
|
|
@ -119,8 +119,6 @@ public:
|
|||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
void SetVSync(bool enabled) override;
|
||||
|
||||
bool BeginPresent(bool skip_present) override;
|
||||
void EndPresent() override;
|
||||
|
||||
|
|
|
@ -271,10 +271,11 @@ bool GPUDevice::IsSameRenderAPI(RenderAPI lhs, RenderAPI rhs)
|
|||
}
|
||||
|
||||
bool GPUDevice::Create(const std::string_view& adapter, const std::string_view& shader_cache_path,
|
||||
u32 shader_cache_version, bool debug_device, bool vsync, bool threaded_presentation,
|
||||
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features, Error* error)
|
||||
u32 shader_cache_version, bool debug_device, DisplaySyncMode sync_mode,
|
||||
bool threaded_presentation, std::optional<bool> exclusive_fullscreen_control,
|
||||
FeatureMask disabled_features, Error* error)
|
||||
{
|
||||
m_vsync_enabled = vsync;
|
||||
m_sync_mode = sync_mode;
|
||||
m_debug_device = debug_device;
|
||||
|
||||
if (!AcquireWindow(true))
|
||||
|
@ -584,6 +585,11 @@ void GPUDevice::RenderImGui()
|
|||
}
|
||||
}
|
||||
|
||||
void GPUDevice::SetSyncMode(DisplaySyncMode mode)
|
||||
{
|
||||
m_sync_mode = mode;
|
||||
}
|
||||
|
||||
void GPUDevice::UploadVertexBuffer(const void* vertices, u32 vertex_size, u32 vertex_count, u32* base_vertex)
|
||||
{
|
||||
void* map;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "gpu_shader_cache.h"
|
||||
#include "gpu_texture.h"
|
||||
#include "gpu_types.h"
|
||||
#include "window_info.h"
|
||||
|
||||
#include "common/bitfield.h"
|
||||
|
@ -25,17 +26,6 @@
|
|||
|
||||
class Error;
|
||||
|
||||
enum class RenderAPI : u32
|
||||
{
|
||||
None,
|
||||
D3D11,
|
||||
D3D12,
|
||||
Vulkan,
|
||||
OpenGL,
|
||||
OpenGLES,
|
||||
Metal
|
||||
};
|
||||
|
||||
class GPUSampler
|
||||
{
|
||||
public:
|
||||
|
@ -551,7 +541,7 @@ public:
|
|||
virtual RenderAPI GetRenderAPI() const = 0;
|
||||
|
||||
bool Create(const std::string_view& adapter, const std::string_view& shader_cache_path, u32 shader_cache_version,
|
||||
bool debug_device, bool vsync, bool threaded_presentation,
|
||||
bool debug_device, DisplaySyncMode sync_mode, bool threaded_presentation,
|
||||
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features, Error* error);
|
||||
void Destroy();
|
||||
|
||||
|
@ -646,8 +636,12 @@ public:
|
|||
/// Renders ImGui screen elements. Call before EndPresent().
|
||||
void RenderImGui();
|
||||
|
||||
ALWAYS_INLINE bool IsVsyncEnabled() const { return m_vsync_enabled; }
|
||||
virtual void SetVSync(bool enabled) = 0;
|
||||
ALWAYS_INLINE DisplaySyncMode GetSyncMode() const { return m_sync_mode; }
|
||||
ALWAYS_INLINE bool IsVSyncActive() const
|
||||
{
|
||||
return (m_sync_mode == DisplaySyncMode::VSync || m_sync_mode == DisplaySyncMode::VSyncRelaxed);
|
||||
}
|
||||
virtual void SetSyncMode(DisplaySyncMode mode);
|
||||
|
||||
ALWAYS_INLINE bool IsDebugDevice() const { return m_debug_device; }
|
||||
ALWAYS_INLINE size_t GetVRAMUsage() const { return s_total_vram_usage; }
|
||||
|
@ -760,8 +754,8 @@ private:
|
|||
protected:
|
||||
static Statistics s_stats;
|
||||
|
||||
DisplaySyncMode m_sync_mode = DisplaySyncMode::Disabled;
|
||||
bool m_gpu_timing_enabled = false;
|
||||
bool m_vsync_enabled = false;
|
||||
bool m_debug_device = false;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
|
||||
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
|
||||
|
||||
#pragma once
|
||||
|
||||
enum class RenderAPI : u32
|
||||
{
|
||||
None,
|
||||
D3D11,
|
||||
D3D12,
|
||||
Vulkan,
|
||||
OpenGL,
|
||||
OpenGLES,
|
||||
Metal
|
||||
};
|
||||
|
||||
enum class DisplaySyncMode : u8
|
||||
{
|
||||
Disabled,
|
||||
VSync,
|
||||
VSyncRelaxed,
|
||||
VRR,
|
||||
Count
|
||||
};
|
|
@ -263,7 +263,7 @@ public:
|
|||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
void SetVSync(bool enabled) override;
|
||||
void SetSyncMode(DisplaySyncMode mode) override;
|
||||
|
||||
bool BeginPresent(bool skip_present) override;
|
||||
void EndPresent() override;
|
||||
|
|
|
@ -124,12 +124,15 @@ bool MetalDevice::GetHostRefreshRate(float* refresh_rate)
|
|||
return GPUDevice::GetHostRefreshRate(refresh_rate);
|
||||
}
|
||||
|
||||
void MetalDevice::SetVSync(bool enabled)
|
||||
void MetalDevice::SetSyncMode(DisplaySyncMode mode)
|
||||
{
|
||||
m_vsync_enabled = enabled;
|
||||
m_sync_mode = mode;
|
||||
|
||||
if (m_layer != nil)
|
||||
{
|
||||
const bool enabled = (mode == DisplaySyncMode::VSync || mode == DisplaySyncMode::VSyncRelaxed);
|
||||
[m_layer setDisplaySyncEnabled:enabled];
|
||||
}
|
||||
}
|
||||
|
||||
bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
|
||||
|
@ -382,7 +385,8 @@ bool MetalDevice::CreateLayer()
|
|||
}
|
||||
});
|
||||
|
||||
[m_layer setDisplaySyncEnabled:m_vsync_enabled];
|
||||
const bool sync_enabled = (m_sync_mode == DisplaySyncMode::VSync || m_sync_mode == DisplaySyncMode::VSyncRelaxed);
|
||||
[m_layer setDisplaySyncEnabled:sync_enabled];
|
||||
|
||||
DebugAssert(m_layer_pass_desc == nil);
|
||||
m_layer_pass_desc = [[MTLRenderPassDescriptor renderPassDescriptor] retain];
|
||||
|
|
|
@ -236,12 +236,12 @@ void OpenGLDevice::InsertDebugMessage(const char* msg)
|
|||
#endif
|
||||
}
|
||||
|
||||
void OpenGLDevice::SetVSync(bool enabled)
|
||||
void OpenGLDevice::SetSyncMode(DisplaySyncMode mode)
|
||||
{
|
||||
if (m_vsync_enabled == enabled)
|
||||
if (m_sync_mode == mode)
|
||||
return;
|
||||
|
||||
m_vsync_enabled = enabled;
|
||||
m_sync_mode = mode;
|
||||
SetSwapInterval();
|
||||
}
|
||||
|
||||
|
@ -577,7 +577,8 @@ void OpenGLDevice::SetSwapInterval()
|
|||
return;
|
||||
|
||||
// Window framebuffer has to be bound to call SetSwapInterval.
|
||||
const s32 interval = m_vsync_enabled ? 1 : 0;
|
||||
const s32 interval =
|
||||
(m_sync_mode == DisplaySyncMode::VSync) ? 1 : ((m_sync_mode == DisplaySyncMode::VSyncRelaxed) ? -1 : 0);
|
||||
GLint current_fbo = 0;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
|
|
|
@ -98,7 +98,7 @@ public:
|
|||
void Draw(u32 vertex_count, u32 base_vertex) override;
|
||||
void DrawIndexed(u32 index_count, u32 base_index, u32 base_vertex) override;
|
||||
|
||||
void SetVSync(bool enabled) override;
|
||||
void SetSyncMode(DisplaySyncMode mode) override;
|
||||
|
||||
bool BeginPresent(bool skip_present) override;
|
||||
void EndPresent() override;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\dep\msvc\vsprops\Configurations.props" />
|
||||
<ItemGroup>
|
||||
<ClInclude Include="gpu_types.h" />
|
||||
<ClInclude Include="imgui_animated.h" />
|
||||
<ClInclude Include="audio_stream.h" />
|
||||
<ClInclude Include="cd_image.h" />
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
<ClInclude Include="opengl_context_egl_wayland.h" />
|
||||
<ClInclude Include="opengl_context_egl_x11.h" />
|
||||
<ClInclude Include="opengl_context_wgl.h" />
|
||||
<ClInclude Include="gpu_types.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="jit_code_buffer.cpp" />
|
||||
|
|
|
@ -2022,7 +2022,7 @@ bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_p
|
|||
|
||||
if (surface != VK_NULL_HANDLE)
|
||||
{
|
||||
m_swap_chain = VulkanSwapChain::Create(m_window_info, surface, m_vsync_enabled, m_exclusive_fullscreen_control);
|
||||
m_swap_chain = VulkanSwapChain::Create(m_window_info, surface, m_sync_mode, m_exclusive_fullscreen_control);
|
||||
if (!m_swap_chain)
|
||||
{
|
||||
Error::SetStringView(error, "Failed to create swap chain");
|
||||
|
@ -2243,7 +2243,7 @@ bool VulkanDevice::UpdateWindow()
|
|||
return false;
|
||||
}
|
||||
|
||||
m_swap_chain = VulkanSwapChain::Create(m_window_info, surface, m_vsync_enabled, m_exclusive_fullscreen_control);
|
||||
m_swap_chain = VulkanSwapChain::Create(m_window_info, surface, m_sync_mode, m_exclusive_fullscreen_control);
|
||||
if (!m_swap_chain)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to create swap chain");
|
||||
|
@ -2319,24 +2319,27 @@ std::string VulkanDevice::GetDriverInfo() const
|
|||
return ret;
|
||||
}
|
||||
|
||||
void VulkanDevice::SetVSync(bool enabled)
|
||||
void VulkanDevice::SetSyncMode(DisplaySyncMode mode)
|
||||
{
|
||||
if (!m_swap_chain || m_vsync_enabled == enabled)
|
||||
if (m_sync_mode == mode)
|
||||
return;
|
||||
|
||||
const DisplaySyncMode prev_mode = m_sync_mode;
|
||||
m_sync_mode = mode;
|
||||
if (!m_swap_chain)
|
||||
return;
|
||||
|
||||
// This swap chain should not be used by the current buffer, thus safe to destroy.
|
||||
WaitForGPUIdle();
|
||||
if (!m_swap_chain->SetVSync(enabled))
|
||||
if (!m_swap_chain->SetSyncMode(mode))
|
||||
{
|
||||
// Try switching back to the old mode..
|
||||
if (!m_swap_chain->SetVSync(m_vsync_enabled))
|
||||
if (!m_swap_chain->SetSyncMode(prev_mode))
|
||||
{
|
||||
Panic("Failed to reset old vsync mode after failure");
|
||||
m_swap_chain.reset();
|
||||
}
|
||||
}
|
||||
|
||||
m_vsync_enabled = enabled;
|
||||
}
|
||||
|
||||
bool VulkanDevice::BeginPresent(bool frame_skip)
|
||||
|
|
|
@ -126,7 +126,7 @@ public:
|
|||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
void SetVSync(bool enabled) override;
|
||||
void SetSyncMode(DisplaySyncMode mode) override;
|
||||
|
||||
bool BeginPresent(bool skip_present) override;
|
||||
void EndPresent() override;
|
||||
|
|
|
@ -22,9 +22,69 @@
|
|||
|
||||
Log_SetChannel(VulkanDevice);
|
||||
|
||||
VulkanSwapChain::VulkanSwapChain(const WindowInfo& wi, VkSurfaceKHR surface, bool vsync,
|
||||
static VkFormat GetLinearFormat(VkFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case VK_FORMAT_R8_SRGB:
|
||||
return VK_FORMAT_R8_UNORM;
|
||||
case VK_FORMAT_R8G8_SRGB:
|
||||
return VK_FORMAT_R8G8_UNORM;
|
||||
case VK_FORMAT_R8G8B8_SRGB:
|
||||
return VK_FORMAT_R8G8B8_UNORM;
|
||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case VK_FORMAT_B8G8R8_SRGB:
|
||||
return VK_FORMAT_B8G8R8_UNORM;
|
||||
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||
return VK_FORMAT_B8G8R8A8_UNORM;
|
||||
default:
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* PresentModeToString(VkPresentModeKHR mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case VK_PRESENT_MODE_IMMEDIATE_KHR:
|
||||
return "VK_PRESENT_MODE_IMMEDIATE_KHR";
|
||||
|
||||
case VK_PRESENT_MODE_MAILBOX_KHR:
|
||||
return "VK_PRESENT_MODE_MAILBOX_KHR";
|
||||
|
||||
case VK_PRESENT_MODE_FIFO_KHR:
|
||||
return "VK_PRESENT_MODE_FIFO_KHR";
|
||||
|
||||
case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
|
||||
return "VK_PRESENT_MODE_FIFO_RELAXED_KHR";
|
||||
|
||||
case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR:
|
||||
return "VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR";
|
||||
|
||||
case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR:
|
||||
return "VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR";
|
||||
|
||||
default:
|
||||
return "UNKNOWN_VK_PRESENT_MODE";
|
||||
}
|
||||
}
|
||||
|
||||
static VkPresentModeKHR GetPreferredPresentModeForVsyncMode(DisplaySyncMode mode)
|
||||
{
|
||||
static constexpr std::array<VkPresentModeKHR, static_cast<size_t>(DisplaySyncMode::Count)> modes = {{
|
||||
VK_PRESENT_MODE_IMMEDIATE_KHR, // Disabled
|
||||
VK_PRESENT_MODE_FIFO_KHR, // VSync
|
||||
VK_PRESENT_MODE_FIFO_RELAXED_KHR, // VSyncRelaxed
|
||||
VK_PRESENT_MODE_IMMEDIATE_KHR, // VRR ??
|
||||
}};
|
||||
|
||||
return modes[static_cast<size_t>(mode)];
|
||||
}
|
||||
|
||||
VulkanSwapChain::VulkanSwapChain(const WindowInfo& wi, VkSurfaceKHR surface, VkPresentModeKHR requested_present_mode,
|
||||
std::optional<bool> exclusive_fullscreen_control)
|
||||
: m_window_info(wi), m_surface(surface), m_vsync_mode(vsync),
|
||||
: m_window_info(wi), m_surface(surface), m_requested_present_mode(requested_present_mode),
|
||||
m_exclusive_fullscreen_control(exclusive_fullscreen_control)
|
||||
{
|
||||
}
|
||||
|
@ -160,38 +220,19 @@ void VulkanSwapChain::DestroyVulkanSurface(VkInstance instance, WindowInfo* wi,
|
|||
#endif
|
||||
}
|
||||
|
||||
std::unique_ptr<VulkanSwapChain> VulkanSwapChain::Create(const WindowInfo& wi, VkSurfaceKHR surface, bool vsync,
|
||||
std::unique_ptr<VulkanSwapChain> VulkanSwapChain::Create(const WindowInfo& wi, VkSurfaceKHR surface,
|
||||
DisplaySyncMode sync_mode,
|
||||
std::optional<bool> exclusive_fullscreen_control)
|
||||
{
|
||||
const VkPresentModeKHR requested_mode = GetPreferredPresentModeForVsyncMode(sync_mode);
|
||||
std::unique_ptr<VulkanSwapChain> swap_chain =
|
||||
std::unique_ptr<VulkanSwapChain>(new VulkanSwapChain(wi, surface, vsync, exclusive_fullscreen_control));
|
||||
std::unique_ptr<VulkanSwapChain>(new VulkanSwapChain(wi, surface, requested_mode, exclusive_fullscreen_control));
|
||||
if (!swap_chain->CreateSwapChain())
|
||||
return nullptr;
|
||||
|
||||
return swap_chain;
|
||||
}
|
||||
|
||||
static VkFormat GetLinearFormat(VkFormat format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case VK_FORMAT_R8_SRGB:
|
||||
return VK_FORMAT_R8_UNORM;
|
||||
case VK_FORMAT_R8G8_SRGB:
|
||||
return VK_FORMAT_R8G8_UNORM;
|
||||
case VK_FORMAT_R8G8B8_SRGB:
|
||||
return VK_FORMAT_R8G8B8_UNORM;
|
||||
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case VK_FORMAT_B8G8R8_SRGB:
|
||||
return VK_FORMAT_B8G8R8_UNORM;
|
||||
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||
return VK_FORMAT_B8G8R8A8_UNORM;
|
||||
default:
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<VkSurfaceFormatKHR> VulkanSwapChain::SelectSurfaceFormat(VkSurfaceKHR surface)
|
||||
{
|
||||
VulkanDevice& dev = VulkanDevice::GetInstance();
|
||||
|
@ -232,44 +273,8 @@ std::optional<VkSurfaceFormatKHR> VulkanSwapChain::SelectSurfaceFormat(VkSurface
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
static const char* PresentModeToString(VkPresentModeKHR mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case VK_PRESENT_MODE_IMMEDIATE_KHR:
|
||||
return "VK_PRESENT_MODE_IMMEDIATE_KHR";
|
||||
|
||||
case VK_PRESENT_MODE_MAILBOX_KHR:
|
||||
return "VK_PRESENT_MODE_MAILBOX_KHR";
|
||||
|
||||
case VK_PRESENT_MODE_FIFO_KHR:
|
||||
return "VK_PRESENT_MODE_FIFO_KHR";
|
||||
|
||||
case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
|
||||
return "VK_PRESENT_MODE_FIFO_RELAXED_KHR";
|
||||
|
||||
case VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR:
|
||||
return "VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR";
|
||||
|
||||
case VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR:
|
||||
return "VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR";
|
||||
|
||||
default:
|
||||
return "UNKNOWN_VK_PRESENT_MODE";
|
||||
}
|
||||
}
|
||||
|
||||
static VkPresentModeKHR GetPreferredPresentModeForVsyncMode(bool mode)
|
||||
{
|
||||
if (mode /*== VsyncMode::On*/)
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
/*else if (mode == VsyncMode::Adaptive)
|
||||
return VK_PRESENT_MODE_FIFO_RELAXED_KHR;*/
|
||||
else
|
||||
return VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
}
|
||||
|
||||
std::optional<VkPresentModeKHR> VulkanSwapChain::SelectPresentMode(VkSurfaceKHR surface, bool vsync)
|
||||
std::optional<VkPresentModeKHR> VulkanSwapChain::SelectPresentMode(VkSurfaceKHR surface,
|
||||
VkPresentModeKHR requested_mode)
|
||||
{
|
||||
VulkanDevice& dev = VulkanDevice::GetInstance();
|
||||
VkResult res;
|
||||
|
@ -294,18 +299,17 @@ std::optional<VkPresentModeKHR> VulkanSwapChain::SelectPresentMode(VkSurfaceKHR
|
|||
};
|
||||
|
||||
// Use preferred mode if available.
|
||||
const VkPresentModeKHR preferred_mode = GetPreferredPresentModeForVsyncMode(vsync);
|
||||
VkPresentModeKHR selected_mode;
|
||||
if (CheckForMode(preferred_mode))
|
||||
if (CheckForMode(requested_mode))
|
||||
{
|
||||
selected_mode = preferred_mode;
|
||||
selected_mode = requested_mode;
|
||||
}
|
||||
else if (!vsync /*vsync != VsyncMode::On*/ && CheckForMode(VK_PRESENT_MODE_MAILBOX_KHR))
|
||||
else if (requested_mode != VK_PRESENT_MODE_FIFO_KHR && CheckForMode(VK_PRESENT_MODE_MAILBOX_KHR))
|
||||
{
|
||||
// Prefer mailbox over fifo for adaptive vsync/no-vsync.
|
||||
selected_mode = VK_PRESENT_MODE_MAILBOX_KHR;
|
||||
}
|
||||
else if (vsync /*vsync != VsyncMode::Off*/ && CheckForMode(VK_PRESENT_MODE_FIFO_KHR))
|
||||
else if (requested_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR && CheckForMode(VK_PRESENT_MODE_FIFO_KHR))
|
||||
{
|
||||
// Fallback to FIFO if we're using any kind of vsync.
|
||||
// This should never fail, FIFO is mandated.
|
||||
|
@ -317,7 +321,7 @@ std::optional<VkPresentModeKHR> VulkanSwapChain::SelectPresentMode(VkSurfaceKHR
|
|||
selected_mode = present_modes[0];
|
||||
}
|
||||
|
||||
Log_DevPrintf("(SwapChain) Preferred present mode: %s, selected: %s", PresentModeToString(preferred_mode),
|
||||
Log_DevPrintf("(SwapChain) Preferred present mode: %s, selected: %s", PresentModeToString(requested_mode),
|
||||
PresentModeToString(selected_mode));
|
||||
|
||||
return selected_mode;
|
||||
|
@ -329,7 +333,7 @@ bool VulkanSwapChain::CreateSwapChain()
|
|||
|
||||
// Select swap chain format and present mode
|
||||
std::optional<VkSurfaceFormatKHR> surface_format = SelectSurfaceFormat(m_surface);
|
||||
std::optional<VkPresentModeKHR> present_mode = SelectPresentMode(m_surface, m_vsync_mode);
|
||||
std::optional<VkPresentModeKHR> present_mode = SelectPresentMode(m_surface, m_requested_present_mode);
|
||||
if (!surface_format.has_value() || !present_mode.has_value())
|
||||
return false;
|
||||
|
||||
|
@ -468,6 +472,7 @@ bool VulkanSwapChain::CreateSwapChain()
|
|||
m_window_info.surface_width = std::max(1u, size.width);
|
||||
m_window_info.surface_height = std::max(1u, size.height);
|
||||
m_window_info.surface_format = VulkanDevice::GetFormatForVkFormat(surface_format->format);
|
||||
m_actual_present_mode = present_mode.value();
|
||||
if (m_window_info.surface_format == GPUTexture::Format::Unknown)
|
||||
{
|
||||
Log_ErrorPrintf("Unknown Vulkan surface format %u", static_cast<u32>(surface_format->format));
|
||||
|
@ -634,12 +639,13 @@ bool VulkanSwapChain::ResizeSwapChain(u32 new_width, u32 new_height, float new_s
|
|||
return true;
|
||||
}
|
||||
|
||||
bool VulkanSwapChain::SetVSync(bool mode)
|
||||
bool VulkanSwapChain::SetSyncMode(DisplaySyncMode mode)
|
||||
{
|
||||
if (m_vsync_mode == mode)
|
||||
const VkPresentModeKHR present_mode = GetPreferredPresentModeForVsyncMode(mode);
|
||||
if (m_requested_present_mode == present_mode)
|
||||
return true;
|
||||
|
||||
m_vsync_mode = mode;
|
||||
m_requested_present_mode = present_mode;
|
||||
|
||||
// Recreate the swap chain with the new present mode.
|
||||
Log_VerbosePrintf("Recreating swap chain to change present mode.");
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
static void DestroyVulkanSurface(VkInstance instance, WindowInfo* wi, VkSurfaceKHR surface);
|
||||
|
||||
// Create a new swap chain from a pre-existing surface.
|
||||
static std::unique_ptr<VulkanSwapChain> Create(const WindowInfo& wi, VkSurfaceKHR surface, bool vsync,
|
||||
static std::unique_ptr<VulkanSwapChain> Create(const WindowInfo& wi, VkSurfaceKHR surface, DisplaySyncMode sync_mode,
|
||||
std::optional<bool> exclusive_fullscreen_control);
|
||||
|
||||
ALWAYS_INLINE VkSurfaceKHR GetSurface() const { return m_surface; }
|
||||
|
@ -60,9 +60,12 @@ public:
|
|||
}
|
||||
|
||||
// Returns true if the current present mode is synchronizing (adaptive or hard).
|
||||
ALWAYS_INLINE bool IsPresentModeSynchronizing() const { return (m_vsync_mode /*!= VsyncMode::Off*/); }
|
||||
ALWAYS_INLINE bool IsPresentModeSynchronizing() const
|
||||
{
|
||||
return (m_actual_present_mode == VK_PRESENT_MODE_FIFO_KHR ||
|
||||
m_actual_present_mode == VK_PRESENT_MODE_FIFO_RELAXED_KHR);
|
||||
}
|
||||
|
||||
VkRenderPass GetRenderPass(VkAttachmentLoadOp load_op) const;
|
||||
VkResult AcquireNextImage();
|
||||
void ReleaseCurrentImage();
|
||||
|
||||
|
@ -70,19 +73,18 @@ public:
|
|||
bool ResizeSwapChain(u32 new_width = 0, u32 new_height = 0, float new_scale = 1.0f);
|
||||
|
||||
// Change vsync enabled state. This may fail as it causes a swapchain recreation.
|
||||
bool SetVSync(bool mode);
|
||||
bool SetSyncMode(DisplaySyncMode mode);
|
||||
|
||||
private:
|
||||
VulkanSwapChain(const WindowInfo& wi, VkSurfaceKHR surface, bool vsync,
|
||||
VulkanSwapChain(const WindowInfo& wi, VkSurfaceKHR surface, VkPresentModeKHR requested_present_mode,
|
||||
std::optional<bool> exclusive_fullscreen_control);
|
||||
|
||||
static std::optional<VkSurfaceFormatKHR> SelectSurfaceFormat(VkSurfaceKHR surface);
|
||||
static std::optional<VkPresentModeKHR> SelectPresentMode(VkSurfaceKHR surface, bool vsync);
|
||||
static std::optional<VkPresentModeKHR> SelectPresentMode(VkSurfaceKHR surface, VkPresentModeKHR requested_mode);
|
||||
|
||||
bool CreateSwapChain();
|
||||
void DestroySwapChain();
|
||||
|
||||
bool SetupSwapChainImages();
|
||||
void DestroySwapChainImages();
|
||||
|
||||
void DestroySurface();
|
||||
|
@ -109,7 +111,8 @@ private:
|
|||
std::vector<ImageSemaphores> m_semaphores;
|
||||
|
||||
VkFormat m_format = VK_FORMAT_UNDEFINED;
|
||||
bool m_vsync_mode = false;
|
||||
VkPresentModeKHR m_requested_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
VkPresentModeKHR m_actual_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
|
||||
u32 m_current_image = 0;
|
||||
u32 m_current_semaphore = 0;
|
||||
|
||||
|
|
Loading…
Reference in New Issue