diff options
Diffstat (limited to 'src')
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 | ) |
| 213 | else() | ||
| 214 | set_source_files_properties(stb.cpp PROPERTIES COMPILE_OPTIONS "-Wno-implicit-fallthrough;-Wno-missing-declarations;-Wno-missing-field-initializers") | ||
| 211 | endif() | 215 | endif() |
| 212 | 216 | ||
| 213 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") | 217 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") |
| @@ -223,7 +227,7 @@ endif() | |||
| 223 | 227 | ||
| 224 | create_target_directory_groups(common) | 228 | create_target_directory_groups(common) |
| 225 | 229 | ||
| 226 | target_link_libraries(common PUBLIC Boost::context Boost::headers fmt::fmt microprofile Threads::Threads) | 230 | target_link_libraries(common PUBLIC Boost::context Boost::headers fmt::fmt microprofile stb::headers Threads::Threads) |
| 227 | target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd LLVM::Demangle) | 231 | target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd LLVM::Demangle) |
| 228 | 232 | ||
| 229 | if (ANDROID) | 233 | if (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 | ||
| 87 | void SetCurrentThreadName(const char* name) { | 86 | void 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 | ||
| 14 | VirtualDir SystemVersion() { | 15 | VirtualDir 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 | ||
| 229 | Result 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 | |||
| 235 | Result 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 | |||
| 254 | Result 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 | |||
| 230 | Result AlbumManager::GetFile(std::filesystem::path& out_path, const AlbumFileId& file_id) const { | 272 | Result 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 | ||
| 410 | static 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 | |||
| 416 | Result 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 | |||
| 368 | AlbumFileDateTime AlbumManager::ConvertToAlbumDateTime(u64 posix_time) const { | 451 | AlbumFileDateTime 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 | |||
| 61 | private: | 70 | private: |
| 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 | ||
| 6 | namespace Service::Capture { | 11 | namespace Service::Capture { |
| 7 | 12 | ||
| 8 | IScreenShotService::IScreenShotService(Core::System& system_) | 13 | IScreenShotService::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 | ||
| 25 | IScreenShotService::~IScreenShotService() = default; | 31 | IScreenShotService::~IScreenShotService() = default; |
| 26 | 32 | ||
| 33 | void 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 | } | ||
| 59 | void 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 | ||
| 14 | class IScreenShotService final : public ServiceFramework<IScreenShotService> { | 14 | class IScreenShotService final : public ServiceFramework<IScreenShotService> { |
| 15 | public: | 15 | public: |
| 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 | |||
| 19 | private: | ||
| 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 | ||
| 8 | namespace Service::Capture { | 10 | namespace Service::Capture { |
| 9 | 11 | ||
| 10 | IScreenShotApplicationService::IScreenShotApplicationService(Core::System& system_) | 12 | IScreenShotApplicationService::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 | ||
| 42 | void 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 | |||
| 69 | void 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 | ||
| 12 | namespace Service::Capture { | 12 | namespace Service::Capture { |
| 13 | class AlbumManager; | ||
| 13 | 14 | ||
| 14 | class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> { | 15 | class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> { |
| 15 | public: | 16 | public: |
| 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 | ||
| 19 | private: | 21 | private: |
| 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 { | |||
| 20 | enum class AlbumReportOption : s32 { | 20 | enum class AlbumReportOption : s32 { |
| 21 | Disable, | 21 | Disable, |
| 22 | Enable, | 22 | Enable, |
| 23 | Unknown2, | ||
| 24 | Unknown3, | ||
| 23 | }; | 25 | }; |
| 24 | 26 | ||
| 25 | enum class ContentType : u8 { | 27 | enum 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 { | |||
| 27 | static thread_local std::array read_buffer_data_a{ | 27 | static 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 | }; |
| 31 | static thread_local std::array read_buffer_data_x{ | 32 | static 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 | ||
| 10 | namespace Service::PTM { | 10 | namespace Service::PTM { |
| 11 | 11 | ||
| 12 | enum class Location : u8 { | ||
| 13 | Internal, | ||
| 14 | External, | ||
| 15 | }; | ||
| 16 | |||
| 17 | class ISession : public ServiceFramework<ISession> { | ||
| 18 | public: | ||
| 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 | |||
| 31 | private: | ||
| 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 | |||
| 12 | TS::TS(Core::System& system_) : ServiceFramework{system_, "ts"} { | 41 | TS::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 | ||
| 79 | void 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 | ||
| 16 | private: | 16 | private: |
| 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 | ||
| 25 | void GetFirmwareVersionImpl(HLERequestContext& ctx, GetFirmwareVersionType type) { | 30 | void 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 | ||
| 88 | void SET_SYS::GetFirmwareVersion(HLERequestContext& ctx) { | 99 | void 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 | ||
| 93 | void SET_SYS::GetFirmwareVersion2(HLERequestContext& ctx) { | 104 | void 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 | ||
| 98 | void SET_SYS::GetAccountSettings(HLERequestContext& ctx) { | 109 | void 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 { | |||
| 19 | namespace { | 19 | namespace { |
| 20 | constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12}; | 20 | constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12}; |
| 21 | 21 | ||
| 22 | std::string_view ExtractName(std::string_view data, std::size_t start_index, char match) { | 22 | std::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 | ||
| 147 | void EmitShuffleUp(EmitContext& ctx, IR::Inst& inst, std::string_view value, std::string_view index, | 148 | void 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 | ||
| 164 | void EmitShuffleDown(EmitContext& ctx, IR::Inst& inst, std::string_view value, | 166 | void 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 | ||
| 181 | void EmitShuffleButterfly(EmitContext& ctx, IR::Inst& inst, std::string_view value, | 184 | void 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 | ||
| 199 | void EmitFSwizzleAdd(EmitContext& ctx, IR::Inst& inst, std::string_view op_a, std::string_view op_b, | 203 | void 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 | ||
| 126 | Id GetCbufU32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) { | 143 | Id 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 | ||
| 69 | struct StorageTypeDefinition { | 105 | struct 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 | ||
| 10 | struct Profile { | 10 | struct 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 | ||
| 86 | enum class NvidiaArchitecture { | ||
| 87 | KeplerOrOlder, | ||
| 88 | Maxwell, | ||
| 89 | Pascal, | ||
| 90 | Volta, | ||
| 91 | Turing, | ||
| 92 | AmpereOrNewer, | ||
| 93 | }; | ||
| 94 | |||
| 95 | template <typename T> | 86 | template <typename T> |
| 96 | void SetNext(void**& next, T& data) { | 87 | void 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 | ||
| 362 | std::vector<const char*> ExtensionListForVulkan( | 353 | std::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). |
| 178 | const u32 GuestWarpSize = 32; | 178 | const u32 GuestWarpSize = 32; |
| 179 | 179 | ||
| 180 | enum 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. |
| 181 | class Device { | 190 | class Device { |
| 182 | public: | 191 | public: |
| @@ -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 | |||
| 673 | private: | 690 | private: |
| 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 |
| 117 | const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{ | 117 | const 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) { | |||
| 319 | void ConfigureHotkeys::RestoreDefaults() { | 319 | void 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 | ||
| 127 | void ConfigureVibration::StopVibrations() { | 127 | void ConfigureVibration::StopVibrations() { |