summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/common/fs/fs_util.cpp4
-rw-r--r--src/common/fs/fs_util.h11
-rw-r--r--src/common/host_memory.cpp9
-rw-r--r--src/common/settings.cpp8
-rw-r--r--src/common/settings.h15
-rw-r--r--src/common/uuid.cpp2
-rw-r--r--src/core/core.cpp10
-rw-r--r--src/core/core.h10
-rw-r--r--src/core/hle/service/acc/acc.cpp22
-rw-r--r--src/core/hle/service/friend/friend.cpp6
-rw-r--r--src/core/hle/service/ns/language.cpp2
-rw-r--r--src/core/hle/service/ns/ns_language.h42
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp2
-rw-r--r--src/core/perf_stats.cpp20
-rw-r--r--src/core/perf_stats.h6
-rw-r--r--src/core/telemetry_session.cpp4
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm.cpp2
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_instructions.h2
-rw-r--r--src/shader_recompiler/exception.h12
-rw-r--r--src/shader_recompiler/frontend/ir/ir_emitter.h4
-rw-r--r--src/shader_recompiler/frontend/ir/value.h4
-rw-r--r--src/shader_recompiler/frontend/maxwell/control_flow.cpp2
-rw-r--r--src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp2
-rw-r--r--src/shader_recompiler/object_pool.h1
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h1
-rw-r--r--src/video_core/engines/fermi_2d.h2
-rw-r--r--src/video_core/engines/maxwell_dma.h2
-rw-r--r--src/video_core/renderer_base.cpp3
-rw-r--r--src/video_core/renderer_base.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp1
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp10
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp10
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pass.cpp7
-rw-r--r--src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp29
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.cpp168
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.h76
-rw-r--r--src/video_core/texture_cache/render_targets.h6
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp2
-rw-r--r--src/yuzu/applets/qt_web_browser.cpp15
-rw-r--r--src/yuzu/applets/qt_web_browser.h3
-rw-r--r--src/yuzu/applets/qt_web_browser_scripts.h6
-rw-r--r--src/yuzu/configuration/config.cpp13
-rw-r--r--src/yuzu/configuration/config.h1
-rw-r--r--src/yuzu/configuration/configuration_shared.cpp14
-rw-r--r--src/yuzu/configuration/configuration_shared.h15
-rw-r--r--src/yuzu/configuration/configure_cpu.cpp17
-rw-r--r--src/yuzu/configuration/configure_general.cpp46
-rw-r--r--src/yuzu/configuration/configure_general.h2
-rw-r--r--src/yuzu/configuration/configure_general.ui4
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp10
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp20
-rw-r--r--src/yuzu/main.cpp26
-rw-r--r--src/yuzu_cmd/config.cpp4
-rw-r--r--src/yuzu_cmd/default_ini.h6
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp4
56 files changed, 238 insertions, 492 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 857550e71..d98ba7767 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -496,7 +496,7 @@ endif()
496# Ensure libusb is properly configured (based on dolphin libusb include) 496# Ensure libusb is properly configured (based on dolphin libusb include)
497if(NOT APPLE AND NOT YUZU_USE_BUNDLED_LIBUSB) 497if(NOT APPLE AND NOT YUZU_USE_BUNDLED_LIBUSB)
498 include(FindPkgConfig) 498 include(FindPkgConfig)
499 if (PKG_CONFIG_FOUND) 499 if (PKG_CONFIG_FOUND AND NOT CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD")
500 pkg_check_modules(LIBUSB QUIET libusb-1.0>=1.0.24) 500 pkg_check_modules(LIBUSB QUIET libusb-1.0>=1.0.24)
501 else() 501 else()
502 find_package(LibUSB) 502 find_package(LibUSB)
diff --git a/src/common/fs/fs_util.cpp b/src/common/fs/fs_util.cpp
index 357cf5855..9f8671982 100644
--- a/src/common/fs/fs_util.cpp
+++ b/src/common/fs/fs_util.cpp
@@ -20,6 +20,10 @@ std::string ToUTF8String(std::u8string_view u8_string) {
20 return std::string{u8_string.begin(), u8_string.end()}; 20 return std::string{u8_string.begin(), u8_string.end()};
21} 21}
22 22
23std::string BufferToUTF8String(std::span<const u8> buffer) {
24 return std::string{buffer.begin(), std::ranges::find(buffer, u8{0})};
25}
26
23std::string PathToUTF8String(const std::filesystem::path& path) { 27std::string PathToUTF8String(const std::filesystem::path& path) {
24 return ToUTF8String(path.u8string()); 28 return ToUTF8String(path.u8string());
25} 29}
diff --git a/src/common/fs/fs_util.h b/src/common/fs/fs_util.h
index ec9950ee7..1ec82eb35 100644
--- a/src/common/fs/fs_util.h
+++ b/src/common/fs/fs_util.h
@@ -47,6 +47,17 @@ concept IsChar = std::same_as<T, char>;
47[[nodiscard]] std::string ToUTF8String(std::u8string_view u8_string); 47[[nodiscard]] std::string ToUTF8String(std::u8string_view u8_string);
48 48
49/** 49/**
50 * Converts a buffer of bytes to a UTF8-encoded std::string.
51 * This converts from the start of the buffer until the first encountered null-terminator.
52 * If no null-terminator is found, this converts the entire buffer instead.
53 *
54 * @param buffer Buffer of bytes
55 *
56 * @returns UTF-8 encoded std::string.
57 */
58[[nodiscard]] std::string BufferToUTF8String(std::span<const u8> buffer);
59
60/**
50 * Converts a filesystem path to a UTF-8 encoded std::string. 61 * Converts a filesystem path to a UTF-8 encoded std::string.
51 * 62 *
52 * @param path Filesystem path 63 * @param path Filesystem path
diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp
index 2a5a7596c..6661244cf 100644
--- a/src/common/host_memory.cpp
+++ b/src/common/host_memory.cpp
@@ -6,7 +6,7 @@
6#include <windows.h> 6#include <windows.h>
7#include "common/dynamic_library.h" 7#include "common/dynamic_library.h"
8 8
9#elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv 9#elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv
10 10
11#ifndef _GNU_SOURCE 11#ifndef _GNU_SOURCE
12#define _GNU_SOURCE 12#define _GNU_SOURCE
@@ -343,7 +343,7 @@ private:
343 std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset 343 std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset
344}; 344};
345 345
346#elif defined(__linux__) // ^^^ Windows ^^^ vvv Linux vvv 346#elif defined(__linux__) || defined(__FreeBSD__) // ^^^ Windows ^^^ vvv Linux vvv
347 347
348class HostMemory::Impl { 348class HostMemory::Impl {
349public: 349public:
@@ -357,7 +357,12 @@ public:
357 }); 357 });
358 358
359 // Backing memory initialization 359 // Backing memory initialization
360#if defined(__FreeBSD__) && __FreeBSD__ < 13
361 // XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30
362 fd = shm_open(SHM_ANON, O_RDWR, 0600);
363#else
360 fd = memfd_create("HostMemory", 0); 364 fd = memfd_create("HostMemory", 0);
365#endif
361 if (fd == -1) { 366 if (fd == -1) {
362 LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno)); 367 LOG_CRITICAL(HW_Memory, "memfd_create failed: {}", strerror(errno));
363 throw std::bad_alloc{}; 368 throw std::bad_alloc{};
diff --git a/src/common/settings.cpp b/src/common/settings.cpp
index 66268ea0f..996315999 100644
--- a/src/common/settings.cpp
+++ b/src/common/settings.cpp
@@ -48,8 +48,8 @@ void LogSettings() {
48 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue()); 48 log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
49 log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue()); 49 log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
50 log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue()); 50 log_setting("Renderer_UseResolutionFactor", values.resolution_factor.GetValue());
51 log_setting("Renderer_UseFrameLimit", values.use_frame_limit.GetValue()); 51 log_setting("Renderer_UseSpeedLimit", values.use_speed_limit.GetValue());
52 log_setting("Renderer_FrameLimit", values.frame_limit.GetValue()); 52 log_setting("Renderer_SpeedLimit", values.speed_limit.GetValue());
53 log_setting("Renderer_UseDiskShaderCache", values.use_disk_shader_cache.GetValue()); 53 log_setting("Renderer_UseDiskShaderCache", values.use_disk_shader_cache.GetValue());
54 log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue()); 54 log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue());
55 log_setting("Renderer_UseAsynchronousGpuEmulation", 55 log_setting("Renderer_UseAsynchronousGpuEmulation",
@@ -132,8 +132,8 @@ void RestoreGlobalState(bool is_powered_on) {
132 values.vulkan_device.SetGlobal(true); 132 values.vulkan_device.SetGlobal(true);
133 values.aspect_ratio.SetGlobal(true); 133 values.aspect_ratio.SetGlobal(true);
134 values.max_anisotropy.SetGlobal(true); 134 values.max_anisotropy.SetGlobal(true);
135 values.use_frame_limit.SetGlobal(true); 135 values.use_speed_limit.SetGlobal(true);
136 values.frame_limit.SetGlobal(true); 136 values.speed_limit.SetGlobal(true);
137 values.use_disk_shader_cache.SetGlobal(true); 137 values.use_disk_shader_cache.SetGlobal(true);
138 values.gpu_accuracy.SetGlobal(true); 138 values.gpu_accuracy.SetGlobal(true);
139 values.use_asynchronous_gpu_emulation.SetGlobal(true); 139 values.use_asynchronous_gpu_emulation.SetGlobal(true);
diff --git a/src/common/settings.h b/src/common/settings.h
index df1762d1b..cfc1ab46f 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -42,6 +42,11 @@ enum class CPUAccuracy : u32 {
42 Unsafe = 2, 42 Unsafe = 2,
43}; 43};
44 44
45enum class FullscreenMode : u32 {
46 Borderless = 0,
47 Exclusive = 1,
48};
49
45/** The BasicSetting class is a simple resource manager. It defines a label and default value 50/** The BasicSetting class is a simple resource manager. It defines a label and default value
46 * alongside the actual value of the setting for simpler and less-error prone use with frontend 51 * alongside the actual value of the setting for simpler and less-error prone use with frontend
47 * configurations. Setting a default value and label is required, though subclasses may deviate from 52 * configurations. Setting a default value and label is required, though subclasses may deviate from
@@ -322,17 +327,17 @@ struct Values {
322 Setting<u16> resolution_factor{1, "resolution_factor"}; 327 Setting<u16> resolution_factor{1, "resolution_factor"};
323 // *nix platforms may have issues with the borderless windowed fullscreen mode. 328 // *nix platforms may have issues with the borderless windowed fullscreen mode.
324 // Default to exclusive fullscreen on these platforms for now. 329 // Default to exclusive fullscreen on these platforms for now.
325 Setting<int> fullscreen_mode{ 330 Setting<FullscreenMode> fullscreen_mode{
326#ifdef _WIN32 331#ifdef _WIN32
327 0, 332 FullscreenMode::Borderless,
328#else 333#else
329 1, 334 FullscreenMode::Exclusive,
330#endif 335#endif
331 "fullscreen_mode"}; 336 "fullscreen_mode"};
332 Setting<int> aspect_ratio{0, "aspect_ratio"}; 337 Setting<int> aspect_ratio{0, "aspect_ratio"};
333 Setting<int> max_anisotropy{0, "max_anisotropy"}; 338 Setting<int> max_anisotropy{0, "max_anisotropy"};
334 Setting<bool> use_frame_limit{true, "use_frame_limit"}; 339 Setting<bool> use_speed_limit{true, "use_speed_limit"};
335 Setting<u16> frame_limit{100, "frame_limit"}; 340 Setting<u16> speed_limit{100, "speed_limit"};
336 Setting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"}; 341 Setting<bool> use_disk_shader_cache{true, "use_disk_shader_cache"};
337 Setting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, "gpu_accuracy"}; 342 Setting<GPUAccuracy> gpu_accuracy{GPUAccuracy::High, "gpu_accuracy"};
338 Setting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"}; 343 Setting<bool> use_asynchronous_gpu_emulation{true, "use_asynchronous_gpu_emulation"};
diff --git a/src/common/uuid.cpp b/src/common/uuid.cpp
index 26db03fba..18303a1e3 100644
--- a/src/common/uuid.cpp
+++ b/src/common/uuid.cpp
@@ -18,7 +18,7 @@ UUID UUID::Generate() {
18} 18}
19 19
20std::string UUID::Format() const { 20std::string UUID::Format() const {
21 return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]); 21 return fmt::format("{:016x}{:016x}", uuid[1], uuid[0]);
22} 22}
23 23
24std::string UUID::FormatSwitch() const { 24std::string UUID::FormatSwitch() const {
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 15226cf41..d3e84c4ef 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -411,7 +411,7 @@ struct System::Impl {
411 std::string status_details = ""; 411 std::string status_details = "";
412 412
413 std::unique_ptr<Core::PerfStats> perf_stats; 413 std::unique_ptr<Core::PerfStats> perf_stats;
414 Core::FrameLimiter frame_limiter; 414 Core::SpeedLimiter speed_limiter;
415 415
416 bool is_multicore{}; 416 bool is_multicore{};
417 bool is_async_gpu{}; 417 bool is_async_gpu{};
@@ -606,12 +606,12 @@ const Core::PerfStats& System::GetPerfStats() const {
606 return *impl->perf_stats; 606 return *impl->perf_stats;
607} 607}
608 608
609Core::FrameLimiter& System::FrameLimiter() { 609Core::SpeedLimiter& System::SpeedLimiter() {
610 return impl->frame_limiter; 610 return impl->speed_limiter;
611} 611}
612 612
613const Core::FrameLimiter& System::FrameLimiter() const { 613const Core::SpeedLimiter& System::SpeedLimiter() const {
614 return impl->frame_limiter; 614 return impl->speed_limiter;
615} 615}
616 616
617Loader::ResultStatus System::GetGameName(std::string& out) const { 617Loader::ResultStatus System::GetGameName(std::string& out) const {
diff --git a/src/core/core.h b/src/core/core.h
index b93c32e60..ea143043c 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -94,7 +94,7 @@ class ARM_Interface;
94class CpuManager; 94class CpuManager;
95class DeviceMemory; 95class DeviceMemory;
96class ExclusiveMonitor; 96class ExclusiveMonitor;
97class FrameLimiter; 97class SpeedLimiter;
98class PerfStats; 98class PerfStats;
99class Reporter; 99class Reporter;
100class TelemetrySession; 100class TelemetrySession;
@@ -292,11 +292,11 @@ public:
292 /// Provides a constant reference to the internal PerfStats instance. 292 /// Provides a constant reference to the internal PerfStats instance.
293 [[nodiscard]] const Core::PerfStats& GetPerfStats() const; 293 [[nodiscard]] const Core::PerfStats& GetPerfStats() const;
294 294
295 /// Provides a reference to the frame limiter; 295 /// Provides a reference to the speed limiter;
296 [[nodiscard]] Core::FrameLimiter& FrameLimiter(); 296 [[nodiscard]] Core::SpeedLimiter& SpeedLimiter();
297 297
298 /// Provides a constant referent to the frame limiter 298 /// Provides a constant reference to the speed limiter
299 [[nodiscard]] const Core::FrameLimiter& FrameLimiter() const; 299 [[nodiscard]] const Core::SpeedLimiter& SpeedLimiter() const;
300 300
301 /// Gets the name of the current game 301 /// Gets the name of the current game
302 [[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const; 302 [[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 2e969f2a8..882fc1492 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -292,7 +292,7 @@ public:
292 292
293protected: 293protected:
294 void Get(Kernel::HLERequestContext& ctx) { 294 void Get(Kernel::HLERequestContext& ctx) {
295 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); 295 LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format());
296 ProfileBase profile_base{}; 296 ProfileBase profile_base{};
297 ProfileData data{}; 297 ProfileData data{};
298 if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { 298 if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
@@ -301,7 +301,7 @@ protected:
301 rb.Push(ResultSuccess); 301 rb.Push(ResultSuccess);
302 rb.PushRaw(profile_base); 302 rb.PushRaw(profile_base);
303 } else { 303 } else {
304 LOG_ERROR(Service_ACC, "Failed to get profile base and data for user={}", 304 LOG_ERROR(Service_ACC, "Failed to get profile base and data for user=0x{}",
305 user_id.Format()); 305 user_id.Format());
306 IPC::ResponseBuilder rb{ctx, 2}; 306 IPC::ResponseBuilder rb{ctx, 2};
307 rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code 307 rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code
@@ -309,14 +309,14 @@ protected:
309 } 309 }
310 310
311 void GetBase(Kernel::HLERequestContext& ctx) { 311 void GetBase(Kernel::HLERequestContext& ctx) {
312 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); 312 LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format());
313 ProfileBase profile_base{}; 313 ProfileBase profile_base{};
314 if (profile_manager.GetProfileBase(user_id, profile_base)) { 314 if (profile_manager.GetProfileBase(user_id, profile_base)) {
315 IPC::ResponseBuilder rb{ctx, 16}; 315 IPC::ResponseBuilder rb{ctx, 16};
316 rb.Push(ResultSuccess); 316 rb.Push(ResultSuccess);
317 rb.PushRaw(profile_base); 317 rb.PushRaw(profile_base);
318 } else { 318 } else {
319 LOG_ERROR(Service_ACC, "Failed to get profile base for user={}", user_id.Format()); 319 LOG_ERROR(Service_ACC, "Failed to get profile base for user=0x{}", user_id.Format());
320 IPC::ResponseBuilder rb{ctx, 2}; 320 IPC::ResponseBuilder rb{ctx, 2};
321 rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code 321 rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code
322 } 322 }
@@ -372,7 +372,7 @@ protected:
372 372
373 const auto user_data = ctx.ReadBuffer(); 373 const auto user_data = ctx.ReadBuffer();
374 374
375 LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}", 375 LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}",
376 Common::StringFromFixedZeroTerminatedBuffer( 376 Common::StringFromFixedZeroTerminatedBuffer(
377 reinterpret_cast<const char*>(base.username.data()), base.username.size()), 377 reinterpret_cast<const char*>(base.username.data()), base.username.size()),
378 base.timestamp, base.user_uuid.Format()); 378 base.timestamp, base.user_uuid.Format());
@@ -405,7 +405,7 @@ protected:
405 const auto user_data = ctx.ReadBuffer(); 405 const auto user_data = ctx.ReadBuffer();
406 const auto image_data = ctx.ReadBuffer(1); 406 const auto image_data = ctx.ReadBuffer(1);
407 407
408 LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid={}", 408 LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}",
409 Common::StringFromFixedZeroTerminatedBuffer( 409 Common::StringFromFixedZeroTerminatedBuffer(
410 reinterpret_cast<const char*>(base.username.data()), base.username.size()), 410 reinterpret_cast<const char*>(base.username.data()), base.username.size()),
411 base.timestamp, base.user_uuid.Format()); 411 base.timestamp, base.user_uuid.Format());
@@ -662,7 +662,7 @@ void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) {
662void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { 662void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) {
663 IPC::RequestParser rp{ctx}; 663 IPC::RequestParser rp{ctx};
664 Common::UUID user_id = rp.PopRaw<Common::UUID>(); 664 Common::UUID user_id = rp.PopRaw<Common::UUID>();
665 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); 665 LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format());
666 666
667 IPC::ResponseBuilder rb{ctx, 3}; 667 IPC::ResponseBuilder rb{ctx, 3};
668 rb.Push(ResultSuccess); 668 rb.Push(ResultSuccess);
@@ -693,7 +693,7 @@ void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
693void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { 693void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
694 IPC::RequestParser rp{ctx}; 694 IPC::RequestParser rp{ctx};
695 Common::UUID user_id = rp.PopRaw<Common::UUID>(); 695 Common::UUID user_id = rp.PopRaw<Common::UUID>();
696 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); 696 LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format());
697 697
698 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 698 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
699 rb.Push(ResultSuccess); 699 rb.Push(ResultSuccess);
@@ -802,7 +802,7 @@ void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) {
802 IPC::RequestParser rp{ctx}; 802 IPC::RequestParser rp{ctx};
803 Common::UUID user_id = rp.PopRaw<Common::UUID>(); 803 Common::UUID user_id = rp.PopRaw<Common::UUID>();
804 804
805 LOG_DEBUG(Service_ACC, "called, user_id={}", user_id.Format()); 805 LOG_DEBUG(Service_ACC, "called, user_id=0x{}", user_id.Format());
806 806
807 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 807 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
808 rb.Push(ResultSuccess); 808 rb.Push(ResultSuccess);
@@ -844,7 +844,7 @@ void Module::Interface::StoreSaveDataThumbnailApplication(Kernel::HLERequestCont
844 IPC::RequestParser rp{ctx}; 844 IPC::RequestParser rp{ctx};
845 const auto uuid = rp.PopRaw<Common::UUID>(); 845 const auto uuid = rp.PopRaw<Common::UUID>();
846 846
847 LOG_WARNING(Service_ACC, "(STUBBED) called, uuid={}", uuid.Format()); 847 LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}", uuid.Format());
848 848
849 // TODO(ogniK): Check if application ID is zero on acc initialize. As we don't have a reliable 849 // TODO(ogniK): Check if application ID is zero on acc initialize. As we don't have a reliable
850 // way of confirming things like the TID, we're going to assume a non zero value for the time 850 // way of confirming things like the TID, we're going to assume a non zero value for the time
@@ -858,7 +858,7 @@ void Module::Interface::StoreSaveDataThumbnailSystem(Kernel::HLERequestContext&
858 const auto uuid = rp.PopRaw<Common::UUID>(); 858 const auto uuid = rp.PopRaw<Common::UUID>();
859 const auto tid = rp.Pop<u64_le>(); 859 const auto tid = rp.Pop<u64_le>();
860 860
861 LOG_WARNING(Service_ACC, "(STUBBED) called, uuid={}, tid={:016X}", uuid.Format(), tid); 861 LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}, tid={:016X}", uuid.Format(), tid);
862 StoreSaveDataThumbnail(ctx, uuid, tid); 862 StoreSaveDataThumbnail(ctx, uuid, tid);
863} 863}
864 864
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index a3c939c0c..b58c152ce 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -158,7 +158,7 @@ private:
158 const auto local_play = rp.Pop<bool>(); 158 const auto local_play = rp.Pop<bool>();
159 const auto uuid = rp.PopRaw<Common::UUID>(); 159 const auto uuid = rp.PopRaw<Common::UUID>();
160 160
161 LOG_WARNING(Service_Friend, "(STUBBED) called local_play={} uuid={}", local_play, 161 LOG_WARNING(Service_Friend, "(STUBBED) called, local_play={}, uuid=0x{}", local_play,
162 uuid.Format()); 162 uuid.Format());
163 163
164 IPC::ResponseBuilder rb{ctx, 2}; 164 IPC::ResponseBuilder rb{ctx, 2};
@@ -171,7 +171,7 @@ private:
171 const auto uuid = rp.PopRaw<Common::UUID>(); 171 const auto uuid = rp.PopRaw<Common::UUID>();
172 [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>(); 172 [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>();
173 const auto pid = rp.Pop<u64>(); 173 const auto pid = rp.Pop<u64>();
174 LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid={}, pid={}", friend_offset, 174 LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid=0x{}, pid={}", friend_offset,
175 uuid.Format(), pid); 175 uuid.Format(), pid);
176 176
177 IPC::ResponseBuilder rb{ctx, 3}; 177 IPC::ResponseBuilder rb{ctx, 3};
@@ -289,7 +289,7 @@ void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx
289 IPC::RequestParser rp{ctx}; 289 IPC::RequestParser rp{ctx};
290 auto uuid = rp.PopRaw<Common::UUID>(); 290 auto uuid = rp.PopRaw<Common::UUID>();
291 291
292 LOG_DEBUG(Service_Friend, "called, uuid={}", uuid.Format()); 292 LOG_DEBUG(Service_Friend, "called, uuid=0x{}", uuid.Format());
293 293
294 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 294 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
295 rb.Push(ResultSuccess); 295 rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/ns/language.cpp b/src/core/hle/service/ns/language.cpp
index 29c4a820c..54b644830 100644
--- a/src/core/hle/service/ns/language.cpp
+++ b/src/core/hle/service/ns/language.cpp
@@ -344,8 +344,10 @@ std::optional<ApplicationLanguage> ConvertToApplicationLanguage(
344 return ApplicationLanguage::Russian; 344 return ApplicationLanguage::Russian;
345 case Set::LanguageCode::KO: 345 case Set::LanguageCode::KO:
346 return ApplicationLanguage::Korean; 346 return ApplicationLanguage::Korean;
347 case Set::LanguageCode::ZH_TW:
347 case Set::LanguageCode::ZH_HANT: 348 case Set::LanguageCode::ZH_HANT:
348 return ApplicationLanguage::TraditionalChinese; 349 return ApplicationLanguage::TraditionalChinese;
350 case Set::LanguageCode::ZH_CN:
349 case Set::LanguageCode::ZH_HANS: 351 case Set::LanguageCode::ZH_HANS:
350 return ApplicationLanguage::SimplifiedChinese; 352 return ApplicationLanguage::SimplifiedChinese;
351 default: 353 default:
diff --git a/src/core/hle/service/ns/ns_language.h b/src/core/hle/service/ns/ns_language.h
deleted file mode 100644
index 59ac85a19..000000000
--- a/src/core/hle/service/ns/ns_language.h
+++ /dev/null
@@ -1,42 +0,0 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6#include <optional>
7#include <string>
8#include "common/common_types.h"
9#include "core/hle/service/set/set.h"
10
11namespace Service::NS {
12/// This is nn::ns::detail::ApplicationLanguage
13enum class ApplicationLanguage : u8 {
14 AmericanEnglish = 0,
15 BritishEnglish,
16 Japanese,
17 French,
18 German,
19 LatinAmericanSpanish,
20 Spanish,
21 Italian,
22 Dutch,
23 CanadianFrench,
24 Portuguese,
25 Russian,
26 Korean,
27 TraditionalChinese,
28 SimplifiedChinese,
29 Count
30};
31using ApplicationLanguagePriorityList =
32 const std::array<ApplicationLanguage, static_cast<std::size_t>(ApplicationLanguage::Count)>;
33
34constexpr u32 GetSupportedLanguageFlag(const ApplicationLanguage lang) {
35 return 1U << static_cast<u32>(lang);
36}
37
38const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList(ApplicationLanguage lang);
39std::optional<ApplicationLanguage> ConvertToApplicationLanguage(
40 Service::Set::LanguageCode language_code);
41std::optional<Service::Set::LanguageCode> ConvertToLanguageCode(ApplicationLanguage lang);
42} // namespace Service::NS \ No newline at end of file
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 2cc0da124..ce6065db2 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -54,7 +54,7 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
54 54
55 system.GetPerfStats().EndSystemFrame(); 55 system.GetPerfStats().EndSystemFrame();
56 system.GPU().SwapBuffers(&framebuffer); 56 system.GPU().SwapBuffers(&framebuffer);
57 system.FrameLimiter().DoFrameLimiting(system.CoreTiming().GetGlobalTimeUs()); 57 system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs());
58 system.GetPerfStats().BeginSystemFrame(); 58 system.GetPerfStats().BeginSystemFrame();
59} 59}
60 60
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
index 6635a1339..c9ded49d0 100644
--- a/src/core/perf_stats.cpp
+++ b/src/core/perf_stats.cpp
@@ -127,15 +127,15 @@ double PerfStats::GetLastFrameTimeScale() const {
127 return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH; 127 return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH;
128} 128}
129 129
130void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) { 130void SpeedLimiter::DoSpeedLimiting(microseconds current_system_time_us) {
131 if (!Settings::values.use_frame_limit.GetValue() || 131 if (!Settings::values.use_speed_limit.GetValue() ||
132 Settings::values.use_multi_core.GetValue()) { 132 Settings::values.use_multi_core.GetValue()) {
133 return; 133 return;
134 } 134 }
135 135
136 auto now = Clock::now(); 136 auto now = Clock::now();
137 137
138 const double sleep_scale = Settings::values.frame_limit.GetValue() / 100.0; 138 const double sleep_scale = Settings::values.speed_limit.GetValue() / 100.0;
139 139
140 // Max lag caused by slow frames. Shouldn't be more than the length of a frame at the current 140 // Max lag caused by slow frames. Shouldn't be more than the length of a frame at the current
141 // speed percent or it will clamp too much and prevent this from properly limiting to that 141 // speed percent or it will clamp too much and prevent this from properly limiting to that
@@ -143,17 +143,17 @@ void FrameLimiter::DoFrameLimiting(microseconds current_system_time_us) {
143 // limiting 143 // limiting
144 const microseconds max_lag_time_us = duration_cast<microseconds>( 144 const microseconds max_lag_time_us = duration_cast<microseconds>(
145 std::chrono::duration<double, std::chrono::microseconds::period>(25ms / sleep_scale)); 145 std::chrono::duration<double, std::chrono::microseconds::period>(25ms / sleep_scale));
146 frame_limiting_delta_err += duration_cast<microseconds>( 146 speed_limiting_delta_err += duration_cast<microseconds>(
147 std::chrono::duration<double, std::chrono::microseconds::period>( 147 std::chrono::duration<double, std::chrono::microseconds::period>(
148 (current_system_time_us - previous_system_time_us) / sleep_scale)); 148 (current_system_time_us - previous_system_time_us) / sleep_scale));
149 frame_limiting_delta_err -= duration_cast<microseconds>(now - previous_walltime); 149 speed_limiting_delta_err -= duration_cast<microseconds>(now - previous_walltime);
150 frame_limiting_delta_err = 150 speed_limiting_delta_err =
151 std::clamp(frame_limiting_delta_err, -max_lag_time_us, max_lag_time_us); 151 std::clamp(speed_limiting_delta_err, -max_lag_time_us, max_lag_time_us);
152 152
153 if (frame_limiting_delta_err > microseconds::zero()) { 153 if (speed_limiting_delta_err > microseconds::zero()) {
154 std::this_thread::sleep_for(frame_limiting_delta_err); 154 std::this_thread::sleep_for(speed_limiting_delta_err);
155 auto now_after_sleep = Clock::now(); 155 auto now_after_sleep = Clock::now();
156 frame_limiting_delta_err -= duration_cast<microseconds>(now_after_sleep - now); 156 speed_limiting_delta_err -= duration_cast<microseconds>(now_after_sleep - now);
157 now = now_after_sleep; 157 now = now_after_sleep;
158 } 158 }
159 159
diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h
index e5d603717..a2541906f 100644
--- a/src/core/perf_stats.h
+++ b/src/core/perf_stats.h
@@ -85,11 +85,11 @@ private:
85 double previous_fps = 0; 85 double previous_fps = 0;
86}; 86};
87 87
88class FrameLimiter { 88class SpeedLimiter {
89public: 89public:
90 using Clock = std::chrono::high_resolution_clock; 90 using Clock = std::chrono::high_resolution_clock;
91 91
92 void DoFrameLimiting(std::chrono::microseconds current_system_time_us); 92 void DoSpeedLimiting(std::chrono::microseconds current_system_time_us);
93 93
94private: 94private:
95 /// Emulated system time (in microseconds) at the last limiter invocation 95 /// Emulated system time (in microseconds) at the last limiter invocation
@@ -98,7 +98,7 @@ private:
98 Clock::time_point previous_walltime = Clock::now(); 98 Clock::time_point previous_walltime = Clock::now();
99 99
100 /// Accumulated difference between walltime and emulated time 100 /// Accumulated difference between walltime and emulated time
101 std::chrono::microseconds frame_limiting_delta_err{0}; 101 std::chrono::microseconds speed_limiting_delta_err{0};
102}; 102};
103 103
104} // namespace Core 104} // namespace Core
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 422de3a7d..5a8cfd301 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -221,8 +221,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
221 TranslateRenderer(Settings::values.renderer_backend.GetValue())); 221 TranslateRenderer(Settings::values.renderer_backend.GetValue()));
222 AddField(field_type, "Renderer_ResolutionFactor", 222 AddField(field_type, "Renderer_ResolutionFactor",
223 Settings::values.resolution_factor.GetValue()); 223 Settings::values.resolution_factor.GetValue());
224 AddField(field_type, "Renderer_UseFrameLimit", Settings::values.use_frame_limit.GetValue()); 224 AddField(field_type, "Renderer_UseSpeedLimit", Settings::values.use_speed_limit.GetValue());
225 AddField(field_type, "Renderer_FrameLimit", Settings::values.frame_limit.GetValue()); 225 AddField(field_type, "Renderer_SpeedLimit", Settings::values.speed_limit.GetValue());
226 AddField(field_type, "Renderer_UseDiskShaderCache", 226 AddField(field_type, "Renderer_UseDiskShaderCache",
227 Settings::values.use_disk_shader_cache.GetValue()); 227 Settings::values.use_disk_shader_cache.GetValue());
228 AddField(field_type, "Renderer_GPUAccuracyLevel", 228 AddField(field_type, "Renderer_GPUAccuracyLevel",
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
index a5e8c9b6e..4ce1c4f54 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
@@ -350,7 +350,7 @@ std::string_view InputPrimitive(InputTopology topology) {
350 case InputTopology::Lines: 350 case InputTopology::Lines:
351 return "LINES"; 351 return "LINES";
352 case InputTopology::LinesAdjacency: 352 case InputTopology::LinesAdjacency:
353 return "LINESS_ADJACENCY"; 353 return "LINES_ADJACENCY";
354 case InputTopology::Triangles: 354 case InputTopology::Triangles:
355 return "TRIANGLES"; 355 return "TRIANGLES";
356 case InputTopology::TrianglesAdjacency: 356 case InputTopology::TrianglesAdjacency:
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
index f99c02848..c9db1c164 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once
6
5#include <sirit/sirit.h> 7#include <sirit/sirit.h>
6 8
7#include "common/common_types.h" 9#include "common/common_types.h"
diff --git a/src/shader_recompiler/exception.h b/src/shader_recompiler/exception.h
index 337e7f0c8..277be8541 100644
--- a/src/shader_recompiler/exception.h
+++ b/src/shader_recompiler/exception.h
@@ -4,7 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <stdexcept> 7#include <exception>
8#include <string> 8#include <string>
9#include <string_view> 9#include <string_view>
10#include <utility> 10#include <utility>
@@ -17,7 +17,7 @@ class Exception : public std::exception {
17public: 17public:
18 explicit Exception(std::string message) noexcept : err_message{std::move(message)} {} 18 explicit Exception(std::string message) noexcept : err_message{std::move(message)} {}
19 19
20 const char* what() const noexcept override { 20 [[nodiscard]] const char* what() const noexcept override {
21 return err_message.c_str(); 21 return err_message.c_str();
22 } 22 }
23 23
@@ -36,21 +36,21 @@ private:
36class LogicError : public Exception { 36class LogicError : public Exception {
37public: 37public:
38 template <typename... Args> 38 template <typename... Args>
39 LogicError(const char* message, Args&&... args) 39 explicit LogicError(const char* message, Args&&... args)
40 : Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {} 40 : Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {}
41}; 41};
42 42
43class RuntimeError : public Exception { 43class RuntimeError : public Exception {
44public: 44public:
45 template <typename... Args> 45 template <typename... Args>
46 RuntimeError(const char* message, Args&&... args) 46 explicit RuntimeError(const char* message, Args&&... args)
47 : Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {} 47 : Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {}
48}; 48};
49 49
50class NotImplementedException : public Exception { 50class NotImplementedException : public Exception {
51public: 51public:
52 template <typename... Args> 52 template <typename... Args>
53 NotImplementedException(const char* message, Args&&... args) 53 explicit NotImplementedException(const char* message, Args&&... args)
54 : Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} { 54 : Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {
55 Append(" is not implemented"); 55 Append(" is not implemented");
56 } 56 }
@@ -59,7 +59,7 @@ public:
59class InvalidArgument : public Exception { 59class InvalidArgument : public Exception {
60public: 60public:
61 template <typename... Args> 61 template <typename... Args>
62 InvalidArgument(const char* message, Args&&... args) 62 explicit InvalidArgument(const char* message, Args&&... args)
63 : Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {} 63 : Exception{fmt::format(fmt::runtime(message), std::forward<Args>(args)...)} {}
64}; 64};
65 65
diff --git a/src/shader_recompiler/frontend/ir/ir_emitter.h b/src/shader_recompiler/frontend/ir/ir_emitter.h
index 53f7b3b06..1b89ca5a0 100644
--- a/src/shader_recompiler/frontend/ir/ir_emitter.h
+++ b/src/shader_recompiler/frontend/ir/ir_emitter.h
@@ -327,8 +327,8 @@ public:
327 const Value& derivates, const Value& offset, 327 const Value& derivates, const Value& offset,
328 const F32& lod_clamp, TextureInstInfo info); 328 const F32& lod_clamp, TextureInstInfo info);
329 [[nodiscard]] Value ImageRead(const Value& handle, const Value& coords, TextureInstInfo info); 329 [[nodiscard]] Value ImageRead(const Value& handle, const Value& coords, TextureInstInfo info);
330 [[nodiscard]] void ImageWrite(const Value& handle, const Value& coords, const Value& color, 330 void ImageWrite(const Value& handle, const Value& coords, const Value& color,
331 TextureInstInfo info); 331 TextureInstInfo info);
332 332
333 [[nodiscard]] Value ImageAtomicIAdd(const Value& handle, const Value& coords, 333 [[nodiscard]] Value ImageAtomicIAdd(const Value& handle, const Value& coords,
334 const Value& value, TextureInstInfo info); 334 const Value& value, TextureInstInfo info);
diff --git a/src/shader_recompiler/frontend/ir/value.h b/src/shader_recompiler/frontend/ir/value.h
index dbea20115..334bb47aa 100644
--- a/src/shader_recompiler/frontend/ir/value.h
+++ b/src/shader_recompiler/frontend/ir/value.h
@@ -198,8 +198,8 @@ public:
198 } 198 }
199 199
200 template <typename FlagsType> 200 template <typename FlagsType>
201 requires(sizeof(FlagsType) <= sizeof(u32) && std::is_trivially_copyable_v<FlagsType>) 201 requires(sizeof(FlagsType) <= sizeof(u32) &&
202 [[nodiscard]] void SetFlags(FlagsType value) noexcept { 202 std::is_trivially_copyable_v<FlagsType>) void SetFlags(FlagsType value) noexcept {
203 std::memcpy(&flags, &value, sizeof(value)); 203 std::memcpy(&flags, &value, sizeof(value));
204 } 204 }
205 205
diff --git a/src/shader_recompiler/frontend/maxwell/control_flow.cpp b/src/shader_recompiler/frontend/maxwell/control_flow.cpp
index 1a954a509..efe457baa 100644
--- a/src/shader_recompiler/frontend/maxwell/control_flow.cpp
+++ b/src/shader_recompiler/frontend/maxwell/control_flow.cpp
@@ -73,7 +73,7 @@ Token OpcodeToken(Opcode opcode) {
73 return Token::PBK; 73 return Token::PBK;
74 case Opcode::PCNT: 74 case Opcode::PCNT:
75 case Opcode::CONT: 75 case Opcode::CONT:
76 return Token::PBK; 76 return Token::PCNT;
77 case Opcode::PEXIT: 77 case Opcode::PEXIT:
78 case Opcode::EXIT: 78 case Opcode::EXIT:
79 return Token::PEXIT; 79 return Token::PEXIT;
diff --git a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
index 5ead930f1..f69e1c9cc 100644
--- a/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
+++ b/src/shader_recompiler/ir_opt/collect_shader_info_pass.cpp
@@ -111,6 +111,8 @@ void VisitUsages(Info& info, IR::Inst& inst) {
111 case IR::Opcode::ConvertF16U16: 111 case IR::Opcode::ConvertF16U16:
112 case IR::Opcode::ConvertF16U32: 112 case IR::Opcode::ConvertF16U32:
113 case IR::Opcode::ConvertF16U64: 113 case IR::Opcode::ConvertF16U64:
114 case IR::Opcode::ConvertF16F32:
115 case IR::Opcode::ConvertF32F16:
114 case IR::Opcode::FPAbs16: 116 case IR::Opcode::FPAbs16:
115 case IR::Opcode::FPAdd16: 117 case IR::Opcode::FPAdd16:
116 case IR::Opcode::FPCeil16: 118 case IR::Opcode::FPCeil16:
diff --git a/src/shader_recompiler/object_pool.h b/src/shader_recompiler/object_pool.h
index f8b255b66..f3b12d04b 100644
--- a/src/shader_recompiler/object_pool.h
+++ b/src/shader_recompiler/object_pool.h
@@ -63,6 +63,7 @@ private:
63 used_objects = std::exchange(rhs.used_objects, 0); 63 used_objects = std::exchange(rhs.used_objects, 0);
64 num_objects = std::exchange(rhs.num_objects, 0); 64 num_objects = std::exchange(rhs.num_objects, 0);
65 storage = std::move(rhs.storage); 65 storage = std::move(rhs.storage);
66 return *this;
66 } 67 }
67 68
68 Chunk(Chunk&& rhs) noexcept 69 Chunk(Chunk&& rhs) noexcept
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 24c858104..3b43554f9 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -817,7 +817,6 @@ void BufferCache<P>::CommitAsyncFlushesHigh() {
817 const std::size_t size = interval.upper() - interval.lower(); 817 const std::size_t size = interval.upper() - interval.lower();
818 const VAddr cpu_addr = interval.lower(); 818 const VAddr cpu_addr = interval.lower();
819 ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) { 819 ForEachBufferInRange(cpu_addr, size, [&](BufferId buffer_id, Buffer& buffer) {
820 boost::container::small_vector<BufferCopy, 1> copies;
821 buffer.ForEachDownloadRangeAndClear( 820 buffer.ForEachDownloadRangeAndClear(
822 cpu_addr, size, [&](u64 range_offset, u64 range_size) { 821 cpu_addr, size, [&](u64 range_offset, u64 range_size) {
823 const VAddr buffer_addr = buffer.CpuAddr(); 822 const VAddr buffer_addr = buffer.CpuAddr();
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h
index a4170ffff..d76c5ed56 100644
--- a/src/video_core/engines/fermi_2d.h
+++ b/src/video_core/engines/fermi_2d.h
@@ -299,7 +299,7 @@ public:
299 }; 299 };
300 300
301private: 301private:
302 VideoCore::RasterizerInterface* rasterizer; 302 VideoCore::RasterizerInterface* rasterizer = nullptr;
303 303
304 /// Performs the copy from the source surface to the destination surface as configured in the 304 /// Performs the copy from the source surface to the destination surface as configured in the
305 /// registers. 305 /// registers.
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h
index d3329b0f8..9e457ae16 100644
--- a/src/video_core/engines/maxwell_dma.h
+++ b/src/video_core/engines/maxwell_dma.h
@@ -227,7 +227,7 @@ private:
227 Core::System& system; 227 Core::System& system;
228 228
229 MemoryManager& memory_manager; 229 MemoryManager& memory_manager;
230 VideoCore::RasterizerInterface* rasterizer; 230 VideoCore::RasterizerInterface* rasterizer = nullptr;
231 231
232 std::vector<u8> read_buffer; 232 std::vector<u8> read_buffer;
233 std::vector<u8> write_buffer; 233 std::vector<u8> write_buffer;
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index c9a360aaf..3ea72fda9 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -19,9 +19,6 @@ RendererBase::~RendererBase() = default;
19 19
20void RendererBase::RefreshBaseSettings() { 20void RendererBase::RefreshBaseSettings() {
21 UpdateCurrentFramebufferLayout(); 21 UpdateCurrentFramebufferLayout();
22
23 renderer_settings.use_framelimiter = Settings::values.use_frame_limit.GetValue();
24 renderer_settings.set_background_color = true;
25} 22}
26 23
27void RendererBase::UpdateCurrentFramebufferLayout() { 24void RendererBase::UpdateCurrentFramebufferLayout() {
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 63d8ad42a..22b80c328 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -21,9 +21,6 @@ class GraphicsContext;
21namespace VideoCore { 21namespace VideoCore {
22 22
23struct RendererSettings { 23struct RendererSettings {
24 std::atomic_bool use_framelimiter{false};
25 std::atomic_bool set_background_color{false};
26
27 // Screenshot 24 // Screenshot
28 std::atomic<bool> screenshot_requested{false}; 25 std::atomic<bool> screenshot_requested{false};
29 void* screenshot_bits{}; 26 void* screenshot_bits{};
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 8d6cc074c..1f4dda17e 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -441,7 +441,6 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
441 441
442 std::array<const Shader::Info*, Maxwell::MaxShaderStage> infos{}; 442 std::array<const Shader::Info*, Maxwell::MaxShaderStage> infos{};
443 443
444 OGLProgram source_program;
445 std::array<std::string, 5> sources; 444 std::array<std::string, 5> sources;
446 std::array<std::vector<u32>, 5> sources_spirv; 445 std::array<std::vector<u32>, 5> sources_spirv;
447 Shader::Backend::Bindings binding; 446 Shader::Backend::Bindings binding;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 285e78384..f1b00c24c 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -328,12 +328,10 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
328} 328}
329 329
330void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) { 330void RendererOpenGL::DrawScreen(const Layout::FramebufferLayout& layout) {
331 if (renderer_settings.set_background_color) { 331 // Update background color before drawing
332 // Update background color before drawing 332 glClearColor(Settings::values.bg_red.GetValue() / 255.0f,
333 glClearColor(Settings::values.bg_red.GetValue() / 255.0f, 333 Settings::values.bg_green.GetValue() / 255.0f,
334 Settings::values.bg_green.GetValue() / 255.0f, 334 Settings::values.bg_blue.GetValue() / 255.0f, 1.0f);
335 Settings::values.bg_blue.GetValue() / 255.0f, 1.0f);
336 }
337 335
338 // Set projection matrix 336 // Set projection matrix
339 const std::array ortho_matrix = 337 const std::array ortho_matrix =
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index f4b3ee95c..8ac58bc2f 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -358,7 +358,7 @@ void BufferCacheRuntime::ReserveNullBuffer() {
358 if (null_buffer) { 358 if (null_buffer) {
359 return; 359 return;
360 } 360 }
361 null_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ 361 VkBufferCreateInfo create_info{
362 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 362 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
363 .pNext = nullptr, 363 .pNext = nullptr,
364 .flags = 0, 364 .flags = 0,
@@ -367,9 +367,13 @@ void BufferCacheRuntime::ReserveNullBuffer() {
367 .sharingMode = VK_SHARING_MODE_EXCLUSIVE, 367 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
368 .queueFamilyIndexCount = 0, 368 .queueFamilyIndexCount = 0,
369 .pQueueFamilyIndices = nullptr, 369 .pQueueFamilyIndices = nullptr,
370 }); 370 };
371 if (device.IsExtTransformFeedbackSupported()) {
372 create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
373 }
374 null_buffer = device.GetLogical().CreateBuffer(create_info);
371 if (device.HasDebuggingToolAttached()) { 375 if (device.HasDebuggingToolAttached()) {
372 null_buffer.SetObjectNameEXT("Null index buffer"); 376 null_buffer.SetObjectNameEXT("Null buffer");
373 } 377 }
374 null_buffer_commit = memory_allocator.Commit(null_buffer, MemoryUsage::DeviceLocal); 378 null_buffer_commit = memory_allocator.Commit(null_buffer, MemoryUsage::DeviceLocal);
375 379
diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
index 8e426ce2c..561cf5e11 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp
@@ -258,10 +258,9 @@ std::pair<VkBuffer, VkDeviceSize> Uint8Pass::Assemble(u32 num_vertices, VkBuffer
258 update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices); 258 update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices);
259 update_descriptor_queue.AddBuffer(staging.buffer, staging.offset, staging_size); 259 update_descriptor_queue.AddBuffer(staging.buffer, staging.offset, staging_size);
260 const void* const descriptor_data{update_descriptor_queue.UpdateData()}; 260 const void* const descriptor_data{update_descriptor_queue.UpdateData()};
261 const VkBuffer buffer{staging.buffer};
262 261
263 scheduler.RequestOutsideRenderPassOperationContext(); 262 scheduler.RequestOutsideRenderPassOperationContext();
264 scheduler.Record([this, buffer, descriptor_data, num_vertices](vk::CommandBuffer cmdbuf) { 263 scheduler.Record([this, descriptor_data, num_vertices](vk::CommandBuffer cmdbuf) {
265 static constexpr u32 DISPATCH_SIZE = 1024; 264 static constexpr u32 DISPATCH_SIZE = 1024;
266 static constexpr VkMemoryBarrier WRITE_BARRIER{ 265 static constexpr VkMemoryBarrier WRITE_BARRIER{
267 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, 266 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
@@ -319,14 +318,14 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble(
319 const void* const descriptor_data{update_descriptor_queue.UpdateData()}; 318 const void* const descriptor_data{update_descriptor_queue.UpdateData()};
320 319
321 scheduler.RequestOutsideRenderPassOperationContext(); 320 scheduler.RequestOutsideRenderPassOperationContext();
322 scheduler.Record([this, buffer = staging.buffer, descriptor_data, num_tri_vertices, base_vertex, 321 scheduler.Record([this, descriptor_data, num_tri_vertices, base_vertex,
323 index_shift](vk::CommandBuffer cmdbuf) { 322 index_shift](vk::CommandBuffer cmdbuf) {
324 static constexpr u32 DISPATCH_SIZE = 1024; 323 static constexpr u32 DISPATCH_SIZE = 1024;
325 static constexpr VkMemoryBarrier WRITE_BARRIER{ 324 static constexpr VkMemoryBarrier WRITE_BARRIER{
326 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, 325 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
327 .pNext = nullptr, 326 .pNext = nullptr,
328 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT, 327 .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
329 .dstAccessMask = VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, 328 .dstAccessMask = VK_ACCESS_INDEX_READ_BIT,
330 }; 329 };
331 const std::array push_constants{base_vertex, index_shift}; 330 const std::array push_constants{base_vertex, index_shift};
332 const VkDescriptorSet set = descriptor_allocator.Commit(); 331 const VkDescriptorSet set = descriptor_allocator.Commit();
diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
index 555b12ed7..5d5329abf 100644
--- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
+++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
@@ -61,11 +61,15 @@ std::optional<u32> FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& p
61 return std::nullopt; 61 return std::nullopt;
62} 62}
63 63
64u32 FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask) { 64u32 FindMemoryTypeIndex(const VkPhysicalDeviceMemoryProperties& props, u32 type_mask,
65 // Try to find a DEVICE_LOCAL_BIT type, Nvidia and AMD have a dedicated heap for this 65 bool try_device_local) {
66 std::optional<u32> type = FindMemoryTypeIndex(props, type_mask, STREAM_FLAGS); 66 std::optional<u32> type;
67 if (type) { 67 if (try_device_local) {
68 return *type; 68 // Try to find a DEVICE_LOCAL_BIT type, Nvidia and AMD have a dedicated heap for this
69 type = FindMemoryTypeIndex(props, type_mask, STREAM_FLAGS);
70 if (type) {
71 return *type;
72 }
69 } 73 }
70 // Otherwise try without the DEVICE_LOCAL_BIT 74 // Otherwise try without the DEVICE_LOCAL_BIT
71 type = FindMemoryTypeIndex(props, type_mask, HOST_FLAGS); 75 type = FindMemoryTypeIndex(props, type_mask, HOST_FLAGS);
@@ -115,12 +119,21 @@ StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& mem
115 .buffer = *stream_buffer, 119 .buffer = *stream_buffer,
116 }; 120 };
117 const auto memory_properties = device.GetPhysical().GetMemoryProperties(); 121 const auto memory_properties = device.GetPhysical().GetMemoryProperties();
118 stream_memory = dev.AllocateMemory(VkMemoryAllocateInfo{ 122 VkMemoryAllocateInfo stream_memory_info{
119 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, 123 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
120 .pNext = make_dedicated ? &dedicated_info : nullptr, 124 .pNext = make_dedicated ? &dedicated_info : nullptr,
121 .allocationSize = requirements.size, 125 .allocationSize = requirements.size,
122 .memoryTypeIndex = FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits), 126 .memoryTypeIndex =
123 }); 127 FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, true),
128 };
129 stream_memory = dev.TryAllocateMemory(stream_memory_info);
130 if (!stream_memory) {
131 LOG_INFO(Render_Vulkan, "Dynamic memory allocation failed, trying with system memory");
132 stream_memory_info.memoryTypeIndex =
133 FindMemoryTypeIndex(memory_properties, requirements.memoryTypeBits, false);
134 stream_memory = dev.AllocateMemory(stream_memory_info);
135 }
136
124 if (device.HasDebuggingToolAttached()) { 137 if (device.HasDebuggingToolAttached()) {
125 stream_memory.SetObjectNameEXT("Stream Buffer Memory"); 138 stream_memory.SetObjectNameEXT("Stream Buffer Memory");
126 } 139 }
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
deleted file mode 100644
index 7b4875d0e..000000000
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
+++ /dev/null
@@ -1,168 +0,0 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <limits>
7#include <optional>
8#include <tuple>
9#include <vector>
10
11#include "common/alignment.h"
12#include "common/assert.h"
13#include "common/literals.h"
14#include "video_core/renderer_vulkan/vk_scheduler.h"
15#include "video_core/renderer_vulkan/vk_stream_buffer.h"
16#include "video_core/vulkan_common/vulkan_device.h"
17#include "video_core/vulkan_common/vulkan_wrapper.h"
18
19namespace Vulkan {
20
21namespace {
22
23using namespace Common::Literals;
24
25constexpr VkBufferUsageFlags BUFFER_USAGE =
26 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
27 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
28
29constexpr u64 WATCHES_INITIAL_RESERVE = 0x4000;
30constexpr u64 WATCHES_RESERVE_CHUNK = 0x1000;
31
32constexpr u64 PREFERRED_STREAM_BUFFER_SIZE = 256_MiB;
33
34/// Find a memory type with the passed requirements
35std::optional<u32> FindMemoryType(const VkPhysicalDeviceMemoryProperties& properties,
36 VkMemoryPropertyFlags wanted,
37 u32 filter = std::numeric_limits<u32>::max()) {
38 for (u32 i = 0; i < properties.memoryTypeCount; ++i) {
39 const auto flags = properties.memoryTypes[i].propertyFlags;
40 if ((flags & wanted) == wanted && (filter & (1U << i)) != 0) {
41 return i;
42 }
43 }
44 return std::nullopt;
45}
46
47/// Get the preferred host visible memory type.
48u32 GetMemoryType(const VkPhysicalDeviceMemoryProperties& properties,
49 u32 filter = std::numeric_limits<u32>::max()) {
50 // Prefer device local host visible allocations. Both AMD and Nvidia now provide one.
51 // Otherwise search for a host visible allocation.
52 static constexpr auto HOST_MEMORY =
53 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
54 static constexpr auto DYNAMIC_MEMORY = HOST_MEMORY | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
55
56 std::optional preferred_type = FindMemoryType(properties, DYNAMIC_MEMORY);
57 if (!preferred_type) {
58 preferred_type = FindMemoryType(properties, HOST_MEMORY);
59 ASSERT_MSG(preferred_type, "No host visible and coherent memory type found");
60 }
61 return preferred_type.value_or(0);
62}
63
64} // Anonymous namespace
65
66VKStreamBuffer::VKStreamBuffer(const Device& device_, VKScheduler& scheduler_)
67 : device{device_}, scheduler{scheduler_} {
68 CreateBuffers();
69 ReserveWatches(current_watches, WATCHES_INITIAL_RESERVE);
70 ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE);
71}
72
73VKStreamBuffer::~VKStreamBuffer() = default;
74
75std::pair<u8*, u64> VKStreamBuffer::Map(u64 size, u64 alignment) {
76 ASSERT(size <= stream_buffer_size);
77 mapped_size = size;
78
79 if (alignment > 0) {
80 offset = Common::AlignUp(offset, alignment);
81 }
82
83 WaitPendingOperations(offset);
84
85 if (offset + size > stream_buffer_size) {
86 // The buffer would overflow, save the amount of used watches and reset the state.
87 invalidation_mark = current_watch_cursor;
88 current_watch_cursor = 0;
89 offset = 0;
90
91 // Swap watches and reset waiting cursors.
92 std::swap(previous_watches, current_watches);
93 wait_cursor = 0;
94 wait_bound = 0;
95
96 // Ensure that we don't wait for uncommitted fences.
97 scheduler.Flush();
98 }
99
100 return std::make_pair(memory.Map(offset, size), offset);
101}
102
103void VKStreamBuffer::Unmap(u64 size) {
104 ASSERT_MSG(size <= mapped_size, "Reserved size is too small");
105
106 memory.Unmap();
107
108 offset += size;
109
110 if (current_watch_cursor + 1 >= current_watches.size()) {
111 // Ensure that there are enough watches.
112 ReserveWatches(current_watches, WATCHES_RESERVE_CHUNK);
113 }
114 auto& watch = current_watches[current_watch_cursor++];
115 watch.upper_bound = offset;
116 watch.tick = scheduler.CurrentTick();
117}
118
119void VKStreamBuffer::CreateBuffers() {
120 const auto memory_properties = device.GetPhysical().GetMemoryProperties();
121 const u32 preferred_type = GetMemoryType(memory_properties);
122 const u32 preferred_heap = memory_properties.memoryTypes[preferred_type].heapIndex;
123
124 // Substract from the preferred heap size some bytes to avoid getting out of memory.
125 const VkDeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size;
126 // As per DXVK's example, using `heap_size / 2`
127 const VkDeviceSize allocable_size = heap_size / 2;
128 buffer = device.GetLogical().CreateBuffer({
129 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
130 .pNext = nullptr,
131 .flags = 0,
132 .size = std::min(PREFERRED_STREAM_BUFFER_SIZE, allocable_size),
133 .usage = BUFFER_USAGE,
134 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
135 .queueFamilyIndexCount = 0,
136 .pQueueFamilyIndices = nullptr,
137 });
138
139 const auto requirements = device.GetLogical().GetBufferMemoryRequirements(*buffer);
140 const u32 required_flags = requirements.memoryTypeBits;
141 stream_buffer_size = static_cast<u64>(requirements.size);
142
143 memory = device.GetLogical().AllocateMemory({
144 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
145 .pNext = nullptr,
146 .allocationSize = requirements.size,
147 .memoryTypeIndex = GetMemoryType(memory_properties, required_flags),
148 });
149 buffer.BindMemory(*memory, 0);
150}
151
152void VKStreamBuffer::ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size) {
153 watches.resize(watches.size() + grow_size);
154}
155
156void VKStreamBuffer::WaitPendingOperations(u64 requested_upper_bound) {
157 if (!invalidation_mark) {
158 return;
159 }
160 while (requested_upper_bound < wait_bound && wait_cursor < *invalidation_mark) {
161 auto& watch = previous_watches[wait_cursor];
162 wait_bound = watch.upper_bound;
163 scheduler.Wait(watch.tick);
164 ++wait_cursor;
165 }
166}
167
168} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.h b/src/video_core/renderer_vulkan/vk_stream_buffer.h
deleted file mode 100644
index 2e9c8cb46..000000000
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.h
+++ /dev/null
@@ -1,76 +0,0 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <optional>
8#include <utility>
9#include <vector>
10
11#include "common/common_types.h"
12#include "video_core/vulkan_common/vulkan_wrapper.h"
13
14namespace Vulkan {
15
16class Device;
17class VKFenceWatch;
18class VKScheduler;
19
20class VKStreamBuffer final {
21public:
22 explicit VKStreamBuffer(const Device& device, VKScheduler& scheduler);
23 ~VKStreamBuffer();
24
25 /**
26 * Reserves a region of memory from the stream buffer.
27 * @param size Size to reserve.
28 * @returns A pair of a raw memory pointer (with offset added), and the buffer offset
29 */
30 std::pair<u8*, u64> Map(u64 size, u64 alignment);
31
32 /// Ensures that "size" bytes of memory are available to the GPU, potentially recording a copy.
33 void Unmap(u64 size);
34
35 VkBuffer Handle() const noexcept {
36 return *buffer;
37 }
38
39 u64 Address() const noexcept {
40 return 0;
41 }
42
43private:
44 struct Watch {
45 u64 tick{};
46 u64 upper_bound{};
47 };
48
49 /// Creates Vulkan buffer handles committing the required the required memory.
50 void CreateBuffers();
51
52 /// Increases the amount of watches available.
53 void ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size);
54
55 void WaitPendingOperations(u64 requested_upper_bound);
56
57 const Device& device; ///< Vulkan device manager.
58 VKScheduler& scheduler; ///< Command scheduler.
59
60 vk::Buffer buffer; ///< Mapped buffer.
61 vk::DeviceMemory memory; ///< Memory allocation.
62 u64 stream_buffer_size{}; ///< Stream buffer size.
63
64 u64 offset{}; ///< Buffer iterator.
65 u64 mapped_size{}; ///< Size reserved for the current copy.
66
67 std::vector<Watch> current_watches; ///< Watches recorded in the current iteration.
68 std::size_t current_watch_cursor{}; ///< Count of watches, reset on invalidation.
69 std::optional<std::size_t> invalidation_mark; ///< Number of watches used in the previous cycle.
70
71 std::vector<Watch> previous_watches; ///< Watches used in the previous iteration.
72 std::size_t wait_cursor{}; ///< Last watch being waited for completion.
73 u64 wait_bound{}; ///< Highest offset being watched for completion.
74};
75
76} // namespace Vulkan
diff --git a/src/video_core/texture_cache/render_targets.h b/src/video_core/texture_cache/render_targets.h
index 9b9544b07..0cb227d69 100644
--- a/src/video_core/texture_cache/render_targets.h
+++ b/src/video_core/texture_cache/render_targets.h
@@ -24,10 +24,10 @@ struct RenderTargets {
24 return std::ranges::any_of(color_buffer_ids, contains) || contains(depth_buffer_id); 24 return std::ranges::any_of(color_buffer_ids, contains) || contains(depth_buffer_id);
25 } 25 }
26 26
27 std::array<ImageViewId, NUM_RT> color_buffer_ids; 27 std::array<ImageViewId, NUM_RT> color_buffer_ids{};
28 ImageViewId depth_buffer_id; 28 ImageViewId depth_buffer_id{};
29 std::array<u8, NUM_RT> draw_buffers{}; 29 std::array<u8, NUM_RT> draw_buffers{};
30 Extent2D size; 30 Extent2D size{};
31}; 31};
32 32
33} // namespace VideoCommon 33} // namespace VideoCommon
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp
index bbf0fccae..70898004a 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -202,7 +202,7 @@ void SetObjectName(const DeviceDispatch* dld, VkDevice device, T handle, VkObjec
202 const VkDebugUtilsObjectNameInfoEXT name_info{ 202 const VkDebugUtilsObjectNameInfoEXT name_info{
203 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, 203 .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
204 .pNext = nullptr, 204 .pNext = nullptr,
205 .objectType = VK_OBJECT_TYPE_IMAGE, 205 .objectType = type,
206 .objectHandle = reinterpret_cast<u64>(handle), 206 .objectHandle = reinterpret_cast<u64>(handle),
207 .pObjectName = name, 207 .pObjectName = name,
208 }; 208 };
diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp
index b112dd7b0..652d99570 100644
--- a/src/yuzu/applets/qt_web_browser.cpp
+++ b/src/yuzu/applets/qt_web_browser.cpp
@@ -107,6 +107,7 @@ void QtNXWebEngineView::LoadLocalWebPage(const std::string& main_url,
107 is_local = true; 107 is_local = true;
108 108
109 LoadExtractedFonts(); 109 LoadExtractedFonts();
110 FocusFirstLinkElement();
110 SetUserAgent(UserAgent::WebApplet); 111 SetUserAgent(UserAgent::WebApplet);
111 SetFinished(false); 112 SetFinished(false);
112 SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed); 113 SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed);
@@ -121,6 +122,7 @@ void QtNXWebEngineView::LoadExternalWebPage(const std::string& main_url,
121 const std::string& additional_args) { 122 const std::string& additional_args) {
122 is_local = false; 123 is_local = false;
123 124
125 FocusFirstLinkElement();
124 SetUserAgent(UserAgent::WebApplet); 126 SetUserAgent(UserAgent::WebApplet);
125 SetFinished(false); 127 SetFinished(false);
126 SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed); 128 SetExitReason(Service::AM::Applets::WebExitReason::EndButtonPressed);
@@ -208,7 +210,7 @@ void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() {
208 if (input_interpreter->IsButtonPressedOnce(button)) { 210 if (input_interpreter->IsButtonPressedOnce(button)) {
209 page()->runJavaScript( 211 page()->runJavaScript(
210 QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(static_cast<u8>(button)), 212 QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(static_cast<u8>(button)),
211 [&](const QVariant& variant) { 213 [this, button](const QVariant& variant) {
212 if (variant.toBool()) { 214 if (variant.toBool()) {
213 switch (button) { 215 switch (button) {
214 case HIDButton::A: 216 case HIDButton::A:
@@ -364,6 +366,17 @@ void QtNXWebEngineView::LoadExtractedFonts() {
364 Qt::QueuedConnection); 366 Qt::QueuedConnection);
365} 367}
366 368
369void QtNXWebEngineView::FocusFirstLinkElement() {
370 QWebEngineScript focus_link_element;
371
372 focus_link_element.setName(QStringLiteral("focus_link_element.js"));
373 focus_link_element.setSourceCode(QString::fromStdString(FOCUS_LINK_ELEMENT_SCRIPT));
374 focus_link_element.setWorldId(QWebEngineScript::MainWorld);
375 focus_link_element.setInjectionPoint(QWebEngineScript::Deferred);
376 focus_link_element.setRunsOnSubFrames(true);
377 default_profile->scripts()->insert(focus_link_element);
378}
379
367#endif 380#endif
368 381
369QtWebBrowser::QtWebBrowser(GMainWindow& main_window) { 382QtWebBrowser::QtWebBrowser(GMainWindow& main_window) {
diff --git a/src/yuzu/applets/qt_web_browser.h b/src/yuzu/applets/qt_web_browser.h
index 7ad07409f..7e9f703fc 100644
--- a/src/yuzu/applets/qt_web_browser.h
+++ b/src/yuzu/applets/qt_web_browser.h
@@ -161,6 +161,9 @@ private:
161 /// Loads the extracted fonts using JavaScript. 161 /// Loads the extracted fonts using JavaScript.
162 void LoadExtractedFonts(); 162 void LoadExtractedFonts();
163 163
164 /// Brings focus to the first available link element.
165 void FocusFirstLinkElement();
166
164 InputCommon::InputSubsystem* input_subsystem; 167 InputCommon::InputSubsystem* input_subsystem;
165 168
166 std::unique_ptr<UrlRequestInterceptor> url_interceptor; 169 std::unique_ptr<UrlRequestInterceptor> url_interceptor;
diff --git a/src/yuzu/applets/qt_web_browser_scripts.h b/src/yuzu/applets/qt_web_browser_scripts.h
index 992837a85..c4ba8d40f 100644
--- a/src/yuzu/applets/qt_web_browser_scripts.h
+++ b/src/yuzu/applets/qt_web_browser_scripts.h
@@ -73,6 +73,12 @@ constexpr char LOAD_NX_FONT[] = R"(
73})(); 73})();
74)"; 74)";
75 75
76constexpr char FOCUS_LINK_ELEMENT_SCRIPT[] = R"(
77if (document.getElementsByTagName("a").length > 0) {
78 document.getElementsByTagName("a")[0].focus();
79}
80)";
81
76constexpr char GAMEPAD_SCRIPT[] = R"( 82constexpr char GAMEPAD_SCRIPT[] = R"(
77window.addEventListener("gamepadconnected", function(e) { 83window.addEventListener("gamepadconnected", function(e) {
78 console.log("Gamepad connected at index %d: %s. %d buttons, %d axes.", 84 console.log("Gamepad connected at index %d: %s. %d buttons, %d axes.",
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 4d89b00e9..ecd5dfac1 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -806,8 +806,8 @@ void Config::ReadRendererValues() {
806 ReadGlobalSetting(Settings::values.fullscreen_mode); 806 ReadGlobalSetting(Settings::values.fullscreen_mode);
807 ReadGlobalSetting(Settings::values.aspect_ratio); 807 ReadGlobalSetting(Settings::values.aspect_ratio);
808 ReadGlobalSetting(Settings::values.max_anisotropy); 808 ReadGlobalSetting(Settings::values.max_anisotropy);
809 ReadGlobalSetting(Settings::values.use_frame_limit); 809 ReadGlobalSetting(Settings::values.use_speed_limit);
810 ReadGlobalSetting(Settings::values.frame_limit); 810 ReadGlobalSetting(Settings::values.speed_limit);
811 ReadGlobalSetting(Settings::values.use_disk_shader_cache); 811 ReadGlobalSetting(Settings::values.use_disk_shader_cache);
812 ReadGlobalSetting(Settings::values.gpu_accuracy); 812 ReadGlobalSetting(Settings::values.gpu_accuracy);
813 ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation); 813 ReadGlobalSetting(Settings::values.use_asynchronous_gpu_emulation);
@@ -1332,11 +1332,14 @@ void Config::SaveRendererValues() {
1332 static_cast<u32>(Settings::values.renderer_backend.GetDefault()), 1332 static_cast<u32>(Settings::values.renderer_backend.GetDefault()),
1333 Settings::values.renderer_backend.UsingGlobal()); 1333 Settings::values.renderer_backend.UsingGlobal());
1334 WriteGlobalSetting(Settings::values.vulkan_device); 1334 WriteGlobalSetting(Settings::values.vulkan_device);
1335 WriteGlobalSetting(Settings::values.fullscreen_mode); 1335 WriteSetting(QString::fromStdString(Settings::values.fullscreen_mode.GetLabel()),
1336 static_cast<u32>(Settings::values.fullscreen_mode.GetValue(global)),
1337 static_cast<u32>(Settings::values.fullscreen_mode.GetDefault()),
1338 Settings::values.fullscreen_mode.UsingGlobal());
1336 WriteGlobalSetting(Settings::values.aspect_ratio); 1339 WriteGlobalSetting(Settings::values.aspect_ratio);
1337 WriteGlobalSetting(Settings::values.max_anisotropy); 1340 WriteGlobalSetting(Settings::values.max_anisotropy);
1338 WriteGlobalSetting(Settings::values.use_frame_limit); 1341 WriteGlobalSetting(Settings::values.use_speed_limit);
1339 WriteGlobalSetting(Settings::values.frame_limit); 1342 WriteGlobalSetting(Settings::values.speed_limit);
1340 WriteGlobalSetting(Settings::values.use_disk_shader_cache); 1343 WriteGlobalSetting(Settings::values.use_disk_shader_cache);
1341 WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()), 1344 WriteSetting(QString::fromStdString(Settings::values.gpu_accuracy.GetLabel()),
1342 static_cast<u32>(Settings::values.gpu_accuracy.GetValue(global)), 1345 static_cast<u32>(Settings::values.gpu_accuracy.GetValue(global)),
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 4bbb9f1cd..c1d7feb9f 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -181,5 +181,6 @@ private:
181// These metatype declarations cannot be in common/settings.h because core is devoid of QT 181// These metatype declarations cannot be in common/settings.h because core is devoid of QT
182Q_DECLARE_METATYPE(Settings::CPUAccuracy); 182Q_DECLARE_METATYPE(Settings::CPUAccuracy);
183Q_DECLARE_METATYPE(Settings::GPUAccuracy); 183Q_DECLARE_METATYPE(Settings::GPUAccuracy);
184Q_DECLARE_METATYPE(Settings::FullscreenMode);
184Q_DECLARE_METATYPE(Settings::RendererBackend); 185Q_DECLARE_METATYPE(Settings::RendererBackend);
185Q_DECLARE_METATYPE(Settings::ShaderBackend); 186Q_DECLARE_METATYPE(Settings::ShaderBackend);
diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp
index 096e42e94..251aab912 100644
--- a/src/yuzu/configuration/configuration_shared.cpp
+++ b/src/yuzu/configuration/configuration_shared.cpp
@@ -25,20 +25,6 @@ void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting,
25 } 25 }
26} 26}
27 27
28void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<int>* setting,
29 const QComboBox* combobox) {
30 if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
31 setting->SetValue(combobox->currentIndex());
32 } else if (!Settings::IsConfiguringGlobal()) {
33 if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
34 setting->SetGlobal(true);
35 } else {
36 setting->SetGlobal(false);
37 setting->SetValue(combobox->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET);
38 }
39 }
40}
41
42void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox, 28void ConfigurationShared::SetPerGameSetting(QCheckBox* checkbox,
43 const Settings::Setting<bool>* setting) { 29 const Settings::Setting<bool>* setting) {
44 if (setting->UsingGlobal()) { 30 if (setting->UsingGlobal()) {
diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h
index 1e0ef01ca..5423dbc92 100644
--- a/src/yuzu/configuration/configuration_shared.h
+++ b/src/yuzu/configuration/configuration_shared.h
@@ -28,7 +28,20 @@ enum class CheckState {
28// ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting 28// ApplyPerGameSetting, given a Settings::Setting and a Qt UI element, properly applies a Setting
29void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox, 29void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox,
30 const CheckState& tracker); 30 const CheckState& tracker);
31void ApplyPerGameSetting(Settings::Setting<int>* setting, const QComboBox* combobox); 31template <typename Type>
32void ApplyPerGameSetting(Settings::Setting<Type>* setting, const QComboBox* combobox) {
33 if (Settings::IsConfiguringGlobal() && setting->UsingGlobal()) {
34 setting->SetValue(static_cast<Type>(combobox->currentIndex()));
35 } else if (!Settings::IsConfiguringGlobal()) {
36 if (combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
37 setting->SetGlobal(true);
38 } else {
39 setting->SetGlobal(false);
40 setting->SetValue(static_cast<Type>(combobox->currentIndex() -
41 ConfigurationShared::USE_GLOBAL_OFFSET));
42 }
43 }
44}
32 45
33// Sets a Qt UI element given a Settings::Setting 46// Sets a Qt UI element given a Settings::Setting
34void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting); 47void SetPerGameSetting(QCheckBox* checkbox, const Settings::Setting<bool>* setting);
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp
index 8d7171487..784b6484e 100644
--- a/src/yuzu/configuration/configure_cpu.cpp
+++ b/src/yuzu/configuration/configure_cpu.cpp
@@ -65,6 +65,7 @@ void ConfigureCpu::UpdateGroup(int index) {
65} 65}
66 66
67void ConfigureCpu::ApplyConfiguration() { 67void ConfigureCpu::ApplyConfiguration() {
68 ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpu_accuracy, ui->accuracy);
68 ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_unfuse_fma, 69 ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_unfuse_fma,
69 ui->cpuopt_unsafe_unfuse_fma, 70 ui->cpuopt_unsafe_unfuse_fma,
70 cpuopt_unsafe_unfuse_fma); 71 cpuopt_unsafe_unfuse_fma);
@@ -80,22 +81,6 @@ void ConfigureCpu::ApplyConfiguration() {
80 ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_fastmem_check, 81 ConfigurationShared::ApplyPerGameSetting(&Settings::values.cpuopt_unsafe_fastmem_check,
81 ui->cpuopt_unsafe_fastmem_check, 82 ui->cpuopt_unsafe_fastmem_check,
82 cpuopt_unsafe_fastmem_check); 83 cpuopt_unsafe_fastmem_check);
83
84 if (Settings::IsConfiguringGlobal()) {
85 // Guard if during game and set to game-specific value
86 if (Settings::values.cpu_accuracy.UsingGlobal()) {
87 Settings::values.cpu_accuracy.SetValue(
88 static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex()));
89 }
90 } else {
91 if (ui->accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
92 Settings::values.cpu_accuracy.SetGlobal(true);
93 } else {
94 Settings::values.cpu_accuracy.SetGlobal(false);
95 Settings::values.cpu_accuracy.SetValue(static_cast<Settings::CPUAccuracy>(
96 ui->accuracy->currentIndex() - ConfigurationShared::USE_GLOBAL_OFFSET));
97 }
98 }
99} 84}
100 85
101void ConfigureCpu::changeEvent(QEvent* event) { 86void ConfigureCpu::changeEvent(QEvent* event) {
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index d79d2e23e..1f647a0d1 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -24,8 +24,8 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
24 SetConfiguration(); 24 SetConfiguration();
25 25
26 if (Settings::IsConfiguringGlobal()) { 26 if (Settings::IsConfiguringGlobal()) {
27 connect(ui->toggle_frame_limit, &QCheckBox::clicked, ui->frame_limit, 27 connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit,
28 [this]() { ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked()); }); 28 [this]() { ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked()); });
29 } 29 }
30 30
31 connect(ui->button_reset_defaults, &QPushButton::clicked, this, 31 connect(ui->button_reset_defaults, &QPushButton::clicked, this,
@@ -45,18 +45,18 @@ void ConfigureGeneral::SetConfiguration() {
45 ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue()); 45 ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background.GetValue());
46 ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue()); 46 ui->toggle_hide_mouse->setChecked(UISettings::values.hide_mouse.GetValue());
47 47
48 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue()); 48 ui->toggle_speed_limit->setChecked(Settings::values.use_speed_limit.GetValue());
49 ui->frame_limit->setValue(Settings::values.frame_limit.GetValue()); 49 ui->speed_limit->setValue(Settings::values.speed_limit.GetValue());
50 50
51 ui->fps_cap->setValue(Settings::values.fps_cap.GetValue()); 51 ui->fps_cap->setValue(Settings::values.fps_cap.GetValue());
52 52
53 ui->button_reset_defaults->setEnabled(runtime_lock); 53 ui->button_reset_defaults->setEnabled(runtime_lock);
54 54
55 if (Settings::IsConfiguringGlobal()) { 55 if (Settings::IsConfiguringGlobal()) {
56 ui->frame_limit->setEnabled(Settings::values.use_frame_limit.GetValue()); 56 ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue());
57 } else { 57 } else {
58 ui->frame_limit->setEnabled(Settings::values.use_frame_limit.GetValue() && 58 ui->speed_limit->setEnabled(Settings::values.use_speed_limit.GetValue() &&
59 use_frame_limit != ConfigurationShared::CheckState::Global); 59 use_speed_limit != ConfigurationShared::CheckState::Global);
60 } 60 }
61} 61}
62 62
@@ -92,19 +92,19 @@ void ConfigureGeneral::ApplyConfiguration() {
92 Settings::values.fps_cap.SetValue(ui->fps_cap->value()); 92 Settings::values.fps_cap.SetValue(ui->fps_cap->value());
93 93
94 // Guard if during game and set to game-specific value 94 // Guard if during game and set to game-specific value
95 if (Settings::values.use_frame_limit.UsingGlobal()) { 95 if (Settings::values.use_speed_limit.UsingGlobal()) {
96 Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() == 96 Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() ==
97 Qt::Checked); 97 Qt::Checked);
98 Settings::values.frame_limit.SetValue(ui->frame_limit->value()); 98 Settings::values.speed_limit.SetValue(ui->speed_limit->value());
99 } 99 }
100 } else { 100 } else {
101 bool global_frame_limit = use_frame_limit == ConfigurationShared::CheckState::Global; 101 bool global_speed_limit = use_speed_limit == ConfigurationShared::CheckState::Global;
102 Settings::values.use_frame_limit.SetGlobal(global_frame_limit); 102 Settings::values.use_speed_limit.SetGlobal(global_speed_limit);
103 Settings::values.frame_limit.SetGlobal(global_frame_limit); 103 Settings::values.speed_limit.SetGlobal(global_speed_limit);
104 if (!global_frame_limit) { 104 if (!global_speed_limit) {
105 Settings::values.use_frame_limit.SetValue(ui->toggle_frame_limit->checkState() == 105 Settings::values.use_speed_limit.SetValue(ui->toggle_speed_limit->checkState() ==
106 Qt::Checked); 106 Qt::Checked);
107 Settings::values.frame_limit.SetValue(ui->frame_limit->value()); 107 Settings::values.speed_limit.SetValue(ui->speed_limit->value());
108 } 108 }
109 } 109 }
110} 110}
@@ -126,8 +126,8 @@ void ConfigureGeneral::SetupPerGameUI() {
126 // Disables each setting if: 126 // Disables each setting if:
127 // - A game is running (thus settings in use), and 127 // - A game is running (thus settings in use), and
128 // - A non-global setting is applied. 128 // - A non-global setting is applied.
129 ui->toggle_frame_limit->setEnabled(Settings::values.use_frame_limit.UsingGlobal()); 129 ui->toggle_speed_limit->setEnabled(Settings::values.use_speed_limit.UsingGlobal());
130 ui->frame_limit->setEnabled(Settings::values.frame_limit.UsingGlobal()); 130 ui->speed_limit->setEnabled(Settings::values.speed_limit.UsingGlobal());
131 131
132 return; 132 return;
133 } 133 }
@@ -139,13 +139,13 @@ void ConfigureGeneral::SetupPerGameUI() {
139 139
140 ui->button_reset_defaults->setVisible(false); 140 ui->button_reset_defaults->setVisible(false);
141 141
142 ConfigurationShared::SetColoredTristate(ui->toggle_frame_limit, 142 ConfigurationShared::SetColoredTristate(ui->toggle_speed_limit,
143 Settings::values.use_frame_limit, use_frame_limit); 143 Settings::values.use_speed_limit, use_speed_limit);
144 ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core, 144 ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core,
145 use_multi_core); 145 use_multi_core);
146 146
147 connect(ui->toggle_frame_limit, &QCheckBox::clicked, ui->frame_limit, [this]() { 147 connect(ui->toggle_speed_limit, &QCheckBox::clicked, ui->speed_limit, [this]() {
148 ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked() && 148 ui->speed_limit->setEnabled(ui->toggle_speed_limit->isChecked() &&
149 (use_frame_limit != ConfigurationShared::CheckState::Global)); 149 (use_speed_limit != ConfigurationShared::CheckState::Global));
150 }); 150 });
151} 151}
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index a0fd52492..c9df37d73 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -43,6 +43,6 @@ private:
43 43
44 std::unique_ptr<Ui::ConfigureGeneral> ui; 44 std::unique_ptr<Ui::ConfigureGeneral> ui;
45 45
46 ConfigurationShared::CheckState use_frame_limit; 46 ConfigurationShared::CheckState use_speed_limit;
47 ConfigurationShared::CheckState use_multi_core; 47 ConfigurationShared::CheckState use_multi_core;
48}; 48};
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index bc3c4b481..8ce97edec 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -27,14 +27,14 @@
27 <item> 27 <item>
28 <layout class="QHBoxLayout" name="horizontalLayout_2"> 28 <layout class="QHBoxLayout" name="horizontalLayout_2">
29 <item> 29 <item>
30 <widget class="QCheckBox" name="toggle_frame_limit"> 30 <widget class="QCheckBox" name="toggle_speed_limit">
31 <property name="text"> 31 <property name="text">
32 <string>Limit Speed Percent</string> 32 <string>Limit Speed Percent</string>
33 </property> 33 </property>
34 </widget> 34 </widget>
35 </item> 35 </item>
36 <item> 36 <item>
37 <widget class="QSpinBox" name="frame_limit"> 37 <widget class="QSpinBox" name="speed_limit">
38 <property name="suffix"> 38 <property name="suffix">
39 <string>%</string> 39 <string>%</string>
40 </property> 40 </property>
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index fef211707..37e896258 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -31,7 +31,7 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
31 } 31 }
32 32
33 ui->backend->addItem(QStringLiteral("GLSL")); 33 ui->backend->addItem(QStringLiteral("GLSL"));
34 ui->backend->addItem(tr("GLASM (NVIDIA Only)")); 34 ui->backend->addItem(tr("GLASM (Assembly Shaders, NVIDIA Only)"));
35 ui->backend->addItem(QStringLiteral("SPIR-V (Experimental, Mesa Only)")); 35 ui->backend->addItem(QStringLiteral("SPIR-V (Experimental, Mesa Only)"));
36 36
37 SetupPerGameUI(); 37 SetupPerGameUI();
@@ -98,7 +98,8 @@ void ConfigureGraphics::SetConfiguration() {
98 98
99 if (Settings::IsConfiguringGlobal()) { 99 if (Settings::IsConfiguringGlobal()) {
100 ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue())); 100 ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue()));
101 ui->fullscreen_mode_combobox->setCurrentIndex(Settings::values.fullscreen_mode.GetValue()); 101 ui->fullscreen_mode_combobox->setCurrentIndex(
102 static_cast<int>(Settings::values.fullscreen_mode.GetValue()));
102 ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue()); 103 ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue());
103 } else { 104 } else {
104 ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend); 105 ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
@@ -310,8 +311,9 @@ void ConfigureGraphics::SetupPerGameUI() {
310 311
311 ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label, 312 ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label,
312 Settings::values.aspect_ratio.GetValue(true)); 313 Settings::values.aspect_ratio.GetValue(true));
313 ConfigurationShared::SetColoredComboBox(ui->fullscreen_mode_combobox, ui->fullscreen_mode_label, 314 ConfigurationShared::SetColoredComboBox(
314 Settings::values.fullscreen_mode.GetValue(true)); 315 ui->fullscreen_mode_combobox, ui->fullscreen_mode_label,
316 static_cast<int>(Settings::values.fullscreen_mode.GetValue(true)));
315 ConfigurationShared::InsertGlobalItem( 317 ConfigurationShared::InsertGlobalItem(
316 ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); 318 ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
317} 319}
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index 38276feb1..a31b8e192 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -48,11 +48,7 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
48} 48}
49 49
50void ConfigureGraphicsAdvanced::ApplyConfiguration() { 50void ConfigureGraphicsAdvanced::ApplyConfiguration() {
51 // Subtract 2 if configuring per-game (separator and "use global configuration" take 2 slots) 51 ConfigurationShared::ApplyPerGameSetting(&Settings::values.gpu_accuracy, ui->gpu_accuracy);
52 const auto gpu_accuracy = static_cast<Settings::GPUAccuracy>(
53 ui->gpu_accuracy->currentIndex() -
54 ((Settings::IsConfiguringGlobal()) ? 0 : ConfigurationShared::USE_GLOBAL_OFFSET));
55
56 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, 52 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
57 ui->anisotropic_filtering_combobox); 53 ui->anisotropic_filtering_combobox);
58 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync); 54 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync, use_vsync);
@@ -63,20 +59,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
63 use_caches_gc); 59 use_caches_gc);
64 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time, 60 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
65 ui->use_fast_gpu_time, use_fast_gpu_time); 61 ui->use_fast_gpu_time, use_fast_gpu_time);
66
67 if (Settings::IsConfiguringGlobal()) {
68 // Must guard in case of a during-game configuration when set to be game-specific.
69 if (Settings::values.gpu_accuracy.UsingGlobal()) {
70 Settings::values.gpu_accuracy.SetValue(gpu_accuracy);
71 }
72 } else {
73 if (ui->gpu_accuracy->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
74 Settings::values.gpu_accuracy.SetGlobal(true);
75 } else {
76 Settings::values.gpu_accuracy.SetGlobal(false);
77 Settings::values.gpu_accuracy.SetValue(gpu_accuracy);
78 }
79 }
80} 62}
81 63
82void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) { 64void ConfigureGraphicsAdvanced::changeEvent(QEvent* event) {
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 3d747e8d9..9544f0fb0 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -972,23 +972,23 @@ void GMainWindow::InitializeHotkeys() {
972 }); 972 });
973 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Speed Limit"), this), 973 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Speed Limit"), this),
974 &QShortcut::activated, this, [&] { 974 &QShortcut::activated, this, [&] {
975 Settings::values.use_frame_limit.SetValue( 975 Settings::values.use_speed_limit.SetValue(
976 !Settings::values.use_frame_limit.GetValue()); 976 !Settings::values.use_speed_limit.GetValue());
977 UpdateStatusBar(); 977 UpdateStatusBar();
978 }); 978 });
979 constexpr u16 SPEED_LIMIT_STEP = 5; 979 constexpr u16 SPEED_LIMIT_STEP = 5;
980 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this), 980 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this),
981 &QShortcut::activated, this, [&] { 981 &QShortcut::activated, this, [&] {
982 if (Settings::values.frame_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) { 982 if (Settings::values.speed_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) {
983 Settings::values.frame_limit.SetValue(SPEED_LIMIT_STEP + 983 Settings::values.speed_limit.SetValue(SPEED_LIMIT_STEP +
984 Settings::values.frame_limit.GetValue()); 984 Settings::values.speed_limit.GetValue());
985 UpdateStatusBar(); 985 UpdateStatusBar();
986 } 986 }
987 }); 987 });
988 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this), 988 connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this),
989 &QShortcut::activated, this, [&] { 989 &QShortcut::activated, this, [&] {
990 if (Settings::values.frame_limit.GetValue() > SPEED_LIMIT_STEP) { 990 if (Settings::values.speed_limit.GetValue() > SPEED_LIMIT_STEP) {
991 Settings::values.frame_limit.SetValue(Settings::values.frame_limit.GetValue() - 991 Settings::values.speed_limit.SetValue(Settings::values.speed_limit.GetValue() -
992 SPEED_LIMIT_STEP); 992 SPEED_LIMIT_STEP);
993 UpdateStatusBar(); 993 UpdateStatusBar();
994 } 994 }
@@ -2513,7 +2513,7 @@ void GMainWindow::ShowFullscreen() {
2513 ui.menubar->hide(); 2513 ui.menubar->hide();
2514 statusBar()->hide(); 2514 statusBar()->hide();
2515 2515
2516 if (Settings::values.fullscreen_mode.GetValue() == 1) { 2516 if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
2517 showFullScreen(); 2517 showFullScreen();
2518 return; 2518 return;
2519 } 2519 }
@@ -2528,7 +2528,7 @@ void GMainWindow::ShowFullscreen() {
2528 } else { 2528 } else {
2529 UISettings::values.renderwindow_geometry = render_window->saveGeometry(); 2529 UISettings::values.renderwindow_geometry = render_window->saveGeometry();
2530 2530
2531 if (Settings::values.fullscreen_mode.GetValue() == 1) { 2531 if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
2532 render_window->showFullScreen(); 2532 render_window->showFullScreen();
2533 return; 2533 return;
2534 } 2534 }
@@ -2545,7 +2545,7 @@ void GMainWindow::ShowFullscreen() {
2545 2545
2546void GMainWindow::HideFullscreen() { 2546void GMainWindow::HideFullscreen() {
2547 if (ui.action_Single_Window_Mode->isChecked()) { 2547 if (ui.action_Single_Window_Mode->isChecked()) {
2548 if (Settings::values.fullscreen_mode.GetValue() == 1) { 2548 if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
2549 showNormal(); 2549 showNormal();
2550 restoreGeometry(UISettings::values.geometry); 2550 restoreGeometry(UISettings::values.geometry);
2551 } else { 2551 } else {
@@ -2559,7 +2559,7 @@ void GMainWindow::HideFullscreen() {
2559 statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); 2559 statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
2560 ui.menubar->show(); 2560 ui.menubar->show();
2561 } else { 2561 } else {
2562 if (Settings::values.fullscreen_mode.GetValue() == 1) { 2562 if (Settings::values.fullscreen_mode.GetValue() == Settings::FullscreenMode::Exclusive) {
2563 render_window->showNormal(); 2563 render_window->showNormal();
2564 render_window->restoreGeometry(UISettings::values.renderwindow_geometry); 2564 render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
2565 } else { 2565 } else {
@@ -2910,10 +2910,10 @@ void GMainWindow::UpdateStatusBar() {
2910 shader_building_label->setVisible(false); 2910 shader_building_label->setVisible(false);
2911 } 2911 }
2912 2912
2913 if (Settings::values.use_frame_limit.GetValue()) { 2913 if (Settings::values.use_speed_limit.GetValue()) {
2914 emu_speed_label->setText(tr("Speed: %1% / %2%") 2914 emu_speed_label->setText(tr("Speed: %1% / %2%")
2915 .arg(results.emulation_speed * 100.0, 0, 'f', 0) 2915 .arg(results.emulation_speed * 100.0, 0, 'f', 0)
2916 .arg(Settings::values.frame_limit.GetValue())); 2916 .arg(Settings::values.speed_limit.GetValue()));
2917 } else { 2917 } else {
2918 emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0)); 2918 emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
2919 } 2919 }
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index d4ca6bb57..5af1ee6a8 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -451,8 +451,8 @@ void Config::ReadValues() {
451 ReadSetting("Renderer", Settings::values.fullscreen_mode); 451 ReadSetting("Renderer", Settings::values.fullscreen_mode);
452 ReadSetting("Renderer", Settings::values.aspect_ratio); 452 ReadSetting("Renderer", Settings::values.aspect_ratio);
453 ReadSetting("Renderer", Settings::values.max_anisotropy); 453 ReadSetting("Renderer", Settings::values.max_anisotropy);
454 ReadSetting("Renderer", Settings::values.use_frame_limit); 454 ReadSetting("Renderer", Settings::values.use_speed_limit);
455 ReadSetting("Renderer", Settings::values.frame_limit); 455 ReadSetting("Renderer", Settings::values.speed_limit);
456 ReadSetting("Renderer", Settings::values.use_disk_shader_cache); 456 ReadSetting("Renderer", Settings::values.use_disk_shader_cache);
457 ReadSetting("Renderer", Settings::values.gpu_accuracy); 457 ReadSetting("Renderer", Settings::values.gpu_accuracy);
458 ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation); 458 ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation);
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index b2b2095d1..e646e2d2f 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -265,13 +265,13 @@ use_nvdec_emulation =
265# 0: Off, 1 (default): On 265# 0: Off, 1 (default): On
266accelerate_astc = 266accelerate_astc =
267 267
268# Turns on the frame limiter, which will limit frames output to the target game speed 268# Turns on the speed limiter, which will limit the emulation speed to the desired speed limit value
269# 0: Off, 1: On (default) 269# 0: Off, 1: On (default)
270use_frame_limit = 270use_speed_limit =
271 271
272# Limits the speed of the game to run no faster than this value as a percentage of target speed 272# Limits the speed of the game to run no faster than this value as a percentage of target speed
273# 1 - 9999: Speed limit as a percentage of target game speed. 100 (default) 273# 1 - 9999: Speed limit as a percentage of target game speed. 100 (default)
274frame_limit = 274speed_limit =
275 275
276# Whether to use disk based shader cache 276# Whether to use disk based shader cache
277# 0: Off, 1 (default): On 277# 0: Off, 1 (default): On
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 353e51ea7..ea3e0ada4 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -124,7 +124,7 @@ void EmuWindow_SDL2::OnResize() {
124 124
125void EmuWindow_SDL2::Fullscreen() { 125void EmuWindow_SDL2::Fullscreen() {
126 switch (Settings::values.fullscreen_mode.GetValue()) { 126 switch (Settings::values.fullscreen_mode.GetValue()) {
127 case 1: // Exclusive fullscreen 127 case Settings::FullscreenMode::Exclusive:
128 // Set window size to render size before entering fullscreen -- SDL does not resize to 128 // Set window size to render size before entering fullscreen -- SDL does not resize to
129 // display dimensions in this mode. 129 // display dimensions in this mode.
130 // TODO: Multiply the window size by resolution_factor (for both docked modes) 130 // TODO: Multiply the window size by resolution_factor (for both docked modes)
@@ -140,7 +140,7 @@ void EmuWindow_SDL2::Fullscreen() {
140 LOG_ERROR(Frontend, "Fullscreening failed: {}", SDL_GetError()); 140 LOG_ERROR(Frontend, "Fullscreening failed: {}", SDL_GetError());
141 LOG_INFO(Frontend, "Attempting to use borderless fullscreen..."); 141 LOG_INFO(Frontend, "Attempting to use borderless fullscreen...");
142 [[fallthrough]]; 142 [[fallthrough]];
143 case 0: // Borderless window 143 case Settings::FullscreenMode::Borderless:
144 if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) { 144 if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) {
145 return; 145 return;
146 } 146 }