diff --git a/src/core/fullscreen_ui.cpp b/src/core/fullscreen_ui.cpp index fc9d44d6a..72b5541ae 100644 --- a/src/core/fullscreen_ui.cpp +++ b/src/core/fullscreen_ui.cpp @@ -2484,7 +2484,7 @@ void FullscreenUI::DrawSettingsWindow() static constexpr std::array<const char*, static_cast<u32>(SettingsPage::Count)> titles = { {FSUI_NSTR("Summary"), FSUI_NSTR("Interface Settings"), FSUI_NSTR("Console Settings"), FSUI_NSTR("Emulation Settings"), FSUI_NSTR("BIOS Settings"), FSUI_NSTR("Controller Settings"), - FSUI_NSTR("Hotkey Settings"), FSUI_NSTR("Memory Card Settings"), FSUI_NSTR("Display Settings"), + FSUI_NSTR("Hotkey Settings"), FSUI_NSTR("Memory Card Settings"), FSUI_NSTR("Graphics Settings"), FSUI_NSTR("Post-Processing Settings"), FSUI_NSTR("Audio Settings"), FSUI_NSTR("Achievements Settings"), FSUI_NSTR("Advanced Settings")}}; @@ -3898,7 +3898,7 @@ void FullscreenUI::DrawDisplaySettingsPage() MenuHeading(FSUI_CSTR("Rendering")); DrawIntListSetting( - bsi, FSUI_CSTR("Internal Resolution Scale"), + bsi, FSUI_CSTR("Internal Resolution"), FSUI_CSTR("Scales internal VRAM resolution by the specified multiplier. Some games require 1x VRAM resolution."), "GPU", "ResolutionScale", 1, resolution_scales.data(), resolution_scales.size(), true, 0, is_hardware); @@ -3975,9 +3975,19 @@ void FullscreenUI::DrawDisplaySettingsPage() "Display", "Scaling", Settings::DEFAULT_DISPLAY_SCALING, &Settings::ParseDisplayScaling, &Settings::GetDisplayScalingName, &Settings::GetDisplayScalingDisplayName, DisplayScalingMode::Count); - DrawToggleSetting(bsi, FSUI_CSTR("Internal Resolution Screenshots"), - FSUI_CSTR("Saves screenshots at internal render resolution and without postprocessing."), "Display", - "InternalResolutionScreenshots", false); + DrawEnumSetting(bsi, FSUI_CSTR("Screenshot Size"), + FSUI_CSTR("Determines the size of screenshots created by DuckStation."), "Display", "ScreenshotMode", + Settings::DEFAULT_DISPLAY_SCREENSHOT_MODE, &Settings::ParseDisplayScreenshotMode, + &Settings::GetDisplayScreenshotModeName, &Settings::GetDisplayScreenshotModeDisplayName, + DisplayScreenshotMode::Count); + DrawEnumSetting(bsi, FSUI_CSTR("Screenshot Format"), + FSUI_CSTR("Determines the format that screenshots will be saved/compressed with."), "Display", + "ScreenshotFormat", Settings::DEFAULT_DISPLAY_SCREENSHOT_FORMAT, + &Settings::ParseDisplayScreenshotFormat, &Settings::GetDisplayScreenshotFormatName, + &Settings::GetDisplayScreenshotFormatDisplayName, DisplayScreenshotFormat::Count); + DrawIntRangeSetting(bsi, FSUI_CSTR("Screenshot Quality"), + FSUI_CSTR("Selects the quality at which screenshots will be compressed."), "Display", + "ScreenshotQuality", Settings::DEFAULT_DISPLAY_SCREENSHOT_QUALITY, 1, 100, "%d%%"); MenuHeading(FSUI_CSTR("Enhancements")); DrawToggleSetting( @@ -6651,7 +6661,9 @@ TRANSLATE_NOOP("FullscreenUI", "Determines quality of audio when not running at TRANSLATE_NOOP("FullscreenUI", "Determines that field that the game list will be sorted by."); TRANSLATE_NOOP("FullscreenUI", "Determines the amount of audio buffered before being pulled by the host API."); TRANSLATE_NOOP("FullscreenUI", "Determines the emulated hardware type."); +TRANSLATE_NOOP("FullscreenUI", "Determines the format that screenshots will be saved/compressed with."); TRANSLATE_NOOP("FullscreenUI", "Determines the position on the screen when black borders must be added."); +TRANSLATE_NOOP("FullscreenUI", "Determines the size of screenshots created by DuckStation."); TRANSLATE_NOOP("FullscreenUI", "Determines whether a prompt will be displayed to confirm shutting down the emulator/game when the hotkey is pressed."); TRANSLATE_NOOP("FullscreenUI", "Device Settings"); TRANSLATE_NOOP("FullscreenUI", "Disable All Enhancements"); @@ -6754,6 +6766,7 @@ TRANSLATE_NOOP("FullscreenUI", "Genre: %s"); TRANSLATE_NOOP("FullscreenUI", "GitHub Repository"); TRANSLATE_NOOP("FullscreenUI", "Global Slot {0} - {1}##global_slot_{0}"); TRANSLATE_NOOP("FullscreenUI", "Global Slot {0}##global_slot_{0}"); +TRANSLATE_NOOP("FullscreenUI", "Graphics Settings"); TRANSLATE_NOOP("FullscreenUI", "Hardcore Mode"); TRANSLATE_NOOP("FullscreenUI", "Hardcore mode will be enabled on next game restart."); TRANSLATE_NOOP("FullscreenUI", "Hide Cursor In Fullscreen"); @@ -6773,8 +6786,7 @@ TRANSLATE_NOOP("FullscreenUI", "Input profile '{}' loaded."); TRANSLATE_NOOP("FullscreenUI", "Input profile '{}' saved."); TRANSLATE_NOOP("FullscreenUI", "Integration"); TRANSLATE_NOOP("FullscreenUI", "Interface Settings"); -TRANSLATE_NOOP("FullscreenUI", "Internal Resolution Scale"); -TRANSLATE_NOOP("FullscreenUI", "Internal Resolution Screenshots"); +TRANSLATE_NOOP("FullscreenUI", "Internal Resolution"); TRANSLATE_NOOP("FullscreenUI", "Issue Tracker"); TRANSLATE_NOOP("FullscreenUI", "Last Played"); TRANSLATE_NOOP("FullscreenUI", "Last Played: %s"); @@ -6926,7 +6938,6 @@ TRANSLATE_NOOP("FullscreenUI", "Save Screenshot"); TRANSLATE_NOOP("FullscreenUI", "Save State"); TRANSLATE_NOOP("FullscreenUI", "Save State On Exit"); TRANSLATE_NOOP("FullscreenUI", "Saved {:%c}"); -TRANSLATE_NOOP("FullscreenUI", "Saves screenshots at internal render resolution and without postprocessing."); TRANSLATE_NOOP("FullscreenUI", "Saves state periodically so you can rewind any mistakes while playing."); TRANSLATE_NOOP("FullscreenUI", "Scaled Dithering"); TRANSLATE_NOOP("FullscreenUI", "Scales internal VRAM resolution by the specified multiplier. Some games require 1x VRAM resolution."); @@ -6935,6 +6946,9 @@ TRANSLATE_NOOP("FullscreenUI", "Scaling"); TRANSLATE_NOOP("FullscreenUI", "Scan For New Games"); TRANSLATE_NOOP("FullscreenUI", "Scanning Subdirectories"); TRANSLATE_NOOP("FullscreenUI", "Screen Display"); +TRANSLATE_NOOP("FullscreenUI", "Screenshot Format"); +TRANSLATE_NOOP("FullscreenUI", "Screenshot Quality"); +TRANSLATE_NOOP("FullscreenUI", "Screenshot Size"); TRANSLATE_NOOP("FullscreenUI", "Search Directories"); TRANSLATE_NOOP("FullscreenUI", "Seek Speedup"); TRANSLATE_NOOP("FullscreenUI", "Select Device"); @@ -6942,6 +6956,7 @@ TRANSLATE_NOOP("FullscreenUI", "Select Disc Image"); TRANSLATE_NOOP("FullscreenUI", "Select Macro {} Binds"); TRANSLATE_NOOP("FullscreenUI", "Selects the GPU to use for rendering."); TRANSLATE_NOOP("FullscreenUI", "Selects the percentage of the normal clock speed the emulated hardware will run at."); +TRANSLATE_NOOP("FullscreenUI", "Selects the quality at which screenshots will be compressed."); TRANSLATE_NOOP("FullscreenUI", "Selects the resolution scale that will be applied to the final image. 1x will downsample to the original console resolution."); TRANSLATE_NOOP("FullscreenUI", "Selects the resolution to use in fullscreen modes."); TRANSLATE_NOOP("FullscreenUI", "Selects the view that the game list will open to."); diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 64cff9f10..9fdfeda77 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -1906,8 +1906,8 @@ Common::Rectangle<s32> GPU::CalculateDrawRect(s32 window_width, s32 window_heigh } static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string filename, FileSystem::ManagedCFilePtr fp, - bool clear_alpha, bool flip_y, u32 resize_width, u32 resize_height, - std::vector<u8> texture_data, u32 texture_data_stride, + u8 quality, bool clear_alpha, bool flip_y, u32 resize_width, + u32 resize_height, std::vector<u8> texture_data, u32 texture_data_stride, GPUTexture::Format texture_format) { @@ -1964,12 +1964,13 @@ static bool CompressAndWriteTextureToFile(u32 width, u32 height, std::string fil bool result = false; if (StringUtil::Strcasecmp(extension, ".png") == 0) { + // TODO: Use quality... libpng is better. result = (stbi_write_png_to_func(write_func, fp.get(), width, height, 4, texture_data.data(), texture_data_stride) != 0); } else if (StringUtil::Strcasecmp(extension, ".jpg") == 0) { - result = (stbi_write_jpg_to_func(write_func, fp.get(), width, height, 4, texture_data.data(), 95) != 0); + result = (stbi_write_jpg_to_func(write_func, fp.get(), width, height, 4, texture_data.data(), quality) != 0); } else if (StringUtil::Strcasecmp(extension, ".tga") == 0) { @@ -2072,14 +2073,16 @@ bool GPU::WriteDisplayTextureToFile(std::string filename, bool full_resolution / if (!compress_on_thread) { - return CompressAndWriteTextureToFile(read_width, read_height, std::move(filename), std::move(fp), clear_alpha, - flip_y, resize_width, resize_height, std::move(texture_data), - texture_data_stride, m_display_texture->GetFormat()); + return CompressAndWriteTextureToFile(read_width, read_height, std::move(filename), std::move(fp), + g_settings.display_screenshot_quality, clear_alpha, flip_y, resize_width, + resize_height, std::move(texture_data), texture_data_stride, + m_display_texture->GetFormat()); } std::thread compress_thread(CompressAndWriteTextureToFile, read_width, read_height, std::move(filename), - std::move(fp), clear_alpha, flip_y, resize_width, resize_height, std::move(texture_data), - texture_data_stride, m_display_texture->GetFormat()); + std::move(fp), g_settings.display_screenshot_quality, clear_alpha, flip_y, resize_width, + resize_height, std::move(texture_data), texture_data_stride, + m_display_texture->GetFormat()); compress_thread.detach(); return true; } @@ -2131,53 +2134,61 @@ bool GPU::RenderScreenshotToBuffer(u32 width, u32 height, const Common::Rectangl return true; } -bool GPU::RenderScreenshotToFile(std::string filename, bool internal_resolution /* = false */, - bool compress_on_thread /* = false */) +bool GPU::RenderScreenshotToFile(std::string filename, DisplayScreenshotMode mode, u8 quality, bool compress_on_thread) { u32 width = g_gpu_device->GetWindowWidth(); u32 height = g_gpu_device->GetWindowHeight(); Common::Rectangle<s32> draw_rect = CalculateDrawRect(width, height); + const bool internal_resolution = (mode != DisplayScreenshotMode::ScreenResolution); if (internal_resolution && m_display_texture_view_width != 0 && m_display_texture_view_height != 0) { - const u32 draw_width = static_cast<u32>(draw_rect.GetWidth()); - const u32 draw_height = static_cast<u32>(draw_rect.GetHeight()); - - // If internal res, scale the computed draw rectangle to the internal res. - // We re-use the draw rect because it's already been AR corrected. - const float sar = - static_cast<float>(m_display_texture_view_width) / static_cast<float>(m_display_texture_view_height); - const float dar = static_cast<float>(draw_width) / static_cast<float>(draw_height); - if (sar >= dar) + if (mode == DisplayScreenshotMode::InternalResolution) + { + const u32 draw_width = static_cast<u32>(draw_rect.GetWidth()); + const u32 draw_height = static_cast<u32>(draw_rect.GetHeight()); + + // If internal res, scale the computed draw rectangle to the internal res. + // We re-use the draw rect because it's already been AR corrected. + const float sar = + static_cast<float>(m_display_texture_view_width) / static_cast<float>(m_display_texture_view_height); + const float dar = static_cast<float>(draw_width) / static_cast<float>(draw_height); + if (sar >= dar) + { + // stretch height, preserve width + const float scale = static_cast<float>(m_display_texture_view_width) / static_cast<float>(draw_width); + width = m_display_texture_view_width; + height = static_cast<u32>(std::round(static_cast<float>(draw_height) * scale)); + } + else + { + // stretch width, preserve height + const float scale = static_cast<float>(m_display_texture_view_height) / static_cast<float>(draw_height); + width = static_cast<u32>(std::round(static_cast<float>(draw_width) * scale)); + height = m_display_texture_view_height; + } + + // DX11 won't go past 16K texture size. + const u32 max_texture_size = g_gpu_device->GetMaxTextureSize(); + if (width > max_texture_size) + { + height = static_cast<u32>(static_cast<float>(height) / + (static_cast<float>(width) / static_cast<float>(max_texture_size))); + width = max_texture_size; + } + if (height > max_texture_size) + { + height = max_texture_size; + width = static_cast<u32>(static_cast<float>(width) / + (static_cast<float>(height) / static_cast<float>(max_texture_size))); + } + } + else // if (mode == DisplayScreenshotMode::UncorrectedInternalResolution) { - // stretch height, preserve width - const float scale = static_cast<float>(m_display_texture_view_width) / static_cast<float>(draw_width); width = m_display_texture_view_width; - height = static_cast<u32>(std::round(static_cast<float>(draw_height) * scale)); - } - else - { - // stretch width, preserve height - const float scale = static_cast<float>(m_display_texture_view_height) / static_cast<float>(draw_height); - width = static_cast<u32>(std::round(static_cast<float>(draw_width) * scale)); height = m_display_texture_view_height; } - // DX11 won't go past 16K texture size. - constexpr u32 MAX_TEXTURE_SIZE = 16384; - if (width > MAX_TEXTURE_SIZE) - { - height = static_cast<u32>(static_cast<float>(height) / - (static_cast<float>(width) / static_cast<float>(MAX_TEXTURE_SIZE))); - width = MAX_TEXTURE_SIZE; - } - if (height > MAX_TEXTURE_SIZE) - { - height = MAX_TEXTURE_SIZE; - width = static_cast<u32>(static_cast<float>(width) / - (static_cast<float>(height) / static_cast<float>(MAX_TEXTURE_SIZE))); - } - // Remove padding, it's not part of the framebuffer. draw_rect.Set(0, 0, static_cast<s32>(width), static_cast<s32>(height)); } @@ -2203,14 +2214,14 @@ bool GPU::RenderScreenshotToFile(std::string filename, bool internal_resolution if (!compress_on_thread) { - return CompressAndWriteTextureToFile(width, height, std::move(filename), std::move(fp), true, + return CompressAndWriteTextureToFile(width, height, std::move(filename), std::move(fp), quality, true, g_gpu_device->UsesLowerLeftOrigin(), width, height, std::move(pixels), pixels_stride, pixels_format); } - std::thread compress_thread(CompressAndWriteTextureToFile, width, height, std::move(filename), std::move(fp), true, - g_gpu_device->UsesLowerLeftOrigin(), width, height, std::move(pixels), pixels_stride, - pixels_format); + std::thread compress_thread(CompressAndWriteTextureToFile, width, height, std::move(filename), std::move(fp), quality, + true, g_gpu_device->UsesLowerLeftOrigin(), width, height, std::move(pixels), + pixels_stride, pixels_format); compress_thread.detach(); return true; } diff --git a/src/core/gpu.h b/src/core/gpu.h index 9e5ad40b9..02ca0f0b3 100644 --- a/src/core/gpu.h +++ b/src/core/gpu.h @@ -209,7 +209,7 @@ public: std::vector<u8>* out_pixels, u32* out_stride, GPUTexture::Format* out_format); /// Helper function to save screenshot to PNG. - bool RenderScreenshotToFile(std::string filename, bool internal_resolution = false, bool compress_on_thread = false); + bool RenderScreenshotToFile(std::string filename, DisplayScreenshotMode mode, u8 quality, bool compress_on_thread); /// Draws the current display texture, with any post-processing. bool PresentDisplay(); diff --git a/src/core/host.cpp b/src/core/host.cpp index 0c4d685fa..73d618eb7 100644 --- a/src/core/host.cpp +++ b/src/core/host.cpp @@ -180,6 +180,12 @@ bool Host::RemoveValueFromBaseStringListSetting(const char* section, const char* ->RemoveFromStringList(section, key, value); } +bool Host::ContainsBaseSettingValue(const char* section, const char* key) +{ + std::unique_lock lock(s_settings_mutex); + return s_layered_settings_interface.GetLayer(LayeredSettingsInterface::LAYER_BASE)->ContainsValue(section, key); +} + void Host::DeleteBaseSettingValue(const char* section, const char* key) { std::unique_lock lock(s_settings_mutex); diff --git a/src/core/host.h b/src/core/host.h index 3cebf13e2..36b5ede06 100644 --- a/src/core/host.h +++ b/src/core/host.h @@ -47,6 +47,7 @@ void SetBaseStringSettingValue(const char* section, const char* key, const char* void SetBaseStringListSettingValue(const char* section, const char* key, const std::vector<std::string>& values); bool AddValueToBaseStringListSetting(const char* section, const char* key, const char* value); bool RemoveValueFromBaseStringListSetting(const char* section, const char* key, const char* value); +bool ContainsBaseSettingValue(const char* section, const char* key); void DeleteBaseSettingValue(const char* section, const char* key); void CommitBaseSettingChanges(); diff --git a/src/core/settings.cpp b/src/core/settings.cpp index b8f9e9246..448858ca3 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -249,6 +249,18 @@ void Settings::Load(SettingsInterface& si) GetDisplayExclusiveFullscreenControlName(DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL)) .c_str()) .value_or(DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL); + display_screenshot_mode = + ParseDisplayScreenshotMode( + si.GetStringValue("Display", "ScreenshotMode", GetDisplayScreenshotModeName(DEFAULT_DISPLAY_SCREENSHOT_MODE)) + .c_str()) + .value_or(DEFAULT_DISPLAY_SCREENSHOT_MODE); + display_screenshot_format = + ParseDisplayScreenshotFormat(si.GetStringValue("Display", "ScreenshotFormat", + GetDisplayScreenshotFormatName(DEFAULT_DISPLAY_SCREENSHOT_FORMAT)) + .c_str()) + .value_or(DEFAULT_DISPLAY_SCREENSHOT_FORMAT); + display_screenshot_quality = static_cast<u8>( + std::clamp<u32>(si.GetUIntValue("Display", "ScreenshotQuality", DEFAULT_DISPLAY_SCREENSHOT_QUALITY), 1, 100)); 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)); @@ -266,7 +278,6 @@ void Settings::Load(SettingsInterface& si) display_show_inputs = si.GetBoolValue("Display", "ShowInputs", false); display_show_enhancements = si.GetBoolValue("Display", "ShowEnhancements", false); display_all_frames = si.GetBoolValue("Display", "DisplayAllFrames", false); - display_internal_resolution_screenshots = si.GetBoolValue("Display", "InternalResolutionScreenshots", 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); @@ -495,6 +506,9 @@ void Settings::Save(SettingsInterface& si) const si.SetStringValue("Display", "Scaling", GetDisplayScalingName(display_scaling)); si.SetStringValue("Display", "ExclusiveFullscreenControl", GetDisplayExclusiveFullscreenControlName(display_exclusive_fullscreen_control)); + si.SetStringValue("Display", "ScreenshotMode", GetDisplayScreenshotModeName(display_screenshot_mode)); + si.SetStringValue("Display", "ScreenshotFormat", GetDisplayScreenshotFormatName(display_screenshot_format)); + si.SetUIntValue("Display", "ScreenshotQuality", display_screenshot_quality); 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); @@ -509,7 +523,6 @@ void Settings::Save(SettingsInterface& si) const si.SetBoolValue("Display", "ShowInputs", display_show_inputs); si.SetBoolValue("Display", "ShowEnhancements", display_show_enhancements); si.SetBoolValue("Display", "DisplayAllFrames", display_all_frames); - si.SetBoolValue("Display", "InternalResolutionScreenshots", display_internal_resolution_screenshots); si.SetBoolValue("Display", "StretchVertically", display_stretch_vertically); si.SetBoolValue("Display", "VSync", video_sync_enabled); si.SetFloatValue("Display", "MaxFPS", display_max_fps); @@ -945,16 +958,16 @@ static constexpr const std::array s_gpu_renderer_names = { static constexpr const std::array s_gpu_renderer_display_names = { TRANSLATE_NOOP("GPURenderer", "Automatic"), #ifdef _WIN32 - TRANSLATE_NOOP("GPURenderer", "Hardware (D3D11)"), TRANSLATE_NOOP("GPURenderer", "Hardware (D3D12)"), + TRANSLATE_NOOP("GPURenderer", "Direct3D 11"), TRANSLATE_NOOP("GPURenderer", "Direct3D 12"), #endif #ifdef __APPLE__ - TRANSLATE_NOOP("GPURenderer", "Hardware (Metal)"), + TRANSLATE_NOOP("GPURenderer", "Metal"), #endif #ifdef ENABLE_VULKAN - TRANSLATE_NOOP("GPURenderer", "Hardware (Vulkan)"), + TRANSLATE_NOOP("GPURenderer", "Vulkan"), #endif #ifdef ENABLE_OPENGL - TRANSLATE_NOOP("GPURenderer", "Hardware (OpenGL)"), + TRANSLATE_NOOP("GPURenderer", "OpenGL"), #endif TRANSLATE_NOOP("GPURenderer", "Software"), }; @@ -1011,6 +1024,44 @@ RenderAPI Settings::GetRenderAPIForRenderer(GPURenderer renderer) } } +GPURenderer Settings::GetRendererForRenderAPI(RenderAPI api) +{ + switch (api) + { +#ifdef _WIN32 + case RenderAPI::D3D11: + return GPURenderer::HardwareD3D11; + + case RenderAPI::D3D12: + return GPURenderer::HardwareD3D12; +#endif + +#ifdef __APPLE__ + case RenderAPI::Metal: + return GPURenderer::HardwareMetal; +#endif + +#ifdef ENABLE_VULKAN + case RenderAPI::Vulkan: + return GPURenderer::HardwareVulkan; +#endif + +#ifdef ENABLE_OPENGL + case RenderAPI::OpenGL: + case RenderAPI::OpenGLES: + return GPURenderer::HardwareOpenGL; +#endif + + default: + return GPURenderer::Automatic; + } +} + +GPURenderer Settings::GetAutomaticRenderer() +{ + return GetRendererForRenderAPI(GPUDevice::GetPreferredAPI()); +} + static constexpr const std::array s_texture_filter_names = { "Nearest", "Bilinear", "BilinearBinAlpha", "JINC2", "JINC2BinAlpha", "xBR", "xBRBinAlpha", }; @@ -1312,7 +1363,7 @@ static constexpr const std::array s_display_exclusive_fullscreen_mode_names = { "Allowed", }; static constexpr const std::array s_display_exclusive_fullscreen_mode_display_names = { - TRANSLATE_NOOP("Settings", "Automatic (Default)"), + TRANSLATE_NOOP("Settings", "Automatic"), TRANSLATE_NOOP("Settings", "Disallowed"), TRANSLATE_NOOP("Settings", "Allowed"), }; @@ -1342,6 +1393,89 @@ const char* Settings::GetDisplayExclusiveFullscreenControlDisplayName(DisplayExc s_display_exclusive_fullscreen_mode_display_names[static_cast<int>(mode)]); } +static constexpr const std::array s_display_screenshot_mode_names = { + "ScreenResolution", + "InternalResolution", + "UncorrectedInternalResolution", +}; +static constexpr const std::array s_display_screenshot_mode_display_names = { + TRANSLATE_NOOP("Settings", "Screen Resolution"), + TRANSLATE_NOOP("Settings", "Internal Resolution"), + TRANSLATE_NOOP("Settings", "Internal Resolution (Aspect Uncorrected)"), +}; + +std::optional<DisplayScreenshotMode> Settings::ParseDisplayScreenshotMode(const char* str) +{ + int index = 0; + for (const char* name : s_display_screenshot_mode_names) + { + if (StringUtil::Strcasecmp(name, str) == 0) + return static_cast<DisplayScreenshotMode>(index); + + index++; + } + + return std::nullopt; +} + +const char* Settings::GetDisplayScreenshotModeName(DisplayScreenshotMode mode) +{ + return s_display_screenshot_mode_names[static_cast<size_t>(mode)]; +} + +const char* Settings::GetDisplayScreenshotModeDisplayName(DisplayScreenshotMode mode) +{ + return Host::TranslateToCString("Settings", s_display_screenshot_mode_display_names[static_cast<size_t>(mode)]); +} + +static constexpr const std::array s_display_screenshot_format_names = { + "PNG", + "JPEG", + "TGA", + "BMP", +}; +static constexpr const std::array s_display_screenshot_format_display_names = { + TRANSLATE_NOOP("Settings", "PNG"), + TRANSLATE_NOOP("Settings", "JPEG"), + TRANSLATE_NOOP("Settings", "TGA"), + TRANSLATE_NOOP("Settings", "BMP"), +}; +static constexpr const std::array s_display_screenshot_format_extensions = { + "png", + "jpg", + "tga", + "bmp", +}; + +std::optional<DisplayScreenshotFormat> Settings::ParseDisplayScreenshotFormat(const char* str) +{ + int index = 0; + for (const char* name : s_display_screenshot_format_names) + { + if (StringUtil::Strcasecmp(name, str) == 0) + return static_cast<DisplayScreenshotFormat>(index); + + index++; + } + + return std::nullopt; +} + +const char* Settings::GetDisplayScreenshotFormatName(DisplayScreenshotFormat format) +{ + return s_display_screenshot_format_names[static_cast<size_t>(format)]; +} + +const char* Settings::GetDisplayScreenshotFormatDisplayName(DisplayScreenshotFormat mode) +{ + return Host::TranslateToCString("Settings", s_display_screenshot_format_display_names[static_cast<size_t>(mode)]); +} + +const char* Settings::GetDisplayScreenshotFormatExtension(DisplayScreenshotFormat format) +{ + return s_display_screenshot_format_extensions[static_cast<size_t>(format)]; +} + static constexpr const std::array s_audio_backend_names = { "Null", #ifdef ENABLE_CUBEB diff --git a/src/core/settings.h b/src/core/settings.h index d0c028327..73febe371 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -135,6 +135,9 @@ struct Settings DisplayAlignment display_alignment = DEFAULT_DISPLAY_ALIGNMENT; DisplayScalingMode display_scaling = DEFAULT_DISPLAY_SCALING; DisplayExclusiveFullscreenControl display_exclusive_fullscreen_control = DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL; + DisplayScreenshotMode display_screenshot_mode = DEFAULT_DISPLAY_SCREENSHOT_MODE; + DisplayScreenshotFormat display_screenshot_format = DEFAULT_DISPLAY_SCREENSHOT_FORMAT; + u8 display_screenshot_quality = DEFAULT_DISPLAY_SCREENSHOT_QUALITY; u16 display_aspect_ratio_custom_numerator = 0; u16 display_aspect_ratio_custom_denominator = 0; s16 display_active_start_offset = 0; @@ -155,7 +158,6 @@ struct Settings bool display_show_inputs : 1 = false; bool display_show_enhancements : 1 = false; bool display_all_frames : 1 = false; - bool display_internal_resolution_screenshots : 1 = false; bool display_stretch_vertically : 1 = false; bool video_sync_enabled = DEFAULT_VSYNC_VALUE; float display_osd_scale = 100.0f; @@ -374,6 +376,8 @@ struct Settings static const char* GetRendererName(GPURenderer renderer); static const char* GetRendererDisplayName(GPURenderer renderer); static RenderAPI GetRenderAPIForRenderer(GPURenderer renderer); + static GPURenderer GetRendererForRenderAPI(RenderAPI api); + static GPURenderer GetAutomaticRenderer(); static std::optional<GPUTextureFilter> ParseTextureFilterName(const char* str); static const char* GetTextureFilterName(GPUTextureFilter filter); @@ -411,6 +415,15 @@ struct Settings static const char* GetDisplayExclusiveFullscreenControlName(DisplayExclusiveFullscreenControl mode); static const char* GetDisplayExclusiveFullscreenControlDisplayName(DisplayExclusiveFullscreenControl mode); + static std::optional<DisplayScreenshotMode> ParseDisplayScreenshotMode(const char* str); + static const char* GetDisplayScreenshotModeName(DisplayScreenshotMode mode); + static const char* GetDisplayScreenshotModeDisplayName(DisplayScreenshotMode mode); + + static std::optional<DisplayScreenshotFormat> ParseDisplayScreenshotFormat(const char* str); + static const char* GetDisplayScreenshotFormatName(DisplayScreenshotFormat mode); + static const char* GetDisplayScreenshotFormatDisplayName(DisplayScreenshotFormat mode); + static const char* GetDisplayScreenshotFormatExtension(DisplayScreenshotFormat mode); + static std::optional<AudioBackend> ParseAudioBackend(const char* str); static const char* GetAudioBackendName(AudioBackend backend); static const char* GetAudioBackendDisplayName(AudioBackend backend); @@ -473,6 +486,9 @@ struct Settings static constexpr DisplayScalingMode DEFAULT_DISPLAY_SCALING = DisplayScalingMode::BilinearSmooth; static constexpr DisplayExclusiveFullscreenControl DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL = DisplayExclusiveFullscreenControl::Automatic; + static constexpr DisplayScreenshotMode DEFAULT_DISPLAY_SCREENSHOT_MODE = DisplayScreenshotMode::ScreenResolution; + static constexpr DisplayScreenshotFormat DEFAULT_DISPLAY_SCREENSHOT_FORMAT = DisplayScreenshotFormat::PNG; + static constexpr u8 DEFAULT_DISPLAY_SCREENSHOT_QUALITY = 85; static constexpr float DEFAULT_OSD_SCALE = 100.0f; static constexpr u8 DEFAULT_CDROM_READAHEAD_SECTORS = 8; diff --git a/src/core/system.cpp b/src/core/system.cpp index bd82b83fc..0dc922386 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -4306,8 +4306,8 @@ void System::StopDumpingAudio() Host::AddOSDMessage(TRANSLATE_STR("OSDMessage", "Stopped dumping audio."), 5.0f); } -bool System::SaveScreenshot(const char* filename /* = nullptr */, bool full_resolution /* = true */, - bool apply_aspect_ratio /* = true */, bool compress_on_thread /* = true */) +bool System::SaveScreenshot(const char* filename, DisplayScreenshotMode mode, DisplayScreenshotFormat format, + u8 quality, bool compress_on_thread) { if (!System::IsValid()) return false; @@ -4316,7 +4316,7 @@ bool System::SaveScreenshot(const char* filename /* = nullptr */, bool full_reso if (!filename) { const auto& code = System::GetGameSerial(); - const char* extension = "png"; + const char* extension = Settings::GetDisplayScreenshotFormatExtension(format); if (code.empty()) { auto_filename = @@ -4337,10 +4337,7 @@ bool System::SaveScreenshot(const char* filename /* = nullptr */, bool full_reso return false; } - const bool screenshot_saved = - g_gpu->RenderScreenshotToFile(filename, g_settings.display_internal_resolution_screenshots, compress_on_thread); - - if (!screenshot_saved) + if (!g_gpu->RenderScreenshotToFile(filename, mode, quality, compress_on_thread)) { Host::AddFormattedOSDMessage(10.0f, TRANSLATE("OSDMessage", "Failed to save screenshot to '%s'"), filename); return false; diff --git a/src/core/system.h b/src/core/system.h index f847e62f9..0aa7b6f66 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -416,9 +416,10 @@ bool StartDumpingAudio(const char* filename = nullptr); /// Stops dumping audio to file if it has been started. void StopDumpingAudio(); -/// Saves a screenshot to the specified file. IF no file name is provided, one will be generated automatically. -bool SaveScreenshot(const char* filename = nullptr, bool full_resolution = true, bool apply_aspect_ratio = true, - bool compress_on_thread = true); +/// Saves a screenshot to the specified file. If no file name is provided, one will be generated automatically. +bool SaveScreenshot(const char* filename = nullptr, DisplayScreenshotMode mode = g_settings.display_screenshot_mode, + DisplayScreenshotFormat format = g_settings.display_screenshot_format, + u8 quality = g_settings.display_screenshot_quality, bool compress_on_thread = true); /// Loads the cheat list from the specified file. bool LoadCheatList(const char* filename); diff --git a/src/core/types.h b/src/core/types.h index 8138fe313..4832b0eb9 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -160,6 +160,23 @@ enum class DisplayExclusiveFullscreenControl : u8 Count }; +enum class DisplayScreenshotMode : u8 +{ + ScreenResolution, + InternalResolution, + UncorrectedInternalResolution, + Count +}; + +enum class DisplayScreenshotFormat : u8 +{ + PNG, + JPEG, + TGA, + BMP, + Count +}; + enum class AudioBackend : u8 { Null, diff --git a/src/duckstation-qt/CMakeLists.txt b/src/duckstation-qt/CMakeLists.txt index 32bf78998..c587687b6 100644 --- a/src/duckstation-qt/CMakeLists.txt +++ b/src/duckstation-qt/CMakeLists.txt @@ -70,18 +70,12 @@ set(SRCS debuggerwindow.cpp debuggerwindow.h debuggerwindow.ui - displaysettingswidget.cpp - displaysettingswidget.h - displaysettingswidget.ui displaywidget.cpp displaywidget.h emptygamelistwidget.ui emulationsettingswidget.cpp emulationsettingswidget.h emulationsettingswidget.ui - enhancementsettingswidget.cpp - enhancementsettingswidget.h - enhancementsettingswidget.ui foldersettingswidget.cpp foldersettingswidget.h foldersettingswidget.ui @@ -104,9 +98,9 @@ set(SRCS gdbconnection.h gdbserver.cpp gdbserver.h - generalsettingswidget.cpp - generalsettingswidget.h - generalsettingswidget.ui + graphicssettingswidget.cpp + graphicssettingswidget.h + graphicssettingswidget.ui hotkeysettingswidget.cpp hotkeysettingswidget.h inputbindingdialog.cpp @@ -114,6 +108,9 @@ set(SRCS inputbindingdialog.ui inputbindingwidgets.cpp inputbindingwidgets.h + interfacesettingswidget.cpp + interfacesettingswidget.h + interfacesettingswidget.ui logwindow.cpp logwindow.h mainwindow.cpp diff --git a/src/duckstation-qt/advancedsettingswidget.cpp b/src/duckstation-qt/advancedsettingswidget.cpp index 14d7d3140..f1f95568f 100644 --- a/src/duckstation-qt/advancedsettingswidget.cpp +++ b/src/duckstation-qt/advancedsettingswidget.cpp @@ -72,42 +72,6 @@ static QSpinBox* setIntRangeTweakOption(QTableWidget* table, int row, int value) return cb; } -static QDoubleSpinBox* addFloatRangeTweakOption(SettingsWindow* dialog, QTableWidget* table, QString name, - std::string section, std::string key, float min_value, float max_value, - float step_value, float default_value) -{ - const int row = table->rowCount(); - - table->insertRow(row); - - QTableWidgetItem* name_item = new QTableWidgetItem(name); - name_item->setFlags(name_item->flags() & ~(Qt::ItemIsEditable | Qt::ItemIsSelectable)); - table->setItem(row, 0, name_item); - - QDoubleSpinBox* cb = new QDoubleSpinBox(table); - cb->setMinimum(min_value); - cb->setMaximum(max_value); - cb->setSingleStep(step_value); - - if (!section.empty() || !key.empty()) - { - SettingWidgetBinder::BindWidgetToFloatSetting(dialog->getSettingsInterface(), cb, std::move(section), - std::move(key), default_value); - } - - table->setCellWidget(row, 1, cb); - return cb; -} - -static QDoubleSpinBox* setFloatRangeTweakOption(QTableWidget* table, int row, float value) -{ - QWidget* widget = table->cellWidget(row, 1); - QDoubleSpinBox* cb = qobject_cast<QDoubleSpinBox*>(widget); - Assert(cb); - cb->setValue(value); - return cb; -} - template<typename T> static QComboBox* addChoiceTweakOption(SettingsWindow* dialog, QTableWidget* table, QString name, std::string section, std::string key, std::optional<T> (*parse_callback)(const char*), @@ -145,36 +109,6 @@ static void setChoiceTweakOption(QTableWidget* table, int row, T value) cb->setCurrentIndex(static_cast<int>(value)); } -static void addMSAATweakOption(SettingsWindow* dialog, QTableWidget* table, const QString& name) -{ - const int row = table->rowCount(); - - table->insertRow(row); - - QTableWidgetItem* name_item = new QTableWidgetItem(name); - name_item->setFlags(name_item->flags() & ~(Qt::ItemIsEditable | Qt::ItemIsSelectable)); - table->setItem(row, 0, name_item); - - QComboBox* msaa = new QComboBox(table); - QtUtils::FillComboBoxWithMSAAModes(msaa); - const QVariant current_msaa_mode( - QtUtils::GetMSAAModeValue(static_cast<uint>(dialog->getEffectiveIntValue("GPU", "Multisamples", 1)), - dialog->getEffectiveBoolValue("GPU", "PerSampleShading", false))); - const int current_msaa_index = msaa->findData(current_msaa_mode); - if (current_msaa_index >= 0) - msaa->setCurrentIndex(current_msaa_index); - msaa->connect(msaa, QOverload<int>::of(&QComboBox::currentIndexChanged), [dialog, msaa](int index) { - uint multisamples; - bool ssaa; - QtUtils::DecodeMSAAModeValue(msaa->itemData(index), &multisamples, &ssaa); - dialog->setIntSettingValue("GPU", "Multisamples", static_cast<int>(multisamples)); - dialog->setBoolSettingValue("GPU", "PerSampleShading", ssaa); - g_emu_thread->applySettings(false); - }); - - table->setCellWidget(row, 1, msaa); -} - static void addDirectoryOption(SettingsWindow* dialog, QTableWidget* table, const QString& name, std::string section, std::string key) { @@ -242,8 +176,9 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget* SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showDebugMenu, "Main", "ShowDebugMenu", false); connect(m_ui.resetToDefaultButton, &QPushButton::clicked, this, &AdvancedSettingsWidget::onResetToDefaultClicked); - connect(m_ui.showDebugMenu, &QCheckBox::toggled, g_main_window, &MainWindow::updateDebugMenuVisibility, + connect(m_ui.showDebugMenu, &QCheckBox::stateChanged, g_main_window, &MainWindow::updateDebugMenuVisibility, Qt::QueuedConnection); + connect(m_ui.showDebugMenu, &QCheckBox::stateChanged, this, &AdvancedSettingsWidget::onShowDebugOptionsStateChanged); m_ui.tweakOptionTable->setColumnWidth(0, 380); m_ui.tweakOptionTable->setColumnWidth(1, 170); @@ -266,29 +201,18 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsWindow* dialog, QWidget* AdvancedSettingsWidget::~AdvancedSettingsWidget() = default; +void AdvancedSettingsWidget::onShowDebugOptionsStateChanged() +{ + const bool enabled = QtHost::ShouldShowDebugOptions(); + emit onShowDebugOptionsChanged(enabled); +} + void AdvancedSettingsWidget::addTweakOptions() { - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Disable All Enhancements"), "Main", - "DisableAllEnhancements", false); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Show Status Indicators"), "Display", - "ShowStatusIndicators", true); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Show Frame Times"), "Display", "ShowFrameTimes", false); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Show Settings Overlay"), "Display", "ShowEnhancements", false); 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")); - - addChoiceTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Wireframe Mode"), "GPU", "WireframeMode", - Settings::ParseGPUWireframeMode, Settings::GetGPUWireframeModeName, - Settings::GetGPUWireframeModeDisplayName, static_cast<u32>(GPUWireframeMode::Count), - GPUWireframeMode::Disabled); + addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Increase Timer Resolution"), "Main", + "IncreaseTimerResolution", true); if (m_dialog->isPerGameSettings()) { @@ -302,11 +226,14 @@ void AdvancedSettingsWidget::addTweakOptions() -128, 127, 0); } - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("PGXP Vertex Cache"), "GPU", "PGXPVertexCache", false); - addFloatRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("PGXP Geometry Tolerance"), "GPU", "PGXPTolerance", - -1.0f, 100.0f, 0.25f, -1.0f); - addFloatRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("PGXP Depth Clear Threshold"), "GPU", - "PGXPDepthClearThreshold", 0.0f, 4096.0f, 1.0f, Settings::DEFAULT_GPU_PGXP_DEPTH_THRESHOLD); + addIntRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("DMA Max Slice Ticks"), "Hacks", "DMAMaxSliceTicks", 100, + 10000, Settings::DEFAULT_DMA_MAX_SLICE_TICKS); + addIntRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("DMA Halt Ticks"), "Hacks", "DMAHaltTicks", 100, 10000, + Settings::DEFAULT_DMA_HALT_TICKS); + addIntRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("GPU FIFO Size"), "Hacks", "GPUFIFOSize", 16, 4096, + Settings::DEFAULT_GPU_FIFO_SIZE); + addIntRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("GPU Max Run-Ahead"), "Hacks", "GPUMaxRunAhead", 0, 1000, + Settings::DEFAULT_GPU_MAX_RUN_AHEAD); addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Enable Recompiler Memory Exceptions"), "CPU", "RecompilerMemoryExceptions", false); @@ -317,50 +244,6 @@ void AdvancedSettingsWidget::addTweakOptions() Settings::GetCPUFastmemModeDisplayName, static_cast<u32>(CPUFastmemMode::Count), Settings::DEFAULT_CPU_FASTMEM_MODE); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Use Old MDEC Routines"), "Hacks", "UseOldMDECRoutines", - false); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Enable VRAM Write Texture Replacement"), - "TextureReplacements", "EnableVRAMWriteReplacements", false); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Preload Texture Replacements"), "TextureReplacements", - "PreloadTextures", false); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Dump Replaceable VRAM Writes"), "TextureReplacements", - "DumpVRAMWrites", false); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Set Dumped VRAM Write Alpha Channel"), - "TextureReplacements", "DumpVRAMWriteForceAlphaChannel", true); - addIntRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Minimum Dumped VRAM Write Width"), "TextureReplacements", - "DumpVRAMWriteWidthThreshold", 1, VRAM_WIDTH, - Settings::DEFAULT_VRAM_WRITE_DUMP_WIDTH_THRESHOLD); - addIntRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Minimum Dumped VRAM Write Height"), "TextureReplacements", - "DumpVRAMWriteHeightThreshold", 1, VRAM_HEIGHT, - Settings::DEFAULT_VRAM_WRITE_DUMP_HEIGHT_THRESHOLD); - - addIntRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("DMA Max Slice Ticks"), "Hacks", "DMAMaxSliceTicks", 100, - 10000, Settings::DEFAULT_DMA_MAX_SLICE_TICKS); - addIntRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("DMA Halt Ticks"), "Hacks", "DMAHaltTicks", 100, 10000, - Settings::DEFAULT_DMA_HALT_TICKS); - addIntRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("GPU FIFO Size"), "Hacks", "GPUFIFOSize", 16, 4096, - Settings::DEFAULT_GPU_FIFO_SIZE); - addIntRangeTweakOption(m_dialog, m_ui.tweakOptionTable, tr("GPU Max Run-Ahead"), "Hacks", "GPUMaxRunAhead", 0, 1000, - Settings::DEFAULT_GPU_MAX_RUN_AHEAD); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Use Debug Host GPU Device"), "GPU", "UseDebugDevice", - false); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Disable Shader Cache"), "GPU", "DisableShaderCache", - false); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Disable Dual-Source Blend"), "GPU", - "DisableDualSourceBlend", false); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Disable Framebuffer Fetch"), "GPU", - "DisableFramebufferFetch", false); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Disable Texture Buffers"), "GPU", "DisableTextureBuffers", - false); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Disable Texture Copy To Self"), "GPU", - "DisableTextureCopyToSelf", false); - - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Stretch Display Vertically"), "Display", - "StretchVertically", false); - - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Increase Timer Resolution"), "Main", - "IncreaseTimerResolution", true); - addChoiceTweakOption(m_dialog, m_ui.tweakOptionTable, tr("CD-ROM Mechacon Version"), "CDROM", "MechaconVersion", Settings::ParseCDROMMechVersionName, Settings::GetCDROMMechVersionName, Settings::GetCDROMMechVersionDisplayName, static_cast<u8>(CDROMMechaconVersion::Count), @@ -368,9 +251,6 @@ void AdvancedSettingsWidget::addTweakOptions() addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Allow Booting Without SBI File"), "CDROM", "AllowBootingWithoutSBIFile", false); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Create Save State Backups"), "General", - "CreateSaveStateBackups", false); - addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Enable PCDrv"), "PCDrv", "Enabled", false); addBooleanTweakOption(m_dialog, m_ui.tweakOptionTable, tr("Enable PCDrv Writes"), "PCDrv", "EnableWrites", false); addDirectoryOption(m_dialog, m_ui.tweakOptionTable, tr("PCDrv Root Directory"), "PCDrv", "Root"); @@ -382,31 +262,8 @@ void AdvancedSettingsWidget::onResetToDefaultClicked() { int i = 0; - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Disable all enhancements - setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Show status indicators - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Show frame times - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Show settings overlay - 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 - setFloatRangeTweakOption(m_ui.tweakOptionTable, i++, -1.0f); // PGXP geometry tolerance - setFloatRangeTweakOption(m_ui.tweakOptionTable, i++, - Settings::DEFAULT_GPU_PGXP_DEPTH_THRESHOLD); // PGXP depth clear threshold - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Recompiler memory exceptions - setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Recompiler block linking - setChoiceTweakOption(m_ui.tweakOptionTable, i++, Settings::DEFAULT_CPU_FASTMEM_MODE); // Recompiler fastmem mode - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Use Old MDEC Routines - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // VRAM write texture replacement - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Preload texture replacements - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Dump replacable VRAM writes - setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Set dumped VRAM write alpha channel - setIntRangeTweakOption(m_ui.tweakOptionTable, i++, - Settings::DEFAULT_VRAM_WRITE_DUMP_WIDTH_THRESHOLD); // Minimum dumped VRAM width - setIntRangeTweakOption(m_ui.tweakOptionTable, i++, - Settings::DEFAULT_VRAM_WRITE_DUMP_HEIGHT_THRESHOLD); // Minimum dumped VRAM height + setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Apply compatibility settings + setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Increase Timer Resolution setIntRangeTweakOption(m_ui.tweakOptionTable, i++, static_cast<int>(Settings::DEFAULT_DMA_MAX_SLICE_TICKS)); // DMA max slice ticks setIntRangeTweakOption(m_ui.tweakOptionTable, i++, @@ -415,18 +272,13 @@ void AdvancedSettingsWidget::onResetToDefaultClicked() static_cast<int>(Settings::DEFAULT_GPU_FIFO_SIZE)); // GPU FIFO size setIntRangeTweakOption(m_ui.tweakOptionTable, i++, static_cast<int>(Settings::DEFAULT_GPU_MAX_RUN_AHEAD)); // GPU max run-ahead - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Use debug host GPU device - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Disable Shader Cache - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Disable Dual-Source Blend - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Disable Framebuffer Fetch - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Disable Texture Buffers - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Disable Texture Copy To Self - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Stretch Display Vertically - setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Increase Timer Resolution + setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Recompiler memory exceptions + setBooleanTweakOption(m_ui.tweakOptionTable, i++, true); // Recompiler block linking + setChoiceTweakOption(m_ui.tweakOptionTable, i++, + Settings::DEFAULT_CPU_FASTMEM_MODE); // Recompiler fastmem mode setChoiceTweakOption(m_ui.tweakOptionTable, i++, Settings::DEFAULT_CDROM_MECHACON_VERSION); // CDROM Mechacon Version setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Allow booting without SBI file - setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Create save state backups setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Enable PCDRV setBooleanTweakOption(m_ui.tweakOptionTable, i++, false); // Enable PCDRV Writes setDirectoryOption(m_ui.tweakOptionTable, i++, ""); // PCDrv Root Directory @@ -436,49 +288,21 @@ void AdvancedSettingsWidget::onResetToDefaultClicked() // for per-game it's easier to just clear and recreate SettingsInterface* sif = m_dialog->getSettingsInterface(); - sif->DeleteValue("Main", "DisableAllEnhancements"); - sif->DeleteValue("Display", "ShowEnhancements"); - sif->DeleteValue("Display", "ShowStatusIndicators"); - sif->DeleteValue("Display", "ShowFrameTimes"); - sif->DeleteValue("Display", "ShowEnhancements"); sif->DeleteValue("Main", "ApplyCompatibilitySettings"); - sif->DeleteValue("Display", "MaxFPS"); + sif->DeleteValue("Main", "IncreaseTimerResolution"); sif->DeleteValue("Display", "ActiveStartOffset"); sif->DeleteValue("Display", "ActiveEndOffset"); 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"); - sif->DeleteValue("GPU", "PGXPTolerance"); - sif->DeleteValue("GPU", "PGXPDepthClearThreshold"); - sif->DeleteValue("CPU", "RecompilerMemoryExceptions"); - sif->DeleteValue("CPU", "RecompilerBlockLinking"); - sif->DeleteValue("CPU", "FastmemMode"); - sif->DeleteValue("TextureReplacements", "EnableVRAMWriteReplacements"); - sif->DeleteValue("TextureReplacements", "PreloadTextures"); - sif->DeleteValue("TextureReplacements", "DumpVRAMWrites"); - sif->DeleteValue("TextureReplacements", "DumpVRAMWriteForceAlphaChannel"); - sif->DeleteValue("TextureReplacements", "DumpVRAMWriteWidthThreshold"); - sif->DeleteValue("TextureReplacements", "DumpVRAMWriteHeightThreshold"); - sif->DeleteValue("Hacks", "UseOldMDECRoutines"); sif->DeleteValue("Hacks", "DMAMaxSliceTicks"); sif->DeleteValue("Hacks", "DMAHaltTicks"); sif->DeleteValue("Hacks", "GPUFIFOSize"); sif->DeleteValue("Hacks", "GPUMaxRunAhead"); - sif->DeleteValue("GPU", "UseDebugDevice"); - sif->DeleteValue("GPU", "DisableShaderCache"); - sif->DeleteValue("GPU", "DisableDualSourceBlend"); - sif->DeleteValue("GPU", "DisableFramebufferFetch"); - sif->DeleteValue("GPU", "DisableTextureBuffers"); - sif->DeleteValue("GPU", "DisableTextureCopyToSelf"); - sif->DeleteValue("Display", "StretchVertically"); - sif->DeleteValue("Main", "IncreaseTimerResolution"); + sif->DeleteValue("CPU", "RecompilerMemoryExceptions"); + sif->DeleteValue("CPU", "RecompilerBlockLinking"); + sif->DeleteValue("CPU", "FastmemMode"); sif->DeleteValue("CDROM", "MechaconVersion"); sif->DeleteValue("CDROM", "AllowBootingWithoutSBIFile"); - sif->DeleteValue("General", "CreateSaveStateBackups"); sif->DeleteValue("PCDrv", "Enabled"); sif->DeleteValue("PCDrv", "EnableWrites"); sif->DeleteValue("PCDrv", "Root"); @@ -486,4 +310,4 @@ void AdvancedSettingsWidget::onResetToDefaultClicked() while (m_ui.tweakOptionTable->rowCount() > 0) m_ui.tweakOptionTable->removeRow(m_ui.tweakOptionTable->rowCount() - 1); addTweakOptions(); -} \ No newline at end of file +} diff --git a/src/duckstation-qt/advancedsettingswidget.h b/src/duckstation-qt/advancedsettingswidget.h index 964836d8c..f30d79275 100644 --- a/src/duckstation-qt/advancedsettingswidget.h +++ b/src/duckstation-qt/advancedsettingswidget.h @@ -17,6 +17,12 @@ public: explicit AdvancedSettingsWidget(SettingsWindow* dialog, QWidget* parent); ~AdvancedSettingsWidget(); +Q_SIGNALS: + void onShowDebugOptionsChanged(bool enabled); + +private Q_SLOTS: + void onShowDebugOptionsStateChanged(); + private: struct TweakOption { diff --git a/src/duckstation-qt/consolesettingswidget.cpp b/src/duckstation-qt/consolesettingswidget.cpp index f49d07b93..08adb8b74 100644 --- a/src/duckstation-qt/consolesettingswidget.cpp +++ b/src/duckstation-qt/consolesettingswidget.cpp @@ -40,6 +40,8 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(SettingsWindow* dialog, QWidget* pa SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.region, "Console", "Region", &Settings::ParseConsoleRegionName, &Settings::GetConsoleRegionName, Settings::DEFAULT_CONSOLE_REGION); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enable8MBRAM, "Console", "Enable8MBRAM", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableAllEnhancements, "Main", "DisableAllEnhancements", + false); SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.cpuExecutionMode, "CPU", "ExecutionMode", &Settings::ParseCPUExecutionMode, &Settings::GetCPUExecutionModeName, Settings::DEFAULT_CPU_EXECUTION_MODE); @@ -72,6 +74,9 @@ ConsoleSettingsWidget::ConsoleSettingsWidget(SettingsWindow* dialog, QWidget* pa "to use a larger heap size for " "this additional RAM to be usable. Titles which rely on memory mirrors may break, so it should only be used " "with compatible mods.")); + dialog->registerWidgetHelp(m_ui.disableAllEnhancements, tr("Disable All Enhancements"), tr("Unchecked"), + tr("Disables all enhancement options, simulating the system as accurately as possible. " + "Use to quickly determine whether an enhancement is responsible for game bugs.")); dialog->registerWidgetHelp( m_ui.cdromLoadImageToRAM, tr("Preload Image to RAM"), tr("Unchecked"), tr("Loads the game image into RAM. Useful for network paths that may become unreliable during gameplay. In some " diff --git a/src/duckstation-qt/consolesettingswidget.ui b/src/duckstation-qt/consolesettingswidget.ui index 9a4a8d1cf..eac5327ce 100644 --- a/src/duckstation-qt/consolesettingswidget.ui +++ b/src/duckstation-qt/consolesettingswidget.ui @@ -40,11 +40,22 @@ <widget class="QComboBox" name="region"/> </item> <item row="1" column="0" colspan="2"> - <widget class="QCheckBox" name="enable8MBRAM"> - <property name="text"> - <string>Enable 8MB RAM (Dev Console)</string> - </property> - </widget> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QCheckBox" name="enable8MBRAM"> + <property name="text"> + <string>Enable 8MB RAM (Dev Console)</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="disableAllEnhancements"> + <property name="text"> + <string>Disable All Enhancements</string> + </property> + </widget> + </item> + </layout> </item> </layout> </widget> diff --git a/src/duckstation-qt/displaysettingswidget.cpp b/src/duckstation-qt/displaysettingswidget.cpp deleted file mode 100644 index afb41d32d..000000000 --- a/src/duckstation-qt/displaysettingswidget.cpp +++ /dev/null @@ -1,305 +0,0 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#include "displaysettingswidget.h" -#include "core/gpu.h" -#include "core/settings.h" -#include "qtutils.h" -#include "settingswindow.h" -#include "settingwidgetbinder.h" -#include <QtWidgets/QMessageBox> - -// For enumerating adapters. -#ifdef _WIN32 -#include "util/d3d11_device.h" -#include "util/d3d12_device.h" -#endif -#ifdef ENABLE_VULKAN -#include "util/vulkan_device.h" -#endif - -DisplaySettingsWidget::DisplaySettingsWidget(SettingsWindow* dialog, QWidget* parent) - : QWidget(parent), m_dialog(dialog) -{ - SettingsInterface* sif = dialog->getSettingsInterface(); - - m_ui.setupUi(this); - setupAdditionalUi(); - - SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.renderer, "GPU", "Renderer", &Settings::ParseRendererName, - &Settings::GetRendererName, Settings::DEFAULT_GPU_RENDERER); - SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayAspectRatio, "Display", "AspectRatio", - &Settings::ParseDisplayAspectRatio, &Settings::GetDisplayAspectRatioName, - Settings::DEFAULT_DISPLAY_ASPECT_RATIO); - SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.customAspectRatioNumerator, "Display", - "CustomAspectRatioNumerator", 1); - SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.customAspectRatioDenominator, "Display", - "CustomAspectRatioDenominator", 1); - SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayCropMode, "Display", "CropMode", - &Settings::ParseDisplayCropMode, &Settings::GetDisplayCropModeName, - Settings::DEFAULT_DISPLAY_CROP_MODE); - SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayAlignment, "Display", "Alignment", - &Settings::ParseDisplayAlignment, &Settings::GetDisplayAlignmentName, - Settings::DEFAULT_DISPLAY_ALIGNMENT); - SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayScaling, "Display", "Scaling", - &Settings::ParseDisplayScaling, &Settings::GetDisplayScalingName, - Settings::DEFAULT_DISPLAY_SCALING); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.internalResolutionScreenshots, "Display", - "InternalResolutionScreenshots", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vsync, "Display", "VSync", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.gpuThread, "GPU", "UseThread", true); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.threadedPresentation, "GPU", "ThreadedPresentation", true); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showOSDMessages, "Display", "ShowOSDMessages", true); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showFPS, "Display", "ShowFPS", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showSpeed, "Display", "ShowSpeed", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showResolution, "Display", "ShowResolution", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showCPU, "Display", "ShowCPU", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showGPU, "Display", "ShowGPU", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showInput, "Display", "ShowInputs", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showGPUStatistics, "Display", "ShowGPUStatistics", false); - - connect(m_ui.renderer, QOverload<int>::of(&QComboBox::currentIndexChanged), this, - &DisplaySettingsWidget::populateGPUAdaptersAndResolutions); - connect(m_ui.adapter, QOverload<int>::of(&QComboBox::currentIndexChanged), this, - &DisplaySettingsWidget::onGPUAdapterIndexChanged); - connect(m_ui.fullscreenMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, - &DisplaySettingsWidget::onGPUFullscreenModeIndexChanged); - connect(m_ui.displayAspectRatio, QOverload<int>::of(&QComboBox::currentIndexChanged), this, - &DisplaySettingsWidget::onAspectRatioChanged); - populateGPUAdaptersAndResolutions(); - onAspectRatioChanged(); - - dialog->registerWidgetHelp( - m_ui.renderer, tr("Renderer"), QString::fromUtf8(Settings::GetRendererDisplayName(Settings::DEFAULT_GPU_RENDERER)), - tr("Chooses the backend to use for rendering the console/game visuals. <br>Depending on your system and hardware, " - "Direct3D 11 and OpenGL hardware backends may be available. <br>The software renderer offers the best " - "compatibility, but is the slowest and does not offer any enhancements.")); - dialog->registerWidgetHelp( - m_ui.adapter, tr("Adapter"), tr("(Default)"), - tr("If your system contains multiple GPUs or adapters, you can select which GPU you wish to use for the hardware " - "renderers. <br>This option is only supported in Direct3D and Vulkan. OpenGL will always use the default " - "device.")); - dialog->registerWidgetHelp(m_ui.fullscreenMode, tr("Fullscreen Mode"), tr("Borderless Fullscreen"), - tr("Chooses the fullscreen resolution and frequency.")); - dialog->registerWidgetHelp( - m_ui.displayAspectRatio, tr("Aspect Ratio"), - QString::fromUtf8(Settings::GetDisplayAspectRatioDisplayName(Settings::DEFAULT_DISPLAY_ASPECT_RATIO)), - tr("Changes the aspect ratio used to display the console's output to the screen. The default is Auto (Game Native) " - "which automatically adjusts the aspect ratio to match how a game would be shown on a typical TV of the era.")); - dialog->registerWidgetHelp( - m_ui.displayCropMode, tr("Crop Mode"), - QString::fromUtf8(Settings::GetDisplayCropModeDisplayName(Settings::DEFAULT_DISPLAY_CROP_MODE)), - tr("Determines how much of the area typically not visible on a consumer TV set to crop/hide. <br>" - "Some games display content in the overscan area, or use it for screen effects. <br>May " - "not display correctly with the \"All Borders\" setting. \"Only Overscan\" offers a good " - "compromise between stability and hiding black borders.")); - dialog->registerWidgetHelp( - m_ui.displayAlignment, tr("Position"), - QString::fromUtf8(Settings::GetDisplayAlignmentDisplayName(Settings::DEFAULT_DISPLAY_ALIGNMENT)), - tr("Determines the position on the screen when black borders must be added.")); - dialog->registerWidgetHelp( - m_ui.displayScaling, tr("Scaling"), tr("Bilinear (Smooth)"), - tr("Determines how the emulated console's output is upscaled or downscaled to your monitor's resolution.")); - dialog->registerWidgetHelp(m_ui.internalResolutionScreenshots, tr("Internal Resolution Screenshots"), tr("Unchecked"), - tr("Saves screenshots at internal render resolution and without postprocessing. If this " - "option is disabled, the screenshots will be taken at the window's resolution. " - "Internal resolution screenshots can be very large at high rendering scales.")); - dialog->registerWidgetHelp( - m_ui.vsync, tr("VSync"), tr("Unchecked"), - tr("Enable this option to match DuckStation's refresh rate with your current monitor or screen. " - "VSync is automatically disabled when it is not possible (e.g. running at non-100% speed).")); - dialog->registerWidgetHelp(m_ui.threadedPresentation, tr("Threaded Presentation"), tr("Checked"), - tr("Presents frames on a background thread when fast forwarding or vsync is disabled. " - "This can measurably improve performance in the Vulkan renderer.")); - dialog->registerWidgetHelp(m_ui.gpuThread, tr("Threaded Rendering"), tr("Checked"), - tr("Uses a second thread for drawing graphics. Currently only available for the software " - "renderer, but can provide a significant speed improvement, and is safe to use.")); - dialog->registerWidgetHelp(m_ui.showOSDMessages, tr("Show OSD Messages"), tr("Checked"), - tr("Shows on-screen-display messages when events occur such as save states being " - "created/loaded, screenshots being taken, etc.")); - dialog->registerWidgetHelp(m_ui.showFPS, tr("Show FPS"), tr("Unchecked"), - tr("Shows the internal frame rate of the game in the top-right corner of the display.")); - dialog->registerWidgetHelp( - m_ui.showSpeed, tr("Show Emulation Speed"), tr("Unchecked"), - tr("Shows the current emulation speed of the system in the top-right corner of the display as a percentage.")); - dialog->registerWidgetHelp(m_ui.showResolution, tr("Show Resolution"), tr("Unchecked"), - tr("Shows the resolution of the game in the top-right corner of the display.")); - dialog->registerWidgetHelp( - m_ui.showCPU, tr("Show CPU Usage"), tr("Unchecked"), - tr("Shows the host's CPU usage based on threads in the top-right corner of the display. This does not display the " - "emulated system CPU's usage. If a value close to 100% is being displayed, this means your host's CPU is likely " - "the bottleneck. In this case, you should reduce enhancement-related settings such as overclocking.")); - dialog->registerWidgetHelp(m_ui.showGPUStatistics, tr("Show GPU Statistics"), tr("Unchecked"), - tr("Shows information about the emulated GPU in the top-right corner of the display.")); - dialog->registerWidgetHelp(m_ui.showGPU, tr("Show GPU Usage"), tr("Unchecked"), - tr("Shows the host's GPU usage in the top-right corner of the display.")); - dialog->registerWidgetHelp( - m_ui.showInput, tr("Show Controller Input"), tr("Unchecked"), - tr("Shows the current controller state of the system in the bottom-left corner of the display.")); - -#ifdef _WIN32 - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.blitSwapChain, "Display", "UseBlitSwapChain", false); - dialog->registerWidgetHelp(m_ui.blitSwapChain, tr("Use Blit Swap Chain"), tr("Unchecked"), - tr("Uses a blit presentation model instead of flipping when using the Direct3D 11 " - "renderer. This usually results in slower performance, but may be required for some " - "streaming applications, or to uncap framerates on some systems.")); -#else - m_ui.blitSwapChain->setEnabled(false); -#endif -} - -DisplaySettingsWidget::~DisplaySettingsWidget() = default; - -void DisplaySettingsWidget::setupAdditionalUi() -{ - for (u32 i = 0; i < static_cast<u32>(GPURenderer::Count); i++) - { - m_ui.renderer->addItem(QString::fromUtf8(Settings::GetRendererDisplayName(static_cast<GPURenderer>(i)))); - } - - for (u32 i = 0; i < static_cast<u32>(DisplayAspectRatio::Count); i++) - { - m_ui.displayAspectRatio->addItem( - QString::fromUtf8(Settings::GetDisplayAspectRatioDisplayName(static_cast<DisplayAspectRatio>(i)))); - } - - for (u32 i = 0; i < static_cast<u32>(DisplayCropMode::Count); i++) - { - m_ui.displayCropMode->addItem( - QString::fromUtf8(Settings::GetDisplayCropModeDisplayName(static_cast<DisplayCropMode>(i)))); - } - - for (u32 i = 0; i < static_cast<u32>(DisplayScalingMode::Count); i++) - { - m_ui.displayScaling->addItem( - QString::fromUtf8(Settings::GetDisplayScalingDisplayName(static_cast<DisplayScalingMode>(i)))); - } - - for (u32 i = 0; i < static_cast<u32>(DisplayAlignment::Count); i++) - { - m_ui.displayAlignment->addItem( - QString::fromUtf8(Settings::GetDisplayAlignmentDisplayName(static_cast<DisplayAlignment>(i)))); - } -} - -void DisplaySettingsWidget::populateGPUAdaptersAndResolutions() -{ - GPUDevice::AdapterAndModeList aml; - bool thread_supported = false; - bool threaded_presentation_supported = false; - switch (static_cast<GPURenderer>(m_ui.renderer->currentIndex())) - { -#ifdef _WIN32 - case GPURenderer::HardwareD3D11: - aml = D3D11Device::StaticGetAdapterAndModeList(); - break; - - case GPURenderer::HardwareD3D12: - aml = D3D12Device::StaticGetAdapterAndModeList(); - break; -#endif -#ifdef __APPLE__ - case GPURenderer::HardwareMetal: - aml = GPUDevice::WrapGetMetalAdapterAndModeList(); - break; -#endif -#ifdef ENABLE_VULKAN - case GPURenderer::HardwareVulkan: - aml = VulkanDevice::StaticGetAdapterAndModeList(); - threaded_presentation_supported = true; - break; -#endif - - case GPURenderer::Software: - thread_supported = true; - break; - - default: - break; - } - - { - const std::string current_adapter(m_dialog->getEffectiveStringValue("GPU", "Adapter", "")); - QSignalBlocker blocker(m_ui.adapter); - - // add the default entry - we'll fall back to this if the GPU no longer exists, or there's no options - m_ui.adapter->clear(); - m_ui.adapter->addItem(tr("(Default)")); - - // add the other adapters - for (const std::string& adapter_name : aml.adapter_names) - { - m_ui.adapter->addItem(QString::fromStdString(adapter_name)); - - if (adapter_name == current_adapter) - m_ui.adapter->setCurrentIndex(m_ui.adapter->count() - 1); - } - - // disable it if we don't have a choice - m_ui.adapter->setEnabled(!aml.adapter_names.empty()); - } - - { - const std::string current_mode(m_dialog->getEffectiveStringValue("GPU", "FullscreenMode", "")); - QSignalBlocker blocker(m_ui.fullscreenMode); - - m_ui.fullscreenMode->clear(); - m_ui.fullscreenMode->addItem(tr("Borderless Fullscreen")); - m_ui.fullscreenMode->setCurrentIndex(0); - - for (const std::string& mode_name : aml.fullscreen_modes) - { - m_ui.fullscreenMode->addItem(QString::fromStdString(mode_name)); - - if (mode_name == current_mode) - m_ui.fullscreenMode->setCurrentIndex(m_ui.fullscreenMode->count() - 1); - } - - // disable it if we don't have a choice - m_ui.fullscreenMode->setEnabled(!aml.fullscreen_modes.empty()); - } - - m_ui.gpuThread->setEnabled(thread_supported); - m_ui.threadedPresentation->setEnabled(threaded_presentation_supported); -} - -void DisplaySettingsWidget::onGPUAdapterIndexChanged() -{ - if (m_ui.adapter->currentIndex() == 0) - { - // default - m_dialog->removeSettingValue("GPU", "Adapter"); - return; - } - - m_dialog->setStringSettingValue("GPU", "Adapter", m_ui.adapter->currentText().toUtf8().constData()); -} - -void DisplaySettingsWidget::onGPUFullscreenModeIndexChanged() -{ - if (m_ui.fullscreenMode->currentIndex() == 0) - { - // default - m_dialog->removeSettingValue("GPU", "FullscreenMode"); - return; - } - - m_dialog->setStringSettingValue("GPU", "FullscreenMode", m_ui.fullscreenMode->currentText().toUtf8().constData()); -} - -void DisplaySettingsWidget::onAspectRatioChanged() -{ - const DisplayAspectRatio ratio = - Settings::ParseDisplayAspectRatio( - m_dialog - ->getEffectiveStringValue("Display", "AspectRatio", - Settings::GetDisplayAspectRatioName(Settings::DEFAULT_DISPLAY_ASPECT_RATIO)) - .c_str()) - .value_or(Settings::DEFAULT_DISPLAY_ASPECT_RATIO); - - const bool is_custom = (ratio == DisplayAspectRatio::Custom); - - m_ui.customAspectRatioNumerator->setVisible(is_custom); - m_ui.customAspectRatioDenominator->setVisible(is_custom); - m_ui.customAspectRatioSeparator->setVisible(is_custom); -} diff --git a/src/duckstation-qt/displaysettingswidget.h b/src/duckstation-qt/displaysettingswidget.h deleted file mode 100644 index d8d648186..000000000 --- a/src/duckstation-qt/displaysettingswidget.h +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#pragma once - -#include <QtWidgets/QWidget> - -#include "ui_displaysettingswidget.h" - -class PostProcessingChainConfigWidget; -class SettingsWindow; - -class DisplaySettingsWidget : public QWidget -{ - Q_OBJECT - -public: - DisplaySettingsWidget(SettingsWindow* dialog, QWidget* parent); - ~DisplaySettingsWidget(); - -private Q_SLOTS: - void populateGPUAdaptersAndResolutions(); - void onGPUAdapterIndexChanged(); - void onGPUFullscreenModeIndexChanged(); - void onAspectRatioChanged(); - -private: - void setupAdditionalUi(); - - Ui::DisplaySettingsWidget m_ui; - - SettingsWindow* m_dialog; -}; diff --git a/src/duckstation-qt/displaysettingswidget.ui b/src/duckstation-qt/displaysettingswidget.ui deleted file mode 100644 index 86284d7da..000000000 --- a/src/duckstation-qt/displaysettingswidget.ui +++ /dev/null @@ -1,270 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>DisplaySettingsWidget</class> - <widget class="QWidget" name="DisplaySettingsWidget"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>485</width> - <height>525</height> - </rect> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QGroupBox" name="basicGroupBox"> - <property name="title"> - <string>Basic</string> - </property> - <layout class="QFormLayout" name="formLayout_2"> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Renderer:</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QComboBox" name="renderer"/> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_5"> - <property name="text"> - <string>Adapter:</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QComboBox" name="adapter"/> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Fullscreen Mode:</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QComboBox" name="fullscreenMode"/> - </item> - <item row="3" column="0" colspan="2"> - <layout class="QGridLayout" name="basicCheckboxGridLayout"> - <item row="1" column="0"> - <widget class="QCheckBox" name="vsync"> - <property name="text"> - <string>VSync</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QCheckBox" name="gpuThread"> - <property name="text"> - <string>Threaded Rendering</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QCheckBox" name="threadedPresentation"> - <property name="text"> - <string>Threaded Presentation</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QCheckBox" name="blitSwapChain"> - <property name="text"> - <string>Use Blit Swap Chain</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="groupBox_3"> - <property name="title"> - <string>Screen Display</string> - </property> - <layout class="QFormLayout" name="formLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>Aspect Ratio:</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <layout class="QHBoxLayout" name="horizontalLayout" 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_3"> - <property name="text"> - <string>Crop:</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QComboBox" name="displayCropMode"/> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label_7"> - <property name="text"> - <string>Position:</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QComboBox" name="displayAlignment"/> - </item> - <item row="4" column="0" colspan="2"> - <layout class="QGridLayout" name="gridLayout"> - <item row="1" column="0"> - <widget class="QCheckBox" name="internalResolutionScreenshots"> - <property name="text"> - <string>Internal Resolution Screenshots</string> - </property> - </widget> - </item> - </layout> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_6"> - <property name="text"> - <string>Scaling:</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QComboBox" name="displayScaling"/> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="groupBox_5"> - <property name="title"> - <string>On-Screen Display</string> - </property> - <layout class="QGridLayout" name="formLayout_5"> - <item row="3" column="0"> - <widget class="QCheckBox" name="showSpeed"> - <property name="text"> - <string>Show Emulation Speed</string> - </property> - </widget> - </item> - <item row="4" column="0"> - <widget class="QCheckBox" name="showCPU"> - <property name="text"> - <string>Show CPU Usage</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QCheckBox" name="showOSDMessages"> - <property name="text"> - <string>Show OSD Messages</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QCheckBox" name="showFPS"> - <property name="text"> - <string>Show FPS</string> - </property> - </widget> - </item> - <item row="4" column="1"> - <widget class="QCheckBox" name="showInput"> - <property name="text"> - <string>Show Controller Input</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QCheckBox" name="showResolution"> - <property name="text"> - <string>Show Resolution</string> - </property> - </widget> - </item> - <item row="5" column="0"> - <widget class="QCheckBox" name="showGPU"> - <property name="text"> - <string>Show GPU Usage</string> - </property> - </widget> - </item> - <item row="5" column="1"> - <widget class="QCheckBox" name="showGPUStatistics"> - <property name="text"> - <string>Show GPU Statistics</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src/duckstation-qt/duckstation-qt.vcxproj b/src/duckstation-qt/duckstation-qt.vcxproj index 7a0b22aa9..d584fd5a0 100644 --- a/src/duckstation-qt/duckstation-qt.vcxproj +++ b/src/duckstation-qt/duckstation-qt.vcxproj @@ -21,12 +21,11 @@ <ClCompile Include="emulationsettingswidget.cpp" /> <ClCompile Include="debuggermodels.cpp" /> <ClCompile Include="debuggerwindow.cpp" /> - <ClCompile Include="enhancementsettingswidget.cpp" /> <ClCompile Include="foldersettingswidget.cpp" /> <ClCompile Include="gamelistmodel.cpp" /> <ClCompile Include="gamelistsearchdirectoriesmodel.cpp" /> - <ClCompile Include="generalsettingswidget.cpp" /> - <ClCompile Include="displaysettingswidget.cpp" /> + <ClCompile Include="interfacesettingswidget.cpp" /> + <ClCompile Include="graphicssettingswidget.cpp" /> <ClCompile Include="hotkeysettingswidget.cpp" /> <ClCompile Include="inputbindingdialog.cpp" /> <ClCompile Include="inputbindingwidgets.cpp" /> @@ -62,12 +61,10 @@ <QtMoc Include="cheatmanagerdialog.h" /> <QtMoc Include="cheatcodeeditordialog.h" /> <QtMoc Include="coverdownloaddialog.h" /> - <QtMoc Include="enhancementsettingswidget.h" /> <QtMoc Include="memorycardsettingswidget.h" /> <QtMoc Include="memorycardeditorwindow.h" /> <QtMoc Include="displaywidget.h" /> - <QtMoc Include="generalsettingswidget.h" /> - <QtMoc Include="displaysettingswidget.h" /> + <QtMoc Include="interfacesettingswidget.h" /> <QtMoc Include="hotkeysettingswidget.h" /> <QtMoc Include="inputbindingwidgets.h" /> <QtMoc Include="advancedsettingswidget.h" /> @@ -88,6 +85,7 @@ <ClInclude Include="controllersettingwidgetbinder.h" /> <QtMoc Include="memoryviewwidget.h" /> <QtMoc Include="logwindow.h" /> + <QtMoc Include="graphicssettingswidget.h" /> <ClInclude Include="pch.h" /> <ClInclude Include="resource.h" /> <ClInclude Include="settingwidgetbinder.h" /> @@ -122,13 +120,10 @@ <QtUi Include="emulationsettingswidget.ui"> <FileType>Document</FileType> </QtUi> - <QtUi Include="enhancementsettingswidget.ui"> - <FileType>Document</FileType> - </QtUi> <QtUi Include="gamelistsettingswidget.ui"> <FileType>Document</FileType> </QtUi> - <QtUi Include="generalsettingswidget.ui"> + <QtUi Include="interfacesettingswidget.ui"> <FileType>Document</FileType> </QtUi> <QtUi Include="mainwindow.ui"> @@ -137,9 +132,6 @@ <QtUi Include="settingswindow.ui"> <FileType>Document</FileType> </QtUi> - <QtUi Include="displaysettingswidget.ui"> - <FileType>Document</FileType> - </QtUi> <QtUi Include="advancedsettingswidget.ui"> <FileType>Document</FileType> </QtUi> @@ -243,7 +235,6 @@ <ClCompile Include="$(IntDir)moc_coverdownloaddialog.cpp" /> <ClCompile Include="$(IntDir)moc_displaywidget.cpp" /> <ClCompile Include="$(IntDir)moc_emulationsettingswidget.cpp" /> - <ClCompile Include="$(IntDir)moc_enhancementsettingswidget.cpp" /> <ClCompile Include="$(IntDir)moc_foldersettingswidget.cpp" /> <ClCompile Include="$(IntDir)moc_gamelistmodel.cpp" /> <ClCompile Include="$(IntDir)moc_gamelistrefreshthread.cpp" /> @@ -253,13 +244,13 @@ <ClCompile Include="$(IntDir)moc_gamesummarywidget.cpp" /> <ClCompile Include="$(IntDir)moc_gdbconnection.cpp" /> <ClCompile Include="$(IntDir)moc_gdbserver.cpp" /> - <ClCompile Include="$(IntDir)moc_generalsettingswidget.cpp" /> + <ClCompile Include="$(IntDir)moc_graphicssettingswidget.cpp" /> <ClCompile Include="$(IntDir)moc_debuggermodels.cpp" /> <ClCompile Include="$(IntDir)moc_debuggerwindow.cpp" /> - <ClCompile Include="$(IntDir)moc_displaysettingswidget.cpp" /> <ClCompile Include="$(IntDir)moc_hotkeysettingswidget.cpp" /> <ClCompile Include="$(IntDir)moc_inputbindingdialog.cpp" /> <ClCompile Include="$(IntDir)moc_inputbindingwidgets.cpp" /> + <ClCompile Include="$(IntDir)moc_interfacesettingswidget.cpp" /> <ClCompile Include="$(IntDir)moc_logwindow.cpp" /> <ClCompile Include="$(IntDir)moc_mainwindow.cpp" /> <ClCompile Include="$(IntDir)moc_memorycardsettingswidget.cpp" /> @@ -335,6 +326,9 @@ <QtUi Include="debuggeraddbreakpointdialog.ui"> <FileType>Document</FileType> </QtUi> + <QtUi Include="graphicssettingswidget.ui"> + <FileType>Document</FileType> + </QtUi> <None Include="translations\duckstation-qt_es-es.ts" /> <None Include="translations\duckstation-qt_tr.ts" /> </ItemGroup> diff --git a/src/duckstation-qt/duckstation-qt.vcxproj.filters b/src/duckstation-qt/duckstation-qt.vcxproj.filters index b54f2db03..7fd2885b4 100644 --- a/src/duckstation-qt/duckstation-qt.vcxproj.filters +++ b/src/duckstation-qt/duckstation-qt.vcxproj.filters @@ -13,7 +13,7 @@ <ClCompile Include="audiosettingswidget.cpp" /> <ClCompile Include="displaywidget.cpp" /> <ClCompile Include="qtprogresscallback.cpp" /> - <ClCompile Include="generalsettingswidget.cpp" /> + <ClCompile Include="interfacesettingswidget.cpp" /> <ClCompile Include="advancedsettingswidget.cpp" /> <ClCompile Include="gdbconnection.cpp" /> <ClCompile Include="gdbserver.cpp" /> @@ -25,8 +25,6 @@ <ClCompile Include="gamelistsearchdirectoriesmodel.cpp" /> <ClCompile Include="autoupdaterdialog.cpp" /> <ClCompile Include="biossettingswidget.cpp" /> - <ClCompile Include="enhancementsettingswidget.cpp" /> - <ClCompile Include="displaysettingswidget.cpp" /> <ClCompile Include="memorycardeditorwindow.cpp" /> <ClCompile Include="postprocessingsettingswidget.cpp" /> <ClCompile Include="cheatmanagerdialog.cpp" /> @@ -105,18 +103,12 @@ <ClCompile Include="$(IntDir)moc_debuggerwindow.cpp"> <Filter>moc</Filter> </ClCompile> - <ClCompile Include="$(IntDir)moc_displaysettingswidget.cpp"> - <Filter>moc</Filter> - </ClCompile> <ClCompile Include="$(IntDir)moc_displaywidget.cpp"> <Filter>moc</Filter> </ClCompile> <ClCompile Include="$(IntDir)moc_emulationsettingswidget.cpp"> <Filter>moc</Filter> </ClCompile> - <ClCompile Include="$(IntDir)moc_enhancementsettingswidget.cpp"> - <Filter>moc</Filter> - </ClCompile> <ClCompile Include="$(IntDir)moc_foldersettingswidget.cpp"> <Filter>moc</Filter> </ClCompile> @@ -144,9 +136,6 @@ <ClCompile Include="$(IntDir)moc_gdbserver.cpp"> <Filter>moc</Filter> </ClCompile> - <ClCompile Include="$(IntDir)moc_generalsettingswidget.cpp"> - <Filter>moc</Filter> - </ClCompile> <ClCompile Include="$(IntDir)moc_hotkeysettingswidget.cpp"> <Filter>moc</Filter> </ClCompile> @@ -186,6 +175,13 @@ <ClCompile Include="$(IntDir)moc_setupwizarddialog.cpp"> <Filter>moc</Filter> </ClCompile> + <ClCompile Include="graphicssettingswidget.cpp" /> + <ClCompile Include="$(IntDir)moc_graphicssettingswidget.cpp"> + <Filter>moc</Filter> + </ClCompile> + <ClCompile Include="$(IntDir)moc_interfacesettingswidget.cpp"> + <Filter>moc</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="qtutils.h" /> @@ -216,7 +212,7 @@ <QtMoc Include="inputbindingwidgets.h" /> <QtMoc Include="audiosettingswidget.h" /> <QtMoc Include="displaywidget.h" /> - <QtMoc Include="generalsettingswidget.h" /> + <QtMoc Include="interfacesettingswidget.h" /> <QtMoc Include="qtprogresscallback.h" /> <QtMoc Include="advancedsettingswidget.h" /> <QtMoc Include="gdbconnection.h" /> @@ -228,9 +224,7 @@ <QtMoc Include="gamelistsearchdirectoriesmodel.h" /> <QtMoc Include="autoupdaterdialog.h" /> <QtMoc Include="biossettingswidget.h" /> - <QtMoc Include="enhancementsettingswidget.h" /> <QtMoc Include="memorycardeditorwindow.h" /> - <QtMoc Include="displaysettingswidget.h" /> <QtMoc Include="postprocessingsettingswidget.h" /> <QtMoc Include="cheatmanagerdialog.h" /> <QtMoc Include="cheatcodeeditordialog.h" /> @@ -251,6 +245,7 @@ <QtMoc Include="colorpickerbutton.h" /> <QtMoc Include="setupwizarddialog.h" /> <QtMoc Include="logwindow.h" /> + <QtMoc Include="graphicssettingswidget.h" /> </ItemGroup> <ItemGroup> <QtUi Include="consolesettingswidget.ui" /> @@ -258,14 +253,12 @@ <QtUi Include="mainwindow.ui" /> <QtUi Include="settingswindow.ui" /> <QtUi Include="audiosettingswidget.ui" /> - <QtUi Include="generalsettingswidget.ui" /> + <QtUi Include="interfacesettingswidget.ui" /> <QtUi Include="advancedsettingswidget.ui" /> <QtUi Include="aboutdialog.ui" /> <QtUi Include="inputbindingdialog.ui" /> <QtUi Include="autoupdaterdialog.ui" /> <QtUi Include="biossettingswidget.ui" /> - <QtUi Include="enhancementsettingswidget.ui" /> - <QtUi Include="displaysettingswidget.ui" /> <QtUi Include="postprocessingsettingswidget.ui" /> <QtUi Include="memorycardeditorwindow.ui" /> <QtUi Include="cheatmanagerdialog.ui" /> @@ -293,6 +286,7 @@ <QtUi Include="setupwizarddialog.ui" /> <QtUi Include="controllerledsettingsdialog.ui" /> <QtUi Include="debuggeraddbreakpointdialog.ui" /> + <QtUi Include="graphicssettingswidget.ui" /> </ItemGroup> <ItemGroup> <Natvis Include="qt5.natvis" /> diff --git a/src/duckstation-qt/enhancementsettingswidget.cpp b/src/duckstation-qt/enhancementsettingswidget.cpp deleted file mode 100644 index 4ffb7a782..000000000 --- a/src/duckstation-qt/enhancementsettingswidget.cpp +++ /dev/null @@ -1,223 +0,0 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#include "enhancementsettingswidget.h" -#include "core/gpu.h" -#include "core/settings.h" -#include "qtutils.h" -#include "settingswindow.h" -#include "settingwidgetbinder.h" - -EnhancementSettingsWidget::EnhancementSettingsWidget(SettingsWindow* dialog, QWidget* parent) - : QWidget(parent), m_dialog(dialog) -{ - SettingsInterface* sif = dialog->getSettingsInterface(); - - m_ui.setupUi(this); - setupAdditionalUi(); - - 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.gpuLineDetectMode, "GPU", "LineDetectMode", - &Settings::ParseLineDetectModeName, &Settings::GetLineDetectModeName, - Settings::DEFAULT_GPU_LINE_DETECT_MODE); - 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::BindWidgetToBoolSetting(sif, m_ui.trueColor, "GPU", "TrueColor", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.debanding, "GPU", "Debanding", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.scaledDithering, "GPU", "ScaledDithering", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableInterlacing, "GPU", "DisableInterlacing", true); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.forceNTSCTimings, "GPU", "ForceNTSCTimings", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.force43For24Bit, "Display", "Force4_3For24Bit", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.chromaSmoothingFor24Bit, "GPU", "ChromaSmoothing24Bit", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.widescreenHack, "GPU", "WidescreenHack", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useSoftwareRendererForReadbacks, "GPU", - "UseSoftwareRendererForReadbacks", false); - - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpEnable, "GPU", "PGXPEnable", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpCulling, "GPU", "PGXPCulling", true); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpTextureCorrection, "GPU", "PGXPTextureCorrection", true); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpColorCorrection, "GPU", "PGXPColorCorrection", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpDepthBuffer, "GPU", "PGXPDepthBuffer", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpPreserveProjPrecision, "GPU", "PGXPPreserveProjFP", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpCPU, "GPU", "PGXPCPU", false); - - connect(m_ui.resolutionScale, QOverload<int>::of(&QComboBox::currentIndexChanged), this, - &EnhancementSettingsWidget::onTrueColorChanged); - connect(m_ui.gpuDownsampleMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, - &EnhancementSettingsWidget::updateDownsampleScaleVisible); - connect(m_ui.trueColor, &QCheckBox::stateChanged, this, &EnhancementSettingsWidget::onTrueColorChanged); - updateDownsampleScaleVisible(); - onTrueColorChanged(); - - connect(m_ui.pgxpEnable, &QCheckBox::stateChanged, this, &EnhancementSettingsWidget::updatePGXPSettingsEnabled); - connect(m_ui.pgxpTextureCorrection, &QCheckBox::stateChanged, this, - &EnhancementSettingsWidget::updatePGXPSettingsEnabled); - updatePGXPSettingsEnabled(); - - dialog->registerWidgetHelp( - m_ui.gpuDownsampleMode, tr("Downsampling"), 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("Downsampling 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.disableInterlacing, tr("Disable Interlacing"), tr("Checked"), - tr( - "Forces the rendering and display of frames to progressive mode. <br>This removes the \"combing\" effect seen in " - "480i games by rendering them in 480p. Usually safe to enable.<br> " - "<b><u>May not be compatible with all games.</u></b>")); - dialog->registerWidgetHelp( - m_ui.resolutionScale, tr("Resolution Scale"), "1x", - tr("Setting this beyond 1x will enhance the resolution of rendered 3D polygons and lines. Only applies " - "to the hardware backends. <br>This option is usually safe, with most games looking fine at " - "higher resolutions. Higher resolutions require a more powerful GPU.")); - dialog->registerWidgetHelp( - m_ui.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 " - "channel. This produces nicer looking gradients at the cost of making some colours look slightly different. " - "Disabling the option also enables dithering, which makes the transition between colours less sharp by applying " - "a pattern around those pixels. Most games are compatible with this option, but there is a number which aren't " - "and will have broken effects with it enabled. Only applies to the hardware renderers.")); - dialog->registerWidgetHelp( - m_ui.debanding, tr("True Color Debanding"), tr("Unchecked"), - tr("Applies modern dithering techniques to further smooth out gradients when true color is enabled. " - "This debanding is performed during rendering (as opposed to a post-processing step), which allows it to be " - "fast while preserving detail. " - "Debanding increases the file size of screenshots due to the subtle dithering pattern present in screenshots.")); - dialog->registerWidgetHelp( - m_ui.scaledDithering, tr("Scaled Dithering"), tr("Checked"), - tr("Scales the dither pattern to the resolution scale of the emulated GPU. This makes the dither pattern much less " - "obvious at higher resolutions. <br>Usually safe to enable, and only supported by the hardware renderers.")); - dialog->registerWidgetHelp(m_ui.forceNTSCTimings, tr("Force NTSC Timings (60hz-on-PAL)"), tr("Unchecked"), - tr("Uses NTSC frame timings when the console is in PAL mode, forcing PAL games to run at " - "60hz. <br>For most games which " - "have a speed tied to the framerate, this will result in the game running " - "approximately 17% faster. <br>For variable " - "frame rate games, it may not affect the speed.")); - dialog->registerWidgetHelp( - m_ui.force43For24Bit, tr("Force 4:3 For 24-bit Display"), tr("Unchecked"), - tr("Switches back to 4:3 display aspect ratio when displaying 24-bit content, usually FMVs.")); - dialog->registerWidgetHelp(m_ui.chromaSmoothingFor24Bit, tr("Chroma Smoothing For 24-Bit Display"), tr("Unchecked"), - tr("Smooths out blockyness between colour transitions in 24-bit content, usually FMVs. " - "Only applies to the hardware renderers.")); - dialog->registerWidgetHelp( - m_ui.textureFiltering, tr("Texture Filtering"), - QString::fromUtf8(Settings::GetTextureFilterDisplayName(Settings::DEFAULT_GPU_TEXTURE_FILTER)), - tr("Smooths out the blockiness of magnified textures on 3D object by using filtering. <br>Will have a " - "greater effect on higher resolution scales. Only applies to the hardware renderers. <br>The JINC2 and " - "especially xBR filtering modes are very demanding, and may not be worth the speed penalty.")); - dialog->registerWidgetHelp(m_ui.gpuLineDetectMode, tr("Line Detection"), - QString::fromUtf8(Settings::GetLineDetectModeName(Settings::DEFAULT_GPU_LINE_DETECT_MODE)), - tr("Attempts to detect one pixel high/wide lines that rely on non-upscaled rasterization " - "behavior, filling in gaps introduced by upscaling.")); - dialog->registerWidgetHelp( - m_ui.widescreenHack, tr("Widescreen Hack"), tr("Unchecked"), - tr("Scales vertex positions in screen-space to a widescreen aspect ratio, essentially " - "increasing the field of view from 4:3 to the chosen display aspect ratio in 3D games. <br>For 2D games, or " - "games which use pre-rendered backgrounds, this enhancement will not work as expected. <br><b><u>May not be " - "compatible with all games.</u></b>")); - dialog->registerWidgetHelp( - m_ui.useSoftwareRendererForReadbacks, tr("Use Software Renderer For Readbacks"), tr("Unchecked"), - tr("Runs the software renderer in parallel for VRAM readbacks. On some systems, this may result in greater " - "performance when using graphical enhancements with the hardware renderer.")); - dialog->registerWidgetHelp( - m_ui.pgxpEnable, tr("Geometry Correction"), tr("Unchecked"), - tr("Reduces \"wobbly\" polygons and \"warping\" textures that are common in PS1 games. <br>Only " - "works with the hardware renderers. <b><u>May not be compatible with all games.</u></b>")); - dialog->registerWidgetHelp(m_ui.pgxpCulling, tr("Culling Correction"), tr("Checked"), - tr("Increases the precision of polygon culling, reducing the number of holes in geometry. " - "Requires geometry correction enabled.")); - dialog->registerWidgetHelp(m_ui.pgxpTextureCorrection, tr("Perspective Correct Textures"), tr("Checked"), - tr("Uses perspective-correct interpolation for texture coordinates, straightening out " - "warped textures. Requires geometry correction enabled.")); - dialog->registerWidgetHelp( - m_ui.pgxpColorCorrection, tr("Perspective Correct Colors"), tr("Unchecked"), - tr("Uses perspective-correct interpolation for vertex colors, which can improve visuals in some games, but cause " - "rendering errors in others. Requires geometry correction enabled.")); - dialog->registerWidgetHelp( - m_ui.pgxpDepthBuffer, tr("Depth Buffer (Low Compatibility)"), tr("Unchecked"), - tr("Attempts to reduce polygon Z-fighting by testing pixels against the depth values from PGXP. Low compatibility, " - "but can work well in some games. Other games may need a threshold adjustment.")); - dialog->registerWidgetHelp( - m_ui.pgxpPreserveProjPrecision, tr("Preserve Projection Precision"), tr("Unchecked"), - tr("Adds additional precision to PGXP data post-projection. May improve visuals in some games.")); - dialog->registerWidgetHelp(m_ui.pgxpCPU, tr("CPU Mode (Very Slow)"), tr("Unchecked"), - tr("Uses PGXP for all instructions, not just memory operations. Required for PGXP to " - "correct wobble in some games, but has a very high performance cost.")); -} - -EnhancementSettingsWidget::~EnhancementSettingsWidget() = default; - -void EnhancementSettingsWidget::onTrueColorChanged() -{ - const int resolution_scale = m_ui.resolutionScale->currentIndex(); - const bool true_color = m_ui.trueColor->isChecked(); - const bool allow_scaled_dithering = (resolution_scale != 1 && !true_color); - const bool allow_debanding = true_color; - m_ui.scaledDithering->setEnabled(allow_scaled_dithering); - m_ui.debanding->setEnabled(allow_debanding); -} - -void EnhancementSettingsWidget::updateDownsampleScaleVisible() -{ - const GPUDownsampleMode mode = - Settings::ParseDownsampleModeName( - m_dialog - ->getEffectiveStringValue("GPU", "DownsampleMode", - Settings::GetDownsampleModeName(Settings::DEFAULT_GPU_DOWNSAMPLE_MODE)) - .c_str()) - .value_or(Settings::DEFAULT_GPU_DOWNSAMPLE_MODE); - - const bool visible = (mode == GPUDownsampleMode::Box); - if (visible && m_ui.gpuDownsampleLayout->indexOf(m_ui.gpuDownsampleScale) < 0) - { - m_ui.gpuDownsampleScale->setVisible(true); - m_ui.gpuDownsampleLayout->addWidget(m_ui.gpuDownsampleScale, 0); - } - else if (!visible && m_ui.gpuDownsampleLayout->indexOf(m_ui.gpuDownsampleScale) >= 0) - { - m_ui.gpuDownsampleScale->setVisible(false); - m_ui.gpuDownsampleLayout->removeWidget(m_ui.gpuDownsampleScale); - } -} - -void EnhancementSettingsWidget::setupAdditionalUi() -{ - QtUtils::FillComboBoxWithResolutionScales(m_ui.resolutionScale); - - 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>(GPULineDetectMode::Count); i++) - { - m_ui.gpuLineDetectMode->addItem( - QString::fromUtf8(Settings::GetLineDetectModeDisplayName(static_cast<GPULineDetectMode>(i)))); - } - - for (u32 i = 0; i < static_cast<u32>(GPUDownsampleMode::Count); i++) - { - m_ui.gpuDownsampleMode->addItem( - QString::fromUtf8(Settings::GetDownsampleModeDisplayName(static_cast<GPUDownsampleMode>(i)))); - } -} - -void EnhancementSettingsWidget::updatePGXPSettingsEnabled() -{ - const bool enabled = m_dialog->getEffectiveBoolValue("GPU", "PGXPEnable", false); - const bool tc_enabled = enabled && m_dialog->getEffectiveBoolValue("GPU", "PGXPTextureCorrection", true); - m_ui.pgxpCulling->setEnabled(enabled); - m_ui.pgxpTextureCorrection->setEnabled(enabled); - m_ui.pgxpColorCorrection->setEnabled(tc_enabled); - m_ui.pgxpDepthBuffer->setEnabled(enabled); - m_ui.pgxpPreserveProjPrecision->setEnabled(enabled); - m_ui.pgxpCPU->setEnabled(enabled); -} diff --git a/src/duckstation-qt/enhancementsettingswidget.h b/src/duckstation-qt/enhancementsettingswidget.h deleted file mode 100644 index 448956a3f..000000000 --- a/src/duckstation-qt/enhancementsettingswidget.h +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> -// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) - -#pragma once - -#include <QtWidgets/QWidget> - -#include "ui_enhancementsettingswidget.h" - -class SettingsWindow; - -class EnhancementSettingsWidget : public QWidget -{ - Q_OBJECT - -public: - EnhancementSettingsWidget(SettingsWindow* dialog, QWidget* parent); - ~EnhancementSettingsWidget(); - -private Q_SLOTS: - void onTrueColorChanged(); - void updateDownsampleScaleVisible(); - void updatePGXPSettingsEnabled(); - -private: - void setupAdditionalUi(); - - Ui::EnhancementSettingsWidget m_ui; - - SettingsWindow* m_dialog; -}; diff --git a/src/duckstation-qt/enhancementsettingswidget.ui b/src/duckstation-qt/enhancementsettingswidget.ui deleted file mode 100644 index 9cf7cb407..000000000 --- a/src/duckstation-qt/enhancementsettingswidget.ui +++ /dev/null @@ -1,243 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>EnhancementSettingsWidget</class> - <widget class="QWidget" name="EnhancementSettingsWidget"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>640</width> - <height>480</height> - </rect> - </property> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QGroupBox" name="groupBox_2"> - <property name="title"> - <string>Rendering Enhancements</string> - </property> - <layout class="QFormLayout" name="formLayout_2"> - <item row="0" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Internal Resolution Scale:</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QComboBox" name="resolutionScale"/> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_3"> - <property name="text"> - <string>Texture Filtering:</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QComboBox" name="textureFiltering"/> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Downsampling:</string> - </property> - </widget> - </item> - <item row="4" column="1"> - <layout class="QHBoxLayout" name="gpuDownsampleLayout" stretch="1,0"> - <item> - <widget class="QComboBox" name="gpuDownsampleMode"/> - </item> - <item> - <widget class="QSpinBox" name="gpuDownsampleScale"> - <property name="suffix"> - <string>x</string> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>16</number> - </property> - </widget> - </item> - </layout> - </item> - <item row="5" column="0" colspan="2"> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> - <widget class="QCheckBox" name="trueColor"> - <property name="text"> - <string>True Color Rendering</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QCheckBox" name="debanding"> - <property name="text"> - <string>True Color Debanding</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QCheckBox" name="scaledDithering"> - <property name="text"> - <string>Scaled Dithering</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QCheckBox" name="widescreenHack"> - <property name="text"> - <string>Widescreen Hack</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QCheckBox" name="useSoftwareRendererForReadbacks"> - <property name="text"> - <string>Software Renderer Readbacks</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QCheckBox" name="disableInterlacing"> - <property name="text"> - <string>Disable Interlacing</string> - </property> - </widget> - </item> - </layout> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>Line Detection:</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QComboBox" name="gpuLineDetectMode"/> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="groupBox_3"> - <property name="title"> - <string>Display Enhancements</string> - </property> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="0" column="0"> - <widget class="QCheckBox" name="force43For24Bit"> - <property name="text"> - <string>Force 4:3 For FMVs</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QCheckBox" name="chromaSmoothingFor24Bit"> - <property name="text"> - <string>FMV Chroma Smoothing</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QCheckBox" name="forceNTSCTimings"> - <property name="text"> - <string>Force NTSC Timings</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="groupBox_4"> - <property name="title"> - <string>PGXP (Precision Geometry Transform Pipeline)</string> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="1"> - <widget class="QCheckBox" name="pgxpCulling"> - <property name="text"> - <string>Culling Correction</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QCheckBox" name="pgxpTextureCorrection"> - <property name="text"> - <string>Perspective Correct Textures</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QCheckBox" name="pgxpEnable"> - <property name="text"> - <string>Geometry Correction</string> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QCheckBox" name="pgxpCPU"> - <property name="text"> - <string>CPU Mode (Very Slow)</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QCheckBox" name="pgxpDepthBuffer"> - <property name="text"> - <string>Depth Buffer (Low Compatibility)</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QCheckBox" name="pgxpPreserveProjPrecision"> - <property name="text"> - <string>Preserve Projection Precision</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QCheckBox" name="pgxpColorCorrection"> - <property name="text"> - <string>Perspective Correct Colors</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src/duckstation-qt/graphicssettingswidget.cpp b/src/duckstation-qt/graphicssettingswidget.cpp new file mode 100644 index 000000000..034502ea4 --- /dev/null +++ b/src/duckstation-qt/graphicssettingswidget.cpp @@ -0,0 +1,861 @@ +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> +// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) + +#include "graphicssettingswidget.h" +#include "core/gpu.h" +#include "core/settings.h" +#include "qtutils.h" +#include "settingswindow.h" +#include "settingwidgetbinder.h" + +// For enumerating adapters. +#ifdef _WIN32 +#include "util/d3d11_device.h" +#include "util/d3d12_device.h" +#endif +#ifdef ENABLE_VULKAN +#include "util/vulkan_device.h" +#endif + +static QVariant GetMSAAModeValue(uint multisamples, bool ssaa) +{ + const uint userdata = (multisamples & 0x7FFFFFFFu) | (static_cast<uint>(ssaa) << 31); + return QVariant(userdata); +} + +static void DecodeMSAAModeValue(const QVariant& userdata, uint* multisamples, bool* ssaa) +{ + bool ok; + const uint value = userdata.toUInt(&ok); + if (!ok || value == 0) + { + *multisamples = 1; + *ssaa = false; + return; + } + + *multisamples = value & 0x7FFFFFFFu; + *ssaa = (value & (1u << 31)) != 0u; +} + +GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget* parent) + : QWidget(parent), m_dialog(dialog) +{ + SettingsInterface* sif = dialog->getSettingsInterface(); + + m_ui.setupUi(this); + setupAdditionalUi(); + removePlatformSpecificUi(); + + // Rendering Tab + + SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.renderer, "GPU", "Renderer", &Settings::ParseRendererName, + &Settings::GetRendererName, Settings::DEFAULT_GPU_RENDERER); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vsync, "Display", "VSync", false); + + SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayAspectRatio, "Display", "AspectRatio", + &Settings::ParseDisplayAspectRatio, &Settings::GetDisplayAspectRatioName, + Settings::DEFAULT_DISPLAY_ASPECT_RATIO); + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.customAspectRatioNumerator, "Display", + "CustomAspectRatioNumerator", 1); + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.customAspectRatioDenominator, "Display", + "CustomAspectRatioDenominator", 1); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.widescreenHack, "GPU", "WidescreenHack", false); + SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayCropMode, "Display", "CropMode", + &Settings::ParseDisplayCropMode, &Settings::GetDisplayCropModeName, + Settings::DEFAULT_DISPLAY_CROP_MODE); + SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayScaling, "Display", "Scaling", + &Settings::ParseDisplayScaling, &Settings::GetDisplayScalingName, + Settings::DEFAULT_DISPLAY_SCALING); + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.resolutionScale, "GPU", "ResolutionScale", 1); + SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.textureFiltering, "GPU", "TextureFilter", + &Settings::ParseTextureFilterName, &Settings::GetTextureFilterName, + Settings::DEFAULT_GPU_TEXTURE_FILTER); + SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.gpuDownsampleMode, "GPU", "DownsampleMode", + &Settings::ParseDownsampleModeName, &Settings::GetDownsampleModeName, + Settings::DEFAULT_GPU_DOWNSAMPLE_MODE); + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.gpuDownsampleScale, "GPU", "DownsampleScale", 1); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.trueColor, "GPU", "TrueColor", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableInterlacing, "GPU", "DisableInterlacing", true); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpEnable, "GPU", "PGXPEnable", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpDepthBuffer, "GPU", "PGXPDepthBuffer", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.force43For24Bit, "Display", "Force4_3For24Bit", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.chromaSmoothingFor24Bit, "GPU", "ChromaSmoothing24Bit", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.forceNTSCTimings, "GPU", "ForceNTSCTimings", false); + + connect(m_ui.renderer, QOverload<int>::of(&QComboBox::currentIndexChanged), this, + &GraphicsSettingsWidget::updateRendererDependentOptions); + connect(m_ui.adapter, QOverload<int>::of(&QComboBox::currentIndexChanged), this, + &GraphicsSettingsWidget::onAdapterChanged); + connect(m_ui.resolutionScale, QOverload<int>::of(&QComboBox::currentIndexChanged), this, + &GraphicsSettingsWidget::onTrueColorChanged); + connect(m_ui.displayAspectRatio, QOverload<int>::of(&QComboBox::currentIndexChanged), this, + &GraphicsSettingsWidget::onAspectRatioChanged); + connect(m_ui.gpuDownsampleMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, + &GraphicsSettingsWidget::onDownsampleModeChanged); + connect(m_ui.trueColor, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::onTrueColorChanged); + connect(m_ui.pgxpEnable, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::updatePGXPSettingsEnabled); + + if (!dialog->isPerGameSettings() || + (dialog->containsSettingValue("GPU", "Multisamples") || dialog->containsSettingValue("GPU", "PerSampleShading"))) + { + const QVariant current_msaa_mode( + GetMSAAModeValue(static_cast<uint>(dialog->getEffectiveIntValue("GPU", "Multisamples", 1)), + dialog->getEffectiveBoolValue("GPU", "PerSampleShading", false))); + const int current_msaa_index = m_ui.msaaMode->findData(current_msaa_mode); + if (current_msaa_index >= 0) + m_ui.msaaMode->setCurrentIndex(current_msaa_index); + } + else + { + m_ui.msaaMode->setCurrentIndex(0); + } + connect(m_ui.msaaMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, + &GraphicsSettingsWidget::onMSAAModeChanged); + + // Advanced Tab + + SettingWidgetBinder::BindWidgetToEnumSetting( + sif, m_ui.exclusiveFullscreenControl, "Display", "ExclusiveFullscreenControl", + &Settings::ParseDisplayExclusiveFullscreenControl, &Settings::GetDisplayExclusiveFullscreenControlName, + Settings::DEFAULT_DISPLAY_EXCLUSIVE_FULLSCREEN_CONTROL); + SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.displayAlignment, "Display", "Alignment", + &Settings::ParseDisplayAlignment, &Settings::GetDisplayAlignmentName, + Settings::DEFAULT_DISPLAY_ALIGNMENT); + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.displayFPSLimit, "Display", "MaxFPS", + Settings::DEFAULT_DISPLAY_MAX_FPS); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.gpuThread, "GPU", "UseThread", true); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.threadedPresentation, "GPU", "ThreadedPresentation", true); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.stretchDisplayVertically, "Display", "StretchVertically", + false); +#ifdef _WIN32 + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.blitSwapChain, "Display", "UseBlitSwapChain", false); +#endif + SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.gpuLineDetectMode, "GPU", "LineDetectMode", + &Settings::ParseLineDetectModeName, &Settings::GetLineDetectModeName, + Settings::DEFAULT_GPU_LINE_DETECT_MODE); + SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.gpuWireframeMode, "GPU", "WireframeMode", + Settings::ParseGPUWireframeMode, Settings::GetGPUWireframeModeName, + Settings::DEFAULT_GPU_WIREFRAME_MODE); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.debanding, "GPU", "Debanding", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.scaledDithering, "GPU", "ScaledDithering", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useSoftwareRendererForReadbacks, "GPU", + "UseSoftwareRendererForReadbacks", false); + + connect(m_ui.fullscreenMode, QOverload<int>::of(&QComboBox::currentIndexChanged), this, + &GraphicsSettingsWidget::onFullscreenModeChanged); + + // PGXP Tab + + SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.pgxpGeometryTolerance, "GPU", "PGXPTolerance", -1.0f); + SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.pgxpDepthClearThreshold, "GPU", "PGXPDepthClearThreshold", + Settings::DEFAULT_GPU_PGXP_DEPTH_THRESHOLD); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpTextureCorrection, "GPU", "PGXPTextureCorrection", true); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpColorCorrection, "GPU", "PGXPColorCorrection", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpCulling, "GPU", "PGXPCulling", true); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpPreserveProjPrecision, "GPU", "PGXPPreserveProjFP", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpCPU, "GPU", "PGXPCPU", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pgxpVertexCache, "GPU", "PGXPVertexCache", false); + + connect(m_ui.pgxpTextureCorrection, &QCheckBox::stateChanged, this, + &GraphicsSettingsWidget::updatePGXPSettingsEnabled); + connect(m_ui.pgxpDepthBuffer, &QCheckBox::stateChanged, this, &GraphicsSettingsWidget::updatePGXPSettingsEnabled); + + // OSD Tab + + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.osdScale, "Display", "OSDScale", 100); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showOSDMessages, "Display", "ShowOSDMessages", true); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showFPS, "Display", "ShowFPS", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showSpeed, "Display", "ShowSpeed", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showResolution, "Display", "ShowResolution", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showCPU, "Display", "ShowCPU", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showGPU, "Display", "ShowGPU", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showInput, "Display", "ShowInputs", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showGPUStatistics, "Display", "ShowGPUStatistics", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showStatusIndicators, "Display", "ShowStatusIndicators", true); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showFrameTimes, "Display", "ShowFrameTimes", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showSettings, "Display", "ShowEnhancements", false); + + // Capture Tab + + SettingWidgetBinder::BindWidgetToEnumSetting( + sif, m_ui.screenshotSize, "Display", "ScreenshotMode", &Settings::ParseDisplayScreenshotMode, + &Settings::GetDisplayScreenshotModeName, Settings::DEFAULT_DISPLAY_SCREENSHOT_MODE); + SettingWidgetBinder::BindWidgetToEnumSetting( + sif, m_ui.screenshotFormat, "Display", "ScreenshotFormat", &Settings::ParseDisplayScreenshotFormat, + &Settings::GetDisplayScreenshotFormatName, Settings::DEFAULT_DISPLAY_SCREENSHOT_FORMAT); + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.screenshotQuality, "Display", "ScreenshotQuality", + Settings::DEFAULT_DISPLAY_SCREENSHOT_QUALITY); + + // Texture Replacements Tab + + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vramWriteReplacement, "TextureReplacements", + "EnableVRAMWriteReplacements", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.preloadTextureReplacements, "TextureReplacements", + "PreloadTextures", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useOldMDECRoutines, "Hacks", "UseOldMDECRoutines", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.vramWriteDumping, "TextureReplacements", "DumpVRAMWrites", + false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.setVRAMWriteAlphaChannel, "TextureReplacements", + "DumpVRAMWriteForceAlphaChannel", true); + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.minDumpedVRAMWriteWidth, "TextureReplacements", + "DumpVRAMWriteWidthThreshold", + Settings::DEFAULT_VRAM_WRITE_DUMP_WIDTH_THRESHOLD); + SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.minDumpedVRAMWriteHeight, "TextureReplacements", + "DumpVRAMWriteHeightThreshold", + Settings::DEFAULT_VRAM_WRITE_DUMP_HEIGHT_THRESHOLD); + + connect(m_ui.vramWriteReplacement, &QCheckBox::stateChanged, this, + &GraphicsSettingsWidget::onEnableAnyTextureReplacementsChanged); + connect(m_ui.vramWriteDumping, &QCheckBox::stateChanged, this, + &GraphicsSettingsWidget::onEnableVRAMWriteDumpingChanged); + + // Debugging Tab + + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useDebugDevice, "GPU", "UseDebugDevice", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableShaderCache, "GPU", "DisableShaderCache", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableDualSource, "GPU", "DisableDualSourceBlend", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableFramebufferFetch, "GPU", "DisableFramebufferFetch", + false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableTextureBuffers, "GPU", "DisableTextureBuffers", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.disableTextureCopyToSelf, "GPU", "DisableTextureCopyToSelf", + false); + + // Init all dependent options. + updateRendererDependentOptions(); + onAspectRatioChanged(); + onDownsampleModeChanged(); + onTrueColorChanged(); + onEnableAnyTextureReplacementsChanged(); + onEnableVRAMWriteDumpingChanged(); + onShowDebugSettingsChanged(QtHost::ShouldShowDebugOptions()); + + // Rendering Tab + + dialog->registerWidgetHelp( + m_ui.renderer, tr("Renderer"), QString::fromUtf8(Settings::GetRendererDisplayName(Settings::DEFAULT_GPU_RENDERER)), + tr("Chooses the backend to use for rendering the console/game visuals. <br>Depending on your system and hardware, " + "Direct3D 11 and OpenGL hardware backends may be available. <br>The software renderer offers the best " + "compatibility, but is the slowest and does not offer any enhancements.")); + dialog->registerWidgetHelp( + m_ui.adapter, tr("Adapter"), tr("(Default)"), + tr("If your system contains multiple GPUs or adapters, you can select which GPU you wish to use for the hardware " + "renderers. <br>This option is only supported in Direct3D and Vulkan. OpenGL will always use the default " + "device.")); + dialog->registerWidgetHelp( + m_ui.vsync, tr("VSync"), tr("Unchecked"), + tr("Enable this option to match DuckStation's refresh rate with your current monitor or screen. " + "VSync is automatically disabled when it is not possible (e.g. running at non-100% speed).")); + dialog->registerWidgetHelp( + m_ui.displayAspectRatio, tr("Aspect Ratio"), + QString::fromUtf8(Settings::GetDisplayAspectRatioDisplayName(Settings::DEFAULT_DISPLAY_ASPECT_RATIO)), + tr("Changes the aspect ratio used to display the console's output to the screen. The default is Auto (Game Native) " + "which automatically adjusts the aspect ratio to match how a game would be shown on a typical TV of the era.")); + dialog->registerWidgetHelp( + m_ui.displayCropMode, tr("Crop Mode"), + QString::fromUtf8(Settings::GetDisplayCropModeDisplayName(Settings::DEFAULT_DISPLAY_CROP_MODE)), + tr("Determines how much of the area typically not visible on a consumer TV set to crop/hide. Some games display " + "content in the overscan area, or use it for screen effects. May not display correctly with the \"All Borders\" " + "setting. \"Only Overscan\" offers a good compromise between stability and hiding black borders.")); + dialog->registerWidgetHelp( + m_ui.displayScaling, tr("Scaling"), tr("Bilinear (Smooth)"), + tr("Determines how the emulated console's output is upscaled or downscaled to your monitor's resolution.")); + dialog->registerWidgetHelp( + m_ui.resolutionScale, tr("Internal Resolution"), "1x", + tr("Setting this beyond 1x will enhance the resolution of rendered 3D polygons and lines. Only applies " + "to the hardware backends. <br>This option is usually safe, with most games looking fine at " + "higher resolutions. Higher resolutions require a more powerful GPU.")); + dialog->registerWidgetHelp( + m_ui.msaaMode, tr("Multi-Sampling"), tr("Disabled"), + tr("Uses multi-sampled anti-aliasing when rendering 3D polygons. Can improve visuals with a lower performance " + "requirement compared to upscaling, <strong>but often introduces rendering errors.</strong>")); + dialog->registerWidgetHelp( + m_ui.gpuDownsampleMode, tr("Down-Sampling"), tr("Disabled"), + tr("Downsamples the rendered image prior to displaying it. Can improve overall image quality in mixed 2D/3D games, " + "but should be disabled for pure 3D games. Only applies to the hardware renderers.")); + dialog->registerWidgetHelp(m_ui.gpuDownsampleScale, tr("Down-Sampling Display Scale"), tr("1x"), + tr("Selects the resolution scale that will be applied to the final image. 1x will " + "downsample to the original console resolution.")); + dialog->registerWidgetHelp( + m_ui.textureFiltering, tr("Texture Filtering"), + QString::fromUtf8(Settings::GetTextureFilterDisplayName(Settings::DEFAULT_GPU_TEXTURE_FILTER)), + tr("Smooths out the blockiness of magnified textures on 3D object by using filtering. <br>Will have a " + "greater effect on higher resolution scales. Only applies to the hardware renderers. <br>The JINC2 and " + "especially xBR filtering modes are very demanding, and may not be worth the speed penalty.")); + dialog->registerWidgetHelp( + m_ui.trueColor, tr("True Color Rendering"), tr("Checked"), + tr("Forces the precision of colours output to the console's framebuffer to use the full 8 bits of precision per " + "channel. This produces nicer looking gradients at the cost of making some colours look slightly different. " + "Disabling the option also enables dithering, which makes the transition between colours less sharp by applying " + "a pattern around those pixels. Most games are compatible with this option, but there is a number which aren't " + "and will have broken effects with it enabled. Only applies to the hardware renderers.")); + dialog->registerWidgetHelp( + m_ui.widescreenHack, tr("Widescreen Rendering"), tr("Unchecked"), + tr("Scales vertex positions in screen-space to a widescreen aspect ratio, essentially " + "increasing the field of view from 4:3 to the chosen display aspect ratio in 3D games. <b><u>May not be " + "compatible with all games.</u></b>")); + dialog->registerWidgetHelp( + m_ui.pgxpEnable, tr("PGXP Geometry Correction"), tr("Unchecked"), + tr("Reduces \"wobbly\" polygons and \"warping\" textures that are common in PS1 games. <br>Only " + "works with the hardware renderers. <b><u>May not be compatible with all games.</u></b>")); + dialog->registerWidgetHelp( + m_ui.pgxpDepthBuffer, tr("PGXP Depth Buffer"), tr("Unchecked"), + tr("Attempts to reduce polygon Z-fighting by testing pixels against the depth values from PGXP. Low compatibility, " + "but can work well in some games. Other games may need a threshold adjustment.")); + dialog->registerWidgetHelp( + m_ui.force43For24Bit, tr("Force 4:3 For FMVs"), tr("Unchecked"), + tr("Switches back to 4:3 display aspect ratio when displaying 24-bit content, usually FMVs.")); + dialog->registerWidgetHelp(m_ui.chromaSmoothingFor24Bit, tr("FMV Chroma Smoothing"), tr("Unchecked"), + tr("Smooths out blockyness between colour transitions in 24-bit content, usually FMVs. " + "Only applies to the hardware renderers.")); + dialog->registerWidgetHelp( + m_ui.disableInterlacing, tr("Disable Interlacing"), tr("Checked"), + tr( + "Forces the rendering and display of frames to progressive mode. <br>This removes the \"combing\" effect seen in " + "480i games by rendering them in 480p. Usually safe to enable.<br><b><u>May not be compatible with all " + "games.</u></b>")); + dialog->registerWidgetHelp( + m_ui.forceNTSCTimings, tr("Force NTSC Timings"), tr("Unchecked"), + tr("Uses NTSC frame timings when the console is in PAL mode, forcing PAL games to run at 60hz. <br>For most games " + "which have a speed tied to the framerate, this will result in the game running approximately 17% faster. " + "<br>For variable frame rate games, it may not affect the speed.")); + + // Advanced Tab + + dialog->registerWidgetHelp(m_ui.fullscreenMode, tr("Fullscreen Mode"), tr("Borderless Fullscreen"), + tr("Chooses the fullscreen resolution and frequency.")); + dialog->registerWidgetHelp(m_ui.exclusiveFullscreenControl, tr("Exclusive Fullscreen Control"), tr("Automatic"), + tr("Controls whether exclusive fullscreen can be utilized by Vulkan drivers.")); + dialog->registerWidgetHelp( + m_ui.displayAlignment, tr("Position"), + QString::fromUtf8(Settings::GetDisplayAlignmentDisplayName(Settings::DEFAULT_DISPLAY_ALIGNMENT)), + tr("Determines the position on the screen when black borders must be added.")); + dialog->registerWidgetHelp( + m_ui.displayFPSLimit, tr("Display FPS Limit"), tr("0"), + tr("Limits the number of frames that are <strong>displayed</strong> every second. Discard frames are <strong>still " + "rendered.</strong> This option can increase frame rates when fast forwarding on some systems.")); + dialog->registerWidgetHelp(m_ui.gpuThread, tr("Threaded Rendering"), tr("Checked"), + tr("Uses a second thread for drawing graphics. Currently only available for the software " + "renderer, but can provide a significant speed improvement, and is safe to use.")); + dialog->registerWidgetHelp(m_ui.threadedPresentation, tr("Threaded Presentation"), tr("Checked"), + tr("Presents frames on a background thread when fast forwarding or vsync is disabled. " + "This can measurably improve performance in the Vulkan renderer.")); + dialog->registerWidgetHelp( + m_ui.stretchDisplayVertically, tr("Stretch Vertically"), tr("Unchecked"), + tr("Prefers stretching the display vertically instead of horizontally, wheen applying the display aspect ratio.")); +#ifdef _WIN32 + dialog->registerWidgetHelp(m_ui.blitSwapChain, tr("Use Blit Swap Chain"), tr("Unchecked"), + tr("Uses a blit presentation model instead of flipping when using the Direct3D 11 " + "renderer. This usually results in slower performance, but may be required for some " + "streaming applications, or to uncap framerates on some systems.")); +#endif + + dialog->registerWidgetHelp(m_ui.gpuLineDetectMode, tr("Line Detection"), + QString::fromUtf8(Settings::GetLineDetectModeName(Settings::DEFAULT_GPU_LINE_DETECT_MODE)), + tr("Attempts to detect one pixel high/wide lines that rely on non-upscaled rasterization " + "behavior, filling in gaps introduced by upscaling.")); + dialog->registerWidgetHelp(m_ui.gpuWireframeMode, tr("Wireframe Mode"), tr("Disabled"), + tr("Draws a wireframe outline of the triangles rendered by the console's GPU, either as a " + "replacement or an overlay.")); + dialog->registerWidgetHelp( + m_ui.debanding, tr("True Color Debanding"), tr("Unchecked"), + tr("Applies modern dithering techniques to further smooth out gradients when true color is enabled. " + "This debanding is performed during rendering (as opposed to a post-processing step), which allows it to be " + "fast while preserving detail. " + "Debanding increases the file size of screenshots due to the subtle dithering pattern present in screenshots.")); + dialog->registerWidgetHelp( + m_ui.scaledDithering, tr("Scaled Dithering"), tr("Checked"), + tr("Scales the dither pattern to the resolution scale of the emulated GPU. This makes the dither pattern much less " + "obvious at higher resolutions. <br>Usually safe to enable, and only supported by the hardware renderers.")); + dialog->registerWidgetHelp( + m_ui.useSoftwareRendererForReadbacks, tr("Software Renderer Readbacks"), tr("Unchecked"), + tr("Runs the software renderer in parallel for VRAM readbacks. On some systems, this may result in greater " + "performance when using graphical enhancements with the hardware renderer.")); + + // PGXP Tab + + dialog->registerWidgetHelp( + m_ui.pgxpGeometryTolerance, tr("Geometry Tolerance"), tr("-1.00px (Disabled)"), + tr("Discards precise geometry when it is found to be offset past the specified threshold. This can help with games " + "that have vertices significantly moved by PGXP, but is still a hack/workaround.")); + dialog->registerWidgetHelp(m_ui.pgxpDepthClearThreshold, tr("Depth Clear Threshold"), + QStringLiteral("%1").arg(Settings::DEFAULT_GPU_PGXP_DEPTH_THRESHOLD), + tr("Determines the increase in depth that will result in the depth buffer being cleared. " + "Can help with depth issues in some games, but is still a hack/workaround.")); + dialog->registerWidgetHelp(m_ui.pgxpTextureCorrection, tr("Perspective Correct Textures"), tr("Checked"), + tr("Uses perspective-correct interpolation for texture coordinates, straightening out " + "warped textures. Requires geometry correction enabled.")); + dialog->registerWidgetHelp( + m_ui.pgxpColorCorrection, tr("Perspective Correct Colors"), tr("Unchecked"), + tr("Uses perspective-correct interpolation for vertex colors, which can improve visuals in some games, but cause " + "rendering errors in others. Requires geometry correction enabled.")); + dialog->registerWidgetHelp(m_ui.pgxpCulling, tr("Culling Correction"), tr("Checked"), + tr("Increases the precision of polygon culling, reducing the number of holes in geometry. " + "Requires geometry correction enabled.")); + dialog->registerWidgetHelp( + m_ui.pgxpPreserveProjPrecision, tr("Preserve Projection Precision"), tr("Unchecked"), + tr("Adds additional precision to PGXP data post-projection. May improve visuals in some games.")); + dialog->registerWidgetHelp(m_ui.pgxpCPU, tr("CPU Mode"), tr("Unchecked"), + tr("Uses PGXP for all instructions, not just memory operations. Required for PGXP to " + "correct wobble in some games, but has a high performance cost.")); + dialog->registerWidgetHelp( + m_ui.pgxpVertexCache, tr("Vertex Cache"), tr("Unchecked"), + tr("Uses screen-space vertex positions to obtain precise positions, instead of tracking memory accesses. Can " + "provide PGXP compatibility for some games, but <strong>generally provides no benefit.</strong>")); + + // OSD Tab + + dialog->registerWidgetHelp( + m_ui.osdScale, tr("OSD Scale"), tr("100%"), + tr("Changes the size at which on-screen elements, including status and messages are displayed.")); + dialog->registerWidgetHelp(m_ui.showOSDMessages, tr("Show OSD Messages"), tr("Checked"), + tr("Shows on-screen-display messages when events occur such as save states being " + "created/loaded, screenshots being taken, etc.")); + dialog->registerWidgetHelp(m_ui.showResolution, tr("Show Resolution"), tr("Unchecked"), + tr("Shows the resolution of the game in the top-right corner of the display.")); + dialog->registerWidgetHelp( + m_ui.showSpeed, tr("Show Emulation Speed"), tr("Unchecked"), + tr("Shows the current emulation speed of the system in the top-right corner of the display as a percentage.")); + dialog->registerWidgetHelp(m_ui.showFPS, tr("Show FPS"), tr("Unchecked"), + tr("Shows the internal frame rate of the game in the top-right corner of the display.")); + dialog->registerWidgetHelp( + m_ui.showCPU, tr("Show CPU Usage"), tr("Unchecked"), + tr("Shows the host's CPU usage based on threads in the top-right corner of the display. This does not display the " + "emulated system CPU's usage. If a value close to 100% is being displayed, this means your host's CPU is likely " + "the bottleneck. In this case, you should reduce enhancement-related settings such as overclocking.")); + dialog->registerWidgetHelp(m_ui.showGPU, tr("Show GPU Usage"), tr("Unchecked"), + tr("Shows the host's GPU usage in the top-right corner of the display.")); + dialog->registerWidgetHelp(m_ui.showGPUStatistics, tr("Show GPU Statistics"), tr("Unchecked"), + tr("Shows information about the emulated GPU in the top-right corner of the display.")); + dialog->registerWidgetHelp( + m_ui.showFrameTimes, tr("Show Frame Times"), tr("Unchecked"), + tr("Shows the history of frame rendering times as a graph in the top-right corner of the display.")); + dialog->registerWidgetHelp( + m_ui.showInput, tr("Show Controller Input"), tr("Unchecked"), + tr("Shows the current controller state of the system in the bottom-left corner of the display.")); + dialog->registerWidgetHelp(m_ui.showInput, tr("Show Settings"), tr("Unchecked"), + tr("Shows a summary of current settings in the bottom-right corner of the display.")); + dialog->registerWidgetHelp(m_ui.showStatusIndicators, tr("Show Status Indicators"), tr("Checked"), + tr("Shows indicators on screen when the system is not running in its \"normal\" state. " + "For example, fast forwarding, or being paused.")); + + // Capture Tab + + dialog->registerWidgetHelp(m_ui.screenshotSize, tr("Screenshot Size"), tr("Screen Resolution"), + tr("Determines the resolution at which screenshots will be saved. Internal resolutions " + "preserve more detail at the cost of file size.")); + dialog->registerWidgetHelp( + m_ui.screenshotFormat, tr("Screenshot Format"), tr("PNG"), + tr("Selects the format which will be used to save screenshots. JPEG produces smaller files, but loses detail.")); + dialog->registerWidgetHelp(m_ui.screenshotQuality, tr("Screenshot Quality"), + QStringLiteral("%1%%").arg(Settings::DEFAULT_DISPLAY_SCREENSHOT_QUALITY), + tr("Selects the quality at which screenshots will be compressed. Higher values preserve " + "more detail for JPEG, and reduce file size for PNG.")); + + // Texture Replacements Tab + + dialog->registerWidgetHelp(m_ui.vramWriteReplacement, tr("Enable VRAM Write Replacement"), tr("Unchecked"), + tr("Enables the replacement of background textures in supported games. <strong>This is " + "not general texture replacement.</strong>")); + dialog->registerWidgetHelp(m_ui.preloadTextureReplacements, tr("Preload Texture Replacements"), tr("Unchecked"), + tr("Loads all replacement texture to RAM, reducing stuttering at runtime.")); + dialog->registerWidgetHelp(m_ui.useOldMDECRoutines, tr("Use Old MDEC Routines"), tr("Unchecked"), + tr("Enables the older, less accurate MDEC decoding routines. May be required for old " + "replacement backgrounds to match/load.")); + dialog->registerWidgetHelp(m_ui.setVRAMWriteAlphaChannel, tr("Set Alpha Channel"), tr("Checked"), + tr("Clears the mask/transparency bit in VRAM write dumps.")); + dialog->registerWidgetHelp(m_ui.vramWriteDumping, tr("Enable VRAM Write Dumping"), tr("Unchecked"), + tr("Writes backgrounds that can be replaced to the dump directory.")); + dialog->registerWidgetHelp(m_ui.minDumpedVRAMWriteWidth, tr("Dump Size Threshold"), tr("128px"), + tr("Determines the threshold that triggers a VRAM write to be dumped.")); + dialog->registerWidgetHelp(m_ui.minDumpedVRAMWriteHeight, tr("Dump Size Threshold"), tr("128px"), + tr("Determines the threshold that triggers a VRAM write to be dumped.")); + + // Debugging Tab + + dialog->registerWidgetHelp( + m_ui.useDebugDevice, tr("Use Debug Device"), tr("Unchecked"), + tr("Enable debugging when supported by the host's renderer API. <strong>Only for developer use.</strong>")); + dialog->registerWidgetHelp( + m_ui.disableShaderCache, tr("Disable Shader Cache"), tr("Unchecked"), + tr("Forces shaders to be compiled for every run of the program. <strong>Only for developer use.</strong>")); + dialog->registerWidgetHelp(m_ui.disableDualSource, tr("Disable Dual-Source Blending"), tr("Unchecked"), + tr("Prevents dual-source blending from being used. Useful for testing broken graphics " + "drivers. <strong>Only for developer use.</strong>")); + dialog->registerWidgetHelp(m_ui.disableFramebufferFetch, tr("Disable Framebuffer Fetch"), tr("Unchecked"), + tr("Prevents the framebuffer fetch extensions from being used. Useful for testing broken " + "graphics drivers. <strong>Only for developer use.</strong>")); + dialog->registerWidgetHelp( + m_ui.disableTextureBuffers, tr("Disable Texture Buffers"), tr("Unchecked"), + tr("Forces VRAM updates through texture updates, instead of texture buffers and draws. Useful for testing broken " + "graphics drivers. <strong>Only for developer use.</strong>")); + dialog->registerWidgetHelp(m_ui.disableTextureCopyToSelf, tr("Disable Texture Copies To Self"), tr("Unchecked"), + tr("Disables the use of self-copy updates for the VRAM texture. Useful for testing broken " + "graphics drivers. <strong>Only for developer use.</strong>")); +} + +GraphicsSettingsWidget::~GraphicsSettingsWidget() = default; + +void GraphicsSettingsWidget::setupAdditionalUi() +{ + // Rendering Tab + + for (u32 i = 0; i < static_cast<u32>(GPURenderer::Count); i++) + { + m_ui.renderer->addItem(QString::fromUtf8(Settings::GetRendererDisplayName(static_cast<GPURenderer>(i)))); + } + + for (u32 i = 0; i < static_cast<u32>(DisplayAspectRatio::Count); i++) + { + m_ui.displayAspectRatio->addItem( + QString::fromUtf8(Settings::GetDisplayAspectRatioDisplayName(static_cast<DisplayAspectRatio>(i)))); + } + + for (u32 i = 0; i < static_cast<u32>(DisplayCropMode::Count); i++) + { + m_ui.displayCropMode->addItem( + QString::fromUtf8(Settings::GetDisplayCropModeDisplayName(static_cast<DisplayCropMode>(i)))); + } + + for (u32 i = 0; i < static_cast<u32>(DisplayScalingMode::Count); i++) + { + m_ui.displayScaling->addItem( + QString::fromUtf8(Settings::GetDisplayScalingDisplayName(static_cast<DisplayScalingMode>(i)))); + } + + { + if (m_dialog->isPerGameSettings()) + m_ui.msaaMode->addItem(tr("Use Global Setting")); + m_ui.msaaMode->addItem(tr("Disabled"), GetMSAAModeValue(1, false)); + for (uint i = 2; i <= 32; i *= 2) + m_ui.msaaMode->addItem(tr("%1x MSAA").arg(i), GetMSAAModeValue(i, false)); + for (uint i = 2; i <= 32; i *= 2) + m_ui.msaaMode->addItem(tr("%1x SSAA").arg(i), GetMSAAModeValue(i, true)); + } + + for (u32 i = 0; i < static_cast<u32>(GPUTextureFilter::Count); i++) + { + m_ui.textureFiltering->addItem( + QString::fromUtf8(Settings::GetTextureFilterDisplayName(static_cast<GPUTextureFilter>(i)))); + } + + for (u32 i = 0; i < static_cast<u32>(GPUDownsampleMode::Count); i++) + { + m_ui.gpuDownsampleMode->addItem( + QString::fromUtf8(Settings::GetDownsampleModeDisplayName(static_cast<GPUDownsampleMode>(i)))); + } + + // Advanced Tab + + for (u32 i = 0; i < static_cast<u32>(DisplayExclusiveFullscreenControl::Count); i++) + { + m_ui.exclusiveFullscreenControl->addItem(QString::fromUtf8( + Settings::GetDisplayExclusiveFullscreenControlDisplayName(static_cast<DisplayExclusiveFullscreenControl>(i)))); + } + + for (u32 i = 0; i < static_cast<u32>(DisplayAlignment::Count); i++) + { + m_ui.displayAlignment->addItem( + QString::fromUtf8(Settings::GetDisplayAlignmentDisplayName(static_cast<DisplayAlignment>(i)))); + } + + for (u32 i = 0; i < static_cast<u32>(GPULineDetectMode::Count); i++) + { + m_ui.gpuLineDetectMode->addItem( + QString::fromUtf8(Settings::GetLineDetectModeDisplayName(static_cast<GPULineDetectMode>(i)))); + } + + for (u32 i = 0; i < static_cast<u32>(GPUWireframeMode::Count); i++) + { + m_ui.gpuWireframeMode->addItem( + QString::fromUtf8(Settings::GetGPUWireframeModeDisplayName(static_cast<GPUWireframeMode>(i)))); + } + + // Capture Tab + + for (u32 i = 0; i < static_cast<u32>(DisplayScreenshotMode::Count); i++) + { + m_ui.screenshotSize->addItem( + QString::fromUtf8(Settings::GetDisplayScreenshotModeDisplayName(static_cast<DisplayScreenshotMode>(i)))); + } + + for (u32 i = 0; i < static_cast<u32>(DisplayScreenshotFormat::Count); i++) + { + m_ui.screenshotFormat->addItem( + QString::fromUtf8(Settings::GetDisplayScreenshotFormatDisplayName(static_cast<DisplayScreenshotFormat>(i)))); + } +} + +void GraphicsSettingsWidget::removePlatformSpecificUi() +{ +#ifndef _WIN32 + m_ui.advancedDisplayOptionsLayout->removeWidget(m_ui.blitSwapChain); + delete m_ui.blitSwapChain; + m_ui.blitSwapChain = nullptr; +#endif +} + +GPURenderer GraphicsSettingsWidget::getEffectiveRenderer() const +{ + return Settings::ParseRendererName( + m_dialog + ->getEffectiveStringValue("GPU", "Renderer", Settings::GetRendererName(Settings::DEFAULT_GPU_RENDERER)) + .c_str()) + .value_or(Settings::DEFAULT_GPU_RENDERER); +} + +bool GraphicsSettingsWidget::effectiveRendererIsHardware() const +{ + return (getEffectiveRenderer() != GPURenderer::Software); +} + +void GraphicsSettingsWidget::onShowDebugSettingsChanged(bool enabled) +{ + m_ui.tabs->setTabVisible(TAB_INDEX_DEBUGGING, enabled); +} + +void GraphicsSettingsWidget::updateRendererDependentOptions() +{ + const GPURenderer renderer = getEffectiveRenderer(); + const RenderAPI render_api = Settings::GetRenderAPIForRenderer(renderer); + const bool is_hardware = (renderer != GPURenderer::Software); + + m_ui.resolutionScale->setEnabled(is_hardware); + m_ui.resolutionScaleLabel->setEnabled(is_hardware); + m_ui.msaaMode->setEnabled(is_hardware); + m_ui.msaaModeLabel->setEnabled(is_hardware); + m_ui.textureFiltering->setEnabled(is_hardware); + m_ui.textureFilteringLabel->setEnabled(is_hardware); + m_ui.gpuDownsampleLabel->setEnabled(is_hardware); + m_ui.gpuDownsampleMode->setEnabled(is_hardware); + m_ui.gpuDownsampleScale->setEnabled(is_hardware); + m_ui.trueColor->setEnabled(is_hardware); + m_ui.pgxpEnable->setEnabled(is_hardware); + m_ui.chromaSmoothingFor24Bit->setEnabled(is_hardware); + + m_ui.gpuLineDetectMode->setEnabled(is_hardware); + m_ui.gpuLineDetectModeLabel->setEnabled(is_hardware); + m_ui.gpuWireframeMode->setEnabled(is_hardware); + m_ui.gpuWireframeModeLabel->setEnabled(is_hardware); + m_ui.debanding->setEnabled(is_hardware); + m_ui.scaledDithering->setEnabled(is_hardware); + m_ui.useSoftwareRendererForReadbacks->setEnabled(is_hardware); + + m_ui.tabs->setTabEnabled(TAB_INDEX_TEXTURE_REPLACEMENTS, is_hardware); + +#ifdef _WIN32 + m_ui.blitSwapChain->setEnabled(render_api == RenderAPI::D3D11); +#endif + + m_ui.gpuThread->setEnabled(!is_hardware); + m_ui.threadedPresentation->setEnabled(render_api == RenderAPI::Vulkan); + + m_ui.exclusiveFullscreenLabel->setEnabled(render_api == RenderAPI::D3D11 || render_api == RenderAPI::D3D12 || + render_api == RenderAPI::Vulkan); + m_ui.exclusiveFullscreenControl->setEnabled(render_api == RenderAPI::Vulkan); + + populateGPUAdaptersAndResolutions(render_api); + updatePGXPSettingsEnabled(); +} + +void GraphicsSettingsWidget::populateGPUAdaptersAndResolutions(RenderAPI render_api) +{ + GPUDevice::AdapterAndModeList aml; + switch (render_api) + { +#ifdef _WIN32 + case RenderAPI::D3D11: + aml = D3D11Device::StaticGetAdapterAndModeList(); + break; + + case RenderAPI::D3D12: + aml = D3D12Device::StaticGetAdapterAndModeList(); + break; +#endif +#ifdef __APPLE__ + case RenderAPI::Metal: + aml = GPUDevice::WrapGetMetalAdapterAndModeList(); + break; +#endif +#ifdef ENABLE_VULKAN + case RenderAPI::Vulkan: + aml = VulkanDevice::StaticGetAdapterAndModeList(); + break; +#endif + + default: + break; + } + + { + const std::string current_adapter(m_dialog->getEffectiveStringValue("GPU", "Adapter", "")); + QSignalBlocker blocker(m_ui.adapter); + + // add the default entry - we'll fall back to this if the GPU no longer exists, or there's no options + m_ui.adapter->clear(); + m_ui.adapter->addItem(tr("(Default)")); + + // add the other adapters + for (const std::string& adapter_name : aml.adapter_names) + { + m_ui.adapter->addItem(QString::fromStdString(adapter_name)); + + if (adapter_name == current_adapter) + m_ui.adapter->setCurrentIndex(m_ui.adapter->count() - 1); + } + + // disable it if we don't have a choice + m_ui.adapter->setEnabled(!aml.adapter_names.empty()); + } + + { + const std::string current_mode(m_dialog->getEffectiveStringValue("GPU", "FullscreenMode", "")); + QSignalBlocker blocker(m_ui.fullscreenMode); + + m_ui.fullscreenMode->clear(); + m_ui.fullscreenMode->addItem(tr("Borderless Fullscreen")); + m_ui.fullscreenMode->setCurrentIndex(0); + + for (const std::string& mode_name : aml.fullscreen_modes) + { + m_ui.fullscreenMode->addItem(QString::fromStdString(mode_name)); + + if (mode_name == current_mode) + m_ui.fullscreenMode->setCurrentIndex(m_ui.fullscreenMode->count() - 1); + } + + // disable it if we don't have a choice + m_ui.fullscreenMode->setEnabled(!aml.fullscreen_modes.empty()); + } + + // TODO: MSAA modes +} + +void GraphicsSettingsWidget::updatePGXPSettingsEnabled() +{ + const bool enabled = (effectiveRendererIsHardware() && m_dialog->getEffectiveBoolValue("GPU", "PGXPEnable", false)); + const bool tc_enabled = (enabled && m_dialog->getEffectiveBoolValue("GPU", "PGXPTextureCorrection", true)); + const bool depth_enabled = (enabled && m_dialog->getEffectiveBoolValue("GPU", "PGXPDepthBuffer", false)); + m_ui.tabs->setTabEnabled(TAB_INDEX_PGXP, enabled); + m_ui.pgxpTab->setEnabled(enabled); + m_ui.pgxpCulling->setEnabled(enabled); + m_ui.pgxpTextureCorrection->setEnabled(enabled); + m_ui.pgxpColorCorrection->setEnabled(tc_enabled); + m_ui.pgxpDepthBuffer->setEnabled(enabled); + m_ui.pgxpPreserveProjPrecision->setEnabled(enabled); + m_ui.pgxpCPU->setEnabled(enabled); + m_ui.pgxpVertexCache->setEnabled(enabled); + m_ui.pgxpGeometryTolerance->setEnabled(enabled); + m_ui.pgxpGeometryToleranceLabel->setEnabled(enabled); + m_ui.pgxpDepthClearThreshold->setEnabled(depth_enabled); + m_ui.pgxpDepthClearThresholdLabel->setEnabled(depth_enabled); +} + +void GraphicsSettingsWidget::onAdapterChanged() +{ + if (m_ui.adapter->currentIndex() == 0) + { + // default + m_dialog->removeSettingValue("GPU", "Adapter"); + return; + } + + m_dialog->setStringSettingValue("GPU", "Adapter", m_ui.adapter->currentText().toUtf8().constData()); +} + +void GraphicsSettingsWidget::onAspectRatioChanged() +{ + const DisplayAspectRatio ratio = + Settings::ParseDisplayAspectRatio( + m_dialog + ->getEffectiveStringValue("Display", "AspectRatio", + Settings::GetDisplayAspectRatioName(Settings::DEFAULT_DISPLAY_ASPECT_RATIO)) + .c_str()) + .value_or(Settings::DEFAULT_DISPLAY_ASPECT_RATIO); + + const bool is_custom = (ratio == DisplayAspectRatio::Custom); + + m_ui.customAspectRatioNumerator->setVisible(is_custom); + m_ui.customAspectRatioDenominator->setVisible(is_custom); + m_ui.customAspectRatioSeparator->setVisible(is_custom); +} + +void GraphicsSettingsWidget::onMSAAModeChanged() +{ + const int index = m_ui.msaaMode->currentIndex(); + if (m_dialog->isPerGameSettings() && index == 0) + { + m_dialog->removeSettingValue("GPU", "Multisamples"); + m_dialog->removeSettingValue("GPU", "PerSampleShading"); + } + else + { + uint multisamples; + bool ssaa; + DecodeMSAAModeValue(m_ui.msaaMode->itemData(index), &multisamples, &ssaa); + m_dialog->setIntSettingValue("GPU", "Multisamples", static_cast<int>(multisamples)); + m_dialog->setBoolSettingValue("GPU", "PerSampleShading", ssaa); + } +} + +void GraphicsSettingsWidget::onTrueColorChanged() +{ + const int resolution_scale = m_ui.resolutionScale->currentIndex(); + const bool true_color = m_ui.trueColor->isChecked(); + const bool allow_scaled_dithering = (resolution_scale != 1 && !true_color); + const bool allow_debanding = true_color; + m_ui.scaledDithering->setEnabled(allow_scaled_dithering); + m_ui.debanding->setEnabled(allow_debanding); +} + +void GraphicsSettingsWidget::onDownsampleModeChanged() +{ + const GPUDownsampleMode mode = + Settings::ParseDownsampleModeName( + m_dialog + ->getEffectiveStringValue("GPU", "DownsampleMode", + Settings::GetDownsampleModeName(Settings::DEFAULT_GPU_DOWNSAMPLE_MODE)) + .c_str()) + .value_or(Settings::DEFAULT_GPU_DOWNSAMPLE_MODE); + + const bool visible = (mode == GPUDownsampleMode::Box); + if (visible && m_ui.gpuDownsampleLayout->indexOf(m_ui.gpuDownsampleScale) < 0) + { + m_ui.gpuDownsampleScale->setVisible(true); + m_ui.gpuDownsampleLayout->addWidget(m_ui.gpuDownsampleScale, 0); + } + else if (!visible && m_ui.gpuDownsampleLayout->indexOf(m_ui.gpuDownsampleScale) >= 0) + { + m_ui.gpuDownsampleScale->setVisible(false); + m_ui.gpuDownsampleLayout->removeWidget(m_ui.gpuDownsampleScale); + } +} + +void GraphicsSettingsWidget::onFullscreenModeChanged() +{ + if (m_ui.fullscreenMode->currentIndex() == 0) + { + // default + m_dialog->removeSettingValue("GPU", "FullscreenMode"); + return; + } + + m_dialog->setStringSettingValue("GPU", "FullscreenMode", m_ui.fullscreenMode->currentText().toUtf8().constData()); +} + +void GraphicsSettingsWidget::onEnableAnyTextureReplacementsChanged() +{ + const bool any_replacements_enabled = + m_dialog->getEffectiveBoolValue("TextureReplacements", "EnableVRAMWriteReplacements", false); + m_ui.preloadTextureReplacements->setEnabled(any_replacements_enabled); +} + +void GraphicsSettingsWidget::onEnableVRAMWriteDumpingChanged() +{ + const bool enabled = m_dialog->getEffectiveBoolValue("TextureReplacements", "DumpVRAMWrites", false); + m_ui.setVRAMWriteAlphaChannel->setEnabled(enabled); + m_ui.minDumpedVRAMWriteWidth->setEnabled(enabled); + m_ui.minDumpedVRAMWriteHeight->setEnabled(enabled); + m_ui.vramWriteDumpThresholdLabel->setEnabled(enabled); + m_ui.vramWriteDumpThresholdSeparator->setEnabled(enabled); +} diff --git a/src/duckstation-qt/graphicssettingswidget.h b/src/duckstation-qt/graphicssettingswidget.h new file mode 100644 index 000000000..d976915c7 --- /dev/null +++ b/src/duckstation-qt/graphicssettingswidget.h @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> +// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) + +#pragma once + +#include <QtWidgets/QWidget> + +#include "ui_graphicssettingswidget.h" + +enum class RenderAPI : u32; +enum class GPURenderer : u8; + +class SettingsWindow; + +class GraphicsSettingsWidget : public QWidget +{ + Q_OBJECT + +public: + GraphicsSettingsWidget(SettingsWindow* dialog, QWidget* parent); + ~GraphicsSettingsWidget(); + +public Q_SLOTS: + void onShowDebugSettingsChanged(bool enabled); + +private Q_SLOTS: + void updateRendererDependentOptions(); + void updatePGXPSettingsEnabled(); + + void onAdapterChanged(); + void onAspectRatioChanged(); + void onMSAAModeChanged(); + void onTrueColorChanged(); + void onDownsampleModeChanged(); + void onFullscreenModeChanged(); + void onEnableAnyTextureReplacementsChanged(); + void onEnableVRAMWriteDumpingChanged(); + +private: + static constexpr int TAB_INDEX_RENDERING = 0; + static constexpr int TAB_INDEX_ADVANCED = 1; + static constexpr int TAB_INDEX_PGXP = 2; + static constexpr int TAB_INDEX_OSD = 3; + static constexpr int TAB_INDEX_CAPTURE = 4; + static constexpr int TAB_INDEX_TEXTURE_REPLACEMENTS = 5; + static constexpr int TAB_INDEX_DEBUGGING = 6; + + void setupAdditionalUi(); + void removePlatformSpecificUi(); + + GPURenderer getEffectiveRenderer() const; + bool effectiveRendererIsHardware() const; + + void populateGPUAdaptersAndResolutions(RenderAPI render_api); + + Ui::GraphicsSettingsWidget m_ui; + + SettingsWindow* m_dialog; +}; diff --git a/src/duckstation-qt/graphicssettingswidget.ui b/src/duckstation-qt/graphicssettingswidget.ui new file mode 100644 index 000000000..e7c556b99 --- /dev/null +++ b/src/duckstation-qt/graphicssettingswidget.ui @@ -0,0 +1,1114 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>GraphicsSettingsWidget</class> + <widget class="QWidget" name="GraphicsSettingsWidget"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>584</width> + <height>446</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox_3"> + <property name="title"> + <string/> + </property> + <layout class="QFormLayout" name="formLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Renderer:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="renderer"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Adapter:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="1,0"> + <item> + <widget class="QComboBox" name="adapter"/> + </item> + <item> + <widget class="QCheckBox" name="vsync"> + <property name="text"> + <string>VSync</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QTabWidget" name="tabs"> + <property name="currentIndex"> + <number>0</number> + </property> + <property name="documentMode"> + <bool>true</bool> + </property> + <widget class="QWidget" name="basicTab"> + <attribute name="title"> + <string>Rendering</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox_6"> + <property name="title"> + <string/> + </property> + <layout class="QFormLayout" name="formLayout_2"> + <item row="0" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Aspect Ratio:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0,0,0"> + <item> + <widget class="QComboBox" name="displayAspectRatio"/> + </item> + <item> + <widget class="QSpinBox" name="customAspectRatioNumerator"> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>9999</number> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="customAspectRatioSeparator"> + <property name="text"> + <string>:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="customAspectRatioDenominator"> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>9999</number> + </property> + </widget> + </item> + </layout> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_7"> + <property name="text"> + <string>Crop:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="displayCropMode"/> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_8"> + <property name="text"> + <string>Scaling:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QComboBox" name="displayScaling"/> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="resolutionScaleLabel"> + <property name="text"> + <string>Internal Resolution:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="resolutionScale"> + <item> + <property name="text"> + <string>Automatic based on window size</string> + </property> + </item> + <item> + <property name="text"> + <string>1x</string> + </property> + </item> + <item> + <property name="text"> + <string>2x</string> + </property> + </item> + <item> + <property name="text"> + <string>3x (for 720p)</string> + </property> + </item> + <item> + <property name="text"> + <string>4x</string> + </property> + </item> + <item> + <property name="text"> + <string>5x (for 1080p)</string> + </property> + </item> + <item> + <property name="text"> + <string>6x (for 1440p)</string> + </property> + </item> + <item> + <property name="text"> + <string>7x</string> + </property> + </item> + <item> + <property name="text"> + <string>8x</string> + </property> + </item> + <item> + <property name="text"> + <string>9x (for 4K)</string> + </property> + </item> + <item> + <property name="text"> + <string>10x</string> + </property> + </item> + <item> + <property name="text"> + <string>11x</string> + </property> + </item> + <item> + <property name="text"> + <string>12x</string> + </property> + </item> + <item> + <property name="text"> + <string>13x</string> + </property> + </item> + <item> + <property name="text"> + <string>14x</string> + </property> + </item> + <item> + <property name="text"> + <string>15x</string> + </property> + </item> + <item> + <property name="text"> + <string>16x</string> + </property> + </item> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="msaaModeLabel"> + <property name="text"> + <string>Multi-Sampling:</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QComboBox" name="msaaMode"/> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="textureFilteringLabel"> + <property name="text"> + <string>Texture Filtering:</string> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QComboBox" name="textureFiltering"/> + </item> + <item row="8" column="0" colspan="2"> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="1" column="0"> + <widget class="QCheckBox" name="pgxpEnable"> + <property name="text"> + <string>PGXP Geometry Correction</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QCheckBox" name="pgxpDepthBuffer"> + <property name="text"> + <string>PGXP Depth Buffer (Low Compatibility)</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QCheckBox" name="force43For24Bit"> + <property name="text"> + <string>Force 4:3 For FMVs</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QCheckBox" name="chromaSmoothingFor24Bit"> + <property name="text"> + <string>FMV Chroma Smoothing</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QCheckBox" name="trueColor"> + <property name="text"> + <string>True Color Rendering</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QCheckBox" name="forceNTSCTimings"> + <property name="text"> + <string>Force NTSC Timings</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QCheckBox" name="disableInterlacing"> + <property name="text"> + <string>Disable Interlacing</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="widescreenHack"> + <property name="text"> + <string>Widescreen Rendering</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="gpuDownsampleLabel"> + <property name="text"> + <string>Down-Sampling:</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <layout class="QHBoxLayout" name="gpuDownsampleLayout" stretch="1,0"> + <item> + <widget class="QComboBox" name="gpuDownsampleMode"/> + </item> + <item> + <widget class="QSpinBox" name="gpuDownsampleScale"> + <property name="suffix"> + <string>x</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>16</number> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>75</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="advancedTab"> + <attribute name="title"> + <string>Advanced</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Display Options</string> + </property> + <layout class="QFormLayout" name="formLayout_7"> + <item row="0" column="0"> + <widget class="QLabel" name="exclusiveFullscreenLabel"> + <property name="text"> + <string>Exclusive Fullscreen:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_8" stretch="1,0"> + <item> + <widget class="QComboBox" name="fullscreenMode"/> + </item> + <item> + <widget class="QComboBox" name="exclusiveFullscreenControl"/> + </item> + </layout> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_11"> + <property name="text"> + <string>Screen Position:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="displayAlignment"/> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_13"> + <property name="text"> + <string>Display FPS Limit:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QSpinBox" name="displayFPSLimit"/> + </item> + <item row="3" column="0" colspan="2"> + <layout class="QGridLayout" name="advancedDisplayOptionsLayout"> + <item row="0" column="0"> + <widget class="QCheckBox" name="gpuThread"> + <property name="text"> + <string>Threaded Rendering</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="threadedPresentation"> + <property name="text"> + <string>Threaded Presentation</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QCheckBox" name="blitSwapChain"> + <property name="text"> + <string>Use Blit Swap Chain</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QCheckBox" name="stretchDisplayVertically"> + <property name="text"> + <string>Stretch Vertically</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Rendering Options</string> + </property> + <layout class="QFormLayout" name="formLayout_6"> + <item row="2" column="0" colspan="2"> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="0" column="1"> + <widget class="QCheckBox" name="scaledDithering"> + <property name="text"> + <string>Scaled Dithering</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QCheckBox" name="debanding"> + <property name="text"> + <string>True Color Debanding</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QCheckBox" name="useSoftwareRendererForReadbacks"> + <property name="text"> + <string>Software Renderer Readbacks</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="gpuLineDetectModeLabel"> + <property name="text"> + <string>Line Detection:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="gpuLineDetectMode"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="gpuWireframeModeLabel"> + <property name="text"> + <string>Wireframe Mode:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="gpuWireframeMode"/> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="pgxpTab"> + <attribute name="title"> + <string>PGXP</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox_7"> + <property name="title"> + <string/> + </property> + <layout class="QFormLayout" name="formLayout_4"> + <item row="0" column="0"> + <widget class="QLabel" name="pgxpGeometryToleranceLabel"> + <property name="text"> + <string>Geometry Tolerance:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QDoubleSpinBox" name="pgxpGeometryTolerance"> + <property name="prefix"> + <string/> + </property> + <property name="suffix"> + <string>px</string> + </property> + <property name="minimum"> + <double>-1.000000000000000</double> + </property> + <property name="maximum"> + <double>100.000000000000000</double> + </property> + <property name="singleStep"> + <double>0.250000000000000</double> + </property> + <property name="value"> + <double>-1.000000000000000</double> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="pgxpDepthClearThresholdLabel"> + <property name="text"> + <string>Depth Clear Threshold:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QDoubleSpinBox" name="pgxpDepthClearThreshold"> + <property name="maximum"> + <double>4096.000000000000000</double> + </property> + </widget> + </item> + <item row="2" column="0" colspan="2"> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QCheckBox" name="pgxpTextureCorrection"> + <property name="text"> + <string>Perspective Correct Textures</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="pgxpColorCorrection"> + <property name="text"> + <string>Perspective Correct Colors</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QCheckBox" name="pgxpCulling"> + <property name="text"> + <string>Culling Correction</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QCheckBox" name="pgxpPreserveProjPrecision"> + <property name="text"> + <string>Preserve Projection Precision</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QCheckBox" name="pgxpCPU"> + <property name="text"> + <string>CPU Mode</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QCheckBox" name="pgxpVertexCache"> + <property name="text"> + <string>Vertex Cache</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_4"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>215</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="osdTab"> + <attribute name="title"> + <string>OSD</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox_8"> + <property name="title"> + <string/> + </property> + <layout class="QFormLayout" name="formLayout_5"> + <item row="0" column="0"> + <widget class="QLabel" name="label_29"> + <property name="text"> + <string>OSD Scale:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QSpinBox" name="osdScale"> + <property name="suffix"> + <string>%</string> + </property> + <property name="minimum"> + <number>25</number> + </property> + <property name="maximum"> + <number>500</number> + </property> + </widget> + </item> + <item row="1" column="0" colspan="2"> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="4" column="0"> + <widget class="QCheckBox" name="showInput"> + <property name="text"> + <string>Show Controller Input</string> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QCheckBox" name="showStatusIndicators"> + <property name="text"> + <string>Show Status Indicators</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QCheckBox" name="showFPS"> + <property name="text"> + <string>Show FPS</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QCheckBox" name="showOSDMessages"> + <property name="text"> + <string>Show OSD Messages</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="showResolution"> + <property name="text"> + <string>Show Resolution</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QCheckBox" name="showSettings"> + <property name="text"> + <string>Show Settings</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QCheckBox" name="showCPU"> + <property name="text"> + <string>Show CPU Usage</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QCheckBox" name="showGPUStatistics"> + <property name="text"> + <string>Show GPU Statistics</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QCheckBox" name="showSpeed"> + <property name="text"> + <string>Show Emulation Speed</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QCheckBox" name="showFrameTimes"> + <property name="text"> + <string>Show Frame Times</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QCheckBox" name="showGPU"> + <property name="text"> + <string>Show GPU Usage</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_5"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>164</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="captureTab"> + <attribute name="title"> + <string>Capture</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_8"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox_10"> + <property name="title"> + <string>Screenshots</string> + </property> + <layout class="QFormLayout" name="formLayout_3"> + <item row="0" column="0"> + <widget class="QLabel" name="label_21"> + <property name="text"> + <string>Screenshot Size:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_5" stretch="1,0,0,0"> + <item> + <widget class="QComboBox" name="screenshotSize"/> + </item> + <item> + <widget class="QComboBox" name="screenshotFormat"/> + </item> + <item> + <widget class="QLabel" name="label_44"> + <property name="text"> + <string>Quality:</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="screenshotQuality"> + <property name="suffix"> + <string>%</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>100</number> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_7"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>295</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="tabTextureReplacements"> + <attribute name="title"> + <string>Texture Replacements</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox_5"> + <property name="title"> + <string>General Settings</string> + </property> + <layout class="QFormLayout" name="formLayout_8"> + <item row="0" column="0" colspan="2"> + <layout class="QGridLayout" name="gridLayout_6"> + <item row="0" column="0"> + <widget class="QCheckBox" name="vramWriteReplacement"> + <property name="text"> + <string>Enable VRAM Write Replacement</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="preloadTextureReplacements"> + <property name="text"> + <string>Preload Texture Replacements</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QCheckBox" name="useOldMDECRoutines"> + <property name="text"> + <string>Use Old MDEC Routines</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox_4"> + <property name="title"> + <string>VRAM Write Dumping</string> + </property> + <layout class="QFormLayout" name="formLayout_9"> + <item row="0" column="0" colspan="2"> + <layout class="QGridLayout" name="gridLayout_7"> + <item row="0" column="0"> + <widget class="QCheckBox" name="vramWriteDumping"> + <property name="text"> + <string>Enable VRAM Write Dumping</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="setVRAMWriteAlphaChannel"> + <property name="text"> + <string>Set Alpha Channel</string> + </property> + </widget> + </item> + </layout> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="vramWriteDumpThresholdLabel"> + <property name="text"> + <string>Dump Size Threshold:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_6" stretch="1,0,1"> + <item> + <widget class="QSpinBox" name="minDumpedVRAMWriteWidth"> + <property name="suffix"> + <string>px</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>1024</number> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="vramWriteDumpThresholdSeparator"> + <property name="text"> + <string>x</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="minDumpedVRAMWriteHeight"> + <property name="suffix"> + <string>px</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>512</number> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <widget class="QWidget" name="debugTab"> + <attribute name="title"> + <string>Debugging</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="groupBox_9"> + <property name="title"> + <string>Device Options</string> + </property> + <layout class="QFormLayout" name="formLayout_10"> + <item row="0" column="0" colspan="2"> + <layout class="QGridLayout" name="gridLayout_8"> + <item row="1" column="1"> + <widget class="QCheckBox" name="disableFramebufferFetch"> + <property name="text"> + <string>Disable Framebuffer Fetch</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QCheckBox" name="disableTextureCopyToSelf"> + <property name="text"> + <string>Disable Texture Copy To Self</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QCheckBox" name="disableDualSource"> + <property name="text"> + <string>Disable Dual-Source Blending</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QCheckBox" name="useDebugDevice"> + <property name="text"> + <string>Use Debug Device</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="disableShaderCache"> + <property name="text"> + <string>Disable Shader Cache</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QCheckBox" name="disableTextureBuffers"> + <property name="text"> + <string>Disable Texture Buffers</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_6"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>244</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/duckstation-qt/generalsettingswidget.cpp b/src/duckstation-qt/interfacesettingswidget.cpp similarity index 92% rename from src/duckstation-qt/generalsettingswidget.cpp rename to src/duckstation-qt/interfacesettingswidget.cpp index 83590dc6c..ef01a77ea 100644 --- a/src/duckstation-qt/generalsettingswidget.cpp +++ b/src/duckstation-qt/interfacesettingswidget.cpp @@ -1,16 +1,15 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) -#include "generalsettingswidget.h" +#include "interfacesettingswidget.h" #include "autoupdaterdialog.h" -#include "generalsettingswidget.h" #include "mainwindow.h" #include "qtutils.h" #include "scmversion/scmversion.h" #include "settingswindow.h" #include "settingwidgetbinder.h" -const char* GeneralSettingsWidget::THEME_NAMES[] = { +const char* InterfaceSettingsWidget::THEME_NAMES[] = { QT_TRANSLATE_NOOP("MainWindow", "Native"), QT_TRANSLATE_NOOP("MainWindow", "Fusion"), QT_TRANSLATE_NOOP("MainWindow", "Dark Fusion (Gray)"), @@ -20,13 +19,13 @@ const char* GeneralSettingsWidget::THEME_NAMES[] = { nullptr, }; -const char* GeneralSettingsWidget::THEME_VALUES[] = { +const char* InterfaceSettingsWidget::THEME_VALUES[] = { "", "fusion", "darkfusion", "darkfusionblue", "greymatter", "qdarkstyle", nullptr, }; -const char* GeneralSettingsWidget::DEFAULT_THEME_NAME = "darkfusion"; +const char* InterfaceSettingsWidget::DEFAULT_THEME_NAME = "darkfusion"; -GeneralSettingsWidget::GeneralSettingsWidget(SettingsWindow* dialog, QWidget* parent) +InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* dialog, QWidget* parent) : QWidget(parent), m_dialog(dialog) { SettingsInterface* sif = dialog->getSettingsInterface(); @@ -57,7 +56,7 @@ GeneralSettingsWidget::GeneralSettingsWidget(SettingsWindow* dialog, QWidget* pa Settings::DEFAULT_SAVE_STATE_COMPRESSION); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableDiscordPresence, "Main", "EnableDiscordPresence", false); connect(m_ui.renderToSeparateWindow, &QCheckBox::stateChanged, this, - &GeneralSettingsWidget::onRenderToSeparateWindowChanged); + &InterfaceSettingsWidget::onRenderToSeparateWindowChanged); onRenderToSeparateWindowChanged(); @@ -124,9 +123,9 @@ GeneralSettingsWidget::GeneralSettingsWidget(SettingsWindow* dialog, QWidget* pa } } -GeneralSettingsWidget::~GeneralSettingsWidget() = default; +InterfaceSettingsWidget::~InterfaceSettingsWidget() = default; -void GeneralSettingsWidget::onRenderToSeparateWindowChanged() +void InterfaceSettingsWidget::onRenderToSeparateWindowChanged() { m_ui.hideMainWindow->setEnabled(m_ui.renderToSeparateWindow->isChecked()); } diff --git a/src/duckstation-qt/generalsettingswidget.h b/src/duckstation-qt/interfacesettingswidget.h similarity index 56% rename from src/duckstation-qt/generalsettingswidget.h rename to src/duckstation-qt/interfacesettingswidget.h index a2c745030..7474b5cf4 100644 --- a/src/duckstation-qt/generalsettingswidget.h +++ b/src/duckstation-qt/interfacesettingswidget.h @@ -1,27 +1,27 @@ -// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once #include <QtWidgets/QWidget> -#include "ui_generalsettingswidget.h" +#include "ui_interfacesettingswidget.h" class SettingsWindow; -class GeneralSettingsWidget : public QWidget +class InterfaceSettingsWidget : public QWidget { Q_OBJECT public: - explicit GeneralSettingsWidget(SettingsWindow* dialog, QWidget* parent); - ~GeneralSettingsWidget(); + explicit InterfaceSettingsWidget(SettingsWindow* dialog, QWidget* parent); + ~InterfaceSettingsWidget(); private Q_SLOTS: void onRenderToSeparateWindowChanged(); private: - Ui::GeneralSettingsWidget m_ui; + Ui::InterfaceSettingsWidget m_ui; SettingsWindow* m_dialog; diff --git a/src/duckstation-qt/generalsettingswidget.ui b/src/duckstation-qt/interfacesettingswidget.ui similarity index 98% rename from src/duckstation-qt/generalsettingswidget.ui rename to src/duckstation-qt/interfacesettingswidget.ui index 03ac719a9..c6a18d85e 100644 --- a/src/duckstation-qt/generalsettingswidget.ui +++ b/src/duckstation-qt/interfacesettingswidget.ui @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> - <class>GeneralSettingsWidget</class> - <widget class="QWidget" name="GeneralSettingsWidget"> + <class>InterfaceSettingsWidget</class> + <widget class="QWidget" name="InterfaceSettingsWidget"> <property name="geometry"> <rect> <x>0</x> diff --git a/src/duckstation-qt/mainwindow.cpp b/src/duckstation-qt/mainwindow.cpp index aaa035332..021e57012 100644 --- a/src/duckstation-qt/mainwindow.cpp +++ b/src/duckstation-qt/mainwindow.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "mainwindow.h" @@ -11,7 +11,7 @@ #include "displaywidget.h" #include "gamelistsettingswidget.h" #include "gamelistwidget.h" -#include "generalsettingswidget.h" +#include "interfacesettingswidget.h" #include "logwindow.h" #include "memorycardeditorwindow.h" #include "qthost.h" @@ -1985,7 +1985,7 @@ void MainWindow::connectSignals() connect(m_ui.actionFullscreen, &QAction::triggered, g_emu_thread, &EmuThread::toggleFullscreen); connect(m_ui.actionSettings, &QAction::triggered, [this]() { doSettings(); }); connect(m_ui.actionSettings2, &QAction::triggered, this, &MainWindow::onSettingsTriggeredFromToolbar); - connect(m_ui.actionGeneralSettings, &QAction::triggered, [this]() { doSettings("General"); }); + connect(m_ui.actionInterfaceSettings, &QAction::triggered, [this]() { doSettings("Interface"); }); connect(m_ui.actionBIOSSettings, &QAction::triggered, [this]() { doSettings("BIOS"); }); connect(m_ui.actionConsoleSettings, &QAction::triggered, [this]() { doSettings("Console"); }); connect(m_ui.actionEmulationSettings, &QAction::triggered, [this]() { doSettings("Emulation"); }); @@ -1995,8 +1995,7 @@ void MainWindow::connectSignals() connect(m_ui.actionControllerSettings, &QAction::triggered, [this]() { doControllerSettings(ControllerSettingsWindow::Category::GlobalSettings); }); connect(m_ui.actionMemoryCardSettings, &QAction::triggered, [this]() { doSettings("Memory Cards"); }); - connect(m_ui.actionDisplaySettings, &QAction::triggered, [this]() { doSettings("Display"); }); - connect(m_ui.actionEnhancementSettings, &QAction::triggered, [this]() { doSettings("Enhancements"); }); + connect(m_ui.actionGraphicsSettings, &QAction::triggered, [this]() { doSettings("Graphics"); }); connect(m_ui.actionPostProcessingSettings, &QAction::triggered, [this]() { doSettings("Post-Processing"); }); connect(m_ui.actionAudioSettings, &QAction::triggered, [this]() { doSettings("Audio"); }); connect(m_ui.actionAchievementSettings, &QAction::triggered, [this]() { doSettings("Achievements"); }); @@ -2120,11 +2119,11 @@ void MainWindow::connectSignals() SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionDebugShowMDECState, "Debug", "ShowMDECState", false); SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionDebugShowDMAState, "Debug", "ShowDMAState", false); - for (u32 i = 0; GeneralSettingsWidget::THEME_NAMES[i]; i++) + for (u32 i = 0; InterfaceSettingsWidget::THEME_NAMES[i]; i++) { - const QString key = QString::fromUtf8(GeneralSettingsWidget::THEME_VALUES[i]); + const QString key = QString::fromUtf8(InterfaceSettingsWidget::THEME_VALUES[i]); QAction* action = - m_ui.menuSettingsTheme->addAction(qApp->translate("MainWindow", GeneralSettingsWidget::THEME_NAMES[i])); + m_ui.menuSettingsTheme->addAction(qApp->translate("MainWindow", InterfaceSettingsWidget::THEME_NAMES[i])); action->setCheckable(true); action->setData(key); connect(action, &QAction::toggled, [this, key](bool) { setTheme(key); }); @@ -2154,7 +2153,7 @@ void MainWindow::reloadThemeSpecificImages() void MainWindow::setStyleFromSettings() { - const std::string theme(Host::GetBaseStringSettingValue("UI", "Theme", GeneralSettingsWidget::DEFAULT_THEME_NAME)); + const std::string theme(Host::GetBaseStringSettingValue("UI", "Theme", InterfaceSettingsWidget::DEFAULT_THEME_NAME)); // setPalette() shouldn't be necessary, as the documentation claims that setStyle() resets the palette, but it // is here, to work around a bug in 6.4.x and 6.5.x where the palette doesn't restore after changing themes. @@ -2471,7 +2470,7 @@ void MainWindow::updateDebugMenuCropMode() void MainWindow::updateMenuSelectedTheme() { QString theme = - QString::fromStdString(Host::GetBaseStringSettingValue("UI", "Theme", GeneralSettingsWidget::DEFAULT_THEME_NAME)); + QString::fromStdString(Host::GetBaseStringSettingValue("UI", "Theme", InterfaceSettingsWidget::DEFAULT_THEME_NAME)); for (QObject* obj : m_ui.menuSettingsTheme->children()) { @@ -2613,7 +2612,7 @@ void MainWindow::startupUpdateCheck() void MainWindow::updateDebugMenuVisibility() { - const bool visible = Host::GetBaseBoolSettingValue("Main", "ShowDebugMenu", false); + const bool visible = QtHost::ShouldShowDebugOptions(); m_ui.menuDebug->menuAction()->setVisible(visible); } diff --git a/src/duckstation-qt/mainwindow.ui b/src/duckstation-qt/mainwindow.ui index afa8d67ac..d1c521be9 100644 --- a/src/duckstation-qt/mainwindow.ui +++ b/src/duckstation-qt/mainwindow.ui @@ -123,14 +123,13 @@ </widget> <addaction name="actionViewGameProperties"/> <addaction name="separator"/> - <addaction name="actionGeneralSettings"/> + <addaction name="actionInterfaceSettings"/> <addaction name="actionGameListSettings"/> <addaction name="actionBIOSSettings"/> <addaction name="actionConsoleSettings"/> <addaction name="actionEmulationSettings"/> <addaction name="actionMemoryCardSettings"/> - <addaction name="actionDisplaySettings"/> - <addaction name="actionEnhancementSettings"/> + <addaction name="actionGraphicsSettings"/> <addaction name="actionPostProcessingSettings"/> <addaction name="actionAudioSettings"/> <addaction name="actionAchievementSettings"/> @@ -433,22 +432,13 @@ <string>&Hotkeys</string> </property> </action> - <action name="actionDisplaySettings"> + <action name="actionGraphicsSettings"> <property name="icon"> <iconset theme="image-fill"> <normaloff>.</normaloff>.</iconset> </property> <property name="text"> - <string>&Display</string> - </property> - </action> - <action name="actionEnhancementSettings"> - <property name="icon"> - <iconset theme="sparkle-fill"> - <normaloff>.</normaloff>.</iconset> - </property> - <property name="text"> - <string>&Enhancements</string> + <string>&Graphics</string> </property> </action> <action name="actionPostProcessingSettings"> @@ -587,13 +577,13 @@ <string>Game List</string> </property> </action> - <action name="actionGeneralSettings"> + <action name="actionInterfaceSettings"> <property name="icon"> <iconset theme="settings-3-line"> <normaloff>.</normaloff>.</iconset> </property> <property name="text"> - <string>General</string> + <string>&Interface</string> </property> </action> <action name="actionAdvancedSettings"> diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp index 94f0b46b5..6a9cbadfb 100644 --- a/src/duckstation-qt/qthost.cpp +++ b/src/duckstation-qt/qthost.cpp @@ -1373,7 +1373,7 @@ void EmuThread::saveScreenshot() return; } - System::SaveScreenshot(nullptr, true, true); + System::SaveScreenshot(); } void Host::OnAchievementsLoginRequested(Achievements::LoginRequestReason reason) @@ -1830,6 +1830,11 @@ void QtHost::QueueSettingsSave() s_settings_save_timer->start(SETTINGS_SAVE_DELAY); } +bool QtHost::ShouldShowDebugOptions() +{ + return Host::GetBaseBoolSettingValue("Main", "ShowDebugMenu", false); +} + void Host::RequestSystemShutdown(bool allow_confirm, bool save_state) { if (!System::IsValid()) diff --git a/src/duckstation-qt/qthost.h b/src/duckstation-qt/qthost.h index 97d768158..907d390a9 100644 --- a/src/duckstation-qt/qthost.h +++ b/src/duckstation-qt/qthost.h @@ -286,6 +286,9 @@ bool DownloadFileFromZip(QWidget* parent, const QString& title, std::string url, /// Thread-safe settings access. void QueueSettingsSave(); +/// Returns true if the debug menu and functionality should be shown. +bool ShouldShowDebugOptions(); + /// VM state, safe to access on UI thread. bool IsSystemValid(); bool IsSystemPaused(); diff --git a/src/duckstation-qt/qtutils.cpp b/src/duckstation-qt/qtutils.cpp index e010c92e4..23c443bbb 100644 --- a/src/duckstation-qt/qtutils.cpp +++ b/src/duckstation-qt/qtutils.cpp @@ -693,59 +693,6 @@ void OpenURL(QWidget* parent, const char* url) return OpenURL(parent, QUrl::fromEncoded(QByteArray(url, static_cast<int>(std::strlen(url))))); } -void FillComboBoxWithResolutionScales(QComboBox* cb) -{ - cb->addItem(qApp->translate("GPUSettingsWidget", "Automatic based on window size")); - cb->addItem(qApp->translate("GPUSettingsWidget", "1x")); - cb->addItem(qApp->translate("GPUSettingsWidget", "2x")); - cb->addItem(qApp->translate("GPUSettingsWidget", "3x (for 720p)")); - cb->addItem(qApp->translate("GPUSettingsWidget", "4x")); - cb->addItem(qApp->translate("GPUSettingsWidget", "5x (for 1080p)")); - cb->addItem(qApp->translate("GPUSettingsWidget", "6x (for 1440p)")); - cb->addItem(qApp->translate("GPUSettingsWidget", "7x")); - cb->addItem(qApp->translate("GPUSettingsWidget", "8x")); - cb->addItem(qApp->translate("GPUSettingsWidget", "9x (for 4K)")); - cb->addItem(qApp->translate("GPUSettingsWidget", "10x")); - cb->addItem(qApp->translate("GPUSettingsWidget", "11x")); - cb->addItem(qApp->translate("GPUSettingsWidget", "12x")); - cb->addItem(qApp->translate("GPUSettingsWidget", "13x")); - cb->addItem(qApp->translate("GPUSettingsWidget", "14x")); - cb->addItem(qApp->translate("GPUSettingsWidget", "15x")); - cb->addItem(qApp->translate("GPUSettingsWidget", "16x")); -} - -QVariant GetMSAAModeValue(uint multisamples, bool ssaa) -{ - const uint userdata = (multisamples & 0x7FFFFFFFu) | (static_cast<uint>(ssaa) << 31); - return QVariant(userdata); -} - -void DecodeMSAAModeValue(const QVariant& userdata, uint* multisamples, bool* ssaa) -{ - bool ok; - const uint value = userdata.toUInt(&ok); - if (!ok || value == 0) - { - *multisamples = 1; - *ssaa = false; - return; - } - - *multisamples = value & 0x7FFFFFFFu; - *ssaa = (value & (1u << 31)) != 0u; -} - -void FillComboBoxWithMSAAModes(QComboBox* cb) -{ - cb->addItem(qApp->translate("GPUSettingsWidget", "Disabled"), GetMSAAModeValue(1, false)); - - for (uint i = 2; i <= 32; i *= 2) - cb->addItem(qApp->translate("GPUSettingsWidget", "%1x MSAA").arg(i), GetMSAAModeValue(i, false)); - - for (uint i = 2; i <= 32; i *= 2) - cb->addItem(qApp->translate("GPUSettingsWidget", "%1x SSAA").arg(i), GetMSAAModeValue(i, true)); -} - std::optional<unsigned> PromptForAddress(QWidget* parent, const QString& title, const QString& label, bool code) { const QString address_str( diff --git a/src/duckstation-qt/qtutils.h b/src/duckstation-qt/qtutils.h index 8ed8c66c1..44a8e8447 100644 --- a/src/duckstation-qt/qtutils.h +++ b/src/duckstation-qt/qtutils.h @@ -67,14 +67,6 @@ void OpenURL(QWidget* parent, const QUrl& qurl); /// Opens a URL string with the default handler. void OpenURL(QWidget* parent, const char* url); -/// Fills a combo box with resolution scale options. -void FillComboBoxWithResolutionScales(QComboBox* cb); - -/// Fills a combo box with multisampling options. -QVariant GetMSAAModeValue(uint multisamples, bool ssaa); -void DecodeMSAAModeValue(const QVariant& userdata, uint* multisamples, bool* ssaa); -void FillComboBoxWithMSAAModes(QComboBox* cb); - /// Prompts for an address in hex. std::optional<unsigned> PromptForAddress(QWidget* parent, const QString& title, const QString& label, bool code); diff --git a/src/duckstation-qt/settingswindow.cpp b/src/duckstation-qt/settingswindow.cpp index 020b1efbe..51721cdfb 100644 --- a/src/duckstation-qt/settingswindow.cpp +++ b/src/duckstation-qt/settingswindow.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "settingswindow.h" @@ -8,13 +8,12 @@ #include "consolesettingswidget.h" #include "achievementsettingswidget.h" -#include "displaysettingswidget.h" #include "emulationsettingswidget.h" -#include "enhancementsettingswidget.h" #include "foldersettingswidget.h" #include "gamelistsettingswidget.h" #include "gamesummarywidget.h" -#include "generalsettingswidget.h" +#include "graphicssettingswidget.h" +#include "interfacesettingswidget.h" #include "mainwindow.h" #include "memorycardsettingswidget.h" #include "postprocessingsettingswidget.h" @@ -78,9 +77,9 @@ void SettingsWindow::closeEvent(QCloseEvent* event) void SettingsWindow::addPages() { addWidget( - m_general_settings = new GeneralSettingsWidget(this, m_ui.settingsContainer), tr("General"), + m_general_settings = new InterfaceSettingsWidget(this, m_ui.settingsContainer), tr("Interface"), QStringLiteral("settings-3-line"), - tr("<strong>General Settings</strong><hr>These options control how the emulator looks and " + tr("<strong>Interface Settings</strong><hr>These options control how the emulator looks and " "behaves.<br><br>Mouse over an option for additional information, and Shift+Wheel to scroll this panel.")); if (!isPerGameSettings()) @@ -112,17 +111,11 @@ void SettingsWindow::addPages() QStringLiteral("memcard-line"), tr("<strong>Memory Card Settings</strong><hr>This page lets you control what mode the memory card emulation will " "function in, and where the images for these cards will be stored on disk.")); - addWidget( - m_display_settings = new DisplaySettingsWidget(this, m_ui.settingsContainer), tr("Display"), - QStringLiteral("image-fill"), - tr("<strong>Display Settings</strong><hr>These options control the how the frames generated by the console are " - "displayed on the screen.")); - addWidget( - m_enhancement_settings = new EnhancementSettingsWidget(this, m_ui.settingsContainer), tr("Enhancements"), - QStringLiteral("sparkle-fill"), - tr("<strong>Enhancement Settings</strong><hr>These options control enhancements which can improve visuals compared " - "to the original console. Mouse over each option for additional information, and Shift+Wheel to scroll this " - "panel.")); + addWidget(m_graphics_settings = new GraphicsSettingsWidget(this, m_ui.settingsContainer), tr("Graphics"), + QStringLiteral("image-fill"), + tr("<strong>Graphics Settings</strong><hr>These options control how the graphics of the emulated console " + "are rendered. Not all options are available for the software renderer. Mouse over each option for " + "additional information, and Shift+Wheel to scroll this panel.")); addWidget( m_post_processing_settings = new PostProcessingSettingsWidget(this, m_ui.settingsContainer), tr("Post-Processing"), QStringLiteral("sun-fill"), @@ -168,6 +161,9 @@ void SettingsWindow::addPages() tr("<strong>Advanced Settings</strong><hr>These options control logging and internal behavior of the " "emulator. Mouse over an option for additional information, and Shift+Wheel to scroll this panel.")); + connect(m_advanced_settings, &AdvancedSettingsWidget::onShowDebugOptionsChanged, m_graphics_settings, + &GraphicsSettingsWidget::onShowDebugSettingsChanged); + if (isPerGameSettings()) { m_ui.buttonBox->button(QDialogButtonBox::RestoreDefaults)->setVisible(false); @@ -500,6 +496,14 @@ void SettingsWindow::setStringSettingValue(const char* section, const char* key, } } +bool SettingsWindow::containsSettingValue(const char* section, const char* key) const +{ + if (m_sif) + return m_sif->ContainsValue(section, key); + else + return Host::ContainsBaseSettingValue(section, key); +} + void SettingsWindow::removeSettingValue(const char* section, const char* key) { if (m_sif) diff --git a/src/duckstation-qt/settingswindow.h b/src/duckstation-qt/settingswindow.h index 8cb0fa6db..bfb1f718e 100644 --- a/src/duckstation-qt/settingswindow.h +++ b/src/duckstation-qt/settingswindow.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once @@ -21,14 +21,13 @@ namespace GameDatabase { struct Entry; } -class GeneralSettingsWidget; +class InterfaceSettingsWidget; class BIOSSettingsWidget; class GameListSettingsWidget; class ConsoleSettingsWidget; class EmulationSettingsWidget; class MemoryCardSettingsWidget; -class DisplaySettingsWidget; -class EnhancementSettingsWidget; +class GraphicsSettingsWidget; class PostProcessingSettingsWidget; class AudioSettingsWidget; class AchievementSettingsWidget; @@ -51,14 +50,13 @@ public: ALWAYS_INLINE bool isPerGameSettings() const { return static_cast<bool>(m_sif); } ALWAYS_INLINE SettingsInterface* getSettingsInterface() const { return m_sif.get(); } - ALWAYS_INLINE GeneralSettingsWidget* getGeneralSettingsWidget() const { return m_general_settings; } + ALWAYS_INLINE InterfaceSettingsWidget* getGeneralSettingsWidget() const { return m_general_settings; } ALWAYS_INLINE BIOSSettingsWidget* getBIOSSettingsWidget() const { return m_bios_settings; } ALWAYS_INLINE ConsoleSettingsWidget* getConsoleSettingsWidget() const { return m_console_settings; } ALWAYS_INLINE EmulationSettingsWidget* getEmulationSettingsWidget() const { return m_emulation_settings; } ALWAYS_INLINE GameListSettingsWidget* getGameListSettingsWidget() const { return m_game_list_settings; } ALWAYS_INLINE MemoryCardSettingsWidget* getMemoryCardSettingsWidget() const { return m_memory_card_settings; } - ALWAYS_INLINE DisplaySettingsWidget* getDisplaySettingsWidget() const { return m_display_settings; } - ALWAYS_INLINE EnhancementSettingsWidget* getEnhancementSettingsWidget() const { return m_enhancement_settings; } + ALWAYS_INLINE GraphicsSettingsWidget* getGraphicsSettingsWidget() const { return m_graphics_settings; } ALWAYS_INLINE AudioSettingsWidget* getAudioSettingsWidget() const { return m_audio_settings; } ALWAYS_INLINE AchievementSettingsWidget* getAchievementSettingsWidget() const { return m_achievement_settings; } ALWAYS_INLINE AdvancedSettingsWidget* getAdvancedSettingsWidget() const { return m_advanced_settings; } @@ -85,6 +83,7 @@ public: void setIntSettingValue(const char* section, const char* key, std::optional<int> value); void setFloatSettingValue(const char* section, const char* key, std::optional<float> value); void setStringSettingValue(const char* section, const char* key, std::optional<const char*> value); + bool containsSettingValue(const char* section, const char* key) const; void removeSettingValue(const char* section, const char* key); Q_SIGNALS: @@ -104,7 +103,7 @@ protected: private: enum : u32 { - MAX_SETTINGS_WIDGETS = 13 + MAX_SETTINGS_WIDGETS = 12 }; void addPages(); @@ -115,14 +114,13 @@ private: std::unique_ptr<SettingsInterface> m_sif; - GeneralSettingsWidget* m_general_settings = nullptr; + InterfaceSettingsWidget* m_general_settings = nullptr; BIOSSettingsWidget* m_bios_settings = nullptr; ConsoleSettingsWidget* m_console_settings = nullptr; EmulationSettingsWidget* m_emulation_settings = nullptr; GameListSettingsWidget* m_game_list_settings = nullptr; MemoryCardSettingsWidget* m_memory_card_settings = nullptr; - DisplaySettingsWidget* m_display_settings = nullptr; - EnhancementSettingsWidget* m_enhancement_settings = nullptr; + GraphicsSettingsWidget* m_graphics_settings = nullptr; PostProcessingSettingsWidget* m_post_processing_settings = nullptr; AudioSettingsWidget* m_audio_settings = nullptr; AchievementSettingsWidget* m_achievement_settings = nullptr; diff --git a/src/duckstation-qt/setupwizarddialog.cpp b/src/duckstation-qt/setupwizarddialog.cpp index adb7c95f5..cc770e845 100644 --- a/src/duckstation-qt/setupwizarddialog.cpp +++ b/src/duckstation-qt/setupwizarddialog.cpp @@ -1,9 +1,9 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>. +// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>. // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "setupwizarddialog.h" #include "controllersettingwidgetbinder.h" -#include "generalsettingswidget.h" +#include "interfacesettingswidget.h" #include "mainwindow.h" #include "qthost.h" #include "qtutils.h" @@ -181,9 +181,9 @@ void SetupWizardDialog::setupUi() void SetupWizardDialog::setupLanguagePage() { - SettingWidgetBinder::BindWidgetToEnumSetting(nullptr, m_ui.theme, "UI", "Theme", GeneralSettingsWidget::THEME_NAMES, - GeneralSettingsWidget::THEME_VALUES, - GeneralSettingsWidget::DEFAULT_THEME_NAME, "InterfaceSettingsWidget"); + SettingWidgetBinder::BindWidgetToEnumSetting(nullptr, m_ui.theme, "UI", "Theme", InterfaceSettingsWidget::THEME_NAMES, + InterfaceSettingsWidget::THEME_VALUES, + InterfaceSettingsWidget::DEFAULT_THEME_NAME, "InterfaceSettingsWidget"); connect(m_ui.theme, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &SetupWizardDialog::themeChanged); for (const auto& [language, code] : Host::GetAvailableLanguageList())