summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/core.cpp26
-rw-r--r--src/core/core.h24
-rw-r--r--src/core/file_sys/card_image.cpp19
-rw-r--r--src/core/file_sys/content_archive.cpp86
-rw-r--r--src/core/file_sys/content_archive.h5
-rw-r--r--src/core/file_sys/partition_filesystem.cpp8
-rw-r--r--src/core/file_sys/program_metadata.cpp12
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp14
-rw-r--r--src/core/loader/elf.cpp2
-rw-r--r--src/core/loader/loader.cpp49
-rw-r--r--src/core/loader/loader.h46
-rw-r--r--src/core/loader/nca.cpp10
-rw-r--r--src/core/loader/nro.cpp10
-rw-r--r--src/core/loader/xci.cpp11
-rw-r--r--src/video_core/engines/shader_bytecode.h7
-rw-r--r--src/video_core/gpu.cpp2
-rw-r--r--src/video_core/gpu.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp47
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h106
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp39
-rw-r--r--src/yuzu/game_list.cpp5
-rw-r--r--src/yuzu/main.cpp76
-rw-r--r--src/yuzu_cmd/yuzu.cpp24
23 files changed, 379 insertions, 251 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 69c45c026..6b8004eb2 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -102,18 +102,8 @@ System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& file
102 LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!", 102 LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
103 static_cast<int>(system_mode.second)); 103 static_cast<int>(system_mode.second));
104 104
105 switch (system_mode.second) { 105 if (system_mode.second != Loader::ResultStatus::Success)
106 case Loader::ResultStatus::ErrorMissingKeys:
107 return ResultStatus::ErrorLoader_ErrorMissingKeys;
108 case Loader::ResultStatus::ErrorDecrypting:
109 return ResultStatus::ErrorLoader_ErrorDecrypting;
110 case Loader::ResultStatus::ErrorInvalidFormat:
111 return ResultStatus::ErrorLoader_ErrorInvalidFormat;
112 case Loader::ResultStatus::ErrorUnsupportedArch:
113 return ResultStatus::ErrorUnsupportedArch;
114 default:
115 return ResultStatus::ErrorSystemMode; 106 return ResultStatus::ErrorSystemMode;
116 }
117 } 107 }
118 108
119 ResultStatus init_result{Init(emu_window)}; 109 ResultStatus init_result{Init(emu_window)};
@@ -129,17 +119,9 @@ System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& file
129 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); 119 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
130 System::Shutdown(); 120 System::Shutdown();
131 121
132 switch (load_result) { 122 if (load_result != Loader::ResultStatus::Success) {
133 case Loader::ResultStatus::ErrorMissingKeys: 123 return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) +
134 return ResultStatus::ErrorLoader_ErrorMissingKeys; 124 static_cast<u32>(load_result));
135 case Loader::ResultStatus::ErrorDecrypting:
136 return ResultStatus::ErrorLoader_ErrorDecrypting;
137 case Loader::ResultStatus::ErrorInvalidFormat:
138 return ResultStatus::ErrorLoader_ErrorInvalidFormat;
139 case Loader::ResultStatus::ErrorUnsupportedArch:
140 return ResultStatus::ErrorUnsupportedArch;
141 default:
142 return ResultStatus::ErrorLoader;
143 } 125 }
144 } 126 }
145 status = ResultStatus::Success; 127 status = ResultStatus::Success;
diff --git a/src/core/core.h b/src/core/core.h
index 7cf7ea4e1..2944b09cd 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -49,21 +49,15 @@ public:
49 49
50 /// Enumeration representing the return values of the System Initialize and Load process. 50 /// Enumeration representing the return values of the System Initialize and Load process.
51 enum class ResultStatus : u32 { 51 enum class ResultStatus : u32 {
52 Success, ///< Succeeded 52 Success, ///< Succeeded
53 ErrorNotInitialized, ///< Error trying to use core prior to initialization 53 ErrorNotInitialized, ///< Error trying to use core prior to initialization
54 ErrorGetLoader, ///< Error finding the correct application loader 54 ErrorGetLoader, ///< Error finding the correct application loader
55 ErrorSystemMode, ///< Error determining the system mode 55 ErrorSystemMode, ///< Error determining the system mode
56 ErrorLoader, ///< Error loading the specified application 56 ErrorSystemFiles, ///< Error in finding system files
57 ErrorLoader_ErrorMissingKeys, ///< Error because the key/keys needed to run could not be 57 ErrorSharedFont, ///< Error in finding shared font
58 ///< found. 58 ErrorVideoCore, ///< Error in the video core
59 ErrorLoader_ErrorDecrypting, ///< Error loading the specified application due to encryption 59 ErrorUnknown, ///< Any other error
60 ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an 60 ErrorLoader, ///< The base for loader errors (too many to repeat)
61 /// invalid format
62 ErrorSystemFiles, ///< Error in finding system files
63 ErrorSharedFont, ///< Error in finding shared font
64 ErrorVideoCore, ///< Error in the video core
65 ErrorUnsupportedArch, ///< Unsupported Architecture (32-Bit ROMs)
66 ErrorUnknown ///< Any other error
67 }; 61 };
68 62
69 /** 63 /**
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index e897d9913..a4823353e 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -12,14 +12,16 @@
12 12
13namespace FileSys { 13namespace FileSys {
14 14
15constexpr std::array<const char*, 0x4> partition_names = {"update", "normal", "secure", "logo"};
16
15XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) { 17XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) {
16 if (file->ReadObject(&header) != sizeof(GamecardHeader)) { 18 if (file->ReadObject(&header) != sizeof(GamecardHeader)) {
17 status = Loader::ResultStatus::ErrorInvalidFormat; 19 status = Loader::ResultStatus::ErrorBadXCIHeader;
18 return; 20 return;
19 } 21 }
20 22
21 if (header.magic != Common::MakeMagic('H', 'E', 'A', 'D')) { 23 if (header.magic != Common::MakeMagic('H', 'E', 'A', 'D')) {
22 status = Loader::ResultStatus::ErrorInvalidFormat; 24 status = Loader::ResultStatus::ErrorBadXCIHeader;
23 return; 25 return;
24 } 26 }
25 27
@@ -31,9 +33,6 @@ XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) {
31 return; 33 return;
32 } 34 }
33 35
34 static constexpr std::array<const char*, 0x4> partition_names = {"update", "normal", "secure",
35 "logo"};
36
37 for (XCIPartition partition : 36 for (XCIPartition partition :
38 {XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) { 37 {XCIPartition::Update, XCIPartition::Normal, XCIPartition::Secure, XCIPartition::Logo}) {
39 auto raw = main_hfs.GetFile(partition_names[static_cast<size_t>(partition)]); 38 auto raw = main_hfs.GetFile(partition_names[static_cast<size_t>(partition)]);
@@ -130,15 +129,21 @@ bool XCI::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
130 129
131Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { 130Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
132 if (partitions[static_cast<size_t>(part)] == nullptr) { 131 if (partitions[static_cast<size_t>(part)] == nullptr) {
133 return Loader::ResultStatus::ErrorInvalidFormat; 132 return Loader::ResultStatus::ErrorXCIMissingPartition;
134 } 133 }
135 134
136 for (const VirtualFile& file : partitions[static_cast<size_t>(part)]->GetFiles()) { 135 for (const VirtualFile& file : partitions[static_cast<size_t>(part)]->GetFiles()) {
137 if (file->GetExtension() != "nca") 136 if (file->GetExtension() != "nca")
138 continue; 137 continue;
139 auto nca = std::make_shared<NCA>(file); 138 auto nca = std::make_shared<NCA>(file);
140 if (nca->GetStatus() == Loader::ResultStatus::Success) 139 if (nca->GetStatus() == Loader::ResultStatus::Success) {
141 ncas.push_back(std::move(nca)); 140 ncas.push_back(std::move(nca));
141 } else {
142 const u16 error_id = static_cast<u16>(nca->GetStatus());
143 LOG_CRITICAL(Loader, "Could not load NCA {}/{}, failed with error code {:04X} ({})",
144 partition_names[static_cast<size_t>(part)], nca->GetName(), error_id,
145 Loader::GetMessageForResultStatus(nca->GetStatus()));
146 }
142 } 147 }
143 148
144 return Loader::ResultStatus::Success; 149 return Loader::ResultStatus::Success;
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index d3007d981..47afcad9b 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -113,17 +113,27 @@ boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType ty
113 return out; 113 return out;
114} 114}
115 115
116boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() const { 116boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() {
117 const auto master_key_id = GetCryptoRevision(); 117 const auto master_key_id = GetCryptoRevision();
118 118
119 u128 rights_id{}; 119 u128 rights_id{};
120 memcpy(rights_id.data(), header.rights_id.data(), 16); 120 memcpy(rights_id.data(), header.rights_id.data(), 16);
121 if (rights_id == u128{}) 121 if (rights_id == u128{}) {
122 status = Loader::ResultStatus::ErrorInvalidRightsID;
122 return boost::none; 123 return boost::none;
124 }
123 125
124 auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]); 126 auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]);
125 if (titlekey == Core::Crypto::Key128{}) 127 if (titlekey == Core::Crypto::Key128{}) {
128 status = Loader::ResultStatus::ErrorMissingTitlekey;
129 return boost::none;
130 }
131
132 if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) {
133 status = Loader::ResultStatus::ErrorMissingTitlekek;
126 return boost::none; 134 return boost::none;
135 }
136
127 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher( 137 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
128 keys.GetKey(Core::Crypto::S128KeyType::Titlekek, master_key_id), Core::Crypto::Mode::ECB); 138 keys.GetKey(Core::Crypto::S128KeyType::Titlekek, master_key_id), Core::Crypto::Mode::ECB);
129 cipher.Transcode(titlekey.data(), titlekey.size(), titlekey.data(), Core::Crypto::Op::Decrypt); 139 cipher.Transcode(titlekey.data(), titlekey.size(), titlekey.data(), Core::Crypto::Op::Decrypt);
@@ -131,7 +141,7 @@ boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() const {
131 return titlekey; 141 return titlekey;
132} 142}
133 143
134VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting_offset) const { 144VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting_offset) {
135 if (!encrypted) 145 if (!encrypted)
136 return in; 146 return in;
137 147
@@ -143,15 +153,22 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting
143 LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset); 153 LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset);
144 { 154 {
145 boost::optional<Core::Crypto::Key128> key = boost::none; 155 boost::optional<Core::Crypto::Key128> key = boost::none;
146 if (std::find_if_not(header.rights_id.begin(), header.rights_id.end(), 156 if (has_rights_id) {
147 [](char c) { return c == 0; }) == header.rights_id.end()) { 157 status = Loader::ResultStatus::Success;
148 key = GetKeyAreaKey(NCASectionCryptoType::CTR);
149 } else {
150 key = GetTitlekey(); 158 key = GetTitlekey();
159 if (key == boost::none) {
160 if (status == Loader::ResultStatus::Success)
161 status = Loader::ResultStatus::ErrorMissingTitlekey;
162 return nullptr;
163 }
164 } else {
165 key = GetKeyAreaKey(NCASectionCryptoType::CTR);
166 if (key == boost::none) {
167 status = Loader::ResultStatus::ErrorMissingKeyAreaKey;
168 return nullptr;
169 }
151 } 170 }
152 171
153 if (key == boost::none)
154 return nullptr;
155 auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>( 172 auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(
156 std::move(in), key.value(), starting_offset); 173 std::move(in), key.value(), starting_offset);
157 std::vector<u8> iv(16); 174 std::vector<u8> iv(16);
@@ -170,16 +187,31 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting
170} 187}
171 188
172NCA::NCA(VirtualFile file_) : file(std::move(file_)) { 189NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
190 status = Loader::ResultStatus::Success;
191
173 if (file == nullptr) { 192 if (file == nullptr) {
174 status = Loader::ResultStatus::ErrorInvalidFormat; 193 status = Loader::ResultStatus::ErrorNullFile;
175 return; 194 return;
176 } 195 }
177 if (sizeof(NCAHeader) != file->ReadObject(&header)) 196
197 if (sizeof(NCAHeader) != file->ReadObject(&header)) {
178 LOG_ERROR(Loader, "File reader errored out during header read."); 198 LOG_ERROR(Loader, "File reader errored out during header read.");
199 status = Loader::ResultStatus::ErrorBadNCAHeader;
200 return;
201 }
179 202
180 encrypted = false; 203 encrypted = false;
181 204
182 if (!IsValidNCA(header)) { 205 if (!IsValidNCA(header)) {
206 if (header.magic == Common::MakeMagic('N', 'C', 'A', '2')) {
207 status = Loader::ResultStatus::ErrorNCA2;
208 return;
209 }
210 if (header.magic == Common::MakeMagic('N', 'C', 'A', '0')) {
211 status = Loader::ResultStatus::ErrorNCA0;
212 return;
213 }
214
183 NCAHeader dec_header{}; 215 NCAHeader dec_header{};
184 Core::Crypto::AESCipher<Core::Crypto::Key256> cipher( 216 Core::Crypto::AESCipher<Core::Crypto::Key256> cipher(
185 keys.GetKey(Core::Crypto::S256KeyType::Header), Core::Crypto::Mode::XTS); 217 keys.GetKey(Core::Crypto::S256KeyType::Header), Core::Crypto::Mode::XTS);
@@ -189,14 +221,26 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
189 header = dec_header; 221 header = dec_header;
190 encrypted = true; 222 encrypted = true;
191 } else { 223 } else {
224 if (dec_header.magic == Common::MakeMagic('N', 'C', 'A', '2')) {
225 status = Loader::ResultStatus::ErrorNCA2;
226 return;
227 }
228 if (dec_header.magic == Common::MakeMagic('N', 'C', 'A', '0')) {
229 status = Loader::ResultStatus::ErrorNCA0;
230 return;
231 }
232
192 if (!keys.HasKey(Core::Crypto::S256KeyType::Header)) 233 if (!keys.HasKey(Core::Crypto::S256KeyType::Header))
193 status = Loader::ResultStatus::ErrorMissingKeys; 234 status = Loader::ResultStatus::ErrorMissingHeaderKey;
194 else 235 else
195 status = Loader::ResultStatus::ErrorDecrypting; 236 status = Loader::ResultStatus::ErrorIncorrectHeaderKey;
196 return; 237 return;
197 } 238 }
198 } 239 }
199 240
241 has_rights_id = std::find_if_not(header.rights_id.begin(), header.rights_id.end(),
242 [](char c) { return c == '\0'; }) != header.rights_id.end();
243
200 const std::ptrdiff_t number_sections = 244 const std::ptrdiff_t number_sections =
201 std::count_if(std::begin(header.section_tables), std::end(header.section_tables), 245 std::count_if(std::begin(header.section_tables), std::end(header.section_tables),
202 [](NCASectionTableEntry entry) { return entry.media_offset > 0; }); 246 [](NCASectionTableEntry entry) { return entry.media_offset > 0; });
@@ -229,7 +273,12 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
229 files.push_back(std::move(dec)); 273 files.push_back(std::move(dec));
230 romfs = files.back(); 274 romfs = files.back();
231 } else { 275 } else {
232 status = Loader::ResultStatus::ErrorMissingKeys; 276 if (status != Loader::ResultStatus::Success)
277 return;
278 if (has_rights_id)
279 status = Loader::ResultStatus::ErrorIncorrectTitlekeyOrTitlekek;
280 else
281 status = Loader::ResultStatus::ErrorIncorrectKeyAreaKey;
233 return; 282 return;
234 } 283 }
235 } else if (section.raw.header.filesystem_type == NCASectionFilesystemType::PFS0) { 284 } else if (section.raw.header.filesystem_type == NCASectionFilesystemType::PFS0) {
@@ -249,7 +298,12 @@ NCA::NCA(VirtualFile file_) : file(std::move(file_)) {
249 exefs = dirs.back(); 298 exefs = dirs.back();
250 } 299 }
251 } else { 300 } else {
252 status = Loader::ResultStatus::ErrorMissingKeys; 301 if (status != Loader::ResultStatus::Success)
302 return;
303 if (has_rights_id)
304 status = Loader::ResultStatus::ErrorIncorrectTitlekeyOrTitlekek;
305 else
306 status = Loader::ResultStatus::ErrorIncorrectKeyAreaKey;
253 return; 307 return;
254 } 308 }
255 } 309 }
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index 5cfd5031a..b82e65ad5 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -98,8 +98,8 @@ protected:
98private: 98private:
99 u8 GetCryptoRevision() const; 99 u8 GetCryptoRevision() const;
100 boost::optional<Core::Crypto::Key128> GetKeyAreaKey(NCASectionCryptoType type) const; 100 boost::optional<Core::Crypto::Key128> GetKeyAreaKey(NCASectionCryptoType type) const;
101 boost::optional<Core::Crypto::Key128> GetTitlekey() const; 101 boost::optional<Core::Crypto::Key128> GetTitlekey();
102 VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset) const; 102 VirtualFile Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_offset);
103 103
104 std::vector<VirtualDir> dirs; 104 std::vector<VirtualDir> dirs;
105 std::vector<VirtualFile> files; 105 std::vector<VirtualFile> files;
@@ -109,6 +109,7 @@ private:
109 VirtualFile file; 109 VirtualFile file;
110 110
111 NCAHeader header{}; 111 NCAHeader header{};
112 bool has_rights_id{};
112 113
113 Loader::ResultStatus status{}; 114 Loader::ResultStatus status{};
114 115
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp
index 47e032b19..c377edc9c 100644
--- a/src/core/file_sys/partition_filesystem.cpp
+++ b/src/core/file_sys/partition_filesystem.cpp
@@ -24,19 +24,19 @@ bool PartitionFilesystem::Header::HasValidMagicValue() const {
24PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) { 24PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
25 // At least be as large as the header 25 // At least be as large as the header
26 if (file->GetSize() < sizeof(Header)) { 26 if (file->GetSize() < sizeof(Header)) {
27 status = Loader::ResultStatus::Error; 27 status = Loader::ResultStatus::ErrorBadPFSHeader;
28 return; 28 return;
29 } 29 }
30 30
31 // For cartridges, HFSs can get very large, so we need to calculate the size up to 31 // For cartridges, HFSs can get very large, so we need to calculate the size up to
32 // the actual content itself instead of just blindly reading in the entire file. 32 // the actual content itself instead of just blindly reading in the entire file.
33 if (sizeof(Header) != file->ReadObject(&pfs_header)) { 33 if (sizeof(Header) != file->ReadObject(&pfs_header)) {
34 status = Loader::ResultStatus::Error; 34 status = Loader::ResultStatus::ErrorBadPFSHeader;
35 return; 35 return;
36 } 36 }
37 37
38 if (!pfs_header.HasValidMagicValue()) { 38 if (!pfs_header.HasValidMagicValue()) {
39 status = Loader::ResultStatus::ErrorInvalidFormat; 39 status = Loader::ResultStatus::ErrorBadPFSHeader;
40 return; 40 return;
41 } 41 }
42 42
@@ -51,7 +51,7 @@ PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
51 const size_t total_size = file_data.size(); 51 const size_t total_size = file_data.size();
52 52
53 if (total_size != metadata_size) { 53 if (total_size != metadata_size) {
54 status = Loader::ResultStatus::Error; 54 status = Loader::ResultStatus::ErrorIncorrectPFSFileSize;
55 return; 55 return;
56 } 56 }
57 57
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index 63d4b6e4f..279f987d4 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -12,26 +12,26 @@ namespace FileSys {
12Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) { 12Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
13 size_t total_size = static_cast<size_t>(file->GetSize()); 13 size_t total_size = static_cast<size_t>(file->GetSize());
14 if (total_size < sizeof(Header)) 14 if (total_size < sizeof(Header))
15 return Loader::ResultStatus::Error; 15 return Loader::ResultStatus::ErrorBadNPDMHeader;
16 16
17 // TODO(DarkLordZach): Use ReadObject when Header/AcidHeader becomes trivially copyable. 17 // TODO(DarkLordZach): Use ReadObject when Header/AcidHeader becomes trivially copyable.
18 std::vector<u8> npdm_header_data = file->ReadBytes(sizeof(Header)); 18 std::vector<u8> npdm_header_data = file->ReadBytes(sizeof(Header));
19 if (sizeof(Header) != npdm_header_data.size()) 19 if (sizeof(Header) != npdm_header_data.size())
20 return Loader::ResultStatus::Error; 20 return Loader::ResultStatus::ErrorBadNPDMHeader;
21 std::memcpy(&npdm_header, npdm_header_data.data(), sizeof(Header)); 21 std::memcpy(&npdm_header, npdm_header_data.data(), sizeof(Header));
22 22
23 std::vector<u8> acid_header_data = file->ReadBytes(sizeof(AcidHeader), npdm_header.acid_offset); 23 std::vector<u8> acid_header_data = file->ReadBytes(sizeof(AcidHeader), npdm_header.acid_offset);
24 if (sizeof(AcidHeader) != acid_header_data.size()) 24 if (sizeof(AcidHeader) != acid_header_data.size())
25 return Loader::ResultStatus::Error; 25 return Loader::ResultStatus::ErrorBadACIDHeader;
26 std::memcpy(&acid_header, acid_header_data.data(), sizeof(AcidHeader)); 26 std::memcpy(&acid_header, acid_header_data.data(), sizeof(AcidHeader));
27 27
28 if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset)) 28 if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset))
29 return Loader::ResultStatus::Error; 29 return Loader::ResultStatus::ErrorBadACIHeader;
30 30
31 if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset)) 31 if (sizeof(FileAccessControl) != file->ReadObject(&acid_file_access, acid_header.fac_offset))
32 return Loader::ResultStatus::Error; 32 return Loader::ResultStatus::ErrorBadFileAccessControl;
33 if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset)) 33 if (sizeof(FileAccessHeader) != file->ReadObject(&aci_file_access, aci_header.fah_offset))
34 return Loader::ResultStatus::Error; 34 return Loader::ResultStatus::ErrorBadFileAccessHeader;
35 35
36 return Loader::ResultStatus::Success; 36 return Loader::ResultStatus::Success;
37} 37}
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 915d525b0..de05f21d8 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -83,13 +83,13 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
83 83
84 if (dir == nullptr) { 84 if (dir == nullptr) {
85 if (file == nullptr) 85 if (file == nullptr)
86 return ResultStatus::ErrorInvalidFormat; 86 return ResultStatus::ErrorNullFile;
87 dir = file->GetContainingDirectory(); 87 dir = file->GetContainingDirectory();
88 } 88 }
89 89
90 const FileSys::VirtualFile npdm = dir->GetFile("main.npdm"); 90 const FileSys::VirtualFile npdm = dir->GetFile("main.npdm");
91 if (npdm == nullptr) 91 if (npdm == nullptr)
92 return ResultStatus::ErrorInvalidFormat; 92 return ResultStatus::ErrorMissingNPDM;
93 93
94 ResultStatus result = metadata.Load(npdm); 94 ResultStatus result = metadata.Load(npdm);
95 if (result != ResultStatus::Success) { 95 if (result != ResultStatus::Success) {
@@ -99,7 +99,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
99 99
100 const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()}; 100 const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
101 if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) { 101 if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) {
102 return ResultStatus::ErrorUnsupportedArch; 102 return ResultStatus::Error32BitISA;
103 } 103 }
104 104
105 // Load NSO modules 105 // Load NSO modules
@@ -143,28 +143,28 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
143 143
144ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& dir) { 144ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& dir) {
145 if (romfs == nullptr) 145 if (romfs == nullptr)
146 return ResultStatus::ErrorNotUsed; 146 return ResultStatus::ErrorNoRomFS;
147 dir = romfs; 147 dir = romfs;
148 return ResultStatus::Success; 148 return ResultStatus::Success;
149} 149}
150 150
151ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) { 151ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) {
152 if (icon_data.empty()) 152 if (icon_data.empty())
153 return ResultStatus::ErrorNotUsed; 153 return ResultStatus::ErrorNoIcon;
154 buffer = icon_data; 154 buffer = icon_data;
155 return ResultStatus::Success; 155 return ResultStatus::Success;
156} 156}
157 157
158ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) { 158ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) {
159 if (name.empty()) 159 if (name.empty())
160 return ResultStatus::ErrorNotUsed; 160 return ResultStatus::ErrorNoControl;
161 out_program_id = title_id; 161 out_program_id = title_id;
162 return ResultStatus::Success; 162 return ResultStatus::Success;
163} 163}
164 164
165ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) { 165ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) {
166 if (name.empty()) 166 if (name.empty())
167 return ResultStatus::ErrorNotUsed; 167 return ResultStatus::ErrorNoControl;
168 title = name; 168 title = name;
169 return ResultStatus::Success; 169 return ResultStatus::Success;
170} 170}
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index a7133f5a6..401cad3ab 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -390,7 +390,7 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
390 390
391 std::vector<u8> buffer = file->ReadAllBytes(); 391 std::vector<u8> buffer = file->ReadAllBytes();
392 if (buffer.size() != file->GetSize()) 392 if (buffer.size() != file->GetSize())
393 return ResultStatus::Error; 393 return ResultStatus::ErrorIncorrectELFFileSize;
394 394
395 ElfReader elf_reader(&buffer[0]); 395 ElfReader elf_reader(&buffer[0]);
396 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); 396 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index a288654df..2f5bfc67c 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -86,6 +86,55 @@ std::string GetFileTypeString(FileType type) {
86 return "unknown"; 86 return "unknown";
87} 87}
88 88
89constexpr std::array<const char*, 36> RESULT_MESSAGES{
90 "The operation completed successfully.",
91 "The loader requested to load is already loaded.",
92 "The operation is not implemented.",
93 "The loader is not initialized properly.",
94 "The NPDM file has a bad header.",
95 "The NPDM has a bad ACID header.",
96 "The NPDM has a bad ACI header,",
97 "The NPDM file has a bad file access control.",
98 "The NPDM has a bad file access header.",
99 "The PFS/HFS partition has a bad header.",
100 "The PFS/HFS partition has incorrect size as determined by the header.",
101 "The NCA file has a bad header.",
102 "The general keyfile could not be found.",
103 "The NCA Header key could not be found.",
104 "The NCA Header key is incorrect or the header is invalid.",
105 "Support for NCA2-type NCAs is not implemented.",
106 "Support for NCA0-type NCAs is not implemented.",
107 "The titlekey for this Rights ID could not be found.",
108 "The titlekek for this crypto revision could not be found.",
109 "The Rights ID in the header is invalid.",
110 "The key area key for this application type and crypto revision could not be found.",
111 "The key area key is incorrect or the section header is invalid.",
112 "The titlekey and/or titlekek is incorrect or the section header is invalid.",
113 "The XCI file is missing a Program-type NCA.",
114 "The NCA file is not an application.",
115 "The ExeFS partition could not be found.",
116 "The XCI file has a bad header.",
117 "The XCI file is missing a partition.",
118 "The file could not be found or does not exist.",
119 "The game is missing a program metadata file (main.npdm).",
120 "The game uses the currently-unimplemented 32-bit architecture.",
121 "The RomFS could not be found.",
122 "The ELF file has incorrect size as determined by the header.",
123 "There was a general error loading the NRO into emulated memory.",
124 "There is no icon available.",
125 "There is no control data available.",
126};
127
128std::string GetMessageForResultStatus(ResultStatus status) {
129 return GetMessageForResultStatus(static_cast<size_t>(status));
130}
131
132std::string GetMessageForResultStatus(u16 status) {
133 if (status >= 36)
134 return "";
135 return RESULT_MESSAGES[status];
136}
137
89/** 138/**
90 * Get a loader for a file with a specific type 139 * Get a loader for a file with a specific type
91 * @param file The file to load 140 * @param file The file to load
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 6a9e5a68b..cfdadbee3 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -58,18 +58,46 @@ std::string GetFileTypeString(FileType type);
58/// Return type for functions in Loader namespace 58/// Return type for functions in Loader namespace
59enum class ResultStatus { 59enum class ResultStatus {
60 Success, 60 Success,
61 Error,
62 ErrorInvalidFormat,
63 ErrorNotImplemented,
64 ErrorNotLoaded,
65 ErrorNotUsed,
66 ErrorAlreadyLoaded, 61 ErrorAlreadyLoaded,
67 ErrorMemoryAllocationFailed, 62 ErrorNotImplemented,
68 ErrorMissingKeys, 63 ErrorNotInitialized,
69 ErrorDecrypting, 64 ErrorBadNPDMHeader,
70 ErrorUnsupportedArch, 65 ErrorBadACIDHeader,
66 ErrorBadACIHeader,
67 ErrorBadFileAccessControl,
68 ErrorBadFileAccessHeader,
69 ErrorBadPFSHeader,
70 ErrorIncorrectPFSFileSize,
71 ErrorBadNCAHeader,
72 ErrorMissingProductionKeyFile,
73 ErrorMissingHeaderKey,
74 ErrorIncorrectHeaderKey,
75 ErrorNCA2,
76 ErrorNCA0,
77 ErrorMissingTitlekey,
78 ErrorMissingTitlekek,
79 ErrorInvalidRightsID,
80 ErrorMissingKeyAreaKey,
81 ErrorIncorrectKeyAreaKey,
82 ErrorIncorrectTitlekeyOrTitlekek,
83 ErrorXCIMissingProgramNCA,
84 ErrorNCANotProgram,
85 ErrorNoExeFS,
86 ErrorBadXCIHeader,
87 ErrorXCIMissingPartition,
88 ErrorNullFile,
89 ErrorMissingNPDM,
90 Error32BitISA,
91 ErrorNoRomFS,
92 ErrorIncorrectELFFileSize,
93 ErrorLoadingNRO,
94 ErrorNoIcon,
95 ErrorNoControl,
71}; 96};
72 97
98std::string GetMessageForResultStatus(ResultStatus status);
99std::string GetMessageForResultStatus(u16 status);
100
73/// Interface for loading an application 101/// Interface for loading an application
74class AppLoader : NonCopyable { 102class AppLoader : NonCopyable {
75public: 103public:
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index 46f5cd393..8498cc94b 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -46,12 +46,12 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
46 } 46 }
47 47
48 if (nca->GetType() != FileSys::NCAContentType::Program) 48 if (nca->GetType() != FileSys::NCAContentType::Program)
49 return ResultStatus::ErrorInvalidFormat; 49 return ResultStatus::ErrorNCANotProgram;
50 50
51 const auto exefs = nca->GetExeFS(); 51 const auto exefs = nca->GetExeFS();
52 52
53 if (exefs == nullptr) 53 if (exefs == nullptr)
54 return ResultStatus::ErrorInvalidFormat; 54 return ResultStatus::ErrorNoExeFS;
55 55
56 directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs); 56 directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs);
57 57
@@ -69,16 +69,16 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
69 69
70ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) { 70ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {
71 if (nca == nullptr) 71 if (nca == nullptr)
72 return ResultStatus::ErrorNotLoaded; 72 return ResultStatus::ErrorNotInitialized;
73 if (nca->GetRomFS() == nullptr || nca->GetRomFS()->GetSize() == 0) 73 if (nca->GetRomFS() == nullptr || nca->GetRomFS()->GetSize() == 0)
74 return ResultStatus::ErrorNotUsed; 74 return ResultStatus::ErrorNoRomFS;
75 dir = nca->GetRomFS(); 75 dir = nca->GetRomFS();
76 return ResultStatus::Success; 76 return ResultStatus::Success;
77} 77}
78 78
79ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { 79ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
80 if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) 80 if (nca == nullptr || nca->GetStatus() != ResultStatus::Success)
81 return ResultStatus::ErrorInvalidFormat; 81 return ResultStatus::ErrorNotInitialized;
82 out_program_id = nca->GetTitleId(); 82 out_program_id = nca->GetTitleId();
83 return ResultStatus::Success; 83 return ResultStatus::Success;
84} 84}
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index dc053cdad..908d91eab 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -182,7 +182,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
182 static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR}; 182 static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR};
183 183
184 if (!LoadNro(file, base_addr)) { 184 if (!LoadNro(file, base_addr)) {
185 return ResultStatus::ErrorInvalidFormat; 185 return ResultStatus::ErrorLoadingNRO;
186 } 186 }
187 187
188 process->svc_access_mask.set(); 188 process->svc_access_mask.set();
@@ -197,7 +197,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
197 197
198ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) { 198ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {
199 if (icon_data.empty()) { 199 if (icon_data.empty()) {
200 return ResultStatus::ErrorNotUsed; 200 return ResultStatus::ErrorNoIcon;
201 } 201 }
202 202
203 buffer = icon_data; 203 buffer = icon_data;
@@ -206,7 +206,7 @@ ResultStatus AppLoader_NRO::ReadIcon(std::vector<u8>& buffer) {
206 206
207ResultStatus AppLoader_NRO::ReadProgramId(u64& out_program_id) { 207ResultStatus AppLoader_NRO::ReadProgramId(u64& out_program_id) {
208 if (nacp == nullptr) { 208 if (nacp == nullptr) {
209 return ResultStatus::ErrorNotUsed; 209 return ResultStatus::ErrorNoControl;
210 } 210 }
211 211
212 out_program_id = nacp->GetTitleId(); 212 out_program_id = nacp->GetTitleId();
@@ -215,7 +215,7 @@ ResultStatus AppLoader_NRO::ReadProgramId(u64& out_program_id) {
215 215
216ResultStatus AppLoader_NRO::ReadRomFS(FileSys::VirtualFile& dir) { 216ResultStatus AppLoader_NRO::ReadRomFS(FileSys::VirtualFile& dir) {
217 if (romfs == nullptr) { 217 if (romfs == nullptr) {
218 return ResultStatus::ErrorNotUsed; 218 return ResultStatus::ErrorNoRomFS;
219 } 219 }
220 220
221 dir = romfs; 221 dir = romfs;
@@ -224,7 +224,7 @@ ResultStatus AppLoader_NRO::ReadRomFS(FileSys::VirtualFile& dir) {
224 224
225ResultStatus AppLoader_NRO::ReadTitle(std::string& title) { 225ResultStatus AppLoader_NRO::ReadTitle(std::string& title) {
226 if (nacp == nullptr) { 226 if (nacp == nullptr) {
227 return ResultStatus::ErrorNotUsed; 227 return ResultStatus::ErrorNoControl;
228 } 228 }
229 229
230 title = nacp->GetApplicationName(); 230 title = nacp->GetApplicationName();
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index d3fe24419..5d67fb186 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -66,10 +66,13 @@ ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr<Kernel::Process>& process) {
66 return ResultStatus::ErrorAlreadyLoaded; 66 return ResultStatus::ErrorAlreadyLoaded;
67 } 67 }
68 68
69 if (xci->GetStatus() != ResultStatus::Success)
70 return xci->GetStatus();
71
69 if (xci->GetNCAFileByType(FileSys::NCAContentType::Program) == nullptr) { 72 if (xci->GetNCAFileByType(FileSys::NCAContentType::Program) == nullptr) {
70 if (!Core::Crypto::KeyManager::KeyFileExists(false)) 73 if (!Core::Crypto::KeyManager::KeyFileExists(false))
71 return ResultStatus::ErrorMissingKeys; 74 return ResultStatus::ErrorMissingProductionKeyFile;
72 return ResultStatus::ErrorDecrypting; 75 return ResultStatus::ErrorXCIMissingProgramNCA;
73 } 76 }
74 77
75 auto result = nca_loader->Load(process); 78 auto result = nca_loader->Load(process);
@@ -91,14 +94,14 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) {
91 94
92ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) { 95ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) {
93 if (icon_file == nullptr) 96 if (icon_file == nullptr)
94 return ResultStatus::ErrorInvalidFormat; 97 return ResultStatus::ErrorNoControl;
95 buffer = icon_file->ReadAllBytes(); 98 buffer = icon_file->ReadAllBytes();
96 return ResultStatus::Success; 99 return ResultStatus::Success;
97} 100}
98 101
99ResultStatus AppLoader_XCI::ReadTitle(std::string& title) { 102ResultStatus AppLoader_XCI::ReadTitle(std::string& title) {
100 if (nacp_file == nullptr) 103 if (nacp_file == nullptr)
101 return ResultStatus::ErrorInvalidFormat; 104 return ResultStatus::ErrorNoControl;
102 title = nacp_file->GetApplicationName(); 105 title = nacp_file->GetApplicationName();
103 return ResultStatus::Success; 106 return ResultStatus::Success;
104} 107}
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 24396c6c9..9f64b248b 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -596,6 +596,13 @@ public:
596 Unknown, 596 Unknown,
597 }; 597 };
598 598
599 /// Returns whether an opcode has an execution predicate field or not (ie, whether it can be
600 /// conditionally executed).
601 static bool IsPredicatedInstruction(Id opcode) {
602 // TODO(Subv): Add the rest of unpredicated instructions.
603 return opcode != Id::SSY;
604 }
605
599 class Matcher { 606 class Matcher {
600 public: 607 public:
601 Matcher(const char* const name, u16 mask, u16 expected, OpCode::Id id, OpCode::Type type) 608 Matcher(const char* const name, u16 mask, u16 expected, OpCode::Id id, OpCode::Type type)
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index ceaf86654..834940b83 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -50,6 +50,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) {
50 case RenderTargetFormat::RG32_FLOAT: 50 case RenderTargetFormat::RG32_FLOAT:
51 return 8; 51 return 8;
52 case RenderTargetFormat::RGBA8_UNORM: 52 case RenderTargetFormat::RGBA8_UNORM:
53 case RenderTargetFormat::RGBA8_SNORM:
53 case RenderTargetFormat::RGBA8_SRGB: 54 case RenderTargetFormat::RGBA8_SRGB:
54 case RenderTargetFormat::RGB10_A2_UNORM: 55 case RenderTargetFormat::RGB10_A2_UNORM:
55 case RenderTargetFormat::BGRA8_UNORM: 56 case RenderTargetFormat::BGRA8_UNORM:
@@ -66,6 +67,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) {
66 case RenderTargetFormat::R16_UINT: 67 case RenderTargetFormat::R16_UINT:
67 case RenderTargetFormat::R16_SINT: 68 case RenderTargetFormat::R16_SINT:
68 case RenderTargetFormat::R16_FLOAT: 69 case RenderTargetFormat::R16_FLOAT:
70 case RenderTargetFormat::RG8_SNORM:
69 return 2; 71 return 2;
70 case RenderTargetFormat::R8_UNORM: 72 case RenderTargetFormat::R8_UNORM:
71 return 1; 73 return 1;
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index b57312b3b..de5b037be 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -26,6 +26,7 @@ enum class RenderTargetFormat : u32 {
26 RGB10_A2_UNORM = 0xD1, 26 RGB10_A2_UNORM = 0xD1,
27 RGBA8_UNORM = 0xD5, 27 RGBA8_UNORM = 0xD5,
28 RGBA8_SRGB = 0xD6, 28 RGBA8_SRGB = 0xD6,
29 RGBA8_SNORM = 0xD7,
29 RG16_UNORM = 0xDA, 30 RG16_UNORM = 0xDA,
30 RG16_SNORM = 0xDB, 31 RG16_SNORM = 0xDB,
31 RG16_SINT = 0xDC, 32 RG16_SINT = 0xDC,
@@ -34,6 +35,7 @@ enum class RenderTargetFormat : u32 {
34 R11G11B10_FLOAT = 0xE0, 35 R11G11B10_FLOAT = 0xE0,
35 R32_FLOAT = 0xE5, 36 R32_FLOAT = 0xE5,
36 B5G6R5_UNORM = 0xE8, 37 B5G6R5_UNORM = 0xE8,
38 RG8_SNORM = 0xEB,
37 R16_UNORM = 0xEE, 39 R16_UNORM = 0xEE,
38 R16_SNORM = 0xEF, 40 R16_SNORM = 0xEF,
39 R16_SINT = 0xF0, 41 R16_SINT = 0xF0,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 15a33ed9b..d055b1dfa 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -92,7 +92,8 @@ struct FormatTuple {
92} 92}
93 93
94static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{ 94static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{
95 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8 95 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U
96 {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S
96 {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5 97 {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, ComponentType::UNorm, false}, // B5G6R5
97 {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm, 98 {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, ComponentType::UNorm,
98 false}, // A2B10G10R10 99 false}, // A2B10G10R10
@@ -132,6 +133,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
132 {GL_RG16_SNORM, GL_RG, GL_SHORT, ComponentType::SNorm, false}, // RG16S 133 {GL_RG16_SNORM, GL_RG, GL_SHORT, ComponentType::SNorm, false}, // RG16S
133 {GL_RGB32F, GL_RGB, GL_FLOAT, ComponentType::Float, false}, // RGB32F 134 {GL_RGB32F, GL_RGB, GL_FLOAT, ComponentType::Float, false}, // RGB32F
134 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // SRGBA8 135 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // SRGBA8
136 {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S
135 137
136 // DepthStencil formats 138 // DepthStencil formats
137 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm, 139 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm,
@@ -231,31 +233,33 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_bu
231static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr), 233static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr),
232 SurfaceParams::MaxPixelFormat> 234 SurfaceParams::MaxPixelFormat>
233 morton_to_gl_fns = { 235 morton_to_gl_fns = {
234 MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>, 236 MortonCopy<true, PixelFormat::ABGR8U>, MortonCopy<true, PixelFormat::ABGR8S>,
235 MortonCopy<true, PixelFormat::A2B10G10R10>, MortonCopy<true, PixelFormat::A1B5G5R5>, 237 MortonCopy<true, PixelFormat::B5G6R5>, MortonCopy<true, PixelFormat::A2B10G10R10>,
236 MortonCopy<true, PixelFormat::R8>, MortonCopy<true, PixelFormat::RGBA16F>, 238 MortonCopy<true, PixelFormat::A1B5G5R5>, MortonCopy<true, PixelFormat::R8>,
237 MortonCopy<true, PixelFormat::R11FG11FB10F>, MortonCopy<true, PixelFormat::RGBA32UI>, 239 MortonCopy<true, PixelFormat::RGBA16F>, MortonCopy<true, PixelFormat::R11FG11FB10F>,
238 MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>, 240 MortonCopy<true, PixelFormat::RGBA32UI>, MortonCopy<true, PixelFormat::DXT1>,
239 MortonCopy<true, PixelFormat::DXT45>, MortonCopy<true, PixelFormat::DXN1>, 241 MortonCopy<true, PixelFormat::DXT23>, MortonCopy<true, PixelFormat::DXT45>,
240 MortonCopy<true, PixelFormat::DXN2UNORM>, MortonCopy<true, PixelFormat::DXN2SNORM>, 242 MortonCopy<true, PixelFormat::DXN1>, MortonCopy<true, PixelFormat::DXN2UNORM>,
241 MortonCopy<true, PixelFormat::BC7U>, MortonCopy<true, PixelFormat::ASTC_2D_4X4>, 243 MortonCopy<true, PixelFormat::DXN2SNORM>, MortonCopy<true, PixelFormat::BC7U>,
242 MortonCopy<true, PixelFormat::G8R8>, MortonCopy<true, PixelFormat::BGRA8>, 244 MortonCopy<true, PixelFormat::ASTC_2D_4X4>, MortonCopy<true, PixelFormat::G8R8>,
243 MortonCopy<true, PixelFormat::RGBA32F>, MortonCopy<true, PixelFormat::RG32F>, 245 MortonCopy<true, PixelFormat::BGRA8>, MortonCopy<true, PixelFormat::RGBA32F>,
244 MortonCopy<true, PixelFormat::R32F>, MortonCopy<true, PixelFormat::R16F>, 246 MortonCopy<true, PixelFormat::RG32F>, MortonCopy<true, PixelFormat::R32F>,
245 MortonCopy<true, PixelFormat::R16UNORM>, MortonCopy<true, PixelFormat::R16S>, 247 MortonCopy<true, PixelFormat::R16F>, MortonCopy<true, PixelFormat::R16UNORM>,
246 MortonCopy<true, PixelFormat::R16UI>, MortonCopy<true, PixelFormat::R16I>, 248 MortonCopy<true, PixelFormat::R16S>, MortonCopy<true, PixelFormat::R16UI>,
247 MortonCopy<true, PixelFormat::RG16>, MortonCopy<true, PixelFormat::RG16F>, 249 MortonCopy<true, PixelFormat::R16I>, MortonCopy<true, PixelFormat::RG16>,
248 MortonCopy<true, PixelFormat::RG16UI>, MortonCopy<true, PixelFormat::RG16I>, 250 MortonCopy<true, PixelFormat::RG16F>, MortonCopy<true, PixelFormat::RG16UI>,
249 MortonCopy<true, PixelFormat::RG16S>, MortonCopy<true, PixelFormat::RGB32F>, 251 MortonCopy<true, PixelFormat::RG16I>, MortonCopy<true, PixelFormat::RG16S>,
250 MortonCopy<true, PixelFormat::SRGBA8>, MortonCopy<true, PixelFormat::Z24S8>, 252 MortonCopy<true, PixelFormat::RGB32F>, MortonCopy<true, PixelFormat::SRGBA8>,
251 MortonCopy<true, PixelFormat::S8Z24>, MortonCopy<true, PixelFormat::Z32F>, 253 MortonCopy<true, PixelFormat::RG8S>, MortonCopy<true, PixelFormat::Z24S8>,
252 MortonCopy<true, PixelFormat::Z16>, MortonCopy<true, PixelFormat::Z32FS8>, 254 MortonCopy<true, PixelFormat::S8Z24>, MortonCopy<true, PixelFormat::Z32F>,
255 MortonCopy<true, PixelFormat::Z16>, MortonCopy<true, PixelFormat::Z32FS8>,
253}; 256};
254 257
255static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr), 258static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr),
256 SurfaceParams::MaxPixelFormat> 259 SurfaceParams::MaxPixelFormat>
257 gl_to_morton_fns = { 260 gl_to_morton_fns = {
258 MortonCopy<false, PixelFormat::ABGR8>, 261 MortonCopy<false, PixelFormat::ABGR8U>,
262 MortonCopy<false, PixelFormat::ABGR8S>,
259 MortonCopy<false, PixelFormat::B5G6R5>, 263 MortonCopy<false, PixelFormat::B5G6R5>,
260 MortonCopy<false, PixelFormat::A2B10G10R10>, 264 MortonCopy<false, PixelFormat::A2B10G10R10>,
261 MortonCopy<false, PixelFormat::A1B5G5R5>, 265 MortonCopy<false, PixelFormat::A1B5G5R5>,
@@ -290,6 +294,7 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPU
290 MortonCopy<false, PixelFormat::RG16S>, 294 MortonCopy<false, PixelFormat::RG16S>,
291 MortonCopy<false, PixelFormat::RGB32F>, 295 MortonCopy<false, PixelFormat::RGB32F>,
292 MortonCopy<false, PixelFormat::SRGBA8>, 296 MortonCopy<false, PixelFormat::SRGBA8>,
297 MortonCopy<false, PixelFormat::RG8S>,
293 MortonCopy<false, PixelFormat::Z24S8>, 298 MortonCopy<false, PixelFormat::Z24S8>,
294 MortonCopy<false, PixelFormat::S8Z24>, 299 MortonCopy<false, PixelFormat::S8Z24>,
295 MortonCopy<false, PixelFormat::Z32F>, 300 MortonCopy<false, PixelFormat::Z32F>,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index e24ba8cfe..d7a43652e 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -23,48 +23,50 @@ using PageMap = boost::icl::interval_map<u64, int>;
23 23
24struct SurfaceParams { 24struct SurfaceParams {
25 enum class PixelFormat { 25 enum class PixelFormat {
26 ABGR8 = 0, 26 ABGR8U = 0,
27 B5G6R5 = 1, 27 ABGR8S = 1,
28 A2B10G10R10 = 2, 28 B5G6R5 = 2,
29 A1B5G5R5 = 3, 29 A2B10G10R10 = 3,
30 R8 = 4, 30 A1B5G5R5 = 4,
31 RGBA16F = 5, 31 R8 = 5,
32 R11FG11FB10F = 6, 32 RGBA16F = 6,
33 RGBA32UI = 7, 33 R11FG11FB10F = 7,
34 DXT1 = 8, 34 RGBA32UI = 8,
35 DXT23 = 9, 35 DXT1 = 9,
36 DXT45 = 10, 36 DXT23 = 10,
37 DXN1 = 11, // This is also known as BC4 37 DXT45 = 11,
38 DXN2UNORM = 12, 38 DXN1 = 12, // This is also known as BC4
39 DXN2SNORM = 13, 39 DXN2UNORM = 13,
40 BC7U = 14, 40 DXN2SNORM = 14,
41 ASTC_2D_4X4 = 15, 41 BC7U = 15,
42 G8R8 = 16, 42 ASTC_2D_4X4 = 16,
43 BGRA8 = 17, 43 G8R8 = 17,
44 RGBA32F = 18, 44 BGRA8 = 18,
45 RG32F = 19, 45 RGBA32F = 19,
46 R32F = 20, 46 RG32F = 20,
47 R16F = 21, 47 R32F = 21,
48 R16UNORM = 22, 48 R16F = 22,
49 R16S = 23, 49 R16UNORM = 23,
50 R16UI = 24, 50 R16S = 24,
51 R16I = 25, 51 R16UI = 25,
52 RG16 = 26, 52 R16I = 26,
53 RG16F = 27, 53 RG16 = 27,
54 RG16UI = 28, 54 RG16F = 28,
55 RG16I = 29, 55 RG16UI = 29,
56 RG16S = 30, 56 RG16I = 30,
57 RGB32F = 31, 57 RG16S = 31,
58 SRGBA8 = 32, 58 RGB32F = 32,
59 SRGBA8 = 33,
60 RG8S = 34,
59 61
60 MaxColorFormat, 62 MaxColorFormat,
61 63
62 // DepthStencil formats 64 // DepthStencil formats
63 Z24S8 = 33, 65 Z24S8 = 35,
64 S8Z24 = 34, 66 S8Z24 = 36,
65 Z32F = 35, 67 Z32F = 37,
66 Z16 = 36, 68 Z16 = 38,
67 Z32FS8 = 37, 69 Z32FS8 = 39,
68 70
69 MaxDepthStencilFormat, 71 MaxDepthStencilFormat,
70 72
@@ -102,7 +104,8 @@ struct SurfaceParams {
102 return 0; 104 return 0;
103 105
104 constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{ 106 constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
105 1, // ABGR8 107 1, // ABGR8U
108 1, // ABGR8S
106 1, // B5G6R5 109 1, // B5G6R5
107 1, // A2B10G10R10 110 1, // A2B10G10R10
108 1, // A1B5G5R5 111 1, // A1B5G5R5
@@ -135,6 +138,7 @@ struct SurfaceParams {
135 1, // RG16S 138 1, // RG16S
136 1, // RGB32F 139 1, // RGB32F
137 1, // SRGBA8 140 1, // SRGBA8
141 1, // RG8S
138 1, // Z24S8 142 1, // Z24S8
139 1, // S8Z24 143 1, // S8Z24
140 1, // Z32F 144 1, // Z32F
@@ -151,7 +155,8 @@ struct SurfaceParams {
151 return 0; 155 return 0;
152 156
153 constexpr std::array<u32, MaxPixelFormat> bpp_table = {{ 157 constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
154 32, // ABGR8 158 32, // ABGR8U
159 32, // ABGR8S
155 16, // B5G6R5 160 16, // B5G6R5
156 32, // A2B10G10R10 161 32, // A2B10G10R10
157 16, // A1B5G5R5 162 16, // A1B5G5R5
@@ -184,6 +189,7 @@ struct SurfaceParams {
184 32, // RG16S 189 32, // RG16S
185 96, // RGB32F 190 96, // RGB32F
186 32, // SRGBA8 191 32, // SRGBA8
192 16, // RG8S
187 32, // Z24S8 193 32, // Z24S8
188 32, // S8Z24 194 32, // S8Z24
189 32, // Z32F 195 32, // Z32F
@@ -223,7 +229,9 @@ struct SurfaceParams {
223 // gamma. 229 // gamma.
224 case Tegra::RenderTargetFormat::RGBA8_SRGB: 230 case Tegra::RenderTargetFormat::RGBA8_SRGB:
225 case Tegra::RenderTargetFormat::RGBA8_UNORM: 231 case Tegra::RenderTargetFormat::RGBA8_UNORM:
226 return PixelFormat::ABGR8; 232 return PixelFormat::ABGR8U;
233 case Tegra::RenderTargetFormat::RGBA8_SNORM:
234 return PixelFormat::ABGR8S;
227 case Tegra::RenderTargetFormat::BGRA8_UNORM: 235 case Tegra::RenderTargetFormat::BGRA8_UNORM:
228 return PixelFormat::BGRA8; 236 return PixelFormat::BGRA8;
229 case Tegra::RenderTargetFormat::RGB10_A2_UNORM: 237 case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
@@ -252,6 +260,8 @@ struct SurfaceParams {
252 return PixelFormat::RG16; 260 return PixelFormat::RG16;
253 case Tegra::RenderTargetFormat::RG16_SNORM: 261 case Tegra::RenderTargetFormat::RG16_SNORM:
254 return PixelFormat::RG16S; 262 return PixelFormat::RG16S;
263 case Tegra::RenderTargetFormat::RG8_SNORM:
264 return PixelFormat::RG8S;
255 case Tegra::RenderTargetFormat::R16_FLOAT: 265 case Tegra::RenderTargetFormat::R16_FLOAT:
256 return PixelFormat::R16F; 266 return PixelFormat::R16F;
257 case Tegra::RenderTargetFormat::R16_UNORM: 267 case Tegra::RenderTargetFormat::R16_UNORM:
@@ -275,7 +285,15 @@ struct SurfaceParams {
275 // TODO(Subv): Properly implement this 285 // TODO(Subv): Properly implement this
276 switch (format) { 286 switch (format) {
277 case Tegra::Texture::TextureFormat::A8R8G8B8: 287 case Tegra::Texture::TextureFormat::A8R8G8B8:
278 return PixelFormat::ABGR8; 288 switch (component_type) {
289 case Tegra::Texture::ComponentType::UNORM:
290 return PixelFormat::ABGR8U;
291 case Tegra::Texture::ComponentType::SNORM:
292 return PixelFormat::ABGR8S;
293 }
294 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
295 static_cast<u32>(component_type));
296 UNREACHABLE();
279 case Tegra::Texture::TextureFormat::B5G6R5: 297 case Tegra::Texture::TextureFormat::B5G6R5:
280 return PixelFormat::B5G6R5; 298 return PixelFormat::B5G6R5;
281 case Tegra::Texture::TextureFormat::A2B10G10R10: 299 case Tegra::Texture::TextureFormat::A2B10G10R10:
@@ -402,8 +420,10 @@ struct SurfaceParams {
402 case Tegra::RenderTargetFormat::R16_UNORM: 420 case Tegra::RenderTargetFormat::R16_UNORM:
403 case Tegra::RenderTargetFormat::B5G6R5_UNORM: 421 case Tegra::RenderTargetFormat::B5G6R5_UNORM:
404 return ComponentType::UNorm; 422 return ComponentType::UNorm;
423 case Tegra::RenderTargetFormat::RGBA8_SNORM:
405 case Tegra::RenderTargetFormat::RG16_SNORM: 424 case Tegra::RenderTargetFormat::RG16_SNORM:
406 case Tegra::RenderTargetFormat::R16_SNORM: 425 case Tegra::RenderTargetFormat::R16_SNORM:
426 case Tegra::RenderTargetFormat::RG8_SNORM:
407 return ComponentType::SNorm; 427 return ComponentType::SNorm;
408 case Tegra::RenderTargetFormat::RGBA16_FLOAT: 428 case Tegra::RenderTargetFormat::RGBA16_FLOAT:
409 case Tegra::RenderTargetFormat::R11G11B10_FLOAT: 429 case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
@@ -429,7 +449,7 @@ struct SurfaceParams {
429 static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) { 449 static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
430 switch (format) { 450 switch (format) {
431 case Tegra::FramebufferConfig::PixelFormat::ABGR8: 451 case Tegra::FramebufferConfig::PixelFormat::ABGR8:
432 return PixelFormat::ABGR8; 452 return PixelFormat::ABGR8U;
433 default: 453 default:
434 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); 454 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
435 UNREACHABLE(); 455 UNREACHABLE();
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 06bfe799c..85297bd00 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -141,6 +141,15 @@ private:
141 ExitMethod jmp = Scan(target, end, labels); 141 ExitMethod jmp = Scan(target, end, labels);
142 return exit_method = ParallelExit(no_jmp, jmp); 142 return exit_method = ParallelExit(no_jmp, jmp);
143 } 143 }
144 case OpCode::Id::SSY: {
145 // The SSY instruction uses a similar encoding as the BRA instruction.
146 ASSERT_MSG(instr.bra.constant_buffer == 0,
147 "Constant buffer SSY is not supported");
148 u32 target = offset + instr.bra.GetBranchTarget();
149 labels.insert(target);
150 // Continue scanning for an exit method.
151 break;
152 }
144 } 153 }
145 } 154 }
146 } 155 }
@@ -830,7 +839,11 @@ private:
830 ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute, 839 ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute,
831 "NeverExecute predicate not implemented"); 840 "NeverExecute predicate not implemented");
832 841
833 if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) { 842 // Some instructions (like SSY) don't have a predicate field, they are always
843 // unconditionally executed.
844 bool can_be_predicated = OpCode::IsPredicatedInstruction(opcode->GetId());
845
846 if (can_be_predicated && instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
834 shader.AddLine("if (" + 847 shader.AddLine("if (" +
835 GetPredicateCondition(instr.pred.pred_index, instr.negate_pred != 0) + 848 GetPredicateCondition(instr.pred.pred_index, instr.negate_pred != 0) +
836 ')'); 849 ')');
@@ -1670,16 +1683,25 @@ private:
1670 break; 1683 break;
1671 } 1684 }
1672 case OpCode::Id::SSY: { 1685 case OpCode::Id::SSY: {
1673 // The SSY opcode tells the GPU where to re-converge divergent execution paths, we 1686 // The SSY opcode tells the GPU where to re-converge divergent execution paths, it
1674 // can ignore this when generating GLSL code. 1687 // sets the target of the jump that the SYNC instruction will make. The SSY opcode
1688 // has a similar structure to the BRA opcode.
1689 ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer SSY is not supported");
1690
1691 u32 target = offset + instr.bra.GetBranchTarget();
1692 shader.AddLine("ssy_target = " + std::to_string(target) + "u;");
1675 break; 1693 break;
1676 } 1694 }
1677 case OpCode::Id::SYNC: 1695 case OpCode::Id::SYNC: {
1696 // The SYNC opcode jumps to the address previously set by the SSY opcode
1678 ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always); 1697 ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
1698 shader.AddLine("{ jmp_to = ssy_target; break; }");
1699 break;
1700 }
1679 case OpCode::Id::DEPBAR: { 1701 case OpCode::Id::DEPBAR: {
1680 // TODO(Subv): Find out if we actually have to care about these instructions or if 1702 // TODO(Subv): Find out if we actually have to care about this instruction or if
1681 // the GLSL compiler takes care of that for us. 1703 // the GLSL compiler takes care of that for us.
1682 LOG_WARNING(HW_GPU, "DEPBAR/SYNC instruction is stubbed"); 1704 LOG_WARNING(HW_GPU, "DEPBAR instruction is stubbed");
1683 break; 1705 break;
1684 } 1706 }
1685 default: { 1707 default: {
@@ -1693,7 +1715,7 @@ private:
1693 } 1715 }
1694 1716
1695 // Close the predicate condition scope. 1717 // Close the predicate condition scope.
1696 if (instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) { 1718 if (can_be_predicated && instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
1697 --shader.scope; 1719 --shader.scope;
1698 shader.AddLine('}'); 1720 shader.AddLine('}');
1699 } 1721 }
@@ -1744,6 +1766,7 @@ private:
1744 } else { 1766 } else {
1745 labels.insert(subroutine.begin); 1767 labels.insert(subroutine.begin);
1746 shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;"); 1768 shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;");
1769 shader.AddLine("uint ssy_target = 0u;");
1747 shader.AddLine("while (true) {"); 1770 shader.AddLine("while (true) {");
1748 ++shader.scope; 1771 ++shader.scope;
1749 1772
@@ -1759,7 +1782,7 @@ private:
1759 u32 compile_end = CompileRange(label, next_label); 1782 u32 compile_end = CompileRange(label, next_label);
1760 if (compile_end > next_label && compile_end != PROGRAM_END) { 1783 if (compile_end > next_label && compile_end != PROGRAM_END) {
1761 // This happens only when there is a label inside a IF/LOOP block 1784 // This happens only when there is a label inside a IF/LOOP block
1762 shader.AddLine("{ jmp_to = " + std::to_string(compile_end) + "u; break; }"); 1785 shader.AddLine(" jmp_to = " + std::to_string(compile_end) + "u; break; }");
1763 labels.emplace(compile_end); 1786 labels.emplace(compile_end);
1764 } 1787 }
1765 1788
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 1c738d2a4..85cb12594 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -453,10 +453,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
453 std::string name = " "; 453 std::string name = " ";
454 const auto res3 = loader->ReadTitle(name); 454 const auto res3 = loader->ReadTitle(name);
455 455
456 if ((res1 == Loader::ResultStatus::ErrorNotUsed || 456 if (res1 != Loader::ResultStatus::Success && res3 != Loader::ResultStatus::Success &&
457 res1 == Loader::ResultStatus::ErrorNotImplemented) &&
458 (res3 == Loader::ResultStatus::ErrorNotUsed ||
459 res3 == Loader::ResultStatus::ErrorNotImplemented) &&
460 res2 == Loader::ResultStatus::Success) { 457 res2 == Loader::ResultStatus::Success) {
461 // Use from metadata pool. 458 // Use from metadata pool.
462 if (nca_control_map.find(program_id) != nca_control_map.end()) { 459 if (nca_control_map.find(program_id) != nca_control_map.end()) {
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 67e3c6549..94fb8ae6a 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -424,67 +424,11 @@ bool GMainWindow::LoadROM(const QString& filename) {
424 QMessageBox::critical(this, tr("Error while loading ROM!"), 424 QMessageBox::critical(this, tr("Error while loading ROM!"),
425 tr("The ROM format is not supported.")); 425 tr("The ROM format is not supported."));
426 break; 426 break;
427 case Core::System::ResultStatus::ErrorUnsupportedArch:
428 LOG_CRITICAL(Frontend, "Unsupported architecture detected!", filename.toStdString());
429 QMessageBox::critical(this, tr("Error while loading ROM!"),
430 tr("The ROM uses currently unusable 32-bit architecture"));
431 break;
432 case Core::System::ResultStatus::ErrorSystemMode: 427 case Core::System::ResultStatus::ErrorSystemMode:
433 LOG_CRITICAL(Frontend, "Failed to load ROM!"); 428 LOG_CRITICAL(Frontend, "Failed to load ROM!");
434 QMessageBox::critical(this, tr("Error while loading ROM!"), 429 QMessageBox::critical(this, tr("Error while loading ROM!"),
435 tr("Could not determine the system mode.")); 430 tr("Could not determine the system mode."));
436 break; 431 break;
437
438 case Core::System::ResultStatus::ErrorLoader_ErrorMissingKeys: {
439 const auto reg_found = Core::Crypto::KeyManager::KeyFileExists(false);
440 const auto title_found = Core::Crypto::KeyManager::KeyFileExists(true);
441
442 std::string file_text;
443
444 if (!reg_found && !title_found) {
445 file_text = "A proper key file (prod.keys, dev.keys, or title.keys) could not be "
446 "found. You will need to dump your keys from your switch to continue.";
447 } else if (reg_found && title_found) {
448 file_text =
449 "Both key files were found in your config directory, but the correct key could"
450 "not be found. You may be missing a titlekey or general key, depending on "
451 "the game.";
452 } else if (reg_found) {
453 file_text =
454 "The regular keys file (prod.keys/dev.keys) was found in your config, but the "
455 "titlekeys file (title.keys) was not. You are either missing the correct "
456 "titlekey or missing a general key required to decrypt the game.";
457 } else {
458 file_text = "The title keys file (title.keys) was found in your config, but "
459 "the regular keys file (prod.keys/dev.keys) was not. Unfortunately, "
460 "having the titlekey is not enough, you need additional general keys "
461 "to properly decrypt the game. You should double-check to make sure "
462 "your keys are correct.";
463 }
464
465 QMessageBox::critical(
466 this, tr("Error while loading ROM!"),
467 tr(("The game you are trying to load is encrypted and the required keys to load "
468 "the game could not be found in your configuration. " +
469 file_text + " Please refer to the yuzu wiki for help.")
470 .c_str()));
471 break;
472 }
473 case Core::System::ResultStatus::ErrorLoader_ErrorDecrypting: {
474 QMessageBox::critical(
475 this, tr("Error while loading ROM!"),
476 tr("There was a general error while decrypting the game. This means that the keys "
477 "necessary were found, but were either incorrect, the game itself was not a "
478 "valid game or the game uses an unhandled cryptographic scheme. Please double "
479 "check that you have the correct "
480 "keys."));
481 break;
482 }
483 case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
484 QMessageBox::critical(this, tr("Error while loading ROM!"),
485 tr("The ROM format is not supported."));
486 break;
487
488 case Core::System::ResultStatus::ErrorVideoCore: 432 case Core::System::ResultStatus::ErrorVideoCore:
489 QMessageBox::critical( 433 QMessageBox::critical(
490 this, tr("An error occurred initializing the video core."), 434 this, tr("An error occurred initializing the video core."),
@@ -499,9 +443,23 @@ bool GMainWindow::LoadROM(const QString& filename) {
499 break; 443 break;
500 444
501 default: 445 default:
502 QMessageBox::critical( 446 if (static_cast<u32>(result) >
503 this, tr("Error while loading ROM!"), 447 static_cast<u32>(Core::System::ResultStatus::ErrorLoader)) {
504 tr("An unknown error occurred. Please see the log for more details.")); 448 LOG_CRITICAL(Frontend, "Failed to load ROM!");
449 const u16 loader_id = static_cast<u16>(Core::System::ResultStatus::ErrorLoader);
450 const u16 error_id = static_cast<u16>(result) - loader_id;
451 QMessageBox::critical(
452 this, tr("Error while loading ROM!"),
453 QString::fromStdString(fmt::format(
454 "While attempting to load the ROM requested, an error occured. Please "
455 "refer to the yuzu wiki for more information or the yuzu discord for "
456 "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
457 loader_id, error_id, Loader::GetMessageForResultStatus(error_id))));
458 } else {
459 QMessageBox::critical(
460 this, tr("Error while loading ROM!"),
461 tr("An unknown error occurred. Please see the log for more details."));
462 }
505 break; 463 break;
506 } 464 }
507 return false; 465 return false;
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index 0605c92e3..e44a98311 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -174,19 +174,6 @@ int main(int argc, char** argv) {
174 case Core::System::ResultStatus::ErrorLoader: 174 case Core::System::ResultStatus::ErrorLoader:
175 LOG_CRITICAL(Frontend, "Failed to load ROM!"); 175 LOG_CRITICAL(Frontend, "Failed to load ROM!");
176 return -1; 176 return -1;
177 case Core::System::ResultStatus::ErrorLoader_ErrorMissingKeys:
178 LOG_CRITICAL(Frontend, "The game you are trying to load is encrypted and the keys required "
179 "could not be found. Please refer to the yuzu wiki for help");
180 return -1;
181 case Core::System::ResultStatus::ErrorLoader_ErrorDecrypting:
182 LOG_CRITICAL(Frontend, "The game you are trying to load is encrypted and there was a "
183 "general error while decrypting. This could mean that the keys are "
184 "incorrect, game is invalid or game uses an unsupported method of "
185 "crypto. Please double-check your keys");
186 return -1;
187 case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
188 LOG_CRITICAL(Frontend, "Error while loading ROM: The ROM format is not supported.");
189 return -1;
190 case Core::System::ResultStatus::ErrorNotInitialized: 177 case Core::System::ResultStatus::ErrorNotInitialized:
191 LOG_CRITICAL(Frontend, "CPUCore not initialized"); 178 LOG_CRITICAL(Frontend, "CPUCore not initialized");
192 return -1; 179 return -1;
@@ -198,6 +185,17 @@ int main(int argc, char** argv) {
198 return -1; 185 return -1;
199 case Core::System::ResultStatus::Success: 186 case Core::System::ResultStatus::Success:
200 break; // Expected case 187 break; // Expected case
188 default:
189 if (static_cast<u32>(load_result) >
190 static_cast<u32>(Core::System::ResultStatus::ErrorLoader)) {
191 const u16 loader_id = static_cast<u16>(Core::System::ResultStatus::ErrorLoader);
192 const u16 error_id = static_cast<u16>(load_result) - loader_id;
193 LOG_CRITICAL(Frontend,
194 "While attempting to load the ROM requested, an error occured. Please "
195 "refer to the yuzu wiki for more information or the yuzu discord for "
196 "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}",
197 loader_id, error_id, Loader::GetMessageForResultStatus(error_id));
198 }
201 } 199 }
202 200
203 Core::Telemetry().AddField(Telemetry::FieldType::App, "Frontend", "SDL"); 201 Core::Telemetry().AddField(Telemetry::FieldType::App, "Frontend", "SDL");