diff options
Diffstat (limited to 'src')
25 files changed, 410 insertions, 185 deletions
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index 7265c4171..bf3434e1c 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h | |||
| @@ -223,7 +223,13 @@ bool operator<(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) { | |||
| 223 | 223 | ||
| 224 | class KeyManager { | 224 | class KeyManager { |
| 225 | public: | 225 | public: |
| 226 | KeyManager(); | 226 | static KeyManager& instance() { |
| 227 | static KeyManager instance; | ||
| 228 | return instance; | ||
| 229 | } | ||
| 230 | |||
| 231 | KeyManager(KeyManager const&) = delete; | ||
| 232 | void operator=(KeyManager const&) = delete; | ||
| 227 | 233 | ||
| 228 | bool HasKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const; | 234 | bool HasKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const; |
| 229 | bool HasKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const; | 235 | bool HasKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const; |
| @@ -257,6 +263,8 @@ public: | |||
| 257 | bool AddTicketPersonalized(Ticket raw); | 263 | bool AddTicketPersonalized(Ticket raw); |
| 258 | 264 | ||
| 259 | private: | 265 | private: |
| 266 | KeyManager(); | ||
| 267 | |||
| 260 | std::map<KeyIndex<S128KeyType>, Key128> s128_keys; | 268 | std::map<KeyIndex<S128KeyType>, Key128> s128_keys; |
| 261 | std::map<KeyIndex<S256KeyType>, Key256> s256_keys; | 269 | std::map<KeyIndex<S256KeyType>, Key256> s256_keys; |
| 262 | 270 | ||
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp index 0af44f340..464ca6503 100644 --- a/src/core/file_sys/bis_factory.cpp +++ b/src/core/file_sys/bis_factory.cpp | |||
| @@ -79,7 +79,7 @@ VirtualDir BISFactory::OpenPartition(BisPartitionId id) const { | |||
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id) const { | 81 | VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id) const { |
| 82 | Core::Crypto::KeyManager keys; | 82 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); |
| 83 | Core::Crypto::PartitionDataManager pdm{ | 83 | Core::Crypto::PartitionDataManager pdm{ |
| 84 | Core::System::GetInstance().GetFilesystem()->OpenDirectory( | 84 | Core::System::GetInstance().GetFilesystem()->OpenDirectory( |
| 85 | FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), Mode::Read)}; | 85 | FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), Mode::Read)}; |
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 07d0c8d5d..664a47e7f 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp | |||
| @@ -178,7 +178,7 @@ u32 XCI::GetSystemUpdateVersion() { | |||
| 178 | return 0; | 178 | return 0; |
| 179 | 179 | ||
| 180 | for (const auto& file : update->GetFiles()) { | 180 | for (const auto& file : update->GetFiles()) { |
| 181 | NCA nca{file, nullptr, 0, keys}; | 181 | NCA nca{file, nullptr, 0}; |
| 182 | 182 | ||
| 183 | if (nca.GetStatus() != Loader::ResultStatus::Success) | 183 | if (nca.GetStatus() != Loader::ResultStatus::Success) |
| 184 | continue; | 184 | continue; |
| @@ -286,7 +286,7 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { | |||
| 286 | continue; | 286 | continue; |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | auto nca = std::make_shared<NCA>(file, nullptr, 0, keys); | 289 | auto nca = std::make_shared<NCA>(file, nullptr, 0); |
| 290 | if (nca->IsUpdate()) { | 290 | if (nca->IsUpdate()) { |
| 291 | continue; | 291 | continue; |
| 292 | } | 292 | } |
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index c2ee0ea99..a09d504ae 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h | |||
| @@ -140,6 +140,6 @@ private: | |||
| 140 | 140 | ||
| 141 | u64 update_normal_partition_end; | 141 | u64 update_normal_partition_end; |
| 142 | 142 | ||
| 143 | Core::Crypto::KeyManager keys; | 143 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); |
| 144 | }; | 144 | }; |
| 145 | } // namespace FileSys | 145 | } // namespace FileSys |
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index b8bbdd1ef..473245d5a 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp | |||
| @@ -118,9 +118,8 @@ static bool IsValidNCA(const NCAHeader& header) { | |||
| 118 | return header.magic == Common::MakeMagic('N', 'C', 'A', '3'); | 118 | return header.magic == Common::MakeMagic('N', 'C', 'A', '3'); |
| 119 | } | 119 | } |
| 120 | 120 | ||
| 121 | NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset, | 121 | NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset) |
| 122 | Core::Crypto::KeyManager keys_) | 122 | : file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)) { |
| 123 | : file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)), keys(std::move(keys_)) { | ||
| 124 | if (file == nullptr) { | 123 | if (file == nullptr) { |
| 125 | status = Loader::ResultStatus::ErrorNullFile; | 124 | status = Loader::ResultStatus::ErrorNullFile; |
| 126 | return; | 125 | return; |
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index e249079b5..e6c887b32 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h | |||
| @@ -99,8 +99,7 @@ inline bool IsDirectoryLogoPartition(const VirtualDir& pfs) { | |||
| 99 | class NCA : public ReadOnlyVfsDirectory { | 99 | class NCA : public ReadOnlyVfsDirectory { |
| 100 | public: | 100 | public: |
| 101 | explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr, | 101 | explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr, |
| 102 | u64 bktr_base_ivfc_offset = 0, | 102 | u64 bktr_base_ivfc_offset = 0); |
| 103 | Core::Crypto::KeyManager keys = Core::Crypto::KeyManager()); | ||
| 104 | ~NCA() override; | 103 | ~NCA() override; |
| 105 | 104 | ||
| 106 | Loader::ResultStatus GetStatus() const; | 105 | Loader::ResultStatus GetStatus() const; |
| @@ -159,7 +158,7 @@ private: | |||
| 159 | bool encrypted = false; | 158 | bool encrypted = false; |
| 160 | bool is_update = false; | 159 | bool is_update = false; |
| 161 | 160 | ||
| 162 | Core::Crypto::KeyManager keys; | 161 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); |
| 163 | }; | 162 | }; |
| 164 | 163 | ||
| 165 | } // namespace FileSys | 164 | } // namespace FileSys |
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index ba5f76288..27c1b0233 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp | |||
| @@ -408,7 +408,7 @@ void RegisteredCache::ProcessFiles(const std::vector<NcaID>& ids) { | |||
| 408 | 408 | ||
| 409 | if (file == nullptr) | 409 | if (file == nullptr) |
| 410 | continue; | 410 | continue; |
| 411 | const auto nca = std::make_shared<NCA>(parser(file, id), nullptr, 0, keys); | 411 | const auto nca = std::make_shared<NCA>(parser(file, id), nullptr, 0); |
| 412 | if (nca->GetStatus() != Loader::ResultStatus::Success || | 412 | if (nca->GetStatus() != Loader::ResultStatus::Success || |
| 413 | nca->GetType() != NCAContentType::Meta) { | 413 | nca->GetType() != NCAContentType::Meta) { |
| 414 | continue; | 414 | continue; |
| @@ -486,7 +486,7 @@ std::unique_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType t | |||
| 486 | const auto raw = GetEntryRaw(title_id, type); | 486 | const auto raw = GetEntryRaw(title_id, type); |
| 487 | if (raw == nullptr) | 487 | if (raw == nullptr) |
| 488 | return nullptr; | 488 | return nullptr; |
| 489 | return std::make_unique<NCA>(raw, nullptr, 0, keys); | 489 | return std::make_unique<NCA>(raw, nullptr, 0); |
| 490 | } | 490 | } |
| 491 | 491 | ||
| 492 | template <typename T> | 492 | template <typename T> |
| @@ -865,7 +865,7 @@ std::unique_ptr<NCA> ManualContentProvider::GetEntry(u64 title_id, ContentRecord | |||
| 865 | const auto res = GetEntryRaw(title_id, type); | 865 | const auto res = GetEntryRaw(title_id, type); |
| 866 | if (res == nullptr) | 866 | if (res == nullptr) |
| 867 | return nullptr; | 867 | return nullptr; |
| 868 | return std::make_unique<NCA>(res, nullptr, 0, keys); | 868 | return std::make_unique<NCA>(res, nullptr, 0); |
| 869 | } | 869 | } |
| 870 | 870 | ||
| 871 | std::vector<ContentProviderEntry> ManualContentProvider::ListEntriesFilter( | 871 | std::vector<ContentProviderEntry> ManualContentProvider::ListEntriesFilter( |
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index d1eec240e..4b2fb08cb 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h | |||
| @@ -88,7 +88,7 @@ public: | |||
| 88 | 88 | ||
| 89 | protected: | 89 | protected: |
| 90 | // A single instance of KeyManager to be used by GetEntry() | 90 | // A single instance of KeyManager to be used by GetEntry() |
| 91 | Core::Crypto::KeyManager keys; | 91 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); |
| 92 | }; | 92 | }; |
| 93 | 93 | ||
| 94 | class PlaceholderCache { | 94 | class PlaceholderCache { |
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp index ef3084681..c35a0d10b 100644 --- a/src/core/file_sys/submission_package.cpp +++ b/src/core/file_sys/submission_package.cpp | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | namespace FileSys { | 21 | namespace FileSys { |
| 22 | namespace { | 22 | namespace { |
| 23 | void SetTicketKeys(const std::vector<VirtualFile>& files) { | 23 | void SetTicketKeys(const std::vector<VirtualFile>& files) { |
| 24 | Core::Crypto::KeyManager keys; | 24 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); |
| 25 | 25 | ||
| 26 | for (const auto& ticket_file : files) { | 26 | for (const auto& ticket_file : files) { |
| 27 | if (ticket_file == nullptr) { | 27 | if (ticket_file == nullptr) { |
| @@ -285,7 +285,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) { | |||
| 285 | continue; | 285 | continue; |
| 286 | } | 286 | } |
| 287 | 287 | ||
| 288 | auto next_nca = std::make_shared<NCA>(std::move(next_file), nullptr, 0, keys); | 288 | auto next_nca = std::make_shared<NCA>(std::move(next_file), nullptr, 0); |
| 289 | if (next_nca->GetType() == NCAContentType::Program) { | 289 | if (next_nca->GetType() == NCAContentType::Program) { |
| 290 | program_status[cnmt.GetTitleID()] = next_nca->GetStatus(); | 290 | program_status[cnmt.GetTitleID()] = next_nca->GetStatus(); |
| 291 | } | 291 | } |
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h index ee9b6ce17..bd577f6e5 100644 --- a/src/core/file_sys/submission_package.h +++ b/src/core/file_sys/submission_package.h | |||
| @@ -73,7 +73,7 @@ private: | |||
| 73 | std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas; | 73 | std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas; |
| 74 | std::vector<VirtualFile> ticket_files; | 74 | std::vector<VirtualFile> ticket_files; |
| 75 | 75 | ||
| 76 | Core::Crypto::KeyManager keys; | 76 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); |
| 77 | 77 | ||
| 78 | VirtualFile romfs; | 78 | VirtualFile romfs; |
| 79 | VirtualDir exefs; | 79 | VirtualDir exefs; |
diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h index 7704dee90..95da907bc 100644 --- a/src/core/file_sys/xts_archive.h +++ b/src/core/file_sys/xts_archive.h | |||
| @@ -62,6 +62,6 @@ private: | |||
| 62 | 62 | ||
| 63 | VirtualFile dec_file; | 63 | VirtualFile dec_file; |
| 64 | 64 | ||
| 65 | Core::Crypto::KeyManager keys; | 65 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); |
| 66 | }; | 66 | }; |
| 67 | } // namespace FileSys | 67 | } // namespace FileSys |
diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index 9365f27e1..da6b74a22 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp | |||
| @@ -302,7 +302,7 @@ private: | |||
| 302 | rb.Push<u64>(write_size); | 302 | rb.Push<u64>(write_size); |
| 303 | } | 303 | } |
| 304 | 304 | ||
| 305 | Core::Crypto::KeyManager keys; | 305 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); |
| 306 | }; | 306 | }; |
| 307 | 307 | ||
| 308 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 308 | void InstallInterfaces(SM::ServiceManager& service_manager) { |
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index 14309c679..67833d9af 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp | |||
| @@ -75,8 +75,13 @@ private: | |||
| 75 | const auto user_id = rp.PopRaw<u128>(); | 75 | const auto user_id = rp.PopRaw<u128>(); |
| 76 | const auto process_id = rp.PopRaw<u64>(); | 76 | const auto process_id = rp.PopRaw<u64>(); |
| 77 | std::vector<std::vector<u8>> data{ctx.ReadBuffer(0)}; | 77 | std::vector<std::vector<u8>> data{ctx.ReadBuffer(0)}; |
| 78 | |||
| 78 | if constexpr (Type == Core::Reporter::PlayReportType::Old2) { | 79 | if constexpr (Type == Core::Reporter::PlayReportType::Old2) { |
| 79 | data.emplace_back(ctx.ReadBuffer(1)); | 80 | const auto read_buffer_count = |
| 81 | ctx.BufferDescriptorX().size() + ctx.BufferDescriptorA().size(); | ||
| 82 | if (read_buffer_count > 1) { | ||
| 83 | data.emplace_back(ctx.ReadBuffer(1)); | ||
| 84 | } | ||
| 80 | } | 85 | } |
| 81 | 86 | ||
| 82 | LOG_DEBUG( | 87 | LOG_DEBUG( |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 2dc752aa9..21c46a567 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -3,6 +3,8 @@ add_library(video_core STATIC | |||
| 3 | buffer_cache/buffer_cache.h | 3 | buffer_cache/buffer_cache.h |
| 4 | buffer_cache/map_interval.cpp | 4 | buffer_cache/map_interval.cpp |
| 5 | buffer_cache/map_interval.h | 5 | buffer_cache/map_interval.h |
| 6 | compatible_formats.cpp | ||
| 7 | compatible_formats.h | ||
| 6 | dirty_flags.cpp | 8 | dirty_flags.cpp |
| 7 | dirty_flags.h | 9 | dirty_flags.h |
| 8 | dma_pusher.cpp | 10 | dma_pusher.cpp |
diff --git a/src/video_core/compatible_formats.cpp b/src/video_core/compatible_formats.cpp new file mode 100644 index 000000000..6c426b035 --- /dev/null +++ b/src/video_core/compatible_formats.cpp | |||
| @@ -0,0 +1,162 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <array> | ||
| 6 | #include <bitset> | ||
| 7 | #include <cstddef> | ||
| 8 | |||
| 9 | #include "video_core/compatible_formats.h" | ||
| 10 | #include "video_core/surface.h" | ||
| 11 | |||
| 12 | namespace VideoCore::Surface { | ||
| 13 | |||
| 14 | namespace { | ||
| 15 | |||
| 16 | // Compatibility table taken from Table 3.X.2 in: | ||
| 17 | // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_texture_view.txt | ||
| 18 | |||
| 19 | constexpr std::array VIEW_CLASS_128_BITS = { | ||
| 20 | PixelFormat::RGBA32F, | ||
| 21 | PixelFormat::RGBA32UI, | ||
| 22 | }; | ||
| 23 | // Missing formats: | ||
| 24 | // PixelFormat::RGBA32I | ||
| 25 | |||
| 26 | constexpr std::array VIEW_CLASS_96_BITS = { | ||
| 27 | PixelFormat::RGB32F, | ||
| 28 | }; | ||
| 29 | // Missing formats: | ||
| 30 | // PixelFormat::RGB32UI, | ||
| 31 | // PixelFormat::RGB32I, | ||
| 32 | |||
| 33 | constexpr std::array VIEW_CLASS_64_BITS = { | ||
| 34 | PixelFormat::RGBA16F, PixelFormat::RG32F, PixelFormat::RGBA16UI, PixelFormat::RG32UI, | ||
| 35 | PixelFormat::RGBA16U, PixelFormat::RGBA16F, PixelFormat::RGBA16S, | ||
| 36 | }; | ||
| 37 | // Missing formats: | ||
| 38 | // PixelFormat::RGBA16I | ||
| 39 | // PixelFormat::RG32I | ||
| 40 | |||
| 41 | // TODO: How should we handle 48 bits? | ||
| 42 | |||
| 43 | constexpr std::array VIEW_CLASS_32_BITS = { | ||
| 44 | PixelFormat::RG16F, PixelFormat::R11FG11FB10F, PixelFormat::R32F, | ||
| 45 | PixelFormat::A2B10G10R10U, PixelFormat::RG16UI, PixelFormat::R32UI, | ||
| 46 | PixelFormat::RG16I, PixelFormat::R32I, PixelFormat::ABGR8U, | ||
| 47 | PixelFormat::RG16, PixelFormat::ABGR8S, PixelFormat::RG16S, | ||
| 48 | PixelFormat::RGBA8_SRGB, PixelFormat::E5B9G9R9F, PixelFormat::BGRA8, | ||
| 49 | PixelFormat::BGRA8_SRGB, | ||
| 50 | }; | ||
| 51 | // Missing formats: | ||
| 52 | // PixelFormat::RGBA8UI | ||
| 53 | // PixelFormat::RGBA8I | ||
| 54 | // PixelFormat::RGB10_A2_UI | ||
| 55 | |||
| 56 | // TODO: How should we handle 24 bits? | ||
| 57 | |||
| 58 | constexpr std::array VIEW_CLASS_16_BITS = { | ||
| 59 | PixelFormat::R16F, PixelFormat::RG8UI, PixelFormat::R16UI, PixelFormat::R16I, | ||
| 60 | PixelFormat::RG8U, PixelFormat::R16U, PixelFormat::RG8S, PixelFormat::R16S, | ||
| 61 | }; | ||
| 62 | // Missing formats: | ||
| 63 | // PixelFormat::RG8I | ||
| 64 | |||
| 65 | constexpr std::array VIEW_CLASS_8_BITS = { | ||
| 66 | PixelFormat::R8UI, | ||
| 67 | PixelFormat::R8U, | ||
| 68 | }; | ||
| 69 | // Missing formats: | ||
| 70 | // PixelFormat::R8I | ||
| 71 | // PixelFormat::R8S | ||
| 72 | |||
| 73 | constexpr std::array VIEW_CLASS_RGTC1_RED = { | ||
| 74 | PixelFormat::DXN1, | ||
| 75 | }; | ||
| 76 | // Missing formats: | ||
| 77 | // COMPRESSED_SIGNED_RED_RGTC1 | ||
| 78 | |||
| 79 | constexpr std::array VIEW_CLASS_RGTC2_RG = { | ||
| 80 | PixelFormat::DXN2UNORM, | ||
| 81 | PixelFormat::DXN2SNORM, | ||
| 82 | }; | ||
| 83 | |||
| 84 | constexpr std::array VIEW_CLASS_BPTC_UNORM = { | ||
| 85 | PixelFormat::BC7U, | ||
| 86 | PixelFormat::BC7U_SRGB, | ||
| 87 | }; | ||
| 88 | |||
| 89 | constexpr std::array VIEW_CLASS_BPTC_FLOAT = { | ||
| 90 | PixelFormat::BC6H_SF16, | ||
| 91 | PixelFormat::BC6H_UF16, | ||
| 92 | }; | ||
| 93 | |||
| 94 | // Compatibility table taken from Table 4.X.1 in: | ||
| 95 | // https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_copy_image.txt | ||
| 96 | |||
| 97 | constexpr std::array COPY_CLASS_128_BITS = { | ||
| 98 | PixelFormat::RGBA32UI, PixelFormat::RGBA32F, PixelFormat::DXT23, | ||
| 99 | PixelFormat::DXT23_SRGB, PixelFormat::DXT45, PixelFormat::DXT45_SRGB, | ||
| 100 | PixelFormat::DXN2SNORM, PixelFormat::BC7U, PixelFormat::BC7U_SRGB, | ||
| 101 | PixelFormat::BC6H_SF16, PixelFormat::BC6H_UF16, | ||
| 102 | }; | ||
| 103 | // Missing formats: | ||
| 104 | // PixelFormat::RGBA32I | ||
| 105 | // COMPRESSED_RG_RGTC2 | ||
| 106 | |||
| 107 | constexpr std::array COPY_CLASS_64_BITS = { | ||
| 108 | PixelFormat::RGBA16F, PixelFormat::RG32F, PixelFormat::RGBA16UI, PixelFormat::RG32UI, | ||
| 109 | PixelFormat::RGBA16U, PixelFormat::RGBA16S, PixelFormat::DXT1_SRGB, PixelFormat::DXT1, | ||
| 110 | |||
| 111 | }; | ||
| 112 | // Missing formats: | ||
| 113 | // PixelFormat::RGBA16I | ||
| 114 | // PixelFormat::RG32I, | ||
| 115 | // COMPRESSED_RGB_S3TC_DXT1_EXT | ||
| 116 | // COMPRESSED_SRGB_S3TC_DXT1_EXT | ||
| 117 | // COMPRESSED_RGBA_S3TC_DXT1_EXT | ||
| 118 | // COMPRESSED_SIGNED_RED_RGTC1 | ||
| 119 | |||
| 120 | void Enable(FormatCompatibility::Table& compatiblity, size_t format_a, size_t format_b) { | ||
| 121 | compatiblity[format_a][format_b] = true; | ||
| 122 | compatiblity[format_b][format_a] = true; | ||
| 123 | } | ||
| 124 | |||
| 125 | void Enable(FormatCompatibility::Table& compatibility, PixelFormat format_a, PixelFormat format_b) { | ||
| 126 | Enable(compatibility, static_cast<size_t>(format_a), static_cast<size_t>(format_b)); | ||
| 127 | } | ||
| 128 | |||
| 129 | template <typename Range> | ||
| 130 | void EnableRange(FormatCompatibility::Table& compatibility, const Range& range) { | ||
| 131 | for (auto it_a = range.begin(); it_a != range.end(); ++it_a) { | ||
| 132 | for (auto it_b = it_a; it_b != range.end(); ++it_b) { | ||
| 133 | Enable(compatibility, *it_a, *it_b); | ||
| 134 | } | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | } // Anonymous namespace | ||
| 139 | |||
| 140 | FormatCompatibility::FormatCompatibility() { | ||
| 141 | for (size_t i = 0; i < MaxPixelFormat; ++i) { | ||
| 142 | // Identity is allowed | ||
| 143 | Enable(view, i, i); | ||
| 144 | } | ||
| 145 | |||
| 146 | EnableRange(view, VIEW_CLASS_128_BITS); | ||
| 147 | EnableRange(view, VIEW_CLASS_96_BITS); | ||
| 148 | EnableRange(view, VIEW_CLASS_64_BITS); | ||
| 149 | EnableRange(view, VIEW_CLASS_32_BITS); | ||
| 150 | EnableRange(view, VIEW_CLASS_16_BITS); | ||
| 151 | EnableRange(view, VIEW_CLASS_8_BITS); | ||
| 152 | EnableRange(view, VIEW_CLASS_RGTC1_RED); | ||
| 153 | EnableRange(view, VIEW_CLASS_RGTC2_RG); | ||
| 154 | EnableRange(view, VIEW_CLASS_BPTC_UNORM); | ||
| 155 | EnableRange(view, VIEW_CLASS_BPTC_FLOAT); | ||
| 156 | |||
| 157 | copy = view; | ||
| 158 | EnableRange(copy, COPY_CLASS_128_BITS); | ||
| 159 | EnableRange(copy, COPY_CLASS_64_BITS); | ||
| 160 | } | ||
| 161 | |||
| 162 | } // namespace VideoCore::Surface | ||
diff --git a/src/video_core/compatible_formats.h b/src/video_core/compatible_formats.h new file mode 100644 index 000000000..d1082566d --- /dev/null +++ b/src/video_core/compatible_formats.h | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <array> | ||
| 6 | #include <bitset> | ||
| 7 | #include <cstddef> | ||
| 8 | |||
| 9 | #include "video_core/surface.h" | ||
| 10 | |||
| 11 | namespace VideoCore::Surface { | ||
| 12 | |||
| 13 | class FormatCompatibility { | ||
| 14 | public: | ||
| 15 | using Table = std::array<std::bitset<MaxPixelFormat>, MaxPixelFormat>; | ||
| 16 | |||
| 17 | explicit FormatCompatibility(); | ||
| 18 | |||
| 19 | bool TestView(PixelFormat format_a, PixelFormat format_b) const noexcept { | ||
| 20 | return view[static_cast<size_t>(format_a)][static_cast<size_t>(format_b)]; | ||
| 21 | } | ||
| 22 | |||
| 23 | bool TestCopy(PixelFormat format_a, PixelFormat format_b) const noexcept { | ||
| 24 | return copy[static_cast<size_t>(format_a)][static_cast<size_t>(format_b)]; | ||
| 25 | } | ||
| 26 | |||
| 27 | private: | ||
| 28 | Table view; | ||
| 29 | Table copy; | ||
| 30 | }; | ||
| 31 | |||
| 32 | } // namespace VideoCore::Surface | ||
diff --git a/src/video_core/macro/macro.cpp b/src/video_core/macro/macro.cpp index ef7dad349..a50e7b4e0 100644 --- a/src/video_core/macro/macro.cpp +++ b/src/video_core/macro/macro.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <optional> | ||
| 5 | #include <boost/container_hash/hash.hpp> | 6 | #include <boost/container_hash/hash.hpp> |
| 6 | #include "common/assert.h" | 7 | #include "common/assert.h" |
| 7 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| @@ -35,22 +36,40 @@ void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method, | |||
| 35 | } | 36 | } |
| 36 | } else { | 37 | } else { |
| 37 | // Macro not compiled, check if it's uploaded and if so, compile it | 38 | // Macro not compiled, check if it's uploaded and if so, compile it |
| 38 | auto macro_code = uploaded_macro_code.find(method); | 39 | std::optional<u32> mid_method = std::nullopt; |
| 40 | const auto macro_code = uploaded_macro_code.find(method); | ||
| 39 | if (macro_code == uploaded_macro_code.end()) { | 41 | if (macro_code == uploaded_macro_code.end()) { |
| 40 | UNREACHABLE_MSG("Macro 0x{0:x} was not uploaded", method); | 42 | for (const auto& [method_base, code] : uploaded_macro_code) { |
| 41 | return; | 43 | if (method >= method_base && (method - method_base) < code.size()) { |
| 44 | mid_method = method_base; | ||
| 45 | break; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | if (!mid_method.has_value()) { | ||
| 49 | UNREACHABLE_MSG("Macro 0x{0:x} was not uploaded", method); | ||
| 50 | return; | ||
| 51 | } | ||
| 42 | } | 52 | } |
| 43 | auto& cache_info = macro_cache[method]; | 53 | auto& cache_info = macro_cache[method]; |
| 44 | cache_info.hash = boost::hash_value(macro_code->second); | 54 | |
| 45 | cache_info.lle_program = Compile(macro_code->second); | 55 | if (!mid_method.has_value()) { |
| 56 | cache_info.lle_program = Compile(macro_code->second); | ||
| 57 | cache_info.hash = boost::hash_value(macro_code->second); | ||
| 58 | } else { | ||
| 59 | const auto& macro_cached = uploaded_macro_code[mid_method.value()]; | ||
| 60 | const auto rebased_method = method - mid_method.value(); | ||
| 61 | auto& code = uploaded_macro_code[method]; | ||
| 62 | code.resize(macro_cached.size() - rebased_method); | ||
| 63 | std::memcpy(code.data(), macro_cached.data() + rebased_method, | ||
| 64 | code.size() * sizeof(u32)); | ||
| 65 | cache_info.hash = boost::hash_value(code); | ||
| 66 | cache_info.lle_program = Compile(code); | ||
| 67 | } | ||
| 46 | 68 | ||
| 47 | auto hle_program = hle_macros->GetHLEProgram(cache_info.hash); | 69 | auto hle_program = hle_macros->GetHLEProgram(cache_info.hash); |
| 48 | if (hle_program.has_value()) { | 70 | if (hle_program.has_value()) { |
| 49 | cache_info.has_hle_program = true; | 71 | cache_info.has_hle_program = true; |
| 50 | cache_info.hle_program = std::move(hle_program.value()); | 72 | cache_info.hle_program = std::move(hle_program.value()); |
| 51 | } | ||
| 52 | |||
| 53 | if (cache_info.has_hle_program) { | ||
| 54 | cache_info.hle_program->Execute(parameters, method); | 73 | cache_info.hle_program->Execute(parameters, method); |
| 55 | } else { | 74 | } else { |
| 56 | cache_info.lle_program->Execute(parameters, method); | 75 | cache_info.lle_program->Execute(parameters, method); |
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index b6b6659c1..208fc6167 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp | |||
| @@ -188,20 +188,6 @@ bool IsASTCSupported() { | |||
| 188 | return true; | 188 | return true; |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | /// @brief Returns true when a GL_RENDERER is a Turing GPU | ||
| 192 | /// @param renderer GL_RENDERER string | ||
| 193 | bool IsTuring(std::string_view renderer) { | ||
| 194 | static constexpr std::array<std::string_view, 12> TURING_GPUS = { | ||
| 195 | "GTX 1650", "GTX 1660", "RTX 2060", "RTX 2070", | ||
| 196 | "RTX 2080", "TITAN RTX", "Quadro RTX 3000", "Quadro RTX 4000", | ||
| 197 | "Quadro RTX 5000", "Quadro RTX 6000", "Quadro RTX 8000", "Tesla T4", | ||
| 198 | }; | ||
| 199 | return std::any_of(TURING_GPUS.begin(), TURING_GPUS.end(), | ||
| 200 | [renderer](std::string_view candidate) { | ||
| 201 | return renderer.find(candidate) != std::string_view::npos; | ||
| 202 | }); | ||
| 203 | } | ||
| 204 | |||
| 205 | } // Anonymous namespace | 191 | } // Anonymous namespace |
| 206 | 192 | ||
| 207 | Device::Device() | 193 | Device::Device() |
| @@ -213,7 +199,6 @@ Device::Device() | |||
| 213 | 199 | ||
| 214 | const bool is_nvidia = vendor == "NVIDIA Corporation"; | 200 | const bool is_nvidia = vendor == "NVIDIA Corporation"; |
| 215 | const bool is_amd = vendor == "ATI Technologies Inc."; | 201 | const bool is_amd = vendor == "ATI Technologies Inc."; |
| 216 | const bool is_turing = is_nvidia && IsTuring(renderer); | ||
| 217 | 202 | ||
| 218 | bool disable_fast_buffer_sub_data = false; | 203 | bool disable_fast_buffer_sub_data = false; |
| 219 | if (is_nvidia && version == "4.6.0 NVIDIA 443.24") { | 204 | if (is_nvidia && version == "4.6.0 NVIDIA 443.24") { |
| @@ -238,15 +223,12 @@ Device::Device() | |||
| 238 | has_component_indexing_bug = is_amd; | 223 | has_component_indexing_bug = is_amd; |
| 239 | has_precise_bug = TestPreciseBug(); | 224 | has_precise_bug = TestPreciseBug(); |
| 240 | has_nv_viewport_array2 = GLAD_GL_NV_viewport_array2; | 225 | has_nv_viewport_array2 = GLAD_GL_NV_viewport_array2; |
| 226 | has_vertex_buffer_unified_memory = GLAD_GL_NV_vertex_buffer_unified_memory; | ||
| 241 | 227 | ||
| 242 | // At the moment of writing this, only Nvidia's driver optimizes BufferSubData on exclusive | 228 | // At the moment of writing this, only Nvidia's driver optimizes BufferSubData on exclusive |
| 243 | // uniform buffers as "push constants" | 229 | // uniform buffers as "push constants" |
| 244 | has_fast_buffer_sub_data = is_nvidia && !disable_fast_buffer_sub_data; | 230 | has_fast_buffer_sub_data = is_nvidia && !disable_fast_buffer_sub_data; |
| 245 | 231 | ||
| 246 | // Nvidia's driver on Turing GPUs randomly crashes when the buffer is made resident, or on | ||
| 247 | // DeleteBuffers. Disable unified memory on these devices. | ||
| 248 | has_vertex_buffer_unified_memory = GLAD_GL_NV_vertex_buffer_unified_memory && !is_turing; | ||
| 249 | |||
| 250 | use_assembly_shaders = Settings::values.use_assembly_shaders && GLAD_GL_NV_gpu_program5 && | 232 | use_assembly_shaders = Settings::values.use_assembly_shaders && GLAD_GL_NV_gpu_program5 && |
| 251 | GLAD_GL_NV_compute_program5 && GLAD_GL_NV_transform_feedback && | 233 | GLAD_GL_NV_compute_program5 && GLAD_GL_NV_transform_feedback && |
| 252 | GLAD_GL_NV_transform_feedback2; | 234 | GLAD_GL_NV_transform_feedback2; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 362457ffe..e960a0ef1 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -213,9 +213,10 @@ void RasterizerOpenGL::SetupVertexFormat() { | |||
| 213 | if (attrib.type == Maxwell::VertexAttribute::Type::SignedInt || | 213 | if (attrib.type == Maxwell::VertexAttribute::Type::SignedInt || |
| 214 | attrib.type == Maxwell::VertexAttribute::Type::UnsignedInt) { | 214 | attrib.type == Maxwell::VertexAttribute::Type::UnsignedInt) { |
| 215 | glVertexAttribIFormat(gl_index, attrib.ComponentCount(), | 215 | glVertexAttribIFormat(gl_index, attrib.ComponentCount(), |
| 216 | MaxwellToGL::VertexType(attrib), attrib.offset); | 216 | MaxwellToGL::VertexFormat(attrib), attrib.offset); |
| 217 | } else { | 217 | } else { |
| 218 | glVertexAttribFormat(gl_index, attrib.ComponentCount(), MaxwellToGL::VertexType(attrib), | 218 | glVertexAttribFormat(gl_index, attrib.ComponentCount(), |
| 219 | MaxwellToGL::VertexFormat(attrib), | ||
| 219 | attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset); | 220 | attrib.IsNormalized() ? GL_TRUE : GL_FALSE, attrib.offset); |
| 220 | } | 221 | } |
| 221 | glVertexAttribBinding(gl_index, attrib.buffer); | 222 | glVertexAttribBinding(gl_index, attrib.buffer); |
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 35e329240..774e70a5b 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h | |||
| @@ -24,10 +24,11 @@ namespace MaxwellToGL { | |||
| 24 | 24 | ||
| 25 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | 25 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
| 26 | 26 | ||
| 27 | inline GLenum VertexType(Maxwell::VertexAttribute attrib) { | 27 | inline GLenum VertexFormat(Maxwell::VertexAttribute attrib) { |
| 28 | switch (attrib.type) { | 28 | switch (attrib.type) { |
| 29 | case Maxwell::VertexAttribute::Type::UnsignedInt: | ||
| 30 | case Maxwell::VertexAttribute::Type::UnsignedNorm: | 29 | case Maxwell::VertexAttribute::Type::UnsignedNorm: |
| 30 | case Maxwell::VertexAttribute::Type::UnsignedScaled: | ||
| 31 | case Maxwell::VertexAttribute::Type::UnsignedInt: | ||
| 31 | switch (attrib.size) { | 32 | switch (attrib.size) { |
| 32 | case Maxwell::VertexAttribute::Size::Size_8: | 33 | case Maxwell::VertexAttribute::Size::Size_8: |
| 33 | case Maxwell::VertexAttribute::Size::Size_8_8: | 34 | case Maxwell::VertexAttribute::Size::Size_8_8: |
| @@ -48,8 +49,9 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) { | |||
| 48 | return GL_UNSIGNED_INT_2_10_10_10_REV; | 49 | return GL_UNSIGNED_INT_2_10_10_10_REV; |
| 49 | } | 50 | } |
| 50 | break; | 51 | break; |
| 51 | case Maxwell::VertexAttribute::Type::SignedInt: | ||
| 52 | case Maxwell::VertexAttribute::Type::SignedNorm: | 52 | case Maxwell::VertexAttribute::Type::SignedNorm: |
| 53 | case Maxwell::VertexAttribute::Type::SignedScaled: | ||
| 54 | case Maxwell::VertexAttribute::Type::SignedInt: | ||
| 53 | switch (attrib.size) { | 55 | switch (attrib.size) { |
| 54 | case Maxwell::VertexAttribute::Size::Size_8: | 56 | case Maxwell::VertexAttribute::Size::Size_8: |
| 55 | case Maxwell::VertexAttribute::Size::Size_8_8: | 57 | case Maxwell::VertexAttribute::Size::Size_8_8: |
| @@ -84,36 +86,8 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) { | |||
| 84 | return GL_FLOAT; | 86 | return GL_FLOAT; |
| 85 | } | 87 | } |
| 86 | break; | 88 | break; |
| 87 | case Maxwell::VertexAttribute::Type::UnsignedScaled: | ||
| 88 | switch (attrib.size) { | ||
| 89 | case Maxwell::VertexAttribute::Size::Size_8: | ||
| 90 | case Maxwell::VertexAttribute::Size::Size_8_8: | ||
| 91 | case Maxwell::VertexAttribute::Size::Size_8_8_8: | ||
| 92 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: | ||
| 93 | return GL_UNSIGNED_BYTE; | ||
| 94 | case Maxwell::VertexAttribute::Size::Size_16: | ||
| 95 | case Maxwell::VertexAttribute::Size::Size_16_16: | ||
| 96 | case Maxwell::VertexAttribute::Size::Size_16_16_16: | ||
| 97 | case Maxwell::VertexAttribute::Size::Size_16_16_16_16: | ||
| 98 | return GL_UNSIGNED_SHORT; | ||
| 99 | } | ||
| 100 | break; | ||
| 101 | case Maxwell::VertexAttribute::Type::SignedScaled: | ||
| 102 | switch (attrib.size) { | ||
| 103 | case Maxwell::VertexAttribute::Size::Size_8: | ||
| 104 | case Maxwell::VertexAttribute::Size::Size_8_8: | ||
| 105 | case Maxwell::VertexAttribute::Size::Size_8_8_8: | ||
| 106 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: | ||
| 107 | return GL_BYTE; | ||
| 108 | case Maxwell::VertexAttribute::Size::Size_16: | ||
| 109 | case Maxwell::VertexAttribute::Size::Size_16_16: | ||
| 110 | case Maxwell::VertexAttribute::Size::Size_16_16_16: | ||
| 111 | case Maxwell::VertexAttribute::Size::Size_16_16_16_16: | ||
| 112 | return GL_SHORT; | ||
| 113 | } | ||
| 114 | break; | ||
| 115 | } | 89 | } |
| 116 | UNIMPLEMENTED_MSG("Unimplemented vertex type={} and size={}", attrib.TypeString(), | 90 | UNIMPLEMENTED_MSG("Unimplemented vertex format of type={} and size={}", attrib.TypeString(), |
| 117 | attrib.SizeString()); | 91 | attrib.SizeString()); |
| 118 | return {}; | 92 | return {}; |
| 119 | } | 93 | } |
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp index 1f2b6734b..d7f1ae89f 100644 --- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp +++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp | |||
| @@ -294,6 +294,28 @@ VkPrimitiveTopology PrimitiveTopology([[maybe_unused]] const VKDevice& device, | |||
| 294 | 294 | ||
| 295 | VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttribute::Size size) { | 295 | VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttribute::Size size) { |
| 296 | switch (type) { | 296 | switch (type) { |
| 297 | case Maxwell::VertexAttribute::Type::UnsignedNorm: | ||
| 298 | switch (size) { | ||
| 299 | case Maxwell::VertexAttribute::Size::Size_8: | ||
| 300 | return VK_FORMAT_R8_UNORM; | ||
| 301 | case Maxwell::VertexAttribute::Size::Size_8_8: | ||
| 302 | return VK_FORMAT_R8G8_UNORM; | ||
| 303 | case Maxwell::VertexAttribute::Size::Size_8_8_8: | ||
| 304 | return VK_FORMAT_R8G8B8_UNORM; | ||
| 305 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: | ||
| 306 | return VK_FORMAT_R8G8B8A8_UNORM; | ||
| 307 | case Maxwell::VertexAttribute::Size::Size_16: | ||
| 308 | return VK_FORMAT_R16_UNORM; | ||
| 309 | case Maxwell::VertexAttribute::Size::Size_16_16: | ||
| 310 | return VK_FORMAT_R16G16_UNORM; | ||
| 311 | case Maxwell::VertexAttribute::Size::Size_16_16_16: | ||
| 312 | return VK_FORMAT_R16G16B16_UNORM; | ||
| 313 | case Maxwell::VertexAttribute::Size::Size_16_16_16_16: | ||
| 314 | return VK_FORMAT_R16G16B16A16_UNORM; | ||
| 315 | case Maxwell::VertexAttribute::Size::Size_10_10_10_2: | ||
| 316 | return VK_FORMAT_A2B10G10R10_UNORM_PACK32; | ||
| 317 | } | ||
| 318 | break; | ||
| 297 | case Maxwell::VertexAttribute::Type::SignedNorm: | 319 | case Maxwell::VertexAttribute::Type::SignedNorm: |
| 298 | switch (size) { | 320 | switch (size) { |
| 299 | case Maxwell::VertexAttribute::Size::Size_8: | 321 | case Maxwell::VertexAttribute::Size::Size_8: |
| @@ -314,62 +336,50 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib | |||
| 314 | return VK_FORMAT_R16G16B16A16_SNORM; | 336 | return VK_FORMAT_R16G16B16A16_SNORM; |
| 315 | case Maxwell::VertexAttribute::Size::Size_10_10_10_2: | 337 | case Maxwell::VertexAttribute::Size::Size_10_10_10_2: |
| 316 | return VK_FORMAT_A2B10G10R10_SNORM_PACK32; | 338 | return VK_FORMAT_A2B10G10R10_SNORM_PACK32; |
| 317 | default: | ||
| 318 | break; | ||
| 319 | } | 339 | } |
| 320 | break; | 340 | break; |
| 321 | case Maxwell::VertexAttribute::Type::UnsignedNorm: | 341 | case Maxwell::VertexAttribute::Type::UnsignedScaled: |
| 322 | switch (size) { | 342 | switch (size) { |
| 323 | case Maxwell::VertexAttribute::Size::Size_8: | 343 | case Maxwell::VertexAttribute::Size::Size_8: |
| 324 | return VK_FORMAT_R8_UNORM; | 344 | return VK_FORMAT_R8_USCALED; |
| 325 | case Maxwell::VertexAttribute::Size::Size_8_8: | 345 | case Maxwell::VertexAttribute::Size::Size_8_8: |
| 326 | return VK_FORMAT_R8G8_UNORM; | 346 | return VK_FORMAT_R8G8_USCALED; |
| 327 | case Maxwell::VertexAttribute::Size::Size_8_8_8: | 347 | case Maxwell::VertexAttribute::Size::Size_8_8_8: |
| 328 | return VK_FORMAT_R8G8B8_UNORM; | 348 | return VK_FORMAT_R8G8B8_USCALED; |
| 329 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: | 349 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: |
| 330 | return VK_FORMAT_R8G8B8A8_UNORM; | 350 | return VK_FORMAT_R8G8B8A8_USCALED; |
| 331 | case Maxwell::VertexAttribute::Size::Size_16: | 351 | case Maxwell::VertexAttribute::Size::Size_16: |
| 332 | return VK_FORMAT_R16_UNORM; | 352 | return VK_FORMAT_R16_USCALED; |
| 333 | case Maxwell::VertexAttribute::Size::Size_16_16: | 353 | case Maxwell::VertexAttribute::Size::Size_16_16: |
| 334 | return VK_FORMAT_R16G16_UNORM; | 354 | return VK_FORMAT_R16G16_USCALED; |
| 335 | case Maxwell::VertexAttribute::Size::Size_16_16_16: | 355 | case Maxwell::VertexAttribute::Size::Size_16_16_16: |
| 336 | return VK_FORMAT_R16G16B16_UNORM; | 356 | return VK_FORMAT_R16G16B16_USCALED; |
| 337 | case Maxwell::VertexAttribute::Size::Size_16_16_16_16: | 357 | case Maxwell::VertexAttribute::Size::Size_16_16_16_16: |
| 338 | return VK_FORMAT_R16G16B16A16_UNORM; | 358 | return VK_FORMAT_R16G16B16A16_USCALED; |
| 339 | case Maxwell::VertexAttribute::Size::Size_10_10_10_2: | 359 | case Maxwell::VertexAttribute::Size::Size_10_10_10_2: |
| 340 | return VK_FORMAT_A2B10G10R10_UNORM_PACK32; | 360 | return VK_FORMAT_A2B10G10R10_USCALED_PACK32; |
| 341 | default: | ||
| 342 | break; | ||
| 343 | } | 361 | } |
| 344 | break; | 362 | break; |
| 345 | case Maxwell::VertexAttribute::Type::SignedInt: | 363 | case Maxwell::VertexAttribute::Type::SignedScaled: |
| 346 | switch (size) { | 364 | switch (size) { |
| 347 | case Maxwell::VertexAttribute::Size::Size_8: | 365 | case Maxwell::VertexAttribute::Size::Size_8: |
| 348 | return VK_FORMAT_R8_SINT; | 366 | return VK_FORMAT_R8_SSCALED; |
| 349 | case Maxwell::VertexAttribute::Size::Size_8_8: | 367 | case Maxwell::VertexAttribute::Size::Size_8_8: |
| 350 | return VK_FORMAT_R8G8_SINT; | 368 | return VK_FORMAT_R8G8_SSCALED; |
| 351 | case Maxwell::VertexAttribute::Size::Size_8_8_8: | 369 | case Maxwell::VertexAttribute::Size::Size_8_8_8: |
| 352 | return VK_FORMAT_R8G8B8_SINT; | 370 | return VK_FORMAT_R8G8B8_SSCALED; |
| 353 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: | 371 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: |
| 354 | return VK_FORMAT_R8G8B8A8_SINT; | 372 | return VK_FORMAT_R8G8B8A8_SSCALED; |
| 355 | case Maxwell::VertexAttribute::Size::Size_16: | 373 | case Maxwell::VertexAttribute::Size::Size_16: |
| 356 | return VK_FORMAT_R16_SINT; | 374 | return VK_FORMAT_R16_SSCALED; |
| 357 | case Maxwell::VertexAttribute::Size::Size_16_16: | 375 | case Maxwell::VertexAttribute::Size::Size_16_16: |
| 358 | return VK_FORMAT_R16G16_SINT; | 376 | return VK_FORMAT_R16G16_SSCALED; |
| 359 | case Maxwell::VertexAttribute::Size::Size_16_16_16: | 377 | case Maxwell::VertexAttribute::Size::Size_16_16_16: |
| 360 | return VK_FORMAT_R16G16B16_SINT; | 378 | return VK_FORMAT_R16G16B16_SSCALED; |
| 361 | case Maxwell::VertexAttribute::Size::Size_16_16_16_16: | 379 | case Maxwell::VertexAttribute::Size::Size_16_16_16_16: |
| 362 | return VK_FORMAT_R16G16B16A16_SINT; | 380 | return VK_FORMAT_R16G16B16A16_SSCALED; |
| 363 | case Maxwell::VertexAttribute::Size::Size_32: | 381 | case Maxwell::VertexAttribute::Size::Size_10_10_10_2: |
| 364 | return VK_FORMAT_R32_SINT; | 382 | return VK_FORMAT_A2B10G10R10_SSCALED_PACK32; |
| 365 | case Maxwell::VertexAttribute::Size::Size_32_32: | ||
| 366 | return VK_FORMAT_R32G32_SINT; | ||
| 367 | case Maxwell::VertexAttribute::Size::Size_32_32_32: | ||
| 368 | return VK_FORMAT_R32G32B32_SINT; | ||
| 369 | case Maxwell::VertexAttribute::Size::Size_32_32_32_32: | ||
| 370 | return VK_FORMAT_R32G32B32A32_SINT; | ||
| 371 | default: | ||
| 372 | break; | ||
| 373 | } | 383 | } |
| 374 | break; | 384 | break; |
| 375 | case Maxwell::VertexAttribute::Type::UnsignedInt: | 385 | case Maxwell::VertexAttribute::Type::UnsignedInt: |
| @@ -398,56 +408,50 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib | |||
| 398 | return VK_FORMAT_R32G32B32_UINT; | 408 | return VK_FORMAT_R32G32B32_UINT; |
| 399 | case Maxwell::VertexAttribute::Size::Size_32_32_32_32: | 409 | case Maxwell::VertexAttribute::Size::Size_32_32_32_32: |
| 400 | return VK_FORMAT_R32G32B32A32_UINT; | 410 | return VK_FORMAT_R32G32B32A32_UINT; |
| 401 | default: | 411 | case Maxwell::VertexAttribute::Size::Size_10_10_10_2: |
| 402 | break; | 412 | return VK_FORMAT_A2B10G10R10_UINT_PACK32; |
| 403 | } | 413 | } |
| 404 | break; | 414 | break; |
| 405 | case Maxwell::VertexAttribute::Type::UnsignedScaled: | 415 | case Maxwell::VertexAttribute::Type::SignedInt: |
| 406 | switch (size) { | 416 | switch (size) { |
| 407 | case Maxwell::VertexAttribute::Size::Size_8: | 417 | case Maxwell::VertexAttribute::Size::Size_8: |
| 408 | return VK_FORMAT_R8_USCALED; | 418 | return VK_FORMAT_R8_SINT; |
| 409 | case Maxwell::VertexAttribute::Size::Size_8_8: | 419 | case Maxwell::VertexAttribute::Size::Size_8_8: |
| 410 | return VK_FORMAT_R8G8_USCALED; | 420 | return VK_FORMAT_R8G8_SINT; |
| 411 | case Maxwell::VertexAttribute::Size::Size_8_8_8: | 421 | case Maxwell::VertexAttribute::Size::Size_8_8_8: |
| 412 | return VK_FORMAT_R8G8B8_USCALED; | 422 | return VK_FORMAT_R8G8B8_SINT; |
| 413 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: | 423 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: |
| 414 | return VK_FORMAT_R8G8B8A8_USCALED; | 424 | return VK_FORMAT_R8G8B8A8_SINT; |
| 415 | case Maxwell::VertexAttribute::Size::Size_16: | 425 | case Maxwell::VertexAttribute::Size::Size_16: |
| 416 | return VK_FORMAT_R16_USCALED; | 426 | return VK_FORMAT_R16_SINT; |
| 417 | case Maxwell::VertexAttribute::Size::Size_16_16: | 427 | case Maxwell::VertexAttribute::Size::Size_16_16: |
| 418 | return VK_FORMAT_R16G16_USCALED; | 428 | return VK_FORMAT_R16G16_SINT; |
| 419 | case Maxwell::VertexAttribute::Size::Size_16_16_16: | 429 | case Maxwell::VertexAttribute::Size::Size_16_16_16: |
| 420 | return VK_FORMAT_R16G16B16_USCALED; | 430 | return VK_FORMAT_R16G16B16_SINT; |
| 421 | case Maxwell::VertexAttribute::Size::Size_16_16_16_16: | 431 | case Maxwell::VertexAttribute::Size::Size_16_16_16_16: |
| 422 | return VK_FORMAT_R16G16B16A16_USCALED; | 432 | return VK_FORMAT_R16G16B16A16_SINT; |
| 423 | default: | 433 | case Maxwell::VertexAttribute::Size::Size_32: |
| 424 | break; | 434 | return VK_FORMAT_R32_SINT; |
| 435 | case Maxwell::VertexAttribute::Size::Size_32_32: | ||
| 436 | return VK_FORMAT_R32G32_SINT; | ||
| 437 | case Maxwell::VertexAttribute::Size::Size_32_32_32: | ||
| 438 | return VK_FORMAT_R32G32B32_SINT; | ||
| 439 | case Maxwell::VertexAttribute::Size::Size_32_32_32_32: | ||
| 440 | return VK_FORMAT_R32G32B32A32_SINT; | ||
| 441 | case Maxwell::VertexAttribute::Size::Size_10_10_10_2: | ||
| 442 | return VK_FORMAT_A2B10G10R10_SINT_PACK32; | ||
| 425 | } | 443 | } |
| 426 | break; | 444 | break; |
| 427 | case Maxwell::VertexAttribute::Type::SignedScaled: | 445 | case Maxwell::VertexAttribute::Type::Float: |
| 428 | switch (size) { | 446 | switch (size) { |
| 429 | case Maxwell::VertexAttribute::Size::Size_8: | ||
| 430 | return VK_FORMAT_R8_SSCALED; | ||
| 431 | case Maxwell::VertexAttribute::Size::Size_8_8: | ||
| 432 | return VK_FORMAT_R8G8_SSCALED; | ||
| 433 | case Maxwell::VertexAttribute::Size::Size_8_8_8: | ||
| 434 | return VK_FORMAT_R8G8B8_SSCALED; | ||
| 435 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: | ||
| 436 | return VK_FORMAT_R8G8B8A8_SSCALED; | ||
| 437 | case Maxwell::VertexAttribute::Size::Size_16: | 447 | case Maxwell::VertexAttribute::Size::Size_16: |
| 438 | return VK_FORMAT_R16_SSCALED; | 448 | return VK_FORMAT_R16_SFLOAT; |
| 439 | case Maxwell::VertexAttribute::Size::Size_16_16: | 449 | case Maxwell::VertexAttribute::Size::Size_16_16: |
| 440 | return VK_FORMAT_R16G16_SSCALED; | 450 | return VK_FORMAT_R16G16_SFLOAT; |
| 441 | case Maxwell::VertexAttribute::Size::Size_16_16_16: | 451 | case Maxwell::VertexAttribute::Size::Size_16_16_16: |
| 442 | return VK_FORMAT_R16G16B16_SSCALED; | 452 | return VK_FORMAT_R16G16B16_SFLOAT; |
| 443 | case Maxwell::VertexAttribute::Size::Size_16_16_16_16: | 453 | case Maxwell::VertexAttribute::Size::Size_16_16_16_16: |
| 444 | return VK_FORMAT_R16G16B16A16_SSCALED; | 454 | return VK_FORMAT_R16G16B16A16_SFLOAT; |
| 445 | default: | ||
| 446 | break; | ||
| 447 | } | ||
| 448 | break; | ||
| 449 | case Maxwell::VertexAttribute::Type::Float: | ||
| 450 | switch (size) { | ||
| 451 | case Maxwell::VertexAttribute::Size::Size_32: | 455 | case Maxwell::VertexAttribute::Size::Size_32: |
| 452 | return VK_FORMAT_R32_SFLOAT; | 456 | return VK_FORMAT_R32_SFLOAT; |
| 453 | case Maxwell::VertexAttribute::Size::Size_32_32: | 457 | case Maxwell::VertexAttribute::Size::Size_32_32: |
| @@ -456,16 +460,6 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib | |||
| 456 | return VK_FORMAT_R32G32B32_SFLOAT; | 460 | return VK_FORMAT_R32G32B32_SFLOAT; |
| 457 | case Maxwell::VertexAttribute::Size::Size_32_32_32_32: | 461 | case Maxwell::VertexAttribute::Size::Size_32_32_32_32: |
| 458 | return VK_FORMAT_R32G32B32A32_SFLOAT; | 462 | return VK_FORMAT_R32G32B32A32_SFLOAT; |
| 459 | case Maxwell::VertexAttribute::Size::Size_16: | ||
| 460 | return VK_FORMAT_R16_SFLOAT; | ||
| 461 | case Maxwell::VertexAttribute::Size::Size_16_16: | ||
| 462 | return VK_FORMAT_R16G16_SFLOAT; | ||
| 463 | case Maxwell::VertexAttribute::Size::Size_16_16_16: | ||
| 464 | return VK_FORMAT_R16G16B16_SFLOAT; | ||
| 465 | case Maxwell::VertexAttribute::Size::Size_16_16_16_16: | ||
| 466 | return VK_FORMAT_R16G16B16A16_SFLOAT; | ||
| 467 | default: | ||
| 468 | break; | ||
| 469 | } | 463 | } |
| 470 | break; | 464 | break; |
| 471 | } | 465 | } |
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 85075e868..6207d8dfe 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include "core/core.h" | 24 | #include "core/core.h" |
| 25 | #include "core/memory.h" | 25 | #include "core/memory.h" |
| 26 | #include "core/settings.h" | 26 | #include "core/settings.h" |
| 27 | #include "video_core/compatible_formats.h" | ||
| 27 | #include "video_core/dirty_flags.h" | 28 | #include "video_core/dirty_flags.h" |
| 28 | #include "video_core/engines/fermi_2d.h" | 29 | #include "video_core/engines/fermi_2d.h" |
| 29 | #include "video_core/engines/maxwell_3d.h" | 30 | #include "video_core/engines/maxwell_3d.h" |
| @@ -47,8 +48,8 @@ class RasterizerInterface; | |||
| 47 | 48 | ||
| 48 | namespace VideoCommon { | 49 | namespace VideoCommon { |
| 49 | 50 | ||
| 51 | using VideoCore::Surface::FormatCompatibility; | ||
| 50 | using VideoCore::Surface::PixelFormat; | 52 | using VideoCore::Surface::PixelFormat; |
| 51 | |||
| 52 | using VideoCore::Surface::SurfaceTarget; | 53 | using VideoCore::Surface::SurfaceTarget; |
| 53 | using RenderTargetConfig = Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig; | 54 | using RenderTargetConfig = Tegra::Engines::Maxwell3D::Regs::RenderTargetConfig; |
| 54 | 55 | ||
| @@ -595,7 +596,7 @@ private: | |||
| 595 | } else { | 596 | } else { |
| 596 | new_surface = GetUncachedSurface(gpu_addr, params); | 597 | new_surface = GetUncachedSurface(gpu_addr, params); |
| 597 | } | 598 | } |
| 598 | const auto& final_params = new_surface->GetSurfaceParams(); | 599 | const SurfaceParams& final_params = new_surface->GetSurfaceParams(); |
| 599 | if (cr_params.type != final_params.type) { | 600 | if (cr_params.type != final_params.type) { |
| 600 | if (Settings::IsGPULevelExtreme()) { | 601 | if (Settings::IsGPULevelExtreme()) { |
| 601 | BufferCopy(current_surface, new_surface); | 602 | BufferCopy(current_surface, new_surface); |
| @@ -603,7 +604,7 @@ private: | |||
| 603 | } else { | 604 | } else { |
| 604 | std::vector<CopyParams> bricks = current_surface->BreakDown(final_params); | 605 | std::vector<CopyParams> bricks = current_surface->BreakDown(final_params); |
| 605 | for (auto& brick : bricks) { | 606 | for (auto& brick : bricks) { |
| 606 | ImageCopy(current_surface, new_surface, brick); | 607 | TryCopyImage(current_surface, new_surface, brick); |
| 607 | } | 608 | } |
| 608 | } | 609 | } |
| 609 | Unregister(current_surface); | 610 | Unregister(current_surface); |
| @@ -694,7 +695,7 @@ private: | |||
| 694 | } | 695 | } |
| 695 | const CopyParams copy_params(0, 0, 0, 0, 0, base_layer, 0, mipmap, width, height, | 696 | const CopyParams copy_params(0, 0, 0, 0, 0, base_layer, 0, mipmap, width, height, |
| 696 | src_params.depth); | 697 | src_params.depth); |
| 697 | ImageCopy(surface, new_surface, copy_params); | 698 | TryCopyImage(surface, new_surface, copy_params); |
| 698 | } | 699 | } |
| 699 | } | 700 | } |
| 700 | if (passed_tests == 0) { | 701 | if (passed_tests == 0) { |
| @@ -791,7 +792,7 @@ private: | |||
| 791 | const u32 width = params.width; | 792 | const u32 width = params.width; |
| 792 | const u32 height = params.height; | 793 | const u32 height = params.height; |
| 793 | const CopyParams copy_params(0, 0, 0, 0, 0, slice, 0, 0, width, height, 1); | 794 | const CopyParams copy_params(0, 0, 0, 0, 0, slice, 0, 0, width, height, 1); |
| 794 | ImageCopy(surface, new_surface, copy_params); | 795 | TryCopyImage(surface, new_surface, copy_params); |
| 795 | } | 796 | } |
| 796 | for (const auto& surface : overlaps) { | 797 | for (const auto& surface : overlaps) { |
| 797 | Unregister(surface); | 798 | Unregister(surface); |
| @@ -1192,6 +1193,19 @@ private: | |||
| 1192 | return {}; | 1193 | return {}; |
| 1193 | } | 1194 | } |
| 1194 | 1195 | ||
| 1196 | /// Try to do an image copy logging when formats are incompatible. | ||
| 1197 | void TryCopyImage(TSurface& src, TSurface& dst, const CopyParams& copy) { | ||
| 1198 | const SurfaceParams& src_params = src->GetSurfaceParams(); | ||
| 1199 | const SurfaceParams& dst_params = dst->GetSurfaceParams(); | ||
| 1200 | if (!format_compatibility.TestCopy(src_params.pixel_format, dst_params.pixel_format)) { | ||
| 1201 | LOG_ERROR(HW_GPU, "Illegal copy between formats={{{}, {}}}", | ||
| 1202 | static_cast<int>(dst_params.pixel_format), | ||
| 1203 | static_cast<int>(src_params.pixel_format)); | ||
| 1204 | return; | ||
| 1205 | } | ||
| 1206 | ImageCopy(src, dst, copy); | ||
| 1207 | } | ||
| 1208 | |||
| 1195 | constexpr PixelFormat GetSiblingFormat(PixelFormat format) const { | 1209 | constexpr PixelFormat GetSiblingFormat(PixelFormat format) const { |
| 1196 | return siblings_table[static_cast<std::size_t>(format)]; | 1210 | return siblings_table[static_cast<std::size_t>(format)]; |
| 1197 | } | 1211 | } |
| @@ -1241,6 +1255,7 @@ private: | |||
| 1241 | VideoCore::RasterizerInterface& rasterizer; | 1255 | VideoCore::RasterizerInterface& rasterizer; |
| 1242 | 1256 | ||
| 1243 | FormatLookupTable format_lookup_table; | 1257 | FormatLookupTable format_lookup_table; |
| 1258 | FormatCompatibility format_compatibility; | ||
| 1244 | 1259 | ||
| 1245 | u64 ticks{}; | 1260 | u64 ticks{}; |
| 1246 | 1261 | ||
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 82625e67f..f586950e7 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -689,6 +689,11 @@ void GMainWindow::InitializeHotkeys() { | |||
| 689 | ui.action_Capture_Screenshot->setShortcutContext( | 689 | ui.action_Capture_Screenshot->setShortcutContext( |
| 690 | hotkey_registry.GetShortcutContext(main_window, capture_screenshot)); | 690 | hotkey_registry.GetShortcutContext(main_window, capture_screenshot)); |
| 691 | 691 | ||
| 692 | ui.action_Fullscreen->setShortcut( | ||
| 693 | hotkey_registry.GetHotkey(main_window, fullscreen, this)->key()); | ||
| 694 | ui.action_Fullscreen->setShortcutContext( | ||
| 695 | hotkey_registry.GetShortcutContext(main_window, fullscreen)); | ||
| 696 | |||
| 692 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this), | 697 | connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Load File"), this), |
| 693 | &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile); | 698 | &QShortcut::activated, this, &GMainWindow::OnMenuLoadFile); |
| 694 | connect( | 699 | connect( |
| @@ -863,6 +868,9 @@ void GMainWindow::ConnectMenuEvents() { | |||
| 863 | connect(ui.action_Report_Compatibility, &QAction::triggered, this, | 868 | connect(ui.action_Report_Compatibility, &QAction::triggered, this, |
| 864 | &GMainWindow::OnMenuReportCompatibility); | 869 | &GMainWindow::OnMenuReportCompatibility); |
| 865 | connect(ui.action_Open_Mods_Page, &QAction::triggered, this, &GMainWindow::OnOpenModsPage); | 870 | connect(ui.action_Open_Mods_Page, &QAction::triggered, this, &GMainWindow::OnOpenModsPage); |
| 871 | connect(ui.action_Open_Quickstart_Guide, &QAction::triggered, this, | ||
| 872 | &GMainWindow::OnOpenQuickstartGuide); | ||
| 873 | connect(ui.action_Open_FAQ, &QAction::triggered, this, &GMainWindow::OnOpenFAQ); | ||
| 866 | connect(ui.action_Restart, &QAction::triggered, this, [this] { BootGame(QString(game_path)); }); | 874 | connect(ui.action_Restart, &QAction::triggered, this, [this] { BootGame(QString(game_path)); }); |
| 867 | connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure); | 875 | connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure); |
| 868 | 876 | ||
| @@ -876,10 +884,6 @@ void GMainWindow::ConnectMenuEvents() { | |||
| 876 | connect(ui.action_Reset_Window_Size, &QAction::triggered, this, &GMainWindow::ResetWindowSize); | 884 | connect(ui.action_Reset_Window_Size, &QAction::triggered, this, &GMainWindow::ResetWindowSize); |
| 877 | 885 | ||
| 878 | // Fullscreen | 886 | // Fullscreen |
| 879 | ui.action_Fullscreen->setShortcut( | ||
| 880 | hotkey_registry | ||
| 881 | .GetHotkey(QStringLiteral("Main Window"), QStringLiteral("Fullscreen"), this) | ||
| 882 | ->key()); | ||
| 883 | connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); | 887 | connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen); |
| 884 | 888 | ||
| 885 | // Movie | 889 | // Movie |
| @@ -1077,17 +1081,19 @@ void GMainWindow::BootGame(const QString& filename) { | |||
| 1077 | const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); | 1081 | const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); |
| 1078 | 1082 | ||
| 1079 | std::string title_name; | 1083 | std::string title_name; |
| 1084 | std::string title_version; | ||
| 1080 | const auto res = Core::System::GetInstance().GetGameName(title_name); | 1085 | const auto res = Core::System::GetInstance().GetGameName(title_name); |
| 1081 | if (res != Loader::ResultStatus::Success) { | ||
| 1082 | const auto metadata = FileSys::PatchManager(title_id).GetControlMetadata(); | ||
| 1083 | if (metadata.first != nullptr) | ||
| 1084 | title_name = metadata.first->GetApplicationName(); | ||
| 1085 | 1086 | ||
| 1086 | if (title_name.empty()) | 1087 | const auto metadata = FileSys::PatchManager(title_id).GetControlMetadata(); |
| 1087 | title_name = FileUtil::GetFilename(filename.toStdString()); | 1088 | if (metadata.first != nullptr) { |
| 1089 | title_version = metadata.first->GetVersionString(); | ||
| 1090 | title_name = metadata.first->GetApplicationName(); | ||
| 1088 | } | 1091 | } |
| 1089 | LOG_INFO(Frontend, "Booting game: {:016X} | {}", title_id, title_name); | 1092 | if (res != Loader::ResultStatus::Success || title_name.empty()) { |
| 1090 | UpdateWindowTitle(QString::fromStdString(title_name)); | 1093 | title_name = FileUtil::GetFilename(filename.toStdString()); |
| 1094 | } | ||
| 1095 | LOG_INFO(Frontend, "Booting game: {:016X} | {} | {}", title_id, title_name, title_version); | ||
| 1096 | UpdateWindowTitle(title_name, title_version); | ||
| 1091 | 1097 | ||
| 1092 | loading_screen->Prepare(Core::System::GetInstance().GetAppLoader()); | 1098 | loading_screen->Prepare(Core::System::GetInstance().GetAppLoader()); |
| 1093 | loading_screen->show(); | 1099 | loading_screen->show(); |
| @@ -1838,16 +1844,26 @@ void GMainWindow::OnMenuReportCompatibility() { | |||
| 1838 | } | 1844 | } |
| 1839 | } | 1845 | } |
| 1840 | 1846 | ||
| 1841 | void GMainWindow::OnOpenModsPage() { | 1847 | void GMainWindow::OpenURL(const QUrl& url) { |
| 1842 | const auto mods_page_url = QStringLiteral("https://github.com/yuzu-emu/yuzu/wiki/Switch-Mods"); | 1848 | const bool open = QDesktopServices::openUrl(url); |
| 1843 | const QUrl mods_page(mods_page_url); | ||
| 1844 | const bool open = QDesktopServices::openUrl(mods_page); | ||
| 1845 | if (!open) { | 1849 | if (!open) { |
| 1846 | QMessageBox::warning(this, tr("Error opening URL"), | 1850 | QMessageBox::warning(this, tr("Error opening URL"), |
| 1847 | tr("Unable to open the URL \"%1\".").arg(mods_page_url)); | 1851 | tr("Unable to open the URL \"%1\".").arg(url.toString())); |
| 1848 | } | 1852 | } |
| 1849 | } | 1853 | } |
| 1850 | 1854 | ||
| 1855 | void GMainWindow::OnOpenModsPage() { | ||
| 1856 | OpenURL(QUrl(QStringLiteral("https://github.com/yuzu-emu/yuzu/wiki/Switch-Mods"))); | ||
| 1857 | } | ||
| 1858 | |||
| 1859 | void GMainWindow::OnOpenQuickstartGuide() { | ||
| 1860 | OpenURL(QUrl(QStringLiteral("https://yuzu-emu.org/help/quickstart/"))); | ||
| 1861 | } | ||
| 1862 | |||
| 1863 | void GMainWindow::OnOpenFAQ() { | ||
| 1864 | OpenURL(QUrl(QStringLiteral("https://yuzu-emu.org/wiki/faq/"))); | ||
| 1865 | } | ||
| 1866 | |||
| 1851 | void GMainWindow::ToggleFullscreen() { | 1867 | void GMainWindow::ToggleFullscreen() { |
| 1852 | if (!emulation_running) { | 1868 | if (!emulation_running) { |
| 1853 | return; | 1869 | return; |
| @@ -2050,7 +2066,8 @@ void GMainWindow::OnCaptureScreenshot() { | |||
| 2050 | OnStartGame(); | 2066 | OnStartGame(); |
| 2051 | } | 2067 | } |
| 2052 | 2068 | ||
| 2053 | void GMainWindow::UpdateWindowTitle(const QString& title_name) { | 2069 | void GMainWindow::UpdateWindowTitle(const std::string& title_name, |
| 2070 | const std::string& title_version) { | ||
| 2054 | const auto full_name = std::string(Common::g_build_fullname); | 2071 | const auto full_name = std::string(Common::g_build_fullname); |
| 2055 | const auto branch_name = std::string(Common::g_scm_branch); | 2072 | const auto branch_name = std::string(Common::g_scm_branch); |
| 2056 | const auto description = std::string(Common::g_scm_desc); | 2073 | const auto description = std::string(Common::g_scm_desc); |
| @@ -2059,7 +2076,7 @@ void GMainWindow::UpdateWindowTitle(const QString& title_name) { | |||
| 2059 | const auto date = | 2076 | const auto date = |
| 2060 | QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd")).toStdString(); | 2077 | QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd")).toStdString(); |
| 2061 | 2078 | ||
| 2062 | if (title_name.isEmpty()) { | 2079 | if (title_name.empty()) { |
| 2063 | const auto fmt = std::string(Common::g_title_bar_format_idle); | 2080 | const auto fmt = std::string(Common::g_title_bar_format_idle); |
| 2064 | setWindowTitle(QString::fromStdString(fmt::format(fmt.empty() ? "yuzu {0}| {1}-{2}" : fmt, | 2081 | setWindowTitle(QString::fromStdString(fmt::format(fmt.empty() ? "yuzu {0}| {1}-{2}" : fmt, |
| 2065 | full_name, branch_name, description, | 2082 | full_name, branch_name, description, |
| @@ -2067,8 +2084,8 @@ void GMainWindow::UpdateWindowTitle(const QString& title_name) { | |||
| 2067 | } else { | 2084 | } else { |
| 2068 | const auto fmt = std::string(Common::g_title_bar_format_running); | 2085 | const auto fmt = std::string(Common::g_title_bar_format_running); |
| 2069 | setWindowTitle(QString::fromStdString( | 2086 | setWindowTitle(QString::fromStdString( |
| 2070 | fmt::format(fmt.empty() ? "yuzu {0}| {3} | {1}-{2}" : fmt, full_name, branch_name, | 2087 | fmt::format(fmt.empty() ? "yuzu {0}| {3} | {6} | {1}-{2}" : fmt, full_name, branch_name, |
| 2071 | description, title_name.toStdString(), date, build_id))); | 2088 | description, title_name, date, build_id, title_version))); |
| 2072 | } | 2089 | } |
| 2073 | } | 2090 | } |
| 2074 | 2091 | ||
| @@ -2209,7 +2226,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { | |||
| 2209 | "title.keys_autogenerated"); | 2226 | "title.keys_autogenerated"); |
| 2210 | } | 2227 | } |
| 2211 | 2228 | ||
| 2212 | Core::Crypto::KeyManager keys{}; | 2229 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); |
| 2213 | if (keys.BaseDeriveNecessary()) { | 2230 | if (keys.BaseDeriveNecessary()) { |
| 2214 | Core::Crypto::PartitionDataManager pdm{vfs->OpenDirectory( | 2231 | Core::Crypto::PartitionDataManager pdm{vfs->OpenDirectory( |
| 2215 | FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), FileSys::Mode::Read)}; | 2232 | FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), FileSys::Mode::Read)}; |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 5581874ed..66c84e5c0 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -182,6 +182,8 @@ private slots: | |||
| 182 | void OnStopGame(); | 182 | void OnStopGame(); |
| 183 | void OnMenuReportCompatibility(); | 183 | void OnMenuReportCompatibility(); |
| 184 | void OnOpenModsPage(); | 184 | void OnOpenModsPage(); |
| 185 | void OnOpenQuickstartGuide(); | ||
| 186 | void OnOpenFAQ(); | ||
| 185 | /// Called whenever a user selects a game in the game list widget. | 187 | /// Called whenever a user selects a game in the game list widget. |
| 186 | void OnGameListLoadFile(QString game_path); | 188 | void OnGameListLoadFile(QString game_path); |
| 187 | void OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path); | 189 | void OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path); |
| @@ -216,10 +218,12 @@ private slots: | |||
| 216 | 218 | ||
| 217 | private: | 219 | private: |
| 218 | std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); | 220 | std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); |
| 219 | void UpdateWindowTitle(const QString& title_name = {}); | 221 | void UpdateWindowTitle(const std::string& title_name = {}, |
| 222 | const std::string& title_version = {}); | ||
| 220 | void UpdateStatusBar(); | 223 | void UpdateStatusBar(); |
| 221 | void HideMouseCursor(); | 224 | void HideMouseCursor(); |
| 222 | void ShowMouseCursor(); | 225 | void ShowMouseCursor(); |
| 226 | void OpenURL(const QUrl& url); | ||
| 223 | 227 | ||
| 224 | Ui::MainWindow ui; | 228 | Ui::MainWindow ui; |
| 225 | 229 | ||
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index b5745dfd5..bee6e107e 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui | |||
| @@ -114,6 +114,8 @@ | |||
| 114 | </property> | 114 | </property> |
| 115 | <addaction name="action_Report_Compatibility"/> | 115 | <addaction name="action_Report_Compatibility"/> |
| 116 | <addaction name="action_Open_Mods_Page"/> | 116 | <addaction name="action_Open_Mods_Page"/> |
| 117 | <addaction name="action_Open_Quickstart_Guide"/> | ||
| 118 | <addaction name="action_Open_FAQ"/> | ||
| 117 | <addaction name="separator"/> | 119 | <addaction name="separator"/> |
| 118 | <addaction name="action_About"/> | 120 | <addaction name="action_About"/> |
| 119 | </widget> | 121 | </widget> |
| @@ -262,6 +264,16 @@ | |||
| 262 | <string>Open Mods Page</string> | 264 | <string>Open Mods Page</string> |
| 263 | </property> | 265 | </property> |
| 264 | </action> | 266 | </action> |
| 267 | <action name="action_Open_Quickstart_Guide"> | ||
| 268 | <property name="text"> | ||
| 269 | <string>Open Quickstart Guide</string> | ||
| 270 | </property> | ||
| 271 | </action> | ||
| 272 | <action name="action_Open_FAQ"> | ||
| 273 | <property name="text"> | ||
| 274 | <string>FAQ</string> | ||
| 275 | </property> | ||
| 276 | </action> | ||
| 265 | <action name="action_Open_yuzu_Folder"> | 277 | <action name="action_Open_yuzu_Folder"> |
| 266 | <property name="text"> | 278 | <property name="text"> |
| 267 | <string>Open yuzu Folder</string> | 279 | <string>Open yuzu Folder</string> |