summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/CMakeLists.txt6
-rw-r--r--src/common/stb.cpp8
-rw-r--r--src/common/stb.h8
-rw-r--r--src/common/thread.cpp24
-rw-r--r--src/core/file_sys/system_archive/system_version.cpp4
-rw-r--r--src/core/hle/service/caps/caps.cpp7
-rw-r--r--src/core/hle/service/caps/caps_manager.cpp87
-rw-r--r--src/core/hle/service/caps/caps_manager.h11
-rw-r--r--src/core/hle/service/caps/caps_ss.cpp75
-rw-r--r--src/core/hle/service/caps/caps_ss.h8
-rw-r--r--src/core/hle/service/caps/caps_su.cpp69
-rw-r--r--src/core/hle/service/caps/caps_su.h8
-rw-r--r--src/core/hle/service/caps/caps_types.h2
-rw-r--r--src/core/hle/service/hle_ipc.cpp6
-rw-r--r--src/core/hle/service/ptm/ts.cpp40
-rw-r--r--src/core/hle/service/ptm/ts.h6
-rw-r--r--src/core/hle/service/set/set_sys.cpp49
-rw-r--r--src/core/memory/cheat_engine.cpp23
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl.cpp1
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp12
-rw-r--r--src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp23
-rw-r--r--src/shader_recompiler/backend/spirv/spirv_emit_context.h36
-rw-r--r--src/shader_recompiler/profile.h4
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp6
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp35
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h18
-rw-r--r--src/video_core/vulkan_common/vulkan_wrapper.cpp2
-rw-r--r--src/yuzu/configuration/config.cpp3
-rw-r--r--src/yuzu/configuration/config.h2
-rw-r--r--src/yuzu/configuration/configure_hotkeys.cpp7
-rw-r--r--src/yuzu/configuration/configure_vibration.cpp10
31 files changed, 493 insertions, 107 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 8a1861051..e216eb3de 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -120,6 +120,8 @@ add_library(common STATIC
120 socket_types.h 120 socket_types.h
121 spin_lock.cpp 121 spin_lock.cpp
122 spin_lock.h 122 spin_lock.h
123 stb.cpp
124 stb.h
123 steady_clock.cpp 125 steady_clock.cpp
124 steady_clock.h 126 steady_clock.h
125 stream.cpp 127 stream.cpp
@@ -208,6 +210,8 @@ if (MSVC)
208 /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data 210 /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
209 /we4800 # Implicit conversion from 'type' to bool. Possible information loss 211 /we4800 # Implicit conversion from 'type' to bool. Possible information loss
210 ) 212 )
213else()
214 set_source_files_properties(stb.cpp PROPERTIES COMPILE_OPTIONS "-Wno-implicit-fallthrough;-Wno-missing-declarations;-Wno-missing-field-initializers")
211endif() 215endif()
212 216
213if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") 217if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
@@ -223,7 +227,7 @@ endif()
223 227
224create_target_directory_groups(common) 228create_target_directory_groups(common)
225 229
226target_link_libraries(common PUBLIC Boost::context Boost::headers fmt::fmt microprofile Threads::Threads) 230target_link_libraries(common PUBLIC Boost::context Boost::headers fmt::fmt microprofile stb::headers Threads::Threads)
227target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd LLVM::Demangle) 231target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd LLVM::Demangle)
228 232
229if (ANDROID) 233if (ANDROID)
diff --git a/src/common/stb.cpp b/src/common/stb.cpp
new file mode 100644
index 000000000..d3b16665d
--- /dev/null
+++ b/src/common/stb.cpp
@@ -0,0 +1,8 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#define STB_IMAGE_IMPLEMENTATION
5#define STB_IMAGE_RESIZE_IMPLEMENTATION
6#define STB_IMAGE_WRITE_IMPLEMENTATION
7
8#include "common/stb.h"
diff --git a/src/common/stb.h b/src/common/stb.h
new file mode 100644
index 000000000..e5c197c11
--- /dev/null
+++ b/src/common/stb.h
@@ -0,0 +1,8 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <stb_image.h>
7#include <stb_image_resize.h>
8#include <stb_image_write.h>
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 919e33af9..34cc1527b 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -11,6 +11,7 @@
11#include <mach/mach.h> 11#include <mach/mach.h>
12#elif defined(_WIN32) 12#elif defined(_WIN32)
13#include <windows.h> 13#include <windows.h>
14#include "common/string_util.h"
14#else 15#else
15#if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) 16#if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
16#include <pthread_np.h> 17#include <pthread_np.h>
@@ -82,29 +83,8 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
82#ifdef _MSC_VER 83#ifdef _MSC_VER
83 84
84// Sets the debugger-visible name of the current thread. 85// Sets the debugger-visible name of the current thread.
85// Uses trick documented in:
86// https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code
87void SetCurrentThreadName(const char* name) { 86void SetCurrentThreadName(const char* name) {
88 static const DWORD MS_VC_EXCEPTION = 0x406D1388; 87 SetThreadDescription(GetCurrentThread(), UTF8ToUTF16W(name).data());
89
90#pragma pack(push, 8)
91 struct THREADNAME_INFO {
92 DWORD dwType; // must be 0x1000
93 LPCSTR szName; // pointer to name (in user addr space)
94 DWORD dwThreadID; // thread ID (-1=caller thread)
95 DWORD dwFlags; // reserved for future use, must be zero
96 } info;
97#pragma pack(pop)
98
99 info.dwType = 0x1000;
100 info.szName = name;
101 info.dwThreadID = std::numeric_limits<DWORD>::max();
102 info.dwFlags = 0;
103
104 __try {
105 RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
106 } __except (EXCEPTION_CONTINUE_EXECUTION) {
107 }
108} 88}
109 89
110#else // !MSVC_VER, so must be POSIX threads 90#else // !MSVC_VER, so must be POSIX threads
diff --git a/src/core/file_sys/system_archive/system_version.cpp b/src/core/file_sys/system_archive/system_version.cpp
index bd493ecca..e4751c2b4 100644
--- a/src/core/file_sys/system_archive/system_version.cpp
+++ b/src/core/file_sys/system_archive/system_version.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/logging/log.h"
4#include "core/file_sys/system_archive/system_version.h" 5#include "core/file_sys/system_archive/system_version.h"
5#include "core/file_sys/vfs_vector.h" 6#include "core/file_sys/vfs_vector.h"
6#include "core/hle/api_version.h" 7#include "core/hle/api_version.h"
@@ -12,6 +13,9 @@ std::string GetLongDisplayVersion() {
12} 13}
13 14
14VirtualDir SystemVersion() { 15VirtualDir SystemVersion() {
16 LOG_WARNING(Common_Filesystem, "called - Using hardcoded firmware version '{}'",
17 GetLongDisplayVersion());
18
15 VirtualFile file = std::make_shared<VectorVfsFile>(std::vector<u8>(0x100), "file"); 19 VirtualFile file = std::make_shared<VectorVfsFile>(std::vector<u8>(0x100), "file");
16 file->WriteObject(HLE::ApiVersion::HOS_VERSION_MAJOR, 0); 20 file->WriteObject(HLE::ApiVersion::HOS_VERSION_MAJOR, 0);
17 file->WriteObject(HLE::ApiVersion::HOS_VERSION_MINOR, 1); 21 file->WriteObject(HLE::ApiVersion::HOS_VERSION_MINOR, 1);
diff --git a/src/core/hle/service/caps/caps.cpp b/src/core/hle/service/caps/caps.cpp
index 31dd98140..cd1dfe993 100644
--- a/src/core/hle/service/caps/caps.cpp
+++ b/src/core/hle/service/caps/caps.cpp
@@ -25,11 +25,12 @@ void LoopProcess(Core::System& system) {
25 server_manager->RegisterNamedService( 25 server_manager->RegisterNamedService(
26 "caps:u", std::make_shared<IAlbumApplicationService>(system, album_manager)); 26 "caps:u", std::make_shared<IAlbumApplicationService>(system, album_manager));
27 27
28 server_manager->RegisterNamedService("caps:ss", std::make_shared<IScreenShotService>(system)); 28 server_manager->RegisterNamedService(
29 "caps:ss", std::make_shared<IScreenShotService>(system, album_manager));
29 server_manager->RegisterNamedService("caps:sc", 30 server_manager->RegisterNamedService("caps:sc",
30 std::make_shared<IScreenShotControlService>(system)); 31 std::make_shared<IScreenShotControlService>(system));
31 server_manager->RegisterNamedService("caps:su", 32 server_manager->RegisterNamedService(
32 std::make_shared<IScreenShotApplicationService>(system)); 33 "caps:su", std::make_shared<IScreenShotApplicationService>(system, album_manager));
33 34
34 ServerManager::RunServer(std::move(server_manager)); 35 ServerManager::RunServer(std::move(server_manager));
35} 36}
diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp
index 2b4e3f076..7d733eb54 100644
--- a/src/core/hle/service/caps/caps_manager.cpp
+++ b/src/core/hle/service/caps/caps_manager.cpp
@@ -2,12 +2,11 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <sstream> 4#include <sstream>
5#include <stb_image.h>
6#include <stb_image_resize.h>
7 5
8#include "common/fs/file.h" 6#include "common/fs/file.h"
9#include "common/fs/path_util.h" 7#include "common/fs/path_util.h"
10#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "common/stb.h"
11#include "core/core.h" 10#include "core/core.h"
12#include "core/hle/service/caps/caps_manager.h" 11#include "core/hle/service/caps/caps_manager.h"
13#include "core/hle/service/caps/caps_result.h" 12#include "core/hle/service/caps/caps_result.h"
@@ -227,6 +226,49 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail(
227 +static_cast<int>(out_image_output.height), decoder_options.flags); 226 +static_cast<int>(out_image_output.height), decoder_options.flags);
228} 227}
229 228
229Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
230 const ScreenShotAttribute& attribute,
231 std::span<const u8> image_data, u64 aruid) {
232 return SaveScreenShot(out_entry, attribute, {}, image_data, aruid);
233}
234
235Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry,
236 const ScreenShotAttribute& attribute,
237 const ApplicationData& app_data, std::span<const u8> image_data,
238 u64 aruid) {
239 const u64 title_id = system.GetApplicationProcessProgramID();
240 const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore();
241
242 s64 posix_time{};
243 Result result = user_clock.GetCurrentTime(system, posix_time);
244
245 if (result.IsError()) {
246 return result;
247 }
248
249 const auto date = ConvertToAlbumDateTime(posix_time);
250
251 return SaveImage(out_entry, image_data, title_id, date);
252}
253
254Result AlbumManager::SaveEditedScreenShot(ApplicationAlbumEntry& out_entry,
255 const ScreenShotAttribute& attribute,
256 const AlbumFileId& file_id,
257 std::span<const u8> image_data) {
258 const auto& user_clock = system.GetTimeManager().GetStandardUserSystemClockCore();
259
260 s64 posix_time{};
261 Result result = user_clock.GetCurrentTime(system, posix_time);
262
263 if (result.IsError()) {
264 return result;
265 }
266
267 const auto date = ConvertToAlbumDateTime(posix_time);
268
269 return SaveImage(out_entry, image_data, file_id.application_id, date);
270}
271
230Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const { 272Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const {
231 const auto file = album_files.find(file_id); 273 const auto file = album_files.find(file_id);
232 274
@@ -365,6 +407,47 @@ Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::p
365 return ResultSuccess; 407 return ResultSuccess;
366} 408}
367 409
410static void PNGToMemory(void* context, void* png, int len) {
411 std::vector<u8>* png_image = static_cast<std::vector<u8>*>(context);
412 png_image->reserve(len);
413 std::memcpy(png_image->data(), png, len);
414}
415
416Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image,
417 u64 title_id, const AlbumFileDateTime& date) const {
418 const auto screenshot_path =
419 Common::FS::GetYuzuPathString(Common::FS::YuzuPath::ScreenshotsDir);
420 const std::string formatted_date =
421 fmt::format("{:04}-{:02}-{:02}_{:02}-{:02}-{:02}-{:03}", date.year, date.month, date.day,
422 date.hour, date.minute, date.second, 0);
423 const std::string file_path =
424 fmt::format("{}/{:016x}_{}.png", screenshot_path, title_id, formatted_date);
425
426 const Common::FS::IOFile db_file{file_path, Common::FS::FileAccessMode::Write,
427 Common::FS::FileType::BinaryFile};
428
429 std::vector<u8> png_image;
430 if (!stbi_write_png_to_func(PNGToMemory, &png_image, 1280, 720, STBI_rgb_alpha, image.data(),
431 0)) {
432 return ResultFileCountLimit;
433 }
434
435 if (db_file.Write(png_image) != png_image.size()) {
436 return ResultFileCountLimit;
437 }
438
439 out_entry = {
440 .size = png_image.size(),
441 .hash = {},
442 .datetime = date,
443 .storage = AlbumStorage::Sd,
444 .content = ContentType::Screenshot,
445 .unknown = 1,
446 };
447
448 return ResultSuccess;
449}
450
368AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const { 451AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const {
369 Time::TimeZone::CalendarInfo calendar_date{}; 452 Time::TimeZone::CalendarInfo calendar_date{};
370 const auto& time_zone_manager = 453 const auto& time_zone_manager =
diff --git a/src/core/hle/service/caps/caps_manager.h b/src/core/hle/service/caps/caps_manager.h
index f65eb12c1..44d85117f 100644
--- a/src/core/hle/service/caps/caps_manager.h
+++ b/src/core/hle/service/caps/caps_manager.h
@@ -58,6 +58,15 @@ public:
58 std::vector<u8>& out_image, const AlbumFileId& file_id, 58 std::vector<u8>& out_image, const AlbumFileId& file_id,
59 const ScreenShotDecodeOption& decoder_options) const; 59 const ScreenShotDecodeOption& decoder_options) const;
60 60
61 Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute,
62 std::span<const u8> image_data, u64 aruid);
63 Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute,
64 const ApplicationData& app_data, std::span<const u8> image_data,
65 u64 aruid);
66 Result SaveEditedScreenShot(ApplicationAlbumEntry& out_entry,
67 const ScreenShotAttribute& attribute, const AlbumFileId& file_id,
68 std::span<const u8> image_data);
69
61private: 70private:
62 static constexpr std::size_t NandAlbumFileLimit = 1000; 71 static constexpr std::size_t NandAlbumFileLimit = 1000;
63 static constexpr std::size_t SdAlbumFileLimit = 10000; 72 static constexpr std::size_t SdAlbumFileLimit = 10000;
@@ -67,6 +76,8 @@ private:
67 Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const; 76 Result GetAlbumEntry(AlbumEntry& out_entry, const std::filesystem::path& path) const;
68 Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width, 77 Result LoadImage(std::span<u8> out_image, const std::filesystem::path& path, int width,
69 int height, ScreenShotDecoderFlag flag) const; 78 int height, ScreenShotDecoderFlag flag) const;
79 Result SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image, u64 title_id,
80 const AlbumFileDateTime& date) const;
70 81
71 AlbumFileDateTime ConvertToAlbumDateTime(u64 posix_time) const; 82 AlbumFileDateTime ConvertToAlbumDateTime(u64 posix_time) const;
72 83
diff --git a/src/core/hle/service/caps/caps_ss.cpp b/src/core/hle/service/caps/caps_ss.cpp
index d0d1b5425..1ba2b7972 100644
--- a/src/core/hle/service/caps/caps_ss.cpp
+++ b/src/core/hle/service/caps/caps_ss.cpp
@@ -1,19 +1,25 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/logging/log.h"
5#include "core/hle/service/caps/caps_manager.h"
6#include "core/hle/service/caps/caps_types.h"
7#include "core/hle/service/ipc_helpers.h"
8
4#include "core/hle/service/caps/caps_ss.h" 9#include "core/hle/service/caps/caps_ss.h"
5 10
6namespace Service::Capture { 11namespace Service::Capture {
7 12
8IScreenShotService::IScreenShotService(Core::System& system_) 13IScreenShotService::IScreenShotService(Core::System& system_,
9 : ServiceFramework{system_, "caps:ss"} { 14 std::shared_ptr<AlbumManager> album_manager)
15 : ServiceFramework{system_, "caps:ss"}, manager{album_manager} {
10 // clang-format off 16 // clang-format off
11 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
12 {201, nullptr, "SaveScreenShot"}, 18 {201, nullptr, "SaveScreenShot"},
13 {202, nullptr, "SaveEditedScreenShot"}, 19 {202, nullptr, "SaveEditedScreenShot"},
14 {203, nullptr, "SaveScreenShotEx0"}, 20 {203, &IScreenShotService::SaveScreenShotEx0, "SaveScreenShotEx0"},
15 {204, nullptr, "SaveEditedScreenShotEx0"}, 21 {204, nullptr, "SaveEditedScreenShotEx0"},
16 {206, nullptr, "Unknown206"}, 22 {206, &IScreenShotService::SaveEditedScreenShotEx1, "SaveEditedScreenShotEx1"},
17 {208, nullptr, "SaveScreenShotOfMovieEx1"}, 23 {208, nullptr, "SaveScreenShotOfMovieEx1"},
18 {1000, nullptr, "Unknown1000"}, 24 {1000, nullptr, "Unknown1000"},
19 }; 25 };
@@ -24,4 +30,65 @@ IScreenShotService::IScreenShotService(Core::System& system_)
24 30
25IScreenShotService::~IScreenShotService() = default; 31IScreenShotService::~IScreenShotService() = default;
26 32
33void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) {
34 IPC::RequestParser rp{ctx};
35 struct Parameters {
36 ScreenShotAttribute attribute{};
37 u32 report_option{};
38 INSERT_PADDING_BYTES(0x4);
39 u64 applet_resource_user_id{};
40 };
41 static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
42
43 const auto parameters{rp.PopRaw<Parameters>()};
44 const auto image_data_buffer = ctx.ReadBuffer();
45
46 LOG_INFO(Service_Capture,
47 "called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
48 parameters.report_option, image_data_buffer.size(),
49 parameters.applet_resource_user_id);
50
51 ApplicationAlbumEntry entry{};
52 const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer,
53 parameters.applet_resource_user_id);
54
55 IPC::ResponseBuilder rb{ctx, 10};
56 rb.Push(result);
57 rb.PushRaw(entry);
58}
59void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) {
60 IPC::RequestParser rp{ctx};
61 struct Parameters {
62 ScreenShotAttribute attribute;
63 u64 width;
64 u64 height;
65 u64 thumbnail_width;
66 u64 thumbnail_height;
67 AlbumFileId file_id;
68 };
69 static_assert(sizeof(Parameters) == 0x78, "Parameters has incorrect size.");
70
71 const auto parameters{rp.PopRaw<Parameters>()};
72 const auto application_data_buffer = ctx.ReadBuffer(0);
73 const auto image_data_buffer = ctx.ReadBuffer(1);
74 const auto thumbnail_image_data_buffer = ctx.ReadBuffer(2);
75
76 LOG_INFO(Service_Capture,
77 "called, width={}, height={}, thumbnail_width={}, thumbnail_height={}, "
78 "application_id={:016x}, storage={}, type={}, app_data_buffer_size={}, "
79 "image_data_buffer_size={}, thumbnail_image_buffer_size={}",
80 parameters.width, parameters.height, parameters.thumbnail_width,
81 parameters.thumbnail_height, parameters.file_id.application_id,
82 parameters.file_id.storage, parameters.file_id.type, application_data_buffer.size(),
83 image_data_buffer.size(), thumbnail_image_data_buffer.size());
84
85 ApplicationAlbumEntry entry{};
86 const auto result = manager->SaveEditedScreenShot(entry, parameters.attribute,
87 parameters.file_id, image_data_buffer);
88
89 IPC::ResponseBuilder rb{ctx, 10};
90 rb.Push(result);
91 rb.PushRaw(entry);
92}
93
27} // namespace Service::Capture 94} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_ss.h b/src/core/hle/service/caps/caps_ss.h
index 381e44fd4..a7e9972ab 100644
--- a/src/core/hle/service/caps/caps_ss.h
+++ b/src/core/hle/service/caps/caps_ss.h
@@ -13,8 +13,14 @@ namespace Service::Capture {
13 13
14class IScreenShotService final : public ServiceFramework<IScreenShotService> { 14class IScreenShotService final : public ServiceFramework<IScreenShotService> {
15public: 15public:
16 explicit IScreenShotService(Core::System& system_); 16 explicit IScreenShotService(Core::System& system_, std::shared_ptr<AlbumManager> album_manager);
17 ~IScreenShotService() override; 17 ~IScreenShotService() override;
18
19private:
20 void SaveScreenShotEx0(HLERequestContext& ctx);
21 void SaveEditedScreenShotEx1(HLERequestContext& ctx);
22
23 std::shared_ptr<AlbumManager> manager;
18}; 24};
19 25
20} // namespace Service::Capture 26} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp
index cad173dc7..e85625ee4 100644
--- a/src/core/hle/service/caps/caps_su.cpp
+++ b/src/core/hle/service/caps/caps_su.cpp
@@ -2,19 +2,22 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/logging/log.h" 4#include "common/logging/log.h"
5#include "core/hle/service/caps/caps_manager.h"
5#include "core/hle/service/caps/caps_su.h" 6#include "core/hle/service/caps/caps_su.h"
7#include "core/hle/service/caps/caps_types.h"
6#include "core/hle/service/ipc_helpers.h" 8#include "core/hle/service/ipc_helpers.h"
7 9
8namespace Service::Capture { 10namespace Service::Capture {
9 11
10IScreenShotApplicationService::IScreenShotApplicationService(Core::System& system_) 12IScreenShotApplicationService::IScreenShotApplicationService(
11 : ServiceFramework{system_, "caps:su"} { 13 Core::System& system_, std::shared_ptr<AlbumManager> album_manager)
14 : ServiceFramework{system_, "caps:su"}, manager{album_manager} {
12 // clang-format off 15 // clang-format off
13 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
14 {32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"}, 17 {32, &IScreenShotApplicationService::SetShimLibraryVersion, "SetShimLibraryVersion"},
15 {201, nullptr, "SaveScreenShot"}, 18 {201, nullptr, "SaveScreenShot"},
16 {203, nullptr, "SaveScreenShotEx0"}, 19 {203, &IScreenShotApplicationService::SaveScreenShotEx0, "SaveScreenShotEx0"},
17 {205, nullptr, "SaveScreenShotEx1"}, 20 {205, &IScreenShotApplicationService::SaveScreenShotEx1, "SaveScreenShotEx1"},
18 {210, nullptr, "SaveScreenShotEx2"}, 21 {210, nullptr, "SaveScreenShotEx2"},
19 }; 22 };
20 // clang-format on 23 // clang-format on
@@ -36,4 +39,62 @@ void IScreenShotApplicationService::SetShimLibraryVersion(HLERequestContext& ctx
36 rb.Push(ResultSuccess); 39 rb.Push(ResultSuccess);
37} 40}
38 41
42void IScreenShotApplicationService::SaveScreenShotEx0(HLERequestContext& ctx) {
43 IPC::RequestParser rp{ctx};
44 struct Parameters {
45 ScreenShotAttribute attribute{};
46 AlbumReportOption report_option{};
47 INSERT_PADDING_BYTES(0x4);
48 u64 applet_resource_user_id{};
49 };
50 static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
51
52 const auto parameters{rp.PopRaw<Parameters>()};
53 const auto image_data_buffer = ctx.ReadBuffer();
54
55 LOG_INFO(Service_Capture,
56 "called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
57 parameters.report_option, image_data_buffer.size(),
58 parameters.applet_resource_user_id);
59
60 ApplicationAlbumEntry entry{};
61 const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer,
62 parameters.applet_resource_user_id);
63
64 IPC::ResponseBuilder rb{ctx, 10};
65 rb.Push(result);
66 rb.PushRaw(entry);
67}
68
69void IScreenShotApplicationService::SaveScreenShotEx1(HLERequestContext& ctx) {
70 IPC::RequestParser rp{ctx};
71 struct Parameters {
72 ScreenShotAttribute attribute{};
73 AlbumReportOption report_option{};
74 INSERT_PADDING_BYTES(0x4);
75 u64 applet_resource_user_id{};
76 };
77 static_assert(sizeof(Parameters) == 0x50, "Parameters has incorrect size.");
78
79 const auto parameters{rp.PopRaw<Parameters>()};
80 const auto app_data_buffer = ctx.ReadBuffer(0);
81 const auto image_data_buffer = ctx.ReadBuffer(1);
82
83 LOG_INFO(Service_Capture,
84 "called, report_option={}, image_data_buffer_size={}, applet_resource_user_id={}",
85 parameters.report_option, image_data_buffer.size(),
86 parameters.applet_resource_user_id);
87
88 ApplicationAlbumEntry entry{};
89 ApplicationData app_data{};
90 std::memcpy(&app_data, app_data_buffer.data(), sizeof(ApplicationData));
91 const auto result =
92 manager->SaveScreenShot(entry, parameters.attribute, app_data, image_data_buffer,
93 parameters.applet_resource_user_id);
94
95 IPC::ResponseBuilder rb{ctx, 10};
96 rb.Push(result);
97 rb.PushRaw(entry);
98}
99
39} // namespace Service::Capture 100} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_su.h b/src/core/hle/service/caps/caps_su.h
index 647e3059d..89e71f506 100644
--- a/src/core/hle/service/caps/caps_su.h
+++ b/src/core/hle/service/caps/caps_su.h
@@ -10,14 +10,20 @@ class System;
10} 10}
11 11
12namespace Service::Capture { 12namespace Service::Capture {
13class AlbumManager;
13 14
14class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> { 15class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> {
15public: 16public:
16 explicit IScreenShotApplicationService(Core::System& system_); 17 explicit IScreenShotApplicationService(Core::System& system_,
18 std::shared_ptr<AlbumManager> album_manager);
17 ~IScreenShotApplicationService() override; 19 ~IScreenShotApplicationService() override;
18 20
19private: 21private:
20 void SetShimLibraryVersion(HLERequestContext& ctx); 22 void SetShimLibraryVersion(HLERequestContext& ctx);
23 void SaveScreenShotEx0(HLERequestContext& ctx);
24 void SaveScreenShotEx1(HLERequestContext& ctx);
25
26 std::shared_ptr<AlbumManager> manager;
21}; 27};
22 28
23} // namespace Service::Capture 29} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_types.h b/src/core/hle/service/caps/caps_types.h
index 7fd357954..589ac28d3 100644
--- a/src/core/hle/service/caps/caps_types.h
+++ b/src/core/hle/service/caps/caps_types.h
@@ -20,6 +20,8 @@ enum class AlbumImageOrientation {
20enum class AlbumReportOption : s32 { 20enum class AlbumReportOption : s32 {
21 Disable, 21 Disable,
22 Enable, 22 Enable,
23 Unknown2,
24 Unknown3,
23}; 25};
24 26
25enum class ContentType : u8 { 27enum class ContentType : u8 {
diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp
index 6f3ae3cc4..ff374ae39 100644
--- a/src/core/hle/service/hle_ipc.cpp
+++ b/src/core/hle/service/hle_ipc.cpp
@@ -27,10 +27,12 @@ namespace {
27static thread_local std::array read_buffer_data_a{ 27static thread_local std::array read_buffer_data_a{
28 Common::ScratchBuffer<u8>(), 28 Common::ScratchBuffer<u8>(),
29 Common::ScratchBuffer<u8>(), 29 Common::ScratchBuffer<u8>(),
30 Common::ScratchBuffer<u8>(),
30}; 31};
31static thread_local std::array read_buffer_data_x{ 32static thread_local std::array read_buffer_data_x{
32 Common::ScratchBuffer<u8>(), 33 Common::ScratchBuffer<u8>(),
33 Common::ScratchBuffer<u8>(), 34 Common::ScratchBuffer<u8>(),
35 Common::ScratchBuffer<u8>(),
34}; 36};
35} // Anonymous namespace 37} // Anonymous namespace
36 38
@@ -343,6 +345,7 @@ std::span<const u8> HLERequestContext::ReadBufferA(std::size_t buffer_index) con
343 static thread_local std::array read_buffer_a{ 345 static thread_local std::array read_buffer_a{
344 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), 346 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
345 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), 347 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
348 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
346 }; 349 };
347 350
348 ASSERT_OR_EXECUTE_MSG( 351 ASSERT_OR_EXECUTE_MSG(
@@ -358,6 +361,7 @@ std::span<const u8> HLERequestContext::ReadBufferX(std::size_t buffer_index) con
358 static thread_local std::array read_buffer_x{ 361 static thread_local std::array read_buffer_x{
359 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), 362 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
360 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), 363 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
364 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
361 }; 365 };
362 366
363 ASSERT_OR_EXECUTE_MSG( 367 ASSERT_OR_EXECUTE_MSG(
@@ -373,10 +377,12 @@ std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) cons
373 static thread_local std::array read_buffer_a{ 377 static thread_local std::array read_buffer_a{
374 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), 378 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
375 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), 379 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
380 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
376 }; 381 };
377 static thread_local std::array read_buffer_x{ 382 static thread_local std::array read_buffer_x{
378 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), 383 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
379 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), 384 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
385 Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0),
380 }; 386 };
381 387
382 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && 388 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
diff --git a/src/core/hle/service/ptm/ts.cpp b/src/core/hle/service/ptm/ts.cpp
index ca064dd90..652f38b97 100644
--- a/src/core/hle/service/ptm/ts.cpp
+++ b/src/core/hle/service/ptm/ts.cpp
@@ -9,6 +9,35 @@
9 9
10namespace Service::PTM { 10namespace Service::PTM {
11 11
12enum class Location : u8 {
13 Internal,
14 External,
15};
16
17class ISession : public ServiceFramework<ISession> {
18public:
19 explicit ISession(Core::System& system_) : ServiceFramework{system_, "ISession"} {
20 // clang-format off
21 static const FunctionInfo functions[] = {
22 {0, nullptr, "GetTemperatureRange"},
23 {2, nullptr, "SetMeasurementMode"},
24 {4, &ISession::GetTemperature, "GetTemperature"},
25 };
26 // clang-format on
27
28 RegisterHandlers(functions);
29 }
30
31private:
32 void GetTemperature(HLERequestContext& ctx) {
33 constexpr f32 temperature = 35;
34
35 IPC::ResponseBuilder rb{ctx, 3};
36 rb.Push(ResultSuccess);
37 rb.Push(temperature);
38 }
39};
40
12TS::TS(Core::System& system_) : ServiceFramework{system_, "ts"} { 41TS::TS(Core::System& system_) : ServiceFramework{system_, "ts"} {
13 // clang-format off 42 // clang-format off
14 static const FunctionInfo functions[] = { 43 static const FunctionInfo functions[] = {
@@ -16,7 +45,7 @@ TS::TS(Core::System& system_) : ServiceFramework{system_, "ts"} {
16 {1, &TS::GetTemperature, "GetTemperature"}, 45 {1, &TS::GetTemperature, "GetTemperature"},
17 {2, nullptr, "SetMeasurementMode"}, 46 {2, nullptr, "SetMeasurementMode"},
18 {3, &TS::GetTemperatureMilliC, "GetTemperatureMilliC"}, 47 {3, &TS::GetTemperatureMilliC, "GetTemperatureMilliC"},
19 {4, nullptr, "OpenSession"}, 48 {4, &TS::OpenSession, "OpenSession"},
20 }; 49 };
21 // clang-format on 50 // clang-format on
22 51
@@ -47,4 +76,13 @@ void TS::GetTemperatureMilliC(HLERequestContext& ctx) {
47 rb.Push(temperature); 76 rb.Push(temperature);
48} 77}
49 78
79void TS::OpenSession(HLERequestContext& ctx) {
80 IPC::RequestParser rp{ctx};
81 [[maybe_unused]] const u32 device_code = rp.Pop<u32>();
82
83 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
84 rb.Push(ResultSuccess);
85 rb.PushIpcInterface<ISession>(system);
86}
87
50} // namespace Service::PTM 88} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ts.h b/src/core/hle/service/ptm/ts.h
index c3f43d5a3..a10a91a64 100644
--- a/src/core/hle/service/ptm/ts.h
+++ b/src/core/hle/service/ptm/ts.h
@@ -14,13 +14,9 @@ public:
14 ~TS() override; 14 ~TS() override;
15 15
16private: 16private:
17 enum class Location : u8 {
18 Internal,
19 External,
20 };
21
22 void GetTemperature(HLERequestContext& ctx); 17 void GetTemperature(HLERequestContext& ctx);
23 void GetTemperatureMilliC(HLERequestContext& ctx); 18 void GetTemperatureMilliC(HLERequestContext& ctx);
19 void OpenSession(HLERequestContext& ctx);
24}; 20};
25 21
26} // namespace Service::PTM 22} // namespace Service::PTM
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index 165b97dad..ec3af80af 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -5,8 +5,13 @@
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "common/settings.h" 6#include "common/settings.h"
7#include "common/string_util.h" 7#include "common/string_util.h"
8#include "core/core.h"
9#include "core/file_sys/content_archive.h"
8#include "core/file_sys/errors.h" 10#include "core/file_sys/errors.h"
9#include "core/file_sys/system_archive/system_version.h" 11#include "core/file_sys/nca_metadata.h"
12#include "core/file_sys/registered_cache.h"
13#include "core/file_sys/romfs.h"
14#include "core/file_sys/system_archive/system_archive.h"
10#include "core/hle/service/filesystem/filesystem.h" 15#include "core/hle/service/filesystem/filesystem.h"
11#include "core/hle/service/ipc_helpers.h" 16#include "core/hle/service/ipc_helpers.h"
12#include "core/hle/service/set/set.h" 17#include "core/hle/service/set/set.h"
@@ -22,18 +27,30 @@ enum class GetFirmwareVersionType {
22 Version2, 27 Version2,
23}; 28};
24 29
25void GetFirmwareVersionImpl(HLERequestContext& ctx, GetFirmwareVersionType type) { 30void GetFirmwareVersionImpl(Core::System& system, HLERequestContext& ctx,
26 LOG_WARNING(Service_SET, "called - Using hardcoded firmware version '{}'", 31 GetFirmwareVersionType type) {
27 FileSys::SystemArchive::GetLongDisplayVersion());
28
29 ASSERT_MSG(ctx.GetWriteBufferSize() == 0x100, 32 ASSERT_MSG(ctx.GetWriteBufferSize() == 0x100,
30 "FirmwareVersion output buffer must be 0x100 bytes in size!"); 33 "FirmwareVersion output buffer must be 0x100 bytes in size!");
31 34
32 // Instead of using the normal procedure of checking for the real system archive and if it 35 constexpr u64 FirmwareVersionSystemDataId = 0x0100000000000809;
33 // doesn't exist, synthesizing one, I feel that that would lead to strange bugs because a 36 auto& fsc = system.GetFileSystemController();
34 // used is using a really old or really new SystemVersion title. The synthesized one ensures 37
35 // consistence (currently reports as 5.1.0-0.0) 38 // Attempt to load version data from disk
36 const auto archive = FileSys::SystemArchive::SystemVersion(); 39 const FileSys::RegisteredCache* bis_system{};
40 std::unique_ptr<FileSys::NCA> nca{};
41 FileSys::VirtualDir romfs{};
42
43 bis_system = fsc.GetSystemNANDContents();
44 if (bis_system) {
45 nca = bis_system->GetEntry(FirmwareVersionSystemDataId, FileSys::ContentRecordType::Data);
46 }
47 if (nca) {
48 romfs = FileSys::ExtractRomFS(nca->GetRomFS());
49 }
50 if (!romfs) {
51 romfs = FileSys::ExtractRomFS(
52 FileSys::SystemArchive::SynthesizeSystemArchive(FirmwareVersionSystemDataId));
53 }
37 54
38 const auto early_exit_failure = [&ctx](std::string_view desc, Result code) { 55 const auto early_exit_failure = [&ctx](std::string_view desc, Result code) {
39 LOG_ERROR(Service_SET, "General failure while attempting to resolve firmware version ({}).", 56 LOG_ERROR(Service_SET, "General failure while attempting to resolve firmware version ({}).",
@@ -42,13 +59,7 @@ void GetFirmwareVersionImpl(HLERequestContext& ctx, GetFirmwareVersionType type)
42 rb.Push(code); 59 rb.Push(code);
43 }; 60 };
44 61
45 if (archive == nullptr) { 62 const auto ver_file = romfs->GetFile("file");
46 early_exit_failure("The system version archive couldn't be synthesized.",
47 FileSys::ERROR_FAILED_MOUNT_ARCHIVE);
48 return;
49 }
50
51 const auto ver_file = archive->GetFile("file");
52 if (ver_file == nullptr) { 63 if (ver_file == nullptr) {
53 early_exit_failure("The system version archive didn't contain the file 'file'.", 64 early_exit_failure("The system version archive didn't contain the file 'file'.",
54 FileSys::ERROR_INVALID_ARGUMENT); 65 FileSys::ERROR_INVALID_ARGUMENT);
@@ -87,12 +98,12 @@ void SET_SYS::SetLanguageCode(HLERequestContext& ctx) {
87 98
88void SET_SYS::GetFirmwareVersion(HLERequestContext& ctx) { 99void SET_SYS::GetFirmwareVersion(HLERequestContext& ctx) {
89 LOG_DEBUG(Service_SET, "called"); 100 LOG_DEBUG(Service_SET, "called");
90 GetFirmwareVersionImpl(ctx, GetFirmwareVersionType::Version1); 101 GetFirmwareVersionImpl(system, ctx, GetFirmwareVersionType::Version1);
91} 102}
92 103
93void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) { 104void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) {
94 LOG_DEBUG(Service_SET, "called"); 105 LOG_DEBUG(Service_SET, "called");
95 GetFirmwareVersionImpl(ctx, GetFirmwareVersionType::Version2); 106 GetFirmwareVersionImpl(system, ctx, GetFirmwareVersionType::Version2);
96} 107}
97 108
98void SET_SYS::GetAccountSettings(HLERequestContext& ctx) { 109void SET_SYS::GetAccountSettings(HLERequestContext& ctx) {
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index a06e99166..53a89cc8f 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -19,16 +19,23 @@ namespace Core::Memory {
19namespace { 19namespace {
20constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12}; 20constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12};
21 21
22std::string_view ExtractName(std::string_view data, std::size_t start_index, char match) { 22std::string_view ExtractName(std::size_t& out_name_size, std::string_view data,
23 std::size_t start_index, char match) {
23 auto end_index = start_index; 24 auto end_index = start_index;
24 while (data[end_index] != match) { 25 while (data[end_index] != match) {
25 ++end_index; 26 ++end_index;
26 if (end_index > data.size() || 27 if (end_index > data.size()) {
27 (end_index - start_index - 1) > sizeof(CheatDefinition::readable_name)) {
28 return {}; 28 return {};
29 } 29 }
30 } 30 }
31 31
32 out_name_size = end_index - start_index;
33
34 // Clamp name if it's too big
35 if (out_name_size > sizeof(CheatDefinition::readable_name)) {
36 end_index = start_index + sizeof(CheatDefinition::readable_name);
37 }
38
32 return data.substr(start_index, end_index - start_index); 39 return data.substr(start_index, end_index - start_index);
33} 40}
34} // Anonymous namespace 41} // Anonymous namespace
@@ -113,7 +120,8 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
113 return {}; 120 return {};
114 } 121 }
115 122
116 const auto name = ExtractName(data, i + 1, '}'); 123 std::size_t name_size{};
124 const auto name = ExtractName(name_size, data, i + 1, '}');
117 if (name.empty()) { 125 if (name.empty()) {
118 return {}; 126 return {};
119 } 127 }
@@ -125,12 +133,13 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
125 .definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] = 133 .definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] =
126 '\0'; 134 '\0';
127 135
128 i += name.length() + 1; 136 i += name_size + 1;
129 } else if (data[i] == '[') { 137 } else if (data[i] == '[') {
130 current_entry = out.size(); 138 current_entry = out.size();
131 out.emplace_back(); 139 out.emplace_back();
132 140
133 const auto name = ExtractName(data, i + 1, ']'); 141 std::size_t name_size{};
142 const auto name = ExtractName(name_size, data, i + 1, ']');
134 if (name.empty()) { 143 if (name.empty()) {
135 return {}; 144 return {};
136 } 145 }
@@ -142,7 +151,7 @@ std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
142 .definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] = 151 .definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] =
143 '\0'; 152 '\0';
144 153
145 i += name.length() + 1; 154 i += name_size + 1;
146 } else if (::isxdigit(data[i])) { 155 } else if (::isxdigit(data[i])) {
147 if (!current_entry || out[*current_entry].definition.num_opcodes >= 156 if (!current_entry || out[*current_entry].definition.num_opcodes >=
148 out[*current_entry].definition.opcodes.size()) { 157 out[*current_entry].definition.opcodes.size()) {
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl.cpp b/src/shader_recompiler/backend/glsl/emit_glsl.cpp
index d91e04446..66ecfc9f7 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl.cpp
@@ -242,6 +242,7 @@ std::string EmitGLSL(const Profile& profile, const RuntimeInfo& runtime_info, IR
242 } 242 }
243 if (program.info.uses_subgroup_shuffles) { 243 if (program.info.uses_subgroup_shuffles) {
244 ctx.header += "bool shfl_in_bounds;"; 244 ctx.header += "bool shfl_in_bounds;";
245 ctx.header += "uint shfl_result;";
245 } 246 }
246 ctx.code.insert(0, ctx.header); 247 ctx.code.insert(0, ctx.header);
247 ctx.code += '}'; 248 ctx.code += '}';
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp
index 1245c9429..f9be5de1c 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl_warp.cpp
@@ -141,7 +141,8 @@ void EmitShuffleIndex(EmitContext& ctx, IR::Inst& inst, std::string_view value,
141 const auto src_thread_id{fmt::format("({})|({})", lhs, min_thread_id)}; 141 const auto src_thread_id{fmt::format("({})|({})", lhs, min_thread_id)};
142 ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id); 142 ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id);
143 SetInBoundsFlag(ctx, inst); 143 SetInBoundsFlag(ctx, inst);
144 ctx.AddU32("{}=shfl_in_bounds?readInvocationARB({},{}):{};", inst, value, src_thread_id, value); 144 ctx.Add("shfl_result=readInvocationARB({},{});", value, src_thread_id);
145 ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
145} 146}
146 147
147void EmitShuffleUp(EmitContext& ctx, IR::Inst& inst, std::string_view value, std::string_view index, 148void EmitShuffleUp(EmitContext& ctx, IR::Inst& inst, std::string_view value, std::string_view index,
@@ -158,7 +159,8 @@ void EmitShuffleUp(EmitContext& ctx, IR::Inst& inst, std::string_view value, std
158 const auto src_thread_id{fmt::format("({}-{})", THREAD_ID, index)}; 159 const auto src_thread_id{fmt::format("({}-{})", THREAD_ID, index)};
159 ctx.Add("shfl_in_bounds=int({})>=int({});", src_thread_id, max_thread_id); 160 ctx.Add("shfl_in_bounds=int({})>=int({});", src_thread_id, max_thread_id);
160 SetInBoundsFlag(ctx, inst); 161 SetInBoundsFlag(ctx, inst);
161 ctx.AddU32("{}=shfl_in_bounds?readInvocationARB({},{}):{};", inst, value, src_thread_id, value); 162 ctx.Add("shfl_result=readInvocationARB({},{});", value, src_thread_id);
163 ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
162} 164}
163 165
164void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, std::string_view value, 166void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, std::string_view value,
@@ -175,7 +177,8 @@ void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, std::string_view value,
175 const auto src_thread_id{fmt::format("({}+{})", THREAD_ID, index)}; 177 const auto src_thread_id{fmt::format("({}+{})", THREAD_ID, index)};
176 ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id); 178 ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id);
177 SetInBoundsFlag(ctx, inst); 179 SetInBoundsFlag(ctx, inst);
178 ctx.AddU32("{}=shfl_in_bounds?readInvocationARB({},{}):{};", inst, value, src_thread_id, value); 180 ctx.Add("shfl_result=readInvocationARB({},{});", value, src_thread_id);
181 ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
179} 182}
180 183
181void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view value, 184void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view value,
@@ -193,7 +196,8 @@ void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view val
193 const auto src_thread_id{fmt::format("({}^{})", THREAD_ID, index)}; 196 const auto src_thread_id{fmt::format("({}^{})", THREAD_ID, index)};
194 ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id); 197 ctx.Add("shfl_in_bounds=int({})<=int({});", src_thread_id, max_thread_id);
195 SetInBoundsFlag(ctx, inst); 198 SetInBoundsFlag(ctx, inst);
196 ctx.AddU32("{}=shfl_in_bounds?readInvocationARB({},{}):{};", inst, value, src_thread_id, value); 199 ctx.Add("shfl_result=readInvocationARB({},{});", value, src_thread_id);
200 ctx.AddU32("{}=shfl_in_bounds?shfl_result:{};", inst, value);
197} 201}
198 202
199void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, std::string_view op_a, std::string_view op_b, 203void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, std::string_view op_a, std::string_view op_b,
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
index 2868fc57d..1d77426e0 100644
--- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
+++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp
@@ -111,16 +111,33 @@ Id GetCbuf(EmitContext& ctx, Id result_type, Id UniformDefinitions::*member_ptr,
111 } else if (element_size > 1) { 111 } else if (element_size > 1) {
112 const u32 log2_element_size{static_cast<u32>(std::countr_zero(element_size))}; 112 const u32 log2_element_size{static_cast<u32>(std::countr_zero(element_size))};
113 const Id shift{ctx.Const(log2_element_size)}; 113 const Id shift{ctx.Const(log2_element_size)};
114 buffer_offset = ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), shift); 114 buffer_offset = ctx.OpShiftRightLogical(ctx.U32[1], ctx.Def(offset), shift);
115 } else { 115 } else {
116 buffer_offset = ctx.Def(offset); 116 buffer_offset = ctx.Def(offset);
117 } 117 }
118 if (!binding.IsImmediate()) { 118 if (!binding.IsImmediate()) {
119 return ctx.OpFunctionCall(result_type, indirect_func, ctx.Def(binding), buffer_offset); 119 return ctx.OpFunctionCall(result_type, indirect_func, ctx.Def(binding), buffer_offset);
120 } 120 }
121
121 const Id cbuf{ctx.cbufs[binding.U32()].*member_ptr}; 122 const Id cbuf{ctx.cbufs[binding.U32()].*member_ptr};
122 const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, buffer_offset)}; 123 const Id access_chain{ctx.OpAccessChain(uniform_type, cbuf, ctx.u32_zero_value, buffer_offset)};
123 return ctx.OpLoad(result_type, access_chain); 124 const Id val = ctx.OpLoad(result_type, access_chain);
125
126 if (offset.IsImmediate() || !ctx.profile.has_broken_robust) {
127 return val;
128 }
129
130 const auto is_float = UniformDefinitions::IsFloat(member_ptr);
131 const auto num_elements = UniformDefinitions::NumElements(member_ptr);
132 const std::array zero_vec{
133 is_float ? ctx.Const(0.0f) : ctx.Const(0u),
134 is_float ? ctx.Const(0.0f) : ctx.Const(0u),
135 is_float ? ctx.Const(0.0f) : ctx.Const(0u),
136 is_float ? ctx.Const(0.0f) : ctx.Const(0u),
137 };
138 const Id cond = ctx.OpULessThanEqual(ctx.TypeBool(), buffer_offset, ctx.Const(0xFFFFu));
139 const Id zero = ctx.OpCompositeConstruct(result_type, std::span(zero_vec.data(), num_elements));
140 return ctx.OpSelect(result_type, cond, val, zero);
124} 141}
125 142
126Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { 143Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
@@ -138,7 +155,7 @@ Id GetCbufElement(EmitContext& ctx, Id vector, const IR::Value& offset, u32 inde
138 const u32 element{(offset.U32() / 4) % 4 + index_offset}; 155 const u32 element{(offset.U32() / 4) % 4 + index_offset};
139 return ctx.OpCompositeExtract(ctx.U32[1], vector, element); 156 return ctx.OpCompositeExtract(ctx.U32[1], vector, element);
140 } 157 }
141 const Id shift{ctx.OpShiftRightArithmetic(ctx.U32[1], ctx.Def(offset), ctx.Const(2u))}; 158 const Id shift{ctx.OpShiftRightLogical(ctx.U32[1], ctx.Def(offset), ctx.Const(2u))};
142 Id element{ctx.OpBitwiseAnd(ctx.U32[1], shift, ctx.Const(3u))}; 159 Id element{ctx.OpBitwiseAnd(ctx.U32[1], shift, ctx.Const(3u))};
143 if (index_offset > 0) { 160 if (index_offset > 0) {
144 element = ctx.OpIAdd(ctx.U32[1], element, ctx.Const(index_offset)); 161 element = ctx.OpIAdd(ctx.U32[1], element, ctx.Const(index_offset));
diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h
index 7c49fd504..1aa79863d 100644
--- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h
+++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h
@@ -64,6 +64,42 @@ struct UniformDefinitions {
64 Id F32{}; 64 Id F32{};
65 Id U32x2{}; 65 Id U32x2{};
66 Id U32x4{}; 66 Id U32x4{};
67
68 constexpr static size_t NumElements(Id UniformDefinitions::*member_ptr) {
69 if (member_ptr == &UniformDefinitions::U8) {
70 return 1;
71 }
72 if (member_ptr == &UniformDefinitions::S8) {
73 return 1;
74 }
75 if (member_ptr == &UniformDefinitions::U16) {
76 return 1;
77 }
78 if (member_ptr == &UniformDefinitions::S16) {
79 return 1;
80 }
81 if (member_ptr == &UniformDefinitions::U32) {
82 return 1;
83 }
84 if (member_ptr == &UniformDefinitions::F32) {
85 return 1;
86 }
87 if (member_ptr == &UniformDefinitions::U32x2) {
88 return 2;
89 }
90 if (member_ptr == &UniformDefinitions::U32x4) {
91 return 4;
92 }
93 ASSERT(false);
94 return 1;
95 }
96
97 constexpr static bool IsFloat(Id UniformDefinitions::*member_ptr) {
98 if (member_ptr == &UniformDefinitions::F32) {
99 return true;
100 }
101 return false;
102 }
67}; 103};
68 104
69struct StorageTypeDefinition { 105struct StorageTypeDefinition {
diff --git a/src/shader_recompiler/profile.h b/src/shader_recompiler/profile.h
index 9ca97f6a4..38d820db2 100644
--- a/src/shader_recompiler/profile.h
+++ b/src/shader_recompiler/profile.h
@@ -9,7 +9,6 @@ namespace Shader {
9 9
10struct Profile { 10struct Profile {
11 u32 supported_spirv{0x00010000}; 11 u32 supported_spirv{0x00010000};
12
13 bool unified_descriptor_binding{}; 12 bool unified_descriptor_binding{};
14 bool support_descriptor_aliasing{}; 13 bool support_descriptor_aliasing{};
15 bool support_int8{}; 14 bool support_int8{};
@@ -82,6 +81,9 @@ struct Profile {
82 bool has_broken_spirv_subgroup_mask_vector_extract_dynamic{}; 81 bool has_broken_spirv_subgroup_mask_vector_extract_dynamic{};
83 82
84 u32 gl_max_compute_smem_size{}; 83 u32 gl_max_compute_smem_size{};
84
85 /// Maxwell and earlier nVidia architectures have broken robust support
86 bool has_broken_robust{};
85}; 87};
86 88
87} // namespace Shader 89} // namespace Shader
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index a1ec1a100..804b95989 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -356,7 +356,11 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
356 .has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY, 356 .has_broken_fp16_float_controls = driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY,
357 .ignore_nan_fp_comparisons = false, 357 .ignore_nan_fp_comparisons = false,
358 .has_broken_spirv_subgroup_mask_vector_extract_dynamic = 358 .has_broken_spirv_subgroup_mask_vector_extract_dynamic =
359 driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY}; 359 driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY,
360 .has_broken_robust =
361 device.IsNvidia() && device.GetNvidiaArch() <= NvidiaArchitecture::Arch_Maxwell,
362 };
363
360 host_info = Shader::HostTranslateInfo{ 364 host_info = Shader::HostTranslateInfo{
361 .support_float64 = device.IsFloat64Supported(), 365 .support_float64 = device.IsFloat64Supported(),
362 .support_float16 = device.IsFloat16Supported(), 366 .support_float16 = device.IsFloat16Supported(),
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 876cec2e8..e518756d2 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -83,15 +83,6 @@ constexpr std::array VK_FORMAT_A4B4G4R4_UNORM_PACK16{
83 83
84} // namespace Alternatives 84} // namespace Alternatives
85 85
86enum class NvidiaArchitecture {
87 KeplerOrOlder,
88 Maxwell,
89 Pascal,
90 Volta,
91 Turing,
92 AmpereOrNewer,
93};
94
95template <typename T> 86template <typename T>
96void SetNext(void**& next, T& data) { 87void SetNext(void**& next, T& data) {
97 *next = &data; 88 *next = &data;
@@ -326,9 +317,9 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
326 if (shading_rate_props.primitiveFragmentShadingRateWithMultipleViewports) { 317 if (shading_rate_props.primitiveFragmentShadingRateWithMultipleViewports) {
327 // Only Ampere and newer support this feature 318 // Only Ampere and newer support this feature
328 // TODO: Find a way to differentiate Ampere and Ada 319 // TODO: Find a way to differentiate Ampere and Ada
329 return NvidiaArchitecture::AmpereOrNewer; 320 return NvidiaArchitecture::Arch_AmpereOrNewer;
330 } 321 }
331 return NvidiaArchitecture::Turing; 322 return NvidiaArchitecture::Arch_Turing;
332 } 323 }
333 324
334 if (exts.contains(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME)) { 325 if (exts.contains(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME)) {
@@ -340,7 +331,7 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
340 physical_properties.pNext = &advanced_blending_props; 331 physical_properties.pNext = &advanced_blending_props;
341 physical.GetProperties2(physical_properties); 332 physical.GetProperties2(physical_properties);
342 if (advanced_blending_props.advancedBlendMaxColorAttachments == 1) { 333 if (advanced_blending_props.advancedBlendMaxColorAttachments == 1) {
343 return NvidiaArchitecture::Maxwell; 334 return NvidiaArchitecture::Arch_Maxwell;
344 } 335 }
345 336
346 if (exts.contains(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME)) { 337 if (exts.contains(VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME)) {
@@ -350,13 +341,13 @@ NvidiaArchitecture GetNvidiaArchitecture(vk::PhysicalDevice physical,
350 physical_properties.pNext = &conservative_raster_props; 341 physical_properties.pNext = &conservative_raster_props;
351 physical.GetProperties2(physical_properties); 342 physical.GetProperties2(physical_properties);
352 if (conservative_raster_props.degenerateLinesRasterized) { 343 if (conservative_raster_props.degenerateLinesRasterized) {
353 return NvidiaArchitecture::Volta; 344 return NvidiaArchitecture::Arch_Volta;
354 } 345 }
355 return NvidiaArchitecture::Pascal; 346 return NvidiaArchitecture::Arch_Pascal;
356 } 347 }
357 } 348 }
358 349
359 return NvidiaArchitecture::KeplerOrOlder; 350 return NvidiaArchitecture::Arch_KeplerOrOlder;
360} 351}
361 352
362std::vector<const char*> ExtensionListForVulkan( 353std::vector<const char*> ExtensionListForVulkan(
@@ -436,6 +427,10 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
436 throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER); 427 throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER);
437 } 428 }
438 429
430 if (is_nvidia) {
431 nvidia_arch = GetNvidiaArchitecture(physical, supported_extensions);
432 }
433
439 SetupFamilies(surface); 434 SetupFamilies(surface);
440 const auto queue_cis = GetDeviceQueueCreateInfos(); 435 const auto queue_cis = GetDeviceQueueCreateInfos();
441 436
@@ -532,11 +527,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
532 527
533 if (is_nvidia) { 528 if (is_nvidia) {
534 const u32 nv_major_version = (properties.properties.driverVersion >> 22) & 0x3ff; 529 const u32 nv_major_version = (properties.properties.driverVersion >> 22) & 0x3ff;
535 const auto arch = GetNvidiaArchitecture(physical, supported_extensions); 530 const auto arch = GetNvidiaArch();
536 if (arch >= NvidiaArchitecture::AmpereOrNewer) { 531 if (arch >= NvidiaArchitecture::Arch_AmpereOrNewer) {
537 LOG_WARNING(Render_Vulkan, "Ampere and newer have broken float16 math"); 532 LOG_WARNING(Render_Vulkan, "Ampere and newer have broken float16 math");
538 features.shader_float16_int8.shaderFloat16 = false; 533 features.shader_float16_int8.shaderFloat16 = false;
539 } else if (arch <= NvidiaArchitecture::Volta) { 534 } else if (arch <= NvidiaArchitecture::Arch_Volta) {
540 if (nv_major_version < 527) { 535 if (nv_major_version < 527) {
541 LOG_WARNING(Render_Vulkan, "Volta and older have broken VK_KHR_push_descriptor"); 536 LOG_WARNING(Render_Vulkan, "Volta and older have broken VK_KHR_push_descriptor");
542 RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); 537 RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
@@ -686,8 +681,8 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
686 RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); 681 RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
687 } 682 }
688 } else if (extensions.push_descriptor && is_nvidia) { 683 } else if (extensions.push_descriptor && is_nvidia) {
689 const auto arch = GetNvidiaArchitecture(physical, supported_extensions); 684 const auto arch = GetNvidiaArch();
690 if (arch <= NvidiaArchitecture::Pascal) { 685 if (arch <= NvidiaArchitecture::Arch_Pascal) {
691 LOG_WARNING(Render_Vulkan, 686 LOG_WARNING(Render_Vulkan,
692 "Pascal and older architectures have broken VK_KHR_push_descriptor"); 687 "Pascal and older architectures have broken VK_KHR_push_descriptor");
693 RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); 688 RemoveExtension(extensions.push_descriptor, VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index 282a2925d..b213ed7dd 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -177,6 +177,15 @@ enum class FormatType { Linear, Optimal, Buffer };
177/// Subgroup size of the guest emulated hardware (Nvidia has 32 threads per subgroup). 177/// Subgroup size of the guest emulated hardware (Nvidia has 32 threads per subgroup).
178const u32 GuestWarpSize = 32; 178const u32 GuestWarpSize = 32;
179 179
180enum class NvidiaArchitecture {
181 Arch_KeplerOrOlder,
182 Arch_Maxwell,
183 Arch_Pascal,
184 Arch_Volta,
185 Arch_Turing,
186 Arch_AmpereOrNewer,
187};
188
180/// Handles data specific to a physical device. 189/// Handles data specific to a physical device.
181class Device { 190class Device {
182public: 191public:
@@ -670,6 +679,14 @@ public:
670 return false; 679 return false;
671 } 680 }
672 681
682 bool IsNvidia() const noexcept {
683 return properties.driver.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY;
684 }
685
686 NvidiaArchitecture GetNvidiaArch() const noexcept {
687 return nvidia_arch;
688 }
689
673private: 690private:
674 /// Checks if the physical device is suitable and configures the object state 691 /// Checks if the physical device is suitable and configures the object state
675 /// with all necessary info about its properties. 692 /// with all necessary info about its properties.
@@ -788,6 +805,7 @@ private:
788 bool supports_conditional_barriers{}; ///< Allows barriers in conditional control flow. 805 bool supports_conditional_barriers{}; ///< Allows barriers in conditional control flow.
789 u64 device_access_memory{}; ///< Total size of device local memory in bytes. 806 u64 device_access_memory{}; ///< Total size of device local memory in bytes.
790 u32 sets_per_pool{}; ///< Sets per Description Pool 807 u32 sets_per_pool{}; ///< Sets per Description Pool
808 NvidiaArchitecture nvidia_arch{NvidiaArchitecture::Arch_AmpereOrNewer};
791 809
792 // Telemetry parameters 810 // Telemetry parameters
793 std::set<std::string, std::less<>> supported_extensions; ///< Reported Vulkan extensions. 811 std::set<std::string, std::less<>> supported_extensions; ///< Reported Vulkan extensions.
diff --git a/src/video_core/vulkan_common/vulkan_wrapper.cpp b/src/video_core/vulkan_common/vulkan_wrapper.cpp
index 2f3254a97..70cf14afa 100644
--- a/src/video_core/vulkan_common/vulkan_wrapper.cpp
+++ b/src/video_core/vulkan_common/vulkan_wrapper.cpp
@@ -522,7 +522,7 @@ Instance Instance::Create(u32 version, Span<const char*> layers, Span<const char
522 .applicationVersion = VK_MAKE_VERSION(0, 1, 0), 522 .applicationVersion = VK_MAKE_VERSION(0, 1, 0),
523 .pEngineName = "yuzu Emulator", 523 .pEngineName = "yuzu Emulator",
524 .engineVersion = VK_MAKE_VERSION(0, 1, 0), 524 .engineVersion = VK_MAKE_VERSION(0, 1, 0),
525 .apiVersion = version, 525 .apiVersion = VK_API_VERSION_1_3,
526 }; 526 };
527 const VkInstanceCreateInfo ci{ 527 const VkInstanceCreateInfo ci{
528 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 528 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index d5157c502..baa3e55f3 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -114,7 +114,7 @@ const std::map<Settings::ShaderBackend, QString> Config::shader_backend_texts_ma
114// This must be in alphabetical order according to action name as it must have the same order as 114// This must be in alphabetical order according to action name as it must have the same order as
115// UISetting::values.shortcuts, which is alphabetically ordered. 115// UISetting::values.shortcuts, which is alphabetically ordered.
116// clang-format off 116// clang-format off
117const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{ 117const std::array<UISettings::Shortcut, 23> Config::default_hotkeys{{
118 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut, false}}, 118 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut, false}},
119 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut, true}}, 119 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut, true}},
120 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("="), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut, true}}, 120 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("="), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut, true}},
@@ -136,6 +136,7 @@ const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{
136 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut, false}}, 136 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut, false}},
137 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut, false}}, 137 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut, false}},
138 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut, false}}, 138 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut, false}},
139 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Renderdoc Capture")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral(""), QStringLiteral(""), Qt::ApplicationShortcut, false}},
139 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut, false}}, 140 {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut, false}},
140}}; 141}};
141// clang-format on 142// clang-format on
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 727feebfb..74ec4f771 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -48,7 +48,7 @@ public:
48 default_mouse_buttons; 48 default_mouse_buttons;
49 static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys; 49 static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
50 static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods; 50 static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods;
51 static const std::array<UISettings::Shortcut, 22> default_hotkeys; 51 static const std::array<UISettings::Shortcut, 23> default_hotkeys;
52 52
53 static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map; 53 static const std::map<Settings::AntiAliasing, QString> anti_aliasing_texts_map;
54 static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map; 54 static const std::map<Settings::ScalingFilter, QString> scaling_filter_texts_map;
diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp
index 0b2a965f8..68e21cd84 100644
--- a/src/yuzu/configuration/configure_hotkeys.cpp
+++ b/src/yuzu/configuration/configure_hotkeys.cpp
@@ -319,6 +319,13 @@ void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) {
319void ConfigureHotkeys::RestoreDefaults() { 319void ConfigureHotkeys::RestoreDefaults() {
320 for (int r = 0; r < model->rowCount(); ++r) { 320 for (int r = 0; r < model->rowCount(); ++r) {
321 const QStandardItem* parent = model->item(r, 0); 321 const QStandardItem* parent = model->item(r, 0);
322 const int hotkey_size = static_cast<int>(Config::default_hotkeys.size());
323
324 if (hotkey_size != parent->rowCount()) {
325 QMessageBox::warning(this, tr("Invalid hotkey settings"),
326 tr("An error occurred. Please report this issue on github."));
327 return;
328 }
322 329
323 for (int r2 = 0; r2 < parent->rowCount(); ++r2) { 330 for (int r2 = 0; r2 < parent->rowCount(); ++r2) {
324 model->item(r, 0) 331 model->item(r, 0)
diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp
index d765e808a..68c28b320 100644
--- a/src/yuzu/configuration/configure_vibration.cpp
+++ b/src/yuzu/configuration/configure_vibration.cpp
@@ -89,7 +89,7 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type
89 89
90 auto& player = Settings::values.players.GetValue()[player_index]; 90 auto& player = Settings::values.players.GetValue()[player_index];
91 auto controller = hid_core.GetEmulatedControllerByIndex(player_index); 91 auto controller = hid_core.GetEmulatedControllerByIndex(player_index);
92 const int vibration_strenght = vibration_spinboxes[player_index]->value(); 92 const int vibration_strength = vibration_spinboxes[player_index]->value();
93 const auto& buttons = controller->GetButtonsValues(); 93 const auto& buttons = controller->GetButtonsValues();
94 94
95 bool button_is_pressed = false; 95 bool button_is_pressed = false;
@@ -105,10 +105,10 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type
105 return; 105 return;
106 } 106 }
107 107
108 const int old_vibration_enabled = player.vibration_enabled; 108 const bool old_vibration_enabled = player.vibration_enabled;
109 const bool old_vibration_strenght = player.vibration_strength; 109 const int old_vibration_strength = player.vibration_strength;
110 player.vibration_enabled = true; 110 player.vibration_enabled = true;
111 player.vibration_strength = vibration_strenght; 111 player.vibration_strength = vibration_strength;
112 112
113 const Core::HID::VibrationValue vibration{ 113 const Core::HID::VibrationValue vibration{
114 .low_amplitude = 1.0f, 114 .low_amplitude = 1.0f,
@@ -121,7 +121,7 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type
121 121
122 // Restore previous values 122 // Restore previous values
123 player.vibration_enabled = old_vibration_enabled; 123 player.vibration_enabled = old_vibration_enabled;
124 player.vibration_strength = old_vibration_strenght; 124 player.vibration_strength = old_vibration_strength;
125} 125}
126 126
127void ConfigureVibration::StopVibrations() { 127void ConfigureVibration::StopVibrations() {