diff options
| author | 2023-05-06 21:55:39 -0700 | |
|---|---|---|
| committer | 2023-05-06 21:55:39 -0700 | |
| commit | 3547248ec2f303ba1ce5cf41548631ad00e7f739 (patch) | |
| tree | a7e99fa79998384d4f20361234bf77de57671571 /src | |
| parent | Merge pull request #10174 from german77/motriod (diff) | |
| parent | qt_common: Remove yuzu prefix (diff) | |
| download | yuzu-3547248ec2f303ba1ce5cf41548631ad00e7f739.tar.gz yuzu-3547248ec2f303ba1ce5cf41548631ad00e7f739.tar.xz yuzu-3547248ec2f303ba1ce5cf41548631ad00e7f739.zip | |
Merge pull request #10125 from lat9nq/vsync-select
configuration: Expose separate swap present modes
Diffstat (limited to 'src')
22 files changed, 456 insertions, 129 deletions
diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 174460c5e..f1ee42ab2 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp | |||
| @@ -61,7 +61,7 @@ void LogSettings() { | |||
| 61 | log_setting("Renderer_NvdecEmulation", values.nvdec_emulation.GetValue()); | 61 | log_setting("Renderer_NvdecEmulation", values.nvdec_emulation.GetValue()); |
| 62 | log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue()); | 62 | log_setting("Renderer_AccelerateASTC", values.accelerate_astc.GetValue()); |
| 63 | log_setting("Renderer_AsyncASTC", values.async_astc.GetValue()); | 63 | log_setting("Renderer_AsyncASTC", values.async_astc.GetValue()); |
| 64 | log_setting("Renderer_UseVsync", values.use_vsync.GetValue()); | 64 | log_setting("Renderer_UseVsync", values.vsync_mode.GetValue()); |
| 65 | log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue()); | 65 | log_setting("Renderer_ShaderBackend", values.shader_backend.GetValue()); |
| 66 | log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); | 66 | log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); |
| 67 | log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue()); | 67 | log_setting("Renderer_AnisotropicFilteringLevel", values.max_anisotropy.GetValue()); |
| @@ -223,7 +223,6 @@ void RestoreGlobalState(bool is_powered_on) { | |||
| 223 | values.nvdec_emulation.SetGlobal(true); | 223 | values.nvdec_emulation.SetGlobal(true); |
| 224 | values.accelerate_astc.SetGlobal(true); | 224 | values.accelerate_astc.SetGlobal(true); |
| 225 | values.async_astc.SetGlobal(true); | 225 | values.async_astc.SetGlobal(true); |
| 226 | values.use_vsync.SetGlobal(true); | ||
| 227 | values.shader_backend.SetGlobal(true); | 226 | values.shader_backend.SetGlobal(true); |
| 228 | values.use_asynchronous_shaders.SetGlobal(true); | 227 | values.use_asynchronous_shaders.SetGlobal(true); |
| 229 | values.use_fast_gpu_time.SetGlobal(true); | 228 | values.use_fast_gpu_time.SetGlobal(true); |
diff --git a/src/common/settings.h b/src/common/settings.h index 55200c36f..2bf191cef 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -16,6 +16,13 @@ | |||
| 16 | 16 | ||
| 17 | namespace Settings { | 17 | namespace Settings { |
| 18 | 18 | ||
| 19 | enum class VSyncMode : u32 { | ||
| 20 | Immediate = 0, | ||
| 21 | Mailbox = 1, | ||
| 22 | FIFO = 2, | ||
| 23 | FIFORelaxed = 3, | ||
| 24 | }; | ||
| 25 | |||
| 19 | enum class RendererBackend : u32 { | 26 | enum class RendererBackend : u32 { |
| 20 | OpenGL = 0, | 27 | OpenGL = 0, |
| 21 | Vulkan = 1, | 28 | Vulkan = 1, |
| @@ -456,7 +463,8 @@ struct Values { | |||
| 456 | SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"}; | 463 | SwitchableSetting<NvdecEmulation> nvdec_emulation{NvdecEmulation::GPU, "nvdec_emulation"}; |
| 457 | SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"}; | 464 | SwitchableSetting<bool> accelerate_astc{true, "accelerate_astc"}; |
| 458 | SwitchableSetting<bool> async_astc{false, "async_astc"}; | 465 | SwitchableSetting<bool> async_astc{false, "async_astc"}; |
| 459 | SwitchableSetting<bool> use_vsync{true, "use_vsync"}; | 466 | Setting<VSyncMode, true> vsync_mode{VSyncMode::FIFO, VSyncMode::Immediate, |
| 467 | VSyncMode::FIFORelaxed, "use_vsync"}; | ||
| 460 | SwitchableSetting<ShaderBackend, true> shader_backend{ShaderBackend::GLSL, ShaderBackend::GLSL, | 468 | SwitchableSetting<ShaderBackend, true> shader_backend{ShaderBackend::GLSL, ShaderBackend::GLSL, |
| 461 | ShaderBackend::SPIRV, "shader_backend"}; | 469 | ShaderBackend::SPIRV, "shader_backend"}; |
| 462 | SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"}; | 470 | SwitchableSetting<bool> use_asynchronous_shaders{false, "use_asynchronous_shaders"}; |
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 9178b00ca..7a2f3c90a 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp | |||
| @@ -85,6 +85,20 @@ static const char* TranslateNvdecEmulation(Settings::NvdecEmulation backend) { | |||
| 85 | return "Unknown"; | 85 | return "Unknown"; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | static constexpr const char* TranslateVSyncMode(Settings::VSyncMode mode) { | ||
| 89 | switch (mode) { | ||
| 90 | case Settings::VSyncMode::Immediate: | ||
| 91 | return "Immediate"; | ||
| 92 | case Settings::VSyncMode::Mailbox: | ||
| 93 | return "Mailbox"; | ||
| 94 | case Settings::VSyncMode::FIFO: | ||
| 95 | return "FIFO"; | ||
| 96 | case Settings::VSyncMode::FIFORelaxed: | ||
| 97 | return "FIFO Relaxed"; | ||
| 98 | } | ||
| 99 | return "Unknown"; | ||
| 100 | } | ||
| 101 | |||
| 88 | u64 GetTelemetryId() { | 102 | u64 GetTelemetryId() { |
| 89 | u64 telemetry_id{}; | 103 | u64 telemetry_id{}; |
| 90 | const auto filename = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "telemetry_id"; | 104 | const auto filename = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "telemetry_id"; |
| @@ -241,7 +255,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader, | |||
| 241 | AddField(field_type, "Renderer_NvdecEmulation", | 255 | AddField(field_type, "Renderer_NvdecEmulation", |
| 242 | TranslateNvdecEmulation(Settings::values.nvdec_emulation.GetValue())); | 256 | TranslateNvdecEmulation(Settings::values.nvdec_emulation.GetValue())); |
| 243 | AddField(field_type, "Renderer_AccelerateASTC", Settings::values.accelerate_astc.GetValue()); | 257 | AddField(field_type, "Renderer_AccelerateASTC", Settings::values.accelerate_astc.GetValue()); |
| 244 | AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue()); | 258 | AddField(field_type, "Renderer_UseVsync", |
| 259 | TranslateVSyncMode(Settings::values.vsync_mode.GetValue())); | ||
| 245 | AddField(field_type, "Renderer_ShaderBackend", | 260 | AddField(field_type, "Renderer_ShaderBackend", |
| 246 | static_cast<u32>(Settings::values.shader_backend.GetValue())); | 261 | static_cast<u32>(Settings::values.shader_backend.GetValue())); |
| 247 | AddField(field_type, "Renderer_UseAsynchronousShaders", | 262 | AddField(field_type, "Renderer_UseAsynchronousShaders", |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 908625c66..8e31eba34 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -88,7 +88,7 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, | |||
| 88 | instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, | 88 | instance(CreateInstance(library, dld, VK_API_VERSION_1_1, render_window.GetWindowInfo().type, |
| 89 | Settings::values.renderer_debug.GetValue())), | 89 | Settings::values.renderer_debug.GetValue())), |
| 90 | debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), | 90 | debug_callback(Settings::values.renderer_debug ? CreateDebugCallback(instance) : nullptr), |
| 91 | surface(CreateSurface(instance, render_window)), | 91 | surface(CreateSurface(instance, render_window.GetWindowInfo())), |
| 92 | device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false), | 92 | device(CreateDevice(instance, dld, *surface)), memory_allocator(device, false), |
| 93 | state_tracker(), scheduler(device, state_tracker), | 93 | state_tracker(), scheduler(device, state_tracker), |
| 94 | swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, | 94 | swapchain(*surface, device, scheduler, render_window.GetFramebufferLayout().width, |
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index 23bbea7f1..1e80ce463 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "video_core/renderer_vulkan/vk_swapchain.h" | 14 | #include "video_core/renderer_vulkan/vk_swapchain.h" |
| 15 | #include "video_core/vulkan_common/vulkan_device.h" | 15 | #include "video_core/vulkan_common/vulkan_device.h" |
| 16 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 16 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 17 | #include "vulkan/vulkan_core.h" | ||
| 17 | 18 | ||
| 18 | namespace Vulkan { | 19 | namespace Vulkan { |
| 19 | 20 | ||
| @@ -33,23 +34,47 @@ VkSurfaceFormatKHR ChooseSwapSurfaceFormat(vk::Span<VkSurfaceFormatKHR> formats) | |||
| 33 | return found != formats.end() ? *found : formats[0]; | 34 | return found != formats.end() ? *found : formats[0]; |
| 34 | } | 35 | } |
| 35 | 36 | ||
| 36 | VkPresentModeKHR ChooseSwapPresentMode(vk::Span<VkPresentModeKHR> modes) { | 37 | static constexpr VkPresentModeKHR ChooseSwapPresentMode(bool has_imm, bool has_mailbox, |
| 37 | // Mailbox (triple buffering) doesn't lock the application like fifo (vsync), | 38 | bool has_fifo_relaxed) { |
| 38 | // prefer it if vsync option is not selected | 39 | // Mailbox doesn't lock the application like FIFO (vsync) |
| 39 | const auto found_mailbox = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR); | 40 | // FIFO present mode locks the framerate to the monitor's refresh rate |
| 40 | if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Borderless && | 41 | Settings::VSyncMode setting = [has_imm, has_mailbox]() { |
| 41 | found_mailbox != modes.end() && !Settings::values.use_vsync.GetValue()) { | 42 | // Choose Mailbox or Immediate if unlocked and those modes are supported |
| 42 | return VK_PRESENT_MODE_MAILBOX_KHR; | 43 | const auto mode = Settings::values.vsync_mode.GetValue(); |
| 43 | } | 44 | if (Settings::values.use_speed_limit.GetValue()) { |
| 44 | if (!Settings::values.use_speed_limit.GetValue()) { | 45 | return mode; |
| 45 | // FIFO present mode locks the framerate to the monitor's refresh rate, | 46 | } |
| 46 | // Find an alternative to surpass this limitation if FPS is unlocked. | 47 | switch (mode) { |
| 47 | const auto found_imm = std::find(modes.begin(), modes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR); | 48 | case Settings::VSyncMode::FIFO: |
| 48 | if (found_imm != modes.end()) { | 49 | case Settings::VSyncMode::FIFORelaxed: |
| 49 | return VK_PRESENT_MODE_IMMEDIATE_KHR; | 50 | if (has_mailbox) { |
| 51 | return Settings::VSyncMode::Mailbox; | ||
| 52 | } else if (has_imm) { | ||
| 53 | return Settings::VSyncMode::Immediate; | ||
| 54 | } | ||
| 55 | [[fallthrough]]; | ||
| 56 | default: | ||
| 57 | return mode; | ||
| 50 | } | 58 | } |
| 59 | }(); | ||
| 60 | if ((setting == Settings::VSyncMode::Mailbox && !has_mailbox) || | ||
| 61 | (setting == Settings::VSyncMode::Immediate && !has_imm) || | ||
| 62 | (setting == Settings::VSyncMode::FIFORelaxed && !has_fifo_relaxed)) { | ||
| 63 | setting = Settings::VSyncMode::FIFO; | ||
| 64 | } | ||
| 65 | |||
| 66 | switch (setting) { | ||
| 67 | case Settings::VSyncMode::Immediate: | ||
| 68 | return VK_PRESENT_MODE_IMMEDIATE_KHR; | ||
| 69 | case Settings::VSyncMode::Mailbox: | ||
| 70 | return VK_PRESENT_MODE_MAILBOX_KHR; | ||
| 71 | case Settings::VSyncMode::FIFO: | ||
| 72 | return VK_PRESENT_MODE_FIFO_KHR; | ||
| 73 | case Settings::VSyncMode::FIFORelaxed: | ||
| 74 | return VK_PRESENT_MODE_FIFO_RELAXED_KHR; | ||
| 75 | default: | ||
| 76 | return VK_PRESENT_MODE_FIFO_KHR; | ||
| 51 | } | 77 | } |
| 52 | return VK_PRESENT_MODE_FIFO_KHR; | ||
| 53 | } | 78 | } |
| 54 | 79 | ||
| 55 | VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height) { | 80 | VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, u32 width, u32 height) { |
| @@ -167,11 +192,17 @@ void Swapchain::Present(VkSemaphore render_semaphore) { | |||
| 167 | void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) { | 192 | void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bool srgb) { |
| 168 | const auto physical_device{device.GetPhysical()}; | 193 | const auto physical_device{device.GetPhysical()}; |
| 169 | const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; | 194 | const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; |
| 170 | const auto present_modes{physical_device.GetSurfacePresentModesKHR(surface)}; | 195 | const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface); |
| 196 | has_mailbox = std::find(present_modes.begin(), present_modes.end(), | ||
| 197 | VK_PRESENT_MODE_MAILBOX_KHR) != present_modes.end(); | ||
| 198 | has_imm = std::find(present_modes.begin(), present_modes.end(), | ||
| 199 | VK_PRESENT_MODE_IMMEDIATE_KHR) != present_modes.end(); | ||
| 200 | has_fifo_relaxed = std::find(present_modes.begin(), present_modes.end(), | ||
| 201 | VK_PRESENT_MODE_FIFO_RELAXED_KHR) != present_modes.end(); | ||
| 171 | 202 | ||
| 172 | const VkCompositeAlphaFlagBitsKHR alpha_flags{ChooseAlphaFlags(capabilities)}; | 203 | const VkCompositeAlphaFlagBitsKHR alpha_flags{ChooseAlphaFlags(capabilities)}; |
| 173 | surface_format = ChooseSwapSurfaceFormat(formats); | 204 | surface_format = ChooseSwapSurfaceFormat(formats); |
| 174 | present_mode = ChooseSwapPresentMode(present_modes); | 205 | present_mode = ChooseSwapPresentMode(has_imm, has_mailbox, has_fifo_relaxed); |
| 175 | 206 | ||
| 176 | u32 requested_image_count{capabilities.minImageCount + 1}; | 207 | u32 requested_image_count{capabilities.minImageCount + 1}; |
| 177 | // Ensure Triple buffering if possible. | 208 | // Ensure Triple buffering if possible. |
| @@ -232,7 +263,6 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities, bo | |||
| 232 | 263 | ||
| 233 | extent = swapchain_ci.imageExtent; | 264 | extent = swapchain_ci.imageExtent; |
| 234 | current_srgb = srgb; | 265 | current_srgb = srgb; |
| 235 | current_fps_unlocked = !Settings::values.use_speed_limit.GetValue(); | ||
| 236 | 266 | ||
| 237 | images = swapchain.GetImages(); | 267 | images = swapchain.GetImages(); |
| 238 | image_count = static_cast<u32>(images.size()); | 268 | image_count = static_cast<u32>(images.size()); |
| @@ -254,14 +284,9 @@ void Swapchain::Destroy() { | |||
| 254 | swapchain.reset(); | 284 | swapchain.reset(); |
| 255 | } | 285 | } |
| 256 | 286 | ||
| 257 | bool Swapchain::HasFpsUnlockChanged() const { | ||
| 258 | return current_fps_unlocked != !Settings::values.use_speed_limit.GetValue(); | ||
| 259 | } | ||
| 260 | |||
| 261 | bool Swapchain::NeedsPresentModeUpdate() const { | 287 | bool Swapchain::NeedsPresentModeUpdate() const { |
| 262 | // Mailbox present mode is the ideal for all scenarios. If it is not available, | 288 | const auto requested_mode = ChooseSwapPresentMode(has_imm, has_mailbox, has_fifo_relaxed); |
| 263 | // A different present mode is needed to support unlocked FPS above the monitor's refresh rate. | 289 | return present_mode != requested_mode; |
| 264 | return present_mode != VK_PRESENT_MODE_MAILBOX_KHR && HasFpsUnlockChanged(); | ||
| 265 | } | 290 | } |
| 266 | 291 | ||
| 267 | } // namespace Vulkan | 292 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h index 419742586..bf1ea7254 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.h +++ b/src/video_core/renderer_vulkan/vk_swapchain.h | |||
| @@ -116,8 +116,6 @@ private: | |||
| 116 | 116 | ||
| 117 | void Destroy(); | 117 | void Destroy(); |
| 118 | 118 | ||
| 119 | bool HasFpsUnlockChanged() const; | ||
| 120 | |||
| 121 | bool NeedsPresentModeUpdate() const; | 119 | bool NeedsPresentModeUpdate() const; |
| 122 | 120 | ||
| 123 | const VkSurfaceKHR surface; | 121 | const VkSurfaceKHR surface; |
| @@ -142,9 +140,11 @@ private: | |||
| 142 | VkExtent2D extent{}; | 140 | VkExtent2D extent{}; |
| 143 | VkPresentModeKHR present_mode{}; | 141 | VkPresentModeKHR present_mode{}; |
| 144 | VkSurfaceFormatKHR surface_format{}; | 142 | VkSurfaceFormatKHR surface_format{}; |
| 143 | bool has_imm{false}; | ||
| 144 | bool has_mailbox{false}; | ||
| 145 | bool has_fifo_relaxed{false}; | ||
| 145 | 146 | ||
| 146 | bool current_srgb{}; | 147 | bool current_srgb{}; |
| 147 | bool current_fps_unlocked{}; | ||
| 148 | bool is_outdated{}; | 148 | bool is_outdated{}; |
| 149 | bool is_suboptimal{}; | 149 | bool is_suboptimal{}; |
| 150 | }; | 150 | }; |
diff --git a/src/video_core/vulkan_common/vulkan_surface.cpp b/src/video_core/vulkan_common/vulkan_surface.cpp index fa9bafa20..c34599365 100644 --- a/src/video_core/vulkan_common/vulkan_surface.cpp +++ b/src/video_core/vulkan_common/vulkan_surface.cpp | |||
| @@ -23,10 +23,10 @@ | |||
| 23 | 23 | ||
| 24 | namespace Vulkan { | 24 | namespace Vulkan { |
| 25 | 25 | ||
| 26 | vk::SurfaceKHR CreateSurface(const vk::Instance& instance, | 26 | vk::SurfaceKHR CreateSurface( |
| 27 | const Core::Frontend::EmuWindow& emu_window) { | 27 | const vk::Instance& instance, |
| 28 | [[maybe_unused]] const Core::Frontend::EmuWindow::WindowSystemInfo& window_info) { | ||
| 28 | [[maybe_unused]] const vk::InstanceDispatch& dld = instance.Dispatch(); | 29 | [[maybe_unused]] const vk::InstanceDispatch& dld = instance.Dispatch(); |
| 29 | [[maybe_unused]] const auto& window_info = emu_window.GetWindowInfo(); | ||
| 30 | VkSurfaceKHR unsafe_surface = nullptr; | 30 | VkSurfaceKHR unsafe_surface = nullptr; |
| 31 | 31 | ||
| 32 | #ifdef _WIN32 | 32 | #ifdef _WIN32 |
diff --git a/src/video_core/vulkan_common/vulkan_surface.h b/src/video_core/vulkan_common/vulkan_surface.h index 5725143e6..5e18c06c4 100644 --- a/src/video_core/vulkan_common/vulkan_surface.h +++ b/src/video_core/vulkan_common/vulkan_surface.h | |||
| @@ -3,15 +3,12 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "core/frontend/emu_window.h" | ||
| 6 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 7 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 7 | 8 | ||
| 8 | namespace Core::Frontend { | ||
| 9 | class EmuWindow; | ||
| 10 | } | ||
| 11 | |||
| 12 | namespace Vulkan { | 9 | namespace Vulkan { |
| 13 | 10 | ||
| 14 | [[nodiscard]] vk::SurfaceKHR CreateSurface(const vk::Instance& instance, | 11 | [[nodiscard]] vk::SurfaceKHR CreateSurface( |
| 15 | const Core::Frontend::EmuWindow& emu_window); | 12 | const vk::Instance& instance, const Core::Frontend::EmuWindow::WindowSystemInfo& window_info); |
| 16 | 13 | ||
| 17 | } // namespace Vulkan | 14 | } // namespace Vulkan |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 0f8c1e6a6..2d7b9ab65 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -189,6 +189,8 @@ add_executable(yuzu | |||
| 189 | multiplayer/state.h | 189 | multiplayer/state.h |
| 190 | multiplayer/validation.h | 190 | multiplayer/validation.h |
| 191 | precompiled_headers.h | 191 | precompiled_headers.h |
| 192 | qt_common.cpp | ||
| 193 | qt_common.h | ||
| 192 | startup_checks.cpp | 194 | startup_checks.cpp |
| 193 | startup_checks.h | 195 | startup_checks.h |
| 194 | uisettings.cpp | 196 | uisettings.cpp |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 4c7bf28d8..59d226113 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -1,36 +1,48 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2014 Citra Emulator Project | 1 | // SPDX-FileCopyrightText: 2014 Citra Emulator Project |
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <algorithm> | ||
| 5 | #include <array> | ||
| 6 | #include <cmath> | ||
| 7 | #include <cstring> | ||
| 8 | #include <string> | ||
| 9 | #include <tuple> | ||
| 10 | #include <type_traits> | ||
| 4 | #include <glad/glad.h> | 11 | #include <glad/glad.h> |
| 5 | 12 | ||
| 6 | #include <QApplication> | 13 | #include <QtCore/qglobal.h> |
| 7 | #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA | 14 | #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) && YUZU_USE_QT_MULTIMEDIA |
| 15 | #include <QCamera> | ||
| 8 | #include <QCameraImageCapture> | 16 | #include <QCameraImageCapture> |
| 9 | #include <QCameraInfo> | 17 | #include <QCameraInfo> |
| 10 | #endif | 18 | #endif |
| 19 | #include <QCursor> | ||
| 20 | #include <QEvent> | ||
| 21 | #include <QGuiApplication> | ||
| 11 | #include <QHBoxLayout> | 22 | #include <QHBoxLayout> |
| 23 | #include <QKeyEvent> | ||
| 24 | #include <QLayout> | ||
| 25 | #include <QList> | ||
| 12 | #include <QMessageBox> | 26 | #include <QMessageBox> |
| 13 | #include <QPainter> | ||
| 14 | #include <QScreen> | 27 | #include <QScreen> |
| 15 | #include <QString> | 28 | #include <QSize> |
| 16 | #include <QStringList> | 29 | #include <QStringLiteral> |
| 30 | #include <QSurfaceFormat> | ||
| 31 | #include <QTimer> | ||
| 17 | #include <QWindow> | 32 | #include <QWindow> |
| 33 | #include <QtCore/qobjectdefs.h> | ||
| 18 | 34 | ||
| 19 | #ifdef HAS_OPENGL | 35 | #ifdef HAS_OPENGL |
| 20 | #include <QOffscreenSurface> | 36 | #include <QOffscreenSurface> |
| 21 | #include <QOpenGLContext> | 37 | #include <QOpenGLContext> |
| 22 | #endif | 38 | #endif |
| 23 | 39 | ||
| 24 | #if !defined(WIN32) | ||
| 25 | #include <qpa/qplatformnativeinterface.h> | ||
| 26 | #endif | ||
| 27 | |||
| 28 | #include <fmt/format.h> | ||
| 29 | |||
| 30 | #include "common/assert.h" | ||
| 31 | #include "common/microprofile.h" | 40 | #include "common/microprofile.h" |
| 41 | #include "common/polyfill_thread.h" | ||
| 32 | #include "common/scm_rev.h" | 42 | #include "common/scm_rev.h" |
| 33 | #include "common/settings.h" | 43 | #include "common/settings.h" |
| 44 | #include "common/settings_input.h" | ||
| 45 | #include "common/thread.h" | ||
| 34 | #include "core/core.h" | 46 | #include "core/core.h" |
| 35 | #include "core/cpu_manager.h" | 47 | #include "core/cpu_manager.h" |
| 36 | #include "core/frontend/framebuffer_layout.h" | 48 | #include "core/frontend/framebuffer_layout.h" |
| @@ -40,11 +52,16 @@ | |||
| 40 | #include "input_common/drivers/tas_input.h" | 52 | #include "input_common/drivers/tas_input.h" |
| 41 | #include "input_common/drivers/touch_screen.h" | 53 | #include "input_common/drivers/touch_screen.h" |
| 42 | #include "input_common/main.h" | 54 | #include "input_common/main.h" |
| 55 | #include "video_core/gpu.h" | ||
| 56 | #include "video_core/rasterizer_interface.h" | ||
| 43 | #include "video_core/renderer_base.h" | 57 | #include "video_core/renderer_base.h" |
| 44 | #include "yuzu/bootmanager.h" | 58 | #include "yuzu/bootmanager.h" |
| 45 | #include "yuzu/main.h" | 59 | #include "yuzu/main.h" |
| 60 | #include "yuzu/qt_common.h" | ||
| 46 | 61 | ||
| 47 | static Core::Frontend::WindowSystemType GetWindowSystemType(); | 62 | class QObject; |
| 63 | class QPaintEngine; | ||
| 64 | class QSurface; | ||
| 48 | 65 | ||
| 49 | EmuThread::EmuThread(Core::System& system) : m_system{system} {} | 66 | EmuThread::EmuThread(Core::System& system) : m_system{system} {} |
| 50 | 67 | ||
| @@ -154,7 +171,10 @@ public: | |||
| 154 | 171 | ||
| 155 | // disable vsync for any shared contexts | 172 | // disable vsync for any shared contexts |
| 156 | auto format = share_context->format(); | 173 | auto format = share_context->format(); |
| 157 | format.setSwapInterval(main_surface ? Settings::values.use_vsync.GetValue() : 0); | 174 | const int swap_interval = |
| 175 | Settings::values.vsync_mode.GetValue() == Settings::VSyncMode::Immediate ? 0 : 1; | ||
| 176 | |||
| 177 | format.setSwapInterval(main_surface ? swap_interval : 0); | ||
| 158 | 178 | ||
| 159 | context = std::make_unique<QOpenGLContext>(); | 179 | context = std::make_unique<QOpenGLContext>(); |
| 160 | context->setShareContext(share_context); | 180 | context->setShareContext(share_context); |
| @@ -221,7 +241,7 @@ public: | |||
| 221 | explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { | 241 | explicit RenderWidget(GRenderWindow* parent) : QWidget(parent), render_window(parent) { |
| 222 | setAttribute(Qt::WA_NativeWindow); | 242 | setAttribute(Qt::WA_NativeWindow); |
| 223 | setAttribute(Qt::WA_PaintOnScreen); | 243 | setAttribute(Qt::WA_PaintOnScreen); |
| 224 | if (GetWindowSystemType() == Core::Frontend::WindowSystemType::Wayland) { | 244 | if (QtCommon::GetWindowSystemType() == Core::Frontend::WindowSystemType::Wayland) { |
| 225 | setAttribute(Qt::WA_DontCreateNativeAncestors); | 245 | setAttribute(Qt::WA_DontCreateNativeAncestors); |
| 226 | } | 246 | } |
| 227 | } | 247 | } |
| @@ -259,46 +279,6 @@ struct NullRenderWidget : public RenderWidget { | |||
| 259 | explicit NullRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {} | 279 | explicit NullRenderWidget(GRenderWindow* parent) : RenderWidget(parent) {} |
| 260 | }; | 280 | }; |
| 261 | 281 | ||
| 262 | static Core::Frontend::WindowSystemType GetWindowSystemType() { | ||
| 263 | // Determine WSI type based on Qt platform. | ||
| 264 | QString platform_name = QGuiApplication::platformName(); | ||
| 265 | if (platform_name == QStringLiteral("windows")) | ||
| 266 | return Core::Frontend::WindowSystemType::Windows; | ||
| 267 | else if (platform_name == QStringLiteral("xcb")) | ||
| 268 | return Core::Frontend::WindowSystemType::X11; | ||
| 269 | else if (platform_name == QStringLiteral("wayland")) | ||
| 270 | return Core::Frontend::WindowSystemType::Wayland; | ||
| 271 | else if (platform_name == QStringLiteral("wayland-egl")) | ||
| 272 | return Core::Frontend::WindowSystemType::Wayland; | ||
| 273 | else if (platform_name == QStringLiteral("cocoa")) | ||
| 274 | return Core::Frontend::WindowSystemType::Cocoa; | ||
| 275 | else if (platform_name == QStringLiteral("android")) | ||
| 276 | return Core::Frontend::WindowSystemType::Android; | ||
| 277 | |||
| 278 | LOG_CRITICAL(Frontend, "Unknown Qt platform {}!", platform_name.toStdString()); | ||
| 279 | return Core::Frontend::WindowSystemType::Windows; | ||
| 280 | } | ||
| 281 | |||
| 282 | static Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) { | ||
| 283 | Core::Frontend::EmuWindow::WindowSystemInfo wsi; | ||
| 284 | wsi.type = GetWindowSystemType(); | ||
| 285 | |||
| 286 | // Our Win32 Qt external doesn't have the private API. | ||
| 287 | #if defined(WIN32) || defined(__APPLE__) | ||
| 288 | wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr; | ||
| 289 | #else | ||
| 290 | QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); | ||
| 291 | wsi.display_connection = pni->nativeResourceForWindow("display", window); | ||
| 292 | if (wsi.type == Core::Frontend::WindowSystemType::Wayland) | ||
| 293 | wsi.render_surface = window ? pni->nativeResourceForWindow("surface", window) : nullptr; | ||
| 294 | else | ||
| 295 | wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr; | ||
| 296 | #endif | ||
| 297 | wsi.render_surface_scale = window ? static_cast<float>(window->devicePixelRatio()) : 1.0f; | ||
| 298 | |||
| 299 | return wsi; | ||
| 300 | } | ||
| 301 | |||
| 302 | GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, | 282 | GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, |
| 303 | std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_, | 283 | std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_, |
| 304 | Core::System& system_) | 284 | Core::System& system_) |
| @@ -904,7 +884,7 @@ bool GRenderWindow::InitRenderTarget() { | |||
| 904 | } | 884 | } |
| 905 | 885 | ||
| 906 | // Update the Window System information with the new render target | 886 | // Update the Window System information with the new render target |
| 907 | window_info = GetWindowSystemInfo(child_widget->windowHandle()); | 887 | window_info = QtCommon::GetWindowSystemInfo(child_widget->windowHandle()); |
| 908 | 888 | ||
| 909 | child_widget->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); | 889 | child_widget->resize(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); |
| 910 | layout()->addWidget(child_widget); | 890 | layout()->addWidget(child_widget); |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index bb4eca07f..4276be82b 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -5,27 +5,46 @@ | |||
| 5 | 5 | ||
| 6 | #include <atomic> | 6 | #include <atomic> |
| 7 | #include <condition_variable> | 7 | #include <condition_variable> |
| 8 | #include <cstddef> | ||
| 8 | #include <memory> | 9 | #include <memory> |
| 9 | #include <mutex> | 10 | #include <mutex> |
| 11 | #include <stop_token> | ||
| 12 | #include <utility> | ||
| 13 | #include <vector> | ||
| 10 | 14 | ||
| 15 | #include <QByteArray> | ||
| 11 | #include <QImage> | 16 | #include <QImage> |
| 17 | #include <QObject> | ||
| 18 | #include <QPoint> | ||
| 19 | #include <QString> | ||
| 12 | #include <QStringList> | 20 | #include <QStringList> |
| 13 | #include <QThread> | 21 | #include <QThread> |
| 14 | #include <QTouchEvent> | ||
| 15 | #include <QWidget> | 22 | #include <QWidget> |
| 23 | #include <qglobal.h> | ||
| 24 | #include <qnamespace.h> | ||
| 25 | #include <qobjectdefs.h> | ||
| 16 | 26 | ||
| 27 | #include "common/common_types.h" | ||
| 28 | #include "common/logging/log.h" | ||
| 17 | #include "common/polyfill_thread.h" | 29 | #include "common/polyfill_thread.h" |
| 18 | #include "common/thread.h" | 30 | #include "common/thread.h" |
| 19 | #include "core/frontend/emu_window.h" | 31 | #include "core/frontend/emu_window.h" |
| 20 | 32 | ||
| 21 | class GRenderWindow; | ||
| 22 | class GMainWindow; | 33 | class GMainWindow; |
| 23 | class QCamera; | 34 | class QCamera; |
| 24 | class QCameraImageCapture; | 35 | class QCameraImageCapture; |
| 36 | class QCloseEvent; | ||
| 37 | class QFocusEvent; | ||
| 25 | class QKeyEvent; | 38 | class QKeyEvent; |
| 39 | class QMouseEvent; | ||
| 40 | class QObject; | ||
| 41 | class QResizeEvent; | ||
| 42 | class QShowEvent; | ||
| 43 | class QTimer; | ||
| 44 | class QTouchEvent; | ||
| 45 | class QWheelEvent; | ||
| 26 | 46 | ||
| 27 | namespace Core { | 47 | namespace Core { |
| 28 | enum class SystemResultStatus : u32; | ||
| 29 | class System; | 48 | class System; |
| 30 | } // namespace Core | 49 | } // namespace Core |
| 31 | 50 | ||
| @@ -40,7 +59,6 @@ enum class TasState; | |||
| 40 | 59 | ||
| 41 | namespace VideoCore { | 60 | namespace VideoCore { |
| 42 | enum class LoadCallbackStage; | 61 | enum class LoadCallbackStage; |
| 43 | class RendererBase; | ||
| 44 | } // namespace VideoCore | 62 | } // namespace VideoCore |
| 45 | 63 | ||
| 46 | class EmuThread final : public QThread { | 64 | class EmuThread final : public QThread { |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 0131f63e7..a85eb4687 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <QSettings> | 6 | #include <QSettings> |
| 7 | #include "common/fs/fs.h" | 7 | #include "common/fs/fs.h" |
| 8 | #include "common/fs/path_util.h" | 8 | #include "common/fs/path_util.h" |
| 9 | #include "common/settings.h" | ||
| 9 | #include "core/core.h" | 10 | #include "core/core.h" |
| 10 | #include "core/hle/service/acc/profile_manager.h" | 11 | #include "core/hle/service/acc/profile_manager.h" |
| 11 | #include "core/hle/service/hid/controllers/npad.h" | 12 | #include "core/hle/service/hid/controllers/npad.h" |
| @@ -709,7 +710,6 @@ void Config::ReadRendererValues() { | |||
| 709 | ReadGlobalSetting(Settings::values.nvdec_emulation); | 710 | ReadGlobalSetting(Settings::values.nvdec_emulation); |
| 710 | ReadGlobalSetting(Settings::values.accelerate_astc); | 711 | ReadGlobalSetting(Settings::values.accelerate_astc); |
| 711 | ReadGlobalSetting(Settings::values.async_astc); | 712 | ReadGlobalSetting(Settings::values.async_astc); |
| 712 | ReadGlobalSetting(Settings::values.use_vsync); | ||
| 713 | ReadGlobalSetting(Settings::values.shader_backend); | 713 | ReadGlobalSetting(Settings::values.shader_backend); |
| 714 | ReadGlobalSetting(Settings::values.use_asynchronous_shaders); | 714 | ReadGlobalSetting(Settings::values.use_asynchronous_shaders); |
| 715 | ReadGlobalSetting(Settings::values.use_fast_gpu_time); | 715 | ReadGlobalSetting(Settings::values.use_fast_gpu_time); |
| @@ -719,6 +719,10 @@ void Config::ReadRendererValues() { | |||
| 719 | ReadGlobalSetting(Settings::values.bg_blue); | 719 | ReadGlobalSetting(Settings::values.bg_blue); |
| 720 | 720 | ||
| 721 | if (global) { | 721 | if (global) { |
| 722 | Settings::values.vsync_mode.SetValue(static_cast<Settings::VSyncMode>( | ||
| 723 | ReadSetting(QString::fromStdString(Settings::values.vsync_mode.GetLabel()), | ||
| 724 | static_cast<u32>(Settings::values.vsync_mode.GetDefault())) | ||
| 725 | .value<u32>())); | ||
| 722 | ReadBasicSetting(Settings::values.renderer_debug); | 726 | ReadBasicSetting(Settings::values.renderer_debug); |
| 723 | ReadBasicSetting(Settings::values.renderer_shader_feedback); | 727 | ReadBasicSetting(Settings::values.renderer_shader_feedback); |
| 724 | ReadBasicSetting(Settings::values.enable_nsight_aftermath); | 728 | ReadBasicSetting(Settings::values.enable_nsight_aftermath); |
| @@ -1351,7 +1355,6 @@ void Config::SaveRendererValues() { | |||
| 1351 | Settings::values.nvdec_emulation.UsingGlobal()); | 1355 | Settings::values.nvdec_emulation.UsingGlobal()); |
| 1352 | WriteGlobalSetting(Settings::values.accelerate_astc); | 1356 | WriteGlobalSetting(Settings::values.accelerate_astc); |
| 1353 | WriteGlobalSetting(Settings::values.async_astc); | 1357 | WriteGlobalSetting(Settings::values.async_astc); |
| 1354 | WriteGlobalSetting(Settings::values.use_vsync); | ||
| 1355 | WriteSetting(QString::fromStdString(Settings::values.shader_backend.GetLabel()), | 1358 | WriteSetting(QString::fromStdString(Settings::values.shader_backend.GetLabel()), |
| 1356 | static_cast<u32>(Settings::values.shader_backend.GetValue(global)), | 1359 | static_cast<u32>(Settings::values.shader_backend.GetValue(global)), |
| 1357 | static_cast<u32>(Settings::values.shader_backend.GetDefault()), | 1360 | static_cast<u32>(Settings::values.shader_backend.GetDefault()), |
| @@ -1364,6 +1367,9 @@ void Config::SaveRendererValues() { | |||
| 1364 | WriteGlobalSetting(Settings::values.bg_blue); | 1367 | WriteGlobalSetting(Settings::values.bg_blue); |
| 1365 | 1368 | ||
| 1366 | if (global) { | 1369 | if (global) { |
| 1370 | WriteSetting(QString::fromStdString(Settings::values.vsync_mode.GetLabel()), | ||
| 1371 | static_cast<u32>(Settings::values.vsync_mode.GetValue()), | ||
| 1372 | static_cast<u32>(Settings::values.vsync_mode.GetDefault())); | ||
| 1367 | WriteBasicSetting(Settings::values.renderer_debug); | 1373 | WriteBasicSetting(Settings::values.renderer_debug); |
| 1368 | WriteBasicSetting(Settings::values.renderer_shader_feedback); | 1374 | WriteBasicSetting(Settings::values.renderer_shader_feedback); |
| 1369 | WriteBasicSetting(Settings::values.enable_nsight_aftermath); | 1375 | WriteBasicSetting(Settings::values.enable_nsight_aftermath); |
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index e9388daad..76e5b7499 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp | |||
| @@ -4,20 +4,76 @@ | |||
| 4 | // Include this early to include Vulkan headers how we want to | 4 | // Include this early to include Vulkan headers how we want to |
| 5 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 5 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 6 | 6 | ||
| 7 | #include <algorithm> | ||
| 8 | #include <iosfwd> | ||
| 9 | #include <iterator> | ||
| 10 | #include <string> | ||
| 11 | #include <tuple> | ||
| 12 | #include <utility> | ||
| 13 | #include <vector> | ||
| 14 | #include <QBoxLayout> | ||
| 15 | #include <QCheckBox> | ||
| 7 | #include <QColorDialog> | 16 | #include <QColorDialog> |
| 8 | #include <QVulkanInstance> | 17 | #include <QComboBox> |
| 18 | #include <QIcon> | ||
| 19 | #include <QLabel> | ||
| 20 | #include <QPixmap> | ||
| 21 | #include <QPushButton> | ||
| 22 | #include <QSlider> | ||
| 23 | #include <QStringLiteral> | ||
| 24 | #include <QtCore/qobjectdefs.h> | ||
| 25 | #include <qcoreevent.h> | ||
| 26 | #include <qglobal.h> | ||
| 27 | #include <vulkan/vulkan_core.h> | ||
| 9 | 28 | ||
| 10 | #include "common/common_types.h" | 29 | #include "common/common_types.h" |
| 30 | #include "common/dynamic_library.h" | ||
| 11 | #include "common/logging/log.h" | 31 | #include "common/logging/log.h" |
| 12 | #include "common/settings.h" | 32 | #include "common/settings.h" |
| 13 | #include "core/core.h" | 33 | #include "core/core.h" |
| 14 | #include "ui_configure_graphics.h" | 34 | #include "ui_configure_graphics.h" |
| 15 | #include "video_core/vulkan_common/vulkan_instance.h" | 35 | #include "video_core/vulkan_common/vulkan_instance.h" |
| 16 | #include "video_core/vulkan_common/vulkan_library.h" | 36 | #include "video_core/vulkan_common/vulkan_library.h" |
| 37 | #include "video_core/vulkan_common/vulkan_surface.h" | ||
| 17 | #include "yuzu/configuration/configuration_shared.h" | 38 | #include "yuzu/configuration/configuration_shared.h" |
| 18 | #include "yuzu/configuration/configure_graphics.h" | 39 | #include "yuzu/configuration/configure_graphics.h" |
| 40 | #include "yuzu/qt_common.h" | ||
| 19 | #include "yuzu/uisettings.h" | 41 | #include "yuzu/uisettings.h" |
| 20 | 42 | ||
| 43 | static const std::vector<VkPresentModeKHR> default_present_modes{VK_PRESENT_MODE_IMMEDIATE_KHR, | ||
| 44 | VK_PRESENT_MODE_FIFO_KHR}; | ||
| 45 | |||
| 46 | // Converts a setting to a present mode (or vice versa) | ||
| 47 | static constexpr VkPresentModeKHR VSyncSettingToMode(Settings::VSyncMode mode) { | ||
| 48 | switch (mode) { | ||
| 49 | case Settings::VSyncMode::Immediate: | ||
| 50 | return VK_PRESENT_MODE_IMMEDIATE_KHR; | ||
| 51 | case Settings::VSyncMode::Mailbox: | ||
| 52 | return VK_PRESENT_MODE_MAILBOX_KHR; | ||
| 53 | case Settings::VSyncMode::FIFO: | ||
| 54 | return VK_PRESENT_MODE_FIFO_KHR; | ||
| 55 | case Settings::VSyncMode::FIFORelaxed: | ||
| 56 | return VK_PRESENT_MODE_FIFO_RELAXED_KHR; | ||
| 57 | default: | ||
| 58 | return VK_PRESENT_MODE_FIFO_KHR; | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | static constexpr Settings::VSyncMode PresentModeToSetting(VkPresentModeKHR mode) { | ||
| 63 | switch (mode) { | ||
| 64 | case VK_PRESENT_MODE_IMMEDIATE_KHR: | ||
| 65 | return Settings::VSyncMode::Immediate; | ||
| 66 | case VK_PRESENT_MODE_MAILBOX_KHR: | ||
| 67 | return Settings::VSyncMode::Mailbox; | ||
| 68 | case VK_PRESENT_MODE_FIFO_KHR: | ||
| 69 | return Settings::VSyncMode::FIFO; | ||
| 70 | case VK_PRESENT_MODE_FIFO_RELAXED_KHR: | ||
| 71 | return Settings::VSyncMode::FIFORelaxed; | ||
| 72 | default: | ||
| 73 | return Settings::VSyncMode::FIFO; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 21 | ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* parent) | 77 | ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* parent) |
| 22 | : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, system{system_} { | 78 | : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, system{system_} { |
| 23 | vulkan_device = Settings::values.vulkan_device.GetValue(); | 79 | vulkan_device = Settings::values.vulkan_device.GetValue(); |
| @@ -39,13 +95,16 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* paren | |||
| 39 | 95 | ||
| 40 | connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] { | 96 | connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] { |
| 41 | UpdateAPILayout(); | 97 | UpdateAPILayout(); |
| 98 | PopulateVSyncModeSelection(); | ||
| 42 | if (!Settings::IsConfiguringGlobal()) { | 99 | if (!Settings::IsConfiguringGlobal()) { |
| 43 | ConfigurationShared::SetHighlight( | 100 | ConfigurationShared::SetHighlight( |
| 44 | ui->api_widget, ui->api->currentIndex() != ConfigurationShared::USE_GLOBAL_INDEX); | 101 | ui->api_widget, ui->api->currentIndex() != ConfigurationShared::USE_GLOBAL_INDEX); |
| 45 | } | 102 | } |
| 46 | }); | 103 | }); |
| 47 | connect(ui->device, qOverload<int>(&QComboBox::activated), this, | 104 | connect(ui->device, qOverload<int>(&QComboBox::activated), this, [this](int device) { |
| 48 | [this](int device) { UpdateDeviceSelection(device); }); | 105 | UpdateDeviceSelection(device); |
| 106 | PopulateVSyncModeSelection(); | ||
| 107 | }); | ||
| 49 | connect(ui->backend, qOverload<int>(&QComboBox::activated), this, | 108 | connect(ui->backend, qOverload<int>(&QComboBox::activated), this, |
| 50 | [this](int backend) { UpdateShaderBackendSelection(backend); }); | 109 | [this](int backend) { UpdateShaderBackendSelection(backend); }); |
| 51 | 110 | ||
| @@ -70,6 +129,43 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* paren | |||
| 70 | ui->fsr_sharpening_label->setVisible(Settings::IsConfiguringGlobal()); | 129 | ui->fsr_sharpening_label->setVisible(Settings::IsConfiguringGlobal()); |
| 71 | } | 130 | } |
| 72 | 131 | ||
| 132 | void ConfigureGraphics::PopulateVSyncModeSelection() { | ||
| 133 | const Settings::RendererBackend backend{GetCurrentGraphicsBackend()}; | ||
| 134 | if (backend == Settings::RendererBackend::Null) { | ||
| 135 | ui->vsync_mode_combobox->setEnabled(false); | ||
| 136 | return; | ||
| 137 | } | ||
| 138 | ui->vsync_mode_combobox->setEnabled(true); | ||
| 139 | |||
| 140 | const int current_index = //< current selected vsync mode from combobox | ||
| 141 | ui->vsync_mode_combobox->currentIndex(); | ||
| 142 | const auto current_mode = //< current selected vsync mode as a VkPresentModeKHR | ||
| 143 | current_index == -1 ? VSyncSettingToMode(Settings::values.vsync_mode.GetValue()) | ||
| 144 | : vsync_mode_combobox_enum_map[current_index]; | ||
| 145 | int index{}; | ||
| 146 | const int device{ui->device->currentIndex()}; //< current selected Vulkan device | ||
| 147 | const auto& present_modes = //< relevant vector of present modes for the selected device or API | ||
| 148 | backend == Settings::RendererBackend::Vulkan ? device_present_modes[device] | ||
| 149 | : default_present_modes; | ||
| 150 | |||
| 151 | ui->vsync_mode_combobox->clear(); | ||
| 152 | vsync_mode_combobox_enum_map.clear(); | ||
| 153 | vsync_mode_combobox_enum_map.reserve(present_modes.size()); | ||
| 154 | for (const auto present_mode : present_modes) { | ||
| 155 | const auto mode_name = TranslateVSyncMode(present_mode, backend); | ||
| 156 | if (mode_name.isEmpty()) { | ||
| 157 | continue; | ||
| 158 | } | ||
| 159 | |||
| 160 | ui->vsync_mode_combobox->insertItem(index, mode_name); | ||
| 161 | vsync_mode_combobox_enum_map.push_back(present_mode); | ||
| 162 | if (present_mode == current_mode) { | ||
| 163 | ui->vsync_mode_combobox->setCurrentIndex(index); | ||
| 164 | } | ||
| 165 | index++; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 73 | void ConfigureGraphics::UpdateDeviceSelection(int device) { | 169 | void ConfigureGraphics::UpdateDeviceSelection(int device) { |
| 74 | if (device == -1) { | 170 | if (device == -1) { |
| 75 | return; | 171 | return; |
| @@ -99,6 +195,9 @@ void ConfigureGraphics::SetConfiguration() { | |||
| 99 | ui->nvdec_emulation_widget->setEnabled(runtime_lock); | 195 | ui->nvdec_emulation_widget->setEnabled(runtime_lock); |
| 100 | ui->resolution_combobox->setEnabled(runtime_lock); | 196 | ui->resolution_combobox->setEnabled(runtime_lock); |
| 101 | ui->accelerate_astc->setEnabled(runtime_lock); | 197 | ui->accelerate_astc->setEnabled(runtime_lock); |
| 198 | ui->vsync_mode_layout->setEnabled(runtime_lock || | ||
| 199 | Settings::values.renderer_backend.GetValue() == | ||
| 200 | Settings::RendererBackend::Vulkan); | ||
| 102 | ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue()); | 201 | ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue()); |
| 103 | ui->use_asynchronous_gpu_emulation->setChecked( | 202 | ui->use_asynchronous_gpu_emulation->setChecked( |
| 104 | Settings::values.use_asynchronous_gpu_emulation.GetValue()); | 203 | Settings::values.use_asynchronous_gpu_emulation.GetValue()); |
| @@ -170,7 +269,24 @@ void ConfigureGraphics::SetConfiguration() { | |||
| 170 | Settings::values.bg_green.GetValue(), | 269 | Settings::values.bg_green.GetValue(), |
| 171 | Settings::values.bg_blue.GetValue())); | 270 | Settings::values.bg_blue.GetValue())); |
| 172 | UpdateAPILayout(); | 271 | UpdateAPILayout(); |
| 272 | PopulateVSyncModeSelection(); //< must happen after UpdateAPILayout | ||
| 173 | SetFSRIndicatorText(ui->fsr_sharpening_slider->sliderPosition()); | 273 | SetFSRIndicatorText(ui->fsr_sharpening_slider->sliderPosition()); |
| 274 | |||
| 275 | // VSync setting needs to be determined after populating the VSync combobox | ||
| 276 | if (Settings::IsConfiguringGlobal()) { | ||
| 277 | const auto vsync_mode_setting = Settings::values.vsync_mode.GetValue(); | ||
| 278 | const auto vsync_mode = VSyncSettingToMode(vsync_mode_setting); | ||
| 279 | int index{}; | ||
| 280 | for (const auto mode : vsync_mode_combobox_enum_map) { | ||
| 281 | if (mode == vsync_mode) { | ||
| 282 | break; | ||
| 283 | } | ||
| 284 | index++; | ||
| 285 | } | ||
| 286 | if (static_cast<unsigned long>(index) < vsync_mode_combobox_enum_map.size()) { | ||
| 287 | ui->vsync_mode_combobox->setCurrentIndex(index); | ||
| 288 | } | ||
| 289 | } | ||
| 174 | } | 290 | } |
| 175 | 291 | ||
| 176 | void ConfigureGraphics::SetFSRIndicatorText(int percentage) { | 292 | void ConfigureGraphics::SetFSRIndicatorText(int percentage) { |
| @@ -178,6 +294,27 @@ void ConfigureGraphics::SetFSRIndicatorText(int percentage) { | |||
| 178 | tr("%1%", "FSR sharpening percentage (e.g. 50%)").arg(100 - (percentage / 2))); | 294 | tr("%1%", "FSR sharpening percentage (e.g. 50%)").arg(100 - (percentage / 2))); |
| 179 | } | 295 | } |
| 180 | 296 | ||
| 297 | const QString ConfigureGraphics::TranslateVSyncMode(VkPresentModeKHR mode, | ||
| 298 | Settings::RendererBackend backend) const { | ||
| 299 | switch (mode) { | ||
| 300 | case VK_PRESENT_MODE_IMMEDIATE_KHR: | ||
| 301 | return backend == Settings::RendererBackend::OpenGL | ||
| 302 | ? tr("Off") | ||
| 303 | : QStringLiteral("Immediate (%1)").arg(tr("VSync Off")); | ||
| 304 | case VK_PRESENT_MODE_MAILBOX_KHR: | ||
| 305 | return QStringLiteral("Mailbox (%1)").arg(tr("Recommended")); | ||
| 306 | case VK_PRESENT_MODE_FIFO_KHR: | ||
| 307 | return backend == Settings::RendererBackend::OpenGL | ||
| 308 | ? tr("On") | ||
| 309 | : QStringLiteral("FIFO (%1)").arg(tr("VSync On")); | ||
| 310 | case VK_PRESENT_MODE_FIFO_RELAXED_KHR: | ||
| 311 | return QStringLiteral("FIFO Relaxed"); | ||
| 312 | default: | ||
| 313 | return {}; | ||
| 314 | break; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 181 | void ConfigureGraphics::ApplyConfiguration() { | 318 | void ConfigureGraphics::ApplyConfiguration() { |
| 182 | const auto resolution_setup = static_cast<Settings::ResolutionSetup>( | 319 | const auto resolution_setup = static_cast<Settings::ResolutionSetup>( |
| 183 | ui->resolution_combobox->currentIndex() - | 320 | ui->resolution_combobox->currentIndex() - |
| @@ -232,6 +369,10 @@ void ConfigureGraphics::ApplyConfiguration() { | |||
| 232 | Settings::values.anti_aliasing.SetValue(anti_aliasing); | 369 | Settings::values.anti_aliasing.SetValue(anti_aliasing); |
| 233 | } | 370 | } |
| 234 | Settings::values.fsr_sharpening_slider.SetValue(ui->fsr_sharpening_slider->value()); | 371 | Settings::values.fsr_sharpening_slider.SetValue(ui->fsr_sharpening_slider->value()); |
| 372 | |||
| 373 | const auto mode = vsync_mode_combobox_enum_map[ui->vsync_mode_combobox->currentIndex()]; | ||
| 374 | const auto vsync_mode = PresentModeToSetting(mode); | ||
| 375 | Settings::values.vsync_mode.SetValue(vsync_mode); | ||
| 235 | } else { | 376 | } else { |
| 236 | if (ui->resolution_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { | 377 | if (ui->resolution_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { |
| 237 | Settings::values.resolution_setup.SetGlobal(true); | 378 | Settings::values.resolution_setup.SetGlobal(true); |
| @@ -345,7 +486,9 @@ void ConfigureGraphics::UpdateAPILayout() { | |||
| 345 | ui->backend_widget->setVisible(true); | 486 | ui->backend_widget->setVisible(true); |
| 346 | break; | 487 | break; |
| 347 | case Settings::RendererBackend::Vulkan: | 488 | case Settings::RendererBackend::Vulkan: |
| 348 | ui->device->setCurrentIndex(vulkan_device); | 489 | if (static_cast<int>(vulkan_device) < ui->device->count()) { |
| 490 | ui->device->setCurrentIndex(vulkan_device); | ||
| 491 | } | ||
| 349 | ui->device_widget->setVisible(true); | 492 | ui->device_widget->setVisible(true); |
| 350 | ui->backend_widget->setVisible(false); | 493 | ui->backend_widget->setVisible(false); |
| 351 | break; | 494 | break; |
| @@ -363,16 +506,27 @@ void ConfigureGraphics::RetrieveVulkanDevices() try { | |||
| 363 | 506 | ||
| 364 | using namespace Vulkan; | 507 | using namespace Vulkan; |
| 365 | 508 | ||
| 509 | auto* window = this->window()->windowHandle(); | ||
| 510 | auto wsi = QtCommon::GetWindowSystemInfo(window); | ||
| 511 | |||
| 366 | vk::InstanceDispatch dld; | 512 | vk::InstanceDispatch dld; |
| 367 | const Common::DynamicLibrary library = OpenLibrary(); | 513 | const Common::DynamicLibrary library = OpenLibrary(); |
| 368 | const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1); | 514 | const vk::Instance instance = CreateInstance(library, dld, VK_API_VERSION_1_1, wsi.type); |
| 369 | const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices(); | 515 | const std::vector<VkPhysicalDevice> physical_devices = instance.EnumeratePhysicalDevices(); |
| 516 | vk::SurfaceKHR surface = //< needed to view present modes for a device | ||
| 517 | CreateSurface(instance, wsi); | ||
| 370 | 518 | ||
| 371 | vulkan_devices.clear(); | 519 | vulkan_devices.clear(); |
| 372 | vulkan_devices.reserve(physical_devices.size()); | 520 | vulkan_devices.reserve(physical_devices.size()); |
| 521 | device_present_modes.clear(); | ||
| 522 | device_present_modes.reserve(physical_devices.size()); | ||
| 373 | for (const VkPhysicalDevice device : physical_devices) { | 523 | for (const VkPhysicalDevice device : physical_devices) { |
| 374 | const std::string name = vk::PhysicalDevice(device, dld).GetProperties().deviceName; | 524 | const auto physical_device = vk::PhysicalDevice(device, dld); |
| 525 | const std::string name = physical_device.GetProperties().deviceName; | ||
| 526 | const std::vector<VkPresentModeKHR> present_modes = | ||
| 527 | physical_device.GetSurfacePresentModesKHR(*surface); | ||
| 375 | vulkan_devices.push_back(QString::fromStdString(name)); | 528 | vulkan_devices.push_back(QString::fromStdString(name)); |
| 529 | device_present_modes.push_back(present_modes); | ||
| 376 | } | 530 | } |
| 377 | } catch (const Vulkan::vk::Exception& exception) { | 531 | } catch (const Vulkan::vk::Exception& exception) { |
| 378 | LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what()); | 532 | LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what()); |
| @@ -465,4 +619,6 @@ void ConfigureGraphics::SetupPerGameUI() { | |||
| 465 | ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); | 619 | ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); |
| 466 | ConfigurationShared::InsertGlobalItem( | 620 | ConfigurationShared::InsertGlobalItem( |
| 467 | ui->nvdec_emulation, static_cast<int>(Settings::values.nvdec_emulation.GetValue(true))); | 621 | ui->nvdec_emulation, static_cast<int>(Settings::values.nvdec_emulation.GetValue(true))); |
| 622 | |||
| 623 | ui->vsync_mode_layout->setVisible(false); | ||
| 468 | } | 624 | } |
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index d98d6624e..901f604a5 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h | |||
| @@ -5,9 +5,21 @@ | |||
| 5 | 5 | ||
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include <vector> | 7 | #include <vector> |
| 8 | #include <QColor> | ||
| 8 | #include <QString> | 9 | #include <QString> |
| 9 | #include <QWidget> | 10 | #include <QWidget> |
| 10 | #include "common/settings.h" | 11 | #include <qobjectdefs.h> |
| 12 | #include <vulkan/vulkan_core.h> | ||
| 13 | #include "common/common_types.h" | ||
| 14 | |||
| 15 | class QEvent; | ||
| 16 | class QObject; | ||
| 17 | |||
| 18 | namespace Settings { | ||
| 19 | enum class NvdecEmulation : u32; | ||
| 20 | enum class RendererBackend : u32; | ||
| 21 | enum class ShaderBackend : u32; | ||
| 22 | } // namespace Settings | ||
| 11 | 23 | ||
| 12 | namespace Core { | 24 | namespace Core { |
| 13 | class System; | 25 | class System; |
| @@ -35,6 +47,7 @@ private: | |||
| 35 | void changeEvent(QEvent* event) override; | 47 | void changeEvent(QEvent* event) override; |
| 36 | void RetranslateUI(); | 48 | void RetranslateUI(); |
| 37 | 49 | ||
| 50 | void PopulateVSyncModeSelection(); | ||
| 38 | void UpdateBackgroundColorButton(QColor color); | 51 | void UpdateBackgroundColorButton(QColor color); |
| 39 | void UpdateAPILayout(); | 52 | void UpdateAPILayout(); |
| 40 | void UpdateDeviceSelection(int device); | 53 | void UpdateDeviceSelection(int device); |
| @@ -43,6 +56,10 @@ private: | |||
| 43 | void RetrieveVulkanDevices(); | 56 | void RetrieveVulkanDevices(); |
| 44 | 57 | ||
| 45 | void SetFSRIndicatorText(int percentage); | 58 | void SetFSRIndicatorText(int percentage); |
| 59 | /* Turns a Vulkan present mode into a textual string for a UI | ||
| 60 | * (and eventually for a human to read) */ | ||
| 61 | const QString TranslateVSyncMode(VkPresentModeKHR mode, | ||
| 62 | Settings::RendererBackend backend) const; | ||
| 46 | 63 | ||
| 47 | void SetupPerGameUI(); | 64 | void SetupPerGameUI(); |
| 48 | 65 | ||
| @@ -58,6 +75,10 @@ private: | |||
| 58 | ConfigurationShared::CheckState use_asynchronous_gpu_emulation; | 75 | ConfigurationShared::CheckState use_asynchronous_gpu_emulation; |
| 59 | 76 | ||
| 60 | std::vector<QString> vulkan_devices; | 77 | std::vector<QString> vulkan_devices; |
| 78 | std::vector<std::vector<VkPresentModeKHR>> device_present_modes; | ||
| 79 | std::vector<VkPresentModeKHR> | ||
| 80 | vsync_mode_combobox_enum_map; //< Keeps track of which present mode corresponds to which | ||
| 81 | // selection in the combobox | ||
| 61 | u32 vulkan_device{}; | 82 | u32 vulkan_device{}; |
| 62 | Settings::ShaderBackend shader_backend{}; | 83 | Settings::ShaderBackend shader_backend{}; |
| 63 | 84 | ||
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index a45ec69ec..39f70e406 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui | |||
| @@ -189,6 +189,44 @@ | |||
| 189 | </widget> | 189 | </widget> |
| 190 | </item> | 190 | </item> |
| 191 | <item> | 191 | <item> |
| 192 | <widget class="QWidget" name="vsync_mode_layout" native="true"> | ||
| 193 | <layout class="QHBoxLayout" name="horizontalLayout_4"> | ||
| 194 | <property name="leftMargin"> | ||
| 195 | <number>0</number> | ||
| 196 | </property> | ||
| 197 | <property name="topMargin"> | ||
| 198 | <number>0</number> | ||
| 199 | </property> | ||
| 200 | <property name="rightMargin"> | ||
| 201 | <number>0</number> | ||
| 202 | </property> | ||
| 203 | <property name="bottomMargin"> | ||
| 204 | <number>0</number> | ||
| 205 | </property> | ||
| 206 | <item> | ||
| 207 | <widget class="QLabel" name="vsync_mode_label"> | ||
| 208 | <property name="text"> | ||
| 209 | <string>VSync Mode:</string> | ||
| 210 | </property> | ||
| 211 | </widget> | ||
| 212 | </item> | ||
| 213 | <item> | ||
| 214 | <widget class="QComboBox" name="vsync_mode_combobox"> | ||
| 215 | <property name="toolTip"> | ||
| 216 | <string>FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. | ||
| 217 | FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down. | ||
| 218 | Mailbox can have lower latency than FIFO and does not tear but may drop frames. | ||
| 219 | Immediate (no synchronization) just presents whatever is available and can exhibit tearing.</string> | ||
| 220 | </property> | ||
| 221 | <property name="currentText"> | ||
| 222 | <string/> | ||
| 223 | </property> | ||
| 224 | </widget> | ||
| 225 | </item> | ||
| 226 | </layout> | ||
| 227 | </widget> | ||
| 228 | </item> | ||
| 229 | <item> | ||
| 192 | <widget class="QWidget" name="nvdec_emulation_widget" native="true"> | 230 | <widget class="QWidget" name="nvdec_emulation_widget" native="true"> |
| 193 | <layout class="QHBoxLayout" name="nvdec_emulation_layout"> | 231 | <layout class="QHBoxLayout" name="nvdec_emulation_layout"> |
| 194 | <property name="leftMargin"> | 232 | <property name="leftMargin"> |
| @@ -366,7 +404,7 @@ | |||
| 366 | </item> | 404 | </item> |
| 367 | <item> | 405 | <item> |
| 368 | <property name="text"> | 406 | <property name="text"> |
| 369 | <string>1.5X (1080p/1620p) [EXPERIMENTAL]</string> | 407 | <string>1.5X (1080p/1620p) [EXPERIMENTAL]</string> |
| 370 | </property> | 408 | </property> |
| 371 | </item> | 409 | </item> |
| 372 | <item> | 410 | <item> |
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index ddda79983..005b022ca 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp | |||
| @@ -21,7 +21,6 @@ ConfigureGraphicsAdvanced::~ConfigureGraphicsAdvanced() = default; | |||
| 21 | 21 | ||
| 22 | void ConfigureGraphicsAdvanced::SetConfiguration() { | 22 | void ConfigureGraphicsAdvanced::SetConfiguration() { |
| 23 | const bool runtime_lock = !system.IsPoweredOn(); | 23 | const bool runtime_lock = !system.IsPoweredOn(); |
| 24 | ui->use_vsync->setEnabled(runtime_lock); | ||
| 25 | ui->async_present->setEnabled(runtime_lock); | 24 | ui->async_present->setEnabled(runtime_lock); |
| 26 | ui->renderer_force_max_clock->setEnabled(runtime_lock); | 25 | ui->renderer_force_max_clock->setEnabled(runtime_lock); |
| 27 | ui->async_astc->setEnabled(runtime_lock); | 26 | ui->async_astc->setEnabled(runtime_lock); |
| @@ -30,7 +29,6 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { | |||
| 30 | 29 | ||
| 31 | ui->async_present->setChecked(Settings::values.async_presentation.GetValue()); | 30 | ui->async_present->setChecked(Settings::values.async_presentation.GetValue()); |
| 32 | ui->renderer_force_max_clock->setChecked(Settings::values.renderer_force_max_clock.GetValue()); | 31 | ui->renderer_force_max_clock->setChecked(Settings::values.renderer_force_max_clock.GetValue()); |
| 33 | ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue()); | ||
| 34 | ui->async_astc->setChecked(Settings::values.async_astc.GetValue()); | 32 | ui->async_astc->setChecked(Settings::values.async_astc.GetValue()); |
| 35 | ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); | 33 | ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue()); |
| 36 | ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); | 34 | ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue()); |
| @@ -62,7 +60,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() { | |||
| 62 | renderer_force_max_clock); | 60 | renderer_force_max_clock); |
| 63 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, | 61 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, |
| 64 | ui->anisotropic_filtering_combobox); | 62 | ui->anisotropic_filtering_combobox); |
| 65 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync); | ||
| 66 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_astc, ui->async_astc, | 63 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.async_astc, ui->async_astc, |
| 67 | async_astc); | 64 | async_astc); |
| 68 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders, | 65 | ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders, |
| @@ -94,7 +91,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { | |||
| 94 | ui->async_present->setEnabled(Settings::values.async_presentation.UsingGlobal()); | 91 | ui->async_present->setEnabled(Settings::values.async_presentation.UsingGlobal()); |
| 95 | ui->renderer_force_max_clock->setEnabled( | 92 | ui->renderer_force_max_clock->setEnabled( |
| 96 | Settings::values.renderer_force_max_clock.UsingGlobal()); | 93 | Settings::values.renderer_force_max_clock.UsingGlobal()); |
| 97 | ui->use_vsync->setEnabled(Settings::values.use_vsync.UsingGlobal()); | ||
| 98 | ui->async_astc->setEnabled(Settings::values.async_astc.UsingGlobal()); | 94 | ui->async_astc->setEnabled(Settings::values.async_astc.UsingGlobal()); |
| 99 | ui->use_asynchronous_shaders->setEnabled( | 95 | ui->use_asynchronous_shaders->setEnabled( |
| 100 | Settings::values.use_asynchronous_shaders.UsingGlobal()); | 96 | Settings::values.use_asynchronous_shaders.UsingGlobal()); |
| @@ -112,7 +108,6 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() { | |||
| 112 | ConfigurationShared::SetColoredTristate(ui->renderer_force_max_clock, | 108 | ConfigurationShared::SetColoredTristate(ui->renderer_force_max_clock, |
| 113 | Settings::values.renderer_force_max_clock, | 109 | Settings::values.renderer_force_max_clock, |
| 114 | renderer_force_max_clock); | 110 | renderer_force_max_clock); |
| 115 | ConfigurationShared::SetColoredTristate(ui->use_vsync, Settings::values.use_vsync, use_vsync); | ||
| 116 | ConfigurationShared::SetColoredTristate(ui->async_astc, Settings::values.async_astc, | 111 | ConfigurationShared::SetColoredTristate(ui->async_astc, Settings::values.async_astc, |
| 117 | async_astc); | 112 | async_astc); |
| 118 | ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders, | 113 | ConfigurationShared::SetColoredTristate(ui->use_asynchronous_shaders, |
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index 1234f695c..d073fe9b1 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui | |||
| @@ -87,16 +87,6 @@ | |||
| 87 | </widget> | 87 | </widget> |
| 88 | </item> | 88 | </item> |
| 89 | <item> | 89 | <item> |
| 90 | <widget class="QCheckBox" name="use_vsync"> | ||
| 91 | <property name="toolTip"> | ||
| 92 | <string>VSync prevents the screen from tearing, but some graphics cards have lower performance with VSync enabled. Keep it enabled if you don't notice a performance difference.</string> | ||
| 93 | </property> | ||
| 94 | <property name="text"> | ||
| 95 | <string>Use VSync</string> | ||
| 96 | </property> | ||
| 97 | </widget> | ||
| 98 | </item> | ||
| 99 | <item> | ||
| 100 | <widget class="QCheckBox" name="async_astc"> | 90 | <widget class="QCheckBox" name="async_astc"> |
| 101 | <property name="toolTip"> | 91 | <property name="toolTip"> |
| 102 | <string>Enables asynchronous ASTC texture decoding, which may reduce load time stutter. This feature is experimental.</string> | 92 | <string>Enables asynchronous ASTC texture decoding, which may reduce load time stutter. This feature is experimental.</string> |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 54f42e0c9..561a08dc5 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <QInputDialog> | 8 | #include <QInputDialog> |
| 9 | #include <QMenu> | 9 | #include <QMenu> |
| 10 | #include <QMessageBox> | 10 | #include <QMessageBox> |
| 11 | #include <QMouseEvent> | ||
| 11 | #include <QTimer> | 12 | #include <QTimer> |
| 12 | #include "common/assert.h" | 13 | #include "common/assert.h" |
| 13 | #include "common/param_package.h" | 14 | #include "common/param_package.h" |
diff --git a/src/yuzu/qt_common.cpp b/src/yuzu/qt_common.cpp new file mode 100644 index 000000000..5ac9fe310 --- /dev/null +++ b/src/yuzu/qt_common.cpp | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <QGuiApplication> | ||
| 5 | #include <QStringLiteral> | ||
| 6 | #include <QWindow> | ||
| 7 | #include "common/logging/log.h" | ||
| 8 | #include "core/frontend/emu_window.h" | ||
| 9 | #include "yuzu/qt_common.h" | ||
| 10 | |||
| 11 | #ifdef __linux__ | ||
| 12 | #include <qpa/qplatformnativeinterface.h> | ||
| 13 | #endif | ||
| 14 | |||
| 15 | namespace QtCommon { | ||
| 16 | Core::Frontend::WindowSystemType GetWindowSystemType() { | ||
| 17 | // Determine WSI type based on Qt platform. | ||
| 18 | QString platform_name = QGuiApplication::platformName(); | ||
| 19 | if (platform_name == QStringLiteral("windows")) | ||
| 20 | return Core::Frontend::WindowSystemType::Windows; | ||
| 21 | else if (platform_name == QStringLiteral("xcb")) | ||
| 22 | return Core::Frontend::WindowSystemType::X11; | ||
| 23 | else if (platform_name == QStringLiteral("wayland")) | ||
| 24 | return Core::Frontend::WindowSystemType::Wayland; | ||
| 25 | else if (platform_name == QStringLiteral("wayland-egl")) | ||
| 26 | return Core::Frontend::WindowSystemType::Wayland; | ||
| 27 | else if (platform_name == QStringLiteral("cocoa")) | ||
| 28 | return Core::Frontend::WindowSystemType::Cocoa; | ||
| 29 | else if (platform_name == QStringLiteral("android")) | ||
| 30 | return Core::Frontend::WindowSystemType::Android; | ||
| 31 | |||
| 32 | LOG_CRITICAL(Frontend, "Unknown Qt platform {}!", platform_name.toStdString()); | ||
| 33 | return Core::Frontend::WindowSystemType::Windows; | ||
| 34 | } // namespace Core::Frontend::WindowSystemType | ||
| 35 | |||
| 36 | Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window) { | ||
| 37 | Core::Frontend::EmuWindow::WindowSystemInfo wsi; | ||
| 38 | wsi.type = GetWindowSystemType(); | ||
| 39 | |||
| 40 | // Our Win32 Qt external doesn't have the private API. | ||
| 41 | #if defined(WIN32) || defined(__APPLE__) | ||
| 42 | wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr; | ||
| 43 | #else | ||
| 44 | QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface(); | ||
| 45 | wsi.display_connection = pni->nativeResourceForWindow("display", window); | ||
| 46 | if (wsi.type == Core::Frontend::WindowSystemType::Wayland) | ||
| 47 | wsi.render_surface = window ? pni->nativeResourceForWindow("surface", window) : nullptr; | ||
| 48 | else | ||
| 49 | wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr; | ||
| 50 | #endif | ||
| 51 | wsi.render_surface_scale = window ? static_cast<float>(window->devicePixelRatio()) : 1.0f; | ||
| 52 | |||
| 53 | return wsi; | ||
| 54 | } | ||
| 55 | } // namespace QtCommon | ||
diff --git a/src/yuzu/qt_common.h b/src/yuzu/qt_common.h new file mode 100644 index 000000000..9c63f08f3 --- /dev/null +++ b/src/yuzu/qt_common.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <QWindow> | ||
| 7 | #include "core/frontend/emu_window.h" | ||
| 8 | |||
| 9 | namespace QtCommon { | ||
| 10 | |||
| 11 | Core::Frontend::WindowSystemType GetWindowSystemType(); | ||
| 12 | |||
| 13 | Core::Frontend::EmuWindow::WindowSystemInfo GetWindowSystemInfo(QWindow* window); | ||
| 14 | |||
| 15 | } // namespace QtCommon | ||
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 352e6a4c7..a6418e693 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp | |||
| @@ -310,7 +310,7 @@ void Config::ReadValues() { | |||
| 310 | ReadSetting("Renderer", Settings::values.use_disk_shader_cache); | 310 | ReadSetting("Renderer", Settings::values.use_disk_shader_cache); |
| 311 | ReadSetting("Renderer", Settings::values.gpu_accuracy); | 311 | ReadSetting("Renderer", Settings::values.gpu_accuracy); |
| 312 | ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation); | 312 | ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation); |
| 313 | ReadSetting("Renderer", Settings::values.use_vsync); | 313 | ReadSetting("Renderer", Settings::values.vsync_mode); |
| 314 | ReadSetting("Renderer", Settings::values.shader_backend); | 314 | ReadSetting("Renderer", Settings::values.shader_backend); |
| 315 | ReadSetting("Renderer", Settings::values.use_asynchronous_shaders); | 315 | ReadSetting("Renderer", Settings::values.use_asynchronous_shaders); |
| 316 | ReadSetting("Renderer", Settings::values.nvdec_emulation); | 316 | ReadSetting("Renderer", Settings::values.nvdec_emulation); |
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index db6fba922..086ed4cfa 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h | |||
| @@ -325,8 +325,14 @@ aspect_ratio = | |||
| 325 | # 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x | 325 | # 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x |
| 326 | max_anisotropy = | 326 | max_anisotropy = |
| 327 | 327 | ||
| 328 | # Whether to enable V-Sync (caps the framerate at 60FPS) or not. | 328 | # Whether to enable VSync or not. |
| 329 | # 0 (default): Off, 1: On | 329 | # OpenGL: Values other than 0 enable VSync |
| 330 | # Vulkan: FIFO is selected if the requested mode is not supported by the driver. | ||
| 331 | # FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. | ||
| 332 | # FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down. | ||
| 333 | # Mailbox can have lower latency than FIFO and does not tear but may drop frames. | ||
| 334 | # Immediate (no synchronization) just presents whatever is available and can exhibit tearing. | ||
| 335 | # 0: Immediate (Off), 1: Mailbox, 2 (Default): FIFO (On), 3: FIFO Relaxed | ||
| 330 | use_vsync = | 336 | use_vsync = |
| 331 | 337 | ||
| 332 | # Selects the OpenGL shader backend. NV_gpu_program5 is required for GLASM. If NV_gpu_program5 is | 338 | # Selects the OpenGL shader backend. NV_gpu_program5 is required for GLASM. If NV_gpu_program5 is |