summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/core.cpp30
-rw-r--r--src/core/core.h33
-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/frontend/emu_window.cpp4
-rw-r--r--src/core/frontend/emu_window.h4
-rw-r--r--src/core/hle/kernel/server_session.cpp8
-rw-r--r--src/core/hle/service/friend/friend.cpp104
-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/maxwell_3d.h26
-rw-r--r--src/video_core/engines/shader_bytecode.h3
-rw-r--r--src/video_core/gpu.cpp3
-rw-r--r--src/video_core/gpu.h3
-rw-r--r--src/video_core/renderer_base.cpp2
-rw-r--r--src/video_core/renderer_base.h6
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp11
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h9
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp24
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h122
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp26
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h19
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp8
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h8
-rw-r--r--src/video_core/video_core.cpp2
-rw-r--r--src/video_core/video_core.h4
-rw-r--r--src/yuzu/bootmanager.h2
-rw-r--r--src/yuzu/game_list.cpp5
-rw-r--r--src/yuzu/main.cpp76
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.h2
-rw-r--r--src/yuzu_cmd/yuzu.cpp24
39 files changed, 573 insertions, 267 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 69c45c026..83d4d742b 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -88,7 +88,7 @@ System::ResultStatus System::SingleStep() {
88 return RunLoop(false); 88 return RunLoop(false);
89} 89}
90 90
91System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& filepath) { 91System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
92 app_loader = Loader::GetLoader(virtual_filesystem->OpenFile(filepath, FileSys::Mode::Read)); 92 app_loader = Loader::GetLoader(virtual_filesystem->OpenFile(filepath, FileSys::Mode::Read));
93 93
94 if (!app_loader) { 94 if (!app_loader) {
@@ -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;
@@ -169,7 +151,7 @@ Cpu& System::CpuCore(size_t core_index) {
169 return *cpu_cores[core_index]; 151 return *cpu_cores[core_index];
170} 152}
171 153
172System::ResultStatus System::Init(EmuWindow& emu_window) { 154System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
173 LOG_DEBUG(HW_Memory, "initialized OK"); 155 LOG_DEBUG(HW_Memory, "initialized OK");
174 156
175 CoreTiming::Init(); 157 CoreTiming::Init();
diff --git a/src/core/core.h b/src/core/core.h
index 7cf7ea4e1..d98b15a71 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -22,9 +22,12 @@
22#include "video_core/debug_utils/debug_utils.h" 22#include "video_core/debug_utils/debug_utils.h"
23#include "video_core/gpu.h" 23#include "video_core/gpu.h"
24 24
25class EmuWindow;
26class ARM_Interface; 25class ARM_Interface;
27 26
27namespace Core::Frontend {
28class EmuWindow;
29}
30
28namespace Service::SM { 31namespace Service::SM {
29class ServiceManager; 32class ServiceManager;
30} 33}
@@ -49,21 +52,15 @@ public:
49 52
50 /// Enumeration representing the return values of the System Initialize and Load process. 53 /// Enumeration representing the return values of the System Initialize and Load process.
51 enum class ResultStatus : u32 { 54 enum class ResultStatus : u32 {
52 Success, ///< Succeeded 55 Success, ///< Succeeded
53 ErrorNotInitialized, ///< Error trying to use core prior to initialization 56 ErrorNotInitialized, ///< Error trying to use core prior to initialization
54 ErrorGetLoader, ///< Error finding the correct application loader 57 ErrorGetLoader, ///< Error finding the correct application loader
55 ErrorSystemMode, ///< Error determining the system mode 58 ErrorSystemMode, ///< Error determining the system mode
56 ErrorLoader, ///< Error loading the specified application 59 ErrorSystemFiles, ///< Error in finding system files
57 ErrorLoader_ErrorMissingKeys, ///< Error because the key/keys needed to run could not be 60 ErrorSharedFont, ///< Error in finding shared font
58 ///< found. 61 ErrorVideoCore, ///< Error in the video core
59 ErrorLoader_ErrorDecrypting, ///< Error loading the specified application due to encryption 62 ErrorUnknown, ///< Any other error
60 ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an 63 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 }; 64 };
68 65
69 /** 66 /**
@@ -105,7 +102,7 @@ public:
105 * @param filepath String path to the executable application to load on the host file system. 102 * @param filepath String path to the executable application to load on the host file system.
106 * @returns ResultStatus code, indicating if the operation succeeded. 103 * @returns ResultStatus code, indicating if the operation succeeded.
107 */ 104 */
108 ResultStatus Load(EmuWindow& emu_window, const std::string& filepath); 105 ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath);
109 106
110 /** 107 /**
111 * Indicates if the emulated system is powered on (all subsystems initialized and able to run an 108 * Indicates if the emulated system is powered on (all subsystems initialized and able to run an
@@ -233,7 +230,7 @@ private:
233 * input. 230 * input.
234 * @return ResultStatus code, indicating if the operation succeeded. 231 * @return ResultStatus code, indicating if the operation succeeded.
235 */ 232 */
236 ResultStatus Init(EmuWindow& emu_window); 233 ResultStatus Init(Frontend::EmuWindow& emu_window);
237 234
238 /// RealVfsFilesystem instance 235 /// RealVfsFilesystem instance
239 FileSys::VirtualFilesystem virtual_filesystem; 236 FileSys::VirtualFilesystem virtual_filesystem;
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/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp
index 2d776c693..9dd493efb 100644
--- a/src/core/frontend/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -8,6 +8,8 @@
8#include "core/frontend/input.h" 8#include "core/frontend/input.h"
9#include "core/settings.h" 9#include "core/settings.h"
10 10
11namespace Core::Frontend {
12
11class EmuWindow::TouchState : public Input::Factory<Input::TouchDevice>, 13class EmuWindow::TouchState : public Input::Factory<Input::TouchDevice>,
12 public std::enable_shared_from_this<TouchState> { 14 public std::enable_shared_from_this<TouchState> {
13public: 15public:
@@ -108,3 +110,5 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
108void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) { 110void EmuWindow::UpdateCurrentFramebufferLayout(unsigned width, unsigned height) {
109 NotifyFramebufferLayoutChanged(Layout::DefaultFrameLayout(width, height)); 111 NotifyFramebufferLayoutChanged(Layout::DefaultFrameLayout(width, height));
110} 112}
113
114} // namespace Core::Frontend
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index e8c29adfb..384dc7822 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -10,6 +10,8 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/frontend/framebuffer_layout.h" 11#include "core/frontend/framebuffer_layout.h"
12 12
13namespace Core::Frontend {
14
13/** 15/**
14 * Abstraction class used to provide an interface between emulation code and the frontend 16 * Abstraction class used to provide an interface between emulation code and the frontend
15 * (e.g. SDL, QGLWidget, GLFW, etc...). 17 * (e.g. SDL, QGLWidget, GLFW, etc...).
@@ -166,3 +168,5 @@ private:
166 */ 168 */
167 std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y); 169 std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y);
168}; 170};
171
172} // namespace Core::Frontend
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 93560152f..d09ca5992 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -71,6 +71,14 @@ ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& con
71 const u32 object_id{context.GetDomainMessageHeader()->object_id}; 71 const u32 object_id{context.GetDomainMessageHeader()->object_id};
72 switch (domain_message_header->command) { 72 switch (domain_message_header->command) {
73 case IPC::DomainMessageHeader::CommandType::SendMessage: 73 case IPC::DomainMessageHeader::CommandType::SendMessage:
74 if (object_id > domain_request_handlers.size()) {
75 LOG_CRITICAL(IPC,
76 "object_id {} is too big! This probably means a recent service call "
77 "to {} needed to return a new interface!",
78 object_id, name);
79 UNREACHABLE();
80 return RESULT_SUCCESS; // Ignore error if asserts are off
81 }
74 return domain_request_handlers[object_id - 1]->HandleSyncRequest(context); 82 return domain_request_handlers[object_id - 1]->HandleSyncRequest(context);
75 83
76 case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { 84 case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: {
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp
index fb4d89068..f2b0e509a 100644
--- a/src/core/hle/service/friend/friend.cpp
+++ b/src/core/hle/service/friend/friend.cpp
@@ -9,10 +9,110 @@
9 9
10namespace Service::Friend { 10namespace Service::Friend {
11 11
12class IFriendService final : public ServiceFramework<IFriendService> {
13public:
14 IFriendService() : ServiceFramework("IFriendService") {
15 static const FunctionInfo functions[] = {
16 {0, nullptr, "GetCompletionEvent"},
17 {1, nullptr, "Cancel"},
18 {10100, nullptr, "GetFriendListIds"},
19 {10101, nullptr, "GetFriendList"},
20 {10102, nullptr, "UpdateFriendInfo"},
21 {10110, nullptr, "GetFriendProfileImage"},
22 {10200, nullptr, "SendFriendRequestForApplication"},
23 {10211, nullptr, "AddFacedFriendRequestForApplication"},
24 {10400, nullptr, "GetBlockedUserListIds"},
25 {10500, nullptr, "GetProfileList"},
26 {10600, nullptr, "DeclareOpenOnlinePlaySession"},
27 {10601, &IFriendService::DeclareCloseOnlinePlaySession,
28 "DeclareCloseOnlinePlaySession"},
29 {10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"},
30 {10700, nullptr, "GetPlayHistoryRegistrationKey"},
31 {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
32 {10702, nullptr, "AddPlayHistory"},
33 {11000, nullptr, "GetProfileImageUrl"},
34 {20100, nullptr, "GetFriendCount"},
35 {20101, nullptr, "GetNewlyFriendCount"},
36 {20102, nullptr, "GetFriendDetailedInfo"},
37 {20103, nullptr, "SyncFriendList"},
38 {20104, nullptr, "RequestSyncFriendList"},
39 {20110, nullptr, "LoadFriendSetting"},
40 {20200, nullptr, "GetReceivedFriendRequestCount"},
41 {20201, nullptr, "GetFriendRequestList"},
42 {20300, nullptr, "GetFriendCandidateList"},
43 {20301, nullptr, "GetNintendoNetworkIdInfo"},
44 {20302, nullptr, "GetSnsAccountLinkage"},
45 {20303, nullptr, "GetSnsAccountProfile"},
46 {20304, nullptr, "GetSnsAccountFriendList"},
47 {20400, nullptr, "GetBlockedUserList"},
48 {20401, nullptr, "SyncBlockedUserList"},
49 {20500, nullptr, "GetProfileExtraList"},
50 {20501, nullptr, "GetRelationship"},
51 {20600, nullptr, "GetUserPresenceView"},
52 {20700, nullptr, "GetPlayHistoryList"},
53 {20701, nullptr, "GetPlayHistoryStatistics"},
54 {20800, nullptr, "LoadUserSetting"},
55 {20801, nullptr, "SyncUserSetting"},
56 {20900, nullptr, "RequestListSummaryOverlayNotification"},
57 {21000, nullptr, "GetExternalApplicationCatalog"},
58 {30100, nullptr, "DropFriendNewlyFlags"},
59 {30101, nullptr, "DeleteFriend"},
60 {30110, nullptr, "DropFriendNewlyFlag"},
61 {30120, nullptr, "ChangeFriendFavoriteFlag"},
62 {30121, nullptr, "ChangeFriendOnlineNotificationFlag"},
63 {30200, nullptr, "SendFriendRequest"},
64 {30201, nullptr, "SendFriendRequestWithApplicationInfo"},
65 {30202, nullptr, "CancelFriendRequest"},
66 {30203, nullptr, "AcceptFriendRequest"},
67 {30204, nullptr, "RejectFriendRequest"},
68 {30205, nullptr, "ReadFriendRequest"},
69 {30210, nullptr, "GetFacedFriendRequestRegistrationKey"},
70 {30211, nullptr, "AddFacedFriendRequest"},
71 {30212, nullptr, "CancelFacedFriendRequest"},
72 {30213, nullptr, "GetFacedFriendRequestProfileImage"},
73 {30214, nullptr, "GetFacedFriendRequestProfileImageFromPath"},
74 {30215, nullptr, "SendFriendRequestWithExternalApplicationCatalogId"},
75 {30216, nullptr, "ResendFacedFriendRequest"},
76 {30217, nullptr, "SendFriendRequestWithNintendoNetworkIdInfo"},
77 {30300, nullptr, "GetSnsAccountLinkPageUrl"},
78 {30301, nullptr, "UnlinkSnsAccount"},
79 {30400, nullptr, "BlockUser"},
80 {30401, nullptr, "BlockUserWithApplicationInfo"},
81 {30402, nullptr, "UnblockUser"},
82 {30500, nullptr, "GetProfileExtraFromFriendCode"},
83 {30700, nullptr, "DeletePlayHistory"},
84 {30810, nullptr, "ChangePresencePermission"},
85 {30811, nullptr, "ChangeFriendRequestReception"},
86 {30812, nullptr, "ChangePlayLogPermission"},
87 {30820, nullptr, "IssueFriendCode"},
88 {30830, nullptr, "ClearPlayLog"},
89 {49900, nullptr, "DeleteNetworkServiceAccountCache"},
90 };
91
92 RegisterHandlers(functions);
93 }
94
95private:
96 void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) {
97 // Stub used by Splatoon 2
98 LOG_WARNING(Service_ACC, "(STUBBED) called");
99 IPC::ResponseBuilder rb{ctx, 2};
100 rb.Push(RESULT_SUCCESS);
101 }
102
103 void UpdateUserPresence(Kernel::HLERequestContext& ctx) {
104 // Stub used by Retro City Rampage
105 LOG_WARNING(Service_ACC, "(STUBBED) called");
106 IPC::ResponseBuilder rb{ctx, 2};
107 rb.Push(RESULT_SUCCESS);
108 }
109};
110
12void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) { 111void Module::Interface::CreateFriendService(Kernel::HLERequestContext& ctx) {
13 IPC::ResponseBuilder rb{ctx, 2}; 112 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
14 rb.Push(RESULT_SUCCESS); 113 rb.Push(RESULT_SUCCESS);
15 LOG_WARNING(Service_Friend, "(STUBBED) called"); 114 rb.PushIpcInterface<IFriendService>();
115 LOG_DEBUG(Service_ACC, "called");
16} 116}
17 117
18Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 118Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
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/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 0506ac8fe..1b30ce018 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -93,6 +93,7 @@ public:
93 93
94 struct VertexAttribute { 94 struct VertexAttribute {
95 enum class Size : u32 { 95 enum class Size : u32 {
96 Invalid = 0x0,
96 Size_32_32_32_32 = 0x01, 97 Size_32_32_32_32 = 0x01,
97 Size_32_32_32 = 0x02, 98 Size_32_32_32 = 0x02,
98 Size_16_16_16_16 = 0x03, 99 Size_16_16_16_16 = 0x03,
@@ -257,6 +258,10 @@ public:
257 bool IsNormalized() const { 258 bool IsNormalized() const {
258 return (type == Type::SignedNorm) || (type == Type::UnsignedNorm); 259 return (type == Type::SignedNorm) || (type == Type::UnsignedNorm);
259 } 260 }
261
262 bool IsValid() const {
263 return size != Size::Invalid;
264 }
260 }; 265 };
261 266
262 enum class PrimitiveTopology : u32 { 267 enum class PrimitiveTopology : u32 {
@@ -352,6 +357,27 @@ public:
352 OneMinusConstantColor = 0x62, 357 OneMinusConstantColor = 0x62,
353 ConstantAlpha = 0x63, 358 ConstantAlpha = 0x63,
354 OneMinusConstantAlpha = 0x64, 359 OneMinusConstantAlpha = 0x64,
360
361 // These values are used by Nouveau and some games.
362 ZeroGL = 0x4000,
363 OneGL = 0x4001,
364 SourceColorGL = 0x4300,
365 OneMinusSourceColorGL = 0x4301,
366 SourceAlphaGL = 0x4302,
367 OneMinusSourceAlphaGL = 0x4303,
368 DestAlphaGL = 0x4304,
369 OneMinusDestAlphaGL = 0x4305,
370 DestColorGL = 0x4306,
371 OneMinusDestColorGL = 0x4307,
372 SourceAlphaSaturateGL = 0x4308,
373 ConstantColorGL = 0xc001,
374 OneMinusConstantColorGL = 0xc002,
375 ConstantAlphaGL = 0xc003,
376 OneMinusConstantAlphaGL = 0xc004,
377 Source1ColorGL = 0xc900,
378 OneMinusSource1ColorGL = 0xc901,
379 Source1AlphaGL = 0xc902,
380 OneMinusSource1AlphaGL = 0xc903,
355 }; 381 };
356 382
357 u32 separate_alpha; 383 u32 separate_alpha;
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 6cb7bea1c..9f64b248b 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -74,12 +74,11 @@ union Attribute {
74 enum class Index : u64 { 74 enum class Index : u64 {
75 Position = 7, 75 Position = 7,
76 Attribute_0 = 8, 76 Attribute_0 = 8,
77 Attribute_31 = 39,
77 // This attribute contains a tuple of (~, ~, InstanceId, VertexId) when inside a vertex 78 // This attribute contains a tuple of (~, ~, InstanceId, VertexId) when inside a vertex
78 // shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval 79 // shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval
79 // shader. 80 // shader.
80 TessCoordInstanceIDVertexID = 47, 81 TessCoordInstanceIDVertexID = 47,
81 // TODO(bunnei): Figure out what this is used for. Super Mario Odyssey uses this.
82 Unknown_63 = 63,
83 }; 82 };
84 83
85 union { 84 union {
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index ceaf86654..19e7f1161 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,8 +67,10 @@ 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:
73 case RenderTargetFormat::R8_UINT:
71 return 1; 74 return 1;
72 default: 75 default:
73 UNIMPLEMENTED_MSG("Unimplemented render target format {}", static_cast<u32>(format)); 76 UNIMPLEMENTED_MSG("Unimplemented render target format {}", static_cast<u32>(format));
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index b57312b3b..e008d8f26 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,12 +35,14 @@ 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,
40 R16_UINT = 0xF1, 42 R16_UINT = 0xF1,
41 R16_FLOAT = 0xF2, 43 R16_FLOAT = 0xF2,
42 R8_UNORM = 0xF3, 44 R8_UNORM = 0xF3,
45 R8_UINT = 0xF6,
43}; 46};
44 47
45enum class DepthFormat : u32 { 48enum class DepthFormat : u32 {
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp
index e87016429..afd86a83a 100644
--- a/src/video_core/renderer_base.cpp
+++ b/src/video_core/renderer_base.cpp
@@ -10,7 +10,7 @@
10 10
11namespace VideoCore { 11namespace VideoCore {
12 12
13RendererBase::RendererBase(EmuWindow& window) : render_window{window} { 13RendererBase::RendererBase(Core::Frontend::EmuWindow& window) : render_window{window} {
14 RefreshBaseSettings(); 14 RefreshBaseSettings();
15} 15}
16 16
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index fd8c47592..d9f16b8e6 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -11,7 +11,9 @@
11#include "video_core/gpu.h" 11#include "video_core/gpu.h"
12#include "video_core/rasterizer_interface.h" 12#include "video_core/rasterizer_interface.h"
13 13
14namespace Core::Frontend {
14class EmuWindow; 15class EmuWindow;
16}
15 17
16namespace VideoCore { 18namespace VideoCore {
17 19
@@ -21,7 +23,7 @@ struct RendererSettings {
21 23
22class RendererBase : NonCopyable { 24class RendererBase : NonCopyable {
23public: 25public:
24 explicit RendererBase(EmuWindow& window); 26 explicit RendererBase(Core::Frontend::EmuWindow& window);
25 virtual ~RendererBase(); 27 virtual ~RendererBase();
26 28
27 /// Swap buffers (render frame) 29 /// Swap buffers (render frame)
@@ -59,7 +61,7 @@ protected:
59 /// Refreshes settings specific to the rasterizer. 61 /// Refreshes settings specific to the rasterizer.
60 void RefreshRasterizerSetting(); 62 void RefreshRasterizerSetting();
61 63
62 EmuWindow& render_window; ///< Reference to the render window handle. 64 Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle.
63 std::unique_ptr<RasterizerInterface> rasterizer; 65 std::unique_ptr<RasterizerInterface> rasterizer;
64 f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer 66 f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer
65 int m_current_frame = 0; ///< Current frame, should be set by the renderer 67 int m_current_frame = 0; ///< Current frame, should be set by the renderer
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 8360feb5d..38a7b1413 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -36,7 +36,7 @@ MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192));
36MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255)); 36MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
37MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); 37MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
38 38
39RasterizerOpenGL::RasterizerOpenGL(EmuWindow& window) : emu_window{window} { 39RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window) : emu_window{window} {
40 // Create sampler objects 40 // Create sampler objects
41 for (size_t i = 0; i < texture_samplers.size(); ++i) { 41 for (size_t i = 0; i < texture_samplers.size(); ++i) {
42 texture_samplers[i].Create(); 42 texture_samplers[i].Create();
@@ -161,11 +161,16 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr,
161 // assume every shader uses them all. 161 // assume every shader uses them all.
162 for (unsigned index = 0; index < 16; ++index) { 162 for (unsigned index = 0; index < 16; ++index) {
163 auto& attrib = regs.vertex_attrib_format[index]; 163 auto& attrib = regs.vertex_attrib_format[index];
164
165 // Ignore invalid attributes.
166 if (!attrib.IsValid())
167 continue;
168
169 auto& buffer = regs.vertex_array[attrib.buffer];
164 LOG_TRACE(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}", 170 LOG_TRACE(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}",
165 index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(), 171 index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(),
166 attrib.offset.Value(), attrib.IsNormalized()); 172 attrib.offset.Value(), attrib.IsNormalized());
167 173
168 auto& buffer = regs.vertex_array[attrib.buffer];
169 ASSERT(buffer.IsEnabled()); 174 ASSERT(buffer.IsEnabled());
170 175
171 glEnableVertexAttribArray(index); 176 glEnableVertexAttribArray(index);
@@ -211,7 +216,7 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
211 216
212 // Next available bindpoints to use when uploading the const buffers and textures to the GLSL 217 // Next available bindpoints to use when uploading the const buffers and textures to the GLSL
213 // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points. 218 // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
214 u32 current_constbuffer_bindpoint = uniform_buffers.size(); 219 u32 current_constbuffer_bindpoint = static_cast<u32>(uniform_buffers.size());
215 u32 current_texture_bindpoint = 0; 220 u32 current_texture_bindpoint = 0;
216 221
217 for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { 222 for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 6d6d85cc1..bd01dc0ae 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -21,12 +21,15 @@
21#include "video_core/renderer_opengl/gl_state.h" 21#include "video_core/renderer_opengl/gl_state.h"
22#include "video_core/renderer_opengl/gl_stream_buffer.h" 22#include "video_core/renderer_opengl/gl_stream_buffer.h"
23 23
24class EmuWindow;
25struct ScreenInfo; 24struct ScreenInfo;
26 25
26namespace Core::Frontend {
27class EmuWindow;
28}
29
27class RasterizerOpenGL : public VideoCore::RasterizerInterface { 30class RasterizerOpenGL : public VideoCore::RasterizerInterface {
28public: 31public:
29 explicit RasterizerOpenGL(EmuWindow& renderer); 32 explicit RasterizerOpenGL(Core::Frontend::EmuWindow& renderer);
30 ~RasterizerOpenGL() override; 33 ~RasterizerOpenGL() override;
31 34
32 void DrawArrays() override; 35 void DrawArrays() override;
@@ -145,7 +148,7 @@ private:
145 148
146 RasterizerCacheOpenGL res_cache; 149 RasterizerCacheOpenGL res_cache;
147 150
148 EmuWindow& emu_window; 151 Core::Frontend::EmuWindow& emu_window;
149 152
150 std::unique_ptr<GLShader::ProgramManager> shader_program_manager; 153 std::unique_ptr<GLShader::ProgramManager> shader_program_manager;
151 OGLVertexArray sw_vao; 154 OGLVertexArray sw_vao;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 15a33ed9b..84c250c63 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -92,12 +92,14 @@ 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
99 {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5 100 {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, ComponentType::UNorm, false}, // A1B5G5R5
100 {GL_R8, GL_RED, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // R8 101 {GL_R8, GL_RED, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // R8
102 {GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // R8UI
101 {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, ComponentType::Float, false}, // RGBA16F 103 {GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, ComponentType::Float, false}, // RGBA16F
102 {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float, 104 {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float,
103 false}, // R11FG11FB10F 105 false}, // R11FG11FB10F
@@ -132,6 +134,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
132 {GL_RG16_SNORM, GL_RG, GL_SHORT, ComponentType::SNorm, false}, // RG16S 134 {GL_RG16_SNORM, GL_RG, GL_SHORT, ComponentType::SNorm, false}, // RG16S
133 {GL_RGB32F, GL_RGB, GL_FLOAT, ComponentType::Float, false}, // RGB32F 135 {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 136 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // SRGBA8
137 {GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S
135 138
136 // DepthStencil formats 139 // DepthStencil formats
137 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm, 140 {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, ComponentType::UNorm,
@@ -231,9 +234,10 @@ 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), 234static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr),
232 SurfaceParams::MaxPixelFormat> 235 SurfaceParams::MaxPixelFormat>
233 morton_to_gl_fns = { 236 morton_to_gl_fns = {
234 MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>, 237 MortonCopy<true, PixelFormat::ABGR8U>, MortonCopy<true, PixelFormat::ABGR8S>,
235 MortonCopy<true, PixelFormat::A2B10G10R10>, MortonCopy<true, PixelFormat::A1B5G5R5>, 238 MortonCopy<true, PixelFormat::B5G6R5>, MortonCopy<true, PixelFormat::A2B10G10R10>,
236 MortonCopy<true, PixelFormat::R8>, MortonCopy<true, PixelFormat::RGBA16F>, 239 MortonCopy<true, PixelFormat::A1B5G5R5>, MortonCopy<true, PixelFormat::R8>,
240 MortonCopy<true, PixelFormat::R8UI>, MortonCopy<true, PixelFormat::RGBA16F>,
237 MortonCopy<true, PixelFormat::R11FG11FB10F>, MortonCopy<true, PixelFormat::RGBA32UI>, 241 MortonCopy<true, PixelFormat::R11FG11FB10F>, MortonCopy<true, PixelFormat::RGBA32UI>,
238 MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>, 242 MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>,
239 MortonCopy<true, PixelFormat::DXT45>, MortonCopy<true, PixelFormat::DXN1>, 243 MortonCopy<true, PixelFormat::DXT45>, MortonCopy<true, PixelFormat::DXN1>,
@@ -247,19 +251,22 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPU
247 MortonCopy<true, PixelFormat::RG16>, MortonCopy<true, PixelFormat::RG16F>, 251 MortonCopy<true, PixelFormat::RG16>, MortonCopy<true, PixelFormat::RG16F>,
248 MortonCopy<true, PixelFormat::RG16UI>, MortonCopy<true, PixelFormat::RG16I>, 252 MortonCopy<true, PixelFormat::RG16UI>, MortonCopy<true, PixelFormat::RG16I>,
249 MortonCopy<true, PixelFormat::RG16S>, MortonCopy<true, PixelFormat::RGB32F>, 253 MortonCopy<true, PixelFormat::RG16S>, MortonCopy<true, PixelFormat::RGB32F>,
250 MortonCopy<true, PixelFormat::SRGBA8>, MortonCopy<true, PixelFormat::Z24S8>, 254 MortonCopy<true, PixelFormat::SRGBA8>, MortonCopy<true, PixelFormat::RG8S>,
251 MortonCopy<true, PixelFormat::S8Z24>, MortonCopy<true, PixelFormat::Z32F>, 255 MortonCopy<true, PixelFormat::Z24S8>, MortonCopy<true, PixelFormat::S8Z24>,
252 MortonCopy<true, PixelFormat::Z16>, MortonCopy<true, PixelFormat::Z32FS8>, 256 MortonCopy<true, PixelFormat::Z32F>, MortonCopy<true, PixelFormat::Z16>,
257 MortonCopy<true, PixelFormat::Z32FS8>,
253}; 258};
254 259
255static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr), 260static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr),
256 SurfaceParams::MaxPixelFormat> 261 SurfaceParams::MaxPixelFormat>
257 gl_to_morton_fns = { 262 gl_to_morton_fns = {
258 MortonCopy<false, PixelFormat::ABGR8>, 263 MortonCopy<false, PixelFormat::ABGR8U>,
264 MortonCopy<false, PixelFormat::ABGR8S>,
259 MortonCopy<false, PixelFormat::B5G6R5>, 265 MortonCopy<false, PixelFormat::B5G6R5>,
260 MortonCopy<false, PixelFormat::A2B10G10R10>, 266 MortonCopy<false, PixelFormat::A2B10G10R10>,
261 MortonCopy<false, PixelFormat::A1B5G5R5>, 267 MortonCopy<false, PixelFormat::A1B5G5R5>,
262 MortonCopy<false, PixelFormat::R8>, 268 MortonCopy<false, PixelFormat::R8>,
269 MortonCopy<false, PixelFormat::R8UI>,
263 MortonCopy<false, PixelFormat::RGBA16F>, 270 MortonCopy<false, PixelFormat::RGBA16F>,
264 MortonCopy<false, PixelFormat::R11FG11FB10F>, 271 MortonCopy<false, PixelFormat::R11FG11FB10F>,
265 MortonCopy<false, PixelFormat::RGBA32UI>, 272 MortonCopy<false, PixelFormat::RGBA32UI>,
@@ -290,6 +297,7 @@ static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPU
290 MortonCopy<false, PixelFormat::RG16S>, 297 MortonCopy<false, PixelFormat::RG16S>,
291 MortonCopy<false, PixelFormat::RGB32F>, 298 MortonCopy<false, PixelFormat::RGB32F>,
292 MortonCopy<false, PixelFormat::SRGBA8>, 299 MortonCopy<false, PixelFormat::SRGBA8>,
300 MortonCopy<false, PixelFormat::RG8S>,
293 MortonCopy<false, PixelFormat::Z24S8>, 301 MortonCopy<false, PixelFormat::Z24S8>,
294 MortonCopy<false, PixelFormat::S8Z24>, 302 MortonCopy<false, PixelFormat::S8Z24>,
295 MortonCopy<false, PixelFormat::Z32F>, 303 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..202257b58 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -23,48 +23,51 @@ 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 R8UI = 6,
33 RGBA32UI = 7, 33 RGBA16F = 7,
34 DXT1 = 8, 34 R11FG11FB10F = 8,
35 DXT23 = 9, 35 RGBA32UI = 9,
36 DXT45 = 10, 36 DXT1 = 10,
37 DXN1 = 11, // This is also known as BC4 37 DXT23 = 11,
38 DXN2UNORM = 12, 38 DXT45 = 12,
39 DXN2SNORM = 13, 39 DXN1 = 13, // This is also known as BC4
40 BC7U = 14, 40 DXN2UNORM = 14,
41 ASTC_2D_4X4 = 15, 41 DXN2SNORM = 15,
42 G8R8 = 16, 42 BC7U = 16,
43 BGRA8 = 17, 43 ASTC_2D_4X4 = 17,
44 RGBA32F = 18, 44 G8R8 = 18,
45 RG32F = 19, 45 BGRA8 = 19,
46 R32F = 20, 46 RGBA32F = 20,
47 R16F = 21, 47 RG32F = 21,
48 R16UNORM = 22, 48 R32F = 22,
49 R16S = 23, 49 R16F = 23,
50 R16UI = 24, 50 R16UNORM = 24,
51 R16I = 25, 51 R16S = 25,
52 RG16 = 26, 52 R16UI = 26,
53 RG16F = 27, 53 R16I = 27,
54 RG16UI = 28, 54 RG16 = 28,
55 RG16I = 29, 55 RG16F = 29,
56 RG16S = 30, 56 RG16UI = 30,
57 RGB32F = 31, 57 RG16I = 31,
58 SRGBA8 = 32, 58 RG16S = 32,
59 RGB32F = 33,
60 SRGBA8 = 34,
61 RG8S = 35,
59 62
60 MaxColorFormat, 63 MaxColorFormat,
61 64
62 // DepthStencil formats 65 // DepthStencil formats
63 Z24S8 = 33, 66 Z24S8 = 36,
64 S8Z24 = 34, 67 S8Z24 = 37,
65 Z32F = 35, 68 Z32F = 38,
66 Z16 = 36, 69 Z16 = 39,
67 Z32FS8 = 37, 70 Z32FS8 = 40,
68 71
69 MaxDepthStencilFormat, 72 MaxDepthStencilFormat,
70 73
@@ -102,11 +105,13 @@ struct SurfaceParams {
102 return 0; 105 return 0;
103 106
104 constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{ 107 constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
105 1, // ABGR8 108 1, // ABGR8U
109 1, // ABGR8S
106 1, // B5G6R5 110 1, // B5G6R5
107 1, // A2B10G10R10 111 1, // A2B10G10R10
108 1, // A1B5G5R5 112 1, // A1B5G5R5
109 1, // R8 113 1, // R8
114 1, // R8UI
110 1, // RGBA16F 115 1, // RGBA16F
111 1, // R11FG11FB10F 116 1, // R11FG11FB10F
112 1, // RGBA32UI 117 1, // RGBA32UI
@@ -135,6 +140,7 @@ struct SurfaceParams {
135 1, // RG16S 140 1, // RG16S
136 1, // RGB32F 141 1, // RGB32F
137 1, // SRGBA8 142 1, // SRGBA8
143 1, // RG8S
138 1, // Z24S8 144 1, // Z24S8
139 1, // S8Z24 145 1, // S8Z24
140 1, // Z32F 146 1, // Z32F
@@ -151,11 +157,13 @@ struct SurfaceParams {
151 return 0; 157 return 0;
152 158
153 constexpr std::array<u32, MaxPixelFormat> bpp_table = {{ 159 constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
154 32, // ABGR8 160 32, // ABGR8U
161 32, // ABGR8S
155 16, // B5G6R5 162 16, // B5G6R5
156 32, // A2B10G10R10 163 32, // A2B10G10R10
157 16, // A1B5G5R5 164 16, // A1B5G5R5
158 8, // R8 165 8, // R8
166 8, // R8UI
159 64, // RGBA16F 167 64, // RGBA16F
160 32, // R11FG11FB10F 168 32, // R11FG11FB10F
161 128, // RGBA32UI 169 128, // RGBA32UI
@@ -184,6 +192,7 @@ struct SurfaceParams {
184 32, // RG16S 192 32, // RG16S
185 96, // RGB32F 193 96, // RGB32F
186 32, // SRGBA8 194 32, // SRGBA8
195 16, // RG8S
187 32, // Z24S8 196 32, // Z24S8
188 32, // S8Z24 197 32, // S8Z24
189 32, // Z32F 198 32, // Z32F
@@ -223,7 +232,9 @@ struct SurfaceParams {
223 // gamma. 232 // gamma.
224 case Tegra::RenderTargetFormat::RGBA8_SRGB: 233 case Tegra::RenderTargetFormat::RGBA8_SRGB:
225 case Tegra::RenderTargetFormat::RGBA8_UNORM: 234 case Tegra::RenderTargetFormat::RGBA8_UNORM:
226 return PixelFormat::ABGR8; 235 return PixelFormat::ABGR8U;
236 case Tegra::RenderTargetFormat::RGBA8_SNORM:
237 return PixelFormat::ABGR8S;
227 case Tegra::RenderTargetFormat::BGRA8_UNORM: 238 case Tegra::RenderTargetFormat::BGRA8_UNORM:
228 return PixelFormat::BGRA8; 239 return PixelFormat::BGRA8;
229 case Tegra::RenderTargetFormat::RGB10_A2_UNORM: 240 case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
@@ -242,6 +253,8 @@ struct SurfaceParams {
242 return PixelFormat::RGBA32UI; 253 return PixelFormat::RGBA32UI;
243 case Tegra::RenderTargetFormat::R8_UNORM: 254 case Tegra::RenderTargetFormat::R8_UNORM:
244 return PixelFormat::R8; 255 return PixelFormat::R8;
256 case Tegra::RenderTargetFormat::R8_UINT:
257 return PixelFormat::R8UI;
245 case Tegra::RenderTargetFormat::RG16_FLOAT: 258 case Tegra::RenderTargetFormat::RG16_FLOAT:
246 return PixelFormat::RG16F; 259 return PixelFormat::RG16F;
247 case Tegra::RenderTargetFormat::RG16_UINT: 260 case Tegra::RenderTargetFormat::RG16_UINT:
@@ -252,6 +265,8 @@ struct SurfaceParams {
252 return PixelFormat::RG16; 265 return PixelFormat::RG16;
253 case Tegra::RenderTargetFormat::RG16_SNORM: 266 case Tegra::RenderTargetFormat::RG16_SNORM:
254 return PixelFormat::RG16S; 267 return PixelFormat::RG16S;
268 case Tegra::RenderTargetFormat::RG8_SNORM:
269 return PixelFormat::RG8S;
255 case Tegra::RenderTargetFormat::R16_FLOAT: 270 case Tegra::RenderTargetFormat::R16_FLOAT:
256 return PixelFormat::R16F; 271 return PixelFormat::R16F;
257 case Tegra::RenderTargetFormat::R16_UNORM: 272 case Tegra::RenderTargetFormat::R16_UNORM:
@@ -275,7 +290,15 @@ struct SurfaceParams {
275 // TODO(Subv): Properly implement this 290 // TODO(Subv): Properly implement this
276 switch (format) { 291 switch (format) {
277 case Tegra::Texture::TextureFormat::A8R8G8B8: 292 case Tegra::Texture::TextureFormat::A8R8G8B8:
278 return PixelFormat::ABGR8; 293 switch (component_type) {
294 case Tegra::Texture::ComponentType::UNORM:
295 return PixelFormat::ABGR8U;
296 case Tegra::Texture::ComponentType::SNORM:
297 return PixelFormat::ABGR8S;
298 }
299 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
300 static_cast<u32>(component_type));
301 UNREACHABLE();
279 case Tegra::Texture::TextureFormat::B5G6R5: 302 case Tegra::Texture::TextureFormat::B5G6R5:
280 return PixelFormat::B5G6R5; 303 return PixelFormat::B5G6R5;
281 case Tegra::Texture::TextureFormat::A2B10G10R10: 304 case Tegra::Texture::TextureFormat::A2B10G10R10:
@@ -283,7 +306,15 @@ struct SurfaceParams {
283 case Tegra::Texture::TextureFormat::A1B5G5R5: 306 case Tegra::Texture::TextureFormat::A1B5G5R5:
284 return PixelFormat::A1B5G5R5; 307 return PixelFormat::A1B5G5R5;
285 case Tegra::Texture::TextureFormat::R8: 308 case Tegra::Texture::TextureFormat::R8:
286 return PixelFormat::R8; 309 switch (component_type) {
310 case Tegra::Texture::ComponentType::UNORM:
311 return PixelFormat::R8;
312 case Tegra::Texture::ComponentType::UINT:
313 return PixelFormat::R8UI;
314 }
315 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
316 static_cast<u32>(component_type));
317 UNREACHABLE();
287 case Tegra::Texture::TextureFormat::G8R8: 318 case Tegra::Texture::TextureFormat::G8R8:
288 return PixelFormat::G8R8; 319 return PixelFormat::G8R8;
289 case Tegra::Texture::TextureFormat::R16_G16_B16_A16: 320 case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
@@ -402,8 +433,10 @@ struct SurfaceParams {
402 case Tegra::RenderTargetFormat::R16_UNORM: 433 case Tegra::RenderTargetFormat::R16_UNORM:
403 case Tegra::RenderTargetFormat::B5G6R5_UNORM: 434 case Tegra::RenderTargetFormat::B5G6R5_UNORM:
404 return ComponentType::UNorm; 435 return ComponentType::UNorm;
436 case Tegra::RenderTargetFormat::RGBA8_SNORM:
405 case Tegra::RenderTargetFormat::RG16_SNORM: 437 case Tegra::RenderTargetFormat::RG16_SNORM:
406 case Tegra::RenderTargetFormat::R16_SNORM: 438 case Tegra::RenderTargetFormat::R16_SNORM:
439 case Tegra::RenderTargetFormat::RG8_SNORM:
407 return ComponentType::SNorm; 440 return ComponentType::SNorm;
408 case Tegra::RenderTargetFormat::RGBA16_FLOAT: 441 case Tegra::RenderTargetFormat::RGBA16_FLOAT:
409 case Tegra::RenderTargetFormat::R11G11B10_FLOAT: 442 case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
@@ -415,6 +448,7 @@ struct SurfaceParams {
415 return ComponentType::Float; 448 return ComponentType::Float;
416 case Tegra::RenderTargetFormat::RGBA32_UINT: 449 case Tegra::RenderTargetFormat::RGBA32_UINT:
417 case Tegra::RenderTargetFormat::RG16_UINT: 450 case Tegra::RenderTargetFormat::RG16_UINT:
451 case Tegra::RenderTargetFormat::R8_UINT:
418 case Tegra::RenderTargetFormat::R16_UINT: 452 case Tegra::RenderTargetFormat::R16_UINT:
419 return ComponentType::UInt; 453 return ComponentType::UInt;
420 case Tegra::RenderTargetFormat::RG16_SINT: 454 case Tegra::RenderTargetFormat::RG16_SINT:
@@ -429,7 +463,7 @@ struct SurfaceParams {
429 static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) { 463 static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
430 switch (format) { 464 switch (format) {
431 case Tegra::FramebufferConfig::PixelFormat::ABGR8: 465 case Tegra::FramebufferConfig::PixelFormat::ABGR8:
432 return PixelFormat::ABGR8; 466 return PixelFormat::ABGR8U;
433 default: 467 default:
434 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); 468 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
435 UNREACHABLE(); 469 UNREACHABLE();
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 8954deb81..d21daf28a 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -358,7 +358,12 @@ public:
358 void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) { 358 void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) {
359 std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem); 359 std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem);
360 std::string src = GetRegisterAsFloat(reg); 360 std::string src = GetRegisterAsFloat(reg);
361 shader.AddLine(dest + " = " + src + ';'); 361
362 if (!dest.empty()) {
363 // Can happen with unknown/unimplemented output attributes, in which case we ignore the
364 // instruction for now.
365 shader.AddLine(dest + " = " + src + ';');
366 }
362 } 367 }
363 368
364 /// Generates code representing a uniform (C buffer) register, interpreted as the input type. 369 /// Generates code representing a uniform (C buffer) register, interpreted as the input type.
@@ -534,20 +539,16 @@ private:
534 // shader. 539 // shader.
535 ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex); 540 ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex);
536 return "vec4(0, 0, uintBitsToFloat(gl_InstanceID), uintBitsToFloat(gl_VertexID))"; 541 return "vec4(0, 0, uintBitsToFloat(gl_InstanceID), uintBitsToFloat(gl_VertexID))";
537 case Attribute::Index::Unknown_63:
538 // TODO(bunnei): Figure out what this is used for. Super Mario Odyssey uses this.
539 LOG_CRITICAL(HW_GPU, "Unhandled input attribute Unknown_63");
540 UNREACHABLE();
541 break;
542 default: 542 default:
543 const u32 index{static_cast<u32>(attribute) - 543 const u32 index{static_cast<u32>(attribute) -
544 static_cast<u32>(Attribute::Index::Attribute_0)}; 544 static_cast<u32>(Attribute::Index::Attribute_0)};
545 if (attribute >= Attribute::Index::Attribute_0) { 545 if (attribute >= Attribute::Index::Attribute_0 &&
546 attribute <= Attribute::Index::Attribute_31) {
546 declr_input_attribute.insert(attribute); 547 declr_input_attribute.insert(attribute);
547 return "input_attribute_" + std::to_string(index); 548 return "input_attribute_" + std::to_string(index);
548 } 549 }
549 550
550 LOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", index); 551 LOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", static_cast<u32>(attribute));
551 UNREACHABLE(); 552 UNREACHABLE();
552 } 553 }
553 554
@@ -569,6 +570,7 @@ private:
569 570
570 LOG_CRITICAL(HW_GPU, "Unhandled output attribute: {}", index); 571 LOG_CRITICAL(HW_GPU, "Unhandled output attribute: {}", index);
571 UNREACHABLE(); 572 UNREACHABLE();
573 return {};
572 } 574 }
573 } 575 }
574 576
@@ -1665,7 +1667,15 @@ private:
1665 } 1667 }
1666 case OpCode::Id::KIL: { 1668 case OpCode::Id::KIL: {
1667 ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always); 1669 ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
1670
1671 // Enclose "discard" in a conditional, so that GLSL compilation does not complain
1672 // about unexecuted instructions that may follow this.
1673 shader.AddLine("if (true) {");
1674 ++shader.scope;
1668 shader.AddLine("discard;"); 1675 shader.AddLine("discard;");
1676 --shader.scope;
1677 shader.AddLine("}");
1678
1669 break; 1679 break;
1670 } 1680 }
1671 case OpCode::Id::BRA: { 1681 case OpCode::Id::BRA: {
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index c439446b1..5afd20dbe 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -156,42 +156,61 @@ inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
156inline GLenum BlendFunc(Maxwell::Blend::Factor factor) { 156inline GLenum BlendFunc(Maxwell::Blend::Factor factor) {
157 switch (factor) { 157 switch (factor) {
158 case Maxwell::Blend::Factor::Zero: 158 case Maxwell::Blend::Factor::Zero:
159 case Maxwell::Blend::Factor::ZeroGL:
159 return GL_ZERO; 160 return GL_ZERO;
160 case Maxwell::Blend::Factor::One: 161 case Maxwell::Blend::Factor::One:
162 case Maxwell::Blend::Factor::OneGL:
161 return GL_ONE; 163 return GL_ONE;
162 case Maxwell::Blend::Factor::SourceColor: 164 case Maxwell::Blend::Factor::SourceColor:
165 case Maxwell::Blend::Factor::SourceColorGL:
163 return GL_SRC_COLOR; 166 return GL_SRC_COLOR;
164 case Maxwell::Blend::Factor::OneMinusSourceColor: 167 case Maxwell::Blend::Factor::OneMinusSourceColor:
168 case Maxwell::Blend::Factor::OneMinusSourceColorGL:
165 return GL_ONE_MINUS_SRC_COLOR; 169 return GL_ONE_MINUS_SRC_COLOR;
166 case Maxwell::Blend::Factor::SourceAlpha: 170 case Maxwell::Blend::Factor::SourceAlpha:
171 case Maxwell::Blend::Factor::SourceAlphaGL:
167 return GL_SRC_ALPHA; 172 return GL_SRC_ALPHA;
168 case Maxwell::Blend::Factor::OneMinusSourceAlpha: 173 case Maxwell::Blend::Factor::OneMinusSourceAlpha:
174 case Maxwell::Blend::Factor::OneMinusSourceAlphaGL:
169 return GL_ONE_MINUS_SRC_ALPHA; 175 return GL_ONE_MINUS_SRC_ALPHA;
170 case Maxwell::Blend::Factor::DestAlpha: 176 case Maxwell::Blend::Factor::DestAlpha:
177 case Maxwell::Blend::Factor::DestAlphaGL:
171 return GL_DST_ALPHA; 178 return GL_DST_ALPHA;
172 case Maxwell::Blend::Factor::OneMinusDestAlpha: 179 case Maxwell::Blend::Factor::OneMinusDestAlpha:
180 case Maxwell::Blend::Factor::OneMinusDestAlphaGL:
173 return GL_ONE_MINUS_DST_ALPHA; 181 return GL_ONE_MINUS_DST_ALPHA;
174 case Maxwell::Blend::Factor::DestColor: 182 case Maxwell::Blend::Factor::DestColor:
183 case Maxwell::Blend::Factor::DestColorGL:
175 return GL_DST_COLOR; 184 return GL_DST_COLOR;
176 case Maxwell::Blend::Factor::OneMinusDestColor: 185 case Maxwell::Blend::Factor::OneMinusDestColor:
186 case Maxwell::Blend::Factor::OneMinusDestColorGL:
177 return GL_ONE_MINUS_DST_COLOR; 187 return GL_ONE_MINUS_DST_COLOR;
178 case Maxwell::Blend::Factor::SourceAlphaSaturate: 188 case Maxwell::Blend::Factor::SourceAlphaSaturate:
189 case Maxwell::Blend::Factor::SourceAlphaSaturateGL:
179 return GL_SRC_ALPHA_SATURATE; 190 return GL_SRC_ALPHA_SATURATE;
180 case Maxwell::Blend::Factor::Source1Color: 191 case Maxwell::Blend::Factor::Source1Color:
192 case Maxwell::Blend::Factor::Source1ColorGL:
181 return GL_SRC1_COLOR; 193 return GL_SRC1_COLOR;
182 case Maxwell::Blend::Factor::OneMinusSource1Color: 194 case Maxwell::Blend::Factor::OneMinusSource1Color:
195 case Maxwell::Blend::Factor::OneMinusSource1ColorGL:
183 return GL_ONE_MINUS_SRC1_COLOR; 196 return GL_ONE_MINUS_SRC1_COLOR;
184 case Maxwell::Blend::Factor::Source1Alpha: 197 case Maxwell::Blend::Factor::Source1Alpha:
198 case Maxwell::Blend::Factor::Source1AlphaGL:
185 return GL_SRC1_ALPHA; 199 return GL_SRC1_ALPHA;
186 case Maxwell::Blend::Factor::OneMinusSource1Alpha: 200 case Maxwell::Blend::Factor::OneMinusSource1Alpha:
201 case Maxwell::Blend::Factor::OneMinusSource1AlphaGL:
187 return GL_ONE_MINUS_SRC1_ALPHA; 202 return GL_ONE_MINUS_SRC1_ALPHA;
188 case Maxwell::Blend::Factor::ConstantColor: 203 case Maxwell::Blend::Factor::ConstantColor:
204 case Maxwell::Blend::Factor::ConstantColorGL:
189 return GL_CONSTANT_COLOR; 205 return GL_CONSTANT_COLOR;
190 case Maxwell::Blend::Factor::OneMinusConstantColor: 206 case Maxwell::Blend::Factor::OneMinusConstantColor:
207 case Maxwell::Blend::Factor::OneMinusConstantColorGL:
191 return GL_ONE_MINUS_CONSTANT_COLOR; 208 return GL_ONE_MINUS_CONSTANT_COLOR;
192 case Maxwell::Blend::Factor::ConstantAlpha: 209 case Maxwell::Blend::Factor::ConstantAlpha:
210 case Maxwell::Blend::Factor::ConstantAlphaGL:
193 return GL_CONSTANT_ALPHA; 211 return GL_CONSTANT_ALPHA;
194 case Maxwell::Blend::Factor::OneMinusConstantAlpha: 212 case Maxwell::Blend::Factor::OneMinusConstantAlpha:
213 case Maxwell::Blend::Factor::OneMinusConstantAlphaGL:
195 return GL_ONE_MINUS_CONSTANT_ALPHA; 214 return GL_ONE_MINUS_CONSTANT_ALPHA;
196 } 215 }
197 LOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor)); 216 LOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor));
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 899865e3b..95f1aa0fe 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -18,7 +18,6 @@
18#include "core/tracer/recorder.h" 18#include "core/tracer/recorder.h"
19#include "video_core/renderer_opengl/renderer_opengl.h" 19#include "video_core/renderer_opengl/renderer_opengl.h"
20#include "video_core/utils.h" 20#include "video_core/utils.h"
21#include "video_core/video_core.h"
22 21
23static const char vertex_shader[] = R"( 22static const char vertex_shader[] = R"(
24#version 150 core 23#version 150 core
@@ -92,7 +91,8 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons
92 return matrix; 91 return matrix;
93} 92}
94 93
95ScopeAcquireGLContext::ScopeAcquireGLContext(EmuWindow& emu_window_) : emu_window{emu_window_} { 94ScopeAcquireGLContext::ScopeAcquireGLContext(Core::Frontend::EmuWindow& emu_window_)
95 : emu_window{emu_window_} {
96 if (Settings::values.use_multi_core) { 96 if (Settings::values.use_multi_core) {
97 emu_window.MakeCurrent(); 97 emu_window.MakeCurrent();
98 } 98 }
@@ -103,7 +103,9 @@ ScopeAcquireGLContext::~ScopeAcquireGLContext() {
103 } 103 }
104} 104}
105 105
106RendererOpenGL::RendererOpenGL(EmuWindow& window) : VideoCore::RendererBase{window} {} 106RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& window)
107 : VideoCore::RendererBase{window} {}
108
107RendererOpenGL::~RendererOpenGL() = default; 109RendererOpenGL::~RendererOpenGL() = default;
108 110
109/// Swap buffers (render frame) 111/// Swap buffers (render frame)
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 428afa3b7..a5eab6997 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -12,7 +12,9 @@
12#include "video_core/renderer_opengl/gl_resource_manager.h" 12#include "video_core/renderer_opengl/gl_resource_manager.h"
13#include "video_core/renderer_opengl/gl_state.h" 13#include "video_core/renderer_opengl/gl_state.h"
14 14
15namespace Core::Frontend {
15class EmuWindow; 16class EmuWindow;
17}
16 18
17/// Structure used for storing information about the textures for the Switch screen 19/// Structure used for storing information about the textures for the Switch screen
18struct TextureInfo { 20struct TextureInfo {
@@ -34,16 +36,16 @@ struct ScreenInfo {
34/// Helper class to acquire/release OpenGL context within a given scope 36/// Helper class to acquire/release OpenGL context within a given scope
35class ScopeAcquireGLContext : NonCopyable { 37class ScopeAcquireGLContext : NonCopyable {
36public: 38public:
37 explicit ScopeAcquireGLContext(EmuWindow& window); 39 explicit ScopeAcquireGLContext(Core::Frontend::EmuWindow& window);
38 ~ScopeAcquireGLContext(); 40 ~ScopeAcquireGLContext();
39 41
40private: 42private:
41 EmuWindow& emu_window; 43 Core::Frontend::EmuWindow& emu_window;
42}; 44};
43 45
44class RendererOpenGL : public VideoCore::RendererBase { 46class RendererOpenGL : public VideoCore::RendererBase {
45public: 47public:
46 explicit RendererOpenGL(EmuWindow& window); 48 explicit RendererOpenGL(Core::Frontend::EmuWindow& window);
47 ~RendererOpenGL() override; 49 ~RendererOpenGL() override;
48 50
49 /// Swap buffers (render frame) 51 /// Swap buffers (render frame)
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index 1e686b89e..6780d1c16 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -9,7 +9,7 @@
9 9
10namespace VideoCore { 10namespace VideoCore {
11 11
12std::unique_ptr<RendererBase> CreateRenderer(EmuWindow& emu_window) { 12std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window) {
13 return std::make_unique<RendererOpenGL>(emu_window); 13 return std::make_unique<RendererOpenGL>(emu_window);
14} 14}
15 15
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index 2dc07540f..f79f85dfe 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -6,7 +6,9 @@
6 6
7#include <memory> 7#include <memory>
8 8
9namespace Core::Frontend {
9class EmuWindow; 10class EmuWindow;
11}
10 12
11namespace VideoCore { 13namespace VideoCore {
12 14
@@ -18,6 +20,6 @@ class RendererBase;
18 * @note The returned renderer instance is simply allocated. Its Init() 20 * @note The returned renderer instance is simply allocated. Its Init()
19 * function still needs to be called to fully complete its setup. 21 * function still needs to be called to fully complete its setup.
20 */ 22 */
21std::unique_ptr<RendererBase> CreateRenderer(EmuWindow& emu_window); 23std::unique_ptr<RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window);
22 24
23} // namespace VideoCore 25} // namespace VideoCore
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h
index d0f990c64..f133bfadf 100644
--- a/src/yuzu/bootmanager.h
+++ b/src/yuzu/bootmanager.h
@@ -101,7 +101,7 @@ signals:
101 void ErrorThrown(Core::System::ResultStatus, std::string); 101 void ErrorThrown(Core::System::ResultStatus, std::string);
102}; 102};
103 103
104class GRenderWindow : public QWidget, public EmuWindow { 104class GRenderWindow : public QWidget, public Core::Frontend::EmuWindow {
105 Q_OBJECT 105 Q_OBJECT
106 106
107public: 107public:
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/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
index 1d835c3c6..d34902109 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h
@@ -10,7 +10,7 @@
10 10
11struct SDL_Window; 11struct SDL_Window;
12 12
13class EmuWindow_SDL2 : public EmuWindow { 13class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
14public: 14public:
15 explicit EmuWindow_SDL2(bool fullscreen); 15 explicit EmuWindow_SDL2(bool fullscreen);
16 ~EmuWindow_SDL2(); 16 ~EmuWindow_SDL2();
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");