summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/audio_core/time_stretch.cpp6
-rw-r--r--src/common/telemetry.h4
-rw-r--r--src/core/core.cpp30
-rw-r--r--src/core/core.h31
-rw-r--r--src/core/crypto/key_manager.cpp44
-rw-r--r--src/core/crypto/key_manager.h9
-rw-r--r--src/core/file_sys/content_archive.cpp33
-rw-r--r--src/core/file_sys/content_archive.h7
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.h1
-rw-r--r--src/core/file_sys/ips_layer.cpp4
-rw-r--r--src/core/file_sys/patch_manager.cpp9
-rw-r--r--src/core/file_sys/registered_cache.cpp62
-rw-r--r--src/core/file_sys/registered_cache.h23
-rw-r--r--src/core/file_sys/vfs.cpp4
-rw-r--r--src/core/file_sys/vfs.h8
-rw-r--r--src/core/file_sys/vfs_offset.cpp4
-rw-r--r--src/core/file_sys/vfs_offset.h2
-rw-r--r--src/core/file_sys/vfs_static.h4
-rw-r--r--src/core/hle/ipc_helpers.h3
-rw-r--r--src/core/hle/kernel/hle_ipc.h8
-rw-r--r--src/core/hle/kernel/kernel.cpp4
-rw-r--r--src/core/hle/kernel/mutex.cpp2
-rw-r--r--src/core/hle/kernel/server_session.cpp4
-rw-r--r--src/core/hle/kernel/svc.cpp2
-rw-r--r--src/core/hle/kernel/thread.cpp8
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp2
-rw-r--r--src/core/hle/service/am/am.cpp2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp8
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h7
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp12
-rw-r--r--src/core/hle/service/usb/usb.cpp6
-rw-r--r--src/core/hle/service/vi/vi.cpp9
-rw-r--r--src/core/loader/loader.h5
-rw-r--r--src/core/memory.cpp2
-rw-r--r--src/core/memory_hook.h15
-rw-r--r--src/core/telemetry_session.cpp9
-rw-r--r--src/core/telemetry_session.h6
-rw-r--r--src/tests/core/arm/arm_test_common.cpp10
-rw-r--r--src/tests/core/arm/arm_test_common.h10
-rw-r--r--src/video_core/CMakeLists.txt4
-rw-r--r--src/video_core/command_processor.cpp2
-rw-r--r--src/video_core/engines/maxwell_3d.cpp36
-rw-r--r--src/video_core/engines/maxwell_3d.h25
-rw-r--r--src/video_core/engines/shader_bytecode.h12
-rw-r--r--src/video_core/macro_interpreter.cpp25
-rw-r--r--src/video_core/macro_interpreter.h17
-rw-r--r--src/video_core/memory_manager.cpp8
-rw-r--r--src/video_core/memory_manager.h7
-rw-r--r--src/video_core/renderer_base.h6
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_primitive_assembler.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp19
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h5
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp405
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h874
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp5
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp210
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.h8
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp8
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h27
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp11
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h3
-rw-r--r--src/video_core/renderer_opengl/utils.cpp38
-rw-r--r--src/video_core/renderer_opengl/utils.h15
-rw-r--r--src/video_core/surface.cpp499
-rw-r--r--src/video_core/surface.h385
-rw-r--r--src/video_core/textures/decoders.h6
-rw-r--r--src/video_core/utils.h26
-rw-r--r--src/web_service/telemetry_json.cpp21
-rw-r--r--src/web_service/telemetry_json.h1
-rw-r--r--src/yuzu/compatdb.cpp27
-rw-r--r--src/yuzu/compatdb.h4
-rw-r--r--src/yuzu/configuration/configure_input.cpp2
-rw-r--r--src/yuzu/configuration/configure_input.h6
-rw-r--r--src/yuzu/configuration/configure_system.cpp10
-rw-r--r--src/yuzu/debugger/graphics/graphics_surface.cpp4
-rw-r--r--src/yuzu/debugger/wait_tree.h1
-rw-r--r--src/yuzu/main.cpp6
-rw-r--r--src/yuzu/main.h5
79 files changed, 1831 insertions, 1365 deletions
diff --git a/src/audio_core/time_stretch.cpp b/src/audio_core/time_stretch.cpp
index cee8b12dd..2fe0b3aef 100644
--- a/src/audio_core/time_stretch.cpp
+++ b/src/audio_core/time_stretch.cpp
@@ -32,10 +32,10 @@ std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out,
32 // We were given actual_samples number of samples, and num_samples were requested from us. 32 // We were given actual_samples number of samples, and num_samples were requested from us.
33 double current_ratio = static_cast<double>(num_in) / static_cast<double>(num_out); 33 double current_ratio = static_cast<double>(num_in) / static_cast<double>(num_out);
34 34
35 const double max_latency = 1.0; // seconds 35 const double max_latency = 0.25; // seconds
36 const double max_backlog = m_sample_rate * max_latency; 36 const double max_backlog = m_sample_rate * max_latency;
37 const double backlog_fullness = m_sound_touch.numSamples() / max_backlog; 37 const double backlog_fullness = m_sound_touch.numSamples() / max_backlog;
38 if (backlog_fullness > 5.0) { 38 if (backlog_fullness > 4.0) {
39 // Too many samples in backlog: Don't push anymore on 39 // Too many samples in backlog: Don't push anymore on
40 num_in = 0; 40 num_in = 0;
41 } 41 }
@@ -49,7 +49,7 @@ std::size_t TimeStretcher::Process(const s16* in, std::size_t num_in, s16* out,
49 49
50 // This low-pass filter smoothes out variance in the calculated stretch ratio. 50 // This low-pass filter smoothes out variance in the calculated stretch ratio.
51 // The time-scale determines how responsive this filter is. 51 // The time-scale determines how responsive this filter is.
52 constexpr double lpf_time_scale = 2.0; // seconds 52 constexpr double lpf_time_scale = 0.712; // seconds
53 const double lpf_gain = 1.0 - std::exp(-time_delta / lpf_time_scale); 53 const double lpf_gain = 1.0 - std::exp(-time_delta / lpf_time_scale);
54 m_stretch_ratio += lpf_gain * (current_ratio - m_stretch_ratio); 54 m_stretch_ratio += lpf_gain * (current_ratio - m_stretch_ratio);
55 55
diff --git a/src/common/telemetry.h b/src/common/telemetry.h
index 8d6ab986b..854a73fae 100644
--- a/src/common/telemetry.h
+++ b/src/common/telemetry.h
@@ -153,6 +153,7 @@ struct VisitorInterface : NonCopyable {
153 153
154 /// Completion method, called once all fields have been visited 154 /// Completion method, called once all fields have been visited
155 virtual void Complete() = 0; 155 virtual void Complete() = 0;
156 virtual bool SubmitTestcase() = 0;
156}; 157};
157 158
158/** 159/**
@@ -178,6 +179,9 @@ struct NullVisitor : public VisitorInterface {
178 void Visit(const Field<std::chrono::microseconds>& /*field*/) override {} 179 void Visit(const Field<std::chrono::microseconds>& /*field*/) override {}
179 180
180 void Complete() override {} 181 void Complete() override {}
182 bool SubmitTestcase() override {
183 return false;
184 }
181}; 185};
182 186
183/// Appends build-specific information to the given FieldCollection, 187/// Appends build-specific information to the given FieldCollection,
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 7cb86ed92..6d5b5a2d0 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -185,7 +185,7 @@ struct System::Impl {
185 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); 185 LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
186 return ResultStatus::ErrorGetLoader; 186 return ResultStatus::ErrorGetLoader;
187 } 187 }
188 std::pair<boost::optional<u32>, Loader::ResultStatus> system_mode = 188 std::pair<std::optional<u32>, Loader::ResultStatus> system_mode =
189 app_loader->LoadKernelSystemMode(); 189 app_loader->LoadKernelSystemMode();
190 190
191 if (system_mode.second != Loader::ResultStatus::Success) { 191 if (system_mode.second != Loader::ResultStatus::Success) {
@@ -312,6 +312,10 @@ Cpu& System::CurrentCpuCore() {
312 return impl->CurrentCpuCore(); 312 return impl->CurrentCpuCore();
313} 313}
314 314
315const Cpu& System::CurrentCpuCore() const {
316 return impl->CurrentCpuCore();
317}
318
315System::ResultStatus System::RunLoop(bool tight_loop) { 319System::ResultStatus System::RunLoop(bool tight_loop) {
316 return impl->RunLoop(tight_loop); 320 return impl->RunLoop(tight_loop);
317} 321}
@@ -342,7 +346,11 @@ PerfStatsResults System::GetAndResetPerfStats() {
342 return impl->GetAndResetPerfStats(); 346 return impl->GetAndResetPerfStats();
343} 347}
344 348
345Core::TelemetrySession& System::TelemetrySession() const { 349TelemetrySession& System::TelemetrySession() {
350 return *impl->telemetry_session;
351}
352
353const TelemetrySession& System::TelemetrySession() const {
346 return *impl->telemetry_session; 354 return *impl->telemetry_session;
347} 355}
348 356
@@ -350,7 +358,11 @@ ARM_Interface& System::CurrentArmInterface() {
350 return CurrentCpuCore().ArmInterface(); 358 return CurrentCpuCore().ArmInterface();
351} 359}
352 360
353std::size_t System::CurrentCoreIndex() { 361const ARM_Interface& System::CurrentArmInterface() const {
362 return CurrentCpuCore().ArmInterface();
363}
364
365std::size_t System::CurrentCoreIndex() const {
354 return CurrentCpuCore().CoreIndex(); 366 return CurrentCpuCore().CoreIndex();
355} 367}
356 368
@@ -358,6 +370,10 @@ Kernel::Scheduler& System::CurrentScheduler() {
358 return CurrentCpuCore().Scheduler(); 370 return CurrentCpuCore().Scheduler();
359} 371}
360 372
373const Kernel::Scheduler& System::CurrentScheduler() const {
374 return CurrentCpuCore().Scheduler();
375}
376
361Kernel::Scheduler& System::Scheduler(std::size_t core_index) { 377Kernel::Scheduler& System::Scheduler(std::size_t core_index) {
362 return CpuCore(core_index).Scheduler(); 378 return CpuCore(core_index).Scheduler();
363} 379}
@@ -378,6 +394,10 @@ ARM_Interface& System::ArmInterface(std::size_t core_index) {
378 return CpuCore(core_index).ArmInterface(); 394 return CpuCore(core_index).ArmInterface();
379} 395}
380 396
397const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
398 return CpuCore(core_index).ArmInterface();
399}
400
381Cpu& System::CpuCore(std::size_t core_index) { 401Cpu& System::CpuCore(std::size_t core_index) {
382 ASSERT(core_index < NUM_CPU_CORES); 402 ASSERT(core_index < NUM_CPU_CORES);
383 return *impl->cpu_cores[core_index]; 403 return *impl->cpu_cores[core_index];
@@ -392,6 +412,10 @@ ExclusiveMonitor& System::Monitor() {
392 return *impl->cpu_exclusive_monitor; 412 return *impl->cpu_exclusive_monitor;
393} 413}
394 414
415const ExclusiveMonitor& System::Monitor() const {
416 return *impl->cpu_exclusive_monitor;
417}
418
395Tegra::GPU& System::GPU() { 419Tegra::GPU& System::GPU() {
396 return *impl->gpu_core; 420 return *impl->gpu_core;
397} 421}
diff --git a/src/core/core.h b/src/core/core.h
index 173be45f8..cfacceb81 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -129,11 +129,11 @@ public:
129 */ 129 */
130 bool IsPoweredOn() const; 130 bool IsPoweredOn() const;
131 131
132 /** 132 /// Gets a reference to the telemetry session for this emulation session.
133 * Returns a reference to the telemetry session for this emulation session. 133 Core::TelemetrySession& TelemetrySession();
134 * @returns Reference to the telemetry session. 134
135 */ 135 /// Gets a reference to the telemetry session for this emulation session.
136 Core::TelemetrySession& TelemetrySession() const; 136 const Core::TelemetrySession& TelemetrySession() const;
137 137
138 /// Prepare the core emulation for a reschedule 138 /// Prepare the core emulation for a reschedule
139 void PrepareReschedule(); 139 void PrepareReschedule();
@@ -144,24 +144,36 @@ public:
144 /// Gets an ARM interface to the CPU core that is currently running 144 /// Gets an ARM interface to the CPU core that is currently running
145 ARM_Interface& CurrentArmInterface(); 145 ARM_Interface& CurrentArmInterface();
146 146
147 /// Gets an ARM interface to the CPU core that is currently running
148 const ARM_Interface& CurrentArmInterface() const;
149
147 /// Gets the index of the currently running CPU core 150 /// Gets the index of the currently running CPU core
148 std::size_t CurrentCoreIndex(); 151 std::size_t CurrentCoreIndex() const;
149 152
150 /// Gets the scheduler for the CPU core that is currently running 153 /// Gets the scheduler for the CPU core that is currently running
151 Kernel::Scheduler& CurrentScheduler(); 154 Kernel::Scheduler& CurrentScheduler();
152 155
153 /// Gets an ARM interface to the CPU core with the specified index 156 /// Gets the scheduler for the CPU core that is currently running
157 const Kernel::Scheduler& CurrentScheduler() const;
158
159 /// Gets a reference to an ARM interface for the CPU core with the specified index
154 ARM_Interface& ArmInterface(std::size_t core_index); 160 ARM_Interface& ArmInterface(std::size_t core_index);
155 161
162 /// Gets a const reference to an ARM interface from the CPU core with the specified index
163 const ARM_Interface& ArmInterface(std::size_t core_index) const;
164
156 /// Gets a CPU interface to the CPU core with the specified index 165 /// Gets a CPU interface to the CPU core with the specified index
157 Cpu& CpuCore(std::size_t core_index); 166 Cpu& CpuCore(std::size_t core_index);
158 167
159 /// Gets a CPU interface to the CPU core with the specified index 168 /// Gets a CPU interface to the CPU core with the specified index
160 const Cpu& CpuCore(std::size_t core_index) const; 169 const Cpu& CpuCore(std::size_t core_index) const;
161 170
162 /// Gets the exclusive monitor 171 /// Gets a reference to the exclusive monitor
163 ExclusiveMonitor& Monitor(); 172 ExclusiveMonitor& Monitor();
164 173
174 /// Gets a constant reference to the exclusive monitor
175 const ExclusiveMonitor& Monitor() const;
176
165 /// Gets a mutable reference to the GPU interface 177 /// Gets a mutable reference to the GPU interface
166 Tegra::GPU& GPU(); 178 Tegra::GPU& GPU();
167 179
@@ -230,6 +242,9 @@ private:
230 /// Returns the currently running CPU core 242 /// Returns the currently running CPU core
231 Cpu& CurrentCpuCore(); 243 Cpu& CurrentCpuCore();
232 244
245 /// Returns the currently running CPU core
246 const Cpu& CurrentCpuCore() const;
247
233 /** 248 /**
234 * Initialize the emulated system. 249 * Initialize the emulated system.
235 * @param emu_window Reference to the host-system window used for video output and keyboard 250 * @param emu_window Reference to the host-system window used for video output and keyboard
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 89ae79eb3..904afa039 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -141,28 +141,28 @@ Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source)
141 return mac_key; 141 return mac_key;
142} 142}
143 143
144boost::optional<Key128> DeriveSDSeed() { 144std::optional<Key128> DeriveSDSeed() {
145 const FileUtil::IOFile save_43(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + 145 const FileUtil::IOFile save_43(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
146 "/system/save/8000000000000043", 146 "/system/save/8000000000000043",
147 "rb+"); 147 "rb+");
148 if (!save_43.IsOpen()) 148 if (!save_43.IsOpen())
149 return boost::none; 149 return {};
150 150
151 const FileUtil::IOFile sd_private( 151 const FileUtil::IOFile sd_private(
152 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "/Nintendo/Contents/private", "rb+"); 152 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "/Nintendo/Contents/private", "rb+");
153 if (!sd_private.IsOpen()) 153 if (!sd_private.IsOpen())
154 return boost::none; 154 return {};
155 155
156 std::array<u8, 0x10> private_seed{}; 156 std::array<u8, 0x10> private_seed{};
157 if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != private_seed.size()) { 157 if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != private_seed.size()) {
158 return boost::none; 158 return {};
159 } 159 }
160 160
161 std::array<u8, 0x10> buffer{}; 161 std::array<u8, 0x10> buffer{};
162 std::size_t offset = 0; 162 std::size_t offset = 0;
163 for (; offset + 0x10 < save_43.GetSize(); ++offset) { 163 for (; offset + 0x10 < save_43.GetSize(); ++offset) {
164 if (!save_43.Seek(offset, SEEK_SET)) { 164 if (!save_43.Seek(offset, SEEK_SET)) {
165 return boost::none; 165 return {};
166 } 166 }
167 167
168 save_43.ReadBytes(buffer.data(), buffer.size()); 168 save_43.ReadBytes(buffer.data(), buffer.size());
@@ -172,12 +172,12 @@ boost::optional<Key128> DeriveSDSeed() {
172 } 172 }
173 173
174 if (!save_43.Seek(offset + 0x10, SEEK_SET)) { 174 if (!save_43.Seek(offset + 0x10, SEEK_SET)) {
175 return boost::none; 175 return {};
176 } 176 }
177 177
178 Key128 seed{}; 178 Key128 seed{};
179 if (save_43.ReadBytes(seed.data(), seed.size()) != seed.size()) { 179 if (save_43.ReadBytes(seed.data(), seed.size()) != seed.size()) {
180 return boost::none; 180 return {};
181 } 181 }
182 return seed; 182 return seed;
183} 183}
@@ -291,26 +291,26 @@ static std::array<u8, target_size> MGF1(const std::array<u8, in_size>& seed) {
291} 291}
292 292
293template <size_t size> 293template <size_t size>
294static boost::optional<u64> FindTicketOffset(const std::array<u8, size>& data) { 294static std::optional<u64> FindTicketOffset(const std::array<u8, size>& data) {
295 u64 offset = 0; 295 u64 offset = 0;
296 for (size_t i = 0x20; i < data.size() - 0x10; ++i) { 296 for (size_t i = 0x20; i < data.size() - 0x10; ++i) {
297 if (data[i] == 0x1) { 297 if (data[i] == 0x1) {
298 offset = i + 1; 298 offset = i + 1;
299 break; 299 break;
300 } else if (data[i] != 0x0) { 300 } else if (data[i] != 0x0) {
301 return boost::none; 301 return {};
302 } 302 }
303 } 303 }
304 304
305 return offset; 305 return offset;
306} 306}
307 307
308boost::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket, 308std::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket,
309 const RSAKeyPair<2048>& key) { 309 const RSAKeyPair<2048>& key) {
310 u32 cert_authority; 310 u32 cert_authority;
311 std::memcpy(&cert_authority, ticket.data() + 0x140, sizeof(cert_authority)); 311 std::memcpy(&cert_authority, ticket.data() + 0x140, sizeof(cert_authority));
312 if (cert_authority == 0) 312 if (cert_authority == 0)
313 return boost::none; 313 return {};
314 if (cert_authority != Common::MakeMagic('R', 'o', 'o', 't')) { 314 if (cert_authority != Common::MakeMagic('R', 'o', 'o', 't')) {
315 LOG_INFO(Crypto, 315 LOG_INFO(Crypto,
316 "Attempting to parse ticket with non-standard certificate authority {:08X}.", 316 "Attempting to parse ticket with non-standard certificate authority {:08X}.",
@@ -321,7 +321,7 @@ boost::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket,
321 std::memcpy(rights_id.data(), ticket.data() + 0x2A0, sizeof(Key128)); 321 std::memcpy(rights_id.data(), ticket.data() + 0x2A0, sizeof(Key128));
322 322
323 if (rights_id == Key128{}) 323 if (rights_id == Key128{})
324 return boost::none; 324 return {};
325 325
326 Key128 key_temp{}; 326 Key128 key_temp{};
327 327
@@ -356,17 +356,17 @@ boost::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket,
356 std::memcpy(m_2.data(), rsa_step.data() + 0x21, m_2.size()); 356 std::memcpy(m_2.data(), rsa_step.data() + 0x21, m_2.size());
357 357
358 if (m_0 != 0) 358 if (m_0 != 0)
359 return boost::none; 359 return {};
360 360
361 m_1 = m_1 ^ MGF1<0x20>(m_2); 361 m_1 = m_1 ^ MGF1<0x20>(m_2);
362 m_2 = m_2 ^ MGF1<0xDF>(m_1); 362 m_2 = m_2 ^ MGF1<0xDF>(m_1);
363 363
364 const auto offset = FindTicketOffset(m_2); 364 const auto offset = FindTicketOffset(m_2);
365 if (offset == boost::none) 365 if (!offset)
366 return boost::none; 366 return {};
367 ASSERT(offset.get() > 0); 367 ASSERT(*offset > 0);
368 368
369 std::memcpy(key_temp.data(), m_2.data() + offset.get(), key_temp.size()); 369 std::memcpy(key_temp.data(), m_2.data() + *offset, key_temp.size());
370 370
371 return std::make_pair(rights_id, key_temp); 371 return std::make_pair(rights_id, key_temp);
372} 372}
@@ -661,8 +661,8 @@ void KeyManager::DeriveSDSeedLazy() {
661 return; 661 return;
662 662
663 const auto res = DeriveSDSeed(); 663 const auto res = DeriveSDSeed();
664 if (res != boost::none) 664 if (res)
665 SetKey(S128KeyType::SDSeed, res.get()); 665 SetKey(S128KeyType::SDSeed, *res);
666} 666}
667 667
668static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) { 668static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) {
@@ -889,9 +889,9 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
889 889
890 for (const auto& raw : res) { 890 for (const auto& raw : res) {
891 const auto pair = ParseTicket(raw, rsa_key); 891 const auto pair = ParseTicket(raw, rsa_key);
892 if (pair == boost::none) 892 if (!pair)
893 continue; 893 continue;
894 const auto& [rid, key] = pair.value(); 894 const auto& [rid, key] = *pair;
895 u128 rights_id; 895 u128 rights_id;
896 std::memcpy(rights_id.data(), rid.data(), rid.size()); 896 std::memcpy(rights_id.data(), rid.data(), rid.size());
897 SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); 897 SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h
index cccb3c0ae..22f268c65 100644
--- a/src/core/crypto/key_manager.h
+++ b/src/core/crypto/key_manager.h
@@ -6,9 +6,10 @@
6 6
7#include <array> 7#include <array>
8#include <map> 8#include <map>
9#include <optional>
9#include <string> 10#include <string>
11
10#include <boost/container/flat_map.hpp> 12#include <boost/container/flat_map.hpp>
11#include <boost/optional.hpp>
12#include <fmt/format.h> 13#include <fmt/format.h>
13#include "common/common_types.h" 14#include "common/common_types.h"
14#include "core/crypto/partition_data_manager.h" 15#include "core/crypto/partition_data_manager.h"
@@ -191,14 +192,14 @@ Key128 DeriveMasterKey(const std::array<u8, 0x90>& keyblob, const Key128& master
191std::array<u8, 0x90> DecryptKeyblob(const std::array<u8, 0xB0>& encrypted_keyblob, 192std::array<u8, 0x90> DecryptKeyblob(const std::array<u8, 0xB0>& encrypted_keyblob,
192 const Key128& key); 193 const Key128& key);
193 194
194boost::optional<Key128> DeriveSDSeed(); 195std::optional<Key128> DeriveSDSeed();
195Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys); 196Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys);
196 197
197std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save); 198std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save);
198 199
199// Returns a pair of {rights_id, titlekey}. Fails if the ticket has no certificate authority (offset 200// Returns a pair of {rights_id, titlekey}. Fails if the ticket has no certificate authority (offset
200// 0x140-0x144 is zero) 201// 0x140-0x144 is zero)
201boost::optional<std::pair<Key128, Key128>> ParseTicket( 202std::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket,
202 const TicketRaw& ticket, const RSAKeyPair<2048>& eticket_extended_key); 203 const RSAKeyPair<2048>& eticket_extended_key);
203 204
204} // namespace Core::Crypto 205} // namespace Core::Crypto
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 77e04704e..b46fe893c 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -4,10 +4,9 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cstring> 6#include <cstring>
7#include <optional>
7#include <utility> 8#include <utility>
8 9
9#include <boost/optional.hpp>
10
11#include "common/logging/log.h" 10#include "common/logging/log.h"
12#include "core/crypto/aes_util.h" 11#include "core/crypto/aes_util.h"
13#include "core/crypto/ctr_encryption_layer.h" 12#include "core/crypto/ctr_encryption_layer.h"
@@ -306,18 +305,18 @@ bool NCA::ReadRomFSSection(const NCASectionHeader& section, const NCASectionTabl
306 subsection_buckets.back().entries.push_back({section.bktr.relocation.offset, {0}, ctr_low}); 305 subsection_buckets.back().entries.push_back({section.bktr.relocation.offset, {0}, ctr_low});
307 subsection_buckets.back().entries.push_back({size, {0}, 0}); 306 subsection_buckets.back().entries.push_back({size, {0}, 0});
308 307
309 boost::optional<Core::Crypto::Key128> key = boost::none; 308 std::optional<Core::Crypto::Key128> key = {};
310 if (encrypted) { 309 if (encrypted) {
311 if (has_rights_id) { 310 if (has_rights_id) {
312 status = Loader::ResultStatus::Success; 311 status = Loader::ResultStatus::Success;
313 key = GetTitlekey(); 312 key = GetTitlekey();
314 if (key == boost::none) { 313 if (!key) {
315 status = Loader::ResultStatus::ErrorMissingTitlekey; 314 status = Loader::ResultStatus::ErrorMissingTitlekey;
316 return false; 315 return false;
317 } 316 }
318 } else { 317 } else {
319 key = GetKeyAreaKey(NCASectionCryptoType::BKTR); 318 key = GetKeyAreaKey(NCASectionCryptoType::BKTR);
320 if (key == boost::none) { 319 if (!key) {
321 status = Loader::ResultStatus::ErrorMissingKeyAreaKey; 320 status = Loader::ResultStatus::ErrorMissingKeyAreaKey;
322 return false; 321 return false;
323 } 322 }
@@ -332,7 +331,7 @@ bool NCA::ReadRomFSSection(const NCASectionHeader& section, const NCASectionTabl
332 auto bktr = std::make_shared<BKTR>( 331 auto bktr = std::make_shared<BKTR>(
333 bktr_base_romfs, std::make_shared<OffsetVfsFile>(file, romfs_size, base_offset), 332 bktr_base_romfs, std::make_shared<OffsetVfsFile>(file, romfs_size, base_offset),
334 relocation_block, relocation_buckets, subsection_block, subsection_buckets, encrypted, 333 relocation_block, relocation_buckets, subsection_block, subsection_buckets, encrypted,
335 encrypted ? key.get() : Core::Crypto::Key128{}, base_offset, bktr_base_ivfc_offset, 334 encrypted ? *key : Core::Crypto::Key128{}, base_offset, bktr_base_ivfc_offset,
336 section.raw.section_ctr); 335 section.raw.section_ctr);
337 336
338 // BKTR applies to entire IVFC, so make an offset version to level 6 337 // BKTR applies to entire IVFC, so make an offset version to level 6
@@ -388,11 +387,11 @@ u8 NCA::GetCryptoRevision() const {
388 return master_key_id; 387 return master_key_id;
389} 388}
390 389
391boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const { 390std::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const {
392 const auto master_key_id = GetCryptoRevision(); 391 const auto master_key_id = GetCryptoRevision();
393 392
394 if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index)) 393 if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index))
395 return boost::none; 394 return {};
396 395
397 std::vector<u8> key_area(header.key_area.begin(), header.key_area.end()); 396 std::vector<u8> key_area(header.key_area.begin(), header.key_area.end());
398 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher( 397 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
@@ -416,25 +415,25 @@ boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType ty
416 return out; 415 return out;
417} 416}
418 417
419boost::optional<Core::Crypto::Key128> NCA::GetTitlekey() { 418std::optional<Core::Crypto::Key128> NCA::GetTitlekey() {
420 const auto master_key_id = GetCryptoRevision(); 419 const auto master_key_id = GetCryptoRevision();
421 420
422 u128 rights_id{}; 421 u128 rights_id{};
423 memcpy(rights_id.data(), header.rights_id.data(), 16); 422 memcpy(rights_id.data(), header.rights_id.data(), 16);
424 if (rights_id == u128{}) { 423 if (rights_id == u128{}) {
425 status = Loader::ResultStatus::ErrorInvalidRightsID; 424 status = Loader::ResultStatus::ErrorInvalidRightsID;
426 return boost::none; 425 return {};
427 } 426 }
428 427
429 auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]); 428 auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]);
430 if (titlekey == Core::Crypto::Key128{}) { 429 if (titlekey == Core::Crypto::Key128{}) {
431 status = Loader::ResultStatus::ErrorMissingTitlekey; 430 status = Loader::ResultStatus::ErrorMissingTitlekey;
432 return boost::none; 431 return {};
433 } 432 }
434 433
435 if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) { 434 if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) {
436 status = Loader::ResultStatus::ErrorMissingTitlekek; 435 status = Loader::ResultStatus::ErrorMissingTitlekek;
437 return boost::none; 436 return {};
438 } 437 }
439 438
440 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher( 439 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
@@ -458,25 +457,25 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s
458 case NCASectionCryptoType::BKTR: 457 case NCASectionCryptoType::BKTR:
459 LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset); 458 LOG_DEBUG(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset);
460 { 459 {
461 boost::optional<Core::Crypto::Key128> key = boost::none; 460 std::optional<Core::Crypto::Key128> key = {};
462 if (has_rights_id) { 461 if (has_rights_id) {
463 status = Loader::ResultStatus::Success; 462 status = Loader::ResultStatus::Success;
464 key = GetTitlekey(); 463 key = GetTitlekey();
465 if (key == boost::none) { 464 if (!key) {
466 if (status == Loader::ResultStatus::Success) 465 if (status == Loader::ResultStatus::Success)
467 status = Loader::ResultStatus::ErrorMissingTitlekey; 466 status = Loader::ResultStatus::ErrorMissingTitlekey;
468 return nullptr; 467 return nullptr;
469 } 468 }
470 } else { 469 } else {
471 key = GetKeyAreaKey(NCASectionCryptoType::CTR); 470 key = GetKeyAreaKey(NCASectionCryptoType::CTR);
472 if (key == boost::none) { 471 if (!key) {
473 status = Loader::ResultStatus::ErrorMissingKeyAreaKey; 472 status = Loader::ResultStatus::ErrorMissingKeyAreaKey;
474 return nullptr; 473 return nullptr;
475 } 474 }
476 } 475 }
477 476
478 auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>( 477 auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(std::move(in), *key,
479 std::move(in), key.value(), starting_offset); 478 starting_offset);
480 std::vector<u8> iv(16); 479 std::vector<u8> iv(16);
481 for (u8 i = 0; i < 8; ++i) 480 for (u8 i = 0; i < 8; ++i)
482 iv[i] = s_header.raw.section_ctr[0x8 - i - 1]; 481 iv[i] = s_header.raw.section_ctr[0x8 - i - 1];
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index 211946686..4bba55607 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -6,9 +6,10 @@
6 6
7#include <array> 7#include <array>
8#include <memory> 8#include <memory>
9#include <optional>
9#include <string> 10#include <string>
10#include <vector> 11#include <vector>
11#include <boost/optional.hpp> 12
12#include "common/common_funcs.h" 13#include "common/common_funcs.h"
13#include "common/common_types.h" 14#include "common/common_types.h"
14#include "common/swap.h" 15#include "common/swap.h"
@@ -111,8 +112,8 @@ private:
111 bool ReadPFS0Section(const NCASectionHeader& section, const NCASectionTableEntry& entry); 112 bool ReadPFS0Section(const NCASectionHeader& section, const NCASectionTableEntry& entry);
112 113
113 u8 GetCryptoRevision() const; 114 u8 GetCryptoRevision() const;
114 boost::optional<Core::Crypto::Key128> GetKeyAreaKey(NCASectionCryptoType type) const; 115 std::optional<Core::Crypto::Key128> GetKeyAreaKey(NCASectionCryptoType type) const;
115 boost::optional<Core::Crypto::Key128> GetTitlekey(); 116 std::optional<Core::Crypto::Key128> GetTitlekey();
116 VirtualFile Decrypt(const NCASectionHeader& header, VirtualFile in, u64 starting_offset); 117 VirtualFile Decrypt(const NCASectionHeader& header, VirtualFile in, u64 starting_offset);
117 118
118 std::vector<VirtualDir> dirs; 119 std::vector<VirtualDir> dirs;
diff --git a/src/core/file_sys/fsmitm_romfsbuild.h b/src/core/file_sys/fsmitm_romfsbuild.h
index 3d377b0af..a62502193 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.h
+++ b/src/core/file_sys/fsmitm_romfsbuild.h
@@ -27,7 +27,6 @@
27#include <map> 27#include <map>
28#include <memory> 28#include <memory>
29#include <string> 29#include <string>
30#include <boost/detail/container_fwd.hpp>
31#include "common/common_types.h" 30#include "common/common_types.h"
32#include "core/file_sys/vfs.h" 31#include "core/file_sys/vfs.h"
33 32
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp
index 999939d5a..485c4913a 100644
--- a/src/core/file_sys/ips_layer.cpp
+++ b/src/core/file_sys/ips_layer.cpp
@@ -103,12 +103,12 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {
103 offset += sizeof(u16); 103 offset += sizeof(u16);
104 104
105 const auto data = ips->ReadByte(offset++); 105 const auto data = ips->ReadByte(offset++);
106 if (data == boost::none) 106 if (!data)
107 return nullptr; 107 return nullptr;
108 108
109 if (real_offset + rle_size > in_data.size()) 109 if (real_offset + rle_size > in_data.size())
110 rle_size = static_cast<u16>(in_data.size() - real_offset); 110 rle_size = static_cast<u16>(in_data.size() - real_offset);
111 std::memset(in_data.data() + real_offset, data.get(), rle_size); 111 std::memset(in_data.data() + real_offset, *data, rle_size);
112 } else { // Standard Patch 112 } else { // Standard Patch
113 auto read = data_size; 113 auto read = data_size;
114 if (real_offset + read > in_data.size()) 114 if (real_offset + read > in_data.size())
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index cb457b987..0c1156989 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -65,7 +65,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
65 if (update != nullptr && update->GetExeFS() != nullptr && 65 if (update != nullptr && update->GetExeFS() != nullptr &&
66 update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { 66 update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
67 LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", 67 LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully",
68 FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0))); 68 FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0)));
69 exefs = update->GetExeFS(); 69 exefs = update->GetExeFS();
70 } 70 }
71 71
@@ -236,7 +236,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
236 if (new_nca->GetStatus() == Loader::ResultStatus::Success && 236 if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
237 new_nca->GetRomFS() != nullptr) { 237 new_nca->GetRomFS() != nullptr) {
238 LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", 238 LOG_INFO(Loader, " RomFS: Update ({}) applied successfully",
239 FormatTitleVersion(installed->GetEntryVersion(update_tid).get_value_or(0))); 239 FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0)));
240 romfs = new_nca->GetRomFS(); 240 romfs = new_nca->GetRomFS();
241 } 241 }
242 } else if (update_raw != nullptr) { 242 } else if (update_raw != nullptr) {
@@ -280,12 +280,11 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
280 } else { 280 } else {
281 if (installed->HasEntry(update_tid, ContentRecordType::Program)) { 281 if (installed->HasEntry(update_tid, ContentRecordType::Program)) {
282 const auto meta_ver = installed->GetEntryVersion(update_tid); 282 const auto meta_ver = installed->GetEntryVersion(update_tid);
283 if (meta_ver == boost::none || meta_ver.get() == 0) { 283 if (meta_ver.value_or(0) == 0) {
284 out.insert_or_assign("Update", ""); 284 out.insert_or_assign("Update", "");
285 } else { 285 } else {
286 out.insert_or_assign( 286 out.insert_or_assign(
287 "Update", 287 "Update", FormatTitleVersion(*meta_ver, TitleVersionFormat::ThreeElements));
288 FormatTitleVersion(meta_ver.get(), TitleVersionFormat::ThreeElements));
289 } 288 }
290 } else if (update_raw != nullptr) { 289 } else if (update_raw != nullptr) {
291 out.insert_or_assign("Update", "PACKED"); 290 out.insert_or_assign("Update", "PACKED");
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 29b100414..96302a241 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -159,28 +159,28 @@ VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
159 return file; 159 return file;
160} 160}
161 161
162static boost::optional<NcaID> CheckMapForContentRecord( 162static std::optional<NcaID> CheckMapForContentRecord(
163 const boost::container::flat_map<u64, CNMT>& map, u64 title_id, ContentRecordType type) { 163 const boost::container::flat_map<u64, CNMT>& map, u64 title_id, ContentRecordType type) {
164 if (map.find(title_id) == map.end()) 164 if (map.find(title_id) == map.end())
165 return boost::none; 165 return {};
166 166
167 const auto& cnmt = map.at(title_id); 167 const auto& cnmt = map.at(title_id);
168 168
169 const auto iter = std::find_if(cnmt.GetContentRecords().begin(), cnmt.GetContentRecords().end(), 169 const auto iter = std::find_if(cnmt.GetContentRecords().begin(), cnmt.GetContentRecords().end(),
170 [type](const ContentRecord& rec) { return rec.type == type; }); 170 [type](const ContentRecord& rec) { return rec.type == type; });
171 if (iter == cnmt.GetContentRecords().end()) 171 if (iter == cnmt.GetContentRecords().end())
172 return boost::none; 172 return {};
173 173
174 return boost::make_optional(iter->nca_id); 174 return std::make_optional(iter->nca_id);
175} 175}
176 176
177boost::optional<NcaID> RegisteredCache::GetNcaIDFromMetadata(u64 title_id, 177std::optional<NcaID> RegisteredCache::GetNcaIDFromMetadata(u64 title_id,
178 ContentRecordType type) const { 178 ContentRecordType type) const {
179 if (type == ContentRecordType::Meta && meta_id.find(title_id) != meta_id.end()) 179 if (type == ContentRecordType::Meta && meta_id.find(title_id) != meta_id.end())
180 return meta_id.at(title_id); 180 return meta_id.at(title_id);
181 181
182 const auto res1 = CheckMapForContentRecord(yuzu_meta, title_id, type); 182 const auto res1 = CheckMapForContentRecord(yuzu_meta, title_id, type);
183 if (res1 != boost::none) 183 if (res1)
184 return res1; 184 return res1;
185 return CheckMapForContentRecord(meta, title_id, type); 185 return CheckMapForContentRecord(meta, title_id, type);
186} 186}
@@ -283,17 +283,14 @@ bool RegisteredCache::HasEntry(RegisteredCacheEntry entry) const {
283 283
284VirtualFile RegisteredCache::GetEntryUnparsed(u64 title_id, ContentRecordType type) const { 284VirtualFile RegisteredCache::GetEntryUnparsed(u64 title_id, ContentRecordType type) const {
285 const auto id = GetNcaIDFromMetadata(title_id, type); 285 const auto id = GetNcaIDFromMetadata(title_id, type);
286 if (id == boost::none) 286 return id ? GetFileAtID(*id) : nullptr;
287 return nullptr;
288
289 return GetFileAtID(id.get());
290} 287}
291 288
292VirtualFile RegisteredCache::GetEntryUnparsed(RegisteredCacheEntry entry) const { 289VirtualFile RegisteredCache::GetEntryUnparsed(RegisteredCacheEntry entry) const {
293 return GetEntryUnparsed(entry.title_id, entry.type); 290 return GetEntryUnparsed(entry.title_id, entry.type);
294} 291}
295 292
296boost::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const { 293std::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const {
297 const auto meta_iter = meta.find(title_id); 294 const auto meta_iter = meta.find(title_id);
298 if (meta_iter != meta.end()) 295 if (meta_iter != meta.end())
299 return meta_iter->second.GetTitleVersion(); 296 return meta_iter->second.GetTitleVersion();
@@ -302,15 +299,12 @@ boost::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const {
302 if (yuzu_meta_iter != yuzu_meta.end()) 299 if (yuzu_meta_iter != yuzu_meta.end())
303 return yuzu_meta_iter->second.GetTitleVersion(); 300 return yuzu_meta_iter->second.GetTitleVersion();
304 301
305 return boost::none; 302 return {};
306} 303}
307 304
308VirtualFile RegisteredCache::GetEntryRaw(u64 title_id, ContentRecordType type) const { 305VirtualFile RegisteredCache::GetEntryRaw(u64 title_id, ContentRecordType type) const {
309 const auto id = GetNcaIDFromMetadata(title_id, type); 306 const auto id = GetNcaIDFromMetadata(title_id, type);
310 if (id == boost::none) 307 return id ? parser(GetFileAtID(*id), *id) : nullptr;
311 return nullptr;
312
313 return parser(GetFileAtID(id.get()), id.get());
314} 308}
315 309
316VirtualFile RegisteredCache::GetEntryRaw(RegisteredCacheEntry entry) const { 310VirtualFile RegisteredCache::GetEntryRaw(RegisteredCacheEntry entry) const {
@@ -364,8 +358,8 @@ std::vector<RegisteredCacheEntry> RegisteredCache::ListEntries() const {
364} 358}
365 359
366std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter( 360std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter(
367 boost::optional<TitleType> title_type, boost::optional<ContentRecordType> record_type, 361 std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
368 boost::optional<u64> title_id) const { 362 std::optional<u64> title_id) const {
369 std::vector<RegisteredCacheEntry> out; 363 std::vector<RegisteredCacheEntry> out;
370 IterateAllMetadata<RegisteredCacheEntry>( 364 IterateAllMetadata<RegisteredCacheEntry>(
371 out, 365 out,
@@ -373,11 +367,11 @@ std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter(
373 return RegisteredCacheEntry{c.GetTitleID(), r.type}; 367 return RegisteredCacheEntry{c.GetTitleID(), r.type};
374 }, 368 },
375 [&title_type, &record_type, &title_id](const CNMT& c, const ContentRecord& r) { 369 [&title_type, &record_type, &title_id](const CNMT& c, const ContentRecord& r) {
376 if (title_type != boost::none && title_type.get() != c.GetType()) 370 if (title_type && *title_type != c.GetType())
377 return false; 371 return false;
378 if (record_type != boost::none && record_type.get() != r.type) 372 if (record_type && *record_type != r.type)
379 return false; 373 return false;
380 if (title_id != boost::none && title_id.get() != c.GetTitleID()) 374 if (title_id && *title_id != c.GetTitleID())
381 return false; 375 return false;
382 return true; 376 return true;
383 }); 377 });
@@ -459,7 +453,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType
459 453
460InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, 454InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy,
461 bool overwrite_if_exists, 455 bool overwrite_if_exists,
462 boost::optional<NcaID> override_id) { 456 std::optional<NcaID> override_id) {
463 const auto in = nca->GetBaseFile(); 457 const auto in = nca->GetBaseFile();
464 Core::Crypto::SHA256Hash hash{}; 458 Core::Crypto::SHA256Hash hash{};
465 459
@@ -468,12 +462,12 @@ InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const Vfs
468 // game is massive), we're going to cheat and only hash the first MB of the NCA. 462 // game is massive), we're going to cheat and only hash the first MB of the NCA.
469 // Also, for XCIs the NcaID matters, so if the override id isn't none, use that. 463 // Also, for XCIs the NcaID matters, so if the override id isn't none, use that.
470 NcaID id{}; 464 NcaID id{};
471 if (override_id == boost::none) { 465 if (override_id) {
466 id = *override_id;
467 } else {
472 const auto& data = in->ReadBytes(0x100000); 468 const auto& data = in->ReadBytes(0x100000);
473 mbedtls_sha256(data.data(), data.size(), hash.data(), 0); 469 mbedtls_sha256(data.data(), data.size(), hash.data(), 0);
474 memcpy(id.data(), hash.data(), 16); 470 memcpy(id.data(), hash.data(), 16);
475 } else {
476 id = override_id.get();
477 } 471 }
478 472
479 std::string path = GetRelativePathFromNcaID(id, false, true); 473 std::string path = GetRelativePathFromNcaID(id, false, true);
@@ -543,14 +537,14 @@ bool RegisteredCacheUnion::HasEntry(RegisteredCacheEntry entry) const {
543 return HasEntry(entry.title_id, entry.type); 537 return HasEntry(entry.title_id, entry.type);
544} 538}
545 539
546boost::optional<u32> RegisteredCacheUnion::GetEntryVersion(u64 title_id) const { 540std::optional<u32> RegisteredCacheUnion::GetEntryVersion(u64 title_id) const {
547 for (const auto& c : caches) { 541 for (const auto& c : caches) {
548 const auto res = c->GetEntryVersion(title_id); 542 const auto res = c->GetEntryVersion(title_id);
549 if (res != boost::none) 543 if (res)
550 return res; 544 return res;
551 } 545 }
552 546
553 return boost::none; 547 return {};
554} 548}
555 549
556VirtualFile RegisteredCacheUnion::GetEntryUnparsed(u64 title_id, ContentRecordType type) const { 550VirtualFile RegisteredCacheUnion::GetEntryUnparsed(u64 title_id, ContentRecordType type) const {
@@ -609,8 +603,8 @@ std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntries() const {
609} 603}
610 604
611std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntriesFilter( 605std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntriesFilter(
612 boost::optional<TitleType> title_type, boost::optional<ContentRecordType> record_type, 606 std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
613 boost::optional<u64> title_id) const { 607 std::optional<u64> title_id) const {
614 std::vector<RegisteredCacheEntry> out; 608 std::vector<RegisteredCacheEntry> out;
615 for (const auto& c : caches) { 609 for (const auto& c : caches) {
616 c->IterateAllMetadata<RegisteredCacheEntry>( 610 c->IterateAllMetadata<RegisteredCacheEntry>(
@@ -619,11 +613,11 @@ std::vector<RegisteredCacheEntry> RegisteredCacheUnion::ListEntriesFilter(
619 return RegisteredCacheEntry{c.GetTitleID(), r.type}; 613 return RegisteredCacheEntry{c.GetTitleID(), r.type};
620 }, 614 },
621 [&title_type, &record_type, &title_id](const CNMT& c, const ContentRecord& r) { 615 [&title_type, &record_type, &title_id](const CNMT& c, const ContentRecord& r) {
622 if (title_type != boost::none && title_type.get() != c.GetType()) 616 if (title_type && *title_type != c.GetType())
623 return false; 617 return false;
624 if (record_type != boost::none && record_type.get() != r.type) 618 if (record_type && *record_type != r.type)
625 return false; 619 return false;
626 if (title_id != boost::none && title_id.get() != c.GetTitleID()) 620 if (title_id && *title_id != c.GetTitleID())
627 return false; 621 return false;
628 return true; 622 return true;
629 }); 623 });
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index 5beceffb3..6cfb16017 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -84,7 +84,7 @@ public:
84 bool HasEntry(u64 title_id, ContentRecordType type) const; 84 bool HasEntry(u64 title_id, ContentRecordType type) const;
85 bool HasEntry(RegisteredCacheEntry entry) const; 85 bool HasEntry(RegisteredCacheEntry entry) const;
86 86
87 boost::optional<u32> GetEntryVersion(u64 title_id) const; 87 std::optional<u32> GetEntryVersion(u64 title_id) const;
88 88
89 VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const; 89 VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const;
90 VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const; 90 VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const;
@@ -96,11 +96,10 @@ public:
96 std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const; 96 std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
97 97
98 std::vector<RegisteredCacheEntry> ListEntries() const; 98 std::vector<RegisteredCacheEntry> ListEntries() const;
99 // If a parameter is not boost::none, it will be filtered for from all entries. 99 // If a parameter is not std::nullopt, it will be filtered for from all entries.
100 std::vector<RegisteredCacheEntry> ListEntriesFilter( 100 std::vector<RegisteredCacheEntry> ListEntriesFilter(
101 boost::optional<TitleType> title_type = boost::none, 101 std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
102 boost::optional<ContentRecordType> record_type = boost::none, 102 std::optional<u64> title_id = {}) const;
103 boost::optional<u64> title_id = boost::none) const;
104 103
105 // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure 104 // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure
106 // there is a meta NCA and all of them are accessible. 105 // there is a meta NCA and all of them are accessible.
@@ -125,12 +124,11 @@ private:
125 std::vector<NcaID> AccumulateFiles() const; 124 std::vector<NcaID> AccumulateFiles() const;
126 void ProcessFiles(const std::vector<NcaID>& ids); 125 void ProcessFiles(const std::vector<NcaID>& ids);
127 void AccumulateYuzuMeta(); 126 void AccumulateYuzuMeta();
128 boost::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; 127 std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const;
129 VirtualFile GetFileAtID(NcaID id) const; 128 VirtualFile GetFileAtID(NcaID id) const;
130 VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; 129 VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const;
131 InstallResult RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, 130 InstallResult RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy,
132 bool overwrite_if_exists, 131 bool overwrite_if_exists, std::optional<NcaID> override_id = {});
133 boost::optional<NcaID> override_id = boost::none);
134 bool RawInstallYuzuMeta(const CNMT& cnmt); 132 bool RawInstallYuzuMeta(const CNMT& cnmt);
135 133
136 VirtualDir dir; 134 VirtualDir dir;
@@ -153,7 +151,7 @@ public:
153 bool HasEntry(u64 title_id, ContentRecordType type) const; 151 bool HasEntry(u64 title_id, ContentRecordType type) const;
154 bool HasEntry(RegisteredCacheEntry entry) const; 152 bool HasEntry(RegisteredCacheEntry entry) const;
155 153
156 boost::optional<u32> GetEntryVersion(u64 title_id) const; 154 std::optional<u32> GetEntryVersion(u64 title_id) const;
157 155
158 VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const; 156 VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const;
159 VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const; 157 VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const;
@@ -165,11 +163,10 @@ public:
165 std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const; 163 std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
166 164
167 std::vector<RegisteredCacheEntry> ListEntries() const; 165 std::vector<RegisteredCacheEntry> ListEntries() const;
168 // If a parameter is not boost::none, it will be filtered for from all entries. 166 // If a parameter is not std::nullopt, it will be filtered for from all entries.
169 std::vector<RegisteredCacheEntry> ListEntriesFilter( 167 std::vector<RegisteredCacheEntry> ListEntriesFilter(
170 boost::optional<TitleType> title_type = boost::none, 168 std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
171 boost::optional<ContentRecordType> record_type = boost::none, 169 std::optional<u64> title_id = {}) const;
172 boost::optional<u64> title_id = boost::none) const;
173 170
174private: 171private:
175 std::vector<RegisteredCache*> caches; 172 std::vector<RegisteredCache*> caches;
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index 3824c74e0..7b584de7f 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -167,13 +167,13 @@ std::string VfsFile::GetExtension() const {
167 167
168VfsDirectory::~VfsDirectory() = default; 168VfsDirectory::~VfsDirectory() = default;
169 169
170boost::optional<u8> VfsFile::ReadByte(std::size_t offset) const { 170std::optional<u8> VfsFile::ReadByte(std::size_t offset) const {
171 u8 out{}; 171 u8 out{};
172 std::size_t size = Read(&out, 1, offset); 172 std::size_t size = Read(&out, 1, offset);
173 if (size == 1) 173 if (size == 1)
174 return out; 174 return out;
175 175
176 return boost::none; 176 return {};
177} 177}
178 178
179std::vector<u8> VfsFile::ReadBytes(std::size_t size, std::size_t offset) const { 179std::vector<u8> VfsFile::ReadBytes(std::size_t size, std::size_t offset) const {
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index 09dc9f288..002f99d4e 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -4,13 +4,15 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <functional>
7#include <map> 8#include <map>
8#include <memory> 9#include <memory>
10#include <optional>
9#include <string> 11#include <string>
10#include <string_view> 12#include <string_view>
11#include <type_traits> 13#include <type_traits>
12#include <vector> 14#include <vector>
13#include <boost/optional.hpp> 15
14#include "common/common_types.h" 16#include "common/common_types.h"
15#include "core/file_sys/vfs_types.h" 17#include "core/file_sys/vfs_types.h"
16 18
@@ -103,8 +105,8 @@ public:
103 // into file. Returns number of bytes successfully written. 105 // into file. Returns number of bytes successfully written.
104 virtual std::size_t Write(const u8* data, std::size_t length, std::size_t offset = 0) = 0; 106 virtual std::size_t Write(const u8* data, std::size_t length, std::size_t offset = 0) = 0;
105 107
106 // Reads exactly one byte at the offset provided, returning boost::none on error. 108 // Reads exactly one byte at the offset provided, returning std::nullopt on error.
107 virtual boost::optional<u8> ReadByte(std::size_t offset = 0) const; 109 virtual std::optional<u8> ReadByte(std::size_t offset = 0) const;
108 // Reads size bytes starting at offset in file into a vector. 110 // Reads size bytes starting at offset in file into a vector.
109 virtual std::vector<u8> ReadBytes(std::size_t size, std::size_t offset = 0) const; 111 virtual std::vector<u8> ReadBytes(std::size_t size, std::size_t offset = 0) const;
110 // Reads all the bytes from the file into a vector. Equivalent to 'file->Read(file->GetSize(), 112 // Reads all the bytes from the file into a vector. Equivalent to 'file->Read(file->GetSize(),
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp
index a4c6719a0..c96f88488 100644
--- a/src/core/file_sys/vfs_offset.cpp
+++ b/src/core/file_sys/vfs_offset.cpp
@@ -57,11 +57,11 @@ std::size_t OffsetVfsFile::Write(const u8* data, std::size_t length, std::size_t
57 return file->Write(data, TrimToFit(length, r_offset), offset + r_offset); 57 return file->Write(data, TrimToFit(length, r_offset), offset + r_offset);
58} 58}
59 59
60boost::optional<u8> OffsetVfsFile::ReadByte(std::size_t r_offset) const { 60std::optional<u8> OffsetVfsFile::ReadByte(std::size_t r_offset) const {
61 if (r_offset < size) 61 if (r_offset < size)
62 return file->ReadByte(offset + r_offset); 62 return file->ReadByte(offset + r_offset);
63 63
64 return boost::none; 64 return {};
65} 65}
66 66
67std::vector<u8> OffsetVfsFile::ReadBytes(std::size_t r_size, std::size_t r_offset) const { 67std::vector<u8> OffsetVfsFile::ReadBytes(std::size_t r_size, std::size_t r_offset) const {
diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h
index 8062702a7..f7b7a3256 100644
--- a/src/core/file_sys/vfs_offset.h
+++ b/src/core/file_sys/vfs_offset.h
@@ -29,7 +29,7 @@ public:
29 bool IsReadable() const override; 29 bool IsReadable() const override;
30 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; 30 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
31 std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override; 31 std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
32 boost::optional<u8> ReadByte(std::size_t offset) const override; 32 std::optional<u8> ReadByte(std::size_t offset) const override;
33 std::vector<u8> ReadBytes(std::size_t size, std::size_t offset) const override; 33 std::vector<u8> ReadBytes(std::size_t size, std::size_t offset) const override;
34 std::vector<u8> ReadAllBytes() const override; 34 std::vector<u8> ReadAllBytes() const override;
35 bool WriteByte(u8 data, std::size_t offset) override; 35 bool WriteByte(u8 data, std::size_t offset) override;
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h
index 44fab51d1..9f5a90b1b 100644
--- a/src/core/file_sys/vfs_static.h
+++ b/src/core/file_sys/vfs_static.h
@@ -53,10 +53,10 @@ public:
53 return 0; 53 return 0;
54 } 54 }
55 55
56 boost::optional<u8> ReadByte(std::size_t offset) const override { 56 std::optional<u8> ReadByte(std::size_t offset) const override {
57 if (offset < size) 57 if (offset < size)
58 return value; 58 return value;
59 return boost::none; 59 return {};
60 } 60 }
61 61
62 std::vector<u8> ReadBytes(std::size_t length, std::size_t offset) const override { 62 std::vector<u8> ReadBytes(std::size_t length, std::size_t offset) const override {
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index a4bfe2eb0..0a7142ada 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -117,8 +117,7 @@ public:
117 117
118 AlignWithPadding(); 118 AlignWithPadding();
119 119
120 const bool request_has_domain_header{context.GetDomainMessageHeader() != nullptr}; 120 if (context.Session()->IsDomain() && context.HasDomainMessageHeader()) {
121 if (context.Session()->IsDomain() && request_has_domain_header) {
122 IPC::DomainMessageHeader domain_header{}; 121 IPC::DomainMessageHeader domain_header{};
123 domain_header.num_objects = num_domain_objects; 122 domain_header.num_objects = num_domain_objects;
124 PushRaw(domain_header); 123 PushRaw(domain_header);
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index f01491daa..a38e34b74 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -161,8 +161,12 @@ public:
161 return buffer_c_desciptors; 161 return buffer_c_desciptors;
162 } 162 }
163 163
164 const std::shared_ptr<IPC::DomainMessageHeader>& GetDomainMessageHeader() const { 164 const IPC::DomainMessageHeader* GetDomainMessageHeader() const {
165 return domain_message_header; 165 return domain_message_header.get();
166 }
167
168 bool HasDomainMessageHeader() const {
169 return domain_message_header != nullptr;
166 } 170 }
167 171
168 /// Helper function to read a buffer using the appropriate buffer descriptor 172 /// Helper function to read a buffer using the appropriate buffer descriptor
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 4b6b32dd5..1fd4ba5d2 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -32,7 +32,7 @@ namespace Kernel {
32 */ 32 */
33static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_late) { 33static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_late) {
34 const auto proper_handle = static_cast<Handle>(thread_handle); 34 const auto proper_handle = static_cast<Handle>(thread_handle);
35 auto& system = Core::System::GetInstance(); 35 const auto& system = Core::System::GetInstance();
36 36
37 // Lock the global kernel mutex when we enter the kernel HLE. 37 // Lock the global kernel mutex when we enter the kernel HLE.
38 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock); 38 std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
@@ -90,7 +90,7 @@ static void ThreadWakeupCallback(u64 thread_handle, [[maybe_unused]] int cycles_
90/// The timer callback event, called when a timer is fired 90/// The timer callback event, called when a timer is fired
91static void TimerCallback(u64 timer_handle, int cycles_late) { 91static void TimerCallback(u64 timer_handle, int cycles_late) {
92 const auto proper_handle = static_cast<Handle>(timer_handle); 92 const auto proper_handle = static_cast<Handle>(timer_handle);
93 auto& system = Core::System::GetInstance(); 93 const auto& system = Core::System::GetInstance();
94 SharedPtr<Timer> timer = system.Kernel().RetrieveTimerFromCallbackHandleTable(proper_handle); 94 SharedPtr<Timer> timer = system.Kernel().RetrieveTimerFromCallbackHandleTable(proper_handle);
95 95
96 if (timer == nullptr) { 96 if (timer == nullptr) {
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index dd541ffcc..0743670ad 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -6,8 +6,6 @@
6#include <utility> 6#include <utility>
7#include <vector> 7#include <vector>
8 8
9#include <boost/range/algorithm_ext/erase.hpp>
10
11#include "common/assert.h" 9#include "common/assert.h"
12#include "core/core.h" 10#include "core/core.h"
13#include "core/hle/kernel/errors.h" 11#include "core/hle/kernel/errors.h"
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 5fc320403..80897f3a4 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -63,7 +63,7 @@ void ServerSession::Acquire(Thread* thread) {
63} 63}
64 64
65ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { 65ResultCode ServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) {
66 auto& domain_message_header = context.GetDomainMessageHeader(); 66 auto* const domain_message_header = context.GetDomainMessageHeader();
67 if (domain_message_header) { 67 if (domain_message_header) {
68 // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs 68 // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs
69 context.SetDomainRequestHandlers(domain_request_handlers); 69 context.SetDomainRequestHandlers(domain_request_handlers);
@@ -111,7 +111,7 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
111 111
112 ResultCode result = RESULT_SUCCESS; 112 ResultCode result = RESULT_SUCCESS;
113 // If the session has been converted to a domain, handle the domain request 113 // If the session has been converted to a domain, handle the domain request
114 if (IsDomain() && context.GetDomainMessageHeader()) { 114 if (IsDomain() && context.HasDomainMessageHeader()) {
115 result = HandleDomainSyncRequest(context); 115 result = HandleDomainSyncRequest(context);
116 // If there is no domain header, the regular session handler is used 116 // If there is no domain header, the regular session handler is used
117 } else if (hle_handler != nullptr) { 117 } else if (hle_handler != nullptr) {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 4e490e2b5..c7c579aaf 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -572,7 +572,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
572 return ERR_INVALID_HANDLE; 572 return ERR_INVALID_HANDLE;
573 } 573 }
574 574
575 auto& system = Core::System::GetInstance(); 575 const auto& system = Core::System::GetInstance();
576 const auto& scheduler = system.CurrentScheduler(); 576 const auto& scheduler = system.CurrentScheduler();
577 const auto* const current_thread = scheduler.GetCurrentThread(); 577 const auto* const current_thread = scheduler.GetCurrentThread();
578 const bool same_thread = current_thread == thread; 578 const bool same_thread = current_thread == thread;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 59bc9e0af..dd5cd9ced 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -4,9 +4,9 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cinttypes> 6#include <cinttypes>
7#include <optional>
7#include <vector> 8#include <vector>
8 9
9#include <boost/optional.hpp>
10#include <boost/range/algorithm_ext/erase.hpp> 10#include <boost/range/algorithm_ext/erase.hpp>
11 11
12#include "common/assert.h" 12#include "common/assert.h"
@@ -94,7 +94,7 @@ void Thread::CancelWakeupTimer() {
94 CoreTiming::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(), callback_handle); 94 CoreTiming::UnscheduleEventThreadsafe(kernel.ThreadWakeupCallbackEventType(), callback_handle);
95} 95}
96 96
97static boost::optional<s32> GetNextProcessorId(u64 mask) { 97static std::optional<s32> GetNextProcessorId(u64 mask) {
98 for (s32 index = 0; index < Core::NUM_CPU_CORES; ++index) { 98 for (s32 index = 0; index < Core::NUM_CPU_CORES; ++index) {
99 if (mask & (1ULL << index)) { 99 if (mask & (1ULL << index)) {
100 if (!Core::System::GetInstance().Scheduler(index).GetCurrentThread()) { 100 if (!Core::System::GetInstance().Scheduler(index).GetCurrentThread()) {
@@ -142,7 +142,7 @@ void Thread::ResumeFromWait() {
142 142
143 status = ThreadStatus::Ready; 143 status = ThreadStatus::Ready;
144 144
145 boost::optional<s32> new_processor_id = GetNextProcessorId(affinity_mask); 145 std::optional<s32> new_processor_id = GetNextProcessorId(affinity_mask);
146 if (!new_processor_id) { 146 if (!new_processor_id) {
147 new_processor_id = processor_id; 147 new_processor_id = processor_id;
148 } 148 }
@@ -369,7 +369,7 @@ void Thread::ChangeCore(u32 core, u64 mask) {
369 return; 369 return;
370 } 370 }
371 371
372 boost::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)}; 372 std::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)};
373 373
374 if (!new_processor_id) { 374 if (!new_processor_id) {
375 new_processor_id = processor_id; 375 new_processor_id = processor_id;
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index 3cac1b4ff..c08394e4c 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -195,7 +195,7 @@ std::size_t ProfileManager::GetOpenUserCount() const {
195 195
196/// Checks if a user id exists in our profile manager 196/// Checks if a user id exists in our profile manager
197bool ProfileManager::UserExists(UUID uuid) const { 197bool ProfileManager::UserExists(UUID uuid) const {
198 return GetUserIndex(uuid) != std::nullopt; 198 return GetUserIndex(uuid).has_value();
199} 199}
200 200
201bool ProfileManager::UserExistsIndex(std::size_t index) const { 201bool ProfileManager::UserExistsIndex(std::size_t index) const {
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 59aafd616..ac3ff9f20 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -743,7 +743,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
743 743
744 Account::ProfileManager profile_manager{}; 744 Account::ProfileManager profile_manager{};
745 const auto uuid = profile_manager.GetUser(Settings::values.current_user); 745 const auto uuid = profile_manager.GetUser(Settings::values.current_user);
746 ASSERT(uuid != std::nullopt); 746 ASSERT(uuid);
747 params.current_user = uuid->uuid; 747 params.current_user = uuid->uuid;
748 748
749 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 749 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index fd98d541d..630ebbfc7 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -31,7 +31,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer)
31 buffer_wait_event->Signal(); 31 buffer_wait_event->Signal();
32} 32}
33 33
34boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { 34std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
35 auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) { 35 auto itr = std::find_if(queue.begin(), queue.end(), [&](const Buffer& buffer) {
36 // Only consider free buffers. Buffers become free once again after they've been Acquired 36 // Only consider free buffers. Buffers become free once again after they've been Acquired
37 // and Released by the compositor, see the NVFlinger::Compose method. 37 // and Released by the compositor, see the NVFlinger::Compose method.
@@ -44,7 +44,7 @@ boost::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
44 }); 44 });
45 45
46 if (itr == queue.end()) { 46 if (itr == queue.end()) {
47 return boost::none; 47 return {};
48 } 48 }
49 49
50 itr->status = Buffer::Status::Dequeued; 50 itr->status = Buffer::Status::Dequeued;
@@ -70,12 +70,12 @@ void BufferQueue::QueueBuffer(u32 slot, BufferTransformFlags transform,
70 itr->crop_rect = crop_rect; 70 itr->crop_rect = crop_rect;
71} 71}
72 72
73boost::optional<const BufferQueue::Buffer&> BufferQueue::AcquireBuffer() { 73std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::AcquireBuffer() {
74 auto itr = std::find_if(queue.begin(), queue.end(), [](const Buffer& buffer) { 74 auto itr = std::find_if(queue.begin(), queue.end(), [](const Buffer& buffer) {
75 return buffer.status == Buffer::Status::Queued; 75 return buffer.status == Buffer::Status::Queued;
76 }); 76 });
77 if (itr == queue.end()) 77 if (itr == queue.end())
78 return boost::none; 78 return {};
79 itr->status = Buffer::Status::Acquired; 79 itr->status = Buffer::Status::Acquired;
80 return *itr; 80 return *itr;
81} 81}
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 50b767732..2fe81a560 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -4,8 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <optional>
7#include <vector> 8#include <vector>
8#include <boost/optional.hpp> 9
9#include "common/common_funcs.h" 10#include "common/common_funcs.h"
10#include "common/math_util.h" 11#include "common/math_util.h"
11#include "common/swap.h" 12#include "common/swap.h"
@@ -73,11 +74,11 @@ public:
73 }; 74 };
74 75
75 void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer); 76 void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer);
76 boost::optional<u32> DequeueBuffer(u32 width, u32 height); 77 std::optional<u32> DequeueBuffer(u32 width, u32 height);
77 const IGBPBuffer& RequestBuffer(u32 slot) const; 78 const IGBPBuffer& RequestBuffer(u32 slot) const;
78 void QueueBuffer(u32 slot, BufferTransformFlags transform, 79 void QueueBuffer(u32 slot, BufferTransformFlags transform,
79 const MathUtil::Rectangle<int>& crop_rect); 80 const MathUtil::Rectangle<int>& crop_rect);
80 boost::optional<const Buffer&> AcquireBuffer(); 81 std::optional<std::reference_wrapper<const Buffer>> AcquireBuffer();
81 void ReleaseBuffer(u32 slot); 82 void ReleaseBuffer(u32 slot);
82 u32 Query(QueryType type); 83 u32 Query(QueryType type);
83 84
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index d47b6f659..214e6d1b3 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -3,7 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <boost/optional.hpp> 6#include <optional>
7 7
8#include "common/alignment.h" 8#include "common/alignment.h"
9#include "common/assert.h" 9#include "common/assert.h"
@@ -134,7 +134,7 @@ void NVFlinger::Compose() {
134 134
135 MicroProfileFlip(); 135 MicroProfileFlip();
136 136
137 if (buffer == boost::none) { 137 if (!buffer) {
138 auto& system_instance = Core::System::GetInstance(); 138 auto& system_instance = Core::System::GetInstance();
139 139
140 // There was no queued buffer to draw, render previous frame 140 // There was no queued buffer to draw, render previous frame
@@ -143,7 +143,7 @@ void NVFlinger::Compose() {
143 continue; 143 continue;
144 } 144 }
145 145
146 auto& igbp_buffer = buffer->igbp_buffer; 146 auto& igbp_buffer = buffer->get().igbp_buffer;
147 147
148 // Now send the buffer to the GPU for drawing. 148 // Now send the buffer to the GPU for drawing.
149 // TODO(Subv): Support more than just disp0. The display device selection is probably based 149 // TODO(Subv): Support more than just disp0. The display device selection is probably based
@@ -152,10 +152,10 @@ void NVFlinger::Compose() {
152 ASSERT(nvdisp); 152 ASSERT(nvdisp);
153 153
154 nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format, 154 nvdisp->flip(igbp_buffer.gpu_buffer_id, igbp_buffer.offset, igbp_buffer.format,
155 igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride, buffer->transform, 155 igbp_buffer.width, igbp_buffer.height, igbp_buffer.stride,
156 buffer->crop_rect); 156 buffer->get().transform, buffer->get().crop_rect);
157 157
158 buffer_queue->ReleaseBuffer(buffer->slot); 158 buffer_queue->ReleaseBuffer(buffer->get().slot);
159 } 159 }
160} 160}
161 161
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index c489da071..f0a831d45 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -132,11 +132,11 @@ public:
132 // clang-format off 132 // clang-format off
133 static const FunctionInfo functions[] = { 133 static const FunctionInfo functions[] = {
134 {0, nullptr, "BindNoticeEvent"}, 134 {0, nullptr, "BindNoticeEvent"},
135 {1, nullptr, "Unknown1"}, 135 {1, nullptr, "UnbindNoticeEvent"},
136 {2, nullptr, "GetStatus"}, 136 {2, nullptr, "GetStatus"},
137 {3, nullptr, "GetNotice"}, 137 {3, nullptr, "GetNotice"},
138 {4, nullptr, "Unknown2"}, 138 {4, nullptr, "EnablePowerRequestNotice"},
139 {5, nullptr, "Unknown3"}, 139 {5, nullptr, "DisablePowerRequestNotice"},
140 {6, nullptr, "ReplyPowerRequest"}, 140 {6, nullptr, "ReplyPowerRequest"},
141 }; 141 };
142 // clang-format on 142 // clang-format on
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 184537daa..d764b2406 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -6,9 +6,10 @@
6#include <array> 6#include <array>
7#include <cstring> 7#include <cstring>
8#include <memory> 8#include <memory>
9#include <optional>
9#include <type_traits> 10#include <type_traits>
10#include <utility> 11#include <utility>
11#include <boost/optional.hpp> 12
12#include "common/alignment.h" 13#include "common/alignment.h"
13#include "common/assert.h" 14#include "common/assert.h"
14#include "common/common_funcs.h" 15#include "common/common_funcs.h"
@@ -506,9 +507,9 @@ private:
506 IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()}; 507 IGBPDequeueBufferRequestParcel request{ctx.ReadBuffer()};
507 const u32 width{request.data.width}; 508 const u32 width{request.data.width};
508 const u32 height{request.data.height}; 509 const u32 height{request.data.height};
509 boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); 510 std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
510 511
511 if (slot != boost::none) { 512 if (slot) {
512 // Buffer is available 513 // Buffer is available
513 IGBPDequeueBufferResponseParcel response{*slot}; 514 IGBPDequeueBufferResponseParcel response{*slot};
514 ctx.WriteBuffer(response.Serialize()); 515 ctx.WriteBuffer(response.Serialize());
@@ -520,7 +521,7 @@ private:
520 Kernel::ThreadWakeupReason reason) { 521 Kernel::ThreadWakeupReason reason) {
521 // Repeat TransactParcel DequeueBuffer when a buffer is available 522 // Repeat TransactParcel DequeueBuffer when a buffer is available
522 auto buffer_queue = nv_flinger->GetBufferQueue(id); 523 auto buffer_queue = nv_flinger->GetBufferQueue(id);
523 boost::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); 524 std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
524 IGBPDequeueBufferResponseParcel response{*slot}; 525 IGBPDequeueBufferResponseParcel response{*slot};
525 ctx.WriteBuffer(response.Serialize()); 526 ctx.WriteBuffer(response.Serialize());
526 IPC::ResponseBuilder rb{ctx, 2}; 527 IPC::ResponseBuilder rb{ctx, 2};
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index e562b3a04..7686634bf 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -6,10 +6,11 @@
6 6
7#include <iosfwd> 7#include <iosfwd>
8#include <memory> 8#include <memory>
9#include <optional>
9#include <string> 10#include <string>
10#include <utility> 11#include <utility>
11#include <vector> 12#include <vector>
12#include <boost/optional.hpp> 13
13#include "common/common_types.h" 14#include "common/common_types.h"
14#include "core/file_sys/vfs.h" 15#include "core/file_sys/vfs.h"
15 16
@@ -145,7 +146,7 @@ public:
145 * information. 146 * information.
146 * @returns A pair with the optional system mode, and and the status. 147 * @returns A pair with the optional system mode, and and the status.
147 */ 148 */
148 virtual std::pair<boost::optional<u32>, ResultStatus> LoadKernelSystemMode() { 149 virtual std::pair<std::optional<u32>, ResultStatus> LoadKernelSystemMode() {
149 // 96MB allocated to the application. 150 // 96MB allocated to the application.
150 return std::make_pair(2, ResultStatus::Success); 151 return std::make_pair(2, ResultStatus::Success);
151 } 152 }
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 014298ed6..70abd856a 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -4,9 +4,9 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cstring> 6#include <cstring>
7#include <optional>
7#include <utility> 8#include <utility>
8 9
9#include <boost/optional.hpp>
10#include "common/assert.h" 10#include "common/assert.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
diff --git a/src/core/memory_hook.h b/src/core/memory_hook.h
index 0269c7ff1..940777107 100644
--- a/src/core/memory_hook.h
+++ b/src/core/memory_hook.h
@@ -5,7 +5,8 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <boost/optional.hpp> 8#include <optional>
9
9#include "common/common_types.h" 10#include "common/common_types.h"
10 11
11namespace Memory { 12namespace Memory {
@@ -18,19 +19,19 @@ namespace Memory {
18 * 19 *
19 * A hook may be mapped to multiple regions of memory. 20 * A hook may be mapped to multiple regions of memory.
20 * 21 *
21 * If a boost::none or false is returned from a function, the read/write request is passed through 22 * If a std::nullopt or false is returned from a function, the read/write request is passed through
22 * to the underlying memory region. 23 * to the underlying memory region.
23 */ 24 */
24class MemoryHook { 25class MemoryHook {
25public: 26public:
26 virtual ~MemoryHook(); 27 virtual ~MemoryHook();
27 28
28 virtual boost::optional<bool> IsValidAddress(VAddr addr) = 0; 29 virtual std::optional<bool> IsValidAddress(VAddr addr) = 0;
29 30
30 virtual boost::optional<u8> Read8(VAddr addr) = 0; 31 virtual std::optional<u8> Read8(VAddr addr) = 0;
31 virtual boost::optional<u16> Read16(VAddr addr) = 0; 32 virtual std::optional<u16> Read16(VAddr addr) = 0;
32 virtual boost::optional<u32> Read32(VAddr addr) = 0; 33 virtual std::optional<u32> Read32(VAddr addr) = 0;
33 virtual boost::optional<u64> Read64(VAddr addr) = 0; 34 virtual std::optional<u64> Read64(VAddr addr) = 0;
34 35
35 virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0; 36 virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0;
36 37
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 0de13edd3..a3b08c740 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -184,4 +184,13 @@ TelemetrySession::~TelemetrySession() {
184 backend = nullptr; 184 backend = nullptr;
185} 185}
186 186
187bool TelemetrySession::SubmitTestcase() {
188#ifdef ENABLE_WEB_SERVICE
189 field_collection.Accept(*backend);
190 return backend->SubmitTestcase();
191#else
192 return false;
193#endif
194}
195
187} // namespace Core 196} // namespace Core
diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h
index 2a4845797..023612b79 100644
--- a/src/core/telemetry_session.h
+++ b/src/core/telemetry_session.h
@@ -31,6 +31,12 @@ public:
31 field_collection.AddField(type, name, std::move(value)); 31 field_collection.AddField(type, name, std::move(value));
32 } 32 }
33 33
34 /**
35 * Submits a Testcase.
36 * @returns A bool indicating whether the submission succeeded
37 */
38 bool SubmitTestcase();
39
34private: 40private:
35 Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session 41 Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session
36 std::unique_ptr<Telemetry::VisitorInterface> backend; ///< Backend interface that logs fields 42 std::unique_ptr<Telemetry::VisitorInterface> backend; ///< Backend interface that logs fields
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
index 37e15bad0..9b8a44fa1 100644
--- a/src/tests/core/arm/arm_test_common.cpp
+++ b/src/tests/core/arm/arm_test_common.cpp
@@ -64,11 +64,11 @@ void TestEnvironment::ClearWriteRecords() {
64 64
65TestEnvironment::TestMemory::~TestMemory() {} 65TestEnvironment::TestMemory::~TestMemory() {}
66 66
67boost::optional<bool> TestEnvironment::TestMemory::IsValidAddress(VAddr addr) { 67std::optional<bool> TestEnvironment::TestMemory::IsValidAddress(VAddr addr) {
68 return true; 68 return true;
69} 69}
70 70
71boost::optional<u8> TestEnvironment::TestMemory::Read8(VAddr addr) { 71std::optional<u8> TestEnvironment::TestMemory::Read8(VAddr addr) {
72 const auto iter = data.find(addr); 72 const auto iter = data.find(addr);
73 73
74 if (iter == data.end()) { 74 if (iter == data.end()) {
@@ -79,15 +79,15 @@ boost::optional<u8> TestEnvironment::TestMemory::Read8(VAddr addr) {
79 return iter->second; 79 return iter->second;
80} 80}
81 81
82boost::optional<u16> TestEnvironment::TestMemory::Read16(VAddr addr) { 82std::optional<u16> TestEnvironment::TestMemory::Read16(VAddr addr) {
83 return *Read8(addr) | static_cast<u16>(*Read8(addr + 1)) << 8; 83 return *Read8(addr) | static_cast<u16>(*Read8(addr + 1)) << 8;
84} 84}
85 85
86boost::optional<u32> TestEnvironment::TestMemory::Read32(VAddr addr) { 86std::optional<u32> TestEnvironment::TestMemory::Read32(VAddr addr) {
87 return *Read16(addr) | static_cast<u32>(*Read16(addr + 2)) << 16; 87 return *Read16(addr) | static_cast<u32>(*Read16(addr + 2)) << 16;
88} 88}
89 89
90boost::optional<u64> TestEnvironment::TestMemory::Read64(VAddr addr) { 90std::optional<u64> TestEnvironment::TestMemory::Read64(VAddr addr) {
91 return *Read32(addr) | static_cast<u64>(*Read32(addr + 4)) << 32; 91 return *Read32(addr) | static_cast<u64>(*Read32(addr + 4)) << 32;
92} 92}
93 93
diff --git a/src/tests/core/arm/arm_test_common.h b/src/tests/core/arm/arm_test_common.h
index 5de8dab4e..0b7539601 100644
--- a/src/tests/core/arm/arm_test_common.h
+++ b/src/tests/core/arm/arm_test_common.h
@@ -64,12 +64,12 @@ private:
64 64
65 ~TestMemory() override; 65 ~TestMemory() override;
66 66
67 boost::optional<bool> IsValidAddress(VAddr addr) override; 67 std::optional<bool> IsValidAddress(VAddr addr) override;
68 68
69 boost::optional<u8> Read8(VAddr addr) override; 69 std::optional<u8> Read8(VAddr addr) override;
70 boost::optional<u16> Read16(VAddr addr) override; 70 std::optional<u16> Read16(VAddr addr) override;
71 boost::optional<u32> Read32(VAddr addr) override; 71 std::optional<u32> Read32(VAddr addr) override;
72 boost::optional<u64> Read64(VAddr addr) override; 72 std::optional<u64> Read64(VAddr addr) override;
73 73
74 bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) override; 74 bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) override;
75 75
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 09ecc5bad..ddb1a1d69 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -51,6 +51,10 @@ add_library(video_core STATIC
51 renderer_opengl/maxwell_to_gl.h 51 renderer_opengl/maxwell_to_gl.h
52 renderer_opengl/renderer_opengl.cpp 52 renderer_opengl/renderer_opengl.cpp
53 renderer_opengl/renderer_opengl.h 53 renderer_opengl/renderer_opengl.h
54 renderer_opengl/utils.cpp
55 renderer_opengl/utils.h
56 surface.cpp
57 surface.h
54 textures/astc.cpp 58 textures/astc.cpp
55 textures/astc.h 59 textures/astc.h
56 textures/decoders.cpp 60 textures/decoders.cpp
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index f1aa6091b..28e8c13aa 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -81,7 +81,7 @@ void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) {
81 for (auto entry : commands) { 81 for (auto entry : commands) {
82 Tegra::GPUVAddr address = entry.Address(); 82 Tegra::GPUVAddr address = entry.Address();
83 u32 size = entry.sz; 83 u32 size = entry.sz;
84 const boost::optional<VAddr> head_address = memory_manager->GpuToCpuAddress(address); 84 const std::optional<VAddr> head_address = memory_manager->GpuToCpuAddress(address);
85 VAddr current_addr = *head_address; 85 VAddr current_addr = *head_address;
86 while (current_addr < *head_address + size * sizeof(CommandHeader)) { 86 while (current_addr < *head_address + size * sizeof(CommandHeader)) {
87 const CommandHeader header = {Memory::Read32(current_addr)}; 87 const CommandHeader header = {Memory::Read32(current_addr)};
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 27ef865a2..d79c50919 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -43,15 +43,17 @@ void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
43 // Reset the current macro. 43 // Reset the current macro.
44 executing_macro = 0; 44 executing_macro = 0;
45 45
46 // The requested macro must have been uploaded already. 46 // Lookup the macro offset
47 auto macro_code = uploaded_macros.find(method); 47 const u32 entry{(method - MacroRegistersStart) >> 1};
48 if (macro_code == uploaded_macros.end()) { 48 const auto& search{macro_offsets.find(entry)};
49 LOG_ERROR(HW_GPU, "Macro {:04X} was not uploaded", method); 49 if (search == macro_offsets.end()) {
50 LOG_CRITICAL(HW_GPU, "macro not found for method 0x{:X}!", method);
51 UNREACHABLE();
50 return; 52 return;
51 } 53 }
52 54
53 // Execute the current macro. 55 // Execute the current macro.
54 macro_interpreter.Execute(macro_code->second, std::move(parameters)); 56 macro_interpreter.Execute(search->second, std::move(parameters));
55} 57}
56 58
57void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { 59void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
@@ -97,6 +99,10 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
97 ProcessMacroUpload(value); 99 ProcessMacroUpload(value);
98 break; 100 break;
99 } 101 }
102 case MAXWELL3D_REG_INDEX(macros.bind): {
103 ProcessMacroBind(value);
104 break;
105 }
100 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]): 106 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
101 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]): 107 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]):
102 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]): 108 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):
@@ -158,16 +164,20 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
158} 164}
159 165
160void Maxwell3D::ProcessMacroUpload(u32 data) { 166void Maxwell3D::ProcessMacroUpload(u32 data) {
161 // Store the uploaded macro code to interpret them when they're called. 167 ASSERT_MSG(regs.macros.upload_address < macro_memory.size(),
162 auto& macro = uploaded_macros[regs.macros.entry * 2 + MacroRegistersStart]; 168 "upload_address exceeded macro_memory size!");
163 macro.push_back(data); 169 macro_memory[regs.macros.upload_address++] = data;
170}
171
172void Maxwell3D::ProcessMacroBind(u32 data) {
173 macro_offsets[regs.macros.entry] = data;
164} 174}
165 175
166void Maxwell3D::ProcessQueryGet() { 176void Maxwell3D::ProcessQueryGet() {
167 GPUVAddr sequence_address = regs.query.QueryAddress(); 177 GPUVAddr sequence_address = regs.query.QueryAddress();
168 // Since the sequence address is given as a GPU VAddr, we have to convert it to an application 178 // Since the sequence address is given as a GPU VAddr, we have to convert it to an application
169 // VAddr before writing. 179 // VAddr before writing.
170 boost::optional<VAddr> address = memory_manager.GpuToCpuAddress(sequence_address); 180 std::optional<VAddr> address = memory_manager.GpuToCpuAddress(sequence_address);
171 181
172 // TODO(Subv): Support the other query units. 182 // TODO(Subv): Support the other query units.
173 ASSERT_MSG(regs.query.query_get.unit == Regs::QueryUnit::Crop, 183 ASSERT_MSG(regs.query.query_get.unit == Regs::QueryUnit::Crop,
@@ -285,7 +295,7 @@ void Maxwell3D::ProcessCBData(u32 value) {
285 // Don't allow writing past the end of the buffer. 295 // Don't allow writing past the end of the buffer.
286 ASSERT(regs.const_buffer.cb_pos + sizeof(u32) <= regs.const_buffer.cb_size); 296 ASSERT(regs.const_buffer.cb_pos + sizeof(u32) <= regs.const_buffer.cb_size);
287 297
288 boost::optional<VAddr> address = 298 std::optional<VAddr> address =
289 memory_manager.GpuToCpuAddress(buffer_address + regs.const_buffer.cb_pos); 299 memory_manager.GpuToCpuAddress(buffer_address + regs.const_buffer.cb_pos);
290 300
291 Memory::Write32(*address, value); 301 Memory::Write32(*address, value);
@@ -298,7 +308,7 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const {
298 GPUVAddr tic_base_address = regs.tic.TICAddress(); 308 GPUVAddr tic_base_address = regs.tic.TICAddress();
299 309
300 GPUVAddr tic_address_gpu = tic_base_address + tic_index * sizeof(Texture::TICEntry); 310 GPUVAddr tic_address_gpu = tic_base_address + tic_index * sizeof(Texture::TICEntry);
301 boost::optional<VAddr> tic_address_cpu = memory_manager.GpuToCpuAddress(tic_address_gpu); 311 std::optional<VAddr> tic_address_cpu = memory_manager.GpuToCpuAddress(tic_address_gpu);
302 312
303 Texture::TICEntry tic_entry; 313 Texture::TICEntry tic_entry;
304 Memory::ReadBlock(*tic_address_cpu, &tic_entry, sizeof(Texture::TICEntry)); 314 Memory::ReadBlock(*tic_address_cpu, &tic_entry, sizeof(Texture::TICEntry));
@@ -322,7 +332,7 @@ Texture::TSCEntry Maxwell3D::GetTSCEntry(u32 tsc_index) const {
322 GPUVAddr tsc_base_address = regs.tsc.TSCAddress(); 332 GPUVAddr tsc_base_address = regs.tsc.TSCAddress();
323 333
324 GPUVAddr tsc_address_gpu = tsc_base_address + tsc_index * sizeof(Texture::TSCEntry); 334 GPUVAddr tsc_address_gpu = tsc_base_address + tsc_index * sizeof(Texture::TSCEntry);
325 boost::optional<VAddr> tsc_address_cpu = memory_manager.GpuToCpuAddress(tsc_address_gpu); 335 std::optional<VAddr> tsc_address_cpu = memory_manager.GpuToCpuAddress(tsc_address_gpu);
326 336
327 Texture::TSCEntry tsc_entry; 337 Texture::TSCEntry tsc_entry;
328 Memory::ReadBlock(*tsc_address_cpu, &tsc_entry, sizeof(Texture::TSCEntry)); 338 Memory::ReadBlock(*tsc_address_cpu, &tsc_entry, sizeof(Texture::TSCEntry));
@@ -386,7 +396,7 @@ Texture::FullTextureInfo Maxwell3D::GetStageTexture(Regs::ShaderStage stage,
386 396
387 ASSERT(tex_info_address < tex_info_buffer.address + tex_info_buffer.size); 397 ASSERT(tex_info_address < tex_info_buffer.address + tex_info_buffer.size);
388 398
389 boost::optional<VAddr> tex_address_cpu = memory_manager.GpuToCpuAddress(tex_info_address); 399 std::optional<VAddr> tex_address_cpu = memory_manager.GpuToCpuAddress(tex_info_address);
390 Texture::TextureHandle tex_handle{Memory::Read32(*tex_address_cpu)}; 400 Texture::TextureHandle tex_handle{Memory::Read32(*tex_address_cpu)};
391 401
392 Texture::FullTextureInfo tex_info{}; 402 Texture::FullTextureInfo tex_info{};
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 443affc36..50873813e 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -475,12 +475,13 @@ public:
475 INSERT_PADDING_WORDS(0x45); 475 INSERT_PADDING_WORDS(0x45);
476 476
477 struct { 477 struct {
478 INSERT_PADDING_WORDS(1); 478 u32 upload_address;
479 u32 data; 479 u32 data;
480 u32 entry; 480 u32 entry;
481 u32 bind;
481 } macros; 482 } macros;
482 483
483 INSERT_PADDING_WORDS(0x189); 484 INSERT_PADDING_WORDS(0x188);
484 485
485 u32 tfb_enabled; 486 u32 tfb_enabled;
486 487
@@ -994,12 +995,25 @@ public:
994 /// Returns the texture information for a specific texture in a specific shader stage. 995 /// Returns the texture information for a specific texture in a specific shader stage.
995 Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const; 996 Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const;
996 997
998 /// Memory for macro code - it's undetermined how big this is, however 1MB is much larger than
999 /// we've seen used.
1000 using MacroMemory = std::array<u32, 0x40000>;
1001
1002 /// Gets a reference to macro memory.
1003 const MacroMemory& GetMacroMemory() const {
1004 return macro_memory;
1005 }
1006
997private: 1007private:
998 void InitializeRegisterDefaults(); 1008 void InitializeRegisterDefaults();
999 1009
1000 VideoCore::RasterizerInterface& rasterizer; 1010 VideoCore::RasterizerInterface& rasterizer;
1001 1011
1002 std::unordered_map<u32, std::vector<u32>> uploaded_macros; 1012 /// Start offsets of each macro in macro_memory
1013 std::unordered_map<u32, u32> macro_offsets;
1014
1015 /// Memory for macro code
1016 MacroMemory macro_memory;
1003 1017
1004 /// Macro method that is currently being executed / being fed parameters. 1018 /// Macro method that is currently being executed / being fed parameters.
1005 u32 executing_macro = 0; 1019 u32 executing_macro = 0;
@@ -1022,9 +1036,12 @@ private:
1022 */ 1036 */
1023 void CallMacroMethod(u32 method, std::vector<u32> parameters); 1037 void CallMacroMethod(u32 method, std::vector<u32> parameters);
1024 1038
1025 /// Handles writes to the macro uploading registers. 1039 /// Handles writes to the macro uploading register.
1026 void ProcessMacroUpload(u32 data); 1040 void ProcessMacroUpload(u32 data);
1027 1041
1042 /// Handles writes to the macro bind register.
1043 void ProcessMacroBind(u32 data);
1044
1028 /// Handles a write to the CLEAR_BUFFERS register. 1045 /// Handles a write to the CLEAR_BUFFERS register.
1029 void ProcessClearBuffers(); 1046 void ProcessClearBuffers();
1030 1047
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 55763332e..83a6fd875 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -5,12 +5,11 @@
5#pragma once 5#pragma once
6 6
7#include <bitset> 7#include <bitset>
8#include <optional>
8#include <string> 9#include <string>
9#include <tuple> 10#include <tuple>
10#include <vector> 11#include <vector>
11 12
12#include <boost/optional.hpp>
13
14#include "common/assert.h" 13#include "common/assert.h"
15#include "common/bit_field.h" 14#include "common/bit_field.h"
16#include "common/common_types.h" 15#include "common/common_types.h"
@@ -579,6 +578,10 @@ union Instruction {
579 } fmul32; 578 } fmul32;
580 579
581 union { 580 union {
581 BitField<52, 1, u64> generates_cc;
582 } op_32;
583
584 union {
582 BitField<48, 1, u64> is_signed; 585 BitField<48, 1, u64> is_signed;
583 } shift; 586 } shift;
584 587
@@ -1457,7 +1460,7 @@ public:
1457 Type type; 1460 Type type;
1458 }; 1461 };
1459 1462
1460 static boost::optional<const Matcher&> Decode(Instruction instr) { 1463 static std::optional<std::reference_wrapper<const Matcher>> Decode(Instruction instr) {
1461 static const auto table{GetDecodeTable()}; 1464 static const auto table{GetDecodeTable()};
1462 1465
1463 const auto matches_instruction = [instr](const auto& matcher) { 1466 const auto matches_instruction = [instr](const auto& matcher) {
@@ -1465,7 +1468,8 @@ public:
1465 }; 1468 };
1466 1469
1467 auto iter = std::find_if(table.begin(), table.end(), matches_instruction); 1470 auto iter = std::find_if(table.begin(), table.end(), matches_instruction);
1468 return iter != table.end() ? boost::optional<const Matcher&>(*iter) : boost::none; 1471 return iter != table.end() ? std::optional<std::reference_wrapper<const Matcher>>(*iter)
1472 : std::nullopt;
1469 } 1473 }
1470 1474
1471private: 1475private:
diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp
index 377bd66ab..335a8d407 100644
--- a/src/video_core/macro_interpreter.cpp
+++ b/src/video_core/macro_interpreter.cpp
@@ -11,7 +11,7 @@ namespace Tegra {
11 11
12MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {} 12MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
13 13
14void MacroInterpreter::Execute(const std::vector<u32>& code, std::vector<u32> parameters) { 14void MacroInterpreter::Execute(u32 offset, std::vector<u32> parameters) {
15 Reset(); 15 Reset();
16 registers[1] = parameters[0]; 16 registers[1] = parameters[0];
17 this->parameters = std::move(parameters); 17 this->parameters = std::move(parameters);
@@ -19,7 +19,7 @@ void MacroInterpreter::Execute(const std::vector<u32>& code, std::vector<u32> pa
19 // Execute the code until we hit an exit condition. 19 // Execute the code until we hit an exit condition.
20 bool keep_executing = true; 20 bool keep_executing = true;
21 while (keep_executing) { 21 while (keep_executing) {
22 keep_executing = Step(code, false); 22 keep_executing = Step(offset, false);
23 } 23 }
24 24
25 // Assert the the macro used all the input parameters 25 // Assert the the macro used all the input parameters
@@ -29,7 +29,7 @@ void MacroInterpreter::Execute(const std::vector<u32>& code, std::vector<u32> pa
29void MacroInterpreter::Reset() { 29void MacroInterpreter::Reset() {
30 registers = {}; 30 registers = {};
31 pc = 0; 31 pc = 0;
32 delayed_pc = boost::none; 32 delayed_pc = {};
33 method_address.raw = 0; 33 method_address.raw = 0;
34 parameters.clear(); 34 parameters.clear();
35 // The next parameter index starts at 1, because $r1 already has the value of the first 35 // The next parameter index starts at 1, because $r1 already has the value of the first
@@ -37,17 +37,17 @@ void MacroInterpreter::Reset() {
37 next_parameter_index = 1; 37 next_parameter_index = 1;
38} 38}
39 39
40bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) { 40bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) {
41 u32 base_address = pc; 41 u32 base_address = pc;
42 42
43 Opcode opcode = GetOpcode(code); 43 Opcode opcode = GetOpcode(offset);
44 pc += 4; 44 pc += 4;
45 45
46 // Update the program counter if we were delayed 46 // Update the program counter if we were delayed
47 if (delayed_pc != boost::none) { 47 if (delayed_pc) {
48 ASSERT(is_delay_slot); 48 ASSERT(is_delay_slot);
49 pc = *delayed_pc; 49 pc = *delayed_pc;
50 delayed_pc = boost::none; 50 delayed_pc = {};
51 } 51 }
52 52
53 switch (opcode.operation) { 53 switch (opcode.operation) {
@@ -108,7 +108,7 @@ bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) {
108 108
109 delayed_pc = base_address + opcode.GetBranchTarget(); 109 delayed_pc = base_address + opcode.GetBranchTarget();
110 // Execute one more instruction due to the delay slot. 110 // Execute one more instruction due to the delay slot.
111 return Step(code, true); 111 return Step(offset, true);
112 } 112 }
113 break; 113 break;
114 } 114 }
@@ -121,17 +121,18 @@ bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) {
121 // Exit has a delay slot, execute the next instruction 121 // Exit has a delay slot, execute the next instruction
122 // Note: Executing an exit during a branch delay slot will cause the instruction at the 122 // Note: Executing an exit during a branch delay slot will cause the instruction at the
123 // branch target to be executed before exiting. 123 // branch target to be executed before exiting.
124 Step(code, true); 124 Step(offset, true);
125 return false; 125 return false;
126 } 126 }
127 127
128 return true; 128 return true;
129} 129}
130 130
131MacroInterpreter::Opcode MacroInterpreter::GetOpcode(const std::vector<u32>& code) const { 131MacroInterpreter::Opcode MacroInterpreter::GetOpcode(u32 offset) const {
132 const auto& macro_memory{maxwell3d.GetMacroMemory()};
132 ASSERT((pc % sizeof(u32)) == 0); 133 ASSERT((pc % sizeof(u32)) == 0);
133 ASSERT(pc < code.size() * sizeof(u32)); 134 ASSERT((pc + offset) < macro_memory.size() * sizeof(u32));
134 return {code[pc / sizeof(u32)]}; 135 return {macro_memory[offset + pc / sizeof(u32)]};
135} 136}
136 137
137u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const { 138u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const {
diff --git a/src/video_core/macro_interpreter.h b/src/video_core/macro_interpreter.h
index cee0baaf3..62d1ce289 100644
--- a/src/video_core/macro_interpreter.h
+++ b/src/video_core/macro_interpreter.h
@@ -5,8 +5,9 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <optional>
8#include <vector> 9#include <vector>
9#include <boost/optional.hpp> 10
10#include "common/bit_field.h" 11#include "common/bit_field.h"
11#include "common/common_types.h" 12#include "common/common_types.h"
12 13
@@ -21,10 +22,10 @@ public:
21 22
22 /** 23 /**
23 * Executes the macro code with the specified input parameters. 24 * Executes the macro code with the specified input parameters.
24 * @param code The macro byte code to execute 25 * @param offset Offset to start execution at.
25 * @param parameters The parameters of the macro 26 * @param parameters The parameters of the macro.
26 */ 27 */
27 void Execute(const std::vector<u32>& code, std::vector<u32> parameters); 28 void Execute(u32 offset, std::vector<u32> parameters);
28 29
29private: 30private:
30 enum class Operation : u32 { 31 enum class Operation : u32 {
@@ -109,11 +110,11 @@ private:
109 /** 110 /**
110 * Executes a single macro instruction located at the current program counter. Returns whether 111 * Executes a single macro instruction located at the current program counter. Returns whether
111 * the interpreter should keep running. 112 * the interpreter should keep running.
112 * @param code The macro code to execute. 113 * @param offset Offset to start execution at.
113 * @param is_delay_slot Whether the current step is being executed due to a delay slot in a 114 * @param is_delay_slot Whether the current step is being executed due to a delay slot in a
114 * previous instruction. 115 * previous instruction.
115 */ 116 */
116 bool Step(const std::vector<u32>& code, bool is_delay_slot); 117 bool Step(u32 offset, bool is_delay_slot);
117 118
118 /// Calculates the result of an ALU operation. src_a OP src_b; 119 /// Calculates the result of an ALU operation. src_a OP src_b;
119 u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const; 120 u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const;
@@ -126,7 +127,7 @@ private:
126 bool EvaluateBranchCondition(BranchCondition cond, u32 value) const; 127 bool EvaluateBranchCondition(BranchCondition cond, u32 value) const;
127 128
128 /// Reads an opcode at the current program counter location. 129 /// Reads an opcode at the current program counter location.
129 Opcode GetOpcode(const std::vector<u32>& code) const; 130 Opcode GetOpcode(u32 offset) const;
130 131
131 /// Returns the specified register's value. Register 0 is hardcoded to always return 0. 132 /// Returns the specified register's value. Register 0 is hardcoded to always return 0.
132 u32 GetRegister(u32 register_id) const; 133 u32 GetRegister(u32 register_id) const;
@@ -149,7 +150,7 @@ private:
149 Engines::Maxwell3D& maxwell3d; 150 Engines::Maxwell3D& maxwell3d;
150 151
151 u32 pc; ///< Current program counter 152 u32 pc; ///< Current program counter
152 boost::optional<u32> 153 std::optional<u32>
153 delayed_pc; ///< Program counter to execute at after the delay slot is executed. 154 delayed_pc; ///< Program counter to execute at after the delay slot is executed.
154 155
155 static constexpr std::size_t NumMacroRegisters = 8; 156 static constexpr std::size_t NumMacroRegisters = 8;
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index 022d4ab74..90a8e825d 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -9,7 +9,7 @@
9namespace Tegra { 9namespace Tegra {
10 10
11GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) { 11GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
12 boost::optional<GPUVAddr> gpu_addr = FindFreeBlock(size, align); 12 std::optional<GPUVAddr> gpu_addr = FindFreeBlock(size, align);
13 ASSERT(gpu_addr); 13 ASSERT(gpu_addr);
14 14
15 for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { 15 for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
@@ -34,7 +34,7 @@ GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) {
34} 34}
35 35
36GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) { 36GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) {
37 boost::optional<GPUVAddr> gpu_addr = FindFreeBlock(size, PAGE_SIZE); 37 std::optional<GPUVAddr> gpu_addr = FindFreeBlock(size, PAGE_SIZE);
38 ASSERT(gpu_addr); 38 ASSERT(gpu_addr);
39 39
40 for (u64 offset = 0; offset < size; offset += PAGE_SIZE) { 40 for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
@@ -97,7 +97,7 @@ GPUVAddr MemoryManager::GetRegionEnd(GPUVAddr region_start) const {
97 return {}; 97 return {};
98} 98}
99 99
100boost::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) { 100std::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
101 GPUVAddr gpu_addr = 0; 101 GPUVAddr gpu_addr = 0;
102 u64 free_space = 0; 102 u64 free_space = 0;
103 align = (align + PAGE_MASK) & ~PAGE_MASK; 103 align = (align + PAGE_MASK) & ~PAGE_MASK;
@@ -118,7 +118,7 @@ boost::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
118 return {}; 118 return {};
119} 119}
120 120
121boost::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) { 121std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) {
122 VAddr base_addr = PageSlot(gpu_addr); 122 VAddr base_addr = PageSlot(gpu_addr);
123 123
124 if (base_addr == static_cast<u64>(PageStatus::Allocated) || 124 if (base_addr == static_cast<u64>(PageStatus::Allocated) ||
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index caf80093f..b1255fd56 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -6,10 +6,9 @@
6 6
7#include <array> 7#include <array>
8#include <memory> 8#include <memory>
9#include <optional>
9#include <vector> 10#include <vector>
10 11
11#include <boost/optional.hpp>
12
13#include "common/common_types.h" 12#include "common/common_types.h"
14 13
15namespace Tegra { 14namespace Tegra {
@@ -27,7 +26,7 @@ public:
27 GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size); 26 GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size);
28 GPUVAddr UnmapBuffer(GPUVAddr gpu_addr, u64 size); 27 GPUVAddr UnmapBuffer(GPUVAddr gpu_addr, u64 size);
29 GPUVAddr GetRegionEnd(GPUVAddr region_start) const; 28 GPUVAddr GetRegionEnd(GPUVAddr region_start) const;
30 boost::optional<VAddr> GpuToCpuAddress(GPUVAddr gpu_addr); 29 std::optional<VAddr> GpuToCpuAddress(GPUVAddr gpu_addr);
31 std::vector<GPUVAddr> CpuToGpuAddress(VAddr cpu_addr) const; 30 std::vector<GPUVAddr> CpuToGpuAddress(VAddr cpu_addr) const;
32 31
33 static constexpr u64 PAGE_BITS = 16; 32 static constexpr u64 PAGE_BITS = 16;
@@ -35,7 +34,7 @@ public:
35 static constexpr u64 PAGE_MASK = PAGE_SIZE - 1; 34 static constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
36 35
37private: 36private:
38 boost::optional<GPUVAddr> FindFreeBlock(u64 size, u64 align = 1); 37 std::optional<GPUVAddr> FindFreeBlock(u64 size, u64 align = 1);
39 bool IsPageMapped(GPUVAddr gpu_addr); 38 bool IsPageMapped(GPUVAddr gpu_addr);
40 VAddr& PageSlot(GPUVAddr gpu_addr); 39 VAddr& PageSlot(GPUVAddr gpu_addr);
41 40
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 2cd0738ff..669e26e15 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -6,7 +6,8 @@
6 6
7#include <atomic> 7#include <atomic>
8#include <memory> 8#include <memory>
9#include <boost/optional.hpp> 9#include <optional>
10
10#include "common/common_types.h" 11#include "common/common_types.h"
11#include "video_core/gpu.h" 12#include "video_core/gpu.h"
12#include "video_core/rasterizer_interface.h" 13#include "video_core/rasterizer_interface.h"
@@ -28,7 +29,8 @@ public:
28 virtual ~RendererBase(); 29 virtual ~RendererBase();
29 30
30 /// Swap buffers (render frame) 31 /// Swap buffers (render frame)
31 virtual void SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) = 0; 32 virtual void SwapBuffers(
33 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) = 0;
32 34
33 /// Initialize the renderer 35 /// Initialize the renderer
34 virtual bool Init() = 0; 36 virtual bool Init() = 0;
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index c142095c5..41a54b3e7 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -17,7 +17,7 @@ OGLBufferCache::OGLBufferCache(std::size_t size) : stream_buffer(GL_ARRAY_BUFFER
17GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size, 17GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size,
18 std::size_t alignment, bool cache) { 18 std::size_t alignment, bool cache) {
19 auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager(); 19 auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager();
20 const boost::optional<VAddr> cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)}; 20 const std::optional<VAddr> cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)};
21 21
22 // Cache management is a big overhead, so only cache entries with a given size. 22 // Cache management is a big overhead, so only cache entries with a given size.
23 // TODO: Figure out which size is the best for given games. 23 // TODO: Figure out which size is the best for given games.
diff --git a/src/video_core/renderer_opengl/gl_primitive_assembler.cpp b/src/video_core/renderer_opengl/gl_primitive_assembler.cpp
index ee1d9601b..741f14bc3 100644
--- a/src/video_core/renderer_opengl/gl_primitive_assembler.cpp
+++ b/src/video_core/renderer_opengl/gl_primitive_assembler.cpp
@@ -45,7 +45,7 @@ GLintptr PrimitiveAssembler::MakeQuadIndexed(Tegra::GPUVAddr gpu_addr, std::size
45 auto [dst_pointer, index_offset] = buffer_cache.ReserveMemory(map_size); 45 auto [dst_pointer, index_offset] = buffer_cache.ReserveMemory(map_size);
46 46
47 auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager(); 47 auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager();
48 const boost::optional<VAddr> cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)}; 48 const std::optional<VAddr> cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)};
49 const u8* source{Memory::GetPointer(*cpu_addr)}; 49 const u8* source{Memory::GetPointer(*cpu_addr)};
50 50
51 for (u32 primitive = 0; primitive < count / 4; ++primitive) { 51 for (u32 primitive = 0; primitive < count / 4; ++primitive) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index cb180b93c..75e31c6de 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -30,8 +30,8 @@
30namespace OpenGL { 30namespace OpenGL {
31 31
32using Maxwell = Tegra::Engines::Maxwell3D::Regs; 32using Maxwell = Tegra::Engines::Maxwell3D::Regs;
33using PixelFormat = SurfaceParams::PixelFormat; 33using PixelFormat = VideoCore::Surface::PixelFormat;
34using SurfaceType = SurfaceParams::SurfaceType; 34using SurfaceType = VideoCore::Surface::SurfaceType;
35 35
36MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(128, 128, 192)); 36MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(128, 128, 192));
37MICROPROFILE_DEFINE(OpenGL_Shader, "OpenGL", "Shader Setup", MP_RGB(128, 128, 192)); 37MICROPROFILE_DEFINE(OpenGL_Shader, "OpenGL", "Shader Setup", MP_RGB(128, 128, 192));
@@ -401,7 +401,7 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
401 401
402void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb, 402void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb,
403 bool preserve_contents, 403 bool preserve_contents,
404 boost::optional<std::size_t> single_color_target) { 404 std::optional<std::size_t> single_color_target) {
405 MICROPROFILE_SCOPE(OpenGL_Framebuffer); 405 MICROPROFILE_SCOPE(OpenGL_Framebuffer);
406 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 406 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
407 407
@@ -703,7 +703,8 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
703 703
704 // Verify that the cached surface is the same size and format as the requested framebuffer 704 // Verify that the cached surface is the same size and format as the requested framebuffer
705 const auto& params{surface->GetSurfaceParams()}; 705 const auto& params{surface->GetSurfaceParams()};
706 const auto& pixel_format{SurfaceParams::PixelFormatFromGPUPixelFormat(config.pixel_format)}; 706 const auto& pixel_format{
707 VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)};
707 ASSERT_MSG(params.width == config.width, "Framebuffer width is different"); 708 ASSERT_MSG(params.width == config.width, "Framebuffer width is different");
708 ASSERT_MSG(params.height == config.height, "Framebuffer height is different"); 709 ASSERT_MSG(params.height == config.height, "Framebuffer height is different");
709 ASSERT_MSG(params.pixel_format == pixel_format, "Framebuffer pixel_format is different"); 710 ASSERT_MSG(params.pixel_format == pixel_format, "Framebuffer pixel_format is different");
@@ -731,11 +732,15 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
731 732
732 if (mag_filter != config.mag_filter) { 733 if (mag_filter != config.mag_filter) {
733 mag_filter = config.mag_filter; 734 mag_filter = config.mag_filter;
734 glSamplerParameteri(s, GL_TEXTURE_MAG_FILTER, MaxwellToGL::TextureFilterMode(mag_filter)); 735 glSamplerParameteri(
736 s, GL_TEXTURE_MAG_FILTER,
737 MaxwellToGL::TextureFilterMode(mag_filter, Tegra::Texture::TextureMipmapFilter::None));
735 } 738 }
736 if (min_filter != config.min_filter) { 739 if (min_filter != config.min_filter || mip_filter != config.mip_filter) {
737 min_filter = config.min_filter; 740 min_filter = config.min_filter;
738 glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, MaxwellToGL::TextureFilterMode(min_filter)); 741 mip_filter = config.mip_filter;
742 glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER,
743 MaxwellToGL::TextureFilterMode(min_filter, mip_filter));
739 } 744 }
740 745
741 if (wrap_u != config.wrap_u) { 746 if (wrap_u != config.wrap_u) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 5020a5392..47097c569 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -8,12 +8,12 @@
8#include <cstddef> 8#include <cstddef>
9#include <map> 9#include <map>
10#include <memory> 10#include <memory>
11#include <optional>
11#include <tuple> 12#include <tuple>
12#include <utility> 13#include <utility>
13#include <vector> 14#include <vector>
14 15
15#include <boost/icl/interval_map.hpp> 16#include <boost/icl/interval_map.hpp>
16#include <boost/optional.hpp>
17#include <boost/range/iterator_range.hpp> 17#include <boost/range/iterator_range.hpp>
18#include <glad/glad.h> 18#include <glad/glad.h>
19 19
@@ -93,6 +93,7 @@ private:
93 private: 93 private:
94 Tegra::Texture::TextureFilter mag_filter; 94 Tegra::Texture::TextureFilter mag_filter;
95 Tegra::Texture::TextureFilter min_filter; 95 Tegra::Texture::TextureFilter min_filter;
96 Tegra::Texture::TextureMipmapFilter mip_filter;
96 Tegra::Texture::WrapMode wrap_u; 97 Tegra::Texture::WrapMode wrap_u;
97 Tegra::Texture::WrapMode wrap_v; 98 Tegra::Texture::WrapMode wrap_v;
98 Tegra::Texture::WrapMode wrap_p; 99 Tegra::Texture::WrapMode wrap_p;
@@ -110,7 +111,7 @@ private:
110 */ 111 */
111 void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true, 112 void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true,
112 bool preserve_contents = true, 113 bool preserve_contents = true,
113 boost::optional<std::size_t> single_color_target = {}); 114 std::optional<std::size_t> single_color_target = {});
114 115
115 /* 116 /*
116 * Configures the current constbuffers to use for the draw command. 117 * Configures the current constbuffers to use for the draw command.
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index b057e2efa..f194a7687 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -16,15 +16,21 @@
16#include "core/settings.h" 16#include "core/settings.h"
17#include "video_core/engines/maxwell_3d.h" 17#include "video_core/engines/maxwell_3d.h"
18#include "video_core/renderer_opengl/gl_rasterizer_cache.h" 18#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
19#include "video_core/renderer_opengl/utils.h"
20#include "video_core/surface.h"
19#include "video_core/textures/astc.h" 21#include "video_core/textures/astc.h"
20#include "video_core/textures/decoders.h" 22#include "video_core/textures/decoders.h"
21#include "video_core/utils.h" 23#include "video_core/utils.h"
22 24
23namespace OpenGL { 25namespace OpenGL {
24 26
25using SurfaceType = SurfaceParams::SurfaceType; 27using VideoCore::Surface::ComponentTypeFromDepthFormat;
26using PixelFormat = SurfaceParams::PixelFormat; 28using VideoCore::Surface::ComponentTypeFromRenderTarget;
27using ComponentType = SurfaceParams::ComponentType; 29using VideoCore::Surface::ComponentTypeFromTexture;
30using VideoCore::Surface::PixelFormatFromDepthFormat;
31using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
32using VideoCore::Surface::PixelFormatFromTextureFormat;
33using VideoCore::Surface::SurfaceTargetFromTextureType;
28 34
29struct FormatTuple { 35struct FormatTuple {
30 GLint internal_format; 36 GLint internal_format;
@@ -34,46 +40,6 @@ struct FormatTuple {
34 bool compressed; 40 bool compressed;
35}; 41};
36 42
37static bool IsPixelFormatASTC(PixelFormat format) {
38 switch (format) {
39 case PixelFormat::ASTC_2D_4X4:
40 case PixelFormat::ASTC_2D_5X4:
41 case PixelFormat::ASTC_2D_8X8:
42 case PixelFormat::ASTC_2D_8X5:
43 case PixelFormat::ASTC_2D_4X4_SRGB:
44 case PixelFormat::ASTC_2D_5X4_SRGB:
45 case PixelFormat::ASTC_2D_8X8_SRGB:
46 case PixelFormat::ASTC_2D_8X5_SRGB:
47 return true;
48 default:
49 return false;
50 }
51}
52
53static std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
54 switch (format) {
55 case PixelFormat::ASTC_2D_4X4:
56 return {4, 4};
57 case PixelFormat::ASTC_2D_5X4:
58 return {5, 4};
59 case PixelFormat::ASTC_2D_8X8:
60 return {8, 8};
61 case PixelFormat::ASTC_2D_8X5:
62 return {8, 5};
63 case PixelFormat::ASTC_2D_4X4_SRGB:
64 return {4, 4};
65 case PixelFormat::ASTC_2D_5X4_SRGB:
66 return {5, 4};
67 case PixelFormat::ASTC_2D_8X8_SRGB:
68 return {8, 8};
69 case PixelFormat::ASTC_2D_8X5_SRGB:
70 return {8, 5};
71 default:
72 LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format));
73 UNREACHABLE();
74 }
75}
76
77void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) { 43void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
78 auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()}; 44 auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()};
79 const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr_)}; 45 const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr_)};
@@ -90,27 +56,36 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
90 } 56 }
91} 57}
92 58
93std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const { 59std::size_t SurfaceParams::InnerMipmapMemorySize(u32 mip_level, bool force_gl, bool layer_only,
60 bool uncompressed) const {
94 const u32 compression_factor{GetCompressionFactor(pixel_format)}; 61 const u32 compression_factor{GetCompressionFactor(pixel_format)};
95 const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)}; 62 const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)};
96 u32 m_depth = (layer_only ? 1U : depth); 63 u32 m_depth = (layer_only ? 1U : depth);
97 u32 m_width = std::max(1U, width / compression_factor); 64 u32 m_width = MipWidth(mip_level);
98 u32 m_height = std::max(1U, height / compression_factor); 65 u32 m_height = MipHeight(mip_level);
99 std::size_t size = Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height, 66 m_width = uncompressed ? m_width
100 m_depth, block_height, block_depth); 67 : std::max(1U, (m_width + compression_factor - 1) / compression_factor);
101 u32 m_block_height = block_height; 68 m_height = uncompressed
102 u32 m_block_depth = block_depth; 69 ? m_height
103 std::size_t block_size_bytes = 512 * block_height * block_depth; // 512 is GOB size 70 : std::max(1U, (m_height + compression_factor - 1) / compression_factor);
104 for (u32 i = 1; i < max_mip_level; i++) { 71 m_depth = std::max(1U, m_depth >> mip_level);
105 m_width = std::max(1U, m_width / 2); 72 u32 m_block_height = MipBlockHeight(mip_level);
106 m_height = std::max(1U, m_height / 2); 73 u32 m_block_depth = MipBlockDepth(mip_level);
107 m_depth = std::max(1U, m_depth / 2); 74 return Tegra::Texture::CalculateSize(force_gl ? false : is_tiled, bytes_per_pixel, m_width,
108 m_block_height = std::max(1U, m_block_height / 2); 75 m_height, m_depth, m_block_height, m_block_depth);
109 m_block_depth = std::max(1U, m_block_depth / 2); 76}
110 size += Tegra::Texture::CalculateSize(is_tiled, bytes_per_pixel, m_width, m_height, m_depth, 77
111 m_block_height, m_block_depth); 78std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only,
79 bool uncompressed) const {
80 std::size_t block_size_bytes = Tegra::Texture::GetGOBSize() * block_height * block_depth;
81 std::size_t size = 0;
82 for (u32 i = 0; i < max_mip_level; i++) {
83 size += InnerMipmapMemorySize(i, force_gl, layer_only, uncompressed);
84 }
85 if (!force_gl && is_tiled) {
86 size = Common::AlignUp(size, block_size_bytes);
112 } 87 }
113 return is_tiled ? Common::AlignUp(size, block_size_bytes) : size; 88 return size;
114} 89}
115 90
116/*static*/ SurfaceParams SurfaceParams::CreateForTexture( 91/*static*/ SurfaceParams SurfaceParams::CreateForTexture(
@@ -188,7 +163,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {
188 params.unaligned_height = config.height; 163 params.unaligned_height = config.height;
189 params.target = SurfaceTarget::Texture2D; 164 params.target = SurfaceTarget::Texture2D;
190 params.depth = 1; 165 params.depth = 1;
191 params.max_mip_level = 0; 166 params.max_mip_level = 1;
192 params.is_layered = false; 167 params.is_layered = false;
193 168
194 // Render target specific parameters, not used for caching 169 // Render target specific parameters, not used for caching
@@ -222,7 +197,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {
222 params.unaligned_height = zeta_height; 197 params.unaligned_height = zeta_height;
223 params.target = SurfaceTarget::Texture2D; 198 params.target = SurfaceTarget::Texture2D;
224 params.depth = 1; 199 params.depth = 1;
225 params.max_mip_level = 0; 200 params.max_mip_level = 1;
226 params.is_layered = false; 201 params.is_layered = false;
227 params.rt = {}; 202 params.rt = {};
228 203
@@ -249,7 +224,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {
249 params.unaligned_height = config.height; 224 params.unaligned_height = config.height;
250 params.target = SurfaceTarget::Texture2D; 225 params.target = SurfaceTarget::Texture2D;
251 params.depth = 1; 226 params.depth = 1;
252 params.max_mip_level = 0; 227 params.max_mip_level = 1;
253 params.rt = {}; 228 params.rt = {};
254 229
255 params.InitCacheParameters(config.Address()); 230 params.InitCacheParameters(config.Address());
@@ -257,7 +232,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool layer_only) const {
257 return params; 232 return params;
258} 233}
259 234
260static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{ 235static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{
261 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U 236 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U
262 {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S 237 {GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S
263 {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI 238 {GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI
@@ -273,7 +248,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
273 {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float, 248 {GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, ComponentType::Float,
274 false}, // R11FG11FB10F 249 false}, // R11FG11FB10F
275 {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RGBA32UI 250 {GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RGBA32UI
276 {GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 251 {GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
277 true}, // DXT1 252 true}, // DXT1
278 {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 253 {GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
279 true}, // DXT23 254 true}, // DXT23
@@ -318,7 +293,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
318 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4 293 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4
319 {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8 294 {GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // BGRA8
320 // Compressed sRGB formats 295 // Compressed sRGB formats
321 {GL_COMPRESSED_SRGB_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 296 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
322 true}, // DXT1_SRGB 297 true}, // DXT1_SRGB
323 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 298 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
324 true}, // DXT23_SRGB 299 true}, // DXT23_SRGB
@@ -345,19 +320,19 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
345 ComponentType::Float, false}, // Z32FS8 320 ComponentType::Float, false}, // Z32FS8
346}}; 321}};
347 322
348static GLenum SurfaceTargetToGL(SurfaceParams::SurfaceTarget target) { 323static GLenum SurfaceTargetToGL(SurfaceTarget target) {
349 switch (target) { 324 switch (target) {
350 case SurfaceParams::SurfaceTarget::Texture1D: 325 case SurfaceTarget::Texture1D:
351 return GL_TEXTURE_1D; 326 return GL_TEXTURE_1D;
352 case SurfaceParams::SurfaceTarget::Texture2D: 327 case SurfaceTarget::Texture2D:
353 return GL_TEXTURE_2D; 328 return GL_TEXTURE_2D;
354 case SurfaceParams::SurfaceTarget::Texture3D: 329 case SurfaceTarget::Texture3D:
355 return GL_TEXTURE_3D; 330 return GL_TEXTURE_3D;
356 case SurfaceParams::SurfaceTarget::Texture1DArray: 331 case SurfaceTarget::Texture1DArray:
357 return GL_TEXTURE_1D_ARRAY; 332 return GL_TEXTURE_1D_ARRAY;
358 case SurfaceParams::SurfaceTarget::Texture2DArray: 333 case SurfaceTarget::Texture2DArray:
359 return GL_TEXTURE_2D_ARRAY; 334 return GL_TEXTURE_2D_ARRAY;
360 case SurfaceParams::SurfaceTarget::TextureCubemap: 335 case SurfaceTarget::TextureCubemap:
361 return GL_TEXTURE_CUBE_MAP; 336 return GL_TEXTURE_CUBE_MAP;
362 } 337 }
363 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target)); 338 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
@@ -373,40 +348,19 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType
373 return format; 348 return format;
374} 349}
375 350
376MathUtil::Rectangle<u32> SurfaceParams::GetRect() const { 351MathUtil::Rectangle<u32> SurfaceParams::GetRect(u32 mip_level) const {
377 u32 actual_height{unaligned_height}; 352 u32 actual_height{std::max(1U, unaligned_height >> mip_level)};
378 if (IsPixelFormatASTC(pixel_format)) { 353 if (IsPixelFormatASTC(pixel_format)) {
379 // ASTC formats must stop at the ATSC block size boundary 354 // ASTC formats must stop at the ATSC block size boundary
380 actual_height = Common::AlignDown(actual_height, GetASTCBlockSize(pixel_format).second); 355 actual_height = Common::AlignDown(actual_height, GetASTCBlockSize(pixel_format).second);
381 } 356 }
382 return {0, actual_height, width, 0}; 357 return {0, actual_height, MipWidth(mip_level), 0};
383}
384
385/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
386static bool IsFormatBCn(PixelFormat format) {
387 switch (format) {
388 case PixelFormat::DXT1:
389 case PixelFormat::DXT23:
390 case PixelFormat::DXT45:
391 case PixelFormat::DXN1:
392 case PixelFormat::DXN2SNORM:
393 case PixelFormat::DXN2UNORM:
394 case PixelFormat::BC7U:
395 case PixelFormat::BC6H_UF16:
396 case PixelFormat::BC6H_SF16:
397 case PixelFormat::DXT1_SRGB:
398 case PixelFormat::DXT23_SRGB:
399 case PixelFormat::DXT45_SRGB:
400 case PixelFormat::BC7U_SRGB:
401 return true;
402 }
403 return false;
404} 358}
405 359
406template <bool morton_to_gl, PixelFormat format> 360template <bool morton_to_gl, PixelFormat format>
407void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer, 361void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer,
408 std::size_t gl_buffer_size, VAddr addr) { 362 std::size_t gl_buffer_size, VAddr addr) {
409 constexpr u32 bytes_per_pixel = SurfaceParams::GetBytesPerPixel(format); 363 constexpr u32 bytes_per_pixel = GetBytesPerPixel(format);
410 364
411 // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual 365 // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
412 // pixel values. 366 // pixel values.
@@ -425,7 +379,7 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 d
425} 379}
426 380
427using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr), 381using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr),
428 SurfaceParams::MaxPixelFormat>; 382 VideoCore::Surface::MaxPixelFormat>;
429 383
430static constexpr GLConversionArray morton_to_gl_fns = { 384static constexpr GLConversionArray morton_to_gl_fns = {
431 // clang-format off 385 // clang-format off
@@ -563,28 +517,31 @@ static constexpr GLConversionArray gl_to_morton_fns = {
563}; 517};
564 518
565void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params, 519void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params,
566 std::vector<u8>& gl_buffer) { 520 std::vector<u8>& gl_buffer, u32 mip_level) {
567 u32 depth = params.depth; 521 u32 depth = params.MipDepth(mip_level);
568 if (params.target == SurfaceParams::SurfaceTarget::Texture2D) { 522 if (params.target == SurfaceTarget::Texture2D) {
569 // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented. 523 // TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
570 depth = 1U; 524 depth = 1U;
571 } 525 }
572 if (params.is_layered) { 526 if (params.is_layered) {
573 u64 offset = 0; 527 u64 offset = params.GetMipmapLevelOffset(mip_level);
574 u64 offset_gl = 0; 528 u64 offset_gl = 0;
575 u64 layer_size = params.LayerMemorySize(); 529 u64 layer_size = params.LayerMemorySize();
576 u64 gl_size = params.LayerSizeGL(); 530 u64 gl_size = params.LayerSizeGL(mip_level);
577 for (u32 i = 0; i < depth; i++) { 531 for (u32 i = 0; i < params.depth; i++) {
578 functions[static_cast<std::size_t>(params.pixel_format)]( 532 functions[static_cast<std::size_t>(params.pixel_format)](
579 params.width, params.block_height, params.height, params.block_depth, 1, 533 params.MipWidth(mip_level), params.MipBlockHeight(mip_level),
534 params.MipHeight(mip_level), params.MipBlockDepth(mip_level), 1,
580 gl_buffer.data() + offset_gl, gl_size, params.addr + offset); 535 gl_buffer.data() + offset_gl, gl_size, params.addr + offset);
581 offset += layer_size; 536 offset += layer_size;
582 offset_gl += gl_size; 537 offset_gl += gl_size;
583 } 538 }
584 } else { 539 } else {
540 u64 offset = params.GetMipmapLevelOffset(mip_level);
585 functions[static_cast<std::size_t>(params.pixel_format)]( 541 functions[static_cast<std::size_t>(params.pixel_format)](
586 params.width, params.block_height, params.height, params.block_depth, depth, 542 params.MipWidth(mip_level), params.MipBlockHeight(mip_level),
587 gl_buffer.data(), gl_buffer.size(), params.addr); 543 params.MipHeight(mip_level), params.MipBlockDepth(mip_level), depth, gl_buffer.data(),
544 gl_buffer.size(), params.addr + offset);
588 } 545 }
589} 546}
590 547
@@ -609,13 +566,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
609 566
610 if (src_params.type == SurfaceType::ColorTexture) { 567 if (src_params.type == SurfaceType::ColorTexture) {
611 switch (src_params.target) { 568 switch (src_params.target) {
612 case SurfaceParams::SurfaceTarget::Texture2D: 569 case SurfaceTarget::Texture2D:
613 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, 570 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
614 GL_TEXTURE_2D, src_surface->Texture().handle, 0); 571 GL_TEXTURE_2D, src_surface->Texture().handle, 0);
615 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 572 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
616 0, 0); 573 0, 0);
617 break; 574 break;
618 case SurfaceParams::SurfaceTarget::TextureCubemap: 575 case SurfaceTarget::TextureCubemap:
619 glFramebufferTexture2D( 576 glFramebufferTexture2D(
620 GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, 577 GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
621 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 578 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
@@ -624,12 +581,12 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
624 GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 581 GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
625 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0); 582 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
626 break; 583 break;
627 case SurfaceParams::SurfaceTarget::Texture2DArray: 584 case SurfaceTarget::Texture2DArray:
628 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, 585 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
629 src_surface->Texture().handle, 0, 0); 586 src_surface->Texture().handle, 0, 0);
630 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); 587 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
631 break; 588 break;
632 case SurfaceParams::SurfaceTarget::Texture3D: 589 case SurfaceTarget::Texture3D:
633 glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment, 590 glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
634 SurfaceTargetToGL(src_params.target), 591 SurfaceTargetToGL(src_params.target),
635 src_surface->Texture().handle, 0, 0); 592 src_surface->Texture().handle, 0, 0);
@@ -645,13 +602,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
645 } 602 }
646 603
647 switch (dst_params.target) { 604 switch (dst_params.target) {
648 case SurfaceParams::SurfaceTarget::Texture2D: 605 case SurfaceTarget::Texture2D:
649 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, 606 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
650 GL_TEXTURE_2D, dst_surface->Texture().handle, 0); 607 GL_TEXTURE_2D, dst_surface->Texture().handle, 0);
651 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 608 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
652 0, 0); 609 0, 0);
653 break; 610 break;
654 case SurfaceParams::SurfaceTarget::TextureCubemap: 611 case SurfaceTarget::TextureCubemap:
655 glFramebufferTexture2D( 612 glFramebufferTexture2D(
656 GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, 613 GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
657 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 614 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
@@ -660,13 +617,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
660 GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 617 GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
661 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0); 618 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
662 break; 619 break;
663 case SurfaceParams::SurfaceTarget::Texture2DArray: 620 case SurfaceTarget::Texture2DArray:
664 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, 621 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
665 dst_surface->Texture().handle, 0, 0); 622 dst_surface->Texture().handle, 0, 0);
666 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); 623 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
667 break; 624 break;
668 625
669 case SurfaceParams::SurfaceTarget::Texture3D: 626 case SurfaceTarget::Texture3D:
670 glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment, 627 glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
671 SurfaceTargetToGL(dst_params.target), 628 SurfaceTargetToGL(dst_params.target),
672 dst_surface->Texture().handle, 0, 0); 629 dst_surface->Texture().handle, 0, 0);
@@ -787,21 +744,21 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
787 UNREACHABLE(); 744 UNREACHABLE();
788 } else { 745 } else {
789 switch (dst_params.target) { 746 switch (dst_params.target) {
790 case SurfaceParams::SurfaceTarget::Texture1D: 747 case SurfaceTarget::Texture1D:
791 glTextureSubImage1D(dst_surface->Texture().handle, 0, 0, width, dest_format.format, 748 glTextureSubImage1D(dst_surface->Texture().handle, 0, 0, width, dest_format.format,
792 dest_format.type, nullptr); 749 dest_format.type, nullptr);
793 break; 750 break;
794 case SurfaceParams::SurfaceTarget::Texture2D: 751 case SurfaceTarget::Texture2D:
795 glTextureSubImage2D(dst_surface->Texture().handle, 0, 0, 0, width, height, 752 glTextureSubImage2D(dst_surface->Texture().handle, 0, 0, 0, width, height,
796 dest_format.format, dest_format.type, nullptr); 753 dest_format.format, dest_format.type, nullptr);
797 break; 754 break;
798 case SurfaceParams::SurfaceTarget::Texture3D: 755 case SurfaceTarget::Texture3D:
799 case SurfaceParams::SurfaceTarget::Texture2DArray: 756 case SurfaceTarget::Texture2DArray:
800 glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 0, width, height, 757 glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 0, width, height,
801 static_cast<GLsizei>(dst_params.depth), dest_format.format, 758 static_cast<GLsizei>(dst_params.depth), dest_format.format,
802 dest_format.type, nullptr); 759 dest_format.type, nullptr);
803 break; 760 break;
804 case SurfaceParams::SurfaceTarget::TextureCubemap: 761 case SurfaceTarget::TextureCubemap:
805 glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 762 glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0,
806 static_cast<GLint>(cubemap_face), width, height, 1, 763 static_cast<GLint>(cubemap_face), width, height, 1,
807 dest_format.format, dest_format.type, nullptr); 764 dest_format.format, dest_format.type, nullptr);
@@ -838,35 +795,42 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
838 if (!format_tuple.compressed) { 795 if (!format_tuple.compressed) {
839 // Only pre-create the texture for non-compressed textures. 796 // Only pre-create the texture for non-compressed textures.
840 switch (params.target) { 797 switch (params.target) {
841 case SurfaceParams::SurfaceTarget::Texture1D: 798 case SurfaceTarget::Texture1D:
842 glTexStorage1D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, 799 glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level,
843 rect.GetWidth()); 800 format_tuple.internal_format, rect.GetWidth());
844 break; 801 break;
845 case SurfaceParams::SurfaceTarget::Texture2D: 802 case SurfaceTarget::Texture2D:
846 case SurfaceParams::SurfaceTarget::TextureCubemap: 803 case SurfaceTarget::TextureCubemap:
847 glTexStorage2D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, 804 glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level,
848 rect.GetWidth(), rect.GetHeight()); 805 format_tuple.internal_format, rect.GetWidth(), rect.GetHeight());
849 break; 806 break;
850 case SurfaceParams::SurfaceTarget::Texture3D: 807 case SurfaceTarget::Texture3D:
851 case SurfaceParams::SurfaceTarget::Texture2DArray: 808 case SurfaceTarget::Texture2DArray:
852 glTexStorage3D(SurfaceTargetToGL(params.target), 1, format_tuple.internal_format, 809 glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level,
853 rect.GetWidth(), rect.GetHeight(), params.depth); 810 format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(),
811 params.depth);
854 break; 812 break;
855 default: 813 default:
856 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", 814 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
857 static_cast<u32>(params.target)); 815 static_cast<u32>(params.target));
858 UNREACHABLE(); 816 UNREACHABLE();
859 glTexStorage2D(GL_TEXTURE_2D, 1, format_tuple.internal_format, rect.GetWidth(), 817 glTexStorage2D(GL_TEXTURE_2D, params.max_mip_level, format_tuple.internal_format,
860 rect.GetHeight()); 818 rect.GetWidth(), rect.GetHeight());
861 } 819 }
862 } 820 }
863 821
864 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR); 822 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MIN_FILTER, GL_LINEAR);
823 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAG_FILTER, GL_LINEAR);
865 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 824 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
866 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 825 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
826 glTexParameteri(SurfaceTargetToGL(params.target), GL_TEXTURE_MAX_LEVEL,
827 params.max_mip_level - 1);
828 if (params.max_mip_level == 1) {
829 glTexParameterf(SurfaceTargetToGL(params.target), GL_TEXTURE_LOD_BIAS, 1000.0);
830 }
867 831
868 VideoCore::LabelGLObject(GL_TEXTURE, texture.handle, params.addr, 832 LabelGLObject(GL_TEXTURE, texture.handle, params.addr,
869 SurfaceParams::SurfaceTargetName(params.target)); 833 SurfaceParams::SurfaceTargetName(params.target));
870 834
871 // Clamp size to mapped GPU memory region 835 // Clamp size to mapped GPU memory region
872 // TODO(bunnei): Super Mario Odyssey maps a 0x40000 byte region and then uses it for a 0x80000 836 // TODO(bunnei): Super Mario Odyssey maps a 0x40000 byte region and then uses it for a 0x80000
@@ -896,7 +860,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height, bo
896 860
897 S8Z24 s8z24_pixel{}; 861 S8Z24 s8z24_pixel{};
898 Z24S8 z24s8_pixel{}; 862 Z24S8 z24s8_pixel{};
899 constexpr auto bpp{SurfaceParams::GetBytesPerPixel(PixelFormat::S8Z24)}; 863 constexpr auto bpp{GetBytesPerPixel(PixelFormat::S8Z24)};
900 for (std::size_t y = 0; y < height; ++y) { 864 for (std::size_t y = 0; y < height; ++y) {
901 for (std::size_t x = 0; x < width; ++x) { 865 for (std::size_t x = 0; x < width; ++x) {
902 const std::size_t offset{bpp * (y * width + x)}; 866 const std::size_t offset{bpp * (y * width + x)};
@@ -916,7 +880,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height, bo
916} 880}
917 881
918static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) { 882static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
919 constexpr auto bpp{SurfaceParams::GetBytesPerPixel(PixelFormat::G8R8U)}; 883 constexpr auto bpp{GetBytesPerPixel(PixelFormat::G8R8U)};
920 for (std::size_t y = 0; y < height; ++y) { 884 for (std::size_t y = 0; y < height; ++y) {
921 for (std::size_t x = 0; x < width; ++x) { 885 for (std::size_t x = 0; x < width; ++x) {
922 const std::size_t offset{bpp * (y * width + x)}; 886 const std::size_t offset{bpp * (y * width + x)};
@@ -992,20 +956,22 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm
992MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192)); 956MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192));
993void CachedSurface::LoadGLBuffer() { 957void CachedSurface::LoadGLBuffer() {
994 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); 958 MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
995 959 gl_buffer.resize(params.max_mip_level);
996 gl_buffer.resize(params.size_in_bytes_gl); 960 for (u32 i = 0; i < params.max_mip_level; i++)
961 gl_buffer[i].resize(params.GetMipmapSizeGL(i));
997 if (params.is_tiled) { 962 if (params.is_tiled) {
998 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", 963 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
999 params.block_width, static_cast<u32>(params.target)); 964 params.block_width, static_cast<u32>(params.target));
1000 965 for (u32 i = 0; i < params.max_mip_level; i++)
1001 SwizzleFunc(morton_to_gl_fns, params, gl_buffer); 966 SwizzleFunc(morton_to_gl_fns, params, gl_buffer[i], i);
1002 } else { 967 } else {
1003 const auto texture_src_data{Memory::GetPointer(params.addr)}; 968 const auto texture_src_data{Memory::GetPointer(params.addr)};
1004 const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl}; 969 const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl};
1005 gl_buffer.assign(texture_src_data, texture_src_data_end); 970 gl_buffer[0].assign(texture_src_data, texture_src_data_end);
1006 } 971 }
1007 972 for (u32 i = 0; i < params.max_mip_level; i++)
1008 ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer, params.pixel_format, params.width, params.height); 973 ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i),
974 params.MipHeight(i));
1009} 975}
1010 976
1011MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); 977MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
@@ -1015,18 +981,19 @@ void CachedSurface::FlushGLBuffer() {
1015 ASSERT_MSG(!IsPixelFormatASTC(params.pixel_format), "Unimplemented"); 981 ASSERT_MSG(!IsPixelFormatASTC(params.pixel_format), "Unimplemented");
1016 982
1017 // OpenGL temporary buffer needs to be big enough to store raw texture size 983 // OpenGL temporary buffer needs to be big enough to store raw texture size
1018 gl_buffer.resize(GetSizeInBytes()); 984 gl_buffer.resize(1);
985 gl_buffer[0].resize(GetSizeInBytes());
1019 986
1020 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); 987 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
1021 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT 988 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT
1022 ASSERT(params.width * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 0); 989 ASSERT(params.width * GetBytesPerPixel(params.pixel_format) % 4 == 0);
1023 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width)); 990 glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width));
1024 ASSERT(!tuple.compressed); 991 ASSERT(!tuple.compressed);
1025 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 992 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
1026 glGetTextureImage(texture.handle, 0, tuple.format, tuple.type, 993 glGetTextureImage(texture.handle, 0, tuple.format, tuple.type,
1027 static_cast<GLsizei>(gl_buffer.size()), gl_buffer.data()); 994 static_cast<GLsizei>(gl_buffer[0].size()), gl_buffer[0].data());
1028 glPixelStorei(GL_PACK_ROW_LENGTH, 0); 995 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
1029 ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer, params.pixel_format, params.width, 996 ConvertFormatAsNeeded_FlushGLBuffer(gl_buffer[0], params.pixel_format, params.width,
1030 params.height); 997 params.height);
1031 ASSERT(params.type != SurfaceType::Fill); 998 ASSERT(params.type != SurfaceType::Fill);
1032 const u8* const texture_src_data = Memory::GetPointer(params.addr); 999 const u8* const texture_src_data = Memory::GetPointer(params.addr);
@@ -1035,28 +1002,23 @@ void CachedSurface::FlushGLBuffer() {
1035 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", 1002 ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}",
1036 params.block_width, static_cast<u32>(params.target)); 1003 params.block_width, static_cast<u32>(params.target));
1037 1004
1038 SwizzleFunc(gl_to_morton_fns, params, gl_buffer); 1005 SwizzleFunc(gl_to_morton_fns, params, gl_buffer[0], 0);
1039 } else { 1006 } else {
1040 std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer.data(), GetSizeInBytes()); 1007 std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer[0].data(), GetSizeInBytes());
1041 } 1008 }
1042} 1009}
1043 1010
1044MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); 1011void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
1045void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) { 1012 GLuint draw_fb_handle) {
1046 if (params.type == SurfaceType::Fill) 1013 const auto& rect{params.GetRect(mip_map)};
1047 return;
1048
1049 MICROPROFILE_SCOPE(OpenGL_TextureUL);
1050
1051 const auto& rect{params.GetRect()};
1052 1014
1053 // Load data from memory to the surface 1015 // Load data from memory to the surface
1054 const GLint x0 = static_cast<GLint>(rect.left); 1016 const GLint x0 = static_cast<GLint>(rect.left);
1055 const GLint y0 = static_cast<GLint>(rect.bottom); 1017 const GLint y0 = static_cast<GLint>(rect.bottom);
1056 std::size_t buffer_offset = 1018 std::size_t buffer_offset =
1057 static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.width + 1019 static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) +
1058 static_cast<std::size_t>(x0)) * 1020 static_cast<std::size_t>(x0)) *
1059 SurfaceParams::GetBytesPerPixel(params.pixel_format); 1021 GetBytesPerPixel(params.pixel_format);
1060 1022
1061 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type); 1023 const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
1062 const GLuint target_tex = texture.handle; 1024 const GLuint target_tex = texture.handle;
@@ -1072,88 +1034,116 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
1072 cur_state.Apply(); 1034 cur_state.Apply();
1073 1035
1074 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT 1036 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT
1075 ASSERT(params.width * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 0); 1037 ASSERT(params.MipWidth(mip_map) * GetBytesPerPixel(params.pixel_format) % 4 == 0);
1076 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.width)); 1038 glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map)));
1077 1039
1040 GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false));
1078 glActiveTexture(GL_TEXTURE0); 1041 glActiveTexture(GL_TEXTURE0);
1079 if (tuple.compressed) { 1042 if (tuple.compressed) {
1080 switch (params.target) { 1043 switch (params.target) {
1081 case SurfaceParams::SurfaceTarget::Texture2D: 1044 case SurfaceTarget::Texture2D:
1082 glCompressedTexImage2D( 1045 glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
1083 SurfaceTargetToGL(params.target), 0, tuple.internal_format, 1046 static_cast<GLsizei>(params.MipWidth(mip_map)),
1084 static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 0, 1047 static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size,
1085 static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); 1048 &gl_buffer[mip_map][buffer_offset]);
1049 break;
1050 case SurfaceTarget::Texture3D:
1051 glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
1052 static_cast<GLsizei>(params.MipWidth(mip_map)),
1053 static_cast<GLsizei>(params.MipHeight(mip_map)),
1054 static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size,
1055 &gl_buffer[mip_map][buffer_offset]);
1086 break; 1056 break;
1087 case SurfaceParams::SurfaceTarget::Texture3D: 1057 case SurfaceTarget::Texture2DArray:
1088 case SurfaceParams::SurfaceTarget::Texture2DArray: 1058 glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
1089 glCompressedTexImage3D( 1059 static_cast<GLsizei>(params.MipWidth(mip_map)),
1090 SurfaceTargetToGL(params.target), 0, tuple.internal_format, 1060 static_cast<GLsizei>(params.MipHeight(mip_map)),
1091 static_cast<GLsizei>(params.width), static_cast<GLsizei>(params.height), 1061 static_cast<GLsizei>(params.depth), 0, image_size,
1092 static_cast<GLsizei>(params.depth), 0, 1062 &gl_buffer[mip_map][buffer_offset]);
1093 static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]);
1094 break; 1063 break;
1095 case SurfaceParams::SurfaceTarget::TextureCubemap: 1064 case SurfaceTarget::TextureCubemap: {
1065 GLsizei layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map));
1096 for (std::size_t face = 0; face < params.depth; ++face) { 1066 for (std::size_t face = 0; face < params.depth; ++face) {
1097 glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), 1067 glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face),
1098 0, tuple.internal_format, static_cast<GLsizei>(params.width), 1068 mip_map, tuple.internal_format,
1099 static_cast<GLsizei>(params.height), 0, 1069 static_cast<GLsizei>(params.MipWidth(mip_map)),
1100 static_cast<GLsizei>(params.SizeInBytesCubeFaceGL()), 1070 static_cast<GLsizei>(params.MipHeight(mip_map)), 0,
1101 &gl_buffer[buffer_offset]); 1071 layer_size, &gl_buffer[mip_map][buffer_offset]);
1102 buffer_offset += params.SizeInBytesCubeFace(); 1072 buffer_offset += layer_size;
1103 } 1073 }
1104 break; 1074 break;
1075 }
1105 default: 1076 default:
1106 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", 1077 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
1107 static_cast<u32>(params.target)); 1078 static_cast<u32>(params.target));
1108 UNREACHABLE(); 1079 UNREACHABLE();
1109 glCompressedTexImage2D( 1080 glCompressedTexImage2D(GL_TEXTURE_2D, mip_map, tuple.internal_format,
1110 GL_TEXTURE_2D, 0, tuple.internal_format, static_cast<GLsizei>(params.width), 1081 static_cast<GLsizei>(params.MipWidth(mip_map)),
1111 static_cast<GLsizei>(params.height), 0, 1082 static_cast<GLsizei>(params.MipHeight(mip_map)), 0,
1112 static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[buffer_offset]); 1083 static_cast<GLsizei>(params.size_in_bytes_gl),
1084 &gl_buffer[mip_map][buffer_offset]);
1113 } 1085 }
1114 } else { 1086 } else {
1115 1087
1116 switch (params.target) { 1088 switch (params.target) {
1117 case SurfaceParams::SurfaceTarget::Texture1D: 1089 case SurfaceTarget::Texture1D:
1118 glTexSubImage1D(SurfaceTargetToGL(params.target), 0, x0, 1090 glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0,
1119 static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type, 1091 static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type,
1120 &gl_buffer[buffer_offset]); 1092 &gl_buffer[mip_map][buffer_offset]);
1121 break; 1093 break;
1122 case SurfaceParams::SurfaceTarget::Texture2D: 1094 case SurfaceTarget::Texture2D:
1123 glTexSubImage2D(SurfaceTargetToGL(params.target), 0, x0, y0, 1095 glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0,
1124 static_cast<GLsizei>(rect.GetWidth()), 1096 static_cast<GLsizei>(rect.GetWidth()),
1125 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, 1097 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
1126 &gl_buffer[buffer_offset]); 1098 &gl_buffer[mip_map][buffer_offset]);
1127 break; 1099 break;
1128 case SurfaceParams::SurfaceTarget::Texture3D: 1100 case SurfaceTarget::Texture3D:
1129 case SurfaceParams::SurfaceTarget::Texture2DArray: 1101 glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
1130 glTexSubImage3D(SurfaceTargetToGL(params.target), 0, x0, y0, 0, 1102 static_cast<GLsizei>(rect.GetWidth()),
1103 static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map),
1104 tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
1105 break;
1106 case SurfaceTarget::Texture2DArray:
1107 glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
1131 static_cast<GLsizei>(rect.GetWidth()), 1108 static_cast<GLsizei>(rect.GetWidth()),
1132 static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format, 1109 static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
1133 tuple.type, &gl_buffer[buffer_offset]); 1110 tuple.type, &gl_buffer[mip_map][buffer_offset]);
1134 break; 1111 break;
1135 case SurfaceParams::SurfaceTarget::TextureCubemap: 1112 case SurfaceTarget::TextureCubemap: {
1113 std::size_t start = buffer_offset;
1136 for (std::size_t face = 0; face < params.depth; ++face) { 1114 for (std::size_t face = 0; face < params.depth; ++face) {
1137 glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), 0, x0, 1115 glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map,
1138 y0, static_cast<GLsizei>(rect.GetWidth()), 1116 x0, y0, static_cast<GLsizei>(rect.GetWidth()),
1139 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, 1117 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
1140 &gl_buffer[buffer_offset]); 1118 &gl_buffer[mip_map][buffer_offset]);
1141 buffer_offset += params.SizeInBytesCubeFace(); 1119 buffer_offset += params.LayerSizeGL(mip_map);
1142 } 1120 }
1143 break; 1121 break;
1122 }
1144 default: 1123 default:
1145 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", 1124 LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
1146 static_cast<u32>(params.target)); 1125 static_cast<u32>(params.target));
1147 UNREACHABLE(); 1126 UNREACHABLE();
1148 glTexSubImage2D(GL_TEXTURE_2D, 0, x0, y0, static_cast<GLsizei>(rect.GetWidth()), 1127 glTexSubImage2D(GL_TEXTURE_2D, mip_map, x0, y0, static_cast<GLsizei>(rect.GetWidth()),
1149 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type, 1128 static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
1150 &gl_buffer[buffer_offset]); 1129 &gl_buffer[mip_map][buffer_offset]);
1151 } 1130 }
1152 } 1131 }
1153 1132
1154 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 1133 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1155} 1134}
1156 1135
1136MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192));
1137void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) {
1138 if (params.type == SurfaceType::Fill)
1139 return;
1140
1141 MICROPROFILE_SCOPE(OpenGL_TextureUL);
1142
1143 for (u32 i = 0; i < params.max_mip_level; i++)
1144 UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle);
1145}
1146
1157RasterizerCacheOpenGL::RasterizerCacheOpenGL() { 1147RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
1158 read_framebuffer.Create(); 1148 read_framebuffer.Create();
1159 draw_framebuffer.Create(); 1149 draw_framebuffer.Create();
@@ -1294,8 +1284,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
1294 // For compatible surfaces, we can just do fast glCopyImageSubData based copy 1284 // For compatible surfaces, we can just do fast glCopyImageSubData based copy
1295 if (old_params.target == new_params.target && old_params.type == new_params.type && 1285 if (old_params.target == new_params.target && old_params.type == new_params.type &&
1296 old_params.depth == new_params.depth && old_params.depth == 1 && 1286 old_params.depth == new_params.depth && old_params.depth == 1 &&
1297 SurfaceParams::GetFormatBpp(old_params.pixel_format) == 1287 GetFormatBpp(old_params.pixel_format) == GetFormatBpp(new_params.pixel_format)) {
1298 SurfaceParams::GetFormatBpp(new_params.pixel_format)) {
1299 FastCopySurface(old_surface, new_surface); 1288 FastCopySurface(old_surface, new_surface);
1300 return new_surface; 1289 return new_surface;
1301 } 1290 }
@@ -1308,15 +1297,15 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
1308 const bool is_blit{old_params.pixel_format == new_params.pixel_format}; 1297 const bool is_blit{old_params.pixel_format == new_params.pixel_format};
1309 1298
1310 switch (new_params.target) { 1299 switch (new_params.target) {
1311 case SurfaceParams::SurfaceTarget::Texture2D: 1300 case SurfaceTarget::Texture2D:
1312 if (is_blit) { 1301 if (is_blit) {
1313 BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle); 1302 BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle);
1314 } else { 1303 } else {
1315 CopySurface(old_surface, new_surface, copy_pbo.handle); 1304 CopySurface(old_surface, new_surface, copy_pbo.handle);
1316 } 1305 }
1317 break; 1306 break;
1318 case SurfaceParams::SurfaceTarget::TextureCubemap: 1307 case SurfaceTarget::TextureCubemap:
1319 case SurfaceParams::SurfaceTarget::Texture3D: 1308 case SurfaceTarget::Texture3D:
1320 AccurateCopySurface(old_surface, new_surface); 1309 AccurateCopySurface(old_surface, new_surface);
1321 break; 1310 break;
1322 default: 1311 default:
@@ -1326,7 +1315,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
1326 } 1315 }
1327 1316
1328 return new_surface; 1317 return new_surface;
1329} // namespace OpenGL 1318}
1330 1319
1331Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr addr) const { 1320Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr addr) const {
1332 return TryGet(addr); 1321 return TryGet(addr);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index be8c00e99..f255f4419 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -7,6 +7,7 @@
7#include <array> 7#include <array>
8#include <map> 8#include <map>
9#include <memory> 9#include <memory>
10#include <string>
10#include <vector> 11#include <vector>
11 12
12#include "common/alignment.h" 13#include "common/alignment.h"
@@ -18,6 +19,7 @@
18#include "video_core/rasterizer_cache.h" 19#include "video_core/rasterizer_cache.h"
19#include "video_core/renderer_opengl/gl_resource_manager.h" 20#include "video_core/renderer_opengl/gl_resource_manager.h"
20#include "video_core/renderer_opengl/gl_shader_gen.h" 21#include "video_core/renderer_opengl/gl_shader_gen.h"
22#include "video_core/surface.h"
21#include "video_core/textures/decoders.h" 23#include "video_core/textures/decoders.h"
22#include "video_core/textures/texture.h" 24#include "video_core/textures/texture.h"
23 25
@@ -27,135 +29,12 @@ class CachedSurface;
27using Surface = std::shared_ptr<CachedSurface>; 29using Surface = std::shared_ptr<CachedSurface>;
28using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>; 30using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>;
29 31
30struct SurfaceParams { 32using SurfaceTarget = VideoCore::Surface::SurfaceTarget;
31 enum class PixelFormat { 33using SurfaceType = VideoCore::Surface::SurfaceType;
32 ABGR8U = 0, 34using PixelFormat = VideoCore::Surface::PixelFormat;
33 ABGR8S = 1, 35using ComponentType = VideoCore::Surface::ComponentType;
34 ABGR8UI = 2,
35 B5G6R5U = 3,
36 A2B10G10R10U = 4,
37 A1B5G5R5U = 5,
38 R8U = 6,
39 R8UI = 7,
40 RGBA16F = 8,
41 RGBA16U = 9,
42 RGBA16UI = 10,
43 R11FG11FB10F = 11,
44 RGBA32UI = 12,
45 DXT1 = 13,
46 DXT23 = 14,
47 DXT45 = 15,
48 DXN1 = 16, // This is also known as BC4
49 DXN2UNORM = 17,
50 DXN2SNORM = 18,
51 BC7U = 19,
52 BC6H_UF16 = 20,
53 BC6H_SF16 = 21,
54 ASTC_2D_4X4 = 22,
55 G8R8U = 23,
56 G8R8S = 24,
57 BGRA8 = 25,
58 RGBA32F = 26,
59 RG32F = 27,
60 R32F = 28,
61 R16F = 29,
62 R16U = 30,
63 R16S = 31,
64 R16UI = 32,
65 R16I = 33,
66 RG16 = 34,
67 RG16F = 35,
68 RG16UI = 36,
69 RG16I = 37,
70 RG16S = 38,
71 RGB32F = 39,
72 RGBA8_SRGB = 40,
73 RG8U = 41,
74 RG8S = 42,
75 RG32UI = 43,
76 R32UI = 44,
77 ASTC_2D_8X8 = 45,
78 ASTC_2D_8X5 = 46,
79 ASTC_2D_5X4 = 47,
80 BGRA8_SRGB = 48,
81 DXT1_SRGB = 49,
82 DXT23_SRGB = 50,
83 DXT45_SRGB = 51,
84 BC7U_SRGB = 52,
85 ASTC_2D_4X4_SRGB = 53,
86 ASTC_2D_8X8_SRGB = 54,
87 ASTC_2D_8X5_SRGB = 55,
88 ASTC_2D_5X4_SRGB = 56,
89
90 MaxColorFormat,
91
92 // Depth formats
93 Z32F = 57,
94 Z16 = 58,
95
96 MaxDepthFormat,
97
98 // DepthStencil formats
99 Z24S8 = 59,
100 S8Z24 = 60,
101 Z32FS8 = 61,
102
103 MaxDepthStencilFormat,
104
105 Max = MaxDepthStencilFormat,
106 Invalid = 255,
107 };
108
109 static constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max);
110
111 enum class ComponentType {
112 Invalid = 0,
113 SNorm = 1,
114 UNorm = 2,
115 SInt = 3,
116 UInt = 4,
117 Float = 5,
118 };
119
120 enum class SurfaceType {
121 ColorTexture = 0,
122 Depth = 1,
123 DepthStencil = 2,
124 Fill = 3,
125 Invalid = 4,
126 };
127
128 enum class SurfaceTarget {
129 Texture1D,
130 Texture2D,
131 Texture3D,
132 Texture1DArray,
133 Texture2DArray,
134 TextureCubemap,
135 };
136
137 static SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) {
138 switch (texture_type) {
139 case Tegra::Texture::TextureType::Texture1D:
140 return SurfaceTarget::Texture1D;
141 case Tegra::Texture::TextureType::Texture2D:
142 case Tegra::Texture::TextureType::Texture2DNoMipmap:
143 return SurfaceTarget::Texture2D;
144 case Tegra::Texture::TextureType::Texture3D:
145 return SurfaceTarget::Texture3D;
146 case Tegra::Texture::TextureType::TextureCubemap:
147 return SurfaceTarget::TextureCubemap;
148 case Tegra::Texture::TextureType::Texture1DArray:
149 return SurfaceTarget::Texture1DArray;
150 case Tegra::Texture::TextureType::Texture2DArray:
151 return SurfaceTarget::Texture2DArray;
152 default:
153 LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type));
154 UNREACHABLE();
155 return SurfaceTarget::Texture2D;
156 }
157 }
158 36
37struct SurfaceParams {
159 static std::string SurfaceTargetName(SurfaceTarget target) { 38 static std::string SurfaceTargetName(SurfaceTarget target) {
160 switch (target) { 39 switch (target) {
161 case SurfaceTarget::Texture1D: 40 case SurfaceTarget::Texture1D:
@@ -177,664 +56,12 @@ struct SurfaceParams {
177 } 56 }
178 } 57 }
179 58
180 static bool SurfaceTargetIsLayered(SurfaceTarget target) {
181 switch (target) {
182 case SurfaceTarget::Texture1D:
183 case SurfaceTarget::Texture2D:
184 case SurfaceTarget::Texture3D:
185 return false;
186 case SurfaceTarget::Texture1DArray:
187 case SurfaceTarget::Texture2DArray:
188 case SurfaceTarget::TextureCubemap:
189 return true;
190 default:
191 LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
192 UNREACHABLE();
193 return false;
194 }
195 }
196
197 /**
198 * Gets the compression factor for the specified PixelFormat. This applies to just the
199 * "compressed width" and "compressed height", not the overall compression factor of a
200 * compressed image. This is used for maintaining proper surface sizes for compressed
201 * texture formats.
202 */
203 static constexpr u32 GetCompressionFactor(PixelFormat format) {
204 if (format == PixelFormat::Invalid)
205 return 0;
206
207 constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
208 1, // ABGR8U
209 1, // ABGR8S
210 1, // ABGR8UI
211 1, // B5G6R5U
212 1, // A2B10G10R10U
213 1, // A1B5G5R5U
214 1, // R8U
215 1, // R8UI
216 1, // RGBA16F
217 1, // RGBA16U
218 1, // RGBA16UI
219 1, // R11FG11FB10F
220 1, // RGBA32UI
221 4, // DXT1
222 4, // DXT23
223 4, // DXT45
224 4, // DXN1
225 4, // DXN2UNORM
226 4, // DXN2SNORM
227 4, // BC7U
228 4, // BC6H_UF16
229 4, // BC6H_SF16
230 4, // ASTC_2D_4X4
231 1, // G8R8U
232 1, // G8R8S
233 1, // BGRA8
234 1, // RGBA32F
235 1, // RG32F
236 1, // R32F
237 1, // R16F
238 1, // R16U
239 1, // R16S
240 1, // R16UI
241 1, // R16I
242 1, // RG16
243 1, // RG16F
244 1, // RG16UI
245 1, // RG16I
246 1, // RG16S
247 1, // RGB32F
248 1, // RGBA8_SRGB
249 1, // RG8U
250 1, // RG8S
251 1, // RG32UI
252 1, // R32UI
253 4, // ASTC_2D_8X8
254 4, // ASTC_2D_8X5
255 4, // ASTC_2D_5X4
256 1, // BGRA8_SRGB
257 4, // DXT1_SRGB
258 4, // DXT23_SRGB
259 4, // DXT45_SRGB
260 4, // BC7U_SRGB
261 4, // ASTC_2D_4X4_SRGB
262 4, // ASTC_2D_8X8_SRGB
263 4, // ASTC_2D_8X5_SRGB
264 4, // ASTC_2D_5X4_SRGB
265 1, // Z32F
266 1, // Z16
267 1, // Z24S8
268 1, // S8Z24
269 1, // Z32FS8
270 }};
271
272 ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
273 return compression_factor_table[static_cast<std::size_t>(format)];
274 }
275
276 static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
277 if (format == PixelFormat::Invalid)
278 return 0;
279 constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
280 1, // ABGR8U
281 1, // ABGR8S
282 1, // ABGR8UI
283 1, // B5G6R5U
284 1, // A2B10G10R10U
285 1, // A1B5G5R5U
286 1, // R8U
287 1, // R8UI
288 1, // RGBA16F
289 1, // RGBA16U
290 1, // RGBA16UI
291 1, // R11FG11FB10F
292 1, // RGBA32UI
293 4, // DXT1
294 4, // DXT23
295 4, // DXT45
296 4, // DXN1
297 4, // DXN2UNORM
298 4, // DXN2SNORM
299 4, // BC7U
300 4, // BC6H_UF16
301 4, // BC6H_SF16
302 4, // ASTC_2D_4X4
303 1, // G8R8U
304 1, // G8R8S
305 1, // BGRA8
306 1, // RGBA32F
307 1, // RG32F
308 1, // R32F
309 1, // R16F
310 1, // R16U
311 1, // R16S
312 1, // R16UI
313 1, // R16I
314 1, // RG16
315 1, // RG16F
316 1, // RG16UI
317 1, // RG16I
318 1, // RG16S
319 1, // RGB32F
320 1, // RGBA8_SRGB
321 1, // RG8U
322 1, // RG8S
323 1, // RG32UI
324 1, // R32UI
325 8, // ASTC_2D_8X8
326 5, // ASTC_2D_8X5
327 4, // ASTC_2D_5X4
328 1, // BGRA8_SRGB
329 4, // DXT1_SRGB
330 4, // DXT23_SRGB
331 4, // DXT45_SRGB
332 4, // BC7U_SRGB
333 4, // ASTC_2D_4X4_SRGB
334 8, // ASTC_2D_8X8_SRGB
335 5, // ASTC_2D_8X5_SRGB
336 4, // ASTC_2D_5X4_SRGB
337 1, // Z32F
338 1, // Z16
339 1, // Z24S8
340 1, // S8Z24
341 1, // Z32FS8
342 }};
343 ASSERT(static_cast<std::size_t>(format) < block_height_table.size());
344 return block_height_table[static_cast<std::size_t>(format)];
345 }
346
347 static constexpr u32 GetFormatBpp(PixelFormat format) {
348 if (format == PixelFormat::Invalid)
349 return 0;
350
351 constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
352 32, // ABGR8U
353 32, // ABGR8S
354 32, // ABGR8UI
355 16, // B5G6R5U
356 32, // A2B10G10R10U
357 16, // A1B5G5R5U
358 8, // R8U
359 8, // R8UI
360 64, // RGBA16F
361 64, // RGBA16U
362 64, // RGBA16UI
363 32, // R11FG11FB10F
364 128, // RGBA32UI
365 64, // DXT1
366 128, // DXT23
367 128, // DXT45
368 64, // DXN1
369 128, // DXN2UNORM
370 128, // DXN2SNORM
371 128, // BC7U
372 128, // BC6H_UF16
373 128, // BC6H_SF16
374 32, // ASTC_2D_4X4
375 16, // G8R8U
376 16, // G8R8S
377 32, // BGRA8
378 128, // RGBA32F
379 64, // RG32F
380 32, // R32F
381 16, // R16F
382 16, // R16U
383 16, // R16S
384 16, // R16UI
385 16, // R16I
386 32, // RG16
387 32, // RG16F
388 32, // RG16UI
389 32, // RG16I
390 32, // RG16S
391 96, // RGB32F
392 32, // RGBA8_SRGB
393 16, // RG8U
394 16, // RG8S
395 64, // RG32UI
396 32, // R32UI
397 16, // ASTC_2D_8X8
398 16, // ASTC_2D_8X5
399 32, // ASTC_2D_5X4
400 32, // BGRA8_SRGB
401 64, // DXT1_SRGB
402 128, // DXT23_SRGB
403 128, // DXT45_SRGB
404 128, // BC7U
405 32, // ASTC_2D_4X4_SRGB
406 16, // ASTC_2D_8X8_SRGB
407 32, // ASTC_2D_8X5_SRGB
408 32, // ASTC_2D_5X4_SRGB
409 32, // Z32F
410 16, // Z16
411 32, // Z24S8
412 32, // S8Z24
413 64, // Z32FS8
414 }};
415
416 ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
417 return bpp_table[static_cast<std::size_t>(format)];
418 }
419
420 u32 GetFormatBpp() const { 59 u32 GetFormatBpp() const {
421 return GetFormatBpp(pixel_format); 60 return VideoCore::Surface::GetFormatBpp(pixel_format);
422 }
423
424 static PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
425 switch (format) {
426 case Tegra::DepthFormat::S8_Z24_UNORM:
427 return PixelFormat::S8Z24;
428 case Tegra::DepthFormat::Z24_S8_UNORM:
429 return PixelFormat::Z24S8;
430 case Tegra::DepthFormat::Z32_FLOAT:
431 return PixelFormat::Z32F;
432 case Tegra::DepthFormat::Z16_UNORM:
433 return PixelFormat::Z16;
434 case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
435 return PixelFormat::Z32FS8;
436 default:
437 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
438 UNREACHABLE();
439 }
440 }
441
442 static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
443 switch (format) {
444 // TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the
445 // gamma.
446 case Tegra::RenderTargetFormat::RGBA8_SRGB:
447 return PixelFormat::RGBA8_SRGB;
448 case Tegra::RenderTargetFormat::RGBA8_UNORM:
449 return PixelFormat::ABGR8U;
450 case Tegra::RenderTargetFormat::RGBA8_SNORM:
451 return PixelFormat::ABGR8S;
452 case Tegra::RenderTargetFormat::RGBA8_UINT:
453 return PixelFormat::ABGR8UI;
454 case Tegra::RenderTargetFormat::BGRA8_SRGB:
455 return PixelFormat::BGRA8_SRGB;
456 case Tegra::RenderTargetFormat::BGRA8_UNORM:
457 return PixelFormat::BGRA8;
458 case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
459 return PixelFormat::A2B10G10R10U;
460 case Tegra::RenderTargetFormat::RGBA16_FLOAT:
461 return PixelFormat::RGBA16F;
462 case Tegra::RenderTargetFormat::RGBA16_UNORM:
463 return PixelFormat::RGBA16U;
464 case Tegra::RenderTargetFormat::RGBA16_UINT:
465 return PixelFormat::RGBA16UI;
466 case Tegra::RenderTargetFormat::RGBA32_FLOAT:
467 return PixelFormat::RGBA32F;
468 case Tegra::RenderTargetFormat::RG32_FLOAT:
469 return PixelFormat::RG32F;
470 case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
471 return PixelFormat::R11FG11FB10F;
472 case Tegra::RenderTargetFormat::B5G6R5_UNORM:
473 return PixelFormat::B5G6R5U;
474 case Tegra::RenderTargetFormat::BGR5A1_UNORM:
475 return PixelFormat::A1B5G5R5U;
476 case Tegra::RenderTargetFormat::RGBA32_UINT:
477 return PixelFormat::RGBA32UI;
478 case Tegra::RenderTargetFormat::R8_UNORM:
479 return PixelFormat::R8U;
480 case Tegra::RenderTargetFormat::R8_UINT:
481 return PixelFormat::R8UI;
482 case Tegra::RenderTargetFormat::RG16_FLOAT:
483 return PixelFormat::RG16F;
484 case Tegra::RenderTargetFormat::RG16_UINT:
485 return PixelFormat::RG16UI;
486 case Tegra::RenderTargetFormat::RG16_SINT:
487 return PixelFormat::RG16I;
488 case Tegra::RenderTargetFormat::RG16_UNORM:
489 return PixelFormat::RG16;
490 case Tegra::RenderTargetFormat::RG16_SNORM:
491 return PixelFormat::RG16S;
492 case Tegra::RenderTargetFormat::RG8_UNORM:
493 return PixelFormat::RG8U;
494 case Tegra::RenderTargetFormat::RG8_SNORM:
495 return PixelFormat::RG8S;
496 case Tegra::RenderTargetFormat::R16_FLOAT:
497 return PixelFormat::R16F;
498 case Tegra::RenderTargetFormat::R16_UNORM:
499 return PixelFormat::R16U;
500 case Tegra::RenderTargetFormat::R16_SNORM:
501 return PixelFormat::R16S;
502 case Tegra::RenderTargetFormat::R16_UINT:
503 return PixelFormat::R16UI;
504 case Tegra::RenderTargetFormat::R16_SINT:
505 return PixelFormat::R16I;
506 case Tegra::RenderTargetFormat::R32_FLOAT:
507 return PixelFormat::R32F;
508 case Tegra::RenderTargetFormat::R32_UINT:
509 return PixelFormat::R32UI;
510 case Tegra::RenderTargetFormat::RG32_UINT:
511 return PixelFormat::RG32UI;
512 default:
513 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
514 UNREACHABLE();
515 }
516 }
517
518 static PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
519 Tegra::Texture::ComponentType component_type,
520 bool is_srgb) {
521 // TODO(Subv): Properly implement this
522 switch (format) {
523 case Tegra::Texture::TextureFormat::A8R8G8B8:
524 if (is_srgb) {
525 return PixelFormat::RGBA8_SRGB;
526 }
527 switch (component_type) {
528 case Tegra::Texture::ComponentType::UNORM:
529 return PixelFormat::ABGR8U;
530 case Tegra::Texture::ComponentType::SNORM:
531 return PixelFormat::ABGR8S;
532 case Tegra::Texture::ComponentType::UINT:
533 return PixelFormat::ABGR8UI;
534 }
535 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
536 static_cast<u32>(component_type));
537 UNREACHABLE();
538 case Tegra::Texture::TextureFormat::B5G6R5:
539 switch (component_type) {
540 case Tegra::Texture::ComponentType::UNORM:
541 return PixelFormat::B5G6R5U;
542 }
543 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
544 static_cast<u32>(component_type));
545 UNREACHABLE();
546 case Tegra::Texture::TextureFormat::A2B10G10R10:
547 switch (component_type) {
548 case Tegra::Texture::ComponentType::UNORM:
549 return PixelFormat::A2B10G10R10U;
550 }
551 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
552 static_cast<u32>(component_type));
553 UNREACHABLE();
554 case Tegra::Texture::TextureFormat::A1B5G5R5:
555 switch (component_type) {
556 case Tegra::Texture::ComponentType::UNORM:
557 return PixelFormat::A1B5G5R5U;
558 }
559 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
560 static_cast<u32>(component_type));
561 UNREACHABLE();
562 case Tegra::Texture::TextureFormat::R8:
563 switch (component_type) {
564 case Tegra::Texture::ComponentType::UNORM:
565 return PixelFormat::R8U;
566 case Tegra::Texture::ComponentType::UINT:
567 return PixelFormat::R8UI;
568 }
569 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
570 static_cast<u32>(component_type));
571 UNREACHABLE();
572 case Tegra::Texture::TextureFormat::G8R8:
573 switch (component_type) {
574 case Tegra::Texture::ComponentType::UNORM:
575 return PixelFormat::G8R8U;
576 case Tegra::Texture::ComponentType::SNORM:
577 return PixelFormat::G8R8S;
578 }
579 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
580 static_cast<u32>(component_type));
581 UNREACHABLE();
582 case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
583 switch (component_type) {
584 case Tegra::Texture::ComponentType::UNORM:
585 return PixelFormat::RGBA16U;
586 case Tegra::Texture::ComponentType::FLOAT:
587 return PixelFormat::RGBA16F;
588 }
589 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
590 static_cast<u32>(component_type));
591 UNREACHABLE();
592 case Tegra::Texture::TextureFormat::BF10GF11RF11:
593 switch (component_type) {
594 case Tegra::Texture::ComponentType::FLOAT:
595 return PixelFormat::R11FG11FB10F;
596 }
597 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
598 static_cast<u32>(component_type));
599 UNREACHABLE();
600 case Tegra::Texture::TextureFormat::R32_G32_B32_A32:
601 switch (component_type) {
602 case Tegra::Texture::ComponentType::FLOAT:
603 return PixelFormat::RGBA32F;
604 case Tegra::Texture::ComponentType::UINT:
605 return PixelFormat::RGBA32UI;
606 }
607 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
608 static_cast<u32>(component_type));
609 UNREACHABLE();
610 case Tegra::Texture::TextureFormat::R32_G32:
611 switch (component_type) {
612 case Tegra::Texture::ComponentType::FLOAT:
613 return PixelFormat::RG32F;
614 case Tegra::Texture::ComponentType::UINT:
615 return PixelFormat::RG32UI;
616 }
617 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
618 static_cast<u32>(component_type));
619 UNREACHABLE();
620 case Tegra::Texture::TextureFormat::R32_G32_B32:
621 switch (component_type) {
622 case Tegra::Texture::ComponentType::FLOAT:
623 return PixelFormat::RGB32F;
624 }
625 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
626 static_cast<u32>(component_type));
627 UNREACHABLE();
628 case Tegra::Texture::TextureFormat::R16:
629 switch (component_type) {
630 case Tegra::Texture::ComponentType::FLOAT:
631 return PixelFormat::R16F;
632 case Tegra::Texture::ComponentType::UNORM:
633 return PixelFormat::R16U;
634 case Tegra::Texture::ComponentType::SNORM:
635 return PixelFormat::R16S;
636 case Tegra::Texture::ComponentType::UINT:
637 return PixelFormat::R16UI;
638 case Tegra::Texture::ComponentType::SINT:
639 return PixelFormat::R16I;
640 }
641 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
642 static_cast<u32>(component_type));
643 UNREACHABLE();
644 case Tegra::Texture::TextureFormat::R32:
645 switch (component_type) {
646 case Tegra::Texture::ComponentType::FLOAT:
647 return PixelFormat::R32F;
648 case Tegra::Texture::ComponentType::UINT:
649 return PixelFormat::R32UI;
650 }
651 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
652 static_cast<u32>(component_type));
653 UNREACHABLE();
654 case Tegra::Texture::TextureFormat::ZF32:
655 return PixelFormat::Z32F;
656 case Tegra::Texture::TextureFormat::Z16:
657 return PixelFormat::Z16;
658 case Tegra::Texture::TextureFormat::Z24S8:
659 return PixelFormat::Z24S8;
660 case Tegra::Texture::TextureFormat::DXT1:
661 return is_srgb ? PixelFormat::DXT1_SRGB : PixelFormat::DXT1;
662 case Tegra::Texture::TextureFormat::DXT23:
663 return is_srgb ? PixelFormat::DXT23_SRGB : PixelFormat::DXT23;
664 case Tegra::Texture::TextureFormat::DXT45:
665 return is_srgb ? PixelFormat::DXT45_SRGB : PixelFormat::DXT45;
666 case Tegra::Texture::TextureFormat::DXN1:
667 return PixelFormat::DXN1;
668 case Tegra::Texture::TextureFormat::DXN2:
669 switch (component_type) {
670 case Tegra::Texture::ComponentType::UNORM:
671 return PixelFormat::DXN2UNORM;
672 case Tegra::Texture::ComponentType::SNORM:
673 return PixelFormat::DXN2SNORM;
674 }
675 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
676 static_cast<u32>(component_type));
677 UNREACHABLE();
678 case Tegra::Texture::TextureFormat::BC7U:
679 return is_srgb ? PixelFormat::BC7U_SRGB : PixelFormat::BC7U;
680 case Tegra::Texture::TextureFormat::BC6H_UF16:
681 return PixelFormat::BC6H_UF16;
682 case Tegra::Texture::TextureFormat::BC6H_SF16:
683 return PixelFormat::BC6H_SF16;
684 case Tegra::Texture::TextureFormat::ASTC_2D_4X4:
685 return is_srgb ? PixelFormat::ASTC_2D_4X4_SRGB : PixelFormat::ASTC_2D_4X4;
686 case Tegra::Texture::TextureFormat::ASTC_2D_5X4:
687 return is_srgb ? PixelFormat::ASTC_2D_5X4_SRGB : PixelFormat::ASTC_2D_5X4;
688 case Tegra::Texture::TextureFormat::ASTC_2D_8X8:
689 return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8;
690 case Tegra::Texture::TextureFormat::ASTC_2D_8X5:
691 return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5;
692 case Tegra::Texture::TextureFormat::R16_G16:
693 switch (component_type) {
694 case Tegra::Texture::ComponentType::FLOAT:
695 return PixelFormat::RG16F;
696 case Tegra::Texture::ComponentType::UNORM:
697 return PixelFormat::RG16;
698 case Tegra::Texture::ComponentType::SNORM:
699 return PixelFormat::RG16S;
700 case Tegra::Texture::ComponentType::UINT:
701 return PixelFormat::RG16UI;
702 case Tegra::Texture::ComponentType::SINT:
703 return PixelFormat::RG16I;
704 }
705 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
706 static_cast<u32>(component_type));
707 UNREACHABLE();
708 default:
709 LOG_CRITICAL(HW_GPU, "Unimplemented format={}, component_type={}",
710 static_cast<u32>(format), static_cast<u32>(component_type));
711 UNREACHABLE();
712 }
713 }
714
715 static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
716 // TODO(Subv): Implement more component types
717 switch (type) {
718 case Tegra::Texture::ComponentType::UNORM:
719 return ComponentType::UNorm;
720 case Tegra::Texture::ComponentType::FLOAT:
721 return ComponentType::Float;
722 case Tegra::Texture::ComponentType::SNORM:
723 return ComponentType::SNorm;
724 case Tegra::Texture::ComponentType::UINT:
725 return ComponentType::UInt;
726 case Tegra::Texture::ComponentType::SINT:
727 return ComponentType::SInt;
728 default:
729 LOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type));
730 UNREACHABLE();
731 }
732 }
733
734 static ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) {
735 // TODO(Subv): Implement more render targets
736 switch (format) {
737 case Tegra::RenderTargetFormat::RGBA8_UNORM:
738 case Tegra::RenderTargetFormat::RGBA8_SRGB:
739 case Tegra::RenderTargetFormat::BGRA8_UNORM:
740 case Tegra::RenderTargetFormat::BGRA8_SRGB:
741 case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
742 case Tegra::RenderTargetFormat::R8_UNORM:
743 case Tegra::RenderTargetFormat::RG16_UNORM:
744 case Tegra::RenderTargetFormat::R16_UNORM:
745 case Tegra::RenderTargetFormat::B5G6R5_UNORM:
746 case Tegra::RenderTargetFormat::BGR5A1_UNORM:
747 case Tegra::RenderTargetFormat::RG8_UNORM:
748 case Tegra::RenderTargetFormat::RGBA16_UNORM:
749 return ComponentType::UNorm;
750 case Tegra::RenderTargetFormat::RGBA8_SNORM:
751 case Tegra::RenderTargetFormat::RG16_SNORM:
752 case Tegra::RenderTargetFormat::R16_SNORM:
753 case Tegra::RenderTargetFormat::RG8_SNORM:
754 return ComponentType::SNorm;
755 case Tegra::RenderTargetFormat::RGBA16_FLOAT:
756 case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
757 case Tegra::RenderTargetFormat::RGBA32_FLOAT:
758 case Tegra::RenderTargetFormat::RG32_FLOAT:
759 case Tegra::RenderTargetFormat::RG16_FLOAT:
760 case Tegra::RenderTargetFormat::R16_FLOAT:
761 case Tegra::RenderTargetFormat::R32_FLOAT:
762 return ComponentType::Float;
763 case Tegra::RenderTargetFormat::RGBA32_UINT:
764 case Tegra::RenderTargetFormat::RGBA16_UINT:
765 case Tegra::RenderTargetFormat::RG16_UINT:
766 case Tegra::RenderTargetFormat::R8_UINT:
767 case Tegra::RenderTargetFormat::R16_UINT:
768 case Tegra::RenderTargetFormat::RG32_UINT:
769 case Tegra::RenderTargetFormat::R32_UINT:
770 case Tegra::RenderTargetFormat::RGBA8_UINT:
771 return ComponentType::UInt;
772 case Tegra::RenderTargetFormat::RG16_SINT:
773 case Tegra::RenderTargetFormat::R16_SINT:
774 return ComponentType::SInt;
775 default:
776 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
777 UNREACHABLE();
778 }
779 }
780
781 static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
782 switch (format) {
783 case Tegra::FramebufferConfig::PixelFormat::ABGR8:
784 return PixelFormat::ABGR8U;
785 default:
786 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
787 UNREACHABLE();
788 }
789 }
790
791 static ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format) {
792 switch (format) {
793 case Tegra::DepthFormat::Z16_UNORM:
794 case Tegra::DepthFormat::S8_Z24_UNORM:
795 case Tegra::DepthFormat::Z24_S8_UNORM:
796 return ComponentType::UNorm;
797 case Tegra::DepthFormat::Z32_FLOAT:
798 case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
799 return ComponentType::Float;
800 default:
801 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
802 UNREACHABLE();
803 }
804 }
805
806 static SurfaceType GetFormatType(PixelFormat pixel_format) {
807 if (static_cast<std::size_t>(pixel_format) <
808 static_cast<std::size_t>(PixelFormat::MaxColorFormat)) {
809 return SurfaceType::ColorTexture;
810 }
811
812 if (static_cast<std::size_t>(pixel_format) <
813 static_cast<std::size_t>(PixelFormat::MaxDepthFormat)) {
814 return SurfaceType::Depth;
815 }
816
817 if (static_cast<std::size_t>(pixel_format) <
818 static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) {
819 return SurfaceType::DepthStencil;
820 }
821
822 // TODO(Subv): Implement the other formats
823 ASSERT(false);
824
825 return SurfaceType::Invalid;
826 }
827
828 /// Returns the sizer in bytes of the specified pixel format
829 static constexpr u32 GetBytesPerPixel(PixelFormat pixel_format) {
830 if (pixel_format == SurfaceParams::PixelFormat::Invalid) {
831 return 0;
832 }
833 return GetFormatBpp(pixel_format) / CHAR_BIT;
834 } 61 }
835 62
836 /// Returns the rectangle corresponding to this surface 63 /// Returns the rectangle corresponding to this surface
837 MathUtil::Rectangle<u32> GetRect() const; 64 MathUtil::Rectangle<u32> GetRect(u32 mip_level = 0) const;
838 65
839 /// Returns the total size of this surface in bytes, adjusted for compression 66 /// Returns the total size of this surface in bytes, adjusted for compression
840 std::size_t SizeInBytesRaw(bool ignore_tiled = false) const { 67 std::size_t SizeInBytesRaw(bool ignore_tiled = false) const {
@@ -865,7 +92,7 @@ struct SurfaceParams {
865 92
866 /// Returns the exact size of memory occupied by the texture in VRAM, including mipmaps. 93 /// Returns the exact size of memory occupied by the texture in VRAM, including mipmaps.
867 std::size_t MemorySize() const { 94 std::size_t MemorySize() const {
868 std::size_t size = InnerMemorySize(is_layered); 95 std::size_t size = InnerMemorySize(false, is_layered);
869 if (is_layered) 96 if (is_layered)
870 return size * depth; 97 return size * depth;
871 return size; 98 return size;
@@ -874,12 +101,78 @@ struct SurfaceParams {
874 /// Returns the exact size of the memory occupied by a layer in a texture in VRAM, including 101 /// Returns the exact size of the memory occupied by a layer in a texture in VRAM, including
875 /// mipmaps. 102 /// mipmaps.
876 std::size_t LayerMemorySize() const { 103 std::size_t LayerMemorySize() const {
877 return InnerMemorySize(true); 104 return InnerMemorySize(false, true);
878 } 105 }
879 106
880 /// Returns the size of a layer of this surface in OpenGL. 107 /// Returns the size of a layer of this surface in OpenGL.
881 std::size_t LayerSizeGL() const { 108 std::size_t LayerSizeGL(u32 mip_level) const {
882 return SizeInBytesRaw(true) / depth; 109 return InnerMipmapMemorySize(mip_level, true, is_layered, false);
110 }
111
112 std::size_t GetMipmapSizeGL(u32 mip_level, bool ignore_compressed = true) const {
113 std::size_t size = InnerMipmapMemorySize(mip_level, true, is_layered, ignore_compressed);
114 if (is_layered)
115 return size * depth;
116 return size;
117 }
118
119 std::size_t GetMipmapLevelOffset(u32 mip_level) const {
120 std::size_t offset = 0;
121 for (u32 i = 0; i < mip_level; i++)
122 offset += InnerMipmapMemorySize(i, false, is_layered);
123 return offset;
124 }
125
126 std::size_t GetMipmapLevelOffsetGL(u32 mip_level) const {
127 std::size_t offset = 0;
128 for (u32 i = 0; i < mip_level; i++)
129 offset += InnerMipmapMemorySize(i, true, is_layered);
130 return offset;
131 }
132
133 u32 MipWidth(u32 mip_level) const {
134 return std::max(1U, width >> mip_level);
135 }
136
137 u32 MipHeight(u32 mip_level) const {
138 return std::max(1U, height >> mip_level);
139 }
140
141 u32 MipDepth(u32 mip_level) const {
142 return std::max(1U, depth >> mip_level);
143 }
144
145 // Auto block resizing algorithm from:
146 // https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nv50/nv50_miptree.c
147 u32 MipBlockHeight(u32 mip_level) const {
148 if (mip_level == 0)
149 return block_height;
150 u32 alt_height = MipHeight(mip_level);
151 u32 h = GetDefaultBlockHeight(pixel_format);
152 u32 blocks_in_y = (alt_height + h - 1) / h;
153 u32 bh = 16;
154 while (bh > 1 && blocks_in_y <= bh * 4) {
155 bh >>= 1;
156 }
157 return bh;
158 }
159
160 u32 MipBlockDepth(u32 mip_level) const {
161 if (mip_level == 0)
162 return block_depth;
163 if (is_layered)
164 return 1;
165 u32 depth = MipDepth(mip_level);
166 u32 bd = 32;
167 while (bd > 1 && depth * 2 <= bd) {
168 bd >>= 1;
169 }
170 if (bd == 32) {
171 u32 bh = MipBlockHeight(mip_level);
172 if (bh >= 4)
173 return 16;
174 }
175 return bd;
883 } 176 }
884 177
885 /// Creates SurfaceParams from a texture configuration 178 /// Creates SurfaceParams from a texture configuration
@@ -940,7 +233,10 @@ struct SurfaceParams {
940 } rt; 233 } rt;
941 234
942private: 235private:
943 std::size_t InnerMemorySize(bool layer_only = false) const; 236 std::size_t InnerMipmapMemorySize(u32 mip_level, bool force_gl = false, bool layer_only = false,
237 bool uncompressed = false) const;
238 std::size_t InnerMemorySize(bool force_gl = false, bool layer_only = false,
239 bool uncompressed = false) const;
944}; 240};
945 241
946}; // namespace OpenGL 242}; // namespace OpenGL
@@ -1002,8 +298,10 @@ public:
1002 void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle); 298 void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle);
1003 299
1004private: 300private:
301 void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle);
302
1005 OGLTexture texture; 303 OGLTexture texture;
1006 std::vector<u8> gl_buffer; 304 std::vector<std::vector<u8>> gl_buffer;
1007 SurfaceParams params; 305 SurfaceParams params;
1008 GLenum gl_target; 306 GLenum gl_target;
1009 std::size_t cached_size_in_bytes; 307 std::size_t cached_size_in_bytes;
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 1a03a677f..9522fd344 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -8,6 +8,7 @@
8#include "video_core/engines/maxwell_3d.h" 8#include "video_core/engines/maxwell_3d.h"
9#include "video_core/renderer_opengl/gl_shader_cache.h" 9#include "video_core/renderer_opengl/gl_shader_cache.h"
10#include "video_core/renderer_opengl/gl_shader_manager.h" 10#include "video_core/renderer_opengl/gl_shader_manager.h"
11#include "video_core/renderer_opengl/utils.h"
11#include "video_core/utils.h" 12#include "video_core/utils.h"
12 13
13namespace OpenGL { 14namespace OpenGL {
@@ -89,7 +90,7 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
89 shader.Create(program_result.first.c_str(), gl_type); 90 shader.Create(program_result.first.c_str(), gl_type);
90 program.Create(true, shader.handle); 91 program.Create(true, shader.handle);
91 SetShaderUniformBlockBindings(program.handle); 92 SetShaderUniformBlockBindings(program.handle);
92 VideoCore::LabelGLObject(GL_PROGRAM, program.handle, addr); 93 LabelGLObject(GL_PROGRAM, program.handle, addr);
93 } else { 94 } else {
94 // Store shader's code to lazily build it on draw 95 // Store shader's code to lazily build it on draw
95 geometry_programs.code = program_result.first; 96 geometry_programs.code = program_result.first;
@@ -130,7 +131,7 @@ GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
130 shader.Create(source.c_str(), GL_GEOMETRY_SHADER); 131 shader.Create(source.c_str(), GL_GEOMETRY_SHADER);
131 target_program.Create(true, shader.handle); 132 target_program.Create(true, shader.handle);
132 SetShaderUniformBlockBindings(target_program.handle); 133 SetShaderUniformBlockBindings(target_program.handle);
133 VideoCore::LabelGLObject(GL_PROGRAM, target_program.handle, addr, debug_name); 134 LabelGLObject(GL_PROGRAM, target_program.handle, addr, debug_name);
134 return target_program.handle; 135 return target_program.handle;
135}; 136};
136 137
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 087baf9ed..09b003c59 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -3,12 +3,12 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <map>
6#include <optional>
6#include <set> 7#include <set>
7#include <string> 8#include <string>
8#include <string_view> 9#include <string_view>
9#include <unordered_set> 10#include <unordered_set>
10 11
11#include <boost/optional.hpp>
12#include <fmt/format.h> 12#include <fmt/format.h>
13 13
14#include "common/assert.h" 14#include "common/assert.h"
@@ -144,7 +144,7 @@ private:
144 for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) { 144 for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) {
145 const Instruction instr = {program_code[offset]}; 145 const Instruction instr = {program_code[offset]};
146 if (const auto opcode = OpCode::Decode(instr)) { 146 if (const auto opcode = OpCode::Decode(instr)) {
147 switch (opcode->GetId()) { 147 switch (opcode->get().GetId()) {
148 case OpCode::Id::EXIT: { 148 case OpCode::Id::EXIT: {
149 // The EXIT instruction can be predicated, which means that the shader can 149 // The EXIT instruction can be predicated, which means that the shader can
150 // conditionally end on this instruction. We have to consider the case where the 150 // conditionally end on this instruction. We have to consider the case where the
@@ -373,6 +373,7 @@ public:
373 if (sets_cc) { 373 if (sets_cc) {
374 const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )"; 374 const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )";
375 SetInternalFlag(InternalFlag::ZeroFlag, zero_condition); 375 SetInternalFlag(InternalFlag::ZeroFlag, zero_condition);
376 LOG_WARNING(HW_GPU, "Control Codes Imcomplete.");
376 } 377 }
377 } 378 }
378 379
@@ -430,7 +431,7 @@ public:
430 */ 431 */
431 void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute, 432 void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute,
432 const Tegra::Shader::IpaMode& input_mode, 433 const Tegra::Shader::IpaMode& input_mode,
433 boost::optional<Register> vertex = {}) { 434 std::optional<Register> vertex = {}) {
434 const std::string dest = GetRegisterAsFloat(reg); 435 const std::string dest = GetRegisterAsFloat(reg);
435 const std::string src = GetInputAttribute(attribute, input_mode, vertex) + GetSwizzle(elem); 436 const std::string src = GetInputAttribute(attribute, input_mode, vertex) + GetSwizzle(elem);
436 shader.AddLine(dest + " = " + src + ';'); 437 shader.AddLine(dest + " = " + src + ';');
@@ -807,10 +808,10 @@ private:
807 /// Generates code representing an input attribute register. 808 /// Generates code representing an input attribute register.
808 std::string GetInputAttribute(Attribute::Index attribute, 809 std::string GetInputAttribute(Attribute::Index attribute,
809 const Tegra::Shader::IpaMode& input_mode, 810 const Tegra::Shader::IpaMode& input_mode,
810 boost::optional<Register> vertex = {}) { 811 std::optional<Register> vertex = {}) {
811 auto GeometryPass = [&](const std::string& name) { 812 auto GeometryPass = [&](const std::string& name) {
812 if (stage == Maxwell3D::Regs::ShaderStage::Geometry && vertex) { 813 if (stage == Maxwell3D::Regs::ShaderStage::Geometry && vertex) {
813 return "gs_" + name + '[' + GetRegisterAsInteger(vertex.value(), 0, false) + ']'; 814 return "gs_" + name + '[' + GetRegisterAsInteger(*vertex, 0, false) + ']';
814 } 815 }
815 return name; 816 return name;
816 }; 817 };
@@ -1465,7 +1466,7 @@ private:
1465 } 1466 }
1466 1467
1467 shader.AddLine( 1468 shader.AddLine(
1468 fmt::format("// {}: {} (0x{:016x})", offset, opcode->GetName(), instr.value)); 1469 fmt::format("// {}: {} (0x{:016x})", offset, opcode->get().GetName(), instr.value));
1469 1470
1470 using Tegra::Shader::Pred; 1471 using Tegra::Shader::Pred;
1471 ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute, 1472 ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute,
@@ -1473,7 +1474,7 @@ private:
1473 1474
1474 // Some instructions (like SSY) don't have a predicate field, they are always 1475 // Some instructions (like SSY) don't have a predicate field, they are always
1475 // unconditionally executed. 1476 // unconditionally executed.
1476 bool can_be_predicated = OpCode::IsPredicatedInstruction(opcode->GetId()); 1477 bool can_be_predicated = OpCode::IsPredicatedInstruction(opcode->get().GetId());
1477 1478
1478 if (can_be_predicated && instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) { 1479 if (can_be_predicated && instr.pred.pred_index != static_cast<u64>(Pred::UnusedIndex)) {
1479 shader.AddLine("if (" + 1480 shader.AddLine("if (" +
@@ -1483,7 +1484,7 @@ private:
1483 ++shader.scope; 1484 ++shader.scope;
1484 } 1485 }
1485 1486
1486 switch (opcode->GetType()) { 1487 switch (opcode->get().GetType()) {
1487 case OpCode::Type::Arithmetic: { 1488 case OpCode::Type::Arithmetic: {
1488 std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); 1489 std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
1489 1490
@@ -1500,7 +1501,7 @@ private:
1500 } 1501 }
1501 } 1502 }
1502 1503
1503 switch (opcode->GetId()) { 1504 switch (opcode->get().GetId()) {
1504 case OpCode::Id::MOV_C: 1505 case OpCode::Id::MOV_C:
1505 case OpCode::Id::MOV_R: { 1506 case OpCode::Id::MOV_R: {
1506 // MOV does not have neither 'abs' nor 'neg' bits. 1507 // MOV does not have neither 'abs' nor 'neg' bits.
@@ -1525,6 +1526,10 @@ private:
1525 1526
1526 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, 1527 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1,
1527 instr.alu.saturate_d, 0, true); 1528 instr.alu.saturate_d, 0, true);
1529 if (instr.generates_cc) {
1530 LOG_CRITICAL(HW_GPU, "FMUL Generates an unhandled Control Code");
1531 UNREACHABLE();
1532 }
1528 break; 1533 break;
1529 } 1534 }
1530 case OpCode::Id::FADD_C: 1535 case OpCode::Id::FADD_C:
@@ -1535,6 +1540,10 @@ private:
1535 1540
1536 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, 1541 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1,
1537 instr.alu.saturate_d, 0, true); 1542 instr.alu.saturate_d, 0, true);
1543 if (instr.generates_cc) {
1544 LOG_CRITICAL(HW_GPU, "FADD Generates an unhandled Control Code");
1545 UNREACHABLE();
1546 }
1538 break; 1547 break;
1539 } 1548 }
1540 case OpCode::Id::MUFU: { 1549 case OpCode::Id::MUFU: {
@@ -1588,6 +1597,10 @@ private:
1588 '(' + condition + ") ? min(" + parameters + ") : max(" + 1597 '(' + condition + ") ? min(" + parameters + ") : max(" +
1589 parameters + ')', 1598 parameters + ')',
1590 1, 1, false, 0, true); 1599 1, 1, false, 0, true);
1600 if (instr.generates_cc) {
1601 LOG_CRITICAL(HW_GPU, "FMNMX Generates an unhandled Control Code");
1602 UNREACHABLE();
1603 }
1591 break; 1604 break;
1592 } 1605 }
1593 case OpCode::Id::RRO_C: 1606 case OpCode::Id::RRO_C:
@@ -1600,14 +1613,15 @@ private:
1600 break; 1613 break;
1601 } 1614 }
1602 default: { 1615 default: {
1603 LOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {}", opcode->GetName()); 1616 LOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {}",
1617 opcode->get().GetName());
1604 UNREACHABLE(); 1618 UNREACHABLE();
1605 } 1619 }
1606 } 1620 }
1607 break; 1621 break;
1608 } 1622 }
1609 case OpCode::Type::ArithmeticImmediate: { 1623 case OpCode::Type::ArithmeticImmediate: {
1610 switch (opcode->GetId()) { 1624 switch (opcode->get().GetId()) {
1611 case OpCode::Id::MOV32_IMM: { 1625 case OpCode::Id::MOV32_IMM: {
1612 regs.SetRegisterToFloat(instr.gpr0, 0, GetImmediate32(instr), 1, 1); 1626 regs.SetRegisterToFloat(instr.gpr0, 0, GetImmediate32(instr), 1, 1);
1613 break; 1627 break;
@@ -1617,6 +1631,10 @@ private:
1617 regs.GetRegisterAsFloat(instr.gpr8) + " * " + 1631 regs.GetRegisterAsFloat(instr.gpr8) + " * " +
1618 GetImmediate32(instr), 1632 GetImmediate32(instr),
1619 1, 1, instr.fmul32.saturate, 0, true); 1633 1, 1, instr.fmul32.saturate, 0, true);
1634 if (instr.op_32.generates_cc) {
1635 LOG_CRITICAL(HW_GPU, "FMUL32 Generates an unhandled Control Code");
1636 UNREACHABLE();
1637 }
1620 break; 1638 break;
1621 } 1639 }
1622 case OpCode::Id::FADD32I: { 1640 case OpCode::Id::FADD32I: {
@@ -1640,6 +1658,10 @@ private:
1640 } 1658 }
1641 1659
1642 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, false, 0, true); 1660 regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, false, 0, true);
1661 if (instr.op_32.generates_cc) {
1662 LOG_CRITICAL(HW_GPU, "FADD32 Generates an unhandled Control Code");
1663 UNREACHABLE();
1664 }
1643 break; 1665 break;
1644 } 1666 }
1645 } 1667 }
@@ -1651,7 +1673,7 @@ private:
1651 std::string op_a = instr.bfe.negate_a ? "-" : ""; 1673 std::string op_a = instr.bfe.negate_a ? "-" : "";
1652 op_a += regs.GetRegisterAsInteger(instr.gpr8); 1674 op_a += regs.GetRegisterAsInteger(instr.gpr8);
1653 1675
1654 switch (opcode->GetId()) { 1676 switch (opcode->get().GetId()) {
1655 case OpCode::Id::BFE_IMM: { 1677 case OpCode::Id::BFE_IMM: {
1656 std::string inner_shift = 1678 std::string inner_shift =
1657 '(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')'; 1679 '(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')';
@@ -1660,10 +1682,14 @@ private:
1660 std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')'; 1682 std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')';
1661 1683
1662 regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1); 1684 regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1);
1685 if (instr.generates_cc) {
1686 LOG_CRITICAL(HW_GPU, "BFE Generates an unhandled Control Code");
1687 UNREACHABLE();
1688 }
1663 break; 1689 break;
1664 } 1690 }
1665 default: { 1691 default: {
1666 LOG_CRITICAL(HW_GPU, "Unhandled BFE instruction: {}", opcode->GetName()); 1692 LOG_CRITICAL(HW_GPU, "Unhandled BFE instruction: {}", opcode->get().GetName());
1667 UNREACHABLE(); 1693 UNREACHABLE();
1668 } 1694 }
1669 } 1695 }
@@ -1685,7 +1711,7 @@ private:
1685 } 1711 }
1686 } 1712 }
1687 1713
1688 switch (opcode->GetId()) { 1714 switch (opcode->get().GetId()) {
1689 case OpCode::Id::SHR_C: 1715 case OpCode::Id::SHR_C:
1690 case OpCode::Id::SHR_R: 1716 case OpCode::Id::SHR_R:
1691 case OpCode::Id::SHR_IMM: { 1717 case OpCode::Id::SHR_IMM: {
@@ -1697,15 +1723,23 @@ private:
1697 // Cast to int is superfluous for arithmetic shift, it's only for a logical shift 1723 // Cast to int is superfluous for arithmetic shift, it's only for a logical shift
1698 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(" + op_a + " >> " + op_b + ')', 1724 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(" + op_a + " >> " + op_b + ')',
1699 1, 1); 1725 1, 1);
1726 if (instr.generates_cc) {
1727 LOG_CRITICAL(HW_GPU, "SHR Generates an unhandled Control Code");
1728 UNREACHABLE();
1729 }
1700 break; 1730 break;
1701 } 1731 }
1702 case OpCode::Id::SHL_C: 1732 case OpCode::Id::SHL_C:
1703 case OpCode::Id::SHL_R: 1733 case OpCode::Id::SHL_R:
1704 case OpCode::Id::SHL_IMM: 1734 case OpCode::Id::SHL_IMM:
1705 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1); 1735 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1);
1736 if (instr.generates_cc) {
1737 LOG_CRITICAL(HW_GPU, "SHL Generates an unhandled Control Code");
1738 UNREACHABLE();
1739 }
1706 break; 1740 break;
1707 default: { 1741 default: {
1708 LOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->GetName()); 1742 LOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->get().GetName());
1709 UNREACHABLE(); 1743 UNREACHABLE();
1710 } 1744 }
1711 } 1745 }
@@ -1715,13 +1749,17 @@ private:
1715 std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); 1749 std::string op_a = regs.GetRegisterAsInteger(instr.gpr8);
1716 std::string op_b = std::to_string(instr.alu.imm20_32.Value()); 1750 std::string op_b = std::to_string(instr.alu.imm20_32.Value());
1717 1751
1718 switch (opcode->GetId()) { 1752 switch (opcode->get().GetId()) {
1719 case OpCode::Id::IADD32I: 1753 case OpCode::Id::IADD32I:
1720 if (instr.iadd32i.negate_a) 1754 if (instr.iadd32i.negate_a)
1721 op_a = "-(" + op_a + ')'; 1755 op_a = "-(" + op_a + ')';
1722 1756
1723 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, 1757 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
1724 instr.iadd32i.saturate != 0); 1758 instr.iadd32i.saturate != 0);
1759 if (instr.op_32.generates_cc) {
1760 LOG_CRITICAL(HW_GPU, "IADD32 Generates an unhandled Control Code");
1761 UNREACHABLE();
1762 }
1725 break; 1763 break;
1726 case OpCode::Id::LOP32I: { 1764 case OpCode::Id::LOP32I: {
1727 if (instr.alu.lop32i.invert_a) 1765 if (instr.alu.lop32i.invert_a)
@@ -1733,11 +1771,15 @@ private:
1733 WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b, 1771 WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b,
1734 Tegra::Shader::PredicateResultMode::None, 1772 Tegra::Shader::PredicateResultMode::None,
1735 Tegra::Shader::Pred::UnusedIndex); 1773 Tegra::Shader::Pred::UnusedIndex);
1774 if (instr.op_32.generates_cc) {
1775 LOG_CRITICAL(HW_GPU, "LOP32I Generates an unhandled Control Code");
1776 UNREACHABLE();
1777 }
1736 break; 1778 break;
1737 } 1779 }
1738 default: { 1780 default: {
1739 LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticIntegerImmediate instruction: {}", 1781 LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticIntegerImmediate instruction: {}",
1740 opcode->GetName()); 1782 opcode->get().GetName());
1741 UNREACHABLE(); 1783 UNREACHABLE();
1742 } 1784 }
1743 } 1785 }
@@ -1757,7 +1799,7 @@ private:
1757 } 1799 }
1758 } 1800 }
1759 1801
1760 switch (opcode->GetId()) { 1802 switch (opcode->get().GetId()) {
1761 case OpCode::Id::IADD_C: 1803 case OpCode::Id::IADD_C:
1762 case OpCode::Id::IADD_R: 1804 case OpCode::Id::IADD_R:
1763 case OpCode::Id::IADD_IMM: { 1805 case OpCode::Id::IADD_IMM: {
@@ -1769,6 +1811,10 @@ private:
1769 1811
1770 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, 1812 regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
1771 instr.alu.saturate_d); 1813 instr.alu.saturate_d);
1814 if (instr.generates_cc) {
1815 LOG_CRITICAL(HW_GPU, "IADD Generates an unhandled Control Code");
1816 UNREACHABLE();
1817 }
1772 break; 1818 break;
1773 } 1819 }
1774 case OpCode::Id::IADD3_C: 1820 case OpCode::Id::IADD3_C:
@@ -1793,7 +1839,7 @@ private:
1793 } 1839 }
1794 }; 1840 };
1795 1841
1796 if (opcode->GetId() == OpCode::Id::IADD3_R) { 1842 if (opcode->get().GetId() == OpCode::Id::IADD3_R) {
1797 apply_height(instr.iadd3.height_a, op_a); 1843 apply_height(instr.iadd3.height_a, op_a);
1798 apply_height(instr.iadd3.height_b, op_b); 1844 apply_height(instr.iadd3.height_b, op_b);
1799 apply_height(instr.iadd3.height_c, op_c); 1845 apply_height(instr.iadd3.height_c, op_c);
@@ -1809,7 +1855,7 @@ private:
1809 op_c = "-(" + op_c + ')'; 1855 op_c = "-(" + op_c + ')';
1810 1856
1811 std::string result; 1857 std::string result;
1812 if (opcode->GetId() == OpCode::Id::IADD3_R) { 1858 if (opcode->get().GetId() == OpCode::Id::IADD3_R) {
1813 switch (instr.iadd3.mode) { 1859 switch (instr.iadd3.mode) {
1814 case Tegra::Shader::IAdd3Mode::RightShift: 1860 case Tegra::Shader::IAdd3Mode::RightShift:
1815 // TODO(tech4me): According to 1861 // TODO(tech4me): According to
@@ -1830,6 +1876,11 @@ private:
1830 } 1876 }
1831 1877
1832 regs.SetRegisterToInteger(instr.gpr0, true, 0, result, 1, 1); 1878 regs.SetRegisterToInteger(instr.gpr0, true, 0, result, 1, 1);
1879
1880 if (instr.generates_cc) {
1881 LOG_CRITICAL(HW_GPU, "IADD3 Generates an unhandled Control Code");
1882 UNREACHABLE();
1883 }
1833 break; 1884 break;
1834 } 1885 }
1835 case OpCode::Id::ISCADD_C: 1886 case OpCode::Id::ISCADD_C:
@@ -1845,6 +1896,10 @@ private:
1845 1896
1846 regs.SetRegisterToInteger(instr.gpr0, true, 0, 1897 regs.SetRegisterToInteger(instr.gpr0, true, 0,
1847 "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1); 1898 "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1);
1899 if (instr.generates_cc) {
1900 LOG_CRITICAL(HW_GPU, "ISCADD Generates an unhandled Control Code");
1901 UNREACHABLE();
1902 }
1848 break; 1903 break;
1849 } 1904 }
1850 case OpCode::Id::POPC_C: 1905 case OpCode::Id::POPC_C:
@@ -1876,6 +1931,10 @@ private:
1876 1931
1877 WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b, 1932 WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b,
1878 instr.alu.lop.pred_result_mode, instr.alu.lop.pred48); 1933 instr.alu.lop.pred_result_mode, instr.alu.lop.pred48);
1934 if (instr.generates_cc) {
1935 LOG_CRITICAL(HW_GPU, "LOP Generates an unhandled Control Code");
1936 UNREACHABLE();
1937 }
1879 break; 1938 break;
1880 } 1939 }
1881 case OpCode::Id::LOP3_C: 1940 case OpCode::Id::LOP3_C:
@@ -1884,13 +1943,17 @@ private:
1884 const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); 1943 const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39);
1885 std::string lut; 1944 std::string lut;
1886 1945
1887 if (opcode->GetId() == OpCode::Id::LOP3_R) { 1946 if (opcode->get().GetId() == OpCode::Id::LOP3_R) {
1888 lut = '(' + std::to_string(instr.alu.lop3.GetImmLut28()) + ')'; 1947 lut = '(' + std::to_string(instr.alu.lop3.GetImmLut28()) + ')';
1889 } else { 1948 } else {
1890 lut = '(' + std::to_string(instr.alu.lop3.GetImmLut48()) + ')'; 1949 lut = '(' + std::to_string(instr.alu.lop3.GetImmLut48()) + ')';
1891 } 1950 }
1892 1951
1893 WriteLop3Instruction(instr.gpr0, op_a, op_b, op_c, lut); 1952 WriteLop3Instruction(instr.gpr0, op_a, op_b, op_c, lut);
1953 if (instr.generates_cc) {
1954 LOG_CRITICAL(HW_GPU, "LOP3 Generates an unhandled Control Code");
1955 UNREACHABLE();
1956 }
1894 break; 1957 break;
1895 } 1958 }
1896 case OpCode::Id::IMNMX_C: 1959 case OpCode::Id::IMNMX_C:
@@ -1905,6 +1968,10 @@ private:
1905 '(' + condition + ") ? min(" + parameters + ") : max(" + 1968 '(' + condition + ") ? min(" + parameters + ") : max(" +
1906 parameters + ')', 1969 parameters + ')',
1907 1, 1); 1970 1, 1);
1971 if (instr.generates_cc) {
1972 LOG_CRITICAL(HW_GPU, "IMNMX Generates an unhandled Control Code");
1973 UNREACHABLE();
1974 }
1908 break; 1975 break;
1909 } 1976 }
1910 case OpCode::Id::LEA_R2: 1977 case OpCode::Id::LEA_R2:
@@ -1914,7 +1981,7 @@ private:
1914 case OpCode::Id::LEA_HI: { 1981 case OpCode::Id::LEA_HI: {
1915 std::string op_c; 1982 std::string op_c;
1916 1983
1917 switch (opcode->GetId()) { 1984 switch (opcode->get().GetId()) {
1918 case OpCode::Id::LEA_R2: { 1985 case OpCode::Id::LEA_R2: {
1919 op_a = regs.GetRegisterAsInteger(instr.gpr20); 1986 op_a = regs.GetRegisterAsInteger(instr.gpr20);
1920 op_b = regs.GetRegisterAsInteger(instr.gpr39); 1987 op_b = regs.GetRegisterAsInteger(instr.gpr39);
@@ -1959,7 +2026,8 @@ private:
1959 op_b = regs.GetRegisterAsInteger(instr.gpr8); 2026 op_b = regs.GetRegisterAsInteger(instr.gpr8);
1960 op_a = std::to_string(instr.lea.imm.entry_a); 2027 op_a = std::to_string(instr.lea.imm.entry_a);
1961 op_c = std::to_string(instr.lea.imm.entry_b); 2028 op_c = std::to_string(instr.lea.imm.entry_b);
1962 LOG_CRITICAL(HW_GPU, "Unhandled LEA subinstruction: {}", opcode->GetName()); 2029 LOG_CRITICAL(HW_GPU, "Unhandled LEA subinstruction: {}",
2030 opcode->get().GetName());
1963 UNREACHABLE(); 2031 UNREACHABLE();
1964 } 2032 }
1965 } 2033 }
@@ -1974,7 +2042,7 @@ private:
1974 } 2042 }
1975 default: { 2043 default: {
1976 LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}", 2044 LOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}",
1977 opcode->GetName()); 2045 opcode->get().GetName());
1978 UNREACHABLE(); 2046 UNREACHABLE();
1979 } 2047 }
1980 } 2048 }
@@ -1982,20 +2050,21 @@ private:
1982 break; 2050 break;
1983 } 2051 }
1984 case OpCode::Type::ArithmeticHalf: { 2052 case OpCode::Type::ArithmeticHalf: {
1985 if (opcode->GetId() == OpCode::Id::HADD2_C || opcode->GetId() == OpCode::Id::HADD2_R) { 2053 if (opcode->get().GetId() == OpCode::Id::HADD2_C ||
2054 opcode->get().GetId() == OpCode::Id::HADD2_R) {
1986 ASSERT_MSG(instr.alu_half.ftz == 0, "Unimplemented"); 2055 ASSERT_MSG(instr.alu_half.ftz == 0, "Unimplemented");
1987 } 2056 }
1988 const bool negate_a = 2057 const bool negate_a =
1989 opcode->GetId() != OpCode::Id::HMUL2_R && instr.alu_half.negate_a != 0; 2058 opcode->get().GetId() != OpCode::Id::HMUL2_R && instr.alu_half.negate_a != 0;
1990 const bool negate_b = 2059 const bool negate_b =
1991 opcode->GetId() != OpCode::Id::HMUL2_C && instr.alu_half.negate_b != 0; 2060 opcode->get().GetId() != OpCode::Id::HMUL2_C && instr.alu_half.negate_b != 0;
1992 2061
1993 const std::string op_a = 2062 const std::string op_a =
1994 GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr8, 0, false), instr.alu_half.type_a, 2063 GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr8, 0, false), instr.alu_half.type_a,
1995 instr.alu_half.abs_a != 0, negate_a); 2064 instr.alu_half.abs_a != 0, negate_a);
1996 2065
1997 std::string op_b; 2066 std::string op_b;
1998 switch (opcode->GetId()) { 2067 switch (opcode->get().GetId()) {
1999 case OpCode::Id::HADD2_C: 2068 case OpCode::Id::HADD2_C:
2000 case OpCode::Id::HMUL2_C: 2069 case OpCode::Id::HMUL2_C:
2001 op_b = regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, 2070 op_b = regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
@@ -2013,7 +2082,7 @@ private:
2013 op_b = GetHalfFloat(op_b, instr.alu_half.type_b, instr.alu_half.abs_b != 0, negate_b); 2082 op_b = GetHalfFloat(op_b, instr.alu_half.type_b, instr.alu_half.abs_b != 0, negate_b);
2014 2083
2015 const std::string result = [&]() { 2084 const std::string result = [&]() {
2016 switch (opcode->GetId()) { 2085 switch (opcode->get().GetId()) {
2017 case OpCode::Id::HADD2_C: 2086 case OpCode::Id::HADD2_C:
2018 case OpCode::Id::HADD2_R: 2087 case OpCode::Id::HADD2_R:
2019 return '(' + op_a + " + " + op_b + ')'; 2088 return '(' + op_a + " + " + op_b + ')';
@@ -2021,7 +2090,8 @@ private:
2021 case OpCode::Id::HMUL2_R: 2090 case OpCode::Id::HMUL2_R:
2022 return '(' + op_a + " * " + op_b + ')'; 2091 return '(' + op_a + " * " + op_b + ')';
2023 default: 2092 default:
2024 LOG_CRITICAL(HW_GPU, "Unhandled half float instruction: {}", opcode->GetName()); 2093 LOG_CRITICAL(HW_GPU, "Unhandled half float instruction: {}",
2094 opcode->get().GetName());
2025 UNREACHABLE(); 2095 UNREACHABLE();
2026 return std::string("0"); 2096 return std::string("0");
2027 } 2097 }
@@ -2032,7 +2102,7 @@ private:
2032 break; 2102 break;
2033 } 2103 }
2034 case OpCode::Type::ArithmeticHalfImmediate: { 2104 case OpCode::Type::ArithmeticHalfImmediate: {
2035 if (opcode->GetId() == OpCode::Id::HADD2_IMM) { 2105 if (opcode->get().GetId() == OpCode::Id::HADD2_IMM) {
2036 ASSERT_MSG(instr.alu_half_imm.ftz == 0, "Unimplemented"); 2106 ASSERT_MSG(instr.alu_half_imm.ftz == 0, "Unimplemented");
2037 } else { 2107 } else {
2038 ASSERT_MSG(instr.alu_half_imm.precision == Tegra::Shader::HalfPrecision::None, 2108 ASSERT_MSG(instr.alu_half_imm.precision == Tegra::Shader::HalfPrecision::None,
@@ -2046,7 +2116,7 @@ private:
2046 const std::string op_b = UnpackHalfImmediate(instr, true); 2116 const std::string op_b = UnpackHalfImmediate(instr, true);
2047 2117
2048 const std::string result = [&]() { 2118 const std::string result = [&]() {
2049 switch (opcode->GetId()) { 2119 switch (opcode->get().GetId()) {
2050 case OpCode::Id::HADD2_IMM: 2120 case OpCode::Id::HADD2_IMM:
2051 return op_a + " + " + op_b; 2121 return op_a + " + " + op_b;
2052 case OpCode::Id::HMUL2_IMM: 2122 case OpCode::Id::HMUL2_IMM:
@@ -2072,7 +2142,7 @@ private:
2072 ASSERT_MSG(instr.ffma.tab5980_1 == 0, "FFMA tab5980_1({}) not implemented", 2142 ASSERT_MSG(instr.ffma.tab5980_1 == 0, "FFMA tab5980_1({}) not implemented",
2073 instr.ffma.tab5980_1.Value()); 2143 instr.ffma.tab5980_1.Value());
2074 2144
2075 switch (opcode->GetId()) { 2145 switch (opcode->get().GetId()) {
2076 case OpCode::Id::FFMA_CR: { 2146 case OpCode::Id::FFMA_CR: {
2077 op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, 2147 op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
2078 GLSLRegister::Type::Float); 2148 GLSLRegister::Type::Float);
@@ -2096,25 +2166,29 @@ private:
2096 break; 2166 break;
2097 } 2167 }
2098 default: { 2168 default: {
2099 LOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {}", opcode->GetName()); 2169 LOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {}", opcode->get().GetName());
2100 UNREACHABLE(); 2170 UNREACHABLE();
2101 } 2171 }
2102 } 2172 }
2103 2173
2104 regs.SetRegisterToFloat(instr.gpr0, 0, "fma(" + op_a + ", " + op_b + ", " + op_c + ')', 2174 regs.SetRegisterToFloat(instr.gpr0, 0, "fma(" + op_a + ", " + op_b + ", " + op_c + ')',
2105 1, 1, instr.alu.saturate_d, 0, true); 2175 1, 1, instr.alu.saturate_d, 0, true);
2176 if (instr.generates_cc) {
2177 LOG_CRITICAL(HW_GPU, "FFMA Generates an unhandled Control Code");
2178 UNREACHABLE();
2179 }
2106 2180
2107 break; 2181 break;
2108 } 2182 }
2109 case OpCode::Type::Hfma2: { 2183 case OpCode::Type::Hfma2: {
2110 if (opcode->GetId() == OpCode::Id::HFMA2_RR) { 2184 if (opcode->get().GetId() == OpCode::Id::HFMA2_RR) {
2111 ASSERT_MSG(instr.hfma2.rr.precision == Tegra::Shader::HalfPrecision::None, 2185 ASSERT_MSG(instr.hfma2.rr.precision == Tegra::Shader::HalfPrecision::None,
2112 "Unimplemented"); 2186 "Unimplemented");
2113 } else { 2187 } else {
2114 ASSERT_MSG(instr.hfma2.precision == Tegra::Shader::HalfPrecision::None, 2188 ASSERT_MSG(instr.hfma2.precision == Tegra::Shader::HalfPrecision::None,
2115 "Unimplemented"); 2189 "Unimplemented");
2116 } 2190 }
2117 const bool saturate = opcode->GetId() == OpCode::Id::HFMA2_RR 2191 const bool saturate = opcode->get().GetId() == OpCode::Id::HFMA2_RR
2118 ? instr.hfma2.rr.saturate != 0 2192 ? instr.hfma2.rr.saturate != 0
2119 : instr.hfma2.saturate != 0; 2193 : instr.hfma2.saturate != 0;
2120 2194
@@ -2122,7 +2196,7 @@ private:
2122 GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr8, 0, false), instr.hfma2.type_a); 2196 GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr8, 0, false), instr.hfma2.type_a);
2123 std::string op_b, op_c; 2197 std::string op_b, op_c;
2124 2198
2125 switch (opcode->GetId()) { 2199 switch (opcode->get().GetId()) {
2126 case OpCode::Id::HFMA2_CR: 2200 case OpCode::Id::HFMA2_CR:
2127 op_b = GetHalfFloat(regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, 2201 op_b = GetHalfFloat(regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
2128 GLSLRegister::Type::UnsignedInteger), 2202 GLSLRegister::Type::UnsignedInteger),
@@ -2160,7 +2234,7 @@ private:
2160 break; 2234 break;
2161 } 2235 }
2162 case OpCode::Type::Conversion: { 2236 case OpCode::Type::Conversion: {
2163 switch (opcode->GetId()) { 2237 switch (opcode->get().GetId()) {
2164 case OpCode::Id::I2I_R: { 2238 case OpCode::Id::I2I_R: {
2165 ASSERT_MSG(!instr.conversion.selector, "Unimplemented"); 2239 ASSERT_MSG(!instr.conversion.selector, "Unimplemented");
2166 2240
@@ -2208,6 +2282,11 @@ private:
2208 } 2282 }
2209 2283
2210 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1); 2284 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
2285
2286 if (instr.generates_cc) {
2287 LOG_CRITICAL(HW_GPU, "I2F Generates an unhandled Control Code");
2288 UNREACHABLE();
2289 }
2211 break; 2290 break;
2212 } 2291 }
2213 case OpCode::Id::F2F_R: { 2292 case OpCode::Id::F2F_R: {
@@ -2246,6 +2325,11 @@ private:
2246 } 2325 }
2247 2326
2248 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d); 2327 regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d);
2328
2329 if (instr.generates_cc) {
2330 LOG_CRITICAL(HW_GPU, "F2F Generates an unhandled Control Code");
2331 UNREACHABLE();
2332 }
2249 break; 2333 break;
2250 } 2334 }
2251 case OpCode::Id::F2I_R: 2335 case OpCode::Id::F2I_R:
@@ -2295,17 +2379,22 @@ private:
2295 2379
2296 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1, 2380 regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
2297 1, false, 0, instr.conversion.dest_size); 2381 1, false, 0, instr.conversion.dest_size);
2382 if (instr.generates_cc) {
2383 LOG_CRITICAL(HW_GPU, "F2I Generates an unhandled Control Code");
2384 UNREACHABLE();
2385 }
2298 break; 2386 break;
2299 } 2387 }
2300 default: { 2388 default: {
2301 LOG_CRITICAL(HW_GPU, "Unhandled conversion instruction: {}", opcode->GetName()); 2389 LOG_CRITICAL(HW_GPU, "Unhandled conversion instruction: {}",
2390 opcode->get().GetName());
2302 UNREACHABLE(); 2391 UNREACHABLE();
2303 } 2392 }
2304 } 2393 }
2305 break; 2394 break;
2306 } 2395 }
2307 case OpCode::Type::Memory: { 2396 case OpCode::Type::Memory: {
2308 switch (opcode->GetId()) { 2397 switch (opcode->get().GetId()) {
2309 case OpCode::Id::LD_A: { 2398 case OpCode::Id::LD_A: {
2310 // Note: Shouldn't this be interp mode flat? As in no interpolation made. 2399 // Note: Shouldn't this be interp mode flat? As in no interpolation made.
2311 ASSERT_MSG(instr.gpr8.Value() == Register::ZeroIndex, 2400 ASSERT_MSG(instr.gpr8.Value() == Register::ZeroIndex,
@@ -2949,7 +3038,7 @@ private:
2949 break; 3038 break;
2950 } 3039 }
2951 default: { 3040 default: {
2952 LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->GetName()); 3041 LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->get().GetName());
2953 UNREACHABLE(); 3042 UNREACHABLE();
2954 } 3043 }
2955 } 3044 }
@@ -3043,7 +3132,7 @@ private:
3043 instr.hsetp2.abs_a, instr.hsetp2.negate_a); 3132 instr.hsetp2.abs_a, instr.hsetp2.negate_a);
3044 3133
3045 const std::string op_b = [&]() { 3134 const std::string op_b = [&]() {
3046 switch (opcode->GetId()) { 3135 switch (opcode->get().GetId()) {
3047 case OpCode::Id::HSETP2_R: 3136 case OpCode::Id::HSETP2_R:
3048 return GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr20, 0, false), 3137 return GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr20, 0, false),
3049 instr.hsetp2.type_b, instr.hsetp2.abs_a, 3138 instr.hsetp2.type_b, instr.hsetp2.abs_a,
@@ -3102,10 +3191,15 @@ private:
3102 regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1); 3191 regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1);
3103 } 3192 }
3104 3193
3194 if (instr.generates_cc) {
3195 LOG_CRITICAL(HW_GPU, "PSET Generates an unhandled Control Code");
3196 UNREACHABLE();
3197 }
3198
3105 break; 3199 break;
3106 } 3200 }
3107 case OpCode::Type::PredicateSetPredicate: { 3201 case OpCode::Type::PredicateSetPredicate: {
3108 switch (opcode->GetId()) { 3202 switch (opcode->get().GetId()) {
3109 case OpCode::Id::PSETP: { 3203 case OpCode::Id::PSETP: {
3110 const std::string op_a = 3204 const std::string op_a =
3111 GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0); 3205 GetPredicateCondition(instr.psetp.pred12, instr.psetp.neg_pred12 != 0);
@@ -3151,7 +3245,8 @@ private:
3151 break; 3245 break;
3152 } 3246 }
3153 default: { 3247 default: {
3154 LOG_CRITICAL(HW_GPU, "Unhandled predicate instruction: {}", opcode->GetName()); 3248 LOG_CRITICAL(HW_GPU, "Unhandled predicate instruction: {}",
3249 opcode->get().GetName());
3155 UNREACHABLE(); 3250 UNREACHABLE();
3156 } 3251 }
3157 } 3252 }
@@ -3239,7 +3334,7 @@ private:
3239 instr.hset2.abs_a != 0, instr.hset2.negate_a != 0); 3334 instr.hset2.abs_a != 0, instr.hset2.negate_a != 0);
3240 3335
3241 const std::string op_b = [&]() { 3336 const std::string op_b = [&]() {
3242 switch (opcode->GetId()) { 3337 switch (opcode->get().GetId()) {
3243 case OpCode::Id::HSET2_R: 3338 case OpCode::Id::HSET2_R:
3244 return GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr20, 0, false), 3339 return GetHalfFloat(regs.GetRegisterAsInteger(instr.gpr20, 0, false),
3245 instr.hset2.type_b, instr.hset2.abs_b != 0, 3340 instr.hset2.type_b, instr.hset2.abs_b != 0,
@@ -3288,7 +3383,7 @@ private:
3288 const bool is_signed{instr.xmad.sign_a == 1}; 3383 const bool is_signed{instr.xmad.sign_a == 1};
3289 3384
3290 bool is_merge{}; 3385 bool is_merge{};
3291 switch (opcode->GetId()) { 3386 switch (opcode->get().GetId()) {
3292 case OpCode::Id::XMAD_CR: { 3387 case OpCode::Id::XMAD_CR: {
3293 is_merge = instr.xmad.merge_56; 3388 is_merge = instr.xmad.merge_56;
3294 op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, 3389 op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
@@ -3317,7 +3412,7 @@ private:
3317 break; 3412 break;
3318 } 3413 }
3319 default: { 3414 default: {
3320 LOG_CRITICAL(HW_GPU, "Unhandled XMAD instruction: {}", opcode->GetName()); 3415 LOG_CRITICAL(HW_GPU, "Unhandled XMAD instruction: {}", opcode->get().GetName());
3321 UNREACHABLE(); 3416 UNREACHABLE();
3322 } 3417 }
3323 } 3418 }
@@ -3366,10 +3461,14 @@ private:
3366 } 3461 }
3367 3462
3368 regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1); 3463 regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1);
3464 if (instr.generates_cc) {
3465 LOG_CRITICAL(HW_GPU, "XMAD Generates an unhandled Control Code");
3466 UNREACHABLE();
3467 }
3369 break; 3468 break;
3370 } 3469 }
3371 default: { 3470 default: {
3372 switch (opcode->GetId()) { 3471 switch (opcode->get().GetId()) {
3373 case OpCode::Id::EXIT: { 3472 case OpCode::Id::EXIT: {
3374 if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { 3473 if (stage == Maxwell3D::Regs::ShaderStage::Fragment) {
3375 EmitFragmentOutputsWrite(); 3474 EmitFragmentOutputsWrite();
@@ -3561,6 +3660,11 @@ private:
3561 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1, 3660 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1,
3562 instr.vmad.saturate == 1, 0, Register::Size::Word, 3661 instr.vmad.saturate == 1, 0, Register::Size::Word,
3563 instr.vmad.cc); 3662 instr.vmad.cc);
3663 if (instr.generates_cc) {
3664 LOG_CRITICAL(HW_GPU, "VMAD Generates an unhandled Control Code");
3665 UNREACHABLE();
3666 }
3667
3564 break; 3668 break;
3565 } 3669 }
3566 case OpCode::Id::VSETP: { 3670 case OpCode::Id::VSETP: {
@@ -3588,7 +3692,7 @@ private:
3588 break; 3692 break;
3589 } 3693 }
3590 default: { 3694 default: {
3591 LOG_CRITICAL(HW_GPU, "Unhandled instruction: {}", opcode->GetName()); 3695 LOG_CRITICAL(HW_GPU, "Unhandled instruction: {}", opcode->get().GetName());
3592 UNREACHABLE(); 3696 UNREACHABLE();
3593 } 3697 }
3594 } 3698 }
@@ -3729,9 +3833,9 @@ std::string GetCommonDeclarations() {
3729 RasterizerOpenGL::MaxConstbufferSize / sizeof(GLvec4)); 3833 RasterizerOpenGL::MaxConstbufferSize / sizeof(GLvec4));
3730} 3834}
3731 3835
3732boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, 3836std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
3733 Maxwell3D::Regs::ShaderStage stage, 3837 Maxwell3D::Regs::ShaderStage stage,
3734 const std::string& suffix) { 3838 const std::string& suffix) {
3735 try { 3839 try {
3736 const auto subroutines = 3840 const auto subroutines =
3737 ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines(); 3841 ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines();
@@ -3740,7 +3844,7 @@ boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code,
3740 } catch (const DecompileFail& exception) { 3844 } catch (const DecompileFail& exception) {
3741 LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what()); 3845 LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());
3742 } 3846 }
3743 return boost::none; 3847 return {};
3744} 3848}
3745 3849
3746} // namespace OpenGL::GLShader::Decompiler 3850} // namespace OpenGL::GLShader::Decompiler
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h
index b20cc4bfa..d01a4a7ee 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.h
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h
@@ -6,8 +6,8 @@
6 6
7#include <array> 7#include <array>
8#include <functional> 8#include <functional>
9#include <optional>
9#include <string> 10#include <string>
10#include <boost/optional.hpp>
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "video_core/engines/maxwell_3d.h" 12#include "video_core/engines/maxwell_3d.h"
13#include "video_core/renderer_opengl/gl_shader_gen.h" 13#include "video_core/renderer_opengl/gl_shader_gen.h"
@@ -18,8 +18,8 @@ using Tegra::Engines::Maxwell3D;
18 18
19std::string GetCommonDeclarations(); 19std::string GetCommonDeclarations();
20 20
21boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, 21std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
22 Maxwell3D::Regs::ShaderStage stage, 22 Maxwell3D::Regs::ShaderStage stage,
23 const std::string& suffix); 23 const std::string& suffix);
24 24
25} // namespace OpenGL::GLShader::Decompiler 25} // namespace OpenGL::GLShader::Decompiler
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index dfb562706..9d17edd63 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -37,7 +37,7 @@ layout(std140) uniform vs_config {
37 ProgramResult program = 37 ProgramResult program =
38 Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET, 38 Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET,
39 Maxwell3D::Regs::ShaderStage::Vertex, "vertex") 39 Maxwell3D::Regs::ShaderStage::Vertex, "vertex")
40 .get_value_or({}); 40 .value_or(ProgramResult());
41 41
42 out += program.first; 42 out += program.first;
43 43
@@ -45,7 +45,7 @@ layout(std140) uniform vs_config {
45 ProgramResult program_b = 45 ProgramResult program_b =
46 Decompiler::DecompileProgram(setup.program.code_b, PROGRAM_OFFSET, 46 Decompiler::DecompileProgram(setup.program.code_b, PROGRAM_OFFSET,
47 Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b") 47 Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b")
48 .get_value_or({}); 48 .value_or(ProgramResult());
49 out += program_b.first; 49 out += program_b.first;
50 } 50 }
51 51
@@ -90,7 +90,7 @@ ProgramResult GenerateGeometryShader(const ShaderSetup& setup) {
90 ProgramResult program = 90 ProgramResult program =
91 Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET, 91 Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET,
92 Maxwell3D::Regs::ShaderStage::Geometry, "geometry") 92 Maxwell3D::Regs::ShaderStage::Geometry, "geometry")
93 .get_value_or({}); 93 .value_or(ProgramResult());
94 out += R"( 94 out += R"(
95out gl_PerVertex { 95out gl_PerVertex {
96 vec4 gl_Position; 96 vec4 gl_Position;
@@ -124,7 +124,7 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup) {
124 ProgramResult program = 124 ProgramResult program =
125 Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET, 125 Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET,
126 Maxwell3D::Regs::ShaderStage::Fragment, "fragment") 126 Maxwell3D::Regs::ShaderStage::Fragment, "fragment")
127 .get_value_or({}); 127 .value_or(ProgramResult());
128 out += R"( 128 out += R"(
129layout(location = 0) out vec4 FragColor0; 129layout(location = 0) out vec4 FragColor0;
130layout(location = 1) out vec4 FragColor1; 130layout(location = 1) out vec4 FragColor1;
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index 0f6dcab2b..87d511c38 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -135,12 +135,29 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) {
135 return {}; 135 return {};
136} 136}
137 137
138inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode) { 138inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode,
139 Tegra::Texture::TextureMipmapFilter mip_filter_mode) {
139 switch (filter_mode) { 140 switch (filter_mode) {
140 case Tegra::Texture::TextureFilter::Linear: 141 case Tegra::Texture::TextureFilter::Linear: {
141 return GL_LINEAR; 142 switch (mip_filter_mode) {
142 case Tegra::Texture::TextureFilter::Nearest: 143 case Tegra::Texture::TextureMipmapFilter::None:
143 return GL_NEAREST; 144 return GL_LINEAR;
145 case Tegra::Texture::TextureMipmapFilter::Nearest:
146 return GL_NEAREST_MIPMAP_LINEAR;
147 case Tegra::Texture::TextureMipmapFilter::Linear:
148 return GL_LINEAR_MIPMAP_LINEAR;
149 }
150 }
151 case Tegra::Texture::TextureFilter::Nearest: {
152 switch (mip_filter_mode) {
153 case Tegra::Texture::TextureMipmapFilter::None:
154 return GL_NEAREST;
155 case Tegra::Texture::TextureMipmapFilter::Nearest:
156 return GL_NEAREST_MIPMAP_NEAREST;
157 case Tegra::Texture::TextureMipmapFilter::Linear:
158 return GL_LINEAR_MIPMAP_NEAREST;
159 }
160 }
144 } 161 }
145 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}", 162 LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}",
146 static_cast<u32>(filter_mode)); 163 static_cast<u32>(filter_mode));
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 90b68943d..ea38da932 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -115,7 +115,8 @@ RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& window)
115RendererOpenGL::~RendererOpenGL() = default; 115RendererOpenGL::~RendererOpenGL() = default;
116 116
117/// Swap buffers (render frame) 117/// Swap buffers (render frame)
118void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) { 118void RendererOpenGL::SwapBuffers(
119 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) {
119 ScopeAcquireGLContext acquire_context{render_window}; 120 ScopeAcquireGLContext acquire_context{render_window};
120 121
121 Core::System::GetInstance().GetPerfStats().EndSystemFrame(); 122 Core::System::GetInstance().GetPerfStats().EndSystemFrame();
@@ -124,11 +125,11 @@ void RendererOpenGL::SwapBuffers(boost::optional<const Tegra::FramebufferConfig&
124 OpenGLState prev_state = OpenGLState::GetCurState(); 125 OpenGLState prev_state = OpenGLState::GetCurState();
125 state.Apply(); 126 state.Apply();
126 127
127 if (framebuffer != boost::none) { 128 if (framebuffer) {
128 // If framebuffer is provided, reload it from memory to a texture 129 // If framebuffer is provided, reload it from memory to a texture
129 if (screen_info.texture.width != (GLsizei)framebuffer->width || 130 if (screen_info.texture.width != (GLsizei)framebuffer->get().width ||
130 screen_info.texture.height != (GLsizei)framebuffer->height || 131 screen_info.texture.height != (GLsizei)framebuffer->get().height ||
131 screen_info.texture.pixel_format != framebuffer->pixel_format) { 132 screen_info.texture.pixel_format != framebuffer->get().pixel_format) {
132 // Reallocate texture if the framebuffer size has changed. 133 // Reallocate texture if the framebuffer size has changed.
133 // This is expected to not happen very often and hence should not be a 134 // This is expected to not happen very often and hence should not be a
134 // performance problem. 135 // performance problem.
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 961467a62..c0868c0e4 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -51,7 +51,8 @@ public:
51 ~RendererOpenGL() override; 51 ~RendererOpenGL() override;
52 52
53 /// Swap buffers (render frame) 53 /// Swap buffers (render frame)
54 void SwapBuffers(boost::optional<const Tegra::FramebufferConfig&> framebuffer) override; 54 void SwapBuffers(
55 std::optional<std::reference_wrapper<const Tegra::FramebufferConfig>> framebuffer) override;
55 56
56 /// Initialize the renderer 57 /// Initialize the renderer
57 bool Init() override; 58 bool Init() override;
diff --git a/src/video_core/renderer_opengl/utils.cpp b/src/video_core/renderer_opengl/utils.cpp
new file mode 100644
index 000000000..d84634cb3
--- /dev/null
+++ b/src/video_core/renderer_opengl/utils.cpp
@@ -0,0 +1,38 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <string>
6#include <fmt/format.h>
7#include <glad/glad.h>
8#include "common/common_types.h"
9#include "video_core/renderer_opengl/utils.h"
10
11namespace OpenGL {
12
13void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string extra_info) {
14 if (!GLAD_GL_KHR_debug) {
15 return; // We don't need to throw an error as this is just for debugging
16 }
17 const std::string nice_addr = fmt::format("0x{:016x}", addr);
18 std::string object_label;
19
20 if (extra_info.empty()) {
21 switch (identifier) {
22 case GL_TEXTURE:
23 object_label = "Texture@" + nice_addr;
24 break;
25 case GL_PROGRAM:
26 object_label = "Shader@" + nice_addr;
27 break;
28 default:
29 object_label = fmt::format("Object(0x{:x})@{}", identifier, nice_addr);
30 break;
31 }
32 } else {
33 object_label = extra_info + '@' + nice_addr;
34 }
35 glObjectLabel(identifier, handle, -1, static_cast<const GLchar*>(object_label.c_str()));
36}
37
38} // namespace OpenGL \ No newline at end of file
diff --git a/src/video_core/renderer_opengl/utils.h b/src/video_core/renderer_opengl/utils.h
new file mode 100644
index 000000000..1fcb6fc11
--- /dev/null
+++ b/src/video_core/renderer_opengl/utils.h
@@ -0,0 +1,15 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <string>
8#include <glad/glad.h>
9#include "common/common_types.h"
10
11namespace OpenGL {
12
13void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr, std::string extra_info = "");
14
15} // namespace OpenGL \ No newline at end of file
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
new file mode 100644
index 000000000..d9a97e30b
--- /dev/null
+++ b/src/video_core/surface.cpp
@@ -0,0 +1,499 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/common_types.h"
6#include "common/math_util.h"
7#include "video_core/surface.h"
8
9namespace VideoCore::Surface {
10
11SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) {
12 switch (texture_type) {
13 case Tegra::Texture::TextureType::Texture1D:
14 return SurfaceTarget::Texture1D;
15 case Tegra::Texture::TextureType::Texture2D:
16 case Tegra::Texture::TextureType::Texture2DNoMipmap:
17 return SurfaceTarget::Texture2D;
18 case Tegra::Texture::TextureType::Texture3D:
19 return SurfaceTarget::Texture3D;
20 case Tegra::Texture::TextureType::TextureCubemap:
21 return SurfaceTarget::TextureCubemap;
22 case Tegra::Texture::TextureType::Texture1DArray:
23 return SurfaceTarget::Texture1DArray;
24 case Tegra::Texture::TextureType::Texture2DArray:
25 return SurfaceTarget::Texture2DArray;
26 default:
27 LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type));
28 UNREACHABLE();
29 return SurfaceTarget::Texture2D;
30 }
31}
32
33bool SurfaceTargetIsLayered(SurfaceTarget target) {
34 switch (target) {
35 case SurfaceTarget::Texture1D:
36 case SurfaceTarget::Texture2D:
37 case SurfaceTarget::Texture3D:
38 return false;
39 case SurfaceTarget::Texture1DArray:
40 case SurfaceTarget::Texture2DArray:
41 case SurfaceTarget::TextureCubemap:
42 return true;
43 default:
44 LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
45 UNREACHABLE();
46 return false;
47 }
48}
49
50PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
51 switch (format) {
52 case Tegra::DepthFormat::S8_Z24_UNORM:
53 return PixelFormat::S8Z24;
54 case Tegra::DepthFormat::Z24_S8_UNORM:
55 return PixelFormat::Z24S8;
56 case Tegra::DepthFormat::Z32_FLOAT:
57 return PixelFormat::Z32F;
58 case Tegra::DepthFormat::Z16_UNORM:
59 return PixelFormat::Z16;
60 case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
61 return PixelFormat::Z32FS8;
62 default:
63 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
64 UNREACHABLE();
65 }
66}
67
68PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
69 switch (format) {
70 // TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the
71 // gamma.
72 case Tegra::RenderTargetFormat::RGBA8_SRGB:
73 return PixelFormat::RGBA8_SRGB;
74 case Tegra::RenderTargetFormat::RGBA8_UNORM:
75 return PixelFormat::ABGR8U;
76 case Tegra::RenderTargetFormat::RGBA8_SNORM:
77 return PixelFormat::ABGR8S;
78 case Tegra::RenderTargetFormat::RGBA8_UINT:
79 return PixelFormat::ABGR8UI;
80 case Tegra::RenderTargetFormat::BGRA8_SRGB:
81 return PixelFormat::BGRA8_SRGB;
82 case Tegra::RenderTargetFormat::BGRA8_UNORM:
83 return PixelFormat::BGRA8;
84 case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
85 return PixelFormat::A2B10G10R10U;
86 case Tegra::RenderTargetFormat::RGBA16_FLOAT:
87 return PixelFormat::RGBA16F;
88 case Tegra::RenderTargetFormat::RGBA16_UNORM:
89 return PixelFormat::RGBA16U;
90 case Tegra::RenderTargetFormat::RGBA16_UINT:
91 return PixelFormat::RGBA16UI;
92 case Tegra::RenderTargetFormat::RGBA32_FLOAT:
93 return PixelFormat::RGBA32F;
94 case Tegra::RenderTargetFormat::RG32_FLOAT:
95 return PixelFormat::RG32F;
96 case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
97 return PixelFormat::R11FG11FB10F;
98 case Tegra::RenderTargetFormat::B5G6R5_UNORM:
99 return PixelFormat::B5G6R5U;
100 case Tegra::RenderTargetFormat::BGR5A1_UNORM:
101 return PixelFormat::A1B5G5R5U;
102 case Tegra::RenderTargetFormat::RGBA32_UINT:
103 return PixelFormat::RGBA32UI;
104 case Tegra::RenderTargetFormat::R8_UNORM:
105 return PixelFormat::R8U;
106 case Tegra::RenderTargetFormat::R8_UINT:
107 return PixelFormat::R8UI;
108 case Tegra::RenderTargetFormat::RG16_FLOAT:
109 return PixelFormat::RG16F;
110 case Tegra::RenderTargetFormat::RG16_UINT:
111 return PixelFormat::RG16UI;
112 case Tegra::RenderTargetFormat::RG16_SINT:
113 return PixelFormat::RG16I;
114 case Tegra::RenderTargetFormat::RG16_UNORM:
115 return PixelFormat::RG16;
116 case Tegra::RenderTargetFormat::RG16_SNORM:
117 return PixelFormat::RG16S;
118 case Tegra::RenderTargetFormat::RG8_UNORM:
119 return PixelFormat::RG8U;
120 case Tegra::RenderTargetFormat::RG8_SNORM:
121 return PixelFormat::RG8S;
122 case Tegra::RenderTargetFormat::R16_FLOAT:
123 return PixelFormat::R16F;
124 case Tegra::RenderTargetFormat::R16_UNORM:
125 return PixelFormat::R16U;
126 case Tegra::RenderTargetFormat::R16_SNORM:
127 return PixelFormat::R16S;
128 case Tegra::RenderTargetFormat::R16_UINT:
129 return PixelFormat::R16UI;
130 case Tegra::RenderTargetFormat::R16_SINT:
131 return PixelFormat::R16I;
132 case Tegra::RenderTargetFormat::R32_FLOAT:
133 return PixelFormat::R32F;
134 case Tegra::RenderTargetFormat::R32_UINT:
135 return PixelFormat::R32UI;
136 case Tegra::RenderTargetFormat::RG32_UINT:
137 return PixelFormat::RG32UI;
138 default:
139 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
140 UNREACHABLE();
141 }
142}
143
144PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
145 Tegra::Texture::ComponentType component_type,
146 bool is_srgb) {
147 // TODO(Subv): Properly implement this
148 switch (format) {
149 case Tegra::Texture::TextureFormat::A8R8G8B8:
150 if (is_srgb) {
151 return PixelFormat::RGBA8_SRGB;
152 }
153 switch (component_type) {
154 case Tegra::Texture::ComponentType::UNORM:
155 return PixelFormat::ABGR8U;
156 case Tegra::Texture::ComponentType::SNORM:
157 return PixelFormat::ABGR8S;
158 case Tegra::Texture::ComponentType::UINT:
159 return PixelFormat::ABGR8UI;
160 }
161 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
162 UNREACHABLE();
163 case Tegra::Texture::TextureFormat::B5G6R5:
164 switch (component_type) {
165 case Tegra::Texture::ComponentType::UNORM:
166 return PixelFormat::B5G6R5U;
167 }
168 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
169 UNREACHABLE();
170 case Tegra::Texture::TextureFormat::A2B10G10R10:
171 switch (component_type) {
172 case Tegra::Texture::ComponentType::UNORM:
173 return PixelFormat::A2B10G10R10U;
174 }
175 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
176 UNREACHABLE();
177 case Tegra::Texture::TextureFormat::A1B5G5R5:
178 switch (component_type) {
179 case Tegra::Texture::ComponentType::UNORM:
180 return PixelFormat::A1B5G5R5U;
181 }
182 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
183 UNREACHABLE();
184 case Tegra::Texture::TextureFormat::R8:
185 switch (component_type) {
186 case Tegra::Texture::ComponentType::UNORM:
187 return PixelFormat::R8U;
188 case Tegra::Texture::ComponentType::UINT:
189 return PixelFormat::R8UI;
190 }
191 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
192 UNREACHABLE();
193 case Tegra::Texture::TextureFormat::G8R8:
194 switch (component_type) {
195 case Tegra::Texture::ComponentType::UNORM:
196 return PixelFormat::G8R8U;
197 case Tegra::Texture::ComponentType::SNORM:
198 return PixelFormat::G8R8S;
199 }
200 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
201 UNREACHABLE();
202 case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
203 switch (component_type) {
204 case Tegra::Texture::ComponentType::UNORM:
205 return PixelFormat::RGBA16U;
206 case Tegra::Texture::ComponentType::FLOAT:
207 return PixelFormat::RGBA16F;
208 }
209 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
210 UNREACHABLE();
211 case Tegra::Texture::TextureFormat::BF10GF11RF11:
212 switch (component_type) {
213 case Tegra::Texture::ComponentType::FLOAT:
214 return PixelFormat::R11FG11FB10F;
215 }
216 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
217 UNREACHABLE();
218 case Tegra::Texture::TextureFormat::R32_G32_B32_A32:
219 switch (component_type) {
220 case Tegra::Texture::ComponentType::FLOAT:
221 return PixelFormat::RGBA32F;
222 case Tegra::Texture::ComponentType::UINT:
223 return PixelFormat::RGBA32UI;
224 }
225 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
226 UNREACHABLE();
227 case Tegra::Texture::TextureFormat::R32_G32:
228 switch (component_type) {
229 case Tegra::Texture::ComponentType::FLOAT:
230 return PixelFormat::RG32F;
231 case Tegra::Texture::ComponentType::UINT:
232 return PixelFormat::RG32UI;
233 }
234 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
235 UNREACHABLE();
236 case Tegra::Texture::TextureFormat::R32_G32_B32:
237 switch (component_type) {
238 case Tegra::Texture::ComponentType::FLOAT:
239 return PixelFormat::RGB32F;
240 }
241 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
242 UNREACHABLE();
243 case Tegra::Texture::TextureFormat::R16:
244 switch (component_type) {
245 case Tegra::Texture::ComponentType::FLOAT:
246 return PixelFormat::R16F;
247 case Tegra::Texture::ComponentType::UNORM:
248 return PixelFormat::R16U;
249 case Tegra::Texture::ComponentType::SNORM:
250 return PixelFormat::R16S;
251 case Tegra::Texture::ComponentType::UINT:
252 return PixelFormat::R16UI;
253 case Tegra::Texture::ComponentType::SINT:
254 return PixelFormat::R16I;
255 }
256 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
257 UNREACHABLE();
258 case Tegra::Texture::TextureFormat::R32:
259 switch (component_type) {
260 case Tegra::Texture::ComponentType::FLOAT:
261 return PixelFormat::R32F;
262 case Tegra::Texture::ComponentType::UINT:
263 return PixelFormat::R32UI;
264 }
265 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
266 UNREACHABLE();
267 case Tegra::Texture::TextureFormat::ZF32:
268 return PixelFormat::Z32F;
269 case Tegra::Texture::TextureFormat::Z16:
270 return PixelFormat::Z16;
271 case Tegra::Texture::TextureFormat::Z24S8:
272 return PixelFormat::Z24S8;
273 case Tegra::Texture::TextureFormat::DXT1:
274 return is_srgb ? PixelFormat::DXT1_SRGB : PixelFormat::DXT1;
275 case Tegra::Texture::TextureFormat::DXT23:
276 return is_srgb ? PixelFormat::DXT23_SRGB : PixelFormat::DXT23;
277 case Tegra::Texture::TextureFormat::DXT45:
278 return is_srgb ? PixelFormat::DXT45_SRGB : PixelFormat::DXT45;
279 case Tegra::Texture::TextureFormat::DXN1:
280 return PixelFormat::DXN1;
281 case Tegra::Texture::TextureFormat::DXN2:
282 switch (component_type) {
283 case Tegra::Texture::ComponentType::UNORM:
284 return PixelFormat::DXN2UNORM;
285 case Tegra::Texture::ComponentType::SNORM:
286 return PixelFormat::DXN2SNORM;
287 }
288 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
289 UNREACHABLE();
290 case Tegra::Texture::TextureFormat::BC7U:
291 return is_srgb ? PixelFormat::BC7U_SRGB : PixelFormat::BC7U;
292 case Tegra::Texture::TextureFormat::BC6H_UF16:
293 return PixelFormat::BC6H_UF16;
294 case Tegra::Texture::TextureFormat::BC6H_SF16:
295 return PixelFormat::BC6H_SF16;
296 case Tegra::Texture::TextureFormat::ASTC_2D_4X4:
297 return is_srgb ? PixelFormat::ASTC_2D_4X4_SRGB : PixelFormat::ASTC_2D_4X4;
298 case Tegra::Texture::TextureFormat::ASTC_2D_5X4:
299 return is_srgb ? PixelFormat::ASTC_2D_5X4_SRGB : PixelFormat::ASTC_2D_5X4;
300 case Tegra::Texture::TextureFormat::ASTC_2D_8X8:
301 return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8;
302 case Tegra::Texture::TextureFormat::ASTC_2D_8X5:
303 return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5;
304 case Tegra::Texture::TextureFormat::R16_G16:
305 switch (component_type) {
306 case Tegra::Texture::ComponentType::FLOAT:
307 return PixelFormat::RG16F;
308 case Tegra::Texture::ComponentType::UNORM:
309 return PixelFormat::RG16;
310 case Tegra::Texture::ComponentType::SNORM:
311 return PixelFormat::RG16S;
312 case Tegra::Texture::ComponentType::UINT:
313 return PixelFormat::RG16UI;
314 case Tegra::Texture::ComponentType::SINT:
315 return PixelFormat::RG16I;
316 }
317 LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
318 UNREACHABLE();
319 default:
320 LOG_CRITICAL(HW_GPU, "Unimplemented format={}, component_type={}", static_cast<u32>(format),
321 static_cast<u32>(component_type));
322 UNREACHABLE();
323 }
324}
325
326ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
327 // TODO(Subv): Implement more component types
328 switch (type) {
329 case Tegra::Texture::ComponentType::UNORM:
330 return ComponentType::UNorm;
331 case Tegra::Texture::ComponentType::FLOAT:
332 return ComponentType::Float;
333 case Tegra::Texture::ComponentType::SNORM:
334 return ComponentType::SNorm;
335 case Tegra::Texture::ComponentType::UINT:
336 return ComponentType::UInt;
337 case Tegra::Texture::ComponentType::SINT:
338 return ComponentType::SInt;
339 default:
340 LOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type));
341 UNREACHABLE();
342 }
343}
344
345ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) {
346 // TODO(Subv): Implement more render targets
347 switch (format) {
348 case Tegra::RenderTargetFormat::RGBA8_UNORM:
349 case Tegra::RenderTargetFormat::RGBA8_SRGB:
350 case Tegra::RenderTargetFormat::BGRA8_UNORM:
351 case Tegra::RenderTargetFormat::BGRA8_SRGB:
352 case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
353 case Tegra::RenderTargetFormat::R8_UNORM:
354 case Tegra::RenderTargetFormat::RG16_UNORM:
355 case Tegra::RenderTargetFormat::R16_UNORM:
356 case Tegra::RenderTargetFormat::B5G6R5_UNORM:
357 case Tegra::RenderTargetFormat::BGR5A1_UNORM:
358 case Tegra::RenderTargetFormat::RG8_UNORM:
359 case Tegra::RenderTargetFormat::RGBA16_UNORM:
360 return ComponentType::UNorm;
361 case Tegra::RenderTargetFormat::RGBA8_SNORM:
362 case Tegra::RenderTargetFormat::RG16_SNORM:
363 case Tegra::RenderTargetFormat::R16_SNORM:
364 case Tegra::RenderTargetFormat::RG8_SNORM:
365 return ComponentType::SNorm;
366 case Tegra::RenderTargetFormat::RGBA16_FLOAT:
367 case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
368 case Tegra::RenderTargetFormat::RGBA32_FLOAT:
369 case Tegra::RenderTargetFormat::RG32_FLOAT:
370 case Tegra::RenderTargetFormat::RG16_FLOAT:
371 case Tegra::RenderTargetFormat::R16_FLOAT:
372 case Tegra::RenderTargetFormat::R32_FLOAT:
373 return ComponentType::Float;
374 case Tegra::RenderTargetFormat::RGBA32_UINT:
375 case Tegra::RenderTargetFormat::RGBA16_UINT:
376 case Tegra::RenderTargetFormat::RG16_UINT:
377 case Tegra::RenderTargetFormat::R8_UINT:
378 case Tegra::RenderTargetFormat::R16_UINT:
379 case Tegra::RenderTargetFormat::RG32_UINT:
380 case Tegra::RenderTargetFormat::R32_UINT:
381 case Tegra::RenderTargetFormat::RGBA8_UINT:
382 return ComponentType::UInt;
383 case Tegra::RenderTargetFormat::RG16_SINT:
384 case Tegra::RenderTargetFormat::R16_SINT:
385 return ComponentType::SInt;
386 default:
387 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
388 UNREACHABLE();
389 }
390}
391
392PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
393 switch (format) {
394 case Tegra::FramebufferConfig::PixelFormat::ABGR8:
395 return PixelFormat::ABGR8U;
396 default:
397 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
398 UNREACHABLE();
399 }
400}
401
402ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format) {
403 switch (format) {
404 case Tegra::DepthFormat::Z16_UNORM:
405 case Tegra::DepthFormat::S8_Z24_UNORM:
406 case Tegra::DepthFormat::Z24_S8_UNORM:
407 return ComponentType::UNorm;
408 case Tegra::DepthFormat::Z32_FLOAT:
409 case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
410 return ComponentType::Float;
411 default:
412 LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
413 UNREACHABLE();
414 }
415}
416
417SurfaceType GetFormatType(PixelFormat pixel_format) {
418 if (static_cast<std::size_t>(pixel_format) <
419 static_cast<std::size_t>(PixelFormat::MaxColorFormat)) {
420 return SurfaceType::ColorTexture;
421 }
422
423 if (static_cast<std::size_t>(pixel_format) <
424 static_cast<std::size_t>(PixelFormat::MaxDepthFormat)) {
425 return SurfaceType::Depth;
426 }
427
428 if (static_cast<std::size_t>(pixel_format) <
429 static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) {
430 return SurfaceType::DepthStencil;
431 }
432
433 // TODO(Subv): Implement the other formats
434 ASSERT(false);
435
436 return SurfaceType::Invalid;
437}
438
439bool IsPixelFormatASTC(PixelFormat format) {
440 switch (format) {
441 case PixelFormat::ASTC_2D_4X4:
442 case PixelFormat::ASTC_2D_5X4:
443 case PixelFormat::ASTC_2D_8X8:
444 case PixelFormat::ASTC_2D_8X5:
445 case PixelFormat::ASTC_2D_4X4_SRGB:
446 case PixelFormat::ASTC_2D_5X4_SRGB:
447 case PixelFormat::ASTC_2D_8X8_SRGB:
448 case PixelFormat::ASTC_2D_8X5_SRGB:
449 return true;
450 default:
451 return false;
452 }
453}
454
455std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
456 switch (format) {
457 case PixelFormat::ASTC_2D_4X4:
458 return {4, 4};
459 case PixelFormat::ASTC_2D_5X4:
460 return {5, 4};
461 case PixelFormat::ASTC_2D_8X8:
462 return {8, 8};
463 case PixelFormat::ASTC_2D_8X5:
464 return {8, 5};
465 case PixelFormat::ASTC_2D_4X4_SRGB:
466 return {4, 4};
467 case PixelFormat::ASTC_2D_5X4_SRGB:
468 return {5, 4};
469 case PixelFormat::ASTC_2D_8X8_SRGB:
470 return {8, 8};
471 case PixelFormat::ASTC_2D_8X5_SRGB:
472 return {8, 5};
473 default:
474 LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format));
475 UNREACHABLE();
476 }
477}
478
479bool IsFormatBCn(PixelFormat format) {
480 switch (format) {
481 case PixelFormat::DXT1:
482 case PixelFormat::DXT23:
483 case PixelFormat::DXT45:
484 case PixelFormat::DXN1:
485 case PixelFormat::DXN2SNORM:
486 case PixelFormat::DXN2UNORM:
487 case PixelFormat::BC7U:
488 case PixelFormat::BC6H_UF16:
489 case PixelFormat::BC6H_SF16:
490 case PixelFormat::DXT1_SRGB:
491 case PixelFormat::DXT23_SRGB:
492 case PixelFormat::DXT45_SRGB:
493 case PixelFormat::BC7U_SRGB:
494 return true;
495 }
496 return false;
497}
498
499} // namespace VideoCore::Surface
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
new file mode 100644
index 000000000..3232e437f
--- /dev/null
+++ b/src/video_core/surface.h
@@ -0,0 +1,385 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <climits>
8#include <utility>
9#include "common/assert.h"
10#include "common/common_types.h"
11#include "common/logging/log.h"
12#include "video_core/gpu.h"
13#include "video_core/textures/texture.h"
14
15namespace VideoCore::Surface {
16
17enum class PixelFormat {
18 ABGR8U = 0,
19 ABGR8S = 1,
20 ABGR8UI = 2,
21 B5G6R5U = 3,
22 A2B10G10R10U = 4,
23 A1B5G5R5U = 5,
24 R8U = 6,
25 R8UI = 7,
26 RGBA16F = 8,
27 RGBA16U = 9,
28 RGBA16UI = 10,
29 R11FG11FB10F = 11,
30 RGBA32UI = 12,
31 DXT1 = 13,
32 DXT23 = 14,
33 DXT45 = 15,
34 DXN1 = 16, // This is also known as BC4
35 DXN2UNORM = 17,
36 DXN2SNORM = 18,
37 BC7U = 19,
38 BC6H_UF16 = 20,
39 BC6H_SF16 = 21,
40 ASTC_2D_4X4 = 22,
41 G8R8U = 23,
42 G8R8S = 24,
43 BGRA8 = 25,
44 RGBA32F = 26,
45 RG32F = 27,
46 R32F = 28,
47 R16F = 29,
48 R16U = 30,
49 R16S = 31,
50 R16UI = 32,
51 R16I = 33,
52 RG16 = 34,
53 RG16F = 35,
54 RG16UI = 36,
55 RG16I = 37,
56 RG16S = 38,
57 RGB32F = 39,
58 RGBA8_SRGB = 40,
59 RG8U = 41,
60 RG8S = 42,
61 RG32UI = 43,
62 R32UI = 44,
63 ASTC_2D_8X8 = 45,
64 ASTC_2D_8X5 = 46,
65 ASTC_2D_5X4 = 47,
66 BGRA8_SRGB = 48,
67 DXT1_SRGB = 49,
68 DXT23_SRGB = 50,
69 DXT45_SRGB = 51,
70 BC7U_SRGB = 52,
71 ASTC_2D_4X4_SRGB = 53,
72 ASTC_2D_8X8_SRGB = 54,
73 ASTC_2D_8X5_SRGB = 55,
74 ASTC_2D_5X4_SRGB = 56,
75
76 MaxColorFormat,
77
78 // Depth formats
79 Z32F = 57,
80 Z16 = 58,
81
82 MaxDepthFormat,
83
84 // DepthStencil formats
85 Z24S8 = 59,
86 S8Z24 = 60,
87 Z32FS8 = 61,
88
89 MaxDepthStencilFormat,
90
91 Max = MaxDepthStencilFormat,
92 Invalid = 255,
93};
94
95static constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max);
96
97enum class ComponentType {
98 Invalid = 0,
99 SNorm = 1,
100 UNorm = 2,
101 SInt = 3,
102 UInt = 4,
103 Float = 5,
104};
105
106enum class SurfaceType {
107 ColorTexture = 0,
108 Depth = 1,
109 DepthStencil = 2,
110 Fill = 3,
111 Invalid = 4,
112};
113
114enum class SurfaceTarget {
115 Texture1D,
116 Texture2D,
117 Texture3D,
118 Texture1DArray,
119 Texture2DArray,
120 TextureCubemap,
121};
122
123/**
124 * Gets the compression factor for the specified PixelFormat. This applies to just the
125 * "compressed width" and "compressed height", not the overall compression factor of a
126 * compressed image. This is used for maintaining proper surface sizes for compressed
127 * texture formats.
128 */
129static constexpr u32 GetCompressionFactor(PixelFormat format) {
130 if (format == PixelFormat::Invalid)
131 return 0;
132
133 constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
134 1, // ABGR8U
135 1, // ABGR8S
136 1, // ABGR8UI
137 1, // B5G6R5U
138 1, // A2B10G10R10U
139 1, // A1B5G5R5U
140 1, // R8U
141 1, // R8UI
142 1, // RGBA16F
143 1, // RGBA16U
144 1, // RGBA16UI
145 1, // R11FG11FB10F
146 1, // RGBA32UI
147 4, // DXT1
148 4, // DXT23
149 4, // DXT45
150 4, // DXN1
151 4, // DXN2UNORM
152 4, // DXN2SNORM
153 4, // BC7U
154 4, // BC6H_UF16
155 4, // BC6H_SF16
156 4, // ASTC_2D_4X4
157 1, // G8R8U
158 1, // G8R8S
159 1, // BGRA8
160 1, // RGBA32F
161 1, // RG32F
162 1, // R32F
163 1, // R16F
164 1, // R16U
165 1, // R16S
166 1, // R16UI
167 1, // R16I
168 1, // RG16
169 1, // RG16F
170 1, // RG16UI
171 1, // RG16I
172 1, // RG16S
173 1, // RGB32F
174 1, // RGBA8_SRGB
175 1, // RG8U
176 1, // RG8S
177 1, // RG32UI
178 1, // R32UI
179 4, // ASTC_2D_8X8
180 4, // ASTC_2D_8X5
181 4, // ASTC_2D_5X4
182 1, // BGRA8_SRGB
183 4, // DXT1_SRGB
184 4, // DXT23_SRGB
185 4, // DXT45_SRGB
186 4, // BC7U_SRGB
187 4, // ASTC_2D_4X4_SRGB
188 4, // ASTC_2D_8X8_SRGB
189 4, // ASTC_2D_8X5_SRGB
190 4, // ASTC_2D_5X4_SRGB
191 1, // Z32F
192 1, // Z16
193 1, // Z24S8
194 1, // S8Z24
195 1, // Z32FS8
196 }};
197
198 ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
199 return compression_factor_table[static_cast<std::size_t>(format)];
200}
201
202static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
203 if (format == PixelFormat::Invalid)
204 return 0;
205
206 constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
207 1, // ABGR8U
208 1, // ABGR8S
209 1, // ABGR8UI
210 1, // B5G6R5U
211 1, // A2B10G10R10U
212 1, // A1B5G5R5U
213 1, // R8U
214 1, // R8UI
215 1, // RGBA16F
216 1, // RGBA16U
217 1, // RGBA16UI
218 1, // R11FG11FB10F
219 1, // RGBA32UI
220 4, // DXT1
221 4, // DXT23
222 4, // DXT45
223 4, // DXN1
224 4, // DXN2UNORM
225 4, // DXN2SNORM
226 4, // BC7U
227 4, // BC6H_UF16
228 4, // BC6H_SF16
229 4, // ASTC_2D_4X4
230 1, // G8R8U
231 1, // G8R8S
232 1, // BGRA8
233 1, // RGBA32F
234 1, // RG32F
235 1, // R32F
236 1, // R16F
237 1, // R16U
238 1, // R16S
239 1, // R16UI
240 1, // R16I
241 1, // RG16
242 1, // RG16F
243 1, // RG16UI
244 1, // RG16I
245 1, // RG16S
246 1, // RGB32F
247 1, // RGBA8_SRGB
248 1, // RG8U
249 1, // RG8S
250 1, // RG32UI
251 1, // R32UI
252 8, // ASTC_2D_8X8
253 5, // ASTC_2D_8X5
254 4, // ASTC_2D_5X4
255 1, // BGRA8_SRGB
256 4, // DXT1_SRGB
257 4, // DXT23_SRGB
258 4, // DXT45_SRGB
259 4, // BC7U_SRGB
260 4, // ASTC_2D_4X4_SRGB
261 8, // ASTC_2D_8X8_SRGB
262 5, // ASTC_2D_8X5_SRGB
263 4, // ASTC_2D_5X4_SRGB
264 1, // Z32F
265 1, // Z16
266 1, // Z24S8
267 1, // S8Z24
268 1, // Z32FS8
269 }};
270
271 ASSERT(static_cast<std::size_t>(format) < block_height_table.size());
272 return block_height_table[static_cast<std::size_t>(format)];
273}
274
275static constexpr u32 GetFormatBpp(PixelFormat format) {
276 if (format == PixelFormat::Invalid)
277 return 0;
278
279 constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
280 32, // ABGR8U
281 32, // ABGR8S
282 32, // ABGR8UI
283 16, // B5G6R5U
284 32, // A2B10G10R10U
285 16, // A1B5G5R5U
286 8, // R8U
287 8, // R8UI
288 64, // RGBA16F
289 64, // RGBA16U
290 64, // RGBA16UI
291 32, // R11FG11FB10F
292 128, // RGBA32UI
293 64, // DXT1
294 128, // DXT23
295 128, // DXT45
296 64, // DXN1
297 128, // DXN2UNORM
298 128, // DXN2SNORM
299 128, // BC7U
300 128, // BC6H_UF16
301 128, // BC6H_SF16
302 32, // ASTC_2D_4X4
303 16, // G8R8U
304 16, // G8R8S
305 32, // BGRA8
306 128, // RGBA32F
307 64, // RG32F
308 32, // R32F
309 16, // R16F
310 16, // R16U
311 16, // R16S
312 16, // R16UI
313 16, // R16I
314 32, // RG16
315 32, // RG16F
316 32, // RG16UI
317 32, // RG16I
318 32, // RG16S
319 96, // RGB32F
320 32, // RGBA8_SRGB
321 16, // RG8U
322 16, // RG8S
323 64, // RG32UI
324 32, // R32UI
325 16, // ASTC_2D_8X8
326 16, // ASTC_2D_8X5
327 32, // ASTC_2D_5X4
328 32, // BGRA8_SRGB
329 64, // DXT1_SRGB
330 128, // DXT23_SRGB
331 128, // DXT45_SRGB
332 128, // BC7U
333 32, // ASTC_2D_4X4_SRGB
334 16, // ASTC_2D_8X8_SRGB
335 16, // ASTC_2D_8X5_SRGB
336 32, // ASTC_2D_5X4_SRGB
337 32, // Z32F
338 16, // Z16
339 32, // Z24S8
340 32, // S8Z24
341 64, // Z32FS8
342 }};
343
344 ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
345 return bpp_table[static_cast<std::size_t>(format)];
346}
347
348/// Returns the sizer in bytes of the specified pixel format
349static constexpr u32 GetBytesPerPixel(PixelFormat pixel_format) {
350 if (pixel_format == PixelFormat::Invalid) {
351 return 0;
352 }
353 return GetFormatBpp(pixel_format) / CHAR_BIT;
354}
355
356SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type);
357
358bool SurfaceTargetIsLayered(SurfaceTarget target);
359
360PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format);
361
362PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format);
363
364PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
365 Tegra::Texture::ComponentType component_type,
366 bool is_srgb);
367
368ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type);
369
370ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format);
371
372PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format);
373
374ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format);
375
376SurfaceType GetFormatType(PixelFormat pixel_format);
377
378bool IsPixelFormatASTC(PixelFormat format);
379
380std::pair<u32, u32> GetASTCBlockSize(PixelFormat format);
381
382/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
383bool IsFormatBCn(PixelFormat format);
384
385} // namespace VideoCore::Surface
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index 4726f54a5..b390219e4 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -10,6 +10,12 @@
10 10
11namespace Tegra::Texture { 11namespace Tegra::Texture {
12 12
13// GOBSize constant. Calculated by 64 bytes in x multiplied by 8 y coords, represents
14// an small rect of (64/bytes_per_pixel)X8.
15inline std::size_t GetGOBSize() {
16 return 512;
17}
18
13/** 19/**
14 * Unswizzles a swizzled texture without changing its format. 20 * Unswizzles a swizzled texture without changing its format.
15 */ 21 */
diff --git a/src/video_core/utils.h b/src/video_core/utils.h
index 237cc1307..e0a14d48f 100644
--- a/src/video_core/utils.h
+++ b/src/video_core/utils.h
@@ -161,30 +161,4 @@ static inline void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixe
161 } 161 }
162} 162}
163 163
164static void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr,
165 std::string extra_info = "") {
166 if (!GLAD_GL_KHR_debug) {
167 return; // We don't need to throw an error as this is just for debugging
168 }
169 const std::string nice_addr = fmt::format("0x{:016x}", addr);
170 std::string object_label;
171
172 if (extra_info.empty()) {
173 switch (identifier) {
174 case GL_TEXTURE:
175 object_label = "Texture@" + nice_addr;
176 break;
177 case GL_PROGRAM:
178 object_label = "Shader@" + nice_addr;
179 break;
180 default:
181 object_label = fmt::format("Object(0x{:x})@{}", identifier, nice_addr);
182 break;
183 }
184 } else {
185 object_label = extra_info + '@' + nice_addr;
186 }
187 glObjectLabel(identifier, handle, -1, static_cast<const GLchar*>(object_label.c_str()));
188}
189
190} // namespace VideoCore 164} // namespace VideoCore
diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp
index 0a8f2bd9e..9156ce802 100644
--- a/src/web_service/telemetry_json.cpp
+++ b/src/web_service/telemetry_json.cpp
@@ -102,16 +102,27 @@ void TelemetryJson::Complete() {
102 impl->SerializeSection(Telemetry::FieldType::App, "App"); 102 impl->SerializeSection(Telemetry::FieldType::App, "App");
103 impl->SerializeSection(Telemetry::FieldType::Session, "Session"); 103 impl->SerializeSection(Telemetry::FieldType::Session, "Session");
104 impl->SerializeSection(Telemetry::FieldType::Performance, "Performance"); 104 impl->SerializeSection(Telemetry::FieldType::Performance, "Performance");
105 impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback");
106 impl->SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig"); 105 impl->SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig");
107 impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem"); 106 impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
108 107
109 auto content = impl->TopSection().dump(); 108 auto content = impl->TopSection().dump();
110 // Send the telemetry async but don't handle the errors since they were written to the log 109 // Send the telemetry async but don't handle the errors since they were written to the log
111 Common::DetachedTasks::AddTask( 110 Common::DetachedTasks::AddTask([host{impl->host}, content]() {
112 [host{impl->host}, username{impl->username}, token{impl->token}, content]() { 111 Client{host, "", ""}.PostJson("/telemetry", content, true);
113 Client{host, username, token}.PostJson("/telemetry", content, true); 112 });
114 }); 113}
114
115bool TelemetryJson::SubmitTestcase() {
116 impl->SerializeSection(Telemetry::FieldType::App, "App");
117 impl->SerializeSection(Telemetry::FieldType::Session, "Session");
118 impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback");
119 impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
120
121 auto content = impl->TopSection().dump();
122 Client client(impl->host, impl->username, impl->token);
123 auto value = client.PostJson("/gamedb/testcase", content, false);
124
125 return value.result_code == Common::WebResult::Code::Success;
115} 126}
116 127
117} // namespace WebService 128} // namespace WebService
diff --git a/src/web_service/telemetry_json.h b/src/web_service/telemetry_json.h
index 93371414a..dfd202829 100644
--- a/src/web_service/telemetry_json.h
+++ b/src/web_service/telemetry_json.h
@@ -35,6 +35,7 @@ public:
35 void Visit(const Telemetry::Field<std::chrono::microseconds>& field) override; 35 void Visit(const Telemetry::Field<std::chrono::microseconds>& field) override;
36 36
37 void Complete() override; 37 void Complete() override;
38 bool SubmitTestcase() override;
38 39
39private: 40private:
40 struct Impl; 41 struct Impl;
diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp
index 91e754274..5f0896f84 100644
--- a/src/yuzu/compatdb.cpp
+++ b/src/yuzu/compatdb.cpp
@@ -5,6 +5,7 @@
5#include <QButtonGroup> 5#include <QButtonGroup>
6#include <QMessageBox> 6#include <QMessageBox>
7#include <QPushButton> 7#include <QPushButton>
8#include <QtConcurrent/qtconcurrentrun.h>
8#include "common/logging/log.h" 9#include "common/logging/log.h"
9#include "common/telemetry.h" 10#include "common/telemetry.h"
10#include "core/core.h" 11#include "core/core.h"
@@ -23,6 +24,8 @@ CompatDB::CompatDB(QWidget* parent)
23 connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext); 24 connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext);
24 connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext); 25 connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext);
25 connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit); 26 connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit);
27 connect(&testcase_watcher, &QFutureWatcher<bool>::finished, this,
28 &CompatDB::OnTestcaseSubmitted);
26} 29}
27 30
28CompatDB::~CompatDB() = default; 31CompatDB::~CompatDB() = default;
@@ -48,18 +51,38 @@ void CompatDB::Submit() {
48 } 51 }
49 break; 52 break;
50 case CompatDBPage::Final: 53 case CompatDBPage::Final:
54 back();
51 LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId()); 55 LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId());
52 Core::Telemetry().AddField(Telemetry::FieldType::UserFeedback, "Compatibility", 56 Core::Telemetry().AddField(Telemetry::FieldType::UserFeedback, "Compatibility",
53 compatibility->checkedId()); 57 compatibility->checkedId());
54 // older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a 58
55 // workaround 59 button(NextButton)->setEnabled(false);
60 button(NextButton)->setText(tr("Submitting"));
56 button(QWizard::CancelButton)->setVisible(false); 61 button(QWizard::CancelButton)->setVisible(false);
62
63 testcase_watcher.setFuture(QtConcurrent::run(
64 [this]() { return Core::System::GetInstance().TelemetrySession().SubmitTestcase(); }));
57 break; 65 break;
58 default: 66 default:
59 LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); 67 LOG_ERROR(Frontend, "Unexpected page: {}", currentId());
60 } 68 }
61} 69}
62 70
71void CompatDB::OnTestcaseSubmitted() {
72 if (!testcase_watcher.result()) {
73 QMessageBox::critical(this, tr("Communication error"),
74 tr("An error occured while sending the Testcase"));
75 button(NextButton)->setEnabled(true);
76 button(NextButton)->setText(tr("Next"));
77 button(QWizard::CancelButton)->setVisible(true);
78 } else {
79 next();
80 // older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a
81 // workaround
82 button(QWizard::CancelButton)->setVisible(false);
83 }
84}
85
63void CompatDB::EnableNext() { 86void CompatDB::EnableNext() {
64 button(NextButton)->setEnabled(true); 87 button(NextButton)->setEnabled(true);
65} 88}
diff --git a/src/yuzu/compatdb.h b/src/yuzu/compatdb.h
index ca0dd11d6..5381f67f7 100644
--- a/src/yuzu/compatdb.h
+++ b/src/yuzu/compatdb.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <QFutureWatcher>
8#include <QWizard> 9#include <QWizard>
9 10
10namespace Ui { 11namespace Ui {
@@ -19,8 +20,11 @@ public:
19 ~CompatDB(); 20 ~CompatDB();
20 21
21private: 22private:
23 QFutureWatcher<bool> testcase_watcher;
24
22 std::unique_ptr<Ui::CompatDB> ui; 25 std::unique_ptr<Ui::CompatDB> ui;
23 26
24 void Submit(); 27 void Submit();
28 void OnTestcaseSubmitted();
25 void EnableNext(); 29 void EnableNext();
26}; 30};
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 94789c064..42a7beac6 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -322,7 +322,7 @@ void ConfigureInput::setPollingResult(const Common::ParamPackage& params, bool a
322 } 322 }
323 323
324 updateButtonLabels(); 324 updateButtonLabels();
325 input_setter = boost::none; 325 input_setter = {};
326} 326}
327 327
328void ConfigureInput::keyPressEvent(QKeyEvent* event) { 328void ConfigureInput::keyPressEvent(QKeyEvent* event) {
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index d1198db81..32c7183f9 100644
--- a/src/yuzu/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
@@ -7,11 +7,13 @@
7#include <array> 7#include <array>
8#include <functional> 8#include <functional>
9#include <memory> 9#include <memory>
10#include <optional>
10#include <string> 11#include <string>
11#include <unordered_map> 12#include <unordered_map>
13
12#include <QKeyEvent> 14#include <QKeyEvent>
13#include <QWidget> 15#include <QWidget>
14#include <boost/optional.hpp> 16
15#include "common/param_package.h" 17#include "common/param_package.h"
16#include "core/settings.h" 18#include "core/settings.h"
17#include "input_common/main.h" 19#include "input_common/main.h"
@@ -41,7 +43,7 @@ private:
41 std::unique_ptr<QTimer> poll_timer; 43 std::unique_ptr<QTimer> poll_timer;
42 44
43 /// This will be the the setting function when an input is awaiting configuration. 45 /// This will be the the setting function when an input is awaiting configuration.
44 boost::optional<std::function<void(const Common::ParamPackage&)>> input_setter; 46 std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
45 47
46 std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param; 48 std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param;
47 std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param; 49 std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param;
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 4b34c1e28..1b8aa7de2 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -78,7 +78,7 @@ QPixmap GetIcon(Service::Account::UUID uuid) {
78 78
79 if (!icon) { 79 if (!icon) {
80 icon.fill(Qt::black); 80 icon.fill(Qt::black);
81 icon.loadFromData(backup_jpeg.data(), backup_jpeg.size()); 81 icon.loadFromData(backup_jpeg.data(), static_cast<u32>(backup_jpeg.size()));
82 } 82 }
83 83
84 return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); 84 return icon.scaled(64, 64, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
@@ -173,7 +173,7 @@ void ConfigureSystem::UpdateCurrentUser() {
173 ui->pm_add->setEnabled(profile_manager->GetUserCount() < Service::Account::MAX_USERS); 173 ui->pm_add->setEnabled(profile_manager->GetUserCount() < Service::Account::MAX_USERS);
174 174
175 const auto& current_user = profile_manager->GetUser(Settings::values.current_user); 175 const auto& current_user = profile_manager->GetUser(Settings::values.current_user);
176 ASSERT(current_user != std::nullopt); 176 ASSERT(current_user);
177 const auto username = GetAccountUsername(*profile_manager, *current_user); 177 const auto username = GetAccountUsername(*profile_manager, *current_user);
178 178
179 scene->clear(); 179 scene->clear();
@@ -261,7 +261,7 @@ void ConfigureSystem::AddUser() {
261void ConfigureSystem::RenameUser() { 261void ConfigureSystem::RenameUser() {
262 const auto user = tree_view->currentIndex().row(); 262 const auto user = tree_view->currentIndex().row();
263 const auto uuid = profile_manager->GetUser(user); 263 const auto uuid = profile_manager->GetUser(user);
264 ASSERT(uuid != std::nullopt); 264 ASSERT(uuid);
265 265
266 Service::Account::ProfileBase profile; 266 Service::Account::ProfileBase profile;
267 if (!profile_manager->GetProfileBase(*uuid, profile)) 267 if (!profile_manager->GetProfileBase(*uuid, profile))
@@ -297,7 +297,7 @@ void ConfigureSystem::RenameUser() {
297void ConfigureSystem::DeleteUser() { 297void ConfigureSystem::DeleteUser() {
298 const auto index = tree_view->currentIndex().row(); 298 const auto index = tree_view->currentIndex().row();
299 const auto uuid = profile_manager->GetUser(index); 299 const auto uuid = profile_manager->GetUser(index);
300 ASSERT(uuid != std::nullopt); 300 ASSERT(uuid);
301 const auto username = GetAccountUsername(*profile_manager, *uuid); 301 const auto username = GetAccountUsername(*profile_manager, *uuid);
302 302
303 const auto confirm = QMessageBox::question( 303 const auto confirm = QMessageBox::question(
@@ -324,7 +324,7 @@ void ConfigureSystem::DeleteUser() {
324void ConfigureSystem::SetUserImage() { 324void ConfigureSystem::SetUserImage() {
325 const auto index = tree_view->currentIndex().row(); 325 const auto index = tree_view->currentIndex().row();
326 const auto uuid = profile_manager->GetUser(index); 326 const auto uuid = profile_manager->GetUser(index);
327 ASSERT(uuid != std::nullopt); 327 ASSERT(uuid);
328 328
329 const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(), 329 const auto file = QFileDialog::getOpenFileName(this, tr("Select User Image"), QString(),
330 tr("JPEG Images (*.jpg *.jpeg)")); 330 tr("JPEG Images (*.jpg *.jpeg)"));
diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp
index 44d423da2..0adbab27d 100644
--- a/src/yuzu/debugger/graphics/graphics_surface.cpp
+++ b/src/yuzu/debugger/graphics/graphics_surface.cpp
@@ -382,7 +382,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
382 // TODO: Implement a good way to visualize alpha components! 382 // TODO: Implement a good way to visualize alpha components!
383 383
384 QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32); 384 QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32);
385 boost::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address); 385 std::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address);
386 386
387 // TODO(bunnei): Will not work with BCn formats that swizzle 4x4 tiles. 387 // TODO(bunnei): Will not work with BCn formats that swizzle 4x4 tiles.
388 // Needs to be fixed if we plan to use this feature more, otherwise we may remove it. 388 // Needs to be fixed if we plan to use this feature more, otherwise we may remove it.
@@ -444,7 +444,7 @@ void GraphicsSurfaceWidget::SaveSurface() {
444 pixmap->save(&file, "PNG"); 444 pixmap->save(&file, "PNG");
445 } else if (selectedFilter == bin_filter) { 445 } else if (selectedFilter == bin_filter) {
446 auto& gpu = Core::System::GetInstance().GPU(); 446 auto& gpu = Core::System::GetInstance().GPU();
447 boost::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address); 447 std::optional<VAddr> address = gpu.MemoryManager().GpuToCpuAddress(surface_address);
448 448
449 const u8* buffer = Memory::GetPointer(*address); 449 const u8* buffer = Memory::GetPointer(*address);
450 ASSERT_MSG(buffer != nullptr, "Memory not accessible"); 450 ASSERT_MSG(buffer != nullptr, "Memory not accessible");
diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h
index defbf734f..331f89885 100644
--- a/src/yuzu/debugger/wait_tree.h
+++ b/src/yuzu/debugger/wait_tree.h
@@ -11,7 +11,6 @@
11#include <QAbstractItemModel> 11#include <QAbstractItemModel>
12#include <QDockWidget> 12#include <QDockWidget>
13#include <QTreeView> 13#include <QTreeView>
14#include <boost/container/flat_set.hpp>
15#include "common/common_types.h" 14#include "common/common_types.h"
16#include "core/hle/kernel/object.h" 15#include "core/hle/kernel/object.h"
17 16
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index b5bfa6741..c5a56cbfd 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -786,7 +786,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
786 ASSERT(index != -1 && index < 8); 786 ASSERT(index != -1 && index < 8);
787 787
788 const auto user_id = manager.GetUser(index); 788 const auto user_id = manager.GetUser(index);
789 ASSERT(user_id != std::nullopt); 789 ASSERT(user_id);
790 path = nand_dir + FileSys::SaveDataFactory::GetFullPath(FileSys::SaveDataSpaceId::NandUser, 790 path = nand_dir + FileSys::SaveDataFactory::GetFullPath(FileSys::SaveDataSpaceId::NandUser,
791 FileSys::SaveDataType::SaveData, 791 FileSys::SaveDataType::SaveData,
792 program_id, user_id->uuid, 0); 792 program_id, user_id->uuid, 0);
@@ -1560,7 +1560,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
1560 } 1560 }
1561} 1561}
1562 1562
1563boost::optional<u64> GMainWindow::SelectRomFSDumpTarget( 1563std::optional<u64> GMainWindow::SelectRomFSDumpTarget(
1564 const FileSys::RegisteredCacheUnion& installed, u64 program_id) { 1564 const FileSys::RegisteredCacheUnion& installed, u64 program_id) {
1565 const auto dlc_entries = 1565 const auto dlc_entries =
1566 installed.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); 1566 installed.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
@@ -1587,7 +1587,7 @@ boost::optional<u64> GMainWindow::SelectRomFSDumpTarget(
1587 this, tr("Select RomFS Dump Target"), 1587 this, tr("Select RomFS Dump Target"),
1588 tr("Please select which RomFS you would like to dump."), list, 0, false, &ok); 1588 tr("Please select which RomFS you would like to dump."), list, 0, false, &ok);
1589 if (!ok) { 1589 if (!ok) {
1590 return boost::none; 1590 return {};
1591 } 1591 }
1592 1592
1593 return romfs_tids[list.indexOf(res)]; 1593 return romfs_tids[list.indexOf(res)];
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 7c7c223e1..af637d89e 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -5,12 +5,12 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <optional>
8#include <unordered_map> 9#include <unordered_map>
9 10
10#include <QMainWindow> 11#include <QMainWindow>
11#include <QTimer> 12#include <QTimer>
12 13
13#include <boost/optional.hpp>
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "core/core.h" 15#include "core/core.h"
16#include "ui_main.h" 16#include "ui_main.h"
@@ -178,8 +178,7 @@ private slots:
178 void OnReinitializeKeys(ReinitializeKeyBehavior behavior); 178 void OnReinitializeKeys(ReinitializeKeyBehavior behavior);
179 179
180private: 180private:
181 boost::optional<u64> SelectRomFSDumpTarget(const FileSys::RegisteredCacheUnion&, 181 std::optional<u64> SelectRomFSDumpTarget(const FileSys::RegisteredCacheUnion&, u64 program_id);
182 u64 program_id);
183 void UpdateStatusBar(); 182 void UpdateStatusBar();
184 183
185 Ui::MainWindow ui; 184 Ui::MainWindow ui;