summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/core.cpp29
-rw-r--r--src/core/hle/service/am/am.cpp5
-rw-r--r--src/core/hle/service/apm/controller.cpp50
-rw-r--r--src/core/hle/service/apm/controller.h2
-rw-r--r--src/core/hle/service/bcat/backend/backend.cpp4
-rw-r--r--src/core/hle/service/bcat/backend/backend.h12
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp29
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.h10
-rw-r--r--src/core/hle/service/bcat/module.cpp24
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp33
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp4
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp4
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp4
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h6
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp12
-rw-r--r--src/core/memory/cheat_engine.cpp7
-rw-r--r--src/core/memory/dmnt_cheat_vm.cpp4
-rw-r--r--src/video_core/engines/maxwell_3d.cpp5
-rw-r--r--src/video_core/gpu.cpp15
-rw-r--r--src/video_core/gpu.h6
-rw-r--r--src/video_core/gpu_asynch.cpp4
-rw-r--r--src/video_core/gpu_asynch.h1
-rw-r--r--src/video_core/gpu_synch.h1
-rw-r--r--src/video_core/gpu_thread.cpp19
-rw-r--r--src/video_core/gpu_thread.h9
-rw-r--r--src/video_core/macro_interpreter.cpp71
-rw-r--r--src/video_core/macro_interpreter.h80
-rw-r--r--src/video_core/morton.cpp22
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp64
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp13
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp44
-rw-r--r--src/video_core/shader/ast.cpp85
-rw-r--r--src/video_core/shader/ast.h6
-rw-r--r--src/video_core/shader/control_flow.cpp4
-rw-r--r--src/video_core/shader/control_flow.h4
-rw-r--r--src/video_core/shader/node.h2
-rw-r--r--src/video_core/surface.cpp34
-rw-r--r--src/video_core/surface.h222
-rw-r--r--src/video_core/texture_cache/texture_cache.h139
43 files changed, 671 insertions, 431 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 4d0ac72a5..b7b9259ec 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -112,8 +112,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
112} 112}
113struct System::Impl { 113struct System::Impl {
114 explicit Impl(System& system) 114 explicit Impl(System& system)
115 : kernel{system}, fs_controller{system}, cpu_core_manager{system}, 115 : kernel{system}, fs_controller{system}, cpu_core_manager{system}, reporter{system},
116 applet_manager{system}, reporter{system} {} 116 applet_manager{system} {}
117 117
118 Cpu& CurrentCpuCore() { 118 Cpu& CurrentCpuCore() {
119 return cpu_core_manager.GetCurrentCore(); 119 return cpu_core_manager.GetCurrentCore();
@@ -240,22 +240,27 @@ struct System::Impl {
240 } 240 }
241 241
242 void Shutdown() { 242 void Shutdown() {
243 // Log last frame performance stats 243 // Log last frame performance stats if game was loded
244 const auto perf_results = GetAndResetPerfStats(); 244 if (perf_stats) {
245 telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_EmulationSpeed", 245 const auto perf_results = GetAndResetPerfStats();
246 perf_results.emulation_speed * 100.0); 246 telemetry_session->AddField(Telemetry::FieldType::Performance,
247 telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate", 247 "Shutdown_EmulationSpeed",
248 perf_results.game_fps); 248 perf_results.emulation_speed * 100.0);
249 telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime", 249 telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate",
250 perf_results.frametime * 1000.0); 250 perf_results.game_fps);
251 telemetry_session->AddField(Telemetry::FieldType::Performance, "Mean_Frametime_MS", 251 telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
252 perf_stats->GetMeanFrametime()); 252 perf_results.frametime * 1000.0);
253 telemetry_session->AddField(Telemetry::FieldType::Performance, "Mean_Frametime_MS",
254 perf_stats->GetMeanFrametime());
255 }
253 256
254 lm_manager.Flush(); 257 lm_manager.Flush();
255 258
256 is_powered_on = false; 259 is_powered_on = false;
257 exit_lock = false; 260 exit_lock = false;
258 261
262 gpu_core->WaitIdle();
263
259 // Shutdown emulation session 264 // Shutdown emulation session
260 renderer.reset(); 265 renderer.reset();
261 GDBStub::Shutdown(); 266 GDBStub::Shutdown();
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 941ebc93a..3a32d5b41 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1140,8 +1140,9 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
1140 LOG_DEBUG(Service_AM, "called, kind={:08X}", static_cast<u8>(kind)); 1140 LOG_DEBUG(Service_AM, "called, kind={:08X}", static_cast<u8>(kind));
1141 1141
1142 if (kind == LaunchParameterKind::ApplicationSpecific && !launch_popped_application_specific) { 1142 if (kind == LaunchParameterKind::ApplicationSpecific && !launch_popped_application_specific) {
1143 const auto backend = BCAT::CreateBackendFromSettings( 1143 const auto backend = BCAT::CreateBackendFromSettings(system, [this](u64 tid) {
1144 [this](u64 tid) { return system.GetFileSystemController().GetBCATDirectory(tid); }); 1144 return system.GetFileSystemController().GetBCATDirectory(tid);
1145 });
1145 const auto build_id_full = system.GetCurrentProcessBuildID(); 1146 const auto build_id_full = system.GetCurrentProcessBuildID();
1146 u64 build_id{}; 1147 u64 build_id{};
1147 std::memcpy(&build_id, build_id_full.data(), sizeof(u64)); 1148 std::memcpy(&build_id, build_id_full.data(), sizeof(u64));
diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp
index 073d0f6fa..25a886238 100644
--- a/src/core/hle/service/apm/controller.cpp
+++ b/src/core/hle/service/apm/controller.cpp
@@ -2,6 +2,10 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <array>
7#include <utility>
8
5#include "common/logging/log.h" 9#include "common/logging/log.h"
6#include "core/core_timing.h" 10#include "core/core_timing.h"
7#include "core/hle/service/apm/controller.h" 11#include "core/hle/service/apm/controller.h"
@@ -9,8 +13,7 @@
9 13
10namespace Service::APM { 14namespace Service::APM {
11 15
12constexpr PerformanceConfiguration DEFAULT_PERFORMANCE_CONFIGURATION = 16constexpr auto DEFAULT_PERFORMANCE_CONFIGURATION = PerformanceConfiguration::Config7;
13 PerformanceConfiguration::Config7;
14 17
15Controller::Controller(Core::Timing::CoreTiming& core_timing) 18Controller::Controller(Core::Timing::CoreTiming& core_timing)
16 : core_timing{core_timing}, configs{ 19 : core_timing{core_timing}, configs{
@@ -22,18 +25,35 @@ Controller::~Controller() = default;
22 25
23void Controller::SetPerformanceConfiguration(PerformanceMode mode, 26void Controller::SetPerformanceConfiguration(PerformanceMode mode,
24 PerformanceConfiguration config) { 27 PerformanceConfiguration config) {
25 static const std::map<PerformanceConfiguration, u32> PCONFIG_TO_SPEED_MAP{ 28 static constexpr std::array<std::pair<PerformanceConfiguration, u32>, 16> config_to_speed{{
26 {PerformanceConfiguration::Config1, 1020}, {PerformanceConfiguration::Config2, 1020}, 29 {PerformanceConfiguration::Config1, 1020},
27 {PerformanceConfiguration::Config3, 1224}, {PerformanceConfiguration::Config4, 1020}, 30 {PerformanceConfiguration::Config2, 1020},
28 {PerformanceConfiguration::Config5, 1020}, {PerformanceConfiguration::Config6, 1224}, 31 {PerformanceConfiguration::Config3, 1224},
29 {PerformanceConfiguration::Config7, 1020}, {PerformanceConfiguration::Config8, 1020}, 32 {PerformanceConfiguration::Config4, 1020},
30 {PerformanceConfiguration::Config9, 1020}, {PerformanceConfiguration::Config10, 1020}, 33 {PerformanceConfiguration::Config5, 1020},
31 {PerformanceConfiguration::Config11, 1020}, {PerformanceConfiguration::Config12, 1020}, 34 {PerformanceConfiguration::Config6, 1224},
32 {PerformanceConfiguration::Config13, 1785}, {PerformanceConfiguration::Config14, 1785}, 35 {PerformanceConfiguration::Config7, 1020},
33 {PerformanceConfiguration::Config15, 1020}, {PerformanceConfiguration::Config16, 1020}, 36 {PerformanceConfiguration::Config8, 1020},
34 }; 37 {PerformanceConfiguration::Config9, 1020},
35 38 {PerformanceConfiguration::Config10, 1020},
36 SetClockSpeed(PCONFIG_TO_SPEED_MAP.find(config)->second); 39 {PerformanceConfiguration::Config11, 1020},
40 {PerformanceConfiguration::Config12, 1020},
41 {PerformanceConfiguration::Config13, 1785},
42 {PerformanceConfiguration::Config14, 1785},
43 {PerformanceConfiguration::Config15, 1020},
44 {PerformanceConfiguration::Config16, 1020},
45 }};
46
47 const auto iter = std::find_if(config_to_speed.cbegin(), config_to_speed.cend(),
48 [config](const auto& entry) { return entry.first == config; });
49
50 if (iter == config_to_speed.cend()) {
51 LOG_ERROR(Service_APM, "Invalid performance configuration value provided: {}",
52 static_cast<u32>(config));
53 return;
54 }
55
56 SetClockSpeed(iter->second);
37 configs.insert_or_assign(mode, config); 57 configs.insert_or_assign(mode, config);
38} 58}
39 59
@@ -48,7 +68,7 @@ void Controller::SetFromCpuBoostMode(CpuBoostMode mode) {
48 BOOST_MODE_TO_CONFIG_MAP.at(static_cast<u32>(mode))); 68 BOOST_MODE_TO_CONFIG_MAP.at(static_cast<u32>(mode)));
49} 69}
50 70
51PerformanceMode Controller::GetCurrentPerformanceMode() { 71PerformanceMode Controller::GetCurrentPerformanceMode() const {
52 return Settings::values.use_docked_mode ? PerformanceMode::Docked : PerformanceMode::Handheld; 72 return Settings::values.use_docked_mode ? PerformanceMode::Docked : PerformanceMode::Handheld;
53} 73}
54 74
diff --git a/src/core/hle/service/apm/controller.h b/src/core/hle/service/apm/controller.h
index 454caa6eb..af0c4cd34 100644
--- a/src/core/hle/service/apm/controller.h
+++ b/src/core/hle/service/apm/controller.h
@@ -56,7 +56,7 @@ public:
56 void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config); 56 void SetPerformanceConfiguration(PerformanceMode mode, PerformanceConfiguration config);
57 void SetFromCpuBoostMode(CpuBoostMode mode); 57 void SetFromCpuBoostMode(CpuBoostMode mode);
58 58
59 PerformanceMode GetCurrentPerformanceMode(); 59 PerformanceMode GetCurrentPerformanceMode() const;
60 PerformanceConfiguration GetCurrentPerformanceConfiguration(PerformanceMode mode); 60 PerformanceConfiguration GetCurrentPerformanceConfiguration(PerformanceMode mode);
61 61
62private: 62private:
diff --git a/src/core/hle/service/bcat/backend/backend.cpp b/src/core/hle/service/bcat/backend/backend.cpp
index 9d6946bc5..b86fda29a 100644
--- a/src/core/hle/service/bcat/backend/backend.cpp
+++ b/src/core/hle/service/bcat/backend/backend.cpp
@@ -10,8 +10,8 @@
10 10
11namespace Service::BCAT { 11namespace Service::BCAT {
12 12
13ProgressServiceBackend::ProgressServiceBackend(std::string_view event_name) { 13ProgressServiceBackend::ProgressServiceBackend(Kernel::KernelCore& kernel,
14 auto& kernel{Core::System::GetInstance().Kernel()}; 14 std::string_view event_name) {
15 event = Kernel::WritableEvent::CreateEventPair( 15 event = Kernel::WritableEvent::CreateEventPair(
16 kernel, Kernel::ResetType::Automatic, 16 kernel, Kernel::ResetType::Automatic,
17 std::string("ProgressServiceBackend:UpdateEvent:").append(event_name)); 17 std::string("ProgressServiceBackend:UpdateEvent:").append(event_name));
diff --git a/src/core/hle/service/bcat/backend/backend.h b/src/core/hle/service/bcat/backend/backend.h
index 51dbd3316..ea4b16ad0 100644
--- a/src/core/hle/service/bcat/backend/backend.h
+++ b/src/core/hle/service/bcat/backend/backend.h
@@ -15,6 +15,14 @@
15#include "core/hle/kernel/writable_event.h" 15#include "core/hle/kernel/writable_event.h"
16#include "core/hle/result.h" 16#include "core/hle/result.h"
17 17
18namespace Core {
19class System;
20}
21
22namespace Kernel {
23class KernelCore;
24}
25
18namespace Service::BCAT { 26namespace Service::BCAT {
19 27
20struct DeliveryCacheProgressImpl; 28struct DeliveryCacheProgressImpl;
@@ -88,7 +96,7 @@ public:
88 void FinishDownload(ResultCode result); 96 void FinishDownload(ResultCode result);
89 97
90private: 98private:
91 explicit ProgressServiceBackend(std::string_view event_name); 99 explicit ProgressServiceBackend(Kernel::KernelCore& kernel, std::string_view event_name);
92 100
93 Kernel::SharedPtr<Kernel::ReadableEvent> GetEvent() const; 101 Kernel::SharedPtr<Kernel::ReadableEvent> GetEvent() const;
94 DeliveryCacheProgressImpl& GetImpl(); 102 DeliveryCacheProgressImpl& GetImpl();
@@ -145,6 +153,6 @@ public:
145 std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) override; 153 std::optional<std::vector<u8>> GetLaunchParameter(TitleIDVersion title) override;
146}; 154};
147 155
148std::unique_ptr<Backend> CreateBackendFromSettings(DirectoryGetter getter); 156std::unique_ptr<Backend> CreateBackendFromSettings(Core::System& system, DirectoryGetter getter);
149 157
150} // namespace Service::BCAT 158} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp
index 64022982b..918159e11 100644
--- a/src/core/hle/service/bcat/backend/boxcat.cpp
+++ b/src/core/hle/service/bcat/backend/boxcat.cpp
@@ -104,14 +104,15 @@ std::string GetZIPFilePath(u64 title_id) {
104 104
105// If the error is something the user should know about (build ID mismatch, bad client version), 105// If the error is something the user should know about (build ID mismatch, bad client version),
106// display an error. 106// display an error.
107void HandleDownloadDisplayResult(DownloadResult res) { 107void HandleDownloadDisplayResult(const AM::Applets::AppletManager& applet_manager,
108 DownloadResult res) {
108 if (res == DownloadResult::Success || res == DownloadResult::NoResponse || 109 if (res == DownloadResult::Success || res == DownloadResult::NoResponse ||
109 res == DownloadResult::GeneralWebError || res == DownloadResult::GeneralFSError || 110 res == DownloadResult::GeneralWebError || res == DownloadResult::GeneralFSError ||
110 res == DownloadResult::NoMatchTitleId || res == DownloadResult::InvalidContentType) { 111 res == DownloadResult::NoMatchTitleId || res == DownloadResult::InvalidContentType) {
111 return; 112 return;
112 } 113 }
113 114
114 const auto& frontend{Core::System::GetInstance().GetAppletManager().GetAppletFrontendSet()}; 115 const auto& frontend{applet_manager.GetAppletFrontendSet()};
115 frontend.error->ShowCustomErrorText( 116 frontend.error->ShowCustomErrorText(
116 ResultCode(-1), "There was an error while attempting to use Boxcat.", 117 ResultCode(-1), "There was an error while attempting to use Boxcat.",
117 DOWNLOAD_RESULT_LOG_MESSAGES[static_cast<std::size_t>(res)], [] {}); 118 DOWNLOAD_RESULT_LOG_MESSAGES[static_cast<std::size_t>(res)], [] {});
@@ -264,12 +265,13 @@ private:
264 u64 build_id; 265 u64 build_id;
265}; 266};
266 267
267Boxcat::Boxcat(DirectoryGetter getter) : Backend(std::move(getter)) {} 268Boxcat::Boxcat(AM::Applets::AppletManager& applet_manager_, DirectoryGetter getter)
269 : Backend(std::move(getter)), applet_manager{applet_manager_} {}
268 270
269Boxcat::~Boxcat() = default; 271Boxcat::~Boxcat() = default;
270 272
271void SynchronizeInternal(DirectoryGetter dir_getter, TitleIDVersion title, 273void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGetter dir_getter,
272 ProgressServiceBackend& progress, 274 TitleIDVersion title, ProgressServiceBackend& progress,
273 std::optional<std::string> dir_name = {}) { 275 std::optional<std::string> dir_name = {}) {
274 progress.SetNeedHLELock(true); 276 progress.SetNeedHLELock(true);
275 277
@@ -295,7 +297,7 @@ void SynchronizeInternal(DirectoryGetter dir_getter, TitleIDVersion title,
295 FileUtil::Delete(zip_path); 297 FileUtil::Delete(zip_path);
296 } 298 }
297 299
298 HandleDownloadDisplayResult(res); 300 HandleDownloadDisplayResult(applet_manager, res);
299 progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); 301 progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE);
300 return; 302 return;
301 } 303 }
@@ -364,17 +366,24 @@ void SynchronizeInternal(DirectoryGetter dir_getter, TitleIDVersion title,
364 366
365bool Boxcat::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) { 367bool Boxcat::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) {
366 is_syncing.exchange(true); 368 is_syncing.exchange(true);
367 std::thread([this, title, &progress] { SynchronizeInternal(dir_getter, title, progress); }) 369
370 std::thread([this, title, &progress] {
371 SynchronizeInternal(applet_manager, dir_getter, title, progress);
372 })
368 .detach(); 373 .detach();
374
369 return true; 375 return true;
370} 376}
371 377
372bool Boxcat::SynchronizeDirectory(TitleIDVersion title, std::string name, 378bool Boxcat::SynchronizeDirectory(TitleIDVersion title, std::string name,
373 ProgressServiceBackend& progress) { 379 ProgressServiceBackend& progress) {
374 is_syncing.exchange(true); 380 is_syncing.exchange(true);
375 std::thread( 381
376 [this, title, name, &progress] { SynchronizeInternal(dir_getter, title, progress, name); }) 382 std::thread([this, title, name, &progress] {
383 SynchronizeInternal(applet_manager, dir_getter, title, progress, name);
384 })
377 .detach(); 385 .detach();
386
378 return true; 387 return true;
379} 388}
380 389
@@ -420,7 +429,7 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title)
420 FileUtil::Delete(path); 429 FileUtil::Delete(path);
421 } 430 }
422 431
423 HandleDownloadDisplayResult(res); 432 HandleDownloadDisplayResult(applet_manager, res);
424 return std::nullopt; 433 return std::nullopt;
425 } 434 }
426 } 435 }
diff --git a/src/core/hle/service/bcat/backend/boxcat.h b/src/core/hle/service/bcat/backend/boxcat.h
index 601151189..d65b42e58 100644
--- a/src/core/hle/service/bcat/backend/boxcat.h
+++ b/src/core/hle/service/bcat/backend/boxcat.h
@@ -9,6 +9,10 @@
9#include <optional> 9#include <optional>
10#include "core/hle/service/bcat/backend/backend.h" 10#include "core/hle/service/bcat/backend/backend.h"
11 11
12namespace Service::AM::Applets {
13class AppletManager;
14}
15
12namespace Service::BCAT { 16namespace Service::BCAT {
13 17
14struct EventStatus { 18struct EventStatus {
@@ -20,12 +24,13 @@ struct EventStatus {
20/// Boxcat is yuzu's custom backend implementation of Nintendo's BCAT service. It is free to use and 24/// Boxcat is yuzu's custom backend implementation of Nintendo's BCAT service. It is free to use and
21/// doesn't require a switch or nintendo account. The content is controlled by the yuzu team. 25/// doesn't require a switch or nintendo account. The content is controlled by the yuzu team.
22class Boxcat final : public Backend { 26class Boxcat final : public Backend {
23 friend void SynchronizeInternal(DirectoryGetter dir_getter, TitleIDVersion title, 27 friend void SynchronizeInternal(AM::Applets::AppletManager& applet_manager,
28 DirectoryGetter dir_getter, TitleIDVersion title,
24 ProgressServiceBackend& progress, 29 ProgressServiceBackend& progress,
25 std::optional<std::string> dir_name); 30 std::optional<std::string> dir_name);
26 31
27public: 32public:
28 explicit Boxcat(DirectoryGetter getter); 33 explicit Boxcat(AM::Applets::AppletManager& applet_manager_, DirectoryGetter getter);
29 ~Boxcat() override; 34 ~Boxcat() override;
30 35
31 bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) override; 36 bool Synchronize(TitleIDVersion title, ProgressServiceBackend& progress) override;
@@ -53,6 +58,7 @@ private:
53 58
54 class Client; 59 class Client;
55 std::unique_ptr<Client> client; 60 std::unique_ptr<Client> client;
61 AM::Applets::AppletManager& applet_manager;
56}; 62};
57 63
58} // namespace Service::BCAT 64} // namespace Service::BCAT
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index 4e4aa758b..6d9d1527d 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -125,7 +125,11 @@ private:
125class IBcatService final : public ServiceFramework<IBcatService> { 125class IBcatService final : public ServiceFramework<IBcatService> {
126public: 126public:
127 explicit IBcatService(Core::System& system_, Backend& backend_) 127 explicit IBcatService(Core::System& system_, Backend& backend_)
128 : ServiceFramework("IBcatService"), system{system_}, backend{backend_} { 128 : ServiceFramework("IBcatService"), system{system_}, backend{backend_},
129 progress{{
130 ProgressServiceBackend{system_.Kernel(), "Normal"},
131 ProgressServiceBackend{system_.Kernel(), "Directory"},
132 }} {
129 // clang-format off 133 // clang-format off
130 static const FunctionInfo functions[] = { 134 static const FunctionInfo functions[] = {
131 {10100, &IBcatService::RequestSyncDeliveryCache, "RequestSyncDeliveryCache"}, 135 {10100, &IBcatService::RequestSyncDeliveryCache, "RequestSyncDeliveryCache"},
@@ -249,10 +253,7 @@ private:
249 Core::System& system; 253 Core::System& system;
250 Backend& backend; 254 Backend& backend;
251 255
252 std::array<ProgressServiceBackend, static_cast<std::size_t>(SyncType::Count)> progress{ 256 std::array<ProgressServiceBackend, static_cast<std::size_t>(SyncType::Count)> progress;
253 ProgressServiceBackend{"Normal"},
254 ProgressServiceBackend{"Directory"},
255 };
256}; 257};
257 258
258void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { 259void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
@@ -557,12 +558,12 @@ void Module::Interface::CreateDeliveryCacheStorageServiceWithApplicationId(
557 rb.PushIpcInterface<IDeliveryCacheStorageService>(fsc.GetBCATDirectory(title_id)); 558 rb.PushIpcInterface<IDeliveryCacheStorageService>(fsc.GetBCATDirectory(title_id));
558} 559}
559 560
560std::unique_ptr<Backend> CreateBackendFromSettings(DirectoryGetter getter) { 561std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System& system,
561 const auto backend = Settings::values.bcat_backend; 562 DirectoryGetter getter) {
562
563#ifdef YUZU_ENABLE_BOXCAT 563#ifdef YUZU_ENABLE_BOXCAT
564 if (backend == "boxcat") 564 if (Settings::values.bcat_backend == "boxcat") {
565 return std::make_unique<Boxcat>(std::move(getter)); 565 return std::make_unique<Boxcat>(system.GetAppletManager(), std::move(getter));
566 }
566#endif 567#endif
567 568
568 return std::make_unique<NullBackend>(std::move(getter)); 569 return std::make_unique<NullBackend>(std::move(getter));
@@ -571,7 +572,8 @@ std::unique_ptr<Backend> CreateBackendFromSettings(DirectoryGetter getter) {
571Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, 572Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
572 FileSystem::FileSystemController& fsc_, const char* name) 573 FileSystem::FileSystemController& fsc_, const char* name)
573 : ServiceFramework(name), fsc{fsc_}, module{std::move(module_)}, 574 : ServiceFramework(name), fsc{fsc_}, module{std::move(module_)},
574 backend{CreateBackendFromSettings([&fsc_](u64 tid) { return fsc_.GetBCATDirectory(tid); })}, 575 backend{CreateBackendFromSettings(system_,
576 [&fsc_](u64 tid) { return fsc_.GetBCATDirectory(tid); })},
575 system{system_} {} 577 system{system_} {}
576 578
577Module::Interface::~Interface() = default; 579Module::Interface::~Interface() = default;
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index f764388bc..3f7b8e670 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -5,6 +5,7 @@
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/core_timing.h"
8#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" 9#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
9#include "core/hle/service/nvdrv/devices/nvmap.h" 10#include "core/hle/service/nvdrv/devices/nvmap.h"
10#include "core/perf_stats.h" 11#include "core/perf_stats.h"
@@ -38,7 +39,10 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3
38 transform, crop_rect}; 39 transform, crop_rect};
39 40
40 system.GetPerfStats().EndGameFrame(); 41 system.GetPerfStats().EndGameFrame();
42 system.GetPerfStats().EndSystemFrame();
41 system.GPU().SwapBuffers(&framebuffer); 43 system.GPU().SwapBuffers(&framebuffer);
44 system.FrameLimiter().DoFrameLimiting(system.CoreTiming().GetGlobalTimeUs());
45 system.GetPerfStats().BeginSystemFrame();
42} 46}
43 47
44} // namespace Service::Nvidia::Devices 48} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index eb88fee1b..b27ee0502 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -63,16 +63,26 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
63 return NvResult::BadParameter; 63 return NvResult::BadParameter;
64 } 64 }
65 65
66 u32 event_id = params.value & 0x00FF;
67
68 if (event_id >= MaxNvEvents) {
69 std::memcpy(output.data(), &params, sizeof(params));
70 return NvResult::BadParameter;
71 }
72
73 auto event = events_interface.events[event_id];
66 auto& gpu = system.GPU(); 74 auto& gpu = system.GPU();
67 // This is mostly to take into account unimplemented features. As synced 75 // This is mostly to take into account unimplemented features. As synced
68 // gpu is always synced. 76 // gpu is always synced.
69 if (!gpu.IsAsync()) { 77 if (!gpu.IsAsync()) {
78 event.writable->Signal();
70 return NvResult::Success; 79 return NvResult::Success;
71 } 80 }
72 auto lock = gpu.LockSync(); 81 auto lock = gpu.LockSync();
73 const u32 current_syncpoint_value = gpu.GetSyncpointValue(params.syncpt_id); 82 const u32 current_syncpoint_value = gpu.GetSyncpointValue(params.syncpt_id);
74 const s32 diff = current_syncpoint_value - params.threshold; 83 const s32 diff = current_syncpoint_value - params.threshold;
75 if (diff >= 0) { 84 if (diff >= 0) {
85 event.writable->Signal();
76 params.value = current_syncpoint_value; 86 params.value = current_syncpoint_value;
77 std::memcpy(output.data(), &params, sizeof(params)); 87 std::memcpy(output.data(), &params, sizeof(params));
78 return NvResult::Success; 88 return NvResult::Success;
@@ -88,27 +98,6 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
88 return NvResult::Timeout; 98 return NvResult::Timeout;
89 } 99 }
90 100
91 u32 event_id;
92 if (is_async) {
93 event_id = params.value & 0x00FF;
94 if (event_id >= MaxNvEvents) {
95 std::memcpy(output.data(), &params, sizeof(params));
96 return NvResult::BadParameter;
97 }
98 } else {
99 if (ctrl.fresh_call) {
100 const auto result = events_interface.GetFreeEvent();
101 if (result) {
102 event_id = *result;
103 } else {
104 LOG_CRITICAL(Service_NVDRV, "No Free Events available!");
105 event_id = params.value & 0x00FF;
106 }
107 } else {
108 event_id = ctrl.event_id;
109 }
110 }
111
112 EventState status = events_interface.status[event_id]; 101 EventState status = events_interface.status[event_id];
113 if (event_id < MaxNvEvents || status == EventState::Free || status == EventState::Registered) { 102 if (event_id < MaxNvEvents || status == EventState::Free || status == EventState::Registered) {
114 events_interface.SetEventStatus(event_id, EventState::Waiting); 103 events_interface.SetEventStatus(event_id, EventState::Waiting);
@@ -120,7 +109,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
120 params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000; 109 params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000;
121 } 110 }
122 params.value |= event_id; 111 params.value |= event_id;
123 events_interface.events[event_id].writable->Clear(); 112 event.writable->Clear();
124 gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); 113 gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
125 if (!is_async && ctrl.fresh_call) { 114 if (!is_async && ctrl.fresh_call) {
126 ctrl.must_delay = true; 115 ctrl.must_delay = true;
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index 5e0c23602..68d139cfb 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -134,7 +134,9 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
134 IPC::ResponseBuilder rb{ctx, 3, 1}; 134 IPC::ResponseBuilder rb{ctx, 3, 1};
135 rb.Push(RESULT_SUCCESS); 135 rb.Push(RESULT_SUCCESS);
136 if (event_id < MaxNvEvents) { 136 if (event_id < MaxNvEvents) {
137 rb.PushCopyObjects(nvdrv->GetEvent(event_id)); 137 auto event = nvdrv->GetEvent(event_id);
138 event->Clear();
139 rb.PushCopyObjects(event);
138 rb.Push<u32>(NvResult::Success); 140 rb.Push<u32>(NvResult::Success);
139 } else { 141 } else {
140 rb.Push<u32>(0); 142 rb.Push<u32>(0);
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 307a7e928..7bfb99e34 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -40,8 +40,8 @@ Module::Module(Core::System& system) {
40 auto& kernel = system.Kernel(); 40 auto& kernel = system.Kernel();
41 for (u32 i = 0; i < MaxNvEvents; i++) { 41 for (u32 i = 0; i < MaxNvEvents; i++) {
42 std::string event_label = fmt::format("NVDRV::NvEvent_{}", i); 42 std::string event_label = fmt::format("NVDRV::NvEvent_{}", i);
43 events_interface.events[i] = Kernel::WritableEvent::CreateEventPair( 43 events_interface.events[i] =
44 kernel, Kernel::ResetType::Automatic, event_label); 44 Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, event_label);
45 events_interface.status[i] = EventState::Free; 45 events_interface.status[i] = EventState::Free;
46 events_interface.registered[i] = false; 46 events_interface.registered[i] = false;
47 } 47 }
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index e1a07d3ee..55b68eb0c 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -14,8 +14,8 @@
14 14
15namespace Service::NVFlinger { 15namespace Service::NVFlinger {
16 16
17BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { 17BufferQueue::BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id)
18 auto& kernel = Core::System::GetInstance().Kernel(); 18 : id(id), layer_id(layer_id) {
19 buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual, 19 buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
20 "BufferQueue NativeHandle"); 20 "BufferQueue NativeHandle");
21} 21}
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 356bedb81..8f9b18547 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -15,6 +15,10 @@
15#include "core/hle/kernel/writable_event.h" 15#include "core/hle/kernel/writable_event.h"
16#include "core/hle/service/nvdrv/nvdata.h" 16#include "core/hle/service/nvdrv/nvdata.h"
17 17
18namespace Kernel {
19class KernelCore;
20}
21
18namespace Service::NVFlinger { 22namespace Service::NVFlinger {
19 23
20struct IGBPBuffer { 24struct IGBPBuffer {
@@ -44,7 +48,7 @@ public:
44 NativeWindowFormat = 2, 48 NativeWindowFormat = 2,
45 }; 49 };
46 50
47 BufferQueue(u32 id, u64 layer_id); 51 explicit BufferQueue(Kernel::KernelCore& kernel, u32 id, u64 layer_id);
48 ~BufferQueue(); 52 ~BufferQueue();
49 53
50 enum class BufferTransformFlags : u32 { 54 enum class BufferTransformFlags : u32 {
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 2e4d707b9..cc9522aad 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -83,7 +83,7 @@ std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
83 83
84 const u64 layer_id = next_layer_id++; 84 const u64 layer_id = next_layer_id++;
85 const u32 buffer_queue_id = next_buffer_queue_id++; 85 const u32 buffer_queue_id = next_buffer_queue_id++;
86 buffer_queues.emplace_back(buffer_queue_id, layer_id); 86 buffer_queues.emplace_back(system.Kernel(), buffer_queue_id, layer_id);
87 display->CreateLayer(layer_id, buffer_queues.back()); 87 display->CreateLayer(layer_id, buffer_queues.back());
88 return layer_id; 88 return layer_id;
89} 89}
@@ -187,14 +187,18 @@ void NVFlinger::Compose() {
187 MicroProfileFlip(); 187 MicroProfileFlip();
188 188
189 if (!buffer) { 189 if (!buffer) {
190 // There was no queued buffer to draw, render previous frame
191 system.GetPerfStats().EndGameFrame();
192 system.GPU().SwapBuffers({});
193 continue; 190 continue;
194 } 191 }
195 192
196 const auto& igbp_buffer = buffer->get().igbp_buffer; 193 const auto& igbp_buffer = buffer->get().igbp_buffer;
197 194
195 const auto& gpu = system.GPU();
196 const auto& multi_fence = buffer->get().multi_fence;
197 for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) {
198 const auto& fence = multi_fence.fences[fence_id];
199 gpu.WaitFence(fence.id, fence.value);
200 }
201
198 // Now send the buffer to the GPU for drawing. 202 // Now send the buffer to the GPU for drawing.
199 // TODO(Subv): Support more than just disp0. The display device selection is probably based 203 // TODO(Subv): Support more than just disp0. The display device selection is probably based
200 // on which display we're drawing (Default, Internal, External, etc) 204 // on which display we're drawing (Default, Internal, External, etc)
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index b56cb0627..10821d452 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -22,7 +22,7 @@ constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF;
22 22
23StandardVmCallbacks::StandardVmCallbacks(const Core::System& system, 23StandardVmCallbacks::StandardVmCallbacks(const Core::System& system,
24 const CheatProcessMetadata& metadata) 24 const CheatProcessMetadata& metadata)
25 : system(system), metadata(metadata) {} 25 : metadata(metadata), system(system) {}
26 26
27StandardVmCallbacks::~StandardVmCallbacks() = default; 27StandardVmCallbacks::~StandardVmCallbacks() = default;
28 28
@@ -176,9 +176,8 @@ std::vector<CheatEntry> TextCheatParser::Parse(const Core::System& system,
176 176
177CheatEngine::CheatEngine(Core::System& system, std::vector<CheatEntry> cheats, 177CheatEngine::CheatEngine(Core::System& system, std::vector<CheatEntry> cheats,
178 const std::array<u8, 0x20>& build_id) 178 const std::array<u8, 0x20>& build_id)
179 : system{system}, core_timing{system.CoreTiming()}, vm{std::make_unique<StandardVmCallbacks>( 179 : vm{std::make_unique<StandardVmCallbacks>(system, metadata)},
180 system, metadata)}, 180 cheats(std::move(cheats)), core_timing{system.CoreTiming()}, system{system} {
181 cheats(std::move(cheats)) {
182 metadata.main_nso_build_id = build_id; 181 metadata.main_nso_build_id = build_id;
183} 182}
184 183
diff --git a/src/core/memory/dmnt_cheat_vm.cpp b/src/core/memory/dmnt_cheat_vm.cpp
index cc16d15a4..4f4fa5099 100644
--- a/src/core/memory/dmnt_cheat_vm.cpp
+++ b/src/core/memory/dmnt_cheat_vm.cpp
@@ -1133,8 +1133,8 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
1133 case SaveRestoreRegisterOpType::ClearRegs: 1133 case SaveRestoreRegisterOpType::ClearRegs:
1134 case SaveRestoreRegisterOpType::Restore: 1134 case SaveRestoreRegisterOpType::Restore:
1135 default: 1135 default:
1136 src = registers.data(); 1136 src = saved_values.data();
1137 dst = saved_values.data(); 1137 dst = registers.data();
1138 break; 1138 break;
1139 } 1139 }
1140 for (std::size_t i = 0; i < NumRegisters; i++) { 1140 for (std::size_t i = 0; i < NumRegisters; i++) {
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 7802fd808..59976943a 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -101,7 +101,8 @@ void Maxwell3D::InitializeRegisterDefaults() {
101#define DIRTY_REGS_POS(field_name) (offsetof(Maxwell3D::DirtyRegs, field_name)) 101#define DIRTY_REGS_POS(field_name) (offsetof(Maxwell3D::DirtyRegs, field_name))
102 102
103void Maxwell3D::InitDirtySettings() { 103void Maxwell3D::InitDirtySettings() {
104 const auto set_block = [this](const u32 start, const u32 range, const u8 position) { 104 const auto set_block = [this](const std::size_t start, const std::size_t range,
105 const u8 position) {
105 const auto start_itr = dirty_pointers.begin() + start; 106 const auto start_itr = dirty_pointers.begin() + start;
106 const auto end_itr = start_itr + range; 107 const auto end_itr = start_itr + range;
107 std::fill(start_itr, end_itr, position); 108 std::fill(start_itr, end_itr, position);
@@ -478,7 +479,7 @@ void Maxwell3D::CallMethodFromMME(const GPU::MethodCall& method_call) {
478} 479}
479 480
480void Maxwell3D::FlushMMEInlineDraw() { 481void Maxwell3D::FlushMMEInlineDraw() {
481 LOG_DEBUG(HW_GPU, "called, topology={}, count={}", static_cast<u32>(regs.draw.topology.Value()), 482 LOG_TRACE(HW_GPU, "called, topology={}, count={}", static_cast<u32>(regs.draw.topology.Value()),
482 regs.vertex_buffer.count); 483 regs.vertex_buffer.count);
483 ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?"); 484 ASSERT_MSG(!(regs.index_array.count && regs.vertex_buffer.count), "Both indexed and direct?");
484 ASSERT(mme_draw.instance_count == mme_draw.gl_end_count); 485 ASSERT(mme_draw.instance_count == mme_draw.gl_end_count);
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 76cfe8107..095660115 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/microprofile.h"
6#include "core/core.h" 7#include "core/core.h"
7#include "core/core_timing.h" 8#include "core/core_timing.h"
8#include "core/memory.h" 9#include "core/memory.h"
@@ -17,6 +18,8 @@
17 18
18namespace Tegra { 19namespace Tegra {
19 20
21MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
22
20GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async) 23GPU::GPU(Core::System& system, VideoCore::RendererBase& renderer, bool is_async)
21 : system{system}, renderer{renderer}, is_async{is_async} { 24 : system{system}, renderer{renderer}, is_async{is_async} {
22 auto& rasterizer{renderer.Rasterizer()}; 25 auto& rasterizer{renderer.Rasterizer()};
@@ -63,6 +66,16 @@ const DmaPusher& GPU::DmaPusher() const {
63 return *dma_pusher; 66 return *dma_pusher;
64} 67}
65 68
69void GPU::WaitFence(u32 syncpoint_id, u32 value) const {
70 // Synced GPU, is always in sync
71 if (!is_async) {
72 return;
73 }
74 MICROPROFILE_SCOPE(GPU_wait);
75 while (syncpoints[syncpoint_id].load(std::memory_order_relaxed) < value) {
76 }
77}
78
66void GPU::IncrementSyncPoint(const u32 syncpoint_id) { 79void GPU::IncrementSyncPoint(const u32 syncpoint_id) {
67 syncpoints[syncpoint_id]++; 80 syncpoints[syncpoint_id]++;
68 std::lock_guard lock{sync_mutex}; 81 std::lock_guard lock{sync_mutex};
@@ -326,7 +339,7 @@ void GPU::ProcessSemaphoreTriggerMethod() {
326 block.sequence = regs.semaphore_sequence; 339 block.sequence = regs.semaphore_sequence;
327 // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of 340 // TODO(Kmather73): Generate a real GPU timestamp and write it here instead of
328 // CoreTiming 341 // CoreTiming
329 block.timestamp = Core::System::GetInstance().CoreTiming().GetTicks(); 342 block.timestamp = system.CoreTiming().GetTicks();
330 memory_manager->WriteBlock(regs.semaphore_address.SemaphoreAddress(), &block, 343 memory_manager->WriteBlock(regs.semaphore_address.SemaphoreAddress(), &block,
331 sizeof(block)); 344 sizeof(block));
332 } else { 345 } else {
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 29fa8e95b..dbca19f35 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -177,6 +177,12 @@ public:
177 /// Returns a reference to the GPU DMA pusher. 177 /// Returns a reference to the GPU DMA pusher.
178 Tegra::DmaPusher& DmaPusher(); 178 Tegra::DmaPusher& DmaPusher();
179 179
180 // Waits for the GPU to finish working
181 virtual void WaitIdle() const = 0;
182
183 /// Allows the CPU/NvFlinger to wait on the GPU before presenting a frame.
184 void WaitFence(u32 syncpoint_id, u32 value) const;
185
180 void IncrementSyncPoint(u32 syncpoint_id); 186 void IncrementSyncPoint(u32 syncpoint_id);
181 187
182 u32 GetSyncpointValue(u32 syncpoint_id) const; 188 u32 GetSyncpointValue(u32 syncpoint_id) const;
diff --git a/src/video_core/gpu_asynch.cpp b/src/video_core/gpu_asynch.cpp
index f2a3a390e..04222d060 100644
--- a/src/video_core/gpu_asynch.cpp
+++ b/src/video_core/gpu_asynch.cpp
@@ -44,4 +44,8 @@ void GPUAsynch::TriggerCpuInterrupt(const u32 syncpoint_id, const u32 value) con
44 interrupt_manager.GPUInterruptSyncpt(syncpoint_id, value); 44 interrupt_manager.GPUInterruptSyncpt(syncpoint_id, value);
45} 45}
46 46
47void GPUAsynch::WaitIdle() const {
48 gpu_thread.WaitIdle();
49}
50
47} // namespace VideoCommon 51} // namespace VideoCommon
diff --git a/src/video_core/gpu_asynch.h b/src/video_core/gpu_asynch.h
index a12f9bac4..1241ade1d 100644
--- a/src/video_core/gpu_asynch.h
+++ b/src/video_core/gpu_asynch.h
@@ -25,6 +25,7 @@ public:
25 void FlushRegion(CacheAddr addr, u64 size) override; 25 void FlushRegion(CacheAddr addr, u64 size) override;
26 void InvalidateRegion(CacheAddr addr, u64 size) override; 26 void InvalidateRegion(CacheAddr addr, u64 size) override;
27 void FlushAndInvalidateRegion(CacheAddr addr, u64 size) override; 27 void FlushAndInvalidateRegion(CacheAddr addr, u64 size) override;
28 void WaitIdle() const override;
28 29
29protected: 30protected:
30 void TriggerCpuInterrupt(u32 syncpoint_id, u32 value) const override; 31 void TriggerCpuInterrupt(u32 syncpoint_id, u32 value) const override;
diff --git a/src/video_core/gpu_synch.h b/src/video_core/gpu_synch.h
index 5eb1c461c..c71baee89 100644
--- a/src/video_core/gpu_synch.h
+++ b/src/video_core/gpu_synch.h
@@ -24,6 +24,7 @@ public:
24 void FlushRegion(CacheAddr addr, u64 size) override; 24 void FlushRegion(CacheAddr addr, u64 size) override;
25 void InvalidateRegion(CacheAddr addr, u64 size) override; 25 void InvalidateRegion(CacheAddr addr, u64 size) override;
26 void FlushAndInvalidateRegion(CacheAddr addr, u64 size) override; 26 void FlushAndInvalidateRegion(CacheAddr addr, u64 size) override;
27 void WaitIdle() const override {}
27 28
28protected: 29protected:
29 void TriggerCpuInterrupt([[maybe_unused]] u32 syncpoint_id, 30 void TriggerCpuInterrupt([[maybe_unused]] u32 syncpoint_id,
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 5f039e4fd..758a37f14 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -5,8 +5,6 @@
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/microprofile.h" 6#include "common/microprofile.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/core_timing.h"
9#include "core/core_timing_util.h"
10#include "core/frontend/scope_acquire_window_context.h" 8#include "core/frontend/scope_acquire_window_context.h"
11#include "video_core/dma_pusher.h" 9#include "video_core/dma_pusher.h"
12#include "video_core/gpu.h" 10#include "video_core/gpu.h"
@@ -68,14 +66,10 @@ ThreadManager::~ThreadManager() {
68 66
69void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher) { 67void ThreadManager::StartThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_pusher) {
70 thread = std::thread{RunThread, std::ref(renderer), std::ref(dma_pusher), std::ref(state)}; 68 thread = std::thread{RunThread, std::ref(renderer), std::ref(dma_pusher), std::ref(state)};
71 synchronization_event = system.CoreTiming().RegisterEvent(
72 "GPUThreadSynch", [this](u64 fence, s64) { state.WaitForSynchronization(fence); });
73} 69}
74 70
75void ThreadManager::SubmitList(Tegra::CommandList&& entries) { 71void ThreadManager::SubmitList(Tegra::CommandList&& entries) {
76 const u64 fence{PushCommand(SubmitListCommand(std::move(entries)))}; 72 PushCommand(SubmitListCommand(std::move(entries)));
77 const s64 synchronization_ticks{Core::Timing::usToCycles(std::chrono::microseconds{9000})};
78 system.CoreTiming().ScheduleEvent(synchronization_ticks, synchronization_event, fence);
79} 73}
80 74
81void ThreadManager::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { 75void ThreadManager::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
@@ -96,16 +90,15 @@ void ThreadManager::FlushAndInvalidateRegion(CacheAddr addr, u64 size) {
96 InvalidateRegion(addr, size); 90 InvalidateRegion(addr, size);
97} 91}
98 92
93void ThreadManager::WaitIdle() const {
94 while (state.last_fence > state.signaled_fence.load(std::memory_order_relaxed)) {
95 }
96}
97
99u64 ThreadManager::PushCommand(CommandData&& command_data) { 98u64 ThreadManager::PushCommand(CommandData&& command_data) {
100 const u64 fence{++state.last_fence}; 99 const u64 fence{++state.last_fence};
101 state.queue.Push(CommandDataContainer(std::move(command_data), fence)); 100 state.queue.Push(CommandDataContainer(std::move(command_data), fence));
102 return fence; 101 return fence;
103} 102}
104 103
105MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
106void SynchState::WaitForSynchronization(u64 fence) {
107 while (signaled_fence.load() < fence)
108 ;
109}
110
111} // namespace VideoCommon::GPUThread 104} // namespace VideoCommon::GPUThread
diff --git a/src/video_core/gpu_thread.h b/src/video_core/gpu_thread.h
index 3ae0ec9f3..08dc96bb3 100644
--- a/src/video_core/gpu_thread.h
+++ b/src/video_core/gpu_thread.h
@@ -21,9 +21,6 @@ class DmaPusher;
21 21
22namespace Core { 22namespace Core {
23class System; 23class System;
24namespace Timing {
25struct EventType;
26} // namespace Timing
27} // namespace Core 24} // namespace Core
28 25
29namespace VideoCommon::GPUThread { 26namespace VideoCommon::GPUThread {
@@ -89,8 +86,6 @@ struct CommandDataContainer {
89struct SynchState final { 86struct SynchState final {
90 std::atomic_bool is_running{true}; 87 std::atomic_bool is_running{true};
91 88
92 void WaitForSynchronization(u64 fence);
93
94 using CommandQueue = Common::SPSCQueue<CommandDataContainer>; 89 using CommandQueue = Common::SPSCQueue<CommandDataContainer>;
95 CommandQueue queue; 90 CommandQueue queue;
96 u64 last_fence{}; 91 u64 last_fence{};
@@ -121,6 +116,9 @@ public:
121 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated 116 /// Notify rasterizer that any caches of the specified region should be flushed and invalidated
122 void FlushAndInvalidateRegion(CacheAddr addr, u64 size); 117 void FlushAndInvalidateRegion(CacheAddr addr, u64 size);
123 118
119 // Wait until the gpu thread is idle.
120 void WaitIdle() const;
121
124private: 122private:
125 /// Pushes a command to be executed by the GPU thread 123 /// Pushes a command to be executed by the GPU thread
126 u64 PushCommand(CommandData&& command_data); 124 u64 PushCommand(CommandData&& command_data);
@@ -128,7 +126,6 @@ private:
128private: 126private:
129 SynchState state; 127 SynchState state;
130 Core::System& system; 128 Core::System& system;
131 Core::Timing::EventType* synchronization_event{};
132 std::thread thread; 129 std::thread thread;
133 std::thread::id thread_id; 130 std::thread::id thread_id;
134}; 131};
diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp
index dbaeac6db..42031d80a 100644
--- a/src/video_core/macro_interpreter.cpp
+++ b/src/video_core/macro_interpreter.cpp
@@ -11,6 +11,77 @@
11MICROPROFILE_DEFINE(MacroInterp, "GPU", "Execute macro interpreter", MP_RGB(128, 128, 192)); 11MICROPROFILE_DEFINE(MacroInterp, "GPU", "Execute macro interpreter", MP_RGB(128, 128, 192));
12 12
13namespace Tegra { 13namespace Tegra {
14namespace {
15enum class Operation : u32 {
16 ALU = 0,
17 AddImmediate = 1,
18 ExtractInsert = 2,
19 ExtractShiftLeftImmediate = 3,
20 ExtractShiftLeftRegister = 4,
21 Read = 5,
22 Unused = 6, // This operation doesn't seem to be a valid encoding.
23 Branch = 7,
24};
25} // Anonymous namespace
26
27enum class MacroInterpreter::ALUOperation : u32 {
28 Add = 0,
29 AddWithCarry = 1,
30 Subtract = 2,
31 SubtractWithBorrow = 3,
32 // Operations 4-7 don't seem to be valid encodings.
33 Xor = 8,
34 Or = 9,
35 And = 10,
36 AndNot = 11,
37 Nand = 12
38};
39
40enum class MacroInterpreter::ResultOperation : u32 {
41 IgnoreAndFetch = 0,
42 Move = 1,
43 MoveAndSetMethod = 2,
44 FetchAndSend = 3,
45 MoveAndSend = 4,
46 FetchAndSetMethod = 5,
47 MoveAndSetMethodFetchAndSend = 6,
48 MoveAndSetMethodSend = 7
49};
50
51enum class MacroInterpreter::BranchCondition : u32 {
52 Zero = 0,
53 NotZero = 1,
54};
55
56union MacroInterpreter::Opcode {
57 u32 raw;
58 BitField<0, 3, Operation> operation;
59 BitField<4, 3, ResultOperation> result_operation;
60 BitField<4, 1, BranchCondition> branch_condition;
61 // If set on a branch, then the branch doesn't have a delay slot.
62 BitField<5, 1, u32> branch_annul;
63 BitField<7, 1, u32> is_exit;
64 BitField<8, 3, u32> dst;
65 BitField<11, 3, u32> src_a;
66 BitField<14, 3, u32> src_b;
67 // The signed immediate overlaps the second source operand and the alu operation.
68 BitField<14, 18, s32> immediate;
69
70 BitField<17, 5, ALUOperation> alu_operation;
71
72 // Bitfield instructions data
73 BitField<17, 5, u32> bf_src_bit;
74 BitField<22, 5, u32> bf_size;
75 BitField<27, 5, u32> bf_dst_bit;
76
77 u32 GetBitfieldMask() const {
78 return (1 << bf_size) - 1;
79 }
80
81 s32 GetBranchTarget() const {
82 return static_cast<s32>(immediate * sizeof(u32));
83 }
84};
14 85
15MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {} 86MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
16 87
diff --git a/src/video_core/macro_interpreter.h b/src/video_core/macro_interpreter.h
index 76b6a895b..631146d89 100644
--- a/src/video_core/macro_interpreter.h
+++ b/src/video_core/macro_interpreter.h
@@ -6,7 +6,6 @@
6 6
7#include <array> 7#include <array>
8#include <optional> 8#include <optional>
9#include <vector>
10 9
11#include "common/bit_field.h" 10#include "common/bit_field.h"
12#include "common/common_types.h" 11#include "common/common_types.h"
@@ -28,75 +27,11 @@ public:
28 void Execute(u32 offset, std::size_t num_parameters, const u32* parameters); 27 void Execute(u32 offset, std::size_t num_parameters, const u32* parameters);
29 28
30private: 29private:
31 enum class Operation : u32 { 30 enum class ALUOperation : u32;
32 ALU = 0, 31 enum class BranchCondition : u32;
33 AddImmediate = 1, 32 enum class ResultOperation : u32;
34 ExtractInsert = 2,
35 ExtractShiftLeftImmediate = 3,
36 ExtractShiftLeftRegister = 4,
37 Read = 5,
38 Unused = 6, // This operation doesn't seem to be a valid encoding.
39 Branch = 7,
40 };
41
42 enum class ALUOperation : u32 {
43 Add = 0,
44 AddWithCarry = 1,
45 Subtract = 2,
46 SubtractWithBorrow = 3,
47 // Operations 4-7 don't seem to be valid encodings.
48 Xor = 8,
49 Or = 9,
50 And = 10,
51 AndNot = 11,
52 Nand = 12
53 };
54
55 enum class ResultOperation : u32 {
56 IgnoreAndFetch = 0,
57 Move = 1,
58 MoveAndSetMethod = 2,
59 FetchAndSend = 3,
60 MoveAndSend = 4,
61 FetchAndSetMethod = 5,
62 MoveAndSetMethodFetchAndSend = 6,
63 MoveAndSetMethodSend = 7
64 };
65 33
66 enum class BranchCondition : u32 { 34 union Opcode;
67 Zero = 0,
68 NotZero = 1,
69 };
70
71 union Opcode {
72 u32 raw;
73 BitField<0, 3, Operation> operation;
74 BitField<4, 3, ResultOperation> result_operation;
75 BitField<4, 1, BranchCondition> branch_condition;
76 BitField<5, 1, u32>
77 branch_annul; // If set on a branch, then the branch doesn't have a delay slot.
78 BitField<7, 1, u32> is_exit;
79 BitField<8, 3, u32> dst;
80 BitField<11, 3, u32> src_a;
81 BitField<14, 3, u32> src_b;
82 // The signed immediate overlaps the second source operand and the alu operation.
83 BitField<14, 18, s32> immediate;
84
85 BitField<17, 5, ALUOperation> alu_operation;
86
87 // Bitfield instructions data
88 BitField<17, 5, u32> bf_src_bit;
89 BitField<22, 5, u32> bf_size;
90 BitField<27, 5, u32> bf_dst_bit;
91
92 u32 GetBitfieldMask() const {
93 return (1 << bf_size) - 1;
94 }
95
96 s32 GetBranchTarget() const {
97 return static_cast<s32>(immediate * sizeof(u32));
98 }
99 };
100 35
101 union MethodAddress { 36 union MethodAddress {
102 u32 raw; 37 u32 raw;
@@ -149,9 +84,10 @@ private:
149 84
150 Engines::Maxwell3D& maxwell3d; 85 Engines::Maxwell3D& maxwell3d;
151 86
152 u32 pc; ///< Current program counter 87 /// Current program counter
153 std::optional<u32> 88 u32 pc;
154 delayed_pc; ///< Program counter to execute at after the delay slot is executed. 89 /// Program counter to execute at after the delay slot is executed.
90 std::optional<u32> delayed_pc;
155 91
156 static constexpr std::size_t NumMacroRegisters = 8; 92 static constexpr std::size_t NumMacroRegisters = 8;
157 93
diff --git a/src/video_core/morton.cpp b/src/video_core/morton.cpp
index ab71870ab..fe5f08ace 100644
--- a/src/video_core/morton.cpp
+++ b/src/video_core/morton.cpp
@@ -93,6 +93,7 @@ static constexpr ConversionArray morton_to_linear_fns = {
93 MortonCopy<true, PixelFormat::DXT23_SRGB>, 93 MortonCopy<true, PixelFormat::DXT23_SRGB>,
94 MortonCopy<true, PixelFormat::DXT45_SRGB>, 94 MortonCopy<true, PixelFormat::DXT45_SRGB>,
95 MortonCopy<true, PixelFormat::BC7U_SRGB>, 95 MortonCopy<true, PixelFormat::BC7U_SRGB>,
96 MortonCopy<true, PixelFormat::R4G4B4A4U>,
96 MortonCopy<true, PixelFormat::ASTC_2D_4X4_SRGB>, 97 MortonCopy<true, PixelFormat::ASTC_2D_4X4_SRGB>,
97 MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>, 98 MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>,
98 MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>, 99 MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>,
@@ -101,6 +102,16 @@ static constexpr ConversionArray morton_to_linear_fns = {
101 MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>, 102 MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>,
102 MortonCopy<true, PixelFormat::ASTC_2D_10X8>, 103 MortonCopy<true, PixelFormat::ASTC_2D_10X8>,
103 MortonCopy<true, PixelFormat::ASTC_2D_10X8_SRGB>, 104 MortonCopy<true, PixelFormat::ASTC_2D_10X8_SRGB>,
105 MortonCopy<true, PixelFormat::ASTC_2D_6X6>,
106 MortonCopy<true, PixelFormat::ASTC_2D_6X6_SRGB>,
107 MortonCopy<true, PixelFormat::ASTC_2D_10X10>,
108 MortonCopy<true, PixelFormat::ASTC_2D_10X10_SRGB>,
109 MortonCopy<true, PixelFormat::ASTC_2D_12X12>,
110 MortonCopy<true, PixelFormat::ASTC_2D_12X12_SRGB>,
111 MortonCopy<true, PixelFormat::ASTC_2D_8X6>,
112 MortonCopy<true, PixelFormat::ASTC_2D_8X6_SRGB>,
113 MortonCopy<true, PixelFormat::ASTC_2D_6X5>,
114 MortonCopy<true, PixelFormat::ASTC_2D_6X5_SRGB>,
104 MortonCopy<true, PixelFormat::Z32F>, 115 MortonCopy<true, PixelFormat::Z32F>,
105 MortonCopy<true, PixelFormat::Z16>, 116 MortonCopy<true, PixelFormat::Z16>,
106 MortonCopy<true, PixelFormat::Z24S8>, 117 MortonCopy<true, PixelFormat::Z24S8>,
@@ -162,6 +173,17 @@ static constexpr ConversionArray linear_to_morton_fns = {
162 MortonCopy<false, PixelFormat::DXT23_SRGB>, 173 MortonCopy<false, PixelFormat::DXT23_SRGB>,
163 MortonCopy<false, PixelFormat::DXT45_SRGB>, 174 MortonCopy<false, PixelFormat::DXT45_SRGB>,
164 MortonCopy<false, PixelFormat::BC7U_SRGB>, 175 MortonCopy<false, PixelFormat::BC7U_SRGB>,
176 MortonCopy<false, PixelFormat::R4G4B4A4U>,
177 nullptr,
178 nullptr,
179 nullptr,
180 nullptr,
181 nullptr,
182 nullptr,
183 nullptr,
184 nullptr,
185 nullptr,
186 nullptr,
165 nullptr, 187 nullptr,
166 nullptr, 188 nullptr,
167 nullptr, 189 nullptr,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index a85f730a8..cbcf81414 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -348,6 +348,7 @@ static constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
348} 348}
349 349
350void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { 350void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
351 std::lock_guard lock{pages_mutex};
351 const u64 page_start{addr >> Memory::PAGE_BITS}; 352 const u64 page_start{addr >> Memory::PAGE_BITS};
352 const u64 page_end{(addr + size + Memory::PAGE_SIZE - 1) >> Memory::PAGE_BITS}; 353 const u64 page_end{(addr + size + Memory::PAGE_SIZE - 1) >> Memory::PAGE_BITS};
353 354
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 9c10ebda3..c24a02d71 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -9,6 +9,7 @@
9#include <cstddef> 9#include <cstddef>
10#include <map> 10#include <map>
11#include <memory> 11#include <memory>
12#include <mutex>
12#include <optional> 13#include <optional>
13#include <tuple> 14#include <tuple>
14#include <utility> 15#include <utility>
@@ -230,6 +231,8 @@ private:
230 231
231 using CachedPageMap = boost::icl::interval_map<u64, int>; 232 using CachedPageMap = boost::icl::interval_map<u64, int>;
232 CachedPageMap cached_pages; 233 CachedPageMap cached_pages;
234
235 std::mutex pages_mutex;
233}; 236};
234 237
235} // namespace OpenGL 238} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index bb972bf37..baec66ff0 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -1148,7 +1148,7 @@ private:
1148 for (const auto& variant : extras) { 1148 for (const auto& variant : extras) {
1149 if (const auto argument = std::get_if<TextureArgument>(&variant)) { 1149 if (const auto argument = std::get_if<TextureArgument>(&variant)) {
1150 expr += GenerateTextureArgument(*argument); 1150 expr += GenerateTextureArgument(*argument);
1151 } else if (std::get_if<TextureAoffi>(&variant)) { 1151 } else if (std::holds_alternative<TextureAoffi>(variant)) {
1152 expr += GenerateTextureAoffi(meta->aoffi); 1152 expr += GenerateTextureAoffi(meta->aoffi);
1153 } else { 1153 } else {
1154 UNREACHABLE(); 1154 UNREACHABLE();
@@ -1158,8 +1158,8 @@ private:
1158 return expr + ')'; 1158 return expr + ')';
1159 } 1159 }
1160 1160
1161 std::string GenerateTextureArgument(TextureArgument argument) { 1161 std::string GenerateTextureArgument(const TextureArgument& argument) {
1162 const auto [type, operand] = argument; 1162 const auto& [type, operand] = argument;
1163 if (operand == nullptr) { 1163 if (operand == nullptr) {
1164 return {}; 1164 return {};
1165 } 1165 }
@@ -1235,7 +1235,7 @@ private:
1235 1235
1236 std::string BuildImageValues(Operation operation) { 1236 std::string BuildImageValues(Operation operation) {
1237 constexpr std::array constructors{"uint", "uvec2", "uvec3", "uvec4"}; 1237 constexpr std::array constructors{"uint", "uvec2", "uvec3", "uvec4"};
1238 const auto meta{std::get<MetaImage>(operation.GetMeta())}; 1238 const auto& meta{std::get<MetaImage>(operation.GetMeta())};
1239 1239
1240 const std::size_t values_count{meta.values.size()}; 1240 const std::size_t values_count{meta.values.size()};
1241 std::string expr = fmt::format("{}(", constructors.at(values_count - 1)); 1241 std::string expr = fmt::format("{}(", constructors.at(values_count - 1));
@@ -1780,14 +1780,14 @@ private:
1780 return {"0", Type::Int}; 1780 return {"0", Type::Int};
1781 } 1781 }
1782 1782
1783 const auto meta{std::get<MetaImage>(operation.GetMeta())}; 1783 const auto& meta{std::get<MetaImage>(operation.GetMeta())};
1784 return {fmt::format("imageLoad({}, {}){}", GetImage(meta.image), 1784 return {fmt::format("imageLoad({}, {}){}", GetImage(meta.image),
1785 BuildIntegerCoordinates(operation), GetSwizzle(meta.element)), 1785 BuildIntegerCoordinates(operation), GetSwizzle(meta.element)),
1786 Type::Uint}; 1786 Type::Uint};
1787 } 1787 }
1788 1788
1789 Expression ImageStore(Operation operation) { 1789 Expression ImageStore(Operation operation) {
1790 const auto meta{std::get<MetaImage>(operation.GetMeta())}; 1790 const auto& meta{std::get<MetaImage>(operation.GetMeta())};
1791 code.AddLine("imageStore({}, {}, {});", GetImage(meta.image), 1791 code.AddLine("imageStore({}, {}, {});", GetImage(meta.image),
1792 BuildIntegerCoordinates(operation), BuildImageValues(operation)); 1792 BuildIntegerCoordinates(operation), BuildImageValues(operation));
1793 return {}; 1793 return {};
@@ -1795,7 +1795,7 @@ private:
1795 1795
1796 template <const std::string_view& opname> 1796 template <const std::string_view& opname>
1797 Expression AtomicImage(Operation operation) { 1797 Expression AtomicImage(Operation operation) {
1798 const auto meta{std::get<MetaImage>(operation.GetMeta())}; 1798 const auto& meta{std::get<MetaImage>(operation.GetMeta())};
1799 ASSERT(meta.values.size() == 1); 1799 ASSERT(meta.values.size() == 1);
1800 1800
1801 return {fmt::format("imageAtomic{}({}, {}, {})", opname, GetImage(meta.image), 1801 return {fmt::format("imageAtomic{}({}, {}, {})", opname, GetImage(meta.image),
@@ -2246,7 +2246,7 @@ private:
2246 code.AddLine("#ifdef SAMPLER_{}_IS_BUFFER", sampler.GetIndex()); 2246 code.AddLine("#ifdef SAMPLER_{}_IS_BUFFER", sampler.GetIndex());
2247 } 2247 }
2248 2248
2249 std::string GetDeclarationWithSuffix(u32 index, const std::string& name) const { 2249 std::string GetDeclarationWithSuffix(u32 index, std::string_view name) const {
2250 return fmt::format("{}_{}_{}", name, index, suffix); 2250 return fmt::format("{}_{}_{}", name, index, suffix);
2251 } 2251 }
2252 2252
@@ -2271,17 +2271,15 @@ private:
2271 ShaderWriter code; 2271 ShaderWriter code;
2272}; 2272};
2273 2273
2274static constexpr std::string_view flow_var = "flow_var_";
2275
2276std::string GetFlowVariable(u32 i) { 2274std::string GetFlowVariable(u32 i) {
2277 return fmt::format("{}{}", flow_var, i); 2275 return fmt::format("flow_var_{}", i);
2278} 2276}
2279 2277
2280class ExprDecompiler { 2278class ExprDecompiler {
2281public: 2279public:
2282 explicit ExprDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {} 2280 explicit ExprDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {}
2283 2281
2284 void operator()(VideoCommon::Shader::ExprAnd& expr) { 2282 void operator()(const ExprAnd& expr) {
2285 inner += "( "; 2283 inner += "( ";
2286 std::visit(*this, *expr.operand1); 2284 std::visit(*this, *expr.operand1);
2287 inner += " && "; 2285 inner += " && ";
@@ -2289,7 +2287,7 @@ public:
2289 inner += ')'; 2287 inner += ')';
2290 } 2288 }
2291 2289
2292 void operator()(VideoCommon::Shader::ExprOr& expr) { 2290 void operator()(const ExprOr& expr) {
2293 inner += "( "; 2291 inner += "( ";
2294 std::visit(*this, *expr.operand1); 2292 std::visit(*this, *expr.operand1);
2295 inner += " || "; 2293 inner += " || ";
@@ -2297,17 +2295,17 @@ public:
2297 inner += ')'; 2295 inner += ')';
2298 } 2296 }
2299 2297
2300 void operator()(VideoCommon::Shader::ExprNot& expr) { 2298 void operator()(const ExprNot& expr) {
2301 inner += '!'; 2299 inner += '!';
2302 std::visit(*this, *expr.operand1); 2300 std::visit(*this, *expr.operand1);
2303 } 2301 }
2304 2302
2305 void operator()(VideoCommon::Shader::ExprPredicate& expr) { 2303 void operator()(const ExprPredicate& expr) {
2306 const auto pred = static_cast<Tegra::Shader::Pred>(expr.predicate); 2304 const auto pred = static_cast<Tegra::Shader::Pred>(expr.predicate);
2307 inner += decomp.GetPredicate(pred); 2305 inner += decomp.GetPredicate(pred);
2308 } 2306 }
2309 2307
2310 void operator()(VideoCommon::Shader::ExprCondCode& expr) { 2308 void operator()(const ExprCondCode& expr) {
2311 const Node cc = decomp.ir.GetConditionCode(expr.cc); 2309 const Node cc = decomp.ir.GetConditionCode(expr.cc);
2312 std::string target; 2310 std::string target;
2313 2311
@@ -2332,15 +2330,15 @@ public:
2332 inner += target; 2330 inner += target;
2333 } 2331 }
2334 2332
2335 void operator()(VideoCommon::Shader::ExprVar& expr) { 2333 void operator()(const ExprVar& expr) {
2336 inner += GetFlowVariable(expr.var_index); 2334 inner += GetFlowVariable(expr.var_index);
2337 } 2335 }
2338 2336
2339 void operator()(VideoCommon::Shader::ExprBoolean& expr) { 2337 void operator()(const ExprBoolean& expr) {
2340 inner += expr.value ? "true" : "false"; 2338 inner += expr.value ? "true" : "false";
2341 } 2339 }
2342 2340
2343 std::string& GetResult() { 2341 const std::string& GetResult() const {
2344 return inner; 2342 return inner;
2345 } 2343 }
2346 2344
@@ -2353,7 +2351,7 @@ class ASTDecompiler {
2353public: 2351public:
2354 explicit ASTDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {} 2352 explicit ASTDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {}
2355 2353
2356 void operator()(VideoCommon::Shader::ASTProgram& ast) { 2354 void operator()(const ASTProgram& ast) {
2357 ASTNode current = ast.nodes.GetFirst(); 2355 ASTNode current = ast.nodes.GetFirst();
2358 while (current) { 2356 while (current) {
2359 Visit(current); 2357 Visit(current);
@@ -2361,7 +2359,7 @@ public:
2361 } 2359 }
2362 } 2360 }
2363 2361
2364 void operator()(VideoCommon::Shader::ASTIfThen& ast) { 2362 void operator()(const ASTIfThen& ast) {
2365 ExprDecompiler expr_parser{decomp}; 2363 ExprDecompiler expr_parser{decomp};
2366 std::visit(expr_parser, *ast.condition); 2364 std::visit(expr_parser, *ast.condition);
2367 decomp.code.AddLine("if ({}) {{", expr_parser.GetResult()); 2365 decomp.code.AddLine("if ({}) {{", expr_parser.GetResult());
@@ -2375,7 +2373,7 @@ public:
2375 decomp.code.AddLine("}}"); 2373 decomp.code.AddLine("}}");
2376 } 2374 }
2377 2375
2378 void operator()(VideoCommon::Shader::ASTIfElse& ast) { 2376 void operator()(const ASTIfElse& ast) {
2379 decomp.code.AddLine("else {{"); 2377 decomp.code.AddLine("else {{");
2380 decomp.code.scope++; 2378 decomp.code.scope++;
2381 ASTNode current = ast.nodes.GetFirst(); 2379 ASTNode current = ast.nodes.GetFirst();
@@ -2387,29 +2385,29 @@ public:
2387 decomp.code.AddLine("}}"); 2385 decomp.code.AddLine("}}");
2388 } 2386 }
2389 2387
2390 void operator()(VideoCommon::Shader::ASTBlockEncoded& ast) { 2388 void operator()([[maybe_unused]] const ASTBlockEncoded& ast) {
2391 UNREACHABLE(); 2389 UNREACHABLE();
2392 } 2390 }
2393 2391
2394 void operator()(VideoCommon::Shader::ASTBlockDecoded& ast) { 2392 void operator()(const ASTBlockDecoded& ast) {
2395 decomp.VisitBlock(ast.nodes); 2393 decomp.VisitBlock(ast.nodes);
2396 } 2394 }
2397 2395
2398 void operator()(VideoCommon::Shader::ASTVarSet& ast) { 2396 void operator()(const ASTVarSet& ast) {
2399 ExprDecompiler expr_parser{decomp}; 2397 ExprDecompiler expr_parser{decomp};
2400 std::visit(expr_parser, *ast.condition); 2398 std::visit(expr_parser, *ast.condition);
2401 decomp.code.AddLine("{} = {};", GetFlowVariable(ast.index), expr_parser.GetResult()); 2399 decomp.code.AddLine("{} = {};", GetFlowVariable(ast.index), expr_parser.GetResult());
2402 } 2400 }
2403 2401
2404 void operator()(VideoCommon::Shader::ASTLabel& ast) { 2402 void operator()(const ASTLabel& ast) {
2405 decomp.code.AddLine("// Label_{}:", ast.index); 2403 decomp.code.AddLine("// Label_{}:", ast.index);
2406 } 2404 }
2407 2405
2408 void operator()(VideoCommon::Shader::ASTGoto& ast) { 2406 void operator()([[maybe_unused]] const ASTGoto& ast) {
2409 UNREACHABLE(); 2407 UNREACHABLE();
2410 } 2408 }
2411 2409
2412 void operator()(VideoCommon::Shader::ASTDoWhile& ast) { 2410 void operator()(const ASTDoWhile& ast) {
2413 ExprDecompiler expr_parser{decomp}; 2411 ExprDecompiler expr_parser{decomp};
2414 std::visit(expr_parser, *ast.condition); 2412 std::visit(expr_parser, *ast.condition);
2415 decomp.code.AddLine("do {{"); 2413 decomp.code.AddLine("do {{");
@@ -2423,7 +2421,7 @@ public:
2423 decomp.code.AddLine("}} while({});", expr_parser.GetResult()); 2421 decomp.code.AddLine("}} while({});", expr_parser.GetResult());
2424 } 2422 }
2425 2423
2426 void operator()(VideoCommon::Shader::ASTReturn& ast) { 2424 void operator()(const ASTReturn& ast) {
2427 const bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); 2425 const bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition);
2428 if (!is_true) { 2426 if (!is_true) {
2429 ExprDecompiler expr_parser{decomp}; 2427 ExprDecompiler expr_parser{decomp};
@@ -2443,7 +2441,7 @@ public:
2443 } 2441 }
2444 } 2442 }
2445 2443
2446 void operator()(VideoCommon::Shader::ASTBreak& ast) { 2444 void operator()(const ASTBreak& ast) {
2447 const bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); 2445 const bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition);
2448 if (!is_true) { 2446 if (!is_true) {
2449 ExprDecompiler expr_parser{decomp}; 2447 ExprDecompiler expr_parser{decomp};
@@ -2458,7 +2456,7 @@ public:
2458 } 2456 }
2459 } 2457 }
2460 2458
2461 void Visit(VideoCommon::Shader::ASTNode& node) { 2459 void Visit(const ASTNode& node) {
2462 std::visit(*this, *node->GetInnerData()); 2460 std::visit(*this, *node->GetInnerData());
2463 } 2461 }
2464 2462
@@ -2471,9 +2469,9 @@ void GLSLDecompiler::DecompileAST() {
2471 for (u32 i = 0; i < num_flow_variables; i++) { 2469 for (u32 i = 0; i < num_flow_variables; i++) {
2472 code.AddLine("bool {} = false;", GetFlowVariable(i)); 2470 code.AddLine("bool {} = false;", GetFlowVariable(i));
2473 } 2471 }
2472
2474 ASTDecompiler decompiler{*this}; 2473 ASTDecompiler decompiler{*this};
2475 VideoCommon::Shader::ASTNode program = ir.GetASTProgram(); 2474 decompiler.Visit(ir.GetASTProgram());
2476 decompiler.Visit(program);
2477} 2475}
2478 2476
2479} // Anonymous namespace 2477} // Anonymous namespace
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp
index 173b76c4e..2f9bfd7e4 100644
--- a/src/video_core/renderer_opengl/gl_texture_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp
@@ -111,7 +111,8 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format
111 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 111 {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
112 true}, // DXT45_SRGB 112 true}, // DXT45_SRGB
113 {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, 113 {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm,
114 true}, // BC7U_SRGB 114 true}, // BC7U_SRGB
115 {GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4_REV, ComponentType::UNorm, false}, // R4G4B4A4U
115 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB 116 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB
116 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB 117 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB
117 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB 118 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB
@@ -120,6 +121,16 @@ constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format
120 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5_SRGB 121 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5_SRGB
121 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8 122 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8
122 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8_SRGB 123 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8_SRGB
124 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_6X6
125 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_6X6_SRGB
126 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X10
127 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X10_SRGB
128 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_12X12
129 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_12X12_SRGB
130 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X6
131 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X6_SRGB
132 {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_6X5
133 {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_6X5_SRGB
123 134
124 // Depth formats 135 // Depth formats
125 {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F 136 {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 1e6ef66ab..4bbd17b12 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -102,8 +102,6 @@ RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::Syst
102RendererOpenGL::~RendererOpenGL() = default; 102RendererOpenGL::~RendererOpenGL() = default;
103 103
104void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { 104void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
105 system.GetPerfStats().EndSystemFrame();
106
107 // Maintain the rasterizer's state as a priority 105 // Maintain the rasterizer's state as a priority
108 OpenGLState prev_state = OpenGLState::GetCurState(); 106 OpenGLState prev_state = OpenGLState::GetCurState();
109 state.AllDirty(); 107 state.AllDirty();
@@ -135,9 +133,6 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {
135 133
136 render_window.PollEvents(); 134 render_window.PollEvents();
137 135
138 system.FrameLimiter().DoFrameLimiting(system.CoreTiming().GetGlobalTimeUs());
139 system.GetPerfStats().BeginSystemFrame();
140
141 // Restore the rasterizer state 136 // Restore the rasterizer state
142 prev_state.AllDirty(); 137 prev_state.AllDirty();
143 prev_state.Apply(); 138 prev_state.Apply();
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index 4fb1ca372..0d943a826 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -1648,32 +1648,32 @@ class ExprDecompiler {
1648public: 1648public:
1649 explicit ExprDecompiler(SPIRVDecompiler& decomp) : decomp{decomp} {} 1649 explicit ExprDecompiler(SPIRVDecompiler& decomp) : decomp{decomp} {}
1650 1650
1651 Id operator()(VideoCommon::Shader::ExprAnd& expr) { 1651 Id operator()(const ExprAnd& expr) {
1652 const Id type_def = decomp.GetTypeDefinition(Type::Bool); 1652 const Id type_def = decomp.GetTypeDefinition(Type::Bool);
1653 const Id op1 = Visit(expr.operand1); 1653 const Id op1 = Visit(expr.operand1);
1654 const Id op2 = Visit(expr.operand2); 1654 const Id op2 = Visit(expr.operand2);
1655 return decomp.Emit(decomp.OpLogicalAnd(type_def, op1, op2)); 1655 return decomp.Emit(decomp.OpLogicalAnd(type_def, op1, op2));
1656 } 1656 }
1657 1657
1658 Id operator()(VideoCommon::Shader::ExprOr& expr) { 1658 Id operator()(const ExprOr& expr) {
1659 const Id type_def = decomp.GetTypeDefinition(Type::Bool); 1659 const Id type_def = decomp.GetTypeDefinition(Type::Bool);
1660 const Id op1 = Visit(expr.operand1); 1660 const Id op1 = Visit(expr.operand1);
1661 const Id op2 = Visit(expr.operand2); 1661 const Id op2 = Visit(expr.operand2);
1662 return decomp.Emit(decomp.OpLogicalOr(type_def, op1, op2)); 1662 return decomp.Emit(decomp.OpLogicalOr(type_def, op1, op2));
1663 } 1663 }
1664 1664
1665 Id operator()(VideoCommon::Shader::ExprNot& expr) { 1665 Id operator()(const ExprNot& expr) {
1666 const Id type_def = decomp.GetTypeDefinition(Type::Bool); 1666 const Id type_def = decomp.GetTypeDefinition(Type::Bool);
1667 const Id op1 = Visit(expr.operand1); 1667 const Id op1 = Visit(expr.operand1);
1668 return decomp.Emit(decomp.OpLogicalNot(type_def, op1)); 1668 return decomp.Emit(decomp.OpLogicalNot(type_def, op1));
1669 } 1669 }
1670 1670
1671 Id operator()(VideoCommon::Shader::ExprPredicate& expr) { 1671 Id operator()(const ExprPredicate& expr) {
1672 const auto pred = static_cast<Tegra::Shader::Pred>(expr.predicate); 1672 const auto pred = static_cast<Tegra::Shader::Pred>(expr.predicate);
1673 return decomp.Emit(decomp.OpLoad(decomp.t_bool, decomp.predicates.at(pred))); 1673 return decomp.Emit(decomp.OpLoad(decomp.t_bool, decomp.predicates.at(pred)));
1674 } 1674 }
1675 1675
1676 Id operator()(VideoCommon::Shader::ExprCondCode& expr) { 1676 Id operator()(const ExprCondCode& expr) {
1677 const Node cc = decomp.ir.GetConditionCode(expr.cc); 1677 const Node cc = decomp.ir.GetConditionCode(expr.cc);
1678 Id target; 1678 Id target;
1679 1679
@@ -1696,15 +1696,15 @@ public:
1696 return decomp.Emit(decomp.OpLoad(decomp.t_bool, target)); 1696 return decomp.Emit(decomp.OpLoad(decomp.t_bool, target));
1697 } 1697 }
1698 1698
1699 Id operator()(VideoCommon::Shader::ExprVar& expr) { 1699 Id operator()(const ExprVar& expr) {
1700 return decomp.Emit(decomp.OpLoad(decomp.t_bool, decomp.flow_variables.at(expr.var_index))); 1700 return decomp.Emit(decomp.OpLoad(decomp.t_bool, decomp.flow_variables.at(expr.var_index)));
1701 } 1701 }
1702 1702
1703 Id operator()(VideoCommon::Shader::ExprBoolean& expr) { 1703 Id operator()(const ExprBoolean& expr) {
1704 return expr.value ? decomp.v_true : decomp.v_false; 1704 return expr.value ? decomp.v_true : decomp.v_false;
1705 } 1705 }
1706 1706
1707 Id Visit(VideoCommon::Shader::Expr& node) { 1707 Id Visit(const Expr& node) {
1708 return std::visit(*this, *node); 1708 return std::visit(*this, *node);
1709 } 1709 }
1710 1710
@@ -1716,7 +1716,7 @@ class ASTDecompiler {
1716public: 1716public:
1717 explicit ASTDecompiler(SPIRVDecompiler& decomp) : decomp{decomp} {} 1717 explicit ASTDecompiler(SPIRVDecompiler& decomp) : decomp{decomp} {}
1718 1718
1719 void operator()(VideoCommon::Shader::ASTProgram& ast) { 1719 void operator()(const ASTProgram& ast) {
1720 ASTNode current = ast.nodes.GetFirst(); 1720 ASTNode current = ast.nodes.GetFirst();
1721 while (current) { 1721 while (current) {
1722 Visit(current); 1722 Visit(current);
@@ -1724,7 +1724,7 @@ public:
1724 } 1724 }
1725 } 1725 }
1726 1726
1727 void operator()(VideoCommon::Shader::ASTIfThen& ast) { 1727 void operator()(const ASTIfThen& ast) {
1728 ExprDecompiler expr_parser{decomp}; 1728 ExprDecompiler expr_parser{decomp};
1729 const Id condition = expr_parser.Visit(ast.condition); 1729 const Id condition = expr_parser.Visit(ast.condition);
1730 const Id then_label = decomp.OpLabel(); 1730 const Id then_label = decomp.OpLabel();
@@ -1741,33 +1741,33 @@ public:
1741 decomp.Emit(endif_label); 1741 decomp.Emit(endif_label);
1742 } 1742 }
1743 1743
1744 void operator()(VideoCommon::Shader::ASTIfElse& ast) { 1744 void operator()([[maybe_unused]] const ASTIfElse& ast) {
1745 UNREACHABLE(); 1745 UNREACHABLE();
1746 } 1746 }
1747 1747
1748 void operator()(VideoCommon::Shader::ASTBlockEncoded& ast) { 1748 void operator()([[maybe_unused]] const ASTBlockEncoded& ast) {
1749 UNREACHABLE(); 1749 UNREACHABLE();
1750 } 1750 }
1751 1751
1752 void operator()(VideoCommon::Shader::ASTBlockDecoded& ast) { 1752 void operator()(const ASTBlockDecoded& ast) {
1753 decomp.VisitBasicBlock(ast.nodes); 1753 decomp.VisitBasicBlock(ast.nodes);
1754 } 1754 }
1755 1755
1756 void operator()(VideoCommon::Shader::ASTVarSet& ast) { 1756 void operator()(const ASTVarSet& ast) {
1757 ExprDecompiler expr_parser{decomp}; 1757 ExprDecompiler expr_parser{decomp};
1758 const Id condition = expr_parser.Visit(ast.condition); 1758 const Id condition = expr_parser.Visit(ast.condition);
1759 decomp.Emit(decomp.OpStore(decomp.flow_variables.at(ast.index), condition)); 1759 decomp.Emit(decomp.OpStore(decomp.flow_variables.at(ast.index), condition));
1760 } 1760 }
1761 1761
1762 void operator()(VideoCommon::Shader::ASTLabel& ast) { 1762 void operator()([[maybe_unused]] const ASTLabel& ast) {
1763 // Do nothing 1763 // Do nothing
1764 } 1764 }
1765 1765
1766 void operator()(VideoCommon::Shader::ASTGoto& ast) { 1766 void operator()([[maybe_unused]] const ASTGoto& ast) {
1767 UNREACHABLE(); 1767 UNREACHABLE();
1768 } 1768 }
1769 1769
1770 void operator()(VideoCommon::Shader::ASTDoWhile& ast) { 1770 void operator()(const ASTDoWhile& ast) {
1771 const Id loop_label = decomp.OpLabel(); 1771 const Id loop_label = decomp.OpLabel();
1772 const Id endloop_label = decomp.OpLabel(); 1772 const Id endloop_label = decomp.OpLabel();
1773 const Id loop_start_block = decomp.OpLabel(); 1773 const Id loop_start_block = decomp.OpLabel();
@@ -1790,7 +1790,7 @@ public:
1790 decomp.Emit(endloop_label); 1790 decomp.Emit(endloop_label);
1791 } 1791 }
1792 1792
1793 void operator()(VideoCommon::Shader::ASTReturn& ast) { 1793 void operator()(const ASTReturn& ast) {
1794 if (!VideoCommon::Shader::ExprIsTrue(ast.condition)) { 1794 if (!VideoCommon::Shader::ExprIsTrue(ast.condition)) {
1795 ExprDecompiler expr_parser{decomp}; 1795 ExprDecompiler expr_parser{decomp};
1796 const Id condition = expr_parser.Visit(ast.condition); 1796 const Id condition = expr_parser.Visit(ast.condition);
@@ -1820,7 +1820,7 @@ public:
1820 } 1820 }
1821 } 1821 }
1822 1822
1823 void operator()(VideoCommon::Shader::ASTBreak& ast) { 1823 void operator()(const ASTBreak& ast) {
1824 if (!VideoCommon::Shader::ExprIsTrue(ast.condition)) { 1824 if (!VideoCommon::Shader::ExprIsTrue(ast.condition)) {
1825 ExprDecompiler expr_parser{decomp}; 1825 ExprDecompiler expr_parser{decomp};
1826 const Id condition = expr_parser.Visit(ast.condition); 1826 const Id condition = expr_parser.Visit(ast.condition);
@@ -1840,7 +1840,7 @@ public:
1840 } 1840 }
1841 } 1841 }
1842 1842
1843 void Visit(VideoCommon::Shader::ASTNode& node) { 1843 void Visit(const ASTNode& node) {
1844 std::visit(*this, *node->GetInnerData()); 1844 std::visit(*this, *node->GetInnerData());
1845 } 1845 }
1846 1846
@@ -1856,9 +1856,11 @@ void SPIRVDecompiler::DecompileAST() {
1856 Name(id, fmt::format("flow_var_{}", i)); 1856 Name(id, fmt::format("flow_var_{}", i));
1857 flow_variables.emplace(i, AddGlobalVariable(id)); 1857 flow_variables.emplace(i, AddGlobalVariable(id));
1858 } 1858 }
1859
1860 const ASTNode program = ir.GetASTProgram();
1859 ASTDecompiler decompiler{*this}; 1861 ASTDecompiler decompiler{*this};
1860 VideoCommon::Shader::ASTNode program = ir.GetASTProgram();
1861 decompiler.Visit(program); 1862 decompiler.Visit(program);
1863
1862 const Id next_block = OpLabel(); 1864 const Id next_block = OpLabel();
1863 Emit(OpBranch(next_block)); 1865 Emit(OpBranch(next_block));
1864 Emit(next_block); 1866 Emit(next_block);
diff --git a/src/video_core/shader/ast.cpp b/src/video_core/shader/ast.cpp
index 436d45f4b..e43aecc18 100644
--- a/src/video_core/shader/ast.cpp
+++ b/src/video_core/shader/ast.cpp
@@ -3,6 +3,9 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <string> 5#include <string>
6#include <string_view>
7
8#include <fmt/format.h>
6 9
7#include "common/assert.h" 10#include "common/assert.h"
8#include "common/common_types.h" 11#include "common/common_types.h"
@@ -229,7 +232,8 @@ public:
229 return inner; 232 return inner;
230 } 233 }
231 234
232 std::string inner{}; 235private:
236 std::string inner;
233}; 237};
234 238
235class ASTPrinter { 239class ASTPrinter {
@@ -249,7 +253,7 @@ public:
249 void operator()(const ASTIfThen& ast) { 253 void operator()(const ASTIfThen& ast) {
250 ExprPrinter expr_parser{}; 254 ExprPrinter expr_parser{};
251 std::visit(expr_parser, *ast.condition); 255 std::visit(expr_parser, *ast.condition);
252 inner += Ident() + "if (" + expr_parser.GetResult() + ") {\n"; 256 inner += fmt::format("{}if ({}) {{\n", Indent(), expr_parser.GetResult());
253 scope++; 257 scope++;
254 ASTNode current = ast.nodes.GetFirst(); 258 ASTNode current = ast.nodes.GetFirst();
255 while (current) { 259 while (current) {
@@ -257,11 +261,13 @@ public:
257 current = current->GetNext(); 261 current = current->GetNext();
258 } 262 }
259 scope--; 263 scope--;
260 inner += Ident() + "}\n"; 264 inner += fmt::format("{}}}\n", Indent());
261 } 265 }
262 266
263 void operator()(const ASTIfElse& ast) { 267 void operator()(const ASTIfElse& ast) {
264 inner += Ident() + "else {\n"; 268 inner += Indent();
269 inner += "else {\n";
270
265 scope++; 271 scope++;
266 ASTNode current = ast.nodes.GetFirst(); 272 ASTNode current = ast.nodes.GetFirst();
267 while (current) { 273 while (current) {
@@ -269,40 +275,41 @@ public:
269 current = current->GetNext(); 275 current = current->GetNext();
270 } 276 }
271 scope--; 277 scope--;
272 inner += Ident() + "}\n"; 278
279 inner += Indent();
280 inner += "}\n";
273 } 281 }
274 282
275 void operator()(const ASTBlockEncoded& ast) { 283 void operator()(const ASTBlockEncoded& ast) {
276 inner += Ident() + "Block(" + std::to_string(ast.start) + ", " + std::to_string(ast.end) + 284 inner += fmt::format("{}Block({}, {});\n", Indent(), ast.start, ast.end);
277 ");\n";
278 } 285 }
279 286
280 void operator()(const ASTBlockDecoded& ast) { 287 void operator()([[maybe_unused]] const ASTBlockDecoded& ast) {
281 inner += Ident() + "Block;\n"; 288 inner += Indent();
289 inner += "Block;\n";
282 } 290 }
283 291
284 void operator()(const ASTVarSet& ast) { 292 void operator()(const ASTVarSet& ast) {
285 ExprPrinter expr_parser{}; 293 ExprPrinter expr_parser{};
286 std::visit(expr_parser, *ast.condition); 294 std::visit(expr_parser, *ast.condition);
287 inner += 295 inner += fmt::format("{}V{} := {};\n", Indent(), ast.index, expr_parser.GetResult());
288 Ident() + "V" + std::to_string(ast.index) + " := " + expr_parser.GetResult() + ";\n";
289 } 296 }
290 297
291 void operator()(const ASTLabel& ast) { 298 void operator()(const ASTLabel& ast) {
292 inner += "Label_" + std::to_string(ast.index) + ":\n"; 299 inner += fmt::format("Label_{}:\n", ast.index);
293 } 300 }
294 301
295 void operator()(const ASTGoto& ast) { 302 void operator()(const ASTGoto& ast) {
296 ExprPrinter expr_parser{}; 303 ExprPrinter expr_parser{};
297 std::visit(expr_parser, *ast.condition); 304 std::visit(expr_parser, *ast.condition);
298 inner += Ident() + "(" + expr_parser.GetResult() + ") -> goto Label_" + 305 inner +=
299 std::to_string(ast.label) + ";\n"; 306 fmt::format("{}({}) -> goto Label_{};\n", Indent(), expr_parser.GetResult(), ast.label);
300 } 307 }
301 308
302 void operator()(const ASTDoWhile& ast) { 309 void operator()(const ASTDoWhile& ast) {
303 ExprPrinter expr_parser{}; 310 ExprPrinter expr_parser{};
304 std::visit(expr_parser, *ast.condition); 311 std::visit(expr_parser, *ast.condition);
305 inner += Ident() + "do {\n"; 312 inner += fmt::format("{}do {{\n", Indent());
306 scope++; 313 scope++;
307 ASTNode current = ast.nodes.GetFirst(); 314 ASTNode current = ast.nodes.GetFirst();
308 while (current) { 315 while (current) {
@@ -310,32 +317,23 @@ public:
310 current = current->GetNext(); 317 current = current->GetNext();
311 } 318 }
312 scope--; 319 scope--;
313 inner += Ident() + "} while (" + expr_parser.GetResult() + ");\n"; 320 inner += fmt::format("{}}} while ({});\n", Indent(), expr_parser.GetResult());
314 } 321 }
315 322
316 void operator()(const ASTReturn& ast) { 323 void operator()(const ASTReturn& ast) {
317 ExprPrinter expr_parser{}; 324 ExprPrinter expr_parser{};
318 std::visit(expr_parser, *ast.condition); 325 std::visit(expr_parser, *ast.condition);
319 inner += Ident() + "(" + expr_parser.GetResult() + ") -> " + 326 inner += fmt::format("{}({}) -> {};\n", Indent(), expr_parser.GetResult(),
320 (ast.kills ? "discard" : "exit") + ";\n"; 327 ast.kills ? "discard" : "exit");
321 } 328 }
322 329
323 void operator()(const ASTBreak& ast) { 330 void operator()(const ASTBreak& ast) {
324 ExprPrinter expr_parser{}; 331 ExprPrinter expr_parser{};
325 std::visit(expr_parser, *ast.condition); 332 std::visit(expr_parser, *ast.condition);
326 inner += Ident() + "(" + expr_parser.GetResult() + ") -> break;\n"; 333 inner += fmt::format("{}({}) -> break;\n", Indent(), expr_parser.GetResult());
327 } 334 }
328 335
329 std::string& Ident() { 336 void Visit(const ASTNode& node) {
330 if (memo_scope == scope) {
331 return tabs_memo;
332 }
333 tabs_memo = tabs.substr(0, scope * 2);
334 memo_scope = scope;
335 return tabs_memo;
336 }
337
338 void Visit(ASTNode& node) {
339 std::visit(*this, *node->GetInnerData()); 337 std::visit(*this, *node->GetInnerData());
340 } 338 }
341 339
@@ -344,16 +342,29 @@ public:
344 } 342 }
345 343
346private: 344private:
345 std::string_view Indent() {
346 if (space_segment_scope == scope) {
347 return space_segment;
348 }
349
350 // Ensure that we don't exceed our view.
351 ASSERT(scope * 2 < spaces.size());
352
353 space_segment = spaces.substr(0, scope * 2);
354 space_segment_scope = scope;
355 return space_segment;
356 }
357
347 std::string inner{}; 358 std::string inner{};
348 u32 scope{}; 359 std::string_view space_segment;
349 360
350 std::string tabs_memo{}; 361 u32 scope{};
351 u32 memo_scope{}; 362 u32 space_segment_scope{};
352 363
353 static constexpr std::string_view tabs{" "}; 364 static constexpr std::string_view spaces{" "};
354}; 365};
355 366
356std::string ASTManager::Print() { 367std::string ASTManager::Print() const {
357 ASTPrinter printer{}; 368 ASTPrinter printer{};
358 printer.Visit(main_node); 369 printer.Visit(main_node);
359 return printer.GetResult(); 370 return printer.GetResult();
@@ -549,13 +560,13 @@ bool ASTManager::DirectlyRelated(const ASTNode& first, const ASTNode& second) co
549 return min->GetParent() == max->GetParent(); 560 return min->GetParent() == max->GetParent();
550} 561}
551 562
552void ASTManager::ShowCurrentState(std::string_view state) { 563void ASTManager::ShowCurrentState(std::string_view state) const {
553 LOG_CRITICAL(HW_GPU, "\nState {}:\n\n{}\n", state, Print()); 564 LOG_CRITICAL(HW_GPU, "\nState {}:\n\n{}\n", state, Print());
554 SanityCheck(); 565 SanityCheck();
555} 566}
556 567
557void ASTManager::SanityCheck() { 568void ASTManager::SanityCheck() const {
558 for (auto& label : labels) { 569 for (const auto& label : labels) {
559 if (!label->GetParent()) { 570 if (!label->GetParent()) {
560 LOG_CRITICAL(HW_GPU, "Sanity Check Failed"); 571 LOG_CRITICAL(HW_GPU, "Sanity Check Failed");
561 } 572 }
diff --git a/src/video_core/shader/ast.h b/src/video_core/shader/ast.h
index d7bf11821..a2f0044ba 100644
--- a/src/video_core/shader/ast.h
+++ b/src/video_core/shader/ast.h
@@ -328,13 +328,13 @@ public:
328 328
329 void InsertReturn(Expr condition, bool kills); 329 void InsertReturn(Expr condition, bool kills);
330 330
331 std::string Print(); 331 std::string Print() const;
332 332
333 void Decompile(); 333 void Decompile();
334 334
335 void ShowCurrentState(std::string_view state); 335 void ShowCurrentState(std::string_view state) const;
336 336
337 void SanityCheck(); 337 void SanityCheck() const;
338 338
339 void Clear(); 339 void Clear();
340 340
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp
index 268d1aed0..9d21f45de 100644
--- a/src/video_core/shader/control_flow.cpp
+++ b/src/video_core/shader/control_flow.cpp
@@ -473,8 +473,8 @@ void DecompileShader(CFGRebuildState& state) {
473 state.manager->Decompile(); 473 state.manager->Decompile();
474} 474}
475 475
476std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 program_size, 476std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
477 u32 start_address, 477 std::size_t program_size, u32 start_address,
478 const CompilerSettings& settings) { 478 const CompilerSettings& settings) {
479 auto result_out = std::make_unique<ShaderCharacteristics>(); 479 auto result_out = std::make_unique<ShaderCharacteristics>();
480 if (settings.depth == CompileDepth::BruteForce) { 480 if (settings.depth == CompileDepth::BruteForce) {
diff --git a/src/video_core/shader/control_flow.h b/src/video_core/shader/control_flow.h
index 74e54a5c7..37e987d62 100644
--- a/src/video_core/shader/control_flow.h
+++ b/src/video_core/shader/control_flow.h
@@ -76,8 +76,8 @@ struct ShaderCharacteristics {
76 CompilerSettings settings{}; 76 CompilerSettings settings{};
77}; 77};
78 78
79std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 program_size, 79std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
80 u32 start_address, 80 std::size_t program_size, u32 start_address,
81 const CompilerSettings& settings); 81 const CompilerSettings& settings);
82 82
83} // namespace VideoCommon::Shader 83} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index 338bab17c..447fb5c1d 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -410,7 +410,7 @@ public:
410 explicit OperationNode(OperationCode code) : OperationNode(code, Meta{}) {} 410 explicit OperationNode(OperationCode code) : OperationNode(code, Meta{}) {}
411 411
412 explicit OperationNode(OperationCode code, Meta meta) 412 explicit OperationNode(OperationCode code, Meta meta)
413 : OperationNode(code, meta, std::vector<Node>{}) {} 413 : OperationNode(code, std::move(meta), std::vector<Node>{}) {}
414 414
415 explicit OperationNode(OperationCode code, std::vector<Node> operands) 415 explicit OperationNode(OperationCode code, std::vector<Node> operands)
416 : OperationNode(code, Meta{}, std::move(operands)) {} 416 : OperationNode(code, Meta{}, std::move(operands)) {}
diff --git a/src/video_core/surface.cpp b/src/video_core/surface.cpp
index 250afc6d6..9a3c05288 100644
--- a/src/video_core/surface.cpp
+++ b/src/video_core/surface.cpp
@@ -212,6 +212,14 @@ PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
212 break; 212 break;
213 } 213 }
214 break; 214 break;
215 case Tegra::Texture::TextureFormat::A4B4G4R4:
216 switch (component_type) {
217 case Tegra::Texture::ComponentType::UNORM:
218 return PixelFormat::R4G4B4A4U;
219 default:
220 break;
221 }
222 break;
215 case Tegra::Texture::TextureFormat::R8: 223 case Tegra::Texture::TextureFormat::R8:
216 switch (component_type) { 224 switch (component_type) {
217 case Tegra::Texture::ComponentType::UNORM: 225 case Tegra::Texture::ComponentType::UNORM:
@@ -252,6 +260,7 @@ PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
252 default: 260 default:
253 break; 261 break;
254 } 262 }
263 break;
255 case Tegra::Texture::TextureFormat::R32_G32_B32_A32: 264 case Tegra::Texture::TextureFormat::R32_G32_B32_A32:
256 switch (component_type) { 265 switch (component_type) {
257 case Tegra::Texture::ComponentType::FLOAT: 266 case Tegra::Texture::ComponentType::FLOAT:
@@ -350,6 +359,16 @@ PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
350 return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5; 359 return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5;
351 case Tegra::Texture::TextureFormat::ASTC_2D_10X8: 360 case Tegra::Texture::TextureFormat::ASTC_2D_10X8:
352 return is_srgb ? PixelFormat::ASTC_2D_10X8_SRGB : PixelFormat::ASTC_2D_10X8; 361 return is_srgb ? PixelFormat::ASTC_2D_10X8_SRGB : PixelFormat::ASTC_2D_10X8;
362 case Tegra::Texture::TextureFormat::ASTC_2D_6X6:
363 return is_srgb ? PixelFormat::ASTC_2D_6X6_SRGB : PixelFormat::ASTC_2D_6X6;
364 case Tegra::Texture::TextureFormat::ASTC_2D_10X10:
365 return is_srgb ? PixelFormat::ASTC_2D_10X10_SRGB : PixelFormat::ASTC_2D_10X10;
366 case Tegra::Texture::TextureFormat::ASTC_2D_12X12:
367 return is_srgb ? PixelFormat::ASTC_2D_12X12_SRGB : PixelFormat::ASTC_2D_12X12;
368 case Tegra::Texture::TextureFormat::ASTC_2D_8X6:
369 return is_srgb ? PixelFormat::ASTC_2D_8X6_SRGB : PixelFormat::ASTC_2D_8X6;
370 case Tegra::Texture::TextureFormat::ASTC_2D_6X5:
371 return is_srgb ? PixelFormat::ASTC_2D_6X5_SRGB : PixelFormat::ASTC_2D_6X5;
353 case Tegra::Texture::TextureFormat::R16_G16: 372 case Tegra::Texture::TextureFormat::R16_G16:
354 switch (component_type) { 373 switch (component_type) {
355 case Tegra::Texture::ComponentType::FLOAT: 374 case Tegra::Texture::ComponentType::FLOAT:
@@ -510,6 +529,16 @@ bool IsPixelFormatASTC(PixelFormat format) {
510 case PixelFormat::ASTC_2D_8X5_SRGB: 529 case PixelFormat::ASTC_2D_8X5_SRGB:
511 case PixelFormat::ASTC_2D_10X8: 530 case PixelFormat::ASTC_2D_10X8:
512 case PixelFormat::ASTC_2D_10X8_SRGB: 531 case PixelFormat::ASTC_2D_10X8_SRGB:
532 case PixelFormat::ASTC_2D_6X6:
533 case PixelFormat::ASTC_2D_6X6_SRGB:
534 case PixelFormat::ASTC_2D_10X10:
535 case PixelFormat::ASTC_2D_10X10_SRGB:
536 case PixelFormat::ASTC_2D_12X12:
537 case PixelFormat::ASTC_2D_12X12_SRGB:
538 case PixelFormat::ASTC_2D_8X6:
539 case PixelFormat::ASTC_2D_8X6_SRGB:
540 case PixelFormat::ASTC_2D_6X5:
541 case PixelFormat::ASTC_2D_6X5_SRGB:
513 return true; 542 return true;
514 default: 543 default:
515 return false; 544 return false;
@@ -530,6 +559,11 @@ bool IsPixelFormatSRGB(PixelFormat format) {
530 case PixelFormat::ASTC_2D_5X4_SRGB: 559 case PixelFormat::ASTC_2D_5X4_SRGB:
531 case PixelFormat::ASTC_2D_5X5_SRGB: 560 case PixelFormat::ASTC_2D_5X5_SRGB:
532 case PixelFormat::ASTC_2D_10X8_SRGB: 561 case PixelFormat::ASTC_2D_10X8_SRGB:
562 case PixelFormat::ASTC_2D_6X6_SRGB:
563 case PixelFormat::ASTC_2D_10X10_SRGB:
564 case PixelFormat::ASTC_2D_12X12_SRGB:
565 case PixelFormat::ASTC_2D_8X6_SRGB:
566 case PixelFormat::ASTC_2D_6X5_SRGB:
533 return true; 567 return true;
534 default: 568 default:
535 return false; 569 return false;
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 1e1c432a5..97668f802 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -67,27 +67,38 @@ enum class PixelFormat {
67 DXT23_SRGB = 49, 67 DXT23_SRGB = 49,
68 DXT45_SRGB = 50, 68 DXT45_SRGB = 50,
69 BC7U_SRGB = 51, 69 BC7U_SRGB = 51,
70 ASTC_2D_4X4_SRGB = 52, 70 R4G4B4A4U = 52,
71 ASTC_2D_8X8_SRGB = 53, 71 ASTC_2D_4X4_SRGB = 53,
72 ASTC_2D_8X5_SRGB = 54, 72 ASTC_2D_8X8_SRGB = 54,
73 ASTC_2D_5X4_SRGB = 55, 73 ASTC_2D_8X5_SRGB = 55,
74 ASTC_2D_5X5 = 56, 74 ASTC_2D_5X4_SRGB = 56,
75 ASTC_2D_5X5_SRGB = 57, 75 ASTC_2D_5X5 = 57,
76 ASTC_2D_10X8 = 58, 76 ASTC_2D_5X5_SRGB = 58,
77 ASTC_2D_10X8_SRGB = 59, 77 ASTC_2D_10X8 = 59,
78 ASTC_2D_10X8_SRGB = 60,
79 ASTC_2D_6X6 = 61,
80 ASTC_2D_6X6_SRGB = 62,
81 ASTC_2D_10X10 = 63,
82 ASTC_2D_10X10_SRGB = 64,
83 ASTC_2D_12X12 = 65,
84 ASTC_2D_12X12_SRGB = 66,
85 ASTC_2D_8X6 = 67,
86 ASTC_2D_8X6_SRGB = 68,
87 ASTC_2D_6X5 = 69,
88 ASTC_2D_6X5_SRGB = 70,
78 89
79 MaxColorFormat, 90 MaxColorFormat,
80 91
81 // Depth formats 92 // Depth formats
82 Z32F = 60, 93 Z32F = 71,
83 Z16 = 61, 94 Z16 = 72,
84 95
85 MaxDepthFormat, 96 MaxDepthFormat,
86 97
87 // DepthStencil formats 98 // DepthStencil formats
88 Z24S8 = 62, 99 Z24S8 = 73,
89 S8Z24 = 63, 100 S8Z24 = 74,
90 Z32FS8 = 64, 101 Z32FS8 = 75,
91 102
92 MaxDepthStencilFormat, 103 MaxDepthStencilFormat,
93 104
@@ -177,6 +188,7 @@ constexpr std::array<u32, MaxPixelFormat> compression_factor_shift_table = {{
177 2, // DXT23_SRGB 188 2, // DXT23_SRGB
178 2, // DXT45_SRGB 189 2, // DXT45_SRGB
179 2, // BC7U_SRGB 190 2, // BC7U_SRGB
191 0, // R4G4B4A4U
180 2, // ASTC_2D_4X4_SRGB 192 2, // ASTC_2D_4X4_SRGB
181 2, // ASTC_2D_8X8_SRGB 193 2, // ASTC_2D_8X8_SRGB
182 2, // ASTC_2D_8X5_SRGB 194 2, // ASTC_2D_8X5_SRGB
@@ -185,6 +197,16 @@ constexpr std::array<u32, MaxPixelFormat> compression_factor_shift_table = {{
185 2, // ASTC_2D_5X5_SRGB 197 2, // ASTC_2D_5X5_SRGB
186 2, // ASTC_2D_10X8 198 2, // ASTC_2D_10X8
187 2, // ASTC_2D_10X8_SRGB 199 2, // ASTC_2D_10X8_SRGB
200 2, // ASTC_2D_6X6
201 2, // ASTC_2D_6X6_SRGB
202 2, // ASTC_2D_10X10
203 2, // ASTC_2D_10X10_SRGB
204 2, // ASTC_2D_12X12
205 2, // ASTC_2D_12X12_SRGB
206 2, // ASTC_2D_8X6
207 2, // ASTC_2D_8X6_SRGB
208 2, // ASTC_2D_6X5
209 2, // ASTC_2D_6X5_SRGB
188 0, // Z32F 210 0, // Z32F
189 0, // Z16 211 0, // Z16
190 0, // Z24S8 212 0, // Z24S8
@@ -261,6 +283,7 @@ constexpr std::array<u32, MaxPixelFormat> block_width_table = {{
261 4, // DXT23_SRGB 283 4, // DXT23_SRGB
262 4, // DXT45_SRGB 284 4, // DXT45_SRGB
263 4, // BC7U_SRGB 285 4, // BC7U_SRGB
286 1, // R4G4B4A4U
264 4, // ASTC_2D_4X4_SRGB 287 4, // ASTC_2D_4X4_SRGB
265 8, // ASTC_2D_8X8_SRGB 288 8, // ASTC_2D_8X8_SRGB
266 8, // ASTC_2D_8X5_SRGB 289 8, // ASTC_2D_8X5_SRGB
@@ -269,6 +292,16 @@ constexpr std::array<u32, MaxPixelFormat> block_width_table = {{
269 5, // ASTC_2D_5X5_SRGB 292 5, // ASTC_2D_5X5_SRGB
270 10, // ASTC_2D_10X8 293 10, // ASTC_2D_10X8
271 10, // ASTC_2D_10X8_SRGB 294 10, // ASTC_2D_10X8_SRGB
295 6, // ASTC_2D_6X6
296 6, // ASTC_2D_6X6_SRGB
297 10, // ASTC_2D_10X10
298 10, // ASTC_2D_10X10_SRGB
299 12, // ASTC_2D_12X12
300 12, // ASTC_2D_12X12_SRGB
301 8, // ASTC_2D_8X6
302 8, // ASTC_2D_8X6_SRGB
303 6, // ASTC_2D_6X5
304 6, // ASTC_2D_6X5_SRGB
272 1, // Z32F 305 1, // Z32F
273 1, // Z16 306 1, // Z16
274 1, // Z24S8 307 1, // Z24S8
@@ -285,71 +318,82 @@ static constexpr u32 GetDefaultBlockWidth(PixelFormat format) {
285} 318}
286 319
287constexpr std::array<u32, MaxPixelFormat> block_height_table = {{ 320constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
288 1, // ABGR8U 321 1, // ABGR8U
289 1, // ABGR8S 322 1, // ABGR8S
290 1, // ABGR8UI 323 1, // ABGR8UI
291 1, // B5G6R5U 324 1, // B5G6R5U
292 1, // A2B10G10R10U 325 1, // A2B10G10R10U
293 1, // A1B5G5R5U 326 1, // A1B5G5R5U
294 1, // R8U 327 1, // R8U
295 1, // R8UI 328 1, // R8UI
296 1, // RGBA16F 329 1, // RGBA16F
297 1, // RGBA16U 330 1, // RGBA16U
298 1, // RGBA16UI 331 1, // RGBA16UI
299 1, // R11FG11FB10F 332 1, // R11FG11FB10F
300 1, // RGBA32UI 333 1, // RGBA32UI
301 4, // DXT1 334 4, // DXT1
302 4, // DXT23 335 4, // DXT23
303 4, // DXT45 336 4, // DXT45
304 4, // DXN1 337 4, // DXN1
305 4, // DXN2UNORM 338 4, // DXN2UNORM
306 4, // DXN2SNORM 339 4, // DXN2SNORM
307 4, // BC7U 340 4, // BC7U
308 4, // BC6H_UF16 341 4, // BC6H_UF16
309 4, // BC6H_SF16 342 4, // BC6H_SF16
310 4, // ASTC_2D_4X4 343 4, // ASTC_2D_4X4
311 1, // BGRA8 344 1, // BGRA8
312 1, // RGBA32F 345 1, // RGBA32F
313 1, // RG32F 346 1, // RG32F
314 1, // R32F 347 1, // R32F
315 1, // R16F 348 1, // R16F
316 1, // R16U 349 1, // R16U
317 1, // R16S 350 1, // R16S
318 1, // R16UI 351 1, // R16UI
319 1, // R16I 352 1, // R16I
320 1, // RG16 353 1, // RG16
321 1, // RG16F 354 1, // RG16F
322 1, // RG16UI 355 1, // RG16UI
323 1, // RG16I 356 1, // RG16I
324 1, // RG16S 357 1, // RG16S
325 1, // RGB32F 358 1, // RGB32F
326 1, // RGBA8_SRGB 359 1, // RGBA8_SRGB
327 1, // RG8U 360 1, // RG8U
328 1, // RG8S 361 1, // RG8S
329 1, // RG32UI 362 1, // RG32UI
330 1, // RGBX16F 363 1, // RGBX16F
331 1, // R32UI 364 1, // R32UI
332 8, // ASTC_2D_8X8 365 8, // ASTC_2D_8X8
333 5, // ASTC_2D_8X5 366 5, // ASTC_2D_8X5
334 4, // ASTC_2D_5X4 367 4, // ASTC_2D_5X4
335 1, // BGRA8_SRGB 368 1, // BGRA8_SRGB
336 4, // DXT1_SRGB 369 4, // DXT1_SRGB
337 4, // DXT23_SRGB 370 4, // DXT23_SRGB
338 4, // DXT45_SRGB 371 4, // DXT45_SRGB
339 4, // BC7U_SRGB 372 4, // BC7U_SRGB
340 4, // ASTC_2D_4X4_SRGB 373 1, // R4G4B4A4U
341 8, // ASTC_2D_8X8_SRGB 374 4, // ASTC_2D_4X4_SRGB
342 5, // ASTC_2D_8X5_SRGB 375 8, // ASTC_2D_8X8_SRGB
343 4, // ASTC_2D_5X4_SRGB 376 5, // ASTC_2D_8X5_SRGB
344 5, // ASTC_2D_5X5 377 4, // ASTC_2D_5X4_SRGB
345 5, // ASTC_2D_5X5_SRGB 378 5, // ASTC_2D_5X5
346 8, // ASTC_2D_10X8 379 5, // ASTC_2D_5X5_SRGB
347 8, // ASTC_2D_10X8_SRGB 380 8, // ASTC_2D_10X8
348 1, // Z32F 381 8, // ASTC_2D_10X8_SRGB
349 1, // Z16 382 6, // ASTC_2D_6X6
350 1, // Z24S8 383 6, // ASTC_2D_6X6_SRGB
351 1, // S8Z24 384 10, // ASTC_2D_10X10
352 1, // Z32FS8 385 10, // ASTC_2D_10X10_SRGB
386 12, // ASTC_2D_12X12
387 12, // ASTC_2D_12X12_SRGB
388 6, // ASTC_2D_8X6
389 6, // ASTC_2D_8X6_SRGB
390 5, // ASTC_2D_6X5
391 5, // ASTC_2D_6X5_SRGB
392 1, // Z32F
393 1, // Z16
394 1, // Z24S8
395 1, // S8Z24
396 1, // Z32FS8
353}}; 397}};
354 398
355static constexpr u32 GetDefaultBlockHeight(PixelFormat format) { 399static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
@@ -413,6 +457,7 @@ constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
413 128, // DXT23_SRGB 457 128, // DXT23_SRGB
414 128, // DXT45_SRGB 458 128, // DXT45_SRGB
415 128, // BC7U 459 128, // BC7U
460 16, // R4G4B4A4U
416 128, // ASTC_2D_4X4_SRGB 461 128, // ASTC_2D_4X4_SRGB
417 128, // ASTC_2D_8X8_SRGB 462 128, // ASTC_2D_8X8_SRGB
418 128, // ASTC_2D_8X5_SRGB 463 128, // ASTC_2D_8X5_SRGB
@@ -421,6 +466,16 @@ constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
421 128, // ASTC_2D_5X5_SRGB 466 128, // ASTC_2D_5X5_SRGB
422 128, // ASTC_2D_10X8 467 128, // ASTC_2D_10X8
423 128, // ASTC_2D_10X8_SRGB 468 128, // ASTC_2D_10X8_SRGB
469 128, // ASTC_2D_6X6
470 128, // ASTC_2D_6X6_SRGB
471 128, // ASTC_2D_10X10
472 128, // ASTC_2D_10X10_SRGB
473 128, // ASTC_2D_12X12
474 128, // ASTC_2D_12X12_SRGB
475 128, // ASTC_2D_8X6
476 128, // ASTC_2D_8X6_SRGB
477 128, // ASTC_2D_6X5
478 128, // ASTC_2D_6X5_SRGB
424 32, // Z32F 479 32, // Z32F
425 16, // Z16 480 16, // Z16
426 32, // Z24S8 481 32, // Z24S8
@@ -504,6 +559,7 @@ constexpr std::array<SurfaceCompression, MaxPixelFormat> compression_type_table
504 SurfaceCompression::Compressed, // DXT23_SRGB 559 SurfaceCompression::Compressed, // DXT23_SRGB
505 SurfaceCompression::Compressed, // DXT45_SRGB 560 SurfaceCompression::Compressed, // DXT45_SRGB
506 SurfaceCompression::Compressed, // BC7U_SRGB 561 SurfaceCompression::Compressed, // BC7U_SRGB
562 SurfaceCompression::None, // R4G4B4A4U
507 SurfaceCompression::Converted, // ASTC_2D_4X4_SRGB 563 SurfaceCompression::Converted, // ASTC_2D_4X4_SRGB
508 SurfaceCompression::Converted, // ASTC_2D_8X8_SRGB 564 SurfaceCompression::Converted, // ASTC_2D_8X8_SRGB
509 SurfaceCompression::Converted, // ASTC_2D_8X5_SRGB 565 SurfaceCompression::Converted, // ASTC_2D_8X5_SRGB
@@ -512,6 +568,16 @@ constexpr std::array<SurfaceCompression, MaxPixelFormat> compression_type_table
512 SurfaceCompression::Converted, // ASTC_2D_5X5_SRGB 568 SurfaceCompression::Converted, // ASTC_2D_5X5_SRGB
513 SurfaceCompression::Converted, // ASTC_2D_10X8 569 SurfaceCompression::Converted, // ASTC_2D_10X8
514 SurfaceCompression::Converted, // ASTC_2D_10X8_SRGB 570 SurfaceCompression::Converted, // ASTC_2D_10X8_SRGB
571 SurfaceCompression::Converted, // ASTC_2D_6X6
572 SurfaceCompression::Converted, // ASTC_2D_6X6_SRGB
573 SurfaceCompression::Converted, // ASTC_2D_10X10
574 SurfaceCompression::Converted, // ASTC_2D_10X10_SRGB
575 SurfaceCompression::Converted, // ASTC_2D_12X12
576 SurfaceCompression::Converted, // ASTC_2D_12X12_SRGB
577 SurfaceCompression::Converted, // ASTC_2D_8X6
578 SurfaceCompression::Converted, // ASTC_2D_8X6_SRGB
579 SurfaceCompression::Converted, // ASTC_2D_6X5
580 SurfaceCompression::Converted, // ASTC_2D_6X5_SRGB
515 SurfaceCompression::None, // Z32F 581 SurfaceCompression::None, // Z32F
516 SurfaceCompression::None, // Z16 582 SurfaceCompression::None, // Z16
517 SurfaceCompression::None, // Z24S8 583 SurfaceCompression::None, // Z24S8
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index ca2da8f97..6a92b22d3 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -62,10 +62,10 @@ public:
62 } 62 }
63 } 63 }
64 64
65 /*** 65 /**
66 * `Guard` guarantees that rendertargets don't unregister themselves if the 66 * Guarantees that rendertargets don't unregister themselves if the
67 * collide. Protection is currently only done on 3D slices. 67 * collide. Protection is currently only done on 3D slices.
68 ***/ 68 */
69 void GuardRenderTargets(bool new_guard) { 69 void GuardRenderTargets(bool new_guard) {
70 guard_render_targets = new_guard; 70 guard_render_targets = new_guard;
71 } 71 }
@@ -287,7 +287,7 @@ protected:
287 const Tegra::Engines::Fermi2D::Config& copy_config) = 0; 287 const Tegra::Engines::Fermi2D::Config& copy_config) = 0;
288 288
289 // Depending on the backend, a buffer copy can be slow as it means deoptimizing the texture 289 // Depending on the backend, a buffer copy can be slow as it means deoptimizing the texture
290 // and reading it from a sepparate buffer. 290 // and reading it from a separate buffer.
291 virtual void BufferCopy(TSurface& src_surface, TSurface& dst_surface) = 0; 291 virtual void BufferCopy(TSurface& src_surface, TSurface& dst_surface) = 0;
292 292
293 void ManageRenderTargetUnregister(TSurface& surface) { 293 void ManageRenderTargetUnregister(TSurface& surface) {
@@ -386,12 +386,13 @@ private:
386 }; 386 };
387 387
388 /** 388 /**
389 * `PickStrategy` takes care of selecting a proper strategy to deal with a texture recycle. 389 * Takes care of selecting a proper strategy to deal with a texture recycle.
390 * @param overlaps, the overlapping surfaces registered in the cache. 390 *
391 * @param params, the paremeters on the new surface. 391 * @param overlaps The overlapping surfaces registered in the cache.
392 * @param gpu_addr, the starting address of the new surface. 392 * @param params The parameters on the new surface.
393 * @param untopological, tells the recycler that the texture has no way to match the overlaps 393 * @param gpu_addr The starting address of the new surface.
394 * due to topological reasons. 394 * @param untopological Indicates to the recycler that the texture has no way
395 * to match the overlaps due to topological reasons.
395 **/ 396 **/
396 RecycleStrategy PickStrategy(std::vector<TSurface>& overlaps, const SurfaceParams& params, 397 RecycleStrategy PickStrategy(std::vector<TSurface>& overlaps, const SurfaceParams& params,
397 const GPUVAddr gpu_addr, const MatchTopologyResult untopological) { 398 const GPUVAddr gpu_addr, const MatchTopologyResult untopological) {
@@ -402,7 +403,7 @@ private:
402 if (params.block_depth > 1 || params.target == SurfaceTarget::Texture3D) { 403 if (params.block_depth > 1 || params.target == SurfaceTarget::Texture3D) {
403 return RecycleStrategy::Flush; 404 return RecycleStrategy::Flush;
404 } 405 }
405 for (auto s : overlaps) { 406 for (const auto& s : overlaps) {
406 const auto& s_params = s->GetSurfaceParams(); 407 const auto& s_params = s->GetSurfaceParams();
407 if (s_params.block_depth > 1 || s_params.target == SurfaceTarget::Texture3D) { 408 if (s_params.block_depth > 1 || s_params.target == SurfaceTarget::Texture3D) {
408 return RecycleStrategy::Flush; 409 return RecycleStrategy::Flush;
@@ -419,16 +420,19 @@ private:
419 } 420 }
420 421
421 /** 422 /**
422 * `RecycleSurface` es a method we use to decide what to do with textures we can't resolve in 423 * Used to decide what to do with textures we can't resolve in the cache It has 2 implemented
423 *the cache It has 2 implemented strategies: Ignore and Flush. Ignore just unregisters all the 424 * strategies: Ignore and Flush.
424 *overlaps and loads the new texture. Flush, flushes all the overlaps into memory and loads the 425 *
425 *new surface from that data. 426 * - Ignore: Just unregisters all the overlaps and loads the new texture.
426 * @param overlaps, the overlapping surfaces registered in the cache. 427 * - Flush: Flushes all the overlaps into memory and loads the new surface from that data.
427 * @param params, the paremeters on the new surface. 428 *
428 * @param gpu_addr, the starting address of the new surface. 429 * @param overlaps The overlapping surfaces registered in the cache.
429 * @param preserve_contents, tells if the new surface should be loaded from meory or left blank 430 * @param params The parameters for the new surface.
430 * @param untopological, tells the recycler that the texture has no way to match the overlaps 431 * @param gpu_addr The starting address of the new surface.
431 * due to topological reasons. 432 * @param preserve_contents Indicates that the new surface should be loaded from memory or left
433 * blank.
434 * @param untopological Indicates to the recycler that the texture has no way to match the
435 * overlaps due to topological reasons.
432 **/ 436 **/
433 std::pair<TSurface, TView> RecycleSurface(std::vector<TSurface>& overlaps, 437 std::pair<TSurface, TView> RecycleSurface(std::vector<TSurface>& overlaps,
434 const SurfaceParams& params, const GPUVAddr gpu_addr, 438 const SurfaceParams& params, const GPUVAddr gpu_addr,
@@ -465,10 +469,12 @@ private:
465 } 469 }
466 470
467 /** 471 /**
468 * `RebuildSurface` this method takes a single surface and recreates into another that 472 * Takes a single surface and recreates into another that may differ in
469 * may differ in format, target or width alingment. 473 * format, target or width alignment.
470 * @param current_surface, the registered surface in the cache which we want to convert. 474 *
471 * @param params, the new surface params which we'll use to recreate the surface. 475 * @param current_surface The registered surface in the cache which we want to convert.
476 * @param params The new surface params which we'll use to recreate the surface.
477 * @param is_render Whether or not the surface is a render target.
472 **/ 478 **/
473 std::pair<TSurface, TView> RebuildSurface(TSurface current_surface, const SurfaceParams& params, 479 std::pair<TSurface, TView> RebuildSurface(TSurface current_surface, const SurfaceParams& params,
474 bool is_render) { 480 bool is_render) {
@@ -502,12 +508,14 @@ private:
502 } 508 }
503 509
504 /** 510 /**
505 * `ManageStructuralMatch` this method takes a single surface and checks with the new surface's 511 * Takes a single surface and checks with the new surface's params if it's an exact
506 * params if it's an exact match, we return the main view of the registered surface. If it's 512 * match, we return the main view of the registered surface. If its formats don't
507 * formats don't match, we rebuild the surface. We call this last method a `Mirage`. If formats 513 * match, we rebuild the surface. We call this last method a `Mirage`. If formats
508 * match but the targets don't, we create an overview View of the registered surface. 514 * match but the targets don't, we create an overview View of the registered surface.
509 * @param current_surface, the registered surface in the cache which we want to convert. 515 *
510 * @param params, the new surface params which we want to check. 516 * @param current_surface The registered surface in the cache which we want to convert.
517 * @param params The new surface params which we want to check.
518 * @param is_render Whether or not the surface is a render target.
511 **/ 519 **/
512 std::pair<TSurface, TView> ManageStructuralMatch(TSurface current_surface, 520 std::pair<TSurface, TView> ManageStructuralMatch(TSurface current_surface,
513 const SurfaceParams& params, bool is_render) { 521 const SurfaceParams& params, bool is_render) {
@@ -529,13 +537,14 @@ private:
529 } 537 }
530 538
531 /** 539 /**
532 * `TryReconstructSurface` unlike `RebuildSurface` where we know the registered surface 540 * Unlike RebuildSurface where we know whether or not registered surfaces match the candidate
533 * matches the candidate in some way, we got no guarantess here. We try to see if the overlaps 541 * in some way, we have no guarantees here. We try to see if the overlaps are sublayers/mipmaps
534 * are sublayers/mipmaps of the new surface, if they all match we end up recreating a surface 542 * of the new surface, if they all match we end up recreating a surface for them,
535 * for them, else we return nothing. 543 * else we return nothing.
536 * @param overlaps, the overlapping surfaces registered in the cache. 544 *
537 * @param params, the paremeters on the new surface. 545 * @param overlaps The overlapping surfaces registered in the cache.
538 * @param gpu_addr, the starting address of the new surface. 546 * @param params The parameters on the new surface.
547 * @param gpu_addr The starting address of the new surface.
539 **/ 548 **/
540 std::optional<std::pair<TSurface, TView>> TryReconstructSurface(std::vector<TSurface>& overlaps, 549 std::optional<std::pair<TSurface, TView>> TryReconstructSurface(std::vector<TSurface>& overlaps,
541 const SurfaceParams& params, 550 const SurfaceParams& params,
@@ -575,7 +584,7 @@ private:
575 } else if (Settings::values.use_accurate_gpu_emulation && passed_tests != overlaps.size()) { 584 } else if (Settings::values.use_accurate_gpu_emulation && passed_tests != overlaps.size()) {
576 return {}; 585 return {};
577 } 586 }
578 for (auto surface : overlaps) { 587 for (const auto& surface : overlaps) {
579 Unregister(surface); 588 Unregister(surface);
580 } 589 }
581 new_surface->MarkAsModified(modified, Tick()); 590 new_surface->MarkAsModified(modified, Tick());
@@ -584,19 +593,27 @@ private:
584 } 593 }
585 594
586 /** 595 /**
587 * `GetSurface` gets the starting address and parameters of a candidate surface and tries 596 * Gets the starting address and parameters of a candidate surface and tries
588 * to find a matching surface within the cache. This is done in 3 big steps. The first is to 597 * to find a matching surface within the cache. This is done in 3 big steps:
589 * check the 1st Level Cache in order to find an exact match, if we fail, we move to step 2. 598 *
590 * Step 2 is checking if there are any overlaps at all, if none, we just load the texture from 599 * 1. Check the 1st Level Cache in order to find an exact match, if we fail, we move to step 2.
591 * memory else we move to step 3. Step 3 consists on figuring the relationship between the 600 *
592 * candidate texture and the overlaps. We divide the scenarios depending if there's 1 or many 601 * 2. Check if there are any overlaps at all, if there are none, we just load the texture from
593 * overlaps. If there's many, we just try to reconstruct a new surface out of them based on the 602 * memory else we move to step 3.
594 * candidate's parameters, if we fail, we recycle. When there's only 1 overlap then we have to 603 *
595 * check if the candidate is a view (layer/mipmap) of the overlap or if the registered surface 604 * 3. Consists of figuring out the relationship between the candidate texture and the
596 * is a mipmap/layer of the candidate. In this last case we reconstruct a new surface. 605 * overlaps. We divide the scenarios depending if there's 1 or many overlaps. If
597 * @param gpu_addr, the starting address of the candidate surface. 606 * there's many, we just try to reconstruct a new surface out of them based on the
598 * @param params, the paremeters on the candidate surface. 607 * candidate's parameters, if we fail, we recycle. When there's only 1 overlap then we
599 * @param preserve_contents, tells if the new surface should be loaded from meory or left blank. 608 * have to check if the candidate is a view (layer/mipmap) of the overlap or if the
609 * registered surface is a mipmap/layer of the candidate. In this last case we reconstruct
610 * a new surface.
611 *
612 * @param gpu_addr The starting address of the candidate surface.
613 * @param params The parameters on the candidate surface.
614 * @param preserve_contents Indicates that the new surface should be loaded from memory or
615 * left blank.
616 * @param is_render Whether or not the surface is a render target.
600 **/ 617 **/
601 std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const SurfaceParams& params, 618 std::pair<TSurface, TView> GetSurface(const GPUVAddr gpu_addr, const SurfaceParams& params,
602 bool preserve_contents, bool is_render) { 619 bool preserve_contents, bool is_render) {
@@ -651,7 +668,7 @@ private:
651 // Step 3 668 // Step 3
652 // Now we need to figure the relationship between the texture and its overlaps 669 // Now we need to figure the relationship between the texture and its overlaps
653 // we do a topological test to ensure we can find some relationship. If it fails 670 // we do a topological test to ensure we can find some relationship. If it fails
654 // inmediatly recycle the texture 671 // immediately recycle the texture
655 for (const auto& surface : overlaps) { 672 for (const auto& surface : overlaps) {
656 const auto topological_result = surface->MatchesTopology(params); 673 const auto topological_result = surface->MatchesTopology(params);
657 if (topological_result != MatchTopologyResult::FullMatch) { 674 if (topological_result != MatchTopologyResult::FullMatch) {
@@ -720,12 +737,13 @@ private:
720 } 737 }
721 738
722 /** 739 /**
723 * `DeduceSurface` gets the starting address and parameters of a candidate surface and tries 740 * Gets the starting address and parameters of a candidate surface and tries to find a
724 * to find a matching surface within the cache that's similar to it. If there are many textures 741 * matching surface within the cache that's similar to it. If there are many textures
725 * or the texture found if entirely incompatible, it will fail. If no texture is found, the 742 * or the texture found if entirely incompatible, it will fail. If no texture is found, the
726 * blit will be unsuccessful. 743 * blit will be unsuccessful.
727 * @param gpu_addr, the starting address of the candidate surface. 744 *
728 * @param params, the paremeters on the candidate surface. 745 * @param gpu_addr The starting address of the candidate surface.
746 * @param params The parameters on the candidate surface.
729 **/ 747 **/
730 Deduction DeduceSurface(const GPUVAddr gpu_addr, const SurfaceParams& params) { 748 Deduction DeduceSurface(const GPUVAddr gpu_addr, const SurfaceParams& params) {
731 const auto host_ptr{system.GPU().MemoryManager().GetPointer(gpu_addr)}; 749 const auto host_ptr{system.GPU().MemoryManager().GetPointer(gpu_addr)};
@@ -777,11 +795,14 @@ private:
777 } 795 }
778 796
779 /** 797 /**
780 * `DeduceBestBlit` gets the a source and destination starting address and parameters, 798 * Gets the a source and destination starting address and parameters,
781 * and tries to deduce if they are supposed to be depth textures. If so, their 799 * and tries to deduce if they are supposed to be depth textures. If so, their
782 * parameters are modified and fixed into so. 800 * parameters are modified and fixed into so.
783 * @param gpu_addr, the starting address of the candidate surface. 801 *
784 * @param params, the parameters on the candidate surface. 802 * @param src_params The parameters of the candidate surface.
803 * @param dst_params The parameters of the destination surface.
804 * @param src_gpu_addr The starting address of the candidate surface.
805 * @param dst_gpu_addr The starting address of the destination surface.
785 **/ 806 **/
786 void DeduceBestBlit(SurfaceParams& src_params, SurfaceParams& dst_params, 807 void DeduceBestBlit(SurfaceParams& src_params, SurfaceParams& dst_params,
787 const GPUVAddr src_gpu_addr, const GPUVAddr dst_gpu_addr) { 808 const GPUVAddr src_gpu_addr, const GPUVAddr dst_gpu_addr) {