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);
|
"GPU", "UseSoftwareRendererForReadbacks", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawToggleSetting(
|
DrawEnumSetting(
|
||||||
bsi, FSUI_CSTR("Enable VSync"),
|
bsi, FSUI_CSTR("VSync"),
|
||||||
FSUI_CSTR("Synchronizes presentation of the console's frames to the host. Enable for smoother animations."),
|
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(
|
DrawToggleSetting(
|
||||||
bsi, FSUI_CSTR("Sync To Host Refresh Rate"),
|
bsi, FSUI_CSTR("Sync To Host Refresh Rate"),
|
||||||
|
|
|
@ -265,13 +265,11 @@ bool Host::CreateGPUDevice(RenderAPI api)
|
||||||
if (g_settings.gpu_disable_texture_copy_to_self)
|
if (g_settings.gpu_disable_texture_copy_to_self)
|
||||||
disabled_features |= GPUDevice::FEATURE_MASK_TEXTURE_COPY_TO_SELF;
|
disabled_features |= GPUDevice::FEATURE_MASK_TEXTURE_COPY_TO_SELF;
|
||||||
|
|
||||||
// TODO: FSUI should always use vsync..
|
|
||||||
Error error;
|
Error error;
|
||||||
const bool vsync = System::IsValid() ? System::ShouldUseVSync() : g_settings.video_sync_enabled;
|
if (!g_gpu_device || !g_gpu_device->Create(
|
||||||
if (!g_gpu_device || !g_gpu_device->Create(g_settings.gpu_adapter,
|
g_settings.gpu_adapter,
|
||||||
g_settings.gpu_disable_shader_cache ? std::string_view() :
|
g_settings.gpu_disable_shader_cache ? std::string_view() : std::string_view(EmuFolders::Cache),
|
||||||
std::string_view(EmuFolders::Cache),
|
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, System::GetEffectiveDisplaySyncMode(),
|
||||||
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, vsync,
|
|
||||||
g_settings.gpu_threaded_presentation, exclusive_fullscreen_control,
|
g_settings.gpu_threaded_presentation, exclusive_fullscreen_control,
|
||||||
static_cast<GPUDevice::FeatureMask>(disabled_features), &error))
|
static_cast<GPUDevice::FeatureMask>(disabled_features), &error))
|
||||||
{
|
{
|
||||||
|
|
|
@ -243,6 +243,10 @@ void Settings::Load(SettingsInterface& si)
|
||||||
display_scaling =
|
display_scaling =
|
||||||
ParseDisplayScaling(si.GetStringValue("Display", "Scaling", GetDisplayScalingName(DEFAULT_DISPLAY_SCALING)).c_str())
|
ParseDisplayScaling(si.GetStringValue("Display", "Scaling", GetDisplayScalingName(DEFAULT_DISPLAY_SCALING)).c_str())
|
||||||
.value_or(DEFAULT_DISPLAY_SCALING);
|
.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 =
|
display_exclusive_fullscreen_control =
|
||||||
ParseDisplayExclusiveFullscreenControl(
|
ParseDisplayExclusiveFullscreenControl(
|
||||||
si.GetStringValue("Display", "ExclusiveFullscreenControl",
|
si.GetStringValue("Display", "ExclusiveFullscreenControl",
|
||||||
|
@ -279,7 +283,6 @@ void Settings::Load(SettingsInterface& si)
|
||||||
display_show_enhancements = si.GetBoolValue("Display", "ShowEnhancements", false);
|
display_show_enhancements = si.GetBoolValue("Display", "ShowEnhancements", false);
|
||||||
display_all_frames = si.GetBoolValue("Display", "DisplayAllFrames", false);
|
display_all_frames = si.GetBoolValue("Display", "DisplayAllFrames", false);
|
||||||
display_stretch_vertically = si.GetBoolValue("Display", "StretchVertically", 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_max_fps = si.GetFloatValue("Display", "MaxFPS", DEFAULT_DISPLAY_MAX_FPS);
|
||||||
display_osd_scale = si.GetFloatValue("Display", "OSDScale", DEFAULT_OSD_SCALE);
|
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", "AspectRatio", GetDisplayAspectRatioName(display_aspect_ratio));
|
||||||
si.SetStringValue("Display", "Alignment", GetDisplayAlignmentName(display_alignment));
|
si.SetStringValue("Display", "Alignment", GetDisplayAlignmentName(display_alignment));
|
||||||
si.SetStringValue("Display", "Scaling", GetDisplayScalingName(display_scaling));
|
si.SetStringValue("Display", "Scaling", GetDisplayScalingName(display_scaling));
|
||||||
|
si.SetStringValue("Display", "SyncMode", GetDisplaySyncModeName(display_sync_mode));
|
||||||
si.SetStringValue("Display", "ExclusiveFullscreenControl",
|
si.SetStringValue("Display", "ExclusiveFullscreenControl",
|
||||||
GetDisplayExclusiveFullscreenControlName(display_exclusive_fullscreen_control));
|
GetDisplayExclusiveFullscreenControlName(display_exclusive_fullscreen_control));
|
||||||
si.SetStringValue("Display", "ScreenshotMode", GetDisplayScreenshotModeName(display_screenshot_mode));
|
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", "ShowEnhancements", display_show_enhancements);
|
||||||
si.SetBoolValue("Display", "DisplayAllFrames", display_all_frames);
|
si.SetBoolValue("Display", "DisplayAllFrames", display_all_frames);
|
||||||
si.SetBoolValue("Display", "StretchVertically", display_stretch_vertically);
|
si.SetBoolValue("Display", "StretchVertically", display_stretch_vertically);
|
||||||
si.SetBoolValue("Display", "VSync", video_sync_enabled);
|
|
||||||
si.SetFloatValue("Display", "MaxFPS", display_max_fps);
|
si.SetFloatValue("Display", "MaxFPS", display_max_fps);
|
||||||
si.SetFloatValue("Display", "OSDScale", display_osd_scale);
|
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)]);
|
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 = {
|
static constexpr const std::array s_display_exclusive_fullscreen_mode_names = {
|
||||||
"Automatic",
|
"Automatic",
|
||||||
"Disallowed",
|
"Disallowed",
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#include "util/audio_stream.h"
|
#include "util/audio_stream.h"
|
||||||
|
#include "util/gpu_types.h"
|
||||||
|
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "common/settings_interface.h"
|
#include "common/settings_interface.h"
|
||||||
|
@ -18,8 +19,6 @@
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
enum class RenderAPI : u32;
|
|
||||||
|
|
||||||
struct SettingInfo
|
struct SettingInfo
|
||||||
{
|
{
|
||||||
enum class Type
|
enum class Type
|
||||||
|
@ -134,6 +133,7 @@ struct Settings
|
||||||
DisplayAspectRatio display_aspect_ratio = DEFAULT_DISPLAY_ASPECT_RATIO;
|
DisplayAspectRatio display_aspect_ratio = DEFAULT_DISPLAY_ASPECT_RATIO;
|
||||||
DisplayAlignment display_alignment = DEFAULT_DISPLAY_ALIGNMENT;
|
DisplayAlignment display_alignment = DEFAULT_DISPLAY_ALIGNMENT;
|
||||||
DisplayScalingMode display_scaling = DEFAULT_DISPLAY_SCALING;
|
DisplayScalingMode display_scaling = DEFAULT_DISPLAY_SCALING;
|
||||||
|
DisplaySyncMode display_sync_mode = DEFAULT_DISPLAY_SYNC_MODE;
|
||||||
DisplayExclusiveFullscreenControl display_exclusive_fullscreen_control = DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL;
|
DisplayExclusiveFullscreenControl display_exclusive_fullscreen_control = DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL;
|
||||||
DisplayScreenshotMode display_screenshot_mode = DEFAULT_DISPLAY_SCREENSHOT_MODE;
|
DisplayScreenshotMode display_screenshot_mode = DEFAULT_DISPLAY_SCREENSHOT_MODE;
|
||||||
DisplayScreenshotFormat display_screenshot_format = DEFAULT_DISPLAY_SCREENSHOT_FORMAT;
|
DisplayScreenshotFormat display_screenshot_format = DEFAULT_DISPLAY_SCREENSHOT_FORMAT;
|
||||||
|
@ -159,7 +159,6 @@ struct Settings
|
||||||
bool display_show_enhancements : 1 = false;
|
bool display_show_enhancements : 1 = false;
|
||||||
bool display_all_frames : 1 = false;
|
bool display_all_frames : 1 = false;
|
||||||
bool display_stretch_vertically : 1 = false;
|
bool display_stretch_vertically : 1 = false;
|
||||||
bool video_sync_enabled = DEFAULT_VSYNC_VALUE;
|
|
||||||
float display_osd_scale = 100.0f;
|
float display_osd_scale = 100.0f;
|
||||||
float display_max_fps = DEFAULT_DISPLAY_MAX_FPS;
|
float display_max_fps = DEFAULT_DISPLAY_MAX_FPS;
|
||||||
float gpu_pgxp_tolerance = -1.0f;
|
float gpu_pgxp_tolerance = -1.0f;
|
||||||
|
@ -411,6 +410,10 @@ struct Settings
|
||||||
static const char* GetDisplayScalingName(DisplayScalingMode mode);
|
static const char* GetDisplayScalingName(DisplayScalingMode mode);
|
||||||
static const char* GetDisplayScalingDisplayName(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 std::optional<DisplayExclusiveFullscreenControl> ParseDisplayExclusiveFullscreenControl(const char* str);
|
||||||
static const char* GetDisplayExclusiveFullscreenControlName(DisplayExclusiveFullscreenControl mode);
|
static const char* GetDisplayExclusiveFullscreenControlName(DisplayExclusiveFullscreenControl mode);
|
||||||
static const char* GetDisplayExclusiveFullscreenControlDisplayName(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 DisplayAspectRatio DEFAULT_DISPLAY_ASPECT_RATIO = DisplayAspectRatio::Auto;
|
||||||
static constexpr DisplayAlignment DEFAULT_DISPLAY_ALIGNMENT = DisplayAlignment::Center;
|
static constexpr DisplayAlignment DEFAULT_DISPLAY_ALIGNMENT = DisplayAlignment::Center;
|
||||||
static constexpr DisplayScalingMode DEFAULT_DISPLAY_SCALING = DisplayScalingMode::BilinearSmooth;
|
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 =
|
static constexpr DisplayExclusiveFullscreenControl DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL =
|
||||||
DisplayExclusiveFullscreenControl::Automatic;
|
DisplayExclusiveFullscreenControl::Automatic;
|
||||||
static constexpr DisplayScreenshotMode DEFAULT_DISPLAY_SCREENSHOT_MODE = DisplayScreenshotMode::ScreenResolution;
|
static constexpr DisplayScreenshotMode DEFAULT_DISPLAY_SCREENSHOT_MODE = DisplayScreenshotMode::ScreenResolution;
|
||||||
|
@ -525,13 +529,11 @@ struct Settings
|
||||||
#ifndef __ANDROID__
|
#ifndef __ANDROID__
|
||||||
static constexpr bool DEFAULT_SAVE_STATE_COMPRESSION = true;
|
static constexpr bool DEFAULT_SAVE_STATE_COMPRESSION = true;
|
||||||
static constexpr bool DEFAULT_SAVE_STATE_BACKUPS = 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 bool DEFAULT_FAST_BOOT_VALUE = false;
|
||||||
static constexpr float DEFAULT_DISPLAY_MAX_FPS = 0.0f;
|
static constexpr float DEFAULT_DISPLAY_MAX_FPS = 0.0f;
|
||||||
#else
|
#else
|
||||||
static constexpr bool DEFAULT_SAVE_STATE_COMPRESSION = true;
|
static constexpr bool DEFAULT_SAVE_STATE_COMPRESSION = true;
|
||||||
static constexpr bool DEFAULT_SAVE_STATE_BACKUPS = false;
|
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 bool DEFAULT_FAST_BOOT_VALUE = true;
|
||||||
static constexpr float DEFAULT_DISPLAY_MAX_FPS = 60.0f;
|
static constexpr float DEFAULT_DISPLAY_MAX_FPS = 60.0f;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1849,6 +1849,12 @@ void System::FrameDone()
|
||||||
SaveRunaheadState();
|
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();
|
const Common::Timer::Value current_time = Common::Timer::GetCurrentValue();
|
||||||
if (current_time < s_next_frame_time || s_display_all_frames || s_last_frame_skipped)
|
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;
|
s_last_frame_skipped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_throttler_enabled && !IsExecutionInterrupted())
|
if (throttle_after_present && s_throttler_enabled && !IsExecutionInterrupted())
|
||||||
Throttle();
|
Throttle();
|
||||||
|
|
||||||
// Input poll already done above
|
// Input poll already done above
|
||||||
|
@ -2638,11 +2644,15 @@ void System::UpdateSpeedLimiterState()
|
||||||
}
|
}
|
||||||
|
|
||||||
// When syncing to host and using vsync, we don't need to sleep.
|
// 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)
|
||||||
|
{
|
||||||
|
const DisplaySyncMode effective_sync_mode = GetEffectiveDisplaySyncMode();
|
||||||
|
if (effective_sync_mode == DisplaySyncMode::VSync || effective_sync_mode == DisplaySyncMode::VSyncRelaxed)
|
||||||
{
|
{
|
||||||
Log_InfoPrintf("Using host vsync for throttling.");
|
Log_InfoPrintf("Using host vsync for throttling.");
|
||||||
s_throttler_enabled = false;
|
s_throttler_enabled = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log_VerbosePrintf("Target speed: %f%%", s_target_speed * 100.0f);
|
Log_VerbosePrintf("Target speed: %f%%", s_target_speed * 100.0f);
|
||||||
|
|
||||||
|
@ -2674,21 +2684,25 @@ void System::UpdateSpeedLimiterState()
|
||||||
|
|
||||||
void System::UpdateDisplaySync()
|
void System::UpdateDisplaySync()
|
||||||
{
|
{
|
||||||
const bool video_sync_enabled = ShouldUseVSync();
|
const DisplaySyncMode display_sync_mode = GetEffectiveDisplaySyncMode();
|
||||||
const bool syncing_to_host_vsync = (s_syncing_to_host && video_sync_enabled && s_display_all_frames);
|
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;
|
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)" : "");
|
syncing_to_host_vsync ? " (for throttling)" : "");
|
||||||
Log_VerbosePrintf("Max display fps: %f (%s)", max_display_fps,
|
Log_VerbosePrintf("Max display fps: %f (%s)", max_display_fps,
|
||||||
s_display_all_frames ? "displaying all frames" : "skipping displaying frames when needed");
|
s_display_all_frames ? "displaying all frames" : "skipping displaying frames when needed");
|
||||||
|
|
||||||
g_gpu_device->SetDisplayMaxFPS(max_display_fps);
|
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()
|
bool System::IsFastForwardEnabled()
|
||||||
|
@ -3737,7 +3751,7 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
|
||||||
DMA::SetHaltTicks(g_settings.dma_halt_ticks);
|
DMA::SetHaltTicks(g_settings.dma_halt_ticks);
|
||||||
|
|
||||||
if (g_settings.audio_backend != old_settings.audio_backend ||
|
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.increase_timer_resolution != old_settings.increase_timer_resolution ||
|
||||||
g_settings.emulation_speed != old_settings.emulation_speed ||
|
g_settings.emulation_speed != old_settings.emulation_speed ||
|
||||||
g_settings.fast_forward_speed != old_settings.fast_forward_speed ||
|
g_settings.fast_forward_speed != old_settings.fast_forward_speed ||
|
||||||
|
|
|
@ -455,7 +455,7 @@ void ToggleWidescreen();
|
||||||
bool IsRunningAtNonStandardSpeed();
|
bool IsRunningAtNonStandardSpeed();
|
||||||
|
|
||||||
/// Returns true if vsync should be used.
|
/// Returns true if vsync should be used.
|
||||||
bool ShouldUseVSync();
|
DisplaySyncMode GetEffectiveDisplaySyncMode();
|
||||||
|
|
||||||
/// Quick switch between software and hardware rendering.
|
/// Quick switch between software and hardware rendering.
|
||||||
void ToggleSoftwareRendering();
|
void ToggleSoftwareRendering();
|
||||||
|
|
|
@ -51,8 +51,13 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||||
|
|
||||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.renderer, "GPU", "Renderer", &Settings::ParseRendererName,
|
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.renderer, "GPU", "Renderer", &Settings::ParseRendererName,
|
||||||
&Settings::GetRendererName, Settings::DEFAULT_GPU_RENDERER);
|
&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",
|
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayAspectRatio, "Display", "AspectRatio",
|
||||||
&Settings::ParseDisplayAspectRatio, &Settings::GetDisplayAspectRatioName,
|
&Settings::ParseDisplayAspectRatio, &Settings::GetDisplayAspectRatioName,
|
||||||
Settings::DEFAULT_DISPLAY_ASPECT_RATIO);
|
Settings::DEFAULT_DISPLAY_ASPECT_RATIO);
|
||||||
|
@ -67,13 +72,9 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
|
||||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayScaling, "Display", "Scaling",
|
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayScaling, "Display", "Scaling",
|
||||||
&Settings::ParseDisplayScaling, &Settings::GetDisplayScalingName,
|
&Settings::ParseDisplayScaling, &Settings::GetDisplayScalingName,
|
||||||
Settings::DEFAULT_DISPLAY_SCALING);
|
Settings::DEFAULT_DISPLAY_SCALING);
|
||||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.resolutionScale, "GPU", "ResolutionScale", 1);
|
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displaySyncMode, "Display", "SyncMode",
|
||||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.textureFiltering, "GPU", "TextureFilter",
|
&Settings::ParseDisplaySyncMode, &Settings::GetDisplaySyncModeName,
|
||||||
&Settings::ParseTextureFilterName, &Settings::GetTextureFilterName,
|
Settings::DEFAULT_DISPLAY_SYNC_MODE);
|
||||||
Settings::DEFAULT_GPU_TEXTURE_FILTER);
|
|
||||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.gpuDownsampleMode, "GPU", "DownsampleMode",
|
|
||||||
&Settings::ParseDownsampleModeName, &Settings::GetDownsampleModeName,
|
|
||||||
Settings::DEFAULT_GPU_DOWNSAMPLE_MODE);
|
|
||||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gpuDownsampleScale, "GPU", "DownsampleScale", 1);
|
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gpuDownsampleScale, "GPU", "DownsampleScale", 1);
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.trueColor, "GPU", "TrueColor", false);
|
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.trueColor, "GPU", "TrueColor", false);
|
||||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableInterlacing, "GPU", "DisableInterlacing", true);
|
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 "
|
"renderers. <br>This option is only supported in Direct3D and Vulkan. OpenGL will always use the default "
|
||||||
"device."));
|
"device."));
|
||||||
dialog->registerWidgetHelp(
|
dialog->registerWidgetHelp(
|
||||||
m_ui.vsync, tr("VSync"), tr("Unchecked"),
|
m_ui.resolutionScale, tr("Internal Resolution"), "1x",
|
||||||
tr("Enable this option to match DuckStation's refresh rate with your current monitor or screen. "
|
tr("Setting this beyond 1x will enhance the resolution of rendered 3D polygons and lines. Only applies "
|
||||||
"VSync is automatically disabled when it is not possible (e.g. running at non-100% speed)."));
|
"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(
|
dialog->registerWidgetHelp(
|
||||||
m_ui.displayAspectRatio, tr("Aspect Ratio"),
|
m_ui.displayAspectRatio, tr("Aspect Ratio"),
|
||||||
QString::fromUtf8(Settings::GetDisplayAspectRatioDisplayName(Settings::DEFAULT_DISPLAY_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)"),
|
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."));
|
tr("Determines how the emulated console's output is upscaled or downscaled to your monitor's resolution."));
|
||||||
dialog->registerWidgetHelp(
|
dialog->registerWidgetHelp(
|
||||||
m_ui.resolutionScale, tr("Internal Resolution"), "1x",
|
m_ui.displaySyncMode, tr("VSync"), tr("Unchecked"),
|
||||||
tr("Setting this beyond 1x will enhance the resolution of rendered 3D polygons and lines. Only applies "
|
tr("Enable this option to match DuckStation's refresh rate with your current monitor or screen. "
|
||||||
"to the hardware backends. <br>This option is usually safe, with most games looking fine at "
|
"VSync is automatically disabled when it is not possible (e.g. running at non-100% speed)."));
|
||||||
"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."));
|
|
||||||
dialog->registerWidgetHelp(
|
dialog->registerWidgetHelp(
|
||||||
m_ui.trueColor, tr("True Color Rendering"), tr("Checked"),
|
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 "
|
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)),
|
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 "
|
tr("Attempts to detect one pixel high/wide lines that rely on non-upscaled rasterization "
|
||||||
"behavior, filling in gaps introduced by upscaling."));
|
"behavior, filling in gaps introduced by upscaling."));
|
||||||
dialog->registerWidgetHelp(m_ui.gpuWireframeMode, tr("Wireframe Mode"), tr("Disabled"),
|
dialog->registerWidgetHelp(
|
||||||
tr("Draws a wireframe outline of the triangles rendered by the console's GPU, either as a "
|
m_ui.msaaMode, tr("Multi-Sampling"), tr("Disabled"),
|
||||||
"replacement or an overlay."));
|
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(
|
dialog->registerWidgetHelp(
|
||||||
m_ui.debanding, tr("True Color Debanding"), tr("Unchecked"),
|
m_ui.debanding, tr("True Color Debanding"), tr("Unchecked"),
|
||||||
tr("Applies modern dithering techniques to further smooth out gradients when true color is enabled. "
|
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
|
// 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(
|
dialog->registerWidgetHelp(
|
||||||
m_ui.useDebugDevice, tr("Use Debug Device"), tr("Unchecked"),
|
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>"));
|
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))));
|
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++)
|
for (u32 i = 0; i < static_cast<u32>(DisplayAspectRatio::Count); i++)
|
||||||
{
|
{
|
||||||
m_ui.displayAspectRatio->addItem(
|
m_ui.displayAspectRatio->addItem(
|
||||||
|
@ -523,26 +537,10 @@ void GraphicsSettingsWidget::setupAdditionalUi()
|
||||||
QString::fromUtf8(Settings::GetDisplayScalingDisplayName(static_cast<DisplayScalingMode>(i))));
|
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.displaySyncMode->addItem(
|
||||||
m_ui.msaaMode->addItem(tr("Use Global Setting"));
|
QString::fromUtf8(Settings::GetDisplaySyncModeDisplayName(static_cast<DisplaySyncMode>(i))));
|
||||||
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))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advanced Tab
|
// Advanced Tab
|
||||||
|
@ -559,18 +557,22 @@ void GraphicsSettingsWidget::setupAdditionalUi()
|
||||||
QString::fromUtf8(Settings::GetDisplayAlignmentDisplayName(static_cast<DisplayAlignment>(i))));
|
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++)
|
for (u32 i = 0; i < static_cast<u32>(GPULineDetectMode::Count); i++)
|
||||||
{
|
{
|
||||||
m_ui.gpuLineDetectMode->addItem(
|
m_ui.gpuLineDetectMode->addItem(
|
||||||
QString::fromUtf8(Settings::GetLineDetectModeDisplayName(static_cast<GPULineDetectMode>(i))));
|
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
|
// Capture Tab
|
||||||
|
|
||||||
for (u32 i = 0; i < static_cast<u32>(DisplayScreenshotMode::Count); i++)
|
for (u32 i = 0; i < static_cast<u32>(DisplayScreenshotMode::Count); i++)
|
||||||
|
@ -584,6 +586,14 @@ void GraphicsSettingsWidget::setupAdditionalUi()
|
||||||
m_ui.screenshotFormat->addItem(
|
m_ui.screenshotFormat->addItem(
|
||||||
QString::fromUtf8(Settings::GetDisplayScreenshotFormatDisplayName(static_cast<DisplayScreenshotFormat>(i))));
|
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()
|
void GraphicsSettingsWidget::removePlatformSpecificUi()
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>584</width>
|
<width>584</width>
|
||||||
<height>446</height>
|
<height>434</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -50,19 +50,8 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="1,0">
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="adapter"/>
|
<widget class="QComboBox" name="adapter"/>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="vsync">
|
|
||||||
<property name="text">
|
|
||||||
<string>VSync</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -98,74 +87,13 @@
|
||||||
</property>
|
</property>
|
||||||
<layout class="QFormLayout" name="formLayout_2">
|
<layout class="QFormLayout" name="formLayout_2">
|
||||||
<item row="0" column="0">
|
<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">
|
<widget class="QLabel" name="resolutionScaleLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Internal Resolution:</string>
|
<string>Internal Resolution:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QComboBox" name="resolutionScale">
|
<widget class="QComboBox" name="resolutionScale">
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -254,27 +182,115 @@
|
||||||
</item>
|
</item>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="msaaModeLabel">
|
<widget class="QLabel" name="gpuDownsampleLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Multi-Sampling:</string>
|
<string>Down-Sampling:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QComboBox" name="msaaMode"/>
|
<layout class="QHBoxLayout" name="gpuDownsampleLayout" stretch="1,0">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="gpuDownsampleMode"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0">
|
<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="2" column="0">
|
||||||
<widget class="QLabel" name="textureFilteringLabel">
|
<widget class="QLabel" name="textureFilteringLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Texture Filtering:</string>
|
<string>Texture Filtering:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QComboBox" name="textureFiltering"/>
|
<widget class="QComboBox" name="textureFiltering"/>
|
||||||
</item>
|
</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">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QCheckBox" name="pgxpEnable">
|
<widget class="QCheckBox" name="pgxpEnable">
|
||||||
|
@ -283,6 +299,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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">
|
<item row="1" column="1">
|
||||||
<widget class="QCheckBox" name="pgxpDepthBuffer">
|
<widget class="QCheckBox" name="pgxpDepthBuffer">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -304,20 +327,6 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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">
|
<item row="3" column="0">
|
||||||
<widget class="QCheckBox" name="disableInterlacing">
|
<widget class="QCheckBox" name="disableInterlacing">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -332,30 +341,10 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
<item row="3" column="1">
|
||||||
</item>
|
<widget class="QCheckBox" name="forceNTSCTimings">
|
||||||
<item row="5" column="0">
|
|
||||||
<widget class="QLabel" name="gpuDownsampleLabel">
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Down-Sampling:</string>
|
<string>Force NTSC Timings</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>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -477,6 +466,16 @@
|
||||||
<string>Rendering Options</string>
|
<string>Rendering Options</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QFormLayout" name="formLayout_6">
|
<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">
|
<item row="2" column="0" colspan="2">
|
||||||
<layout class="QGridLayout" name="gridLayout_5">
|
<layout class="QGridLayout" name="gridLayout_5">
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
|
@ -503,24 +502,14 @@
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="gpuLineDetectModeLabel">
|
<widget class="QLabel" name="msaaModeLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Line Detection:</string>
|
<string>Multi-Sampling:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QComboBox" name="gpuLineDetectMode"/>
|
<widget class="QComboBox" name="msaaMode"/>
|
||||||
</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"/>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -1035,6 +1024,25 @@
|
||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</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>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox_9">
|
<widget class="QGroupBox" name="groupBox_9">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
|
|
|
@ -1529,7 +1529,7 @@ void EmuThread::run()
|
||||||
if (g_gpu_device)
|
if (g_gpu_device)
|
||||||
{
|
{
|
||||||
System::PresentDisplay(false);
|
System::PresentDisplay(false);
|
||||||
if (!g_gpu_device->IsVsyncEnabled())
|
if (!g_gpu_device->IsVSyncActive())
|
||||||
g_gpu_device->ThrottlePresentation();
|
g_gpu_device->ThrottlePresentation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ add_library(util
|
||||||
gpu_shader_cache.h
|
gpu_shader_cache.h
|
||||||
gpu_texture.cpp
|
gpu_texture.cpp
|
||||||
gpu_texture.h
|
gpu_texture.h
|
||||||
|
gpu_types.h
|
||||||
host.cpp
|
host.cpp
|
||||||
host.h
|
host.h
|
||||||
http_downloader.cpp
|
http_downloader.cpp
|
||||||
|
|
|
@ -233,7 +233,8 @@ bool D3D11Device::CreateSwapChain()
|
||||||
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
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;
|
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)
|
if (m_using_allow_tearing)
|
||||||
swap_chain_desc.Flags |= DXGI_SWAP_CHAIN_FLAG_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);
|
return GPUDevice::GetHostRefreshRate(refresh_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D11Device::SetVSync(bool enabled)
|
|
||||||
{
|
|
||||||
m_vsync_enabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool D3D11Device::BeginPresent(bool skip_present)
|
bool D3D11Device::BeginPresent(bool skip_present)
|
||||||
{
|
{
|
||||||
if (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
|
// 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
|
// 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.
|
// 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();
|
PopTimestampQuery();
|
||||||
|
|
||||||
static constexpr float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
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);
|
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();
|
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);
|
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||||
else
|
else
|
||||||
m_swap_chain->Present(BoolToUInt32(m_vsync_enabled), 0);
|
m_swap_chain->Present(0, 0);
|
||||||
|
|
||||||
if (m_gpu_timing_enabled)
|
if (m_gpu_timing_enabled)
|
||||||
KickTimestampQuery();
|
KickTimestampQuery();
|
||||||
|
|
|
@ -98,8 +98,6 @@ public:
|
||||||
bool SetGPUTimingEnabled(bool enabled) override;
|
bool SetGPUTimingEnabled(bool enabled) override;
|
||||||
float GetAndResetAccumulatedGPUTime() override;
|
float GetAndResetAccumulatedGPUTime() override;
|
||||||
|
|
||||||
void SetVSync(bool enabled) override;
|
|
||||||
|
|
||||||
bool BeginPresent(bool skip_present) override;
|
bool BeginPresent(bool skip_present) override;
|
||||||
void EndPresent() override;
|
void EndPresent() override;
|
||||||
|
|
||||||
|
|
|
@ -1060,11 +1060,6 @@ std::string D3D12Device::GetDriverInfo() const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12Device::SetVSync(bool enabled)
|
|
||||||
{
|
|
||||||
m_vsync_enabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool D3D12Device::BeginPresent(bool frame_skip)
|
bool D3D12Device::BeginPresent(bool frame_skip)
|
||||||
{
|
{
|
||||||
if (InRenderPass())
|
if (InRenderPass())
|
||||||
|
@ -1112,10 +1107,13 @@ void D3D12Device::EndPresent()
|
||||||
|
|
||||||
SubmitCommandList(false);
|
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);
|
m_swap_chain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||||
else
|
else
|
||||||
m_swap_chain->Present(static_cast<UINT>(m_vsync_enabled), 0);
|
m_swap_chain->Present(0, 0);
|
||||||
|
|
||||||
TrimTexturePool();
|
TrimTexturePool();
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,8 +119,6 @@ public:
|
||||||
bool SetGPUTimingEnabled(bool enabled) override;
|
bool SetGPUTimingEnabled(bool enabled) override;
|
||||||
float GetAndResetAccumulatedGPUTime() override;
|
float GetAndResetAccumulatedGPUTime() override;
|
||||||
|
|
||||||
void SetVSync(bool enabled) override;
|
|
||||||
|
|
||||||
bool BeginPresent(bool skip_present) override;
|
bool BeginPresent(bool skip_present) override;
|
||||||
void EndPresent() 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,
|
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,
|
u32 shader_cache_version, bool debug_device, DisplaySyncMode sync_mode,
|
||||||
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features, Error* error)
|
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;
|
m_debug_device = debug_device;
|
||||||
|
|
||||||
if (!AcquireWindow(true))
|
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 GPUDevice::UploadVertexBuffer(const void* vertices, u32 vertex_size, u32 vertex_count, u32* base_vertex)
|
||||||
{
|
{
|
||||||
void* map;
|
void* map;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "gpu_shader_cache.h"
|
#include "gpu_shader_cache.h"
|
||||||
#include "gpu_texture.h"
|
#include "gpu_texture.h"
|
||||||
|
#include "gpu_types.h"
|
||||||
#include "window_info.h"
|
#include "window_info.h"
|
||||||
|
|
||||||
#include "common/bitfield.h"
|
#include "common/bitfield.h"
|
||||||
|
@ -25,17 +26,6 @@
|
||||||
|
|
||||||
class Error;
|
class Error;
|
||||||
|
|
||||||
enum class RenderAPI : u32
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
D3D11,
|
|
||||||
D3D12,
|
|
||||||
Vulkan,
|
|
||||||
OpenGL,
|
|
||||||
OpenGLES,
|
|
||||||
Metal
|
|
||||||
};
|
|
||||||
|
|
||||||
class GPUSampler
|
class GPUSampler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -551,7 +541,7 @@ public:
|
||||||
virtual RenderAPI GetRenderAPI() const = 0;
|
virtual RenderAPI GetRenderAPI() const = 0;
|
||||||
|
|
||||||
bool Create(const std::string_view& adapter, const std::string_view& shader_cache_path, u32 shader_cache_version,
|
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);
|
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features, Error* error);
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
|
@ -646,8 +636,12 @@ public:
|
||||||
/// Renders ImGui screen elements. Call before EndPresent().
|
/// Renders ImGui screen elements. Call before EndPresent().
|
||||||
void RenderImGui();
|
void RenderImGui();
|
||||||
|
|
||||||
ALWAYS_INLINE bool IsVsyncEnabled() const { return m_vsync_enabled; }
|
ALWAYS_INLINE DisplaySyncMode GetSyncMode() const { return m_sync_mode; }
|
||||||
virtual void SetVSync(bool enabled) = 0;
|
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 bool IsDebugDevice() const { return m_debug_device; }
|
||||||
ALWAYS_INLINE size_t GetVRAMUsage() const { return s_total_vram_usage; }
|
ALWAYS_INLINE size_t GetVRAMUsage() const { return s_total_vram_usage; }
|
||||||
|
@ -760,8 +754,8 @@ private:
|
||||||
protected:
|
protected:
|
||||||
static Statistics s_stats;
|
static Statistics s_stats;
|
||||||
|
|
||||||
|
DisplaySyncMode m_sync_mode = DisplaySyncMode::Disabled;
|
||||||
bool m_gpu_timing_enabled = false;
|
bool m_gpu_timing_enabled = false;
|
||||||
bool m_vsync_enabled = false;
|
|
||||||
bool m_debug_device = 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;
|
bool SetGPUTimingEnabled(bool enabled) override;
|
||||||
float GetAndResetAccumulatedGPUTime() override;
|
float GetAndResetAccumulatedGPUTime() override;
|
||||||
|
|
||||||
void SetVSync(bool enabled) override;
|
void SetSyncMode(DisplaySyncMode mode) override;
|
||||||
|
|
||||||
bool BeginPresent(bool skip_present) override;
|
bool BeginPresent(bool skip_present) override;
|
||||||
void EndPresent() override;
|
void EndPresent() override;
|
||||||
|
|
|
@ -124,13 +124,16 @@ bool MetalDevice::GetHostRefreshRate(float* refresh_rate)
|
||||||
return GPUDevice::GetHostRefreshRate(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)
|
if (m_layer != nil)
|
||||||
|
{
|
||||||
|
const bool enabled = (mode == DisplaySyncMode::VSync || mode == DisplaySyncMode::VSyncRelaxed);
|
||||||
[m_layer setDisplaySyncEnabled:enabled];
|
[m_layer setDisplaySyncEnabled:enabled];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
|
bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
|
||||||
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
|
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features,
|
||||||
|
@ -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);
|
DebugAssert(m_layer_pass_desc == nil);
|
||||||
m_layer_pass_desc = [[MTLRenderPassDescriptor renderPassDescriptor] retain];
|
m_layer_pass_desc = [[MTLRenderPassDescriptor renderPassDescriptor] retain];
|
||||||
|
|
|
@ -236,12 +236,12 @@ void OpenGLDevice::InsertDebugMessage(const char* msg)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDevice::SetVSync(bool enabled)
|
void OpenGLDevice::SetSyncMode(DisplaySyncMode mode)
|
||||||
{
|
{
|
||||||
if (m_vsync_enabled == enabled)
|
if (m_sync_mode == mode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_vsync_enabled = enabled;
|
m_sync_mode = mode;
|
||||||
SetSwapInterval();
|
SetSwapInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,7 +577,8 @@ void OpenGLDevice::SetSwapInterval()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Window framebuffer has to be bound to call SetSwapInterval.
|
// 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;
|
GLint current_fbo = 0;
|
||||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_fbo);
|
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_fbo);
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
|
|
@ -98,7 +98,7 @@ public:
|
||||||
void Draw(u32 vertex_count, u32 base_vertex) override;
|
void Draw(u32 vertex_count, u32 base_vertex) override;
|
||||||
void DrawIndexed(u32 index_count, u32 base_index, 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;
|
bool BeginPresent(bool skip_present) override;
|
||||||
void EndPresent() override;
|
void EndPresent() override;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="..\..\dep\msvc\vsprops\Configurations.props" />
|
<Import Project="..\..\dep\msvc\vsprops\Configurations.props" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="gpu_types.h" />
|
||||||
<ClInclude Include="imgui_animated.h" />
|
<ClInclude Include="imgui_animated.h" />
|
||||||
<ClInclude Include="audio_stream.h" />
|
<ClInclude Include="audio_stream.h" />
|
||||||
<ClInclude Include="cd_image.h" />
|
<ClInclude Include="cd_image.h" />
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
<ClInclude Include="opengl_context_egl_wayland.h" />
|
<ClInclude Include="opengl_context_egl_wayland.h" />
|
||||||
<ClInclude Include="opengl_context_egl_x11.h" />
|
<ClInclude Include="opengl_context_egl_x11.h" />
|
||||||
<ClInclude Include="opengl_context_wgl.h" />
|
<ClInclude Include="opengl_context_wgl.h" />
|
||||||
|
<ClInclude Include="gpu_types.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="jit_code_buffer.cpp" />
|
<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)
|
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)
|
if (!m_swap_chain)
|
||||||
{
|
{
|
||||||
Error::SetStringView(error, "Failed to create swap chain");
|
Error::SetStringView(error, "Failed to create swap chain");
|
||||||
|
@ -2243,7 +2243,7 @@ bool VulkanDevice::UpdateWindow()
|
||||||
return false;
|
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)
|
if (!m_swap_chain)
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Failed to create swap chain");
|
Log_ErrorPrintf("Failed to create swap chain");
|
||||||
|
@ -2319,24 +2319,27 @@ std::string VulkanDevice::GetDriverInfo() const
|
||||||
return ret;
|
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;
|
return;
|
||||||
|
|
||||||
// This swap chain should not be used by the current buffer, thus safe to destroy.
|
// This swap chain should not be used by the current buffer, thus safe to destroy.
|
||||||
WaitForGPUIdle();
|
WaitForGPUIdle();
|
||||||
if (!m_swap_chain->SetVSync(enabled))
|
if (!m_swap_chain->SetSyncMode(mode))
|
||||||
{
|
{
|
||||||
// Try switching back to the old 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");
|
Panic("Failed to reset old vsync mode after failure");
|
||||||
m_swap_chain.reset();
|
m_swap_chain.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_vsync_enabled = enabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanDevice::BeginPresent(bool frame_skip)
|
bool VulkanDevice::BeginPresent(bool frame_skip)
|
||||||
|
|
|
@ -126,7 +126,7 @@ public:
|
||||||
bool SetGPUTimingEnabled(bool enabled) override;
|
bool SetGPUTimingEnabled(bool enabled) override;
|
||||||
float GetAndResetAccumulatedGPUTime() override;
|
float GetAndResetAccumulatedGPUTime() override;
|
||||||
|
|
||||||
void SetVSync(bool enabled) override;
|
void SetSyncMode(DisplaySyncMode mode) override;
|
||||||
|
|
||||||
bool BeginPresent(bool skip_present) override;
|
bool BeginPresent(bool skip_present) override;
|
||||||
void EndPresent() override;
|
void EndPresent() override;
|
||||||
|
|
|
@ -22,9 +22,69 @@
|
||||||
|
|
||||||
Log_SetChannel(VulkanDevice);
|
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)
|
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)
|
m_exclusive_fullscreen_control(exclusive_fullscreen_control)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -160,38 +220,19 @@ void VulkanSwapChain::DestroyVulkanSurface(VkInstance instance, WindowInfo* wi,
|
||||||
#endif
|
#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)
|
std::optional<bool> exclusive_fullscreen_control)
|
||||||
{
|
{
|
||||||
|
const VkPresentModeKHR requested_mode = GetPreferredPresentModeForVsyncMode(sync_mode);
|
||||||
std::unique_ptr<VulkanSwapChain> swap_chain =
|
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())
|
if (!swap_chain->CreateSwapChain())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return swap_chain;
|
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)
|
std::optional<VkSurfaceFormatKHR> VulkanSwapChain::SelectSurfaceFormat(VkSurfaceKHR surface)
|
||||||
{
|
{
|
||||||
VulkanDevice& dev = VulkanDevice::GetInstance();
|
VulkanDevice& dev = VulkanDevice::GetInstance();
|
||||||
|
@ -232,44 +273,8 @@ std::optional<VkSurfaceFormatKHR> VulkanSwapChain::SelectSurfaceFormat(VkSurface
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* PresentModeToString(VkPresentModeKHR mode)
|
std::optional<VkPresentModeKHR> VulkanSwapChain::SelectPresentMode(VkSurfaceKHR surface,
|
||||||
{
|
VkPresentModeKHR requested_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)
|
|
||||||
{
|
{
|
||||||
VulkanDevice& dev = VulkanDevice::GetInstance();
|
VulkanDevice& dev = VulkanDevice::GetInstance();
|
||||||
VkResult res;
|
VkResult res;
|
||||||
|
@ -294,18 +299,17 @@ std::optional<VkPresentModeKHR> VulkanSwapChain::SelectPresentMode(VkSurfaceKHR
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use preferred mode if available.
|
// Use preferred mode if available.
|
||||||
const VkPresentModeKHR preferred_mode = GetPreferredPresentModeForVsyncMode(vsync);
|
|
||||||
VkPresentModeKHR selected_mode;
|
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.
|
// Prefer mailbox over fifo for adaptive vsync/no-vsync.
|
||||||
selected_mode = VK_PRESENT_MODE_MAILBOX_KHR;
|
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.
|
// Fallback to FIFO if we're using any kind of vsync.
|
||||||
// This should never fail, FIFO is mandated.
|
// This should never fail, FIFO is mandated.
|
||||||
|
@ -317,7 +321,7 @@ std::optional<VkPresentModeKHR> VulkanSwapChain::SelectPresentMode(VkSurfaceKHR
|
||||||
selected_mode = present_modes[0];
|
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));
|
PresentModeToString(selected_mode));
|
||||||
|
|
||||||
return selected_mode;
|
return selected_mode;
|
||||||
|
@ -329,7 +333,7 @@ bool VulkanSwapChain::CreateSwapChain()
|
||||||
|
|
||||||
// Select swap chain format and present mode
|
// Select swap chain format and present mode
|
||||||
std::optional<VkSurfaceFormatKHR> surface_format = SelectSurfaceFormat(m_surface);
|
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())
|
if (!surface_format.has_value() || !present_mode.has_value())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -468,6 +472,7 @@ bool VulkanSwapChain::CreateSwapChain()
|
||||||
m_window_info.surface_width = std::max(1u, size.width);
|
m_window_info.surface_width = std::max(1u, size.width);
|
||||||
m_window_info.surface_height = std::max(1u, size.height);
|
m_window_info.surface_height = std::max(1u, size.height);
|
||||||
m_window_info.surface_format = VulkanDevice::GetFormatForVkFormat(surface_format->format);
|
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)
|
if (m_window_info.surface_format == GPUTexture::Format::Unknown)
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Unknown Vulkan surface format %u", static_cast<u32>(surface_format->format));
|
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;
|
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;
|
return true;
|
||||||
|
|
||||||
m_vsync_mode = mode;
|
m_requested_present_mode = present_mode;
|
||||||
|
|
||||||
// Recreate the swap chain with the new present mode.
|
// Recreate the swap chain with the new present mode.
|
||||||
Log_VerbosePrintf("Recreating swap chain to change 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);
|
static void DestroyVulkanSurface(VkInstance instance, WindowInfo* wi, VkSurfaceKHR surface);
|
||||||
|
|
||||||
// Create a new swap chain from a pre-existing 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);
|
std::optional<bool> exclusive_fullscreen_control);
|
||||||
|
|
||||||
ALWAYS_INLINE VkSurfaceKHR GetSurface() const { return m_surface; }
|
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).
|
// 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();
|
VkResult AcquireNextImage();
|
||||||
void ReleaseCurrentImage();
|
void ReleaseCurrentImage();
|
||||||
|
|
||||||
|
@ -70,19 +73,18 @@ public:
|
||||||
bool ResizeSwapChain(u32 new_width = 0, u32 new_height = 0, float new_scale = 1.0f);
|
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.
|
// Change vsync enabled state. This may fail as it causes a swapchain recreation.
|
||||||
bool SetVSync(bool mode);
|
bool SetSyncMode(DisplaySyncMode mode);
|
||||||
|
|
||||||
private:
|
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);
|
std::optional<bool> exclusive_fullscreen_control);
|
||||||
|
|
||||||
static std::optional<VkSurfaceFormatKHR> SelectSurfaceFormat(VkSurfaceKHR surface);
|
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();
|
bool CreateSwapChain();
|
||||||
void DestroySwapChain();
|
void DestroySwapChain();
|
||||||
|
|
||||||
bool SetupSwapChainImages();
|
|
||||||
void DestroySwapChainImages();
|
void DestroySwapChainImages();
|
||||||
|
|
||||||
void DestroySurface();
|
void DestroySurface();
|
||||||
|
@ -109,7 +111,8 @@ private:
|
||||||
std::vector<ImageSemaphores> m_semaphores;
|
std::vector<ImageSemaphores> m_semaphores;
|
||||||
|
|
||||||
VkFormat m_format = VK_FORMAT_UNDEFINED;
|
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_image = 0;
|
||||||
u32 m_current_semaphore = 0;
|
u32 m_current_semaphore = 0;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue