Settings: Expose exclusive fullscreen control

This commit is contained in:
Stenzek 2023-12-25 23:43:39 +10:00
parent 46e0afd2d4
commit 62d2f12236
No known key found for this signature in database
18 changed files with 111 additions and 30 deletions

View file

@ -241,6 +241,13 @@ bool Host::CreateGPUDevice(RenderAPI api)
Log_InfoPrintf("Trying to create a %s GPU device...", GPUDevice::RenderAPIToString(api));
g_gpu_device = GPUDevice::CreateDeviceForAPI(api);
std::optional<bool> exclusive_fullscreen_control;
if (g_settings.display_exclusive_fullscreen_control != DisplayExclusiveFullscreenControl::Automatic)
{
exclusive_fullscreen_control =
(g_settings.display_exclusive_fullscreen_control == DisplayExclusiveFullscreenControl::Allowed);
}
u32 disabled_features = 0;
if (g_settings.gpu_disable_dual_source_blend)
disabled_features |= GPUDevice::FEATURE_MASK_DUAL_SOURCE_BLEND;
@ -249,11 +256,12 @@ bool Host::CreateGPUDevice(RenderAPI api)
// TODO: FSUI should always use vsync..
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, static_cast<GPUDevice::FeatureMask>(disabled_features)))
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)))
{
Log_ErrorPrintf("Failed to create GPU device.");
if (g_gpu_device)

View file

@ -236,6 +236,12 @@ void Settings::Load(SettingsInterface& si)
display_scaling =
ParseDisplayScaling(si.GetStringValue("Display", "Scaling", GetDisplayScalingName(DEFAULT_DISPLAY_SCALING)).c_str())
.value_or(DEFAULT_DISPLAY_SCALING);
display_exclusive_fullscreen_control =
ParseDisplayExclusiveFullscreenControl(
si.GetStringValue("Display", "ExclusiveFullscreenControl",
GetDisplayExclusiveFullscreenControlName(DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL))
.c_str())
.value_or(DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL);
display_force_4_3_for_24bit = si.GetBoolValue("Display", "Force4_3For24Bit", false);
display_active_start_offset = static_cast<s16>(si.GetIntValue("Display", "ActiveStartOffset", 0));
display_active_end_offset = static_cast<s16>(si.GetIntValue("Display", "ActiveEndOffset", 0));
@ -475,6 +481,8 @@ 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", "ExclusiveFullscreenControl",
GetDisplayExclusiveFullscreenControlName(display_exclusive_fullscreen_control));
si.SetIntValue("Display", "CustomAspectRatioNumerator", display_aspect_ratio_custom_numerator);
si.GetIntValue("Display", "CustomAspectRatioDenominator", display_aspect_ratio_custom_denominator);
si.SetBoolValue("Display", "ShowOSDMessages", display_show_osd_messages);
@ -1238,6 +1246,42 @@ 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_exclusive_fullscreen_mode_names = {
"Automatic",
"Disallowed",
"Allowed",
};
static constexpr const std::array s_display_exclusive_fullscreen_mode_display_names = {
TRANSLATE_NOOP("Settings", "Automatic (Default)"),
TRANSLATE_NOOP("Settings", "Disallowed"),
TRANSLATE_NOOP("Settings", "Allowed"),
};
std::optional<DisplayExclusiveFullscreenControl> Settings::ParseDisplayExclusiveFullscreenControl(const char* str)
{
int index = 0;
for (const char* name : s_display_exclusive_fullscreen_mode_names)
{
if (StringUtil::Strcasecmp(name, str) == 0)
return static_cast<DisplayExclusiveFullscreenControl>(index);
index++;
}
return std::nullopt;
}
const char* Settings::GetDisplayExclusiveFullscreenControlName(DisplayExclusiveFullscreenControl mode)
{
return s_display_exclusive_fullscreen_mode_names[static_cast<int>(mode)];
}
const char* Settings::GetDisplayExclusiveFullscreenControlDisplayName(DisplayExclusiveFullscreenControl mode)
{
return Host::TranslateToCString("Settings",
s_display_exclusive_fullscreen_mode_display_names[static_cast<int>(mode)]);
}
static constexpr const std::array s_audio_backend_names = {
"Null",
#ifdef ENABLE_CUBEB

View file

@ -124,6 +124,7 @@ struct Settings
DisplayAspectRatio display_aspect_ratio = DEFAULT_DISPLAY_ASPECT_RATIO;
DisplayAlignment display_alignment = DEFAULT_DISPLAY_ALIGNMENT;
DisplayScalingMode display_scaling = DEFAULT_DISPLAY_SCALING;
DisplayExclusiveFullscreenControl display_exclusive_fullscreen_control = DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL;
u16 display_aspect_ratio_custom_numerator = 0;
u16 display_aspect_ratio_custom_denominator = 0;
s16 display_active_start_offset = 0;
@ -391,6 +392,10 @@ struct Settings
static const char* GetDisplayScalingName(DisplayScalingMode mode);
static const char* GetDisplayScalingDisplayName(DisplayScalingMode mode);
static std::optional<DisplayExclusiveFullscreenControl> ParseDisplayExclusiveFullscreenControl(const char* str);
static const char* GetDisplayExclusiveFullscreenControlName(DisplayExclusiveFullscreenControl mode);
static const char* GetDisplayExclusiveFullscreenControlDisplayName(DisplayExclusiveFullscreenControl mode);
static std::optional<AudioBackend> ParseAudioBackend(const char* str);
static const char* GetAudioBackendName(AudioBackend backend);
static const char* GetAudioBackendDisplayName(AudioBackend backend);
@ -450,6 +455,8 @@ 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 DisplayExclusiveFullscreenControl DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL =
DisplayExclusiveFullscreenControl::Automatic;
static constexpr float DEFAULT_OSD_SCALE = 100.0f;
static constexpr u8 DEFAULT_CDROM_READAHEAD_SECTORS = 8;

View file

@ -3509,12 +3509,14 @@ void System::SetCheatList(std::unique_ptr<CheatList> cheats)
void System::CheckForSettingsChanges(const Settings& old_settings)
{
if (IsValid() && (g_settings.gpu_renderer != old_settings.gpu_renderer ||
g_settings.gpu_use_debug_device != old_settings.gpu_use_debug_device ||
g_settings.gpu_threaded_presentation != old_settings.gpu_threaded_presentation ||
g_settings.gpu_disable_shader_cache != old_settings.gpu_disable_shader_cache ||
g_settings.gpu_disable_dual_source_blend != old_settings.gpu_disable_dual_source_blend ||
g_settings.gpu_disable_framebuffer_fetch != old_settings.gpu_disable_framebuffer_fetch))
if (IsValid() &&
(g_settings.gpu_renderer != old_settings.gpu_renderer ||
g_settings.gpu_use_debug_device != old_settings.gpu_use_debug_device ||
g_settings.gpu_threaded_presentation != old_settings.gpu_threaded_presentation ||
g_settings.gpu_disable_shader_cache != old_settings.gpu_disable_shader_cache ||
g_settings.gpu_disable_dual_source_blend != old_settings.gpu_disable_dual_source_blend ||
g_settings.gpu_disable_framebuffer_fetch != old_settings.gpu_disable_framebuffer_fetch ||
g_settings.display_exclusive_fullscreen_control != old_settings.display_exclusive_fullscreen_control))
{
// if debug device/threaded presentation change, we need to recreate the whole display
const bool recreate_device =
@ -3522,7 +3524,8 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
g_settings.gpu_threaded_presentation != old_settings.gpu_threaded_presentation ||
g_settings.gpu_disable_shader_cache != old_settings.gpu_disable_shader_cache ||
g_settings.gpu_disable_dual_source_blend != old_settings.gpu_disable_dual_source_blend ||
g_settings.gpu_disable_framebuffer_fetch != old_settings.gpu_disable_framebuffer_fetch);
g_settings.gpu_disable_framebuffer_fetch != old_settings.gpu_disable_framebuffer_fetch ||
g_settings.display_exclusive_fullscreen_control != old_settings.display_exclusive_fullscreen_control);
Host::AddIconOSDMessage("RendererSwitch", ICON_FA_PAINT_ROLLER,
fmt::format(TRANSLATE_FS("OSDMessage", "Switching to {}{} GPU renderer."),

View file

@ -143,6 +143,14 @@ enum class DisplayScalingMode : u8
Count
};
enum class DisplayExclusiveFullscreenControl : u8
{
Automatic,
Disallowed,
Allowed,
Count
};
enum class AudioBackend : u8
{
Null,

View file

@ -276,6 +276,11 @@ void AdvancedSettingsWidget::addTweakOptions()
addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Apply Compatibility Settings"), "Main",
"ApplyCompatibilitySettings", true);
addIntRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Display FPS Limit"), "Display", "MaxFPS", 0, 1000, 0);
addChoiceTweakOption(
m_dialog, m_ui.tweakOptionTable, tr("Exclusive Fullscreen Control"), "Display", "ExclusiveFullscreenControl",
&Settings::ParseDisplayExclusiveFullscreenControl, &Settings::GetDisplayExclusiveFullscreenControlName,
&Settings::GetDisplayExclusiveFullscreenControlDisplayName,
static_cast<u32>(DisplayExclusiveFullscreenControl::Count), Settings::DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL);
addMSAATweakOption(m_dialog, m_ui.tweakOptionTable, tr("Multisample Antialiasing"));
@ -377,6 +382,7 @@ void AdvancedSettingsWidget::onResetToDefaultClicked()
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Show frame times
setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Apply compatibility settings
setIntRangeTweakOption(m_ui.tweakOptionTable, i++, 0); // Display FPS limit
setChoiceTweakOption(m_ui.tweakOptionTable, i++, Settings::DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL);
setChoiceTweakOption(m_ui.tweakOptionTable, i++, 0); // Multisample antialiasing
setChoiceTweakOption(m_ui.tweakOptionTable, i++, 0); // Wireframe mode
setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // PGXP vertex cache
@ -433,6 +439,7 @@ void AdvancedSettingsWidget::onResetToDefaultClicked()
sif->DeleteValue("Display", "LineStartOffset");
sif->DeleteValue("Display", "LineEndOffset");
sif->DeleteValue("Display", "StretchVertically");
sif->DeleteValue("Display", "ExclusiveFullscreenControl");
sif->DeleteValue("GPU", "Multisamples");
sif->DeleteValue("GPU", "PerSampleShading");
sif->DeleteValue("GPU", "PGXPVertexCache");

View file

@ -64,7 +64,7 @@ bool D3D11Device::HasSurface() const
}
bool D3D11Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features)
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features)
{
std::unique_lock lock(s_instance_mutex);

View file

@ -107,7 +107,7 @@ public:
protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features) override;
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) override;
void DestroyDevice() override;
private:

View file

@ -117,7 +117,7 @@ D3D12Device::ComPtr<ID3D12RootSignature> D3D12Device::CreateRootSignature(const
}
bool D3D12Device::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features)
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features)
{
std::unique_lock lock(s_instance_mutex);

View file

@ -175,7 +175,7 @@ public:
protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features) override;
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) override;
void DestroyDevice() override;
bool ReadPipelineCache(const std::string& filename) override;

View file

@ -258,7 +258,7 @@ 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,
FeatureMask disabled_features)
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features)
{
m_vsync_enabled = vsync;
m_debug_device = debug_device;
@ -269,7 +269,7 @@ bool GPUDevice::Create(const std::string_view& adapter, const std::string_view&
return false;
}
if (!CreateDevice(adapter, threaded_presentation, disabled_features))
if (!CreateDevice(adapter, threaded_presentation, exclusive_fullscreen_control, disabled_features))
{
Log_ErrorPrintf("Failed to create device.");
return false;

View file

@ -536,7 +536,8 @@ 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, FeatureMask disabled_features);
bool debug_device, bool vsync, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features);
void Destroy();
virtual bool HasSurface() const = 0;
@ -651,7 +652,7 @@ public:
protected:
virtual bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features) = 0;
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) = 0;
virtual void DestroyDevice() = 0;
std::string GetShaderCacheBaseName(const std::string_view& type) const;
@ -775,7 +776,8 @@ struct GLAutoPop
#define GL_INS(msg) g_gpu_device->InsertDebugMessage(msg)
#define GL_OBJECT_NAME(obj, name) (obj)->SetDebugName(name)
#define GL_SCOPE_FMT(...) GLAutoPop gl_auto_pop((g_gpu_device->PushDebugGroup(SmallString::from_format(__VA_ARGS__)), 0))
#define GL_SCOPE_FMT(...) \
GLAutoPop gl_auto_pop((g_gpu_device->PushDebugGroup(SmallString::from_format(__VA_ARGS__)), 0))
#define GL_PUSH_FMT(...) g_gpu_device->PushDebugGroup(SmallString::from_format(__VA_ARGS__))
#define GL_INS_FMT(...) g_gpu_device->InsertDebugMessage(SmallString::from_format(__VA_ARGS__))
#define GL_OBJECT_NAME_FMT(obj, ...) (obj)->SetDebugName(SmallString::from_format(__VA_ARGS__))

View file

@ -257,7 +257,7 @@ public:
protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features) override;
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) override;
void DestroyDevice() override;
private:

View file

@ -121,6 +121,7 @@ void MetalDevice::SetVSync(bool enabled)
}
bool MetalDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
std::optional<bool> exclusive_fullscreen_control,
FeatureMask disabled_features)
{
@autoreleasepool

View file

@ -307,7 +307,7 @@ bool OpenGLDevice::HasSurface() const
}
bool OpenGLDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features)
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features)
{
m_gl_context = GL::Context::Create(m_window_info);
if (!m_gl_context)

View file

@ -120,7 +120,7 @@ public:
protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features) override;
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) override;
void DestroyDevice() override;
bool ReadPipelineCache(const std::string& filename) override;

View file

@ -1836,12 +1836,11 @@ bool VulkanDevice::HasSurface() const
}
bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features)
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features)
{
std::unique_lock lock(s_instance_mutex);
bool enable_debug_utils = m_debug_device;
bool enable_validation_layer = m_debug_device;
std::optional<bool> exclusive_fullscreen_control;
if (!Vulkan::LoadVulkanLibrary())
{
@ -1953,9 +1952,11 @@ bool VulkanDevice::CreateDevice(const std::string_view& adapter, bool threaded_p
if (threaded_presentation)
StartPresentThread();
m_exclusive_fullscreen_control = exclusive_fullscreen_control;
if (surface != VK_NULL_HANDLE)
{
m_swap_chain = VulkanSwapChain::Create(m_window_info, surface, m_vsync_enabled, exclusive_fullscreen_control);
m_swap_chain = VulkanSwapChain::Create(m_window_info, surface, m_vsync_enabled, m_exclusive_fullscreen_control);
if (!m_swap_chain)
{
Log_ErrorPrintf("Failed to create swap chain");
@ -2174,8 +2175,7 @@ bool VulkanDevice::UpdateWindow()
return false;
}
// TODO: exclusive fullscreen control
m_swap_chain = VulkanSwapChain::Create(m_window_info, surface, m_vsync_enabled, std::nullopt);
m_swap_chain = VulkanSwapChain::Create(m_window_info, surface, m_vsync_enabled, m_exclusive_fullscreen_control);
if (!m_swap_chain)
{
Log_ErrorPrintf("Failed to create swap chain");

View file

@ -218,7 +218,7 @@ public:
protected:
bool CreateDevice(const std::string_view& adapter, bool threaded_presentation,
FeatureMask disabled_features) override;
std::optional<bool> exclusive_fullscreen_control, FeatureMask disabled_features) override;
void DestroyDevice() override;
bool ReadPipelineCache(const std::string& filename) override;
@ -428,6 +428,7 @@ private:
VkPhysicalDeviceProperties m_device_properties = {};
VkPhysicalDeviceDriverPropertiesKHR m_device_driver_properties = {};
OptionalExtensions m_optional_extensions = {};
std::optional<bool> m_exclusive_fullscreen_control;
std::unique_ptr<VulkanSwapChain> m_swap_chain;
std::unique_ptr<VulkanTexture> m_null_texture;