summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_renderer.h2
-rw-r--r--src/core/CMakeLists.txt12
-rw-r--r--src/core/core.cpp2
-rw-r--r--src/core/gdbstub/gdbstub.cpp9
-rw-r--r--src/core/gdbstub/gdbstub.h7
-rw-r--r--src/core/hle/service/am/am.cpp42
-rw-r--r--src/core/hle/service/am/am.h3
-rw-r--r--src/core/hle/service/caps/caps.cpp158
-rw-r--r--src/core/hle/service/caps/caps.h71
-rw-r--r--src/core/hle/service/caps/caps_a.cpp78
-rw-r--r--src/core/hle/service/caps/caps_a.h21
-rw-r--r--src/core/hle/service/caps/caps_c.cpp75
-rw-r--r--src/core/hle/service/caps/caps_c.h21
-rw-r--r--src/core/hle/service/caps/caps_sc.cpp40
-rw-r--r--src/core/hle/service/caps/caps_sc.h21
-rw-r--r--src/core/hle/service/caps/caps_ss.cpp26
-rw-r--r--src/core/hle/service/caps/caps_ss.h21
-rw-r--r--src/core/hle/service/caps/caps_su.cpp22
-rw-r--r--src/core/hle/service/caps/caps_su.h21
-rw-r--r--src/core/hle/service/caps/caps_u.cpp76
-rw-r--r--src/core/hle/service/caps/caps_u.h24
-rw-r--r--src/core/hle/service/hid/hid.cpp9
-rw-r--r--src/core/hle/service/hid/hid.h1
-rw-r--r--src/core/hle/service/time/interface.cpp2
-rw-r--r--src/core/hle/service/time/time.cpp29
-rw-r--r--src/core/hle/service/time/time.h1
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/engines/const_buffer_engine_interface.h14
-rw-r--r--src/video_core/engines/shader_bytecode.h20
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp87
-rw-r--r--src/video_core/renderer_vulkan/maxwell_to_vk.cpp20
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp31
-rw-r--r--src/video_core/renderer_vulkan/wrapper.cpp750
-rw-r--r--src/video_core/renderer_vulkan/wrapper.h987
-rw-r--r--src/video_core/shader/decode/arithmetic_integer.cpp15
-rw-r--r--src/video_core/shader/decode/conversion.cpp15
-rw-r--r--src/video_core/shader/decode/memory.cpp60
-rw-r--r--src/video_core/shader/decode/xmad.cpp9
-rw-r--r--src/video_core/shader/node.h16
-rw-r--r--src/video_core/shader/node_helper.cpp14
-rw-r--r--src/video_core/shader/shader_ir.cpp85
-rw-r--r--src/video_core/shader/shader_ir.h8
-rw-r--r--src/yuzu/main.cpp15
44 files changed, 2673 insertions, 276 deletions
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index be1b019f1..c0fae669e 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -189,7 +189,7 @@ struct UpdateDataHeader {
189 UpdateDataHeader() {} 189 UpdateDataHeader() {}
190 190
191 explicit UpdateDataHeader(const AudioRendererParameter& config) { 191 explicit UpdateDataHeader(const AudioRendererParameter& config) {
192 revision = Common::MakeMagic('R', 'E', 'V', '4'); // 5.1.0 Revision 192 revision = Common::MakeMagic('R', 'E', 'V', '8'); // 9.2.0 Revision
193 behavior_size = 0xb0; 193 behavior_size = 0xb0;
194 memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10; 194 memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10;
195 voices_size = config.voice_count * 0x10; 195 voices_size = config.voice_count * 0x10;
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 29a267957..66497a386 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -285,6 +285,18 @@ add_library(core STATIC
285 hle/service/btm/btm.h 285 hle/service/btm/btm.h
286 hle/service/caps/caps.cpp 286 hle/service/caps/caps.cpp
287 hle/service/caps/caps.h 287 hle/service/caps/caps.h
288 hle/service/caps/caps_a.cpp
289 hle/service/caps/caps_a.h
290 hle/service/caps/caps_c.cpp
291 hle/service/caps/caps_c.h
292 hle/service/caps/caps_u.cpp
293 hle/service/caps/caps_u.h
294 hle/service/caps/caps_sc.cpp
295 hle/service/caps/caps_sc.h
296 hle/service/caps/caps_ss.cpp
297 hle/service/caps/caps_ss.h
298 hle/service/caps/caps_su.cpp
299 hle/service/caps/caps_su.h
288 hle/service/erpt/erpt.cpp 300 hle/service/erpt/erpt.cpp
289 hle/service/erpt/erpt.h 301 hle/service/erpt/erpt.h
290 hle/service/es/es.cpp 302 hle/service/es/es.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 26a580cb7..3bd90d79f 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -165,7 +165,7 @@ struct System::Impl {
165 service_manager = std::make_shared<Service::SM::ServiceManager>(); 165 service_manager = std::make_shared<Service::SM::ServiceManager>();
166 166
167 Service::Init(service_manager, system); 167 Service::Init(service_manager, system);
168 GDBStub::Init(); 168 GDBStub::DeferStart();
169 169
170 interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system); 170 interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system);
171 gpu_core = VideoCore::CreateGPU(emu_window, system); 171 gpu_core = VideoCore::CreateGPU(emu_window, system);
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index e8d8871a7..6d15aeed9 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -141,6 +141,7 @@ constexpr char target_xml[] =
141)"; 141)";
142 142
143int gdbserver_socket = -1; 143int gdbserver_socket = -1;
144bool defer_start = false;
144 145
145u8 command_buffer[GDB_BUFFER_SIZE]; 146u8 command_buffer[GDB_BUFFER_SIZE];
146u32 command_length; 147u32 command_length;
@@ -1166,6 +1167,9 @@ static void RemoveBreakpoint() {
1166 1167
1167void HandlePacket() { 1168void HandlePacket() {
1168 if (!IsConnected()) { 1169 if (!IsConnected()) {
1170 if (defer_start) {
1171 ToggleServer(true);
1172 }
1169 return; 1173 return;
1170 } 1174 }
1171 1175
@@ -1256,6 +1260,10 @@ void ToggleServer(bool status) {
1256 } 1260 }
1257} 1261}
1258 1262
1263void DeferStart() {
1264 defer_start = true;
1265}
1266
1259static void Init(u16 port) { 1267static void Init(u16 port) {
1260 if (!server_enabled) { 1268 if (!server_enabled) {
1261 // Set the halt loop to false in case the user enabled the gdbstub mid-execution. 1269 // Set the halt loop to false in case the user enabled the gdbstub mid-execution.
@@ -1341,6 +1349,7 @@ void Shutdown() {
1341 if (!server_enabled) { 1349 if (!server_enabled) {
1342 return; 1350 return;
1343 } 1351 }
1352 defer_start = false;
1344 1353
1345 LOG_INFO(Debug_GDBStub, "Stopping GDB ..."); 1354 LOG_INFO(Debug_GDBStub, "Stopping GDB ...");
1346 if (gdbserver_socket != -1) { 1355 if (gdbserver_socket != -1) {
diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h
index 5a36524b2..8fe3c320b 100644
--- a/src/core/gdbstub/gdbstub.h
+++ b/src/core/gdbstub/gdbstub.h
@@ -43,6 +43,13 @@ void ToggleServer(bool status);
43/// Start the gdbstub server. 43/// Start the gdbstub server.
44void Init(); 44void Init();
45 45
46/**
47 * Defer initialization of the gdbstub to the first packet processing functions.
48 * This avoids a case where the gdbstub thread is frozen after initialization
49 * and fails to respond in time to packets.
50 */
51void DeferStart();
52
46/// Stop gdbstub server. 53/// Stop gdbstub server.
47void Shutdown(); 54void Shutdown();
48 55
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index d1bf13c89..557608e76 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -52,6 +52,11 @@ enum class LaunchParameterKind : u32 {
52 AccountPreselectedUser = 2, 52 AccountPreselectedUser = 2,
53}; 53};
54 54
55enum class VrMode : u8 {
56 Disabled = 0,
57 Enabled = 1,
58};
59
55constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; 60constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA;
56 61
57struct LaunchParameterAccountPreselectedUser { 62struct LaunchParameterAccountPreselectedUser {
@@ -605,11 +610,11 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system,
605 {30, nullptr, "GetHomeButtonReaderLockAccessor"}, 610 {30, nullptr, "GetHomeButtonReaderLockAccessor"},
606 {31, nullptr, "GetReaderLockAccessorEx"}, 611 {31, nullptr, "GetReaderLockAccessorEx"},
607 {40, nullptr, "GetCradleFwVersion"}, 612 {40, nullptr, "GetCradleFwVersion"},
608 {50, nullptr, "IsVrModeEnabled"}, 613 {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
609 {51, nullptr, "SetVrModeEnabled"}, 614 {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"},
610 {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"}, 615 {52, &ICommonStateGetter::SetLcdBacklighOffEnabled, "SetLcdBacklighOffEnabled"},
611 {53, nullptr, "BeginVrModeEx"}, 616 {53, nullptr, "BeginVrModeEx"},
612 {54, nullptr, "EndVrModeEx"}, 617 {54, &ICommonStateGetter::EndVrModeEx, "EndVrModeEx"},
613 {55, nullptr, "IsInControllerFirmwareUpdateSection"}, 618 {55, nullptr, "IsInControllerFirmwareUpdateSection"},
614 {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, 619 {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
615 {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"}, 620 {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
@@ -672,6 +677,30 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
672 rb.Push(static_cast<u8>(FocusState::InFocus)); 677 rb.Push(static_cast<u8>(FocusState::InFocus));
673} 678}
674 679
680void ICommonStateGetter::IsVrModeEnabled(Kernel::HLERequestContext& ctx) {
681 LOG_WARNING(Service_AM, "(STUBBED) called");
682
683 IPC::ResponseBuilder rb{ctx, 3};
684 rb.Push(RESULT_SUCCESS);
685 rb.PushEnum(VrMode::Disabled);
686}
687
688void ICommonStateGetter::SetVrModeEnabled(Kernel::HLERequestContext& ctx) {
689 IPC::RequestParser rp{ctx};
690 const auto is_vr_mode_enabled = rp.Pop<bool>();
691
692 LOG_WARNING(Service_AM, "(STUBBED) called. is_vr_mode_enabled={}", is_vr_mode_enabled);
693
694 IPC::ResponseBuilder rb{ctx, 2};
695 if (!is_vr_mode_enabled) {
696 rb.Push(RESULT_SUCCESS);
697 } else {
698 // TODO: Find better error code for this
699 UNIMPLEMENTED_MSG("is_vr_mode_enabled={}", is_vr_mode_enabled);
700 rb.Push(RESULT_UNKNOWN);
701 }
702}
703
675void ICommonStateGetter::SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx) { 704void ICommonStateGetter::SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx) {
676 IPC::RequestParser rp{ctx}; 705 IPC::RequestParser rp{ctx};
677 const auto is_lcd_backlight_off_enabled = rp.Pop<bool>(); 706 const auto is_lcd_backlight_off_enabled = rp.Pop<bool>();
@@ -683,6 +712,13 @@ void ICommonStateGetter::SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx
683 rb.Push(RESULT_SUCCESS); 712 rb.Push(RESULT_SUCCESS);
684} 713}
685 714
715void ICommonStateGetter::EndVrModeEx(Kernel::HLERequestContext& ctx) {
716 LOG_WARNING(Service_AM, "(STUBBED) called");
717
718 IPC::ResponseBuilder rb{ctx, 2};
719 rb.Push(RESULT_SUCCESS);
720}
721
686void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) { 722void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) {
687 LOG_DEBUG(Service_AM, "called"); 723 LOG_DEBUG(Service_AM, "called");
688 724
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 0843de781..53cfce10f 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -182,7 +182,10 @@ private:
182 void GetOperationMode(Kernel::HLERequestContext& ctx); 182 void GetOperationMode(Kernel::HLERequestContext& ctx);
183 void GetPerformanceMode(Kernel::HLERequestContext& ctx); 183 void GetPerformanceMode(Kernel::HLERequestContext& ctx);
184 void GetBootMode(Kernel::HLERequestContext& ctx); 184 void GetBootMode(Kernel::HLERequestContext& ctx);
185 void IsVrModeEnabled(Kernel::HLERequestContext& ctx);
186 void SetVrModeEnabled(Kernel::HLERequestContext& ctx);
185 void SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx); 187 void SetLcdBacklighOffEnabled(Kernel::HLERequestContext& ctx);
188 void EndVrModeEx(Kernel::HLERequestContext& ctx);
186 void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); 189 void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
187 void SetCpuBoostMode(Kernel::HLERequestContext& ctx); 190 void SetCpuBoostMode(Kernel::HLERequestContext& ctx);
188 191
diff --git a/src/core/hle/service/caps/caps.cpp b/src/core/hle/service/caps/caps.cpp
index 907f464ab..26c8a7081 100644
--- a/src/core/hle/service/caps/caps.cpp
+++ b/src/core/hle/service/caps/caps.cpp
@@ -2,168 +2,24 @@
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 <memory>
6
7#include "core/hle/service/caps/caps.h" 5#include "core/hle/service/caps/caps.h"
6#include "core/hle/service/caps/caps_a.h"
7#include "core/hle/service/caps/caps_c.h"
8#include "core/hle/service/caps/caps_sc.h"
9#include "core/hle/service/caps/caps_ss.h"
10#include "core/hle/service/caps/caps_su.h"
11#include "core/hle/service/caps/caps_u.h"
8#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
9#include "core/hle/service/sm/sm.h"
10 13
11namespace Service::Capture { 14namespace Service::Capture {
12 15
13class CAPS_A final : public ServiceFramework<CAPS_A> {
14public:
15 explicit CAPS_A() : ServiceFramework{"caps:a"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {0, nullptr, "GetAlbumFileCount"},
19 {1, nullptr, "GetAlbumFileList"},
20 {2, nullptr, "LoadAlbumFile"},
21 {3, nullptr, "DeleteAlbumFile"},
22 {4, nullptr, "StorageCopyAlbumFile"},
23 {5, nullptr, "IsAlbumMounted"},
24 {6, nullptr, "GetAlbumUsage"},
25 {7, nullptr, "GetAlbumFileSize"},
26 {8, nullptr, "LoadAlbumFileThumbnail"},
27 {9, nullptr, "LoadAlbumScreenShotImage"},
28 {10, nullptr, "LoadAlbumScreenShotThumbnailImage"},
29 {11, nullptr, "GetAlbumEntryFromApplicationAlbumEntry"},
30 {12, nullptr, "Unknown12"},
31 {13, nullptr, "Unknown13"},
32 {14, nullptr, "Unknown14"},
33 {15, nullptr, "Unknown15"},
34 {16, nullptr, "Unknown16"},
35 {17, nullptr, "Unknown17"},
36 {18, nullptr, "Unknown18"},
37 {202, nullptr, "SaveEditedScreenShot"},
38 {301, nullptr, "GetLastThumbnail"},
39 {401, nullptr, "GetAutoSavingStorage"},
40 {501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"},
41 {1001, nullptr, "Unknown1001"},
42 {1002, nullptr, "Unknown1002"},
43 {1003, nullptr, "Unknown1003"},
44 {8001, nullptr, "ForceAlbumUnmounted"},
45 {8002, nullptr, "ResetAlbumMountStatus"},
46 {8011, nullptr, "RefreshAlbumCache"},
47 {8012, nullptr, "GetAlbumCache"},
48 {8013, nullptr, "Unknown8013"},
49 {8021, nullptr, "GetAlbumEntryFromApplicationAlbumEntryAruid"},
50 {10011, nullptr, "SetInternalErrorConversionEnabled"},
51 {50000, nullptr, "Unknown50000"},
52 {60002, nullptr, "Unknown60002"},
53 };
54 // clang-format on
55
56 RegisterHandlers(functions);
57 }
58};
59
60class CAPS_C final : public ServiceFramework<CAPS_C> {
61public:
62 explicit CAPS_C() : ServiceFramework{"caps:c"} {
63 // clang-format off
64 static const FunctionInfo functions[] = {
65 {33, nullptr, "Unknown33"},
66 {2001, nullptr, "Unknown2001"},
67 {2002, nullptr, "Unknown2002"},
68 {2011, nullptr, "Unknown2011"},
69 {2012, nullptr, "Unknown2012"},
70 {2013, nullptr, "Unknown2013"},
71 {2014, nullptr, "Unknown2014"},
72 {2101, nullptr, "Unknown2101"},
73 {2102, nullptr, "Unknown2102"},
74 {2201, nullptr, "Unknown2201"},
75 {2301, nullptr, "Unknown2301"},
76 };
77 // clang-format on
78
79 RegisterHandlers(functions);
80 }
81};
82
83class CAPS_SC final : public ServiceFramework<CAPS_SC> {
84public:
85 explicit CAPS_SC() : ServiceFramework{"caps:sc"} {
86 // clang-format off
87 static const FunctionInfo functions[] = {
88 {1, nullptr, "Unknown1"},
89 {2, nullptr, "Unknown2"},
90 {1001, nullptr, "Unknown3"},
91 {1002, nullptr, "Unknown4"},
92 {1003, nullptr, "Unknown5"},
93 {1011, nullptr, "Unknown6"},
94 {1012, nullptr, "Unknown7"},
95 {1201, nullptr, "Unknown8"},
96 {1202, nullptr, "Unknown9"},
97 {1203, nullptr, "Unknown10"},
98 };
99 // clang-format on
100
101 RegisterHandlers(functions);
102 }
103};
104
105class CAPS_SS final : public ServiceFramework<CAPS_SS> {
106public:
107 explicit CAPS_SS() : ServiceFramework{"caps:ss"} {
108 // clang-format off
109 static const FunctionInfo functions[] = {
110 {201, nullptr, "Unknown1"},
111 {202, nullptr, "Unknown2"},
112 {203, nullptr, "Unknown3"},
113 {204, nullptr, "Unknown4"},
114 };
115 // clang-format on
116
117 RegisterHandlers(functions);
118 }
119};
120
121class CAPS_SU final : public ServiceFramework<CAPS_SU> {
122public:
123 explicit CAPS_SU() : ServiceFramework{"caps:su"} {
124 // clang-format off
125 static const FunctionInfo functions[] = {
126 {201, nullptr, "SaveScreenShot"},
127 {203, nullptr, "SaveScreenShotEx0"},
128 };
129 // clang-format on
130
131 RegisterHandlers(functions);
132 }
133};
134
135class CAPS_U final : public ServiceFramework<CAPS_U> {
136public:
137 explicit CAPS_U() : ServiceFramework{"caps:u"} {
138 // clang-format off
139 static const FunctionInfo functions[] = {
140 {32, nullptr, "SetShimLibraryVersion"},
141 {102, nullptr, "GetAlbumFileListByAruid"},
142 {103, nullptr, "DeleteAlbumFileByAruid"},
143 {104, nullptr, "GetAlbumFileSizeByAruid"},
144 {105, nullptr, "DeleteAlbumFileByAruidForDebug"},
145 {110, nullptr, "LoadAlbumScreenShotImageByAruid"},
146 {120, nullptr, "LoadAlbumScreenShotThumbnailImageByAruid"},
147 {130, nullptr, "PrecheckToCreateContentsByAruid"},
148 {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"},
149 {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"},
150 {142, nullptr, "GetAlbumFileList3AaeAruid"},
151 {143, nullptr, "GetAlbumFileList4AaeUidAruid"},
152 {60002, nullptr, "OpenAccessorSessionForApplication"},
153 };
154 // clang-format on
155
156 RegisterHandlers(functions);
157 }
158};
159
160void InstallInterfaces(SM::ServiceManager& sm) { 16void InstallInterfaces(SM::ServiceManager& sm) {
161 std::make_shared<CAPS_A>()->InstallAsService(sm); 17 std::make_shared<CAPS_A>()->InstallAsService(sm);
162 std::make_shared<CAPS_C>()->InstallAsService(sm); 18 std::make_shared<CAPS_C>()->InstallAsService(sm);
19 std::make_shared<CAPS_U>()->InstallAsService(sm);
163 std::make_shared<CAPS_SC>()->InstallAsService(sm); 20 std::make_shared<CAPS_SC>()->InstallAsService(sm);
164 std::make_shared<CAPS_SS>()->InstallAsService(sm); 21 std::make_shared<CAPS_SS>()->InstallAsService(sm);
165 std::make_shared<CAPS_SU>()->InstallAsService(sm); 22 std::make_shared<CAPS_SU>()->InstallAsService(sm);
166 std::make_shared<CAPS_U>()->InstallAsService(sm);
167} 23}
168 24
169} // namespace Service::Capture 25} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps.h b/src/core/hle/service/caps/caps.h
index 471185dfa..fc70a4c27 100644
--- a/src/core/hle/service/caps/caps.h
+++ b/src/core/hle/service/caps/caps.h
@@ -4,12 +4,83 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/service/service.h"
8
7namespace Service::SM { 9namespace Service::SM {
8class ServiceManager; 10class ServiceManager;
9} 11}
10 12
11namespace Service::Capture { 13namespace Service::Capture {
12 14
15enum AlbumImageOrientation {
16 Orientation0 = 0,
17 Orientation1 = 1,
18 Orientation2 = 2,
19 Orientation3 = 3,
20};
21
22enum AlbumReportOption {
23 Disable = 0,
24 Enable = 1,
25};
26
27enum ContentType : u8 {
28 Screenshot = 0,
29 Movie = 1,
30 ExtraMovie = 3,
31};
32
33enum AlbumStorage : u8 {
34 NAND = 0,
35 SD = 1,
36};
37
38struct AlbumFileDateTime {
39 u16 year;
40 u8 month;
41 u8 day;
42 u8 hour;
43 u8 minute;
44 u8 second;
45 u8 uid;
46};
47
48struct AlbumEntry {
49 u64 size;
50 u64 application_id;
51 AlbumFileDateTime datetime;
52 AlbumStorage storage;
53 ContentType content;
54 u8 padding[6];
55};
56
57struct AlbumFileEntry {
58 u64 size;
59 u64 hash;
60 AlbumFileDateTime datetime;
61 AlbumStorage storage;
62 ContentType content;
63 u8 padding[5];
64 u8 unknown;
65};
66
67struct ApplicationAlbumEntry {
68 u64 size;
69 u64 hash;
70 AlbumFileDateTime datetime;
71 AlbumStorage storage;
72 ContentType content;
73 u8 padding[5];
74 u8 unknown;
75};
76
77struct ApplicationAlbumFileEntry {
78 ApplicationAlbumEntry entry;
79 AlbumFileDateTime datetime;
80 u64 unknown;
81};
82
83/// Registers all Capture services with the specified service manager.
13void InstallInterfaces(SM::ServiceManager& sm); 84void InstallInterfaces(SM::ServiceManager& sm);
14 85
15} // namespace Service::Capture 86} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_a.cpp b/src/core/hle/service/caps/caps_a.cpp
new file mode 100644
index 000000000..88a3fdc05
--- /dev/null
+++ b/src/core/hle/service/caps/caps_a.cpp
@@ -0,0 +1,78 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/service/caps/caps_a.h"
6
7namespace Service::Capture {
8
9class IAlbumAccessorSession final : public ServiceFramework<IAlbumAccessorSession> {
10public:
11 explicit IAlbumAccessorSession() : ServiceFramework{"IAlbumAccessorSession"} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {2001, nullptr, "OpenAlbumMovieReadStream"},
15 {2002, nullptr, "CloseAlbumMovieReadStream"},
16 {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
17 {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
18 {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
19 {2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"},
20 {2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"},
21 {2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"},
22 };
23 // clang-format on
24
25 RegisterHandlers(functions);
26 }
27};
28
29CAPS_A::CAPS_A() : ServiceFramework("caps:a") {
30 // clang-format off
31 static const FunctionInfo functions[] = {
32 {0, nullptr, "GetAlbumFileCount"},
33 {1, nullptr, "GetAlbumFileList"},
34 {2, nullptr, "LoadAlbumFile"},
35 {3, nullptr, "DeleteAlbumFile"},
36 {4, nullptr, "StorageCopyAlbumFile"},
37 {5, nullptr, "IsAlbumMounted"},
38 {6, nullptr, "GetAlbumUsage"},
39 {7, nullptr, "GetAlbumFileSize"},
40 {8, nullptr, "LoadAlbumFileThumbnail"},
41 {9, nullptr, "LoadAlbumScreenShotImage"},
42 {10, nullptr, "LoadAlbumScreenShotThumbnailImage"},
43 {11, nullptr, "GetAlbumEntryFromApplicationAlbumEntry"},
44 {12, nullptr, "LoadAlbumScreenShotImageEx"},
45 {13, nullptr, "LoadAlbumScreenShotThumbnailImageEx"},
46 {14, nullptr, "LoadAlbumScreenShotImageEx0"},
47 {15, nullptr, "GetAlbumUsage3"},
48 {16, nullptr, "GetAlbumMountResult"},
49 {17, nullptr, "GetAlbumUsage16"},
50 {18, nullptr, "Unknown18"},
51 {100, nullptr, "GetAlbumFileCountEx0"},
52 {101, nullptr, "GetAlbumFileListEx0"},
53 {202, nullptr, "SaveEditedScreenShot"},
54 {301, nullptr, "GetLastThumbnail"},
55 {302, nullptr, "GetLastOverlayMovieThumbnail"},
56 {401, nullptr, "GetAutoSavingStorage"},
57 {501, nullptr, "GetRequiredStorageSpaceSizeToCopyAll"},
58 {1001, nullptr, "LoadAlbumScreenShotThumbnailImageEx0"},
59 {1002, nullptr, "LoadAlbumScreenShotImageEx1"},
60 {1003, nullptr, "LoadAlbumScreenShotThumbnailImageEx1"},
61 {8001, nullptr, "ForceAlbumUnmounted"},
62 {8002, nullptr, "ResetAlbumMountStatus"},
63 {8011, nullptr, "RefreshAlbumCache"},
64 {8012, nullptr, "GetAlbumCache"},
65 {8013, nullptr, "GetAlbumCacheEx"},
66 {8021, nullptr, "GetAlbumEntryFromApplicationAlbumEntryAruid"},
67 {10011, nullptr, "SetInternalErrorConversionEnabled"},
68 {50000, nullptr, "LoadMakerNoteInfoForDebug"},
69 {60002, nullptr, "OpenAccessorSession"},
70 };
71 // clang-format on
72
73 RegisterHandlers(functions);
74}
75
76CAPS_A::~CAPS_A() = default;
77
78} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_a.h b/src/core/hle/service/caps/caps_a.h
new file mode 100644
index 000000000..8de832491
--- /dev/null
+++ b/src/core/hle/service/caps/caps_a.h
@@ -0,0 +1,21 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9namespace Kernel {
10class HLERequestContext;
11}
12
13namespace Service::Capture {
14
15class CAPS_A final : public ServiceFramework<CAPS_A> {
16public:
17 explicit CAPS_A();
18 ~CAPS_A() override;
19};
20
21} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_c.cpp b/src/core/hle/service/caps/caps_c.cpp
new file mode 100644
index 000000000..ea6452ffa
--- /dev/null
+++ b/src/core/hle/service/caps/caps_c.cpp
@@ -0,0 +1,75 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/service/caps/caps_c.h"
6
7namespace Service::Capture {
8
9class IAlbumControlSession final : public ServiceFramework<IAlbumControlSession> {
10public:
11 explicit IAlbumControlSession() : ServiceFramework{"IAlbumControlSession"} {
12 // clang-format off
13 static const FunctionInfo functions[] = {
14 {2001, nullptr, "OpenAlbumMovieReadStream"},
15 {2002, nullptr, "CloseAlbumMovieReadStream"},
16 {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
17 {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
18 {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
19 {2006, nullptr, "GetAlbumMovieReadStreamImageDataSize"},
20 {2007, nullptr, "ReadImageDataFromAlbumMovieReadStream"},
21 {2008, nullptr, "ReadFileAttributeFromAlbumMovieReadStream"},
22 {2401, nullptr, "OpenAlbumMovieWriteStream"},
23 {2402, nullptr, "FinishAlbumMovieWriteStream"},
24 {2403, nullptr, "CommitAlbumMovieWriteStream"},
25 {2404, nullptr, "DiscardAlbumMovieWriteStream"},
26 {2405, nullptr, "DiscardAlbumMovieWriteStreamNoDelete"},
27 {2406, nullptr, "CommitAlbumMovieWriteStreamEx"},
28 {2411, nullptr, "StartAlbumMovieWriteStreamDataSection"},
29 {2412, nullptr, "EndAlbumMovieWriteStreamDataSection"},
30 {2413, nullptr, "StartAlbumMovieWriteStreamMetaSection"},
31 {2414, nullptr, "EndAlbumMovieWriteStreamMetaSection"},
32 {2421, nullptr, "ReadDataFromAlbumMovieWriteStream"},
33 {2422, nullptr, "WriteDataToAlbumMovieWriteStream"},
34 {2424, nullptr, "WriteMetaToAlbumMovieWriteStream"},
35 {2431, nullptr, "GetAlbumMovieWriteStreamBrokenReason"},
36 {2433, nullptr, "GetAlbumMovieWriteStreamDataSize"},
37 {2434, nullptr, "SetAlbumMovieWriteStreamDataSize"},
38 };
39 // clang-format on
40
41 RegisterHandlers(functions);
42 }
43};
44
45CAPS_C::CAPS_C() : ServiceFramework("caps:c") {
46 // clang-format off
47 static const FunctionInfo functions[] = {
48 {1, nullptr, "CaptureRawImage"},
49 {2, nullptr, "CaptureRawImageWithTimeout"},
50 {33, nullptr, "Unknown33"},
51 {1001, nullptr, "RequestTakingScreenShot"},
52 {1002, nullptr, "RequestTakingScreenShotWithTimeout"},
53 {1011, nullptr, "NotifyTakingScreenShotRefused"},
54 {2001, nullptr, "NotifyAlbumStorageIsAvailable"},
55 {2002, nullptr, "NotifyAlbumStorageIsUnavailable"},
56 {2011, nullptr, "RegisterAppletResourceUserId"},
57 {2012, nullptr, "UnregisterAppletResourceUserId"},
58 {2013, nullptr, "GetApplicationIdFromAruid"},
59 {2014, nullptr, "CheckApplicationIdRegistered"},
60 {2101, nullptr, "GenerateCurrentAlbumFileId"},
61 {2102, nullptr, "GenerateApplicationAlbumEntry"},
62 {2201, nullptr, "SaveAlbumScreenShotFile"},
63 {2202, nullptr, "SaveAlbumScreenShotFileEx"},
64 {2301, nullptr, "SetOverlayScreenShotThumbnailData"},
65 {2302, nullptr, "SetOverlayMovieThumbnailData"},
66 {60001, nullptr, "OpenControlSession"},
67 };
68 // clang-format on
69
70 RegisterHandlers(functions);
71}
72
73CAPS_C::~CAPS_C() = default;
74
75} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_c.h b/src/core/hle/service/caps/caps_c.h
new file mode 100644
index 000000000..d07cdb441
--- /dev/null
+++ b/src/core/hle/service/caps/caps_c.h
@@ -0,0 +1,21 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9namespace Kernel {
10class HLERequestContext;
11}
12
13namespace Service::Capture {
14
15class CAPS_C final : public ServiceFramework<CAPS_C> {
16public:
17 explicit CAPS_C();
18 ~CAPS_C() override;
19};
20
21} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_sc.cpp b/src/core/hle/service/caps/caps_sc.cpp
new file mode 100644
index 000000000..d01a8a58e
--- /dev/null
+++ b/src/core/hle/service/caps/caps_sc.cpp
@@ -0,0 +1,40 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/service/caps/caps_sc.h"
6
7namespace Service::Capture {
8
9CAPS_SC::CAPS_SC() : ServiceFramework("caps:sc") {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {1, nullptr, "CaptureRawImage"},
13 {2, nullptr, "CaptureRawImageWithTimeout"},
14 {3, nullptr, "AttachSharedBuffer"},
15 {5, nullptr, "CaptureRawImageToAttachedSharedBuffer"},
16 {210, nullptr, "Unknown210"},
17 {1001, nullptr, "RequestTakingScreenShot"},
18 {1002, nullptr, "RequestTakingScreenShotWithTimeout"},
19 {1003, nullptr, "RequestTakingScreenShotEx"},
20 {1004, nullptr, "RequestTakingScreenShotEx1"},
21 {1009, nullptr, "CancelTakingScreenShot"},
22 {1010, nullptr, "SetTakingScreenShotCancelState"},
23 {1011, nullptr, "NotifyTakingScreenShotRefused"},
24 {1012, nullptr, "NotifyTakingScreenShotFailed"},
25 {1101, nullptr, "SetupOverlayMovieThumbnail"},
26 {1106, nullptr, "Unknown1106"},
27 {1107, nullptr, "Unknown1107"},
28 {1201, nullptr, "OpenRawScreenShotReadStream"},
29 {1202, nullptr, "CloseRawScreenShotReadStream"},
30 {1203, nullptr, "ReadRawScreenShotReadStream"},
31 {1204, nullptr, "Unknown1204"},
32 };
33 // clang-format on
34
35 RegisterHandlers(functions);
36}
37
38CAPS_SC::~CAPS_SC() = default;
39
40} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_sc.h b/src/core/hle/service/caps/caps_sc.h
new file mode 100644
index 000000000..9ba372f7a
--- /dev/null
+++ b/src/core/hle/service/caps/caps_sc.h
@@ -0,0 +1,21 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9namespace Kernel {
10class HLERequestContext;
11}
12
13namespace Service::Capture {
14
15class CAPS_SC final : public ServiceFramework<CAPS_SC> {
16public:
17 explicit CAPS_SC();
18 ~CAPS_SC() override;
19};
20
21} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_ss.cpp b/src/core/hle/service/caps/caps_ss.cpp
new file mode 100644
index 000000000..eaa3a7494
--- /dev/null
+++ b/src/core/hle/service/caps/caps_ss.cpp
@@ -0,0 +1,26 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/service/caps/caps_ss.h"
6
7namespace Service::Capture {
8
9CAPS_SS::CAPS_SS() : ServiceFramework("caps:ss") {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {201, nullptr, "SaveScreenShot"},
13 {202, nullptr, "SaveEditedScreenShot"},
14 {203, nullptr, "SaveScreenShotEx0"},
15 {204, nullptr, "SaveEditedScreenShotEx0"},
16 {206, nullptr, "Unknown206"},
17 {208, nullptr, "SaveScreenShotOfMovieEx1"},
18 };
19 // clang-format on
20
21 RegisterHandlers(functions);
22}
23
24CAPS_SS::~CAPS_SS() = default;
25
26} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_ss.h b/src/core/hle/service/caps/caps_ss.h
new file mode 100644
index 000000000..e258a6925
--- /dev/null
+++ b/src/core/hle/service/caps/caps_ss.h
@@ -0,0 +1,21 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9namespace Kernel {
10class HLERequestContext;
11}
12
13namespace Service::Capture {
14
15class CAPS_SS final : public ServiceFramework<CAPS_SS> {
16public:
17 explicit CAPS_SS();
18 ~CAPS_SS() override;
19};
20
21} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp
new file mode 100644
index 000000000..2b4c2d808
--- /dev/null
+++ b/src/core/hle/service/caps/caps_su.cpp
@@ -0,0 +1,22 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/service/caps/caps_su.h"
6
7namespace Service::Capture {
8
9CAPS_SU::CAPS_SU() : ServiceFramework("caps:su") {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {201, nullptr, "SaveScreenShot"},
13 {203, nullptr, "SaveScreenShotEx0"},
14 };
15 // clang-format on
16
17 RegisterHandlers(functions);
18}
19
20CAPS_SU::~CAPS_SU() = default;
21
22} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_su.h b/src/core/hle/service/caps/caps_su.h
new file mode 100644
index 000000000..cb11f7c9a
--- /dev/null
+++ b/src/core/hle/service/caps/caps_su.h
@@ -0,0 +1,21 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9namespace Kernel {
10class HLERequestContext;
11}
12
13namespace Service::Capture {
14
15class CAPS_SU final : public ServiceFramework<CAPS_SU> {
16public:
17 explicit CAPS_SU();
18 ~CAPS_SU() override;
19};
20
21} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_u.cpp b/src/core/hle/service/caps/caps_u.cpp
new file mode 100644
index 000000000..78bab6ed8
--- /dev/null
+++ b/src/core/hle/service/caps/caps_u.cpp
@@ -0,0 +1,76 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h"
7#include "core/hle/service/caps/caps.h"
8#include "core/hle/service/caps/caps_u.h"
9
10namespace Service::Capture {
11
12class IAlbumAccessorApplicationSession final
13 : public ServiceFramework<IAlbumAccessorApplicationSession> {
14public:
15 explicit IAlbumAccessorApplicationSession()
16 : ServiceFramework{"IAlbumAccessorApplicationSession"} {
17 // clang-format off
18 static const FunctionInfo functions[] = {
19 {2001, nullptr, "OpenAlbumMovieReadStream"},
20 {2002, nullptr, "CloseAlbumMovieReadStream"},
21 {2003, nullptr, "GetAlbumMovieReadStreamMovieDataSize"},
22 {2004, nullptr, "ReadMovieDataFromAlbumMovieReadStream"},
23 {2005, nullptr, "GetAlbumMovieReadStreamBrokenReason"},
24 };
25 // clang-format on
26
27 RegisterHandlers(functions);
28 }
29};
30
31CAPS_U::CAPS_U() : ServiceFramework("caps:u") {
32 // clang-format off
33 static const FunctionInfo functions[] = {
34 {31, nullptr, "GetShimLibraryVersion"},
35 {32, nullptr, "SetShimLibraryVersion"},
36 {102, &CAPS_U::GetAlbumContentsFileListForApplication, "GetAlbumContentsFileListForApplication"},
37 {103, nullptr, "DeleteAlbumContentsFileForApplication"},
38 {104, nullptr, "GetAlbumContentsFileSizeForApplication"},
39 {105, nullptr, "DeleteAlbumFileByAruidForDebug"},
40 {110, nullptr, "LoadAlbumContentsFileScreenShotImageForApplication"},
41 {120, nullptr, "LoadAlbumContentsFileThumbnailImageForApplication"},
42 {130, nullptr, "PrecheckToCreateContentsForApplication"},
43 {140, nullptr, "GetAlbumFileList1AafeAruidDeprecated"},
44 {141, nullptr, "GetAlbumFileList2AafeUidAruidDeprecated"},
45 {142, nullptr, "GetAlbumFileList3AaeAruid"},
46 {143, nullptr, "GetAlbumFileList4AaeUidAruid"},
47 {60002, nullptr, "OpenAccessorSessionForApplication"},
48 };
49 // clang-format on
50
51 RegisterHandlers(functions);
52}
53
54CAPS_U::~CAPS_U() = default;
55
56void CAPS_U::GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx) {
57 // Takes a type-0x6 output buffer containing an array of ApplicationAlbumFileEntry, a PID, an
58 // u8 ContentType, two s64s, and an u64 AppletResourceUserId. Returns an output u64 for total
59 // output entries (which is copied to a s32 by official SW).
60 IPC::RequestParser rp{ctx};
61 [[maybe_unused]] const auto application_album_file_entries = rp.PopRaw<std::array<u8, 0x30>>();
62 const auto pid = rp.Pop<s32>();
63 const auto content_type = rp.PopRaw<ContentType>();
64 [[maybe_unused]] const auto start_datetime = rp.PopRaw<AlbumFileDateTime>();
65 [[maybe_unused]] const auto end_datetime = rp.PopRaw<AlbumFileDateTime>();
66 const auto applet_resource_user_id = rp.Pop<u64>();
67 LOG_WARNING(Service_Capture,
68 "(STUBBED) called. pid={}, content_type={}, applet_resource_user_id={}", pid,
69 content_type, applet_resource_user_id);
70
71 IPC::ResponseBuilder rb{ctx, 3};
72 rb.Push(RESULT_SUCCESS);
73 rb.Push<s32>(0);
74}
75
76} // namespace Service::Capture
diff --git a/src/core/hle/service/caps/caps_u.h b/src/core/hle/service/caps/caps_u.h
new file mode 100644
index 000000000..e6e0716ff
--- /dev/null
+++ b/src/core/hle/service/caps/caps_u.h
@@ -0,0 +1,24 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9namespace Kernel {
10class HLERequestContext;
11}
12
13namespace Service::Capture {
14
15class CAPS_U final : public ServiceFramework<CAPS_U> {
16public:
17 explicit CAPS_U();
18 ~CAPS_U() override;
19
20private:
21 void GetAlbumContentsFileListForApplication(Kernel::HLERequestContext& ctx);
22};
23
24} // namespace Service::Capture
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index e6b56a9f9..d6ed5f304 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -235,7 +235,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
235 {303, nullptr, "ActivateSevenSixAxisSensor"}, 235 {303, nullptr, "ActivateSevenSixAxisSensor"},
236 {304, nullptr, "StartSevenSixAxisSensor"}, 236 {304, nullptr, "StartSevenSixAxisSensor"},
237 {305, nullptr, "StopSevenSixAxisSensor"}, 237 {305, nullptr, "StopSevenSixAxisSensor"},
238 {306, nullptr, "InitializeSevenSixAxisSensor"}, 238 {306, &Hid::InitializeSevenSixAxisSensor, "InitializeSevenSixAxisSensor"},
239 {307, nullptr, "FinalizeSevenSixAxisSensor"}, 239 {307, nullptr, "FinalizeSevenSixAxisSensor"},
240 {308, nullptr, "SetSevenSixAxisSensorFusionStrength"}, 240 {308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
241 {309, nullptr, "GetSevenSixAxisSensorFusionStrength"}, 241 {309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
@@ -853,6 +853,13 @@ void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
853 rb.Push(RESULT_SUCCESS); 853 rb.Push(RESULT_SUCCESS);
854} 854}
855 855
856void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) {
857 LOG_WARNING(Service_HID, "(STUBBED) called");
858
859 IPC::ResponseBuilder rb{ctx, 2};
860 rb.Push(RESULT_SUCCESS);
861}
862
856class HidDbg final : public ServiceFramework<HidDbg> { 863class HidDbg final : public ServiceFramework<HidDbg> {
857public: 864public:
858 explicit HidDbg() : ServiceFramework{"hid:dbg"} { 865 explicit HidDbg() : ServiceFramework{"hid:dbg"} {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index ad20f147c..039c38b58 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -128,6 +128,7 @@ private:
128 void StopSixAxisSensor(Kernel::HLERequestContext& ctx); 128 void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
129 void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); 129 void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
130 void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); 130 void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
131 void InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx);
131 132
132 std::shared_ptr<IAppletResource> applet_resource; 133 std::shared_ptr<IAppletResource> applet_resource;
133 Core::System& system; 134 Core::System& system;
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp
index 1660bbdb8..f509653a3 100644
--- a/src/core/hle/service/time/interface.cpp
+++ b/src/core/hle/service/time/interface.cpp
@@ -30,7 +30,7 @@ Time::Time(std::shared_ptr<Module> module, Core::System& system, const char* nam
30 {400, &Time::GetClockSnapshot, "GetClockSnapshot"}, 30 {400, &Time::GetClockSnapshot, "GetClockSnapshot"},
31 {401, &Time::GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"}, 31 {401, &Time::GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"},
32 {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"}, 32 {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"},
33 {501, nullptr, "CalculateSpanBetween"}, 33 {501, &Time::CalculateSpanBetween, "CalculateSpanBetween"},
34 }; 34 };
35 // clang-format on 35 // clang-format on
36 36
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 749b7be70..ce859f18d 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -308,6 +308,35 @@ void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLEReques
308 ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot)); 308 ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot));
309} 309}
310 310
311void Module::Interface::CalculateSpanBetween(Kernel::HLERequestContext& ctx) {
312 LOG_DEBUG(Service_Time, "called");
313
314 IPC::RequestParser rp{ctx};
315 const auto snapshot_a = rp.PopRaw<Clock::ClockSnapshot>();
316 const auto snapshot_b = rp.PopRaw<Clock::ClockSnapshot>();
317
318 Clock::TimeSpanType time_span_type{};
319 s64 span{};
320 if (const ResultCode result{snapshot_a.steady_clock_time_point.GetSpanBetween(
321 snapshot_b.steady_clock_time_point, span)};
322 result != RESULT_SUCCESS) {
323 if (snapshot_a.network_time && snapshot_b.network_time) {
324 time_span_type =
325 Clock::TimeSpanType::FromSeconds(snapshot_b.network_time - snapshot_a.network_time);
326 } else {
327 IPC::ResponseBuilder rb{ctx, 2};
328 rb.Push(ERROR_TIME_NOT_FOUND);
329 return;
330 }
331 } else {
332 time_span_type = Clock::TimeSpanType::FromSeconds(span);
333 }
334
335 IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
336 rb.Push(RESULT_SUCCESS);
337 rb.PushRaw(time_span_type.nanoseconds);
338}
339
311void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { 340void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
312 LOG_DEBUG(Service_Time, "called"); 341 LOG_DEBUG(Service_Time, "called");
313 IPC::ResponseBuilder rb{ctx, 2, 1}; 342 IPC::ResponseBuilder rb{ctx, 2, 1};
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index aadc2df60..351988468 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -32,6 +32,7 @@ public:
32 void CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx); 32 void CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx);
33 void GetClockSnapshot(Kernel::HLERequestContext& ctx); 33 void GetClockSnapshot(Kernel::HLERequestContext& ctx);
34 void GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx); 34 void GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx);
35 void CalculateSpanBetween(Kernel::HLERequestContext& ctx);
35 void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx); 36 void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx);
36 37
37 private: 38 private:
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 91df062d7..effe76a63 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -210,6 +210,8 @@ if (ENABLE_VULKAN)
210 renderer_vulkan/vk_texture_cache.h 210 renderer_vulkan/vk_texture_cache.h
211 renderer_vulkan/vk_update_descriptor.cpp 211 renderer_vulkan/vk_update_descriptor.cpp
212 renderer_vulkan/vk_update_descriptor.h 212 renderer_vulkan/vk_update_descriptor.h
213 renderer_vulkan/wrapper.cpp
214 renderer_vulkan/wrapper.h
213 ) 215 )
214 216
215 target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include) 217 target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include)
diff --git a/src/video_core/engines/const_buffer_engine_interface.h b/src/video_core/engines/const_buffer_engine_interface.h
index 724ee0fd6..ebe139504 100644
--- a/src/video_core/engines/const_buffer_engine_interface.h
+++ b/src/video_core/engines/const_buffer_engine_interface.h
@@ -18,10 +18,14 @@ struct SamplerDescriptor {
18 union { 18 union {
19 u32 raw = 0; 19 u32 raw = 0;
20 BitField<0, 2, Tegra::Shader::TextureType> texture_type; 20 BitField<0, 2, Tegra::Shader::TextureType> texture_type;
21 BitField<2, 3, Tegra::Texture::ComponentType> component_type; 21 BitField<2, 3, Tegra::Texture::ComponentType> r_type;
22 BitField<5, 1, u32> is_array; 22 BitField<5, 1, u32> is_array;
23 BitField<6, 1, u32> is_buffer; 23 BitField<6, 1, u32> is_buffer;
24 BitField<7, 1, u32> is_shadow; 24 BitField<7, 1, u32> is_shadow;
25 BitField<8, 3, Tegra::Texture::ComponentType> g_type;
26 BitField<11, 3, Tegra::Texture::ComponentType> b_type;
27 BitField<14, 3, Tegra::Texture::ComponentType> a_type;
28 BitField<17, 7, Tegra::Texture::TextureFormat> format;
25 }; 29 };
26 30
27 bool operator==(const SamplerDescriptor& rhs) const noexcept { 31 bool operator==(const SamplerDescriptor& rhs) const noexcept {
@@ -36,9 +40,11 @@ struct SamplerDescriptor {
36 using Tegra::Shader::TextureType; 40 using Tegra::Shader::TextureType;
37 SamplerDescriptor result; 41 SamplerDescriptor result;
38 42
39 // This is going to be used to determine the shading language type. 43 result.format.Assign(tic.format.Value());
40 // Because of that we don't care about all component types on color textures. 44 result.r_type.Assign(tic.r_type.Value());
41 result.component_type.Assign(tic.r_type.Value()); 45 result.g_type.Assign(tic.g_type.Value());
46 result.b_type.Assign(tic.b_type.Value());
47 result.a_type.Assign(tic.a_type.Value());
42 48
43 switch (tic.texture_type.Value()) { 49 switch (tic.texture_type.Value()) {
44 case Tegra::Texture::TextureType::Texture1D: 50 case Tegra::Texture::TextureType::Texture1D:
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index eba42deb4..930b605af 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -82,6 +82,10 @@ union Attribute {
82 Position = 7, 82 Position = 7,
83 Attribute_0 = 8, 83 Attribute_0 = 8,
84 Attribute_31 = 39, 84 Attribute_31 = 39,
85 FrontColor = 40,
86 FrontSecondaryColor = 41,
87 BackColor = 42,
88 BackSecondaryColor = 43,
85 ClipDistances0123 = 44, 89 ClipDistances0123 = 44,
86 ClipDistances4567 = 45, 90 ClipDistances4567 = 45,
87 PointCoord = 46, 91 PointCoord = 46,
@@ -89,6 +93,8 @@ union Attribute {
89 // shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval 93 // shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval
90 // shader. 94 // shader.
91 TessCoordInstanceIDVertexID = 47, 95 TessCoordInstanceIDVertexID = 47,
96 TexCoord_0 = 48,
97 TexCoord_7 = 55,
92 // This attribute contains a tuple of (Unk, Unk, Unk, gl_FrontFacing) when inside a fragment 98 // This attribute contains a tuple of (Unk, Unk, Unk, gl_FrontFacing) when inside a fragment
93 // shader. It is unknown what the other values contain. 99 // shader. It is unknown what the other values contain.
94 FrontFacing = 63, 100 FrontFacing = 63,
@@ -225,18 +231,6 @@ enum class AtomicOp : u64 {
225 Or = 6, 231 Or = 6,
226 Xor = 7, 232 Xor = 7,
227 Exch = 8, 233 Exch = 8,
228};
229
230enum class GlobalAtomicOp : u64 {
231 Add = 0,
232 Min = 1,
233 Max = 2,
234 Inc = 3,
235 Dec = 4,
236 And = 5,
237 Or = 6,
238 Xor = 7,
239 Exch = 8,
240 SafeAdd = 10, 234 SafeAdd = 10,
241}; 235};
242 236
@@ -995,7 +989,7 @@ union Instruction {
995 } stg; 989 } stg;
996 990
997 union { 991 union {
998 BitField<52, 4, GlobalAtomicOp> operation; 992 BitField<52, 4, AtomicOp> operation;
999 BitField<49, 3, GlobalAtomicType> type; 993 BitField<49, 3, GlobalAtomicType> type;
1000 BitField<28, 20, s64> offset; 994 BitField<28, 20, s64> offset;
1001 } atom; 995 } atom;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 826eee7df..31add708f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -444,6 +444,7 @@ void RasterizerOpenGL::Clear() {
444 } 444 }
445 445
446 SyncRasterizeEnable(); 446 SyncRasterizeEnable();
447 SyncStencilTestState();
447 448
448 if (regs.clear_flags.scissor) { 449 if (regs.clear_flags.scissor) {
449 SyncScissorTest(); 450 SyncScissorTest();
@@ -1052,12 +1053,8 @@ void RasterizerOpenGL::SyncStencilTestState() {
1052 flags[Dirty::StencilTest] = false; 1053 flags[Dirty::StencilTest] = false;
1053 1054
1054 const auto& regs = gpu.regs; 1055 const auto& regs = gpu.regs;
1055 if (!regs.stencil_enable) { 1056 oglEnable(GL_STENCIL_TEST, regs.stencil_enable);
1056 glDisable(GL_STENCIL_TEST);
1057 return;
1058 }
1059 1057
1060 glEnable(GL_STENCIL_TEST);
1061 glStencilFuncSeparate(GL_FRONT, MaxwellToGL::ComparisonOp(regs.stencil_front_func_func), 1058 glStencilFuncSeparate(GL_FRONT, MaxwellToGL::ComparisonOp(regs.stencil_front_func_func),
1062 regs.stencil_front_func_ref, regs.stencil_front_func_mask); 1059 regs.stencil_front_func_ref, regs.stencil_front_func_mask);
1063 glStencilOpSeparate(GL_FRONT, MaxwellToGL::StencilOp(regs.stencil_front_op_fail), 1060 glStencilOpSeparate(GL_FRONT, MaxwellToGL::StencilOp(regs.stencil_front_op_fail),
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 2c38f57fd..c7d24cf14 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -366,10 +366,19 @@ constexpr bool IsGenericAttribute(Attribute::Index index) {
366 return index >= Attribute::Index::Attribute_0 && index <= Attribute::Index::Attribute_31; 366 return index >= Attribute::Index::Attribute_0 && index <= Attribute::Index::Attribute_31;
367} 367}
368 368
369constexpr bool IsLegacyTexCoord(Attribute::Index index) {
370 return static_cast<int>(index) >= static_cast<int>(Attribute::Index::TexCoord_0) &&
371 static_cast<int>(index) <= static_cast<int>(Attribute::Index::TexCoord_7);
372}
373
369constexpr Attribute::Index ToGenericAttribute(u64 value) { 374constexpr Attribute::Index ToGenericAttribute(u64 value) {
370 return static_cast<Attribute::Index>(value + static_cast<u64>(Attribute::Index::Attribute_0)); 375 return static_cast<Attribute::Index>(value + static_cast<u64>(Attribute::Index::Attribute_0));
371} 376}
372 377
378constexpr int GetLegacyTexCoordIndex(Attribute::Index index) {
379 return static_cast<int>(index) - static_cast<int>(Attribute::Index::TexCoord_0);
380}
381
373u32 GetGenericAttributeIndex(Attribute::Index index) { 382u32 GetGenericAttributeIndex(Attribute::Index index) {
374 ASSERT(IsGenericAttribute(index)); 383 ASSERT(IsGenericAttribute(index));
375 return static_cast<u32>(index) - static_cast<u32>(Attribute::Index::Attribute_0); 384 return static_cast<u32>(index) - static_cast<u32>(Attribute::Index::Attribute_0);
@@ -498,7 +507,7 @@ private:
498 if (!identifier.empty()) { 507 if (!identifier.empty()) {
499 code.AddLine("// {}", identifier); 508 code.AddLine("// {}", identifier);
500 } 509 }
501 code.AddLine("#version 440 core"); 510 code.AddLine("#version 440 {}", ir.UsesLegacyVaryings() ? "compatibility" : "core");
502 code.AddLine("#extension GL_ARB_separate_shader_objects : enable"); 511 code.AddLine("#extension GL_ARB_separate_shader_objects : enable");
503 if (device.HasShaderBallot()) { 512 if (device.HasShaderBallot()) {
504 code.AddLine("#extension GL_ARB_shader_ballot : require"); 513 code.AddLine("#extension GL_ARB_shader_ballot : require");
@@ -561,6 +570,16 @@ private:
561 if (stage != ShaderType::Fragment) { 570 if (stage != ShaderType::Fragment) {
562 return; 571 return;
563 } 572 }
573 if (ir.UsesLegacyVaryings()) {
574 code.AddLine("in gl_PerFragment {{");
575 ++code.scope;
576 code.AddLine("vec4 gl_TexCoord[8];");
577 code.AddLine("vec4 gl_Color;");
578 code.AddLine("vec4 gl_SecondaryColor;");
579 --code.scope;
580 code.AddLine("}};");
581 }
582
564 for (u32 rt = 0; rt < Maxwell::NumRenderTargets; ++rt) { 583 for (u32 rt = 0; rt < Maxwell::NumRenderTargets; ++rt) {
565 code.AddLine("layout (location = {}) out vec4 frag_color{};", rt, rt); 584 code.AddLine("layout (location = {}) out vec4 frag_color{};", rt, rt);
566 } 585 }
@@ -617,12 +636,12 @@ private:
617 code.AddLine("float gl_PointSize;"); 636 code.AddLine("float gl_PointSize;");
618 } 637 }
619 638
620 if (ir.UsesInstanceId()) { 639 if (ir.UsesLegacyVaryings()) {
621 code.AddLine("int gl_InstanceID;"); 640 code.AddLine("vec4 gl_TexCoord[8];");
622 } 641 code.AddLine("vec4 gl_FrontColor;");
623 642 code.AddLine("vec4 gl_FrontSecondaryColor;");
624 if (ir.UsesVertexId()) { 643 code.AddLine("vec4 gl_BackColor;");
625 code.AddLine("int gl_VertexID;"); 644 code.AddLine("vec4 gl_BackSecondaryColor;");
626 } 645 }
627 646
628 --code.scope; 647 --code.scope;
@@ -1128,6 +1147,10 @@ private:
1128 default: 1147 default:
1129 UNREACHABLE(); 1148 UNREACHABLE();
1130 } 1149 }
1150 case Attribute::Index::FrontColor:
1151 return {"gl_Color"s + GetSwizzle(element), Type::Float};
1152 case Attribute::Index::FrontSecondaryColor:
1153 return {"gl_SecondaryColor"s + GetSwizzle(element), Type::Float};
1131 case Attribute::Index::PointCoord: 1154 case Attribute::Index::PointCoord:
1132 switch (element) { 1155 switch (element) {
1133 case 0: 1156 case 0:
@@ -1168,6 +1191,12 @@ private:
1168 return {GeometryPass(GetGenericInputAttribute(attribute)) + GetSwizzle(element), 1191 return {GeometryPass(GetGenericInputAttribute(attribute)) + GetSwizzle(element),
1169 Type::Float}; 1192 Type::Float};
1170 } 1193 }
1194 if (IsLegacyTexCoord(attribute)) {
1195 UNIMPLEMENTED_IF(stage == ShaderType::Geometry);
1196 return {fmt::format("gl_TexCoord[{}]{}", GetLegacyTexCoordIndex(attribute),
1197 GetSwizzle(element)),
1198 Type::Float};
1199 }
1171 break; 1200 break;
1172 } 1201 }
1173 UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); 1202 UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute));
@@ -1206,11 +1235,12 @@ private:
1206 } 1235 }
1207 1236
1208 std::optional<Expression> GetOutputAttribute(const AbufNode* abuf) { 1237 std::optional<Expression> GetOutputAttribute(const AbufNode* abuf) {
1238 const u32 element = abuf->GetElement();
1209 switch (const auto attribute = abuf->GetIndex()) { 1239 switch (const auto attribute = abuf->GetIndex()) {
1210 case Attribute::Index::Position: 1240 case Attribute::Index::Position:
1211 return {{"gl_Position"s + GetSwizzle(abuf->GetElement()), Type::Float}}; 1241 return {{"gl_Position"s + GetSwizzle(element), Type::Float}};
1212 case Attribute::Index::LayerViewportPointSize: 1242 case Attribute::Index::LayerViewportPointSize:
1213 switch (abuf->GetElement()) { 1243 switch (element) {
1214 case 0: 1244 case 0:
1215 UNIMPLEMENTED(); 1245 UNIMPLEMENTED();
1216 return {}; 1246 return {};
@@ -1228,13 +1258,26 @@ private:
1228 return {{"gl_PointSize", Type::Float}}; 1258 return {{"gl_PointSize", Type::Float}};
1229 } 1259 }
1230 return {}; 1260 return {};
1261 case Attribute::Index::FrontColor:
1262 return {{"gl_FrontColor"s + GetSwizzle(element), Type::Float}};
1263 case Attribute::Index::FrontSecondaryColor:
1264 return {{"gl_FrontSecondaryColor"s + GetSwizzle(element), Type::Float}};
1265 case Attribute::Index::BackColor:
1266 return {{"gl_BackColor"s + GetSwizzle(element), Type::Float}};
1267 case Attribute::Index::BackSecondaryColor:
1268 return {{"gl_BackSecondaryColor"s + GetSwizzle(element), Type::Float}};
1231 case Attribute::Index::ClipDistances0123: 1269 case Attribute::Index::ClipDistances0123:
1232 return {{fmt::format("gl_ClipDistance[{}]", abuf->GetElement()), Type::Float}}; 1270 return {{fmt::format("gl_ClipDistance[{}]", element), Type::Float}};
1233 case Attribute::Index::ClipDistances4567: 1271 case Attribute::Index::ClipDistances4567:
1234 return {{fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4), Type::Float}}; 1272 return {{fmt::format("gl_ClipDistance[{}]", element + 4), Type::Float}};
1235 default: 1273 default:
1236 if (IsGenericAttribute(attribute)) { 1274 if (IsGenericAttribute(attribute)) {
1237 return {{GetGenericOutputAttribute(attribute, abuf->GetElement()), Type::Float}}; 1275 return {{GetGenericOutputAttribute(attribute, element), Type::Float}};
1276 }
1277 if (IsLegacyTexCoord(attribute)) {
1278 return {{fmt::format("gl_TexCoord[{}]{}", GetLegacyTexCoordIndex(attribute),
1279 GetSwizzle(element)),
1280 Type::Float}};
1238 } 1281 }
1239 UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute)); 1282 UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute));
1240 return {}; 1283 return {};
@@ -2071,6 +2114,10 @@ private:
2071 2114
2072 template <const std::string_view& opname, Type type> 2115 template <const std::string_view& opname, Type type>
2073 Expression Atomic(Operation operation) { 2116 Expression Atomic(Operation operation) {
2117 if ((opname == Func::Min || opname == Func::Max) && type == Type::Int) {
2118 UNIMPLEMENTED_MSG("Unimplemented Min & Max for atomic operations");
2119 return {};
2120 }
2074 return {fmt::format("atomic{}({}, {})", opname, Visit(operation[0]).GetCode(), 2121 return {fmt::format("atomic{}({}, {})", opname, Visit(operation[0]).GetCode(),
2075 Visit(operation[1]).As(type)), 2122 Visit(operation[1]).As(type)),
2076 type}; 2123 type};
@@ -2264,6 +2311,8 @@ private:
2264 ~Func() = delete; 2311 ~Func() = delete;
2265 2312
2266 static constexpr std::string_view Add = "Add"; 2313 static constexpr std::string_view Add = "Add";
2314 static constexpr std::string_view Min = "Min";
2315 static constexpr std::string_view Max = "Max";
2267 static constexpr std::string_view And = "And"; 2316 static constexpr std::string_view And = "And";
2268 static constexpr std::string_view Or = "Or"; 2317 static constexpr std::string_view Or = "Or";
2269 static constexpr std::string_view Xor = "Xor"; 2318 static constexpr std::string_view Xor = "Xor";
@@ -2414,7 +2463,21 @@ private:
2414 &GLSLDecompiler::AtomicImage<Func::Xor>, 2463 &GLSLDecompiler::AtomicImage<Func::Xor>,
2415 &GLSLDecompiler::AtomicImage<Func::Exchange>, 2464 &GLSLDecompiler::AtomicImage<Func::Exchange>,
2416 2465
2466 &GLSLDecompiler::Atomic<Func::Exchange, Type::Uint>,
2417 &GLSLDecompiler::Atomic<Func::Add, Type::Uint>, 2467 &GLSLDecompiler::Atomic<Func::Add, Type::Uint>,
2468 &GLSLDecompiler::Atomic<Func::Min, Type::Uint>,
2469 &GLSLDecompiler::Atomic<Func::Max, Type::Uint>,
2470 &GLSLDecompiler::Atomic<Func::And, Type::Uint>,
2471 &GLSLDecompiler::Atomic<Func::Or, Type::Uint>,
2472 &GLSLDecompiler::Atomic<Func::Xor, Type::Uint>,
2473
2474 &GLSLDecompiler::Atomic<Func::Exchange, Type::Int>,
2475 &GLSLDecompiler::Atomic<Func::Add, Type::Int>,
2476 &GLSLDecompiler::Atomic<Func::Min, Type::Int>,
2477 &GLSLDecompiler::Atomic<Func::Max, Type::Int>,
2478 &GLSLDecompiler::Atomic<Func::And, Type::Int>,
2479 &GLSLDecompiler::Atomic<Func::Or, Type::Int>,
2480 &GLSLDecompiler::Atomic<Func::Xor, Type::Int>,
2418 2481
2419 &GLSLDecompiler::Branch, 2482 &GLSLDecompiler::Branch,
2420 &GLSLDecompiler::BranchIndirect, 2483 &GLSLDecompiler::BranchIndirect,
diff --git a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
index f93447610..7480cb7c3 100644
--- a/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
+++ b/src/video_core/renderer_vulkan/maxwell_to_vk.cpp
@@ -401,6 +401,26 @@ vk::Format VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttr
401 } 401 }
402 break; 402 break;
403 case Maxwell::VertexAttribute::Type::SignedScaled: 403 case Maxwell::VertexAttribute::Type::SignedScaled:
404 switch (size) {
405 case Maxwell::VertexAttribute::Size::Size_8:
406 return vk::Format::eR8Sscaled;
407 case Maxwell::VertexAttribute::Size::Size_8_8:
408 return vk::Format::eR8G8Sscaled;
409 case Maxwell::VertexAttribute::Size::Size_8_8_8:
410 return vk::Format::eR8G8B8Sscaled;
411 case Maxwell::VertexAttribute::Size::Size_8_8_8_8:
412 return vk::Format::eR8G8B8A8Sscaled;
413 case Maxwell::VertexAttribute::Size::Size_16:
414 return vk::Format::eR16Sscaled;
415 case Maxwell::VertexAttribute::Size::Size_16_16:
416 return vk::Format::eR16G16Sscaled;
417 case Maxwell::VertexAttribute::Size::Size_16_16_16:
418 return vk::Format::eR16G16B16Sscaled;
419 case Maxwell::VertexAttribute::Size::Size_16_16_16_16:
420 return vk::Format::eR16G16B16A16Sscaled;
421 default:
422 break;
423 }
404 break; 424 break;
405 case Maxwell::VertexAttribute::Type::Float: 425 case Maxwell::VertexAttribute::Type::Float:
406 switch (size) { 426 switch (size) {
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index 51ecb5567..d67f08cf9 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -1941,7 +1941,11 @@ private:
1941 return {}; 1941 return {};
1942 } 1942 }
1943 1943
1944 Expression AtomicAdd(Operation operation) { 1944 template <Id (Module::*func)(Id, Id, Id, Id, Id), Type result_type,
1945 Type value_type = result_type>
1946 Expression Atomic(Operation operation) {
1947 const Id type_def = GetTypeDefinition(result_type);
1948
1945 Id pointer; 1949 Id pointer;
1946 if (const auto smem = std::get_if<SmemNode>(&*operation[0])) { 1950 if (const auto smem = std::get_if<SmemNode>(&*operation[0])) {
1947 pointer = GetSharedMemoryPointer(*smem); 1951 pointer = GetSharedMemoryPointer(*smem);
@@ -1949,14 +1953,15 @@ private:
1949 pointer = GetGlobalMemoryPointer(*gmem); 1953 pointer = GetGlobalMemoryPointer(*gmem);
1950 } else { 1954 } else {
1951 UNREACHABLE(); 1955 UNREACHABLE();
1952 return {Constant(t_uint, 0), Type::Uint}; 1956 return {Constant(type_def, 0), result_type};
1953 } 1957 }
1954 1958
1959 const Id value = As(Visit(operation[1]), value_type);
1960
1955 const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device)); 1961 const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device));
1956 const Id semantics = Constant(t_uint, 0U); 1962 const Id semantics = Constant(type_def, 0);
1957 1963
1958 const Id value = AsUint(Visit(operation[1])); 1964 return {(this->*func)(type_def, pointer, scope, semantics, value), result_type};
1959 return {OpAtomicIAdd(t_uint, pointer, scope, semantics, value), Type::Uint};
1960 } 1965 }
1961 1966
1962 Expression Branch(Operation operation) { 1967 Expression Branch(Operation operation) {
@@ -2545,7 +2550,21 @@ private:
2545 &SPIRVDecompiler::AtomicImageXor, 2550 &SPIRVDecompiler::AtomicImageXor,
2546 &SPIRVDecompiler::AtomicImageExchange, 2551 &SPIRVDecompiler::AtomicImageExchange,
2547 2552
2548 &SPIRVDecompiler::AtomicAdd, 2553 &SPIRVDecompiler::Atomic<&Module::OpAtomicExchange, Type::Uint>,
2554 &SPIRVDecompiler::Atomic<&Module::OpAtomicIAdd, Type::Uint>,
2555 &SPIRVDecompiler::Atomic<&Module::OpAtomicUMin, Type::Uint>,
2556 &SPIRVDecompiler::Atomic<&Module::OpAtomicUMax, Type::Uint>,
2557 &SPIRVDecompiler::Atomic<&Module::OpAtomicAnd, Type::Uint>,
2558 &SPIRVDecompiler::Atomic<&Module::OpAtomicOr, Type::Uint>,
2559 &SPIRVDecompiler::Atomic<&Module::OpAtomicXor, Type::Uint>,
2560
2561 &SPIRVDecompiler::Atomic<&Module::OpAtomicExchange, Type::Int>,
2562 &SPIRVDecompiler::Atomic<&Module::OpAtomicIAdd, Type::Int>,
2563 &SPIRVDecompiler::Atomic<&Module::OpAtomicSMin, Type::Int>,
2564 &SPIRVDecompiler::Atomic<&Module::OpAtomicSMax, Type::Int>,
2565 &SPIRVDecompiler::Atomic<&Module::OpAtomicAnd, Type::Int>,
2566 &SPIRVDecompiler::Atomic<&Module::OpAtomicOr, Type::Int>,
2567 &SPIRVDecompiler::Atomic<&Module::OpAtomicXor, Type::Int>,
2549 2568
2550 &SPIRVDecompiler::Branch, 2569 &SPIRVDecompiler::Branch,
2551 &SPIRVDecompiler::BranchIndirect, 2570 &SPIRVDecompiler::BranchIndirect,
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp
new file mode 100644
index 000000000..9b94dfff1
--- /dev/null
+++ b/src/video_core/renderer_vulkan/wrapper.cpp
@@ -0,0 +1,750 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <exception>
6#include <memory>
7#include <optional>
8#include <utility>
9#include <vector>
10
11#include "common/common_types.h"
12
13#include "video_core/renderer_vulkan/wrapper.h"
14
15namespace Vulkan::vk {
16
17namespace {
18
19template <typename T>
20bool Proc(T& result, const InstanceDispatch& dld, const char* proc_name,
21 VkInstance instance = nullptr) noexcept {
22 result = reinterpret_cast<T>(dld.vkGetInstanceProcAddr(instance, proc_name));
23 return result != nullptr;
24}
25
26template <typename T>
27void Proc(T& result, const DeviceDispatch& dld, const char* proc_name, VkDevice device) noexcept {
28 result = reinterpret_cast<T>(dld.vkGetDeviceProcAddr(device, proc_name));
29}
30
31void Load(VkDevice device, DeviceDispatch& dld) noexcept {
32#define X(name) Proc(dld.name, dld, #name, device)
33 X(vkAcquireNextImageKHR);
34 X(vkAllocateCommandBuffers);
35 X(vkAllocateDescriptorSets);
36 X(vkAllocateMemory);
37 X(vkBeginCommandBuffer);
38 X(vkBindBufferMemory);
39 X(vkBindImageMemory);
40 X(vkCmdBeginQuery);
41 X(vkCmdBeginRenderPass);
42 X(vkCmdBeginTransformFeedbackEXT);
43 X(vkCmdBindDescriptorSets);
44 X(vkCmdBindIndexBuffer);
45 X(vkCmdBindPipeline);
46 X(vkCmdBindTransformFeedbackBuffersEXT);
47 X(vkCmdBindVertexBuffers);
48 X(vkCmdBlitImage);
49 X(vkCmdClearAttachments);
50 X(vkCmdCopyBuffer);
51 X(vkCmdCopyBufferToImage);
52 X(vkCmdCopyImage);
53 X(vkCmdCopyImageToBuffer);
54 X(vkCmdDispatch);
55 X(vkCmdDraw);
56 X(vkCmdDrawIndexed);
57 X(vkCmdEndQuery);
58 X(vkCmdEndRenderPass);
59 X(vkCmdEndTransformFeedbackEXT);
60 X(vkCmdFillBuffer);
61 X(vkCmdPipelineBarrier);
62 X(vkCmdPushConstants);
63 X(vkCmdSetBlendConstants);
64 X(vkCmdSetCheckpointNV);
65 X(vkCmdSetDepthBias);
66 X(vkCmdSetDepthBounds);
67 X(vkCmdSetScissor);
68 X(vkCmdSetStencilCompareMask);
69 X(vkCmdSetStencilReference);
70 X(vkCmdSetStencilWriteMask);
71 X(vkCmdSetViewport);
72 X(vkCreateBuffer);
73 X(vkCreateBufferView);
74 X(vkCreateCommandPool);
75 X(vkCreateComputePipelines);
76 X(vkCreateDescriptorPool);
77 X(vkCreateDescriptorSetLayout);
78 X(vkCreateDescriptorUpdateTemplateKHR);
79 X(vkCreateFence);
80 X(vkCreateFramebuffer);
81 X(vkCreateGraphicsPipelines);
82 X(vkCreateImage);
83 X(vkCreateImageView);
84 X(vkCreatePipelineLayout);
85 X(vkCreateQueryPool);
86 X(vkCreateRenderPass);
87 X(vkCreateSampler);
88 X(vkCreateSemaphore);
89 X(vkCreateShaderModule);
90 X(vkCreateSwapchainKHR);
91 X(vkDestroyBuffer);
92 X(vkDestroyBufferView);
93 X(vkDestroyCommandPool);
94 X(vkDestroyDescriptorPool);
95 X(vkDestroyDescriptorSetLayout);
96 X(vkDestroyDescriptorUpdateTemplateKHR);
97 X(vkDestroyFence);
98 X(vkDestroyFramebuffer);
99 X(vkDestroyImage);
100 X(vkDestroyImageView);
101 X(vkDestroyPipeline);
102 X(vkDestroyPipelineLayout);
103 X(vkDestroyQueryPool);
104 X(vkDestroyRenderPass);
105 X(vkDestroySampler);
106 X(vkDestroySemaphore);
107 X(vkDestroyShaderModule);
108 X(vkDestroySwapchainKHR);
109 X(vkDeviceWaitIdle);
110 X(vkEndCommandBuffer);
111 X(vkFreeCommandBuffers);
112 X(vkFreeDescriptorSets);
113 X(vkFreeMemory);
114 X(vkGetBufferMemoryRequirements);
115 X(vkGetDeviceQueue);
116 X(vkGetFenceStatus);
117 X(vkGetImageMemoryRequirements);
118 X(vkGetQueryPoolResults);
119 X(vkGetQueueCheckpointDataNV);
120 X(vkMapMemory);
121 X(vkQueueSubmit);
122 X(vkResetFences);
123 X(vkResetQueryPoolEXT);
124 X(vkUnmapMemory);
125 X(vkUpdateDescriptorSetWithTemplateKHR);
126 X(vkUpdateDescriptorSets);
127 X(vkWaitForFences);
128#undef X
129}
130
131} // Anonymous namespace
132
133bool Load(InstanceDispatch& dld) noexcept {
134#define X(name) Proc(dld.name, dld, #name)
135 return X(vkCreateInstance) && X(vkEnumerateInstanceExtensionProperties);
136#undef X
137}
138
139bool Load(VkInstance instance, InstanceDispatch& dld) noexcept {
140#define X(name) Proc(dld.name, dld, #name, instance)
141 // These functions may fail to load depending on the enabled extensions.
142 // Don't return a failure on these.
143 X(vkCreateDebugUtilsMessengerEXT);
144 X(vkDestroyDebugUtilsMessengerEXT);
145 X(vkDestroySurfaceKHR);
146 X(vkGetPhysicalDeviceFeatures2KHR);
147 X(vkGetPhysicalDeviceProperties2KHR);
148 X(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
149 X(vkGetPhysicalDeviceSurfaceFormatsKHR);
150 X(vkGetPhysicalDeviceSurfacePresentModesKHR);
151 X(vkGetPhysicalDeviceSurfaceSupportKHR);
152 X(vkGetSwapchainImagesKHR);
153 X(vkQueuePresentKHR);
154
155 return X(vkCreateDevice) && X(vkDestroyDevice) && X(vkDestroyDevice) &&
156 X(vkEnumerateDeviceExtensionProperties) && X(vkEnumeratePhysicalDevices) &&
157 X(vkGetDeviceProcAddr) && X(vkGetPhysicalDeviceFormatProperties) &&
158 X(vkGetPhysicalDeviceMemoryProperties) && X(vkGetPhysicalDeviceProperties) &&
159 X(vkGetPhysicalDeviceQueueFamilyProperties);
160#undef X
161}
162
163const char* Exception::what() const noexcept {
164 return ToString(result);
165}
166
167const char* ToString(VkResult result) noexcept {
168 switch (result) {
169 case VkResult::VK_SUCCESS:
170 return "VK_SUCCESS";
171 case VkResult::VK_NOT_READY:
172 return "VK_NOT_READY";
173 case VkResult::VK_TIMEOUT:
174 return "VK_TIMEOUT";
175 case VkResult::VK_EVENT_SET:
176 return "VK_EVENT_SET";
177 case VkResult::VK_EVENT_RESET:
178 return "VK_EVENT_RESET";
179 case VkResult::VK_INCOMPLETE:
180 return "VK_INCOMPLETE";
181 case VkResult::VK_ERROR_OUT_OF_HOST_MEMORY:
182 return "VK_ERROR_OUT_OF_HOST_MEMORY";
183 case VkResult::VK_ERROR_OUT_OF_DEVICE_MEMORY:
184 return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
185 case VkResult::VK_ERROR_INITIALIZATION_FAILED:
186 return "VK_ERROR_INITIALIZATION_FAILED";
187 case VkResult::VK_ERROR_DEVICE_LOST:
188 return "VK_ERROR_DEVICE_LOST";
189 case VkResult::VK_ERROR_MEMORY_MAP_FAILED:
190 return "VK_ERROR_MEMORY_MAP_FAILED";
191 case VkResult::VK_ERROR_LAYER_NOT_PRESENT:
192 return "VK_ERROR_LAYER_NOT_PRESENT";
193 case VkResult::VK_ERROR_EXTENSION_NOT_PRESENT:
194 return "VK_ERROR_EXTENSION_NOT_PRESENT";
195 case VkResult::VK_ERROR_FEATURE_NOT_PRESENT:
196 return "VK_ERROR_FEATURE_NOT_PRESENT";
197 case VkResult::VK_ERROR_INCOMPATIBLE_DRIVER:
198 return "VK_ERROR_INCOMPATIBLE_DRIVER";
199 case VkResult::VK_ERROR_TOO_MANY_OBJECTS:
200 return "VK_ERROR_TOO_MANY_OBJECTS";
201 case VkResult::VK_ERROR_FORMAT_NOT_SUPPORTED:
202 return "VK_ERROR_FORMAT_NOT_SUPPORTED";
203 case VkResult::VK_ERROR_FRAGMENTED_POOL:
204 return "VK_ERROR_FRAGMENTED_POOL";
205 case VkResult::VK_ERROR_OUT_OF_POOL_MEMORY:
206 return "VK_ERROR_OUT_OF_POOL_MEMORY";
207 case VkResult::VK_ERROR_INVALID_EXTERNAL_HANDLE:
208 return "VK_ERROR_INVALID_EXTERNAL_HANDLE";
209 case VkResult::VK_ERROR_SURFACE_LOST_KHR:
210 return "VK_ERROR_SURFACE_LOST_KHR";
211 case VkResult::VK_ERROR_NATIVE_WINDOW_IN_USE_KHR:
212 return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
213 case VkResult::VK_SUBOPTIMAL_KHR:
214 return "VK_SUBOPTIMAL_KHR";
215 case VkResult::VK_ERROR_OUT_OF_DATE_KHR:
216 return "VK_ERROR_OUT_OF_DATE_KHR";
217 case VkResult::VK_ERROR_INCOMPATIBLE_DISPLAY_KHR:
218 return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
219 case VkResult::VK_ERROR_VALIDATION_FAILED_EXT:
220 return "VK_ERROR_VALIDATION_FAILED_EXT";
221 case VkResult::VK_ERROR_INVALID_SHADER_NV:
222 return "VK_ERROR_INVALID_SHADER_NV";
223 case VkResult::VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT:
224 return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT";
225 case VkResult::VK_ERROR_FRAGMENTATION_EXT:
226 return "VK_ERROR_FRAGMENTATION_EXT";
227 case VkResult::VK_ERROR_NOT_PERMITTED_EXT:
228 return "VK_ERROR_NOT_PERMITTED_EXT";
229 case VkResult::VK_ERROR_INVALID_DEVICE_ADDRESS_EXT:
230 return "VK_ERROR_INVALID_DEVICE_ADDRESS_EXT";
231 case VkResult::VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
232 return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
233 }
234 return "Unknown";
235}
236
237void Destroy(VkInstance instance, const InstanceDispatch& dld) noexcept {
238 dld.vkDestroyInstance(instance, nullptr);
239}
240
241void Destroy(VkDevice device, const InstanceDispatch& dld) noexcept {
242 dld.vkDestroyDevice(device, nullptr);
243}
244
245void Destroy(VkDevice device, VkBuffer handle, const DeviceDispatch& dld) noexcept {
246 dld.vkDestroyBuffer(device, handle, nullptr);
247}
248
249void Destroy(VkDevice device, VkBufferView handle, const DeviceDispatch& dld) noexcept {
250 dld.vkDestroyBufferView(device, handle, nullptr);
251}
252
253void Destroy(VkDevice device, VkCommandPool handle, const DeviceDispatch& dld) noexcept {
254 dld.vkDestroyCommandPool(device, handle, nullptr);
255}
256
257void Destroy(VkDevice device, VkDescriptorPool handle, const DeviceDispatch& dld) noexcept {
258 dld.vkDestroyDescriptorPool(device, handle, nullptr);
259}
260
261void Destroy(VkDevice device, VkDescriptorSetLayout handle, const DeviceDispatch& dld) noexcept {
262 dld.vkDestroyDescriptorSetLayout(device, handle, nullptr);
263}
264
265void Destroy(VkDevice device, VkDescriptorUpdateTemplateKHR handle,
266 const DeviceDispatch& dld) noexcept {
267 dld.vkDestroyDescriptorUpdateTemplateKHR(device, handle, nullptr);
268}
269
270void Destroy(VkDevice device, VkDeviceMemory handle, const DeviceDispatch& dld) noexcept {
271 dld.vkFreeMemory(device, handle, nullptr);
272}
273
274void Destroy(VkDevice device, VkFence handle, const DeviceDispatch& dld) noexcept {
275 dld.vkDestroyFence(device, handle, nullptr);
276}
277
278void Destroy(VkDevice device, VkFramebuffer handle, const DeviceDispatch& dld) noexcept {
279 dld.vkDestroyFramebuffer(device, handle, nullptr);
280}
281
282void Destroy(VkDevice device, VkImage handle, const DeviceDispatch& dld) noexcept {
283 dld.vkDestroyImage(device, handle, nullptr);
284}
285
286void Destroy(VkDevice device, VkImageView handle, const DeviceDispatch& dld) noexcept {
287 dld.vkDestroyImageView(device, handle, nullptr);
288}
289
290void Destroy(VkDevice device, VkPipeline handle, const DeviceDispatch& dld) noexcept {
291 dld.vkDestroyPipeline(device, handle, nullptr);
292}
293
294void Destroy(VkDevice device, VkPipelineLayout handle, const DeviceDispatch& dld) noexcept {
295 dld.vkDestroyPipelineLayout(device, handle, nullptr);
296}
297
298void Destroy(VkDevice device, VkQueryPool handle, const DeviceDispatch& dld) noexcept {
299 dld.vkDestroyQueryPool(device, handle, nullptr);
300}
301
302void Destroy(VkDevice device, VkRenderPass handle, const DeviceDispatch& dld) noexcept {
303 dld.vkDestroyRenderPass(device, handle, nullptr);
304}
305
306void Destroy(VkDevice device, VkSampler handle, const DeviceDispatch& dld) noexcept {
307 dld.vkDestroySampler(device, handle, nullptr);
308}
309
310void Destroy(VkDevice device, VkSwapchainKHR handle, const DeviceDispatch& dld) noexcept {
311 dld.vkDestroySwapchainKHR(device, handle, nullptr);
312}
313
314void Destroy(VkDevice device, VkSemaphore handle, const DeviceDispatch& dld) noexcept {
315 dld.vkDestroySemaphore(device, handle, nullptr);
316}
317
318void Destroy(VkDevice device, VkShaderModule handle, const DeviceDispatch& dld) noexcept {
319 dld.vkDestroyShaderModule(device, handle, nullptr);
320}
321
322void Destroy(VkInstance instance, VkDebugUtilsMessengerEXT handle,
323 const InstanceDispatch& dld) noexcept {
324 dld.vkDestroyDebugUtilsMessengerEXT(instance, handle, nullptr);
325}
326
327void Destroy(VkInstance instance, VkSurfaceKHR handle, const InstanceDispatch& dld) noexcept {
328 dld.vkDestroySurfaceKHR(instance, handle, nullptr);
329}
330
331VkResult Free(VkDevice device, VkDescriptorPool handle, Span<VkDescriptorSet> sets,
332 const DeviceDispatch& dld) noexcept {
333 return dld.vkFreeDescriptorSets(device, handle, sets.size(), sets.data());
334}
335
336VkResult Free(VkDevice device, VkCommandPool handle, Span<VkCommandBuffer> buffers,
337 const DeviceDispatch& dld) noexcept {
338 dld.vkFreeCommandBuffers(device, handle, buffers.size(), buffers.data());
339 return VK_SUCCESS;
340}
341
342Instance Instance::Create(Span<const char*> layers, Span<const char*> extensions,
343 InstanceDispatch& dld) noexcept {
344 VkApplicationInfo application_info;
345 application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
346 application_info.pNext = nullptr;
347 application_info.pApplicationName = "yuzu Emulator";
348 application_info.applicationVersion = VK_MAKE_VERSION(0, 1, 0);
349 application_info.pEngineName = "yuzu Emulator";
350 application_info.engineVersion = VK_MAKE_VERSION(0, 1, 0);
351 application_info.apiVersion = VK_API_VERSION_1_1;
352
353 VkInstanceCreateInfo ci;
354 ci.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
355 ci.pNext = nullptr;
356 ci.flags = 0;
357 ci.pApplicationInfo = &application_info;
358 ci.enabledLayerCount = layers.size();
359 ci.ppEnabledLayerNames = layers.data();
360 ci.enabledExtensionCount = extensions.size();
361 ci.ppEnabledExtensionNames = extensions.data();
362
363 VkInstance instance;
364 if (dld.vkCreateInstance(&ci, nullptr, &instance) != VK_SUCCESS) {
365 // Failed to create the instance.
366 return {};
367 }
368 if (!Proc(dld.vkDestroyInstance, dld, "vkDestroyInstance", instance)) {
369 // We successfully created an instance but the destroy function couldn't be loaded.
370 // This is a good moment to panic.
371 return {};
372 }
373
374 return Instance(instance, dld);
375}
376
377std::optional<std::vector<VkPhysicalDevice>> Instance::EnumeratePhysicalDevices() {
378 u32 num;
379 if (dld->vkEnumeratePhysicalDevices(handle, &num, nullptr) != VK_SUCCESS) {
380 return std::nullopt;
381 }
382 std::vector<VkPhysicalDevice> physical_devices(num);
383 if (dld->vkEnumeratePhysicalDevices(handle, &num, physical_devices.data()) != VK_SUCCESS) {
384 return std::nullopt;
385 }
386 return physical_devices;
387}
388
389DebugCallback Instance::TryCreateDebugCallback(
390 PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept {
391 VkDebugUtilsMessengerCreateInfoEXT ci;
392 ci.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
393 ci.pNext = nullptr;
394 ci.flags = 0;
395 ci.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
396 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
397 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
398 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
399 ci.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
400 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
401 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
402 ci.pfnUserCallback = callback;
403 ci.pUserData = nullptr;
404
405 VkDebugUtilsMessengerEXT messenger;
406 if (dld->vkCreateDebugUtilsMessengerEXT(handle, &ci, nullptr, &messenger) != VK_SUCCESS) {
407 return {};
408 }
409 return DebugCallback(messenger, handle, *dld);
410}
411
412std::vector<VkCheckpointDataNV> Queue::GetCheckpointDataNV(const DeviceDispatch& dld) const {
413 if (!dld.vkGetQueueCheckpointDataNV) {
414 return {};
415 }
416 u32 num;
417 dld.vkGetQueueCheckpointDataNV(queue, &num, nullptr);
418 std::vector<VkCheckpointDataNV> checkpoints(num);
419 dld.vkGetQueueCheckpointDataNV(queue, &num, checkpoints.data());
420 return checkpoints;
421}
422
423void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const {
424 Check(dld->vkBindBufferMemory(owner, handle, memory, offset));
425}
426
427void Image::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const {
428 Check(dld->vkBindImageMemory(owner, handle, memory, offset));
429}
430
431DescriptorSets DescriptorPool::Allocate(const VkDescriptorSetAllocateInfo& ai) const {
432 const std::size_t num = ai.descriptorSetCount;
433 std::unique_ptr sets = std::make_unique<VkDescriptorSet[]>(num);
434 switch (const VkResult result = dld->vkAllocateDescriptorSets(owner, &ai, sets.get())) {
435 case VK_SUCCESS:
436 return DescriptorSets(std::move(sets), num, owner, handle, *dld);
437 case VK_ERROR_OUT_OF_POOL_MEMORY:
438 return {};
439 default:
440 throw Exception(result);
441 }
442}
443
444CommandBuffers CommandPool::Allocate(std::size_t num_buffers, VkCommandBufferLevel level) const {
445 VkCommandBufferAllocateInfo ai;
446 ai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
447 ai.pNext = nullptr;
448 ai.commandPool = handle;
449 ai.level = level;
450 ai.commandBufferCount = static_cast<u32>(num_buffers);
451
452 std::unique_ptr buffers = std::make_unique<VkCommandBuffer[]>(num_buffers);
453 switch (const VkResult result = dld->vkAllocateCommandBuffers(owner, &ai, buffers.get())) {
454 case VK_SUCCESS:
455 return CommandBuffers(std::move(buffers), num_buffers, owner, handle, *dld);
456 case VK_ERROR_OUT_OF_POOL_MEMORY:
457 return {};
458 default:
459 throw Exception(result);
460 }
461}
462
463std::vector<VkImage> SwapchainKHR::GetImages() const {
464 u32 num;
465 Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, nullptr));
466 std::vector<VkImage> images(num);
467 Check(dld->vkGetSwapchainImagesKHR(owner, handle, &num, images.data()));
468 return images;
469}
470
471Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
472 Span<const char*> enabled_extensions,
473 const VkPhysicalDeviceFeatures2& enabled_features,
474 DeviceDispatch& dld) noexcept {
475 VkDeviceCreateInfo ci;
476 ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
477 ci.pNext = &enabled_features;
478 ci.flags = 0;
479 ci.queueCreateInfoCount = queues_ci.size();
480 ci.pQueueCreateInfos = queues_ci.data();
481 ci.enabledLayerCount = 0;
482 ci.ppEnabledLayerNames = nullptr;
483 ci.enabledExtensionCount = enabled_extensions.size();
484 ci.ppEnabledExtensionNames = enabled_extensions.data();
485 ci.pEnabledFeatures = nullptr;
486
487 VkDevice device;
488 if (dld.vkCreateDevice(physical_device, &ci, nullptr, &device) != VK_SUCCESS) {
489 return {};
490 }
491 Load(device, dld);
492 return Device(device, dld);
493}
494
495Queue Device::GetQueue(u32 family_index) const noexcept {
496 VkQueue queue;
497 dld->vkGetDeviceQueue(handle, family_index, 0, &queue);
498 return Queue(queue, *dld);
499}
500
501Buffer Device::CreateBuffer(const VkBufferCreateInfo& ci) const {
502 VkBuffer object;
503 Check(dld->vkCreateBuffer(handle, &ci, nullptr, &object));
504 return Buffer(object, handle, *dld);
505}
506
507BufferView Device::CreateBufferView(const VkBufferViewCreateInfo& ci) const {
508 VkBufferView object;
509 Check(dld->vkCreateBufferView(handle, &ci, nullptr, &object));
510 return BufferView(object, handle, *dld);
511}
512
513Image Device::CreateImage(const VkImageCreateInfo& ci) const {
514 VkImage object;
515 Check(dld->vkCreateImage(handle, &ci, nullptr, &object));
516 return Image(object, handle, *dld);
517}
518
519ImageView Device::CreateImageView(const VkImageViewCreateInfo& ci) const {
520 VkImageView object;
521 Check(dld->vkCreateImageView(handle, &ci, nullptr, &object));
522 return ImageView(object, handle, *dld);
523}
524
525Semaphore Device::CreateSemaphore() const {
526 VkSemaphoreCreateInfo ci;
527 ci.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
528 ci.pNext = nullptr;
529 ci.flags = 0;
530
531 VkSemaphore object;
532 Check(dld->vkCreateSemaphore(handle, &ci, nullptr, &object));
533 return Semaphore(object, handle, *dld);
534}
535
536Fence Device::CreateFence(const VkFenceCreateInfo& ci) const {
537 VkFence object;
538 Check(dld->vkCreateFence(handle, &ci, nullptr, &object));
539 return Fence(object, handle, *dld);
540}
541
542DescriptorPool Device::CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const {
543 VkDescriptorPool object;
544 Check(dld->vkCreateDescriptorPool(handle, &ci, nullptr, &object));
545 return DescriptorPool(object, handle, *dld);
546}
547
548RenderPass Device::CreateRenderPass(const VkRenderPassCreateInfo& ci) const {
549 VkRenderPass object;
550 Check(dld->vkCreateRenderPass(handle, &ci, nullptr, &object));
551 return RenderPass(object, handle, *dld);
552}
553
554DescriptorSetLayout Device::CreateDescriptorSetLayout(
555 const VkDescriptorSetLayoutCreateInfo& ci) const {
556 VkDescriptorSetLayout object;
557 Check(dld->vkCreateDescriptorSetLayout(handle, &ci, nullptr, &object));
558 return DescriptorSetLayout(object, handle, *dld);
559}
560
561PipelineLayout Device::CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const {
562 VkPipelineLayout object;
563 Check(dld->vkCreatePipelineLayout(handle, &ci, nullptr, &object));
564 return PipelineLayout(object, handle, *dld);
565}
566
567Pipeline Device::CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const {
568 VkPipeline object;
569 Check(dld->vkCreateGraphicsPipelines(handle, nullptr, 1, &ci, nullptr, &object));
570 return Pipeline(object, handle, *dld);
571}
572
573Pipeline Device::CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const {
574 VkPipeline object;
575 Check(dld->vkCreateComputePipelines(handle, nullptr, 1, &ci, nullptr, &object));
576 return Pipeline(object, handle, *dld);
577}
578
579Sampler Device::CreateSampler(const VkSamplerCreateInfo& ci) const {
580 VkSampler object;
581 Check(dld->vkCreateSampler(handle, &ci, nullptr, &object));
582 return Sampler(object, handle, *dld);
583}
584
585Framebuffer Device::CreateFramebuffer(const VkFramebufferCreateInfo& ci) const {
586 VkFramebuffer object;
587 Check(dld->vkCreateFramebuffer(handle, &ci, nullptr, &object));
588 return Framebuffer(object, handle, *dld);
589}
590
591CommandPool Device::CreateCommandPool(const VkCommandPoolCreateInfo& ci) const {
592 VkCommandPool object;
593 Check(dld->vkCreateCommandPool(handle, &ci, nullptr, &object));
594 return CommandPool(object, handle, *dld);
595}
596
597DescriptorUpdateTemplateKHR Device::CreateDescriptorUpdateTemplateKHR(
598 const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const {
599 VkDescriptorUpdateTemplateKHR object;
600 Check(dld->vkCreateDescriptorUpdateTemplateKHR(handle, &ci, nullptr, &object));
601 return DescriptorUpdateTemplateKHR(object, handle, *dld);
602}
603
604QueryPool Device::CreateQueryPool(const VkQueryPoolCreateInfo& ci) const {
605 VkQueryPool object;
606 Check(dld->vkCreateQueryPool(handle, &ci, nullptr, &object));
607 return QueryPool(object, handle, *dld);
608}
609
610ShaderModule Device::CreateShaderModule(const VkShaderModuleCreateInfo& ci) const {
611 VkShaderModule object;
612 Check(dld->vkCreateShaderModule(handle, &ci, nullptr, &object));
613 return ShaderModule(object, handle, *dld);
614}
615
616SwapchainKHR Device::CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const {
617 VkSwapchainKHR object;
618 Check(dld->vkCreateSwapchainKHR(handle, &ci, nullptr, &object));
619 return SwapchainKHR(object, handle, *dld);
620}
621
622DeviceMemory Device::TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept {
623 VkDeviceMemory memory;
624 if (dld->vkAllocateMemory(handle, &ai, nullptr, &memory) != VK_SUCCESS) {
625 return {};
626 }
627 return DeviceMemory(memory, handle, *dld);
628}
629
630DeviceMemory Device::AllocateMemory(const VkMemoryAllocateInfo& ai) const {
631 VkDeviceMemory memory;
632 Check(dld->vkAllocateMemory(handle, &ai, nullptr, &memory));
633 return DeviceMemory(memory, handle, *dld);
634}
635
636VkMemoryRequirements Device::GetBufferMemoryRequirements(VkBuffer buffer) const noexcept {
637 VkMemoryRequirements requirements;
638 dld->vkGetBufferMemoryRequirements(handle, buffer, &requirements);
639 return requirements;
640}
641
642VkMemoryRequirements Device::GetImageMemoryRequirements(VkImage image) const noexcept {
643 VkMemoryRequirements requirements;
644 dld->vkGetImageMemoryRequirements(handle, image, &requirements);
645 return requirements;
646}
647
648void Device::UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes,
649 Span<VkCopyDescriptorSet> copies) const noexcept {
650 dld->vkUpdateDescriptorSets(handle, writes.size(), writes.data(), copies.size(), copies.data());
651}
652
653VkPhysicalDeviceProperties PhysicalDevice::GetProperties() const noexcept {
654 VkPhysicalDeviceProperties properties;
655 dld->vkGetPhysicalDeviceProperties(physical_device, &properties);
656 return properties;
657}
658
659void PhysicalDevice::GetProperties2KHR(VkPhysicalDeviceProperties2KHR& properties) const noexcept {
660 dld->vkGetPhysicalDeviceProperties2KHR(physical_device, &properties);
661}
662
663VkPhysicalDeviceFeatures PhysicalDevice::GetFeatures() const noexcept {
664 VkPhysicalDeviceFeatures2KHR features2;
665 features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
666 features2.pNext = nullptr;
667 dld->vkGetPhysicalDeviceFeatures2KHR(physical_device, &features2);
668 return features2.features;
669}
670
671void PhysicalDevice::GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR& features) const noexcept {
672 dld->vkGetPhysicalDeviceFeatures2KHR(physical_device, &features);
673}
674
675VkFormatProperties PhysicalDevice::GetFormatProperties(VkFormat format) const noexcept {
676 VkFormatProperties properties;
677 dld->vkGetPhysicalDeviceFormatProperties(physical_device, format, &properties);
678 return properties;
679}
680
681std::vector<VkExtensionProperties> PhysicalDevice::EnumerateDeviceExtensionProperties() const {
682 u32 num;
683 dld->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &num, nullptr);
684 std::vector<VkExtensionProperties> properties(num);
685 dld->vkEnumerateDeviceExtensionProperties(physical_device, nullptr, &num, properties.data());
686 return properties;
687}
688
689std::vector<VkQueueFamilyProperties> PhysicalDevice::GetQueueFamilyProperties() const {
690 u32 num;
691 dld->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &num, nullptr);
692 std::vector<VkQueueFamilyProperties> properties(num);
693 dld->vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &num, properties.data());
694 return properties;
695}
696
697bool PhysicalDevice::GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR surface) const {
698 VkBool32 supported;
699 Check(dld->vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_index, surface,
700 &supported));
701 return supported == VK_TRUE;
702}
703
704VkSurfaceCapabilitiesKHR PhysicalDevice::GetSurfaceCapabilitiesKHR(VkSurfaceKHR surface) const
705 noexcept {
706 VkSurfaceCapabilitiesKHR capabilities;
707 Check(dld->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &capabilities));
708 return capabilities;
709}
710
711std::vector<VkSurfaceFormatKHR> PhysicalDevice::GetSurfaceFormatsKHR(VkSurfaceKHR surface) const {
712 u32 num;
713 Check(dld->vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &num, nullptr));
714 std::vector<VkSurfaceFormatKHR> formats(num);
715 Check(
716 dld->vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &num, formats.data()));
717 return formats;
718}
719
720std::vector<VkPresentModeKHR> PhysicalDevice::GetSurfacePresentModesKHR(
721 VkSurfaceKHR surface) const {
722 u32 num;
723 Check(dld->vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &num, nullptr));
724 std::vector<VkPresentModeKHR> modes(num);
725 Check(dld->vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &num,
726 modes.data()));
727 return modes;
728}
729
730VkPhysicalDeviceMemoryProperties PhysicalDevice::GetMemoryProperties() const noexcept {
731 VkPhysicalDeviceMemoryProperties properties;
732 dld->vkGetPhysicalDeviceMemoryProperties(physical_device, &properties);
733 return properties;
734}
735
736std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties(
737 const InstanceDispatch& dld) {
738 u32 num;
739 if (dld.vkEnumerateInstanceExtensionProperties(nullptr, &num, nullptr) != VK_SUCCESS) {
740 return std::nullopt;
741 }
742 std::vector<VkExtensionProperties> properties(num);
743 if (dld.vkEnumerateInstanceExtensionProperties(nullptr, &num, properties.data()) !=
744 VK_SUCCESS) {
745 return std::nullopt;
746 }
747 return properties;
748}
749
750} // namespace Vulkan::vk
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h
new file mode 100644
index 000000000..fb3657819
--- /dev/null
+++ b/src/video_core/renderer_vulkan/wrapper.h
@@ -0,0 +1,987 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <exception>
8#include <iterator>
9#include <limits>
10#include <memory>
11#include <optional>
12#include <type_traits>
13#include <utility>
14#include <vector>
15
16#define VK_NO_PROTOTYPES
17#include <vulkan/vulkan.h>
18
19#include "common/common_types.h"
20
21namespace Vulkan::vk {
22
23/**
24 * Span for Vulkan arrays.
25 * Based on std::span but optimized for array access instead of iterators.
26 * Size returns uint32_t instead of size_t to ease interaction with Vulkan functions.
27 */
28template <typename T>
29class Span {
30public:
31 using value_type = T;
32 using size_type = u32;
33 using difference_type = std::ptrdiff_t;
34 using reference = const T&;
35 using const_reference = const T&;
36 using pointer = const T*;
37 using const_pointer = const T*;
38 using iterator = const T*;
39 using const_iterator = const T*;
40
41 /// Construct an empty span.
42 constexpr Span() noexcept = default;
43
44 /// Construct a span from a single element.
45 constexpr Span(const T& value) noexcept : ptr{&value}, num{1} {}
46
47 /// Construct a span from a range.
48 template <typename Range>
49 // requires std::data(const Range&)
50 // requires std::size(const Range&)
51 constexpr Span(const Range& range) : ptr{std::data(range)}, num{std::size(range)} {}
52
53 /// Construct a span from a pointer and a size.
54 /// This is inteded for subranges.
55 constexpr Span(const T* ptr, std::size_t num) noexcept : ptr{ptr}, num{num} {}
56
57 /// Returns the data pointer by the span.
58 constexpr const T* data() const noexcept {
59 return ptr;
60 }
61
62 /// Returns the number of elements in the span.
63 /// @note Returns a 32 bits integer because most Vulkan functions expect this type.
64 constexpr u32 size() const noexcept {
65 return static_cast<u32>(num);
66 }
67
68 /// Returns true when the span is empty.
69 constexpr bool empty() const noexcept {
70 return num == 0;
71 }
72
73 /// Returns a reference to the element in the passed index.
74 /// @pre: index < size()
75 constexpr const T& operator[](std::size_t index) const noexcept {
76 return ptr[index];
77 }
78
79 /// Returns an iterator to the beginning of the span.
80 constexpr const T* begin() const noexcept {
81 return ptr;
82 }
83
84 /// Returns an iterator to the end of the span.
85 constexpr const T* end() const noexcept {
86 return ptr + num;
87 }
88
89 /// Returns an iterator to the beginning of the span.
90 constexpr const T* cbegin() const noexcept {
91 return ptr;
92 }
93
94 /// Returns an iterator to the end of the span.
95 constexpr const T* cend() const noexcept {
96 return ptr + num;
97 }
98
99private:
100 const T* ptr = nullptr;
101 std::size_t num = 0;
102};
103
104/// Vulkan exception generated from a VkResult.
105class Exception final : public std::exception {
106public:
107 /// Construct the exception with a result.
108 /// @pre result != VK_SUCCESS
109 explicit Exception(VkResult result_) : result{result_} {}
110 virtual ~Exception() = default;
111
112 const char* what() const noexcept override;
113
114private:
115 VkResult result;
116};
117
118/// Converts a VkResult enum into a rodata string
119const char* ToString(VkResult) noexcept;
120
121/// Throws a Vulkan exception if result is not success.
122inline void Check(VkResult result) {
123 if (result != VK_SUCCESS) {
124 throw Exception(result);
125 }
126}
127
128/// Throws a Vulkan exception if result is an error.
129/// @return result
130inline VkResult Filter(VkResult result) {
131 if (result < 0) {
132 throw Exception(result);
133 }
134 return result;
135}
136
137/// Table holding Vulkan instance function pointers.
138struct InstanceDispatch {
139 PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
140
141 PFN_vkCreateInstance vkCreateInstance;
142 PFN_vkDestroyInstance vkDestroyInstance;
143 PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
144
145 PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT;
146 PFN_vkCreateDevice vkCreateDevice;
147 PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT;
148 PFN_vkDestroyDevice vkDestroyDevice;
149 PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
150 PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
151 PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
152 PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
153 PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
154 PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties;
155 PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
156 PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
157 PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
158 PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
159 PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
160 PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
161 PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
162 PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR;
163 PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR;
164 PFN_vkQueuePresentKHR vkQueuePresentKHR;
165};
166
167/// Table holding Vulkan device function pointers.
168struct DeviceDispatch : public InstanceDispatch {
169 PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR;
170 PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
171 PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets;
172 PFN_vkAllocateMemory vkAllocateMemory;
173 PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
174 PFN_vkBindBufferMemory vkBindBufferMemory;
175 PFN_vkBindImageMemory vkBindImageMemory;
176 PFN_vkCmdBeginQuery vkCmdBeginQuery;
177 PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
178 PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT;
179 PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets;
180 PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer;
181 PFN_vkCmdBindPipeline vkCmdBindPipeline;
182 PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT;
183 PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
184 PFN_vkCmdBlitImage vkCmdBlitImage;
185 PFN_vkCmdClearAttachments vkCmdClearAttachments;
186 PFN_vkCmdCopyBuffer vkCmdCopyBuffer;
187 PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage;
188 PFN_vkCmdCopyImage vkCmdCopyImage;
189 PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer;
190 PFN_vkCmdDispatch vkCmdDispatch;
191 PFN_vkCmdDraw vkCmdDraw;
192 PFN_vkCmdDrawIndexed vkCmdDrawIndexed;
193 PFN_vkCmdEndQuery vkCmdEndQuery;
194 PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
195 PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT;
196 PFN_vkCmdFillBuffer vkCmdFillBuffer;
197 PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
198 PFN_vkCmdPushConstants vkCmdPushConstants;
199 PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants;
200 PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV;
201 PFN_vkCmdSetDepthBias vkCmdSetDepthBias;
202 PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds;
203 PFN_vkCmdSetScissor vkCmdSetScissor;
204 PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask;
205 PFN_vkCmdSetStencilReference vkCmdSetStencilReference;
206 PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask;
207 PFN_vkCmdSetViewport vkCmdSetViewport;
208 PFN_vkCreateBuffer vkCreateBuffer;
209 PFN_vkCreateBufferView vkCreateBufferView;
210 PFN_vkCreateCommandPool vkCreateCommandPool;
211 PFN_vkCreateComputePipelines vkCreateComputePipelines;
212 PFN_vkCreateDescriptorPool vkCreateDescriptorPool;
213 PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout;
214 PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR;
215 PFN_vkCreateFence vkCreateFence;
216 PFN_vkCreateFramebuffer vkCreateFramebuffer;
217 PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
218 PFN_vkCreateImage vkCreateImage;
219 PFN_vkCreateImageView vkCreateImageView;
220 PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
221 PFN_vkCreateQueryPool vkCreateQueryPool;
222 PFN_vkCreateRenderPass vkCreateRenderPass;
223 PFN_vkCreateSampler vkCreateSampler;
224 PFN_vkCreateSemaphore vkCreateSemaphore;
225 PFN_vkCreateShaderModule vkCreateShaderModule;
226 PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR;
227 PFN_vkDestroyBuffer vkDestroyBuffer;
228 PFN_vkDestroyBufferView vkDestroyBufferView;
229 PFN_vkDestroyCommandPool vkDestroyCommandPool;
230 PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool;
231 PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout;
232 PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR;
233 PFN_vkDestroyFence vkDestroyFence;
234 PFN_vkDestroyFramebuffer vkDestroyFramebuffer;
235 PFN_vkDestroyImage vkDestroyImage;
236 PFN_vkDestroyImageView vkDestroyImageView;
237 PFN_vkDestroyPipeline vkDestroyPipeline;
238 PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout;
239 PFN_vkDestroyQueryPool vkDestroyQueryPool;
240 PFN_vkDestroyRenderPass vkDestroyRenderPass;
241 PFN_vkDestroySampler vkDestroySampler;
242 PFN_vkDestroySemaphore vkDestroySemaphore;
243 PFN_vkDestroyShaderModule vkDestroyShaderModule;
244 PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR;
245 PFN_vkDeviceWaitIdle vkDeviceWaitIdle;
246 PFN_vkEndCommandBuffer vkEndCommandBuffer;
247 PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
248 PFN_vkFreeDescriptorSets vkFreeDescriptorSets;
249 PFN_vkFreeMemory vkFreeMemory;
250 PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
251 PFN_vkGetDeviceQueue vkGetDeviceQueue;
252 PFN_vkGetFenceStatus vkGetFenceStatus;
253 PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
254 PFN_vkGetQueryPoolResults vkGetQueryPoolResults;
255 PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV;
256 PFN_vkMapMemory vkMapMemory;
257 PFN_vkQueueSubmit vkQueueSubmit;
258 PFN_vkResetFences vkResetFences;
259 PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT;
260 PFN_vkUnmapMemory vkUnmapMemory;
261 PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR;
262 PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
263 PFN_vkWaitForFences vkWaitForFences;
264};
265
266/// Loads instance agnostic function pointers.
267/// @return True on success, false on error.
268bool Load(InstanceDispatch&) noexcept;
269
270/// Loads instance function pointers.
271/// @return True on success, false on error.
272bool Load(VkInstance, InstanceDispatch&) noexcept;
273
274void Destroy(VkInstance, const InstanceDispatch&) noexcept;
275void Destroy(VkDevice, const InstanceDispatch&) noexcept;
276
277void Destroy(VkDevice, VkBuffer, const DeviceDispatch&) noexcept;
278void Destroy(VkDevice, VkBufferView, const DeviceDispatch&) noexcept;
279void Destroy(VkDevice, VkCommandPool, const DeviceDispatch&) noexcept;
280void Destroy(VkDevice, VkDescriptorPool, const DeviceDispatch&) noexcept;
281void Destroy(VkDevice, VkDescriptorSetLayout, const DeviceDispatch&) noexcept;
282void Destroy(VkDevice, VkDescriptorUpdateTemplateKHR, const DeviceDispatch&) noexcept;
283void Destroy(VkDevice, VkDeviceMemory, const DeviceDispatch&) noexcept;
284void Destroy(VkDevice, VkFence, const DeviceDispatch&) noexcept;
285void Destroy(VkDevice, VkFramebuffer, const DeviceDispatch&) noexcept;
286void Destroy(VkDevice, VkImage, const DeviceDispatch&) noexcept;
287void Destroy(VkDevice, VkImageView, const DeviceDispatch&) noexcept;
288void Destroy(VkDevice, VkPipeline, const DeviceDispatch&) noexcept;
289void Destroy(VkDevice, VkPipelineLayout, const DeviceDispatch&) noexcept;
290void Destroy(VkDevice, VkQueryPool, const DeviceDispatch&) noexcept;
291void Destroy(VkDevice, VkRenderPass, const DeviceDispatch&) noexcept;
292void Destroy(VkDevice, VkSampler, const DeviceDispatch&) noexcept;
293void Destroy(VkDevice, VkSwapchainKHR, const DeviceDispatch&) noexcept;
294void Destroy(VkDevice, VkSemaphore, const DeviceDispatch&) noexcept;
295void Destroy(VkDevice, VkShaderModule, const DeviceDispatch&) noexcept;
296void Destroy(VkInstance, VkDebugUtilsMessengerEXT, const InstanceDispatch&) noexcept;
297void Destroy(VkInstance, VkSurfaceKHR, const InstanceDispatch&) noexcept;
298
299VkResult Free(VkDevice, VkDescriptorPool, Span<VkDescriptorSet>, const DeviceDispatch&) noexcept;
300VkResult Free(VkDevice, VkCommandPool, Span<VkCommandBuffer>, const DeviceDispatch&) noexcept;
301
302template <typename Type, typename OwnerType, typename Dispatch>
303class Handle;
304
305/// Handle with an owning type.
306/// Analogue to std::unique_ptr.
307template <typename Type, typename OwnerType, typename Dispatch>
308class Handle {
309public:
310 /// Construct a handle and hold it's ownership.
311 explicit Handle(Type handle_, OwnerType owner_, const Dispatch& dld_) noexcept
312 : handle{handle_}, owner{owner_}, dld{&dld_} {}
313
314 /// Construct an empty handle.
315 Handle() = default;
316
317 /// Copying Vulkan objects is not supported and will never be.
318 Handle(const Handle&) = delete;
319 Handle& operator=(const Handle&) = delete;
320
321 /// Construct a handle transfering the ownership from another handle.
322 Handle(Handle&& rhs) noexcept
323 : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, dld{rhs.dld} {}
324
325 /// Assign the current handle transfering the ownership from another handle.
326 /// Destroys any previously held object.
327 Handle& operator=(Handle&& rhs) noexcept {
328 Release();
329 handle = std::exchange(rhs.handle, nullptr);
330 owner = rhs.owner;
331 dld = rhs.dld;
332 return *this;
333 }
334
335 /// Destroys the current handle if it existed.
336 ~Handle() noexcept {
337 Release();
338 }
339
340 /// Destroys any held object.
341 void reset() noexcept {
342 Release();
343 handle = nullptr;
344 }
345
346 /// Returns the address of the held object.
347 /// Intended for Vulkan structures that expect a pointer to an array.
348 const Type* address() const noexcept {
349 return std::addressof(handle);
350 }
351
352 /// Returns the held Vulkan handle.
353 Type operator*() const noexcept {
354 return handle;
355 }
356
357 /// Returns true when there's a held object.
358 explicit operator bool() const noexcept {
359 return handle != nullptr;
360 }
361
362protected:
363 Type handle = nullptr;
364 OwnerType owner = nullptr;
365 const Dispatch* dld = nullptr;
366
367private:
368 /// Destroys the held object if it exists.
369 void Release() noexcept {
370 if (handle) {
371 Destroy(owner, handle, *dld);
372 }
373 }
374};
375
376/// Dummy type used to specify a handle has no owner.
377struct NoOwner {};
378
379/// Handle without an owning type.
380/// Analogue to std::unique_ptr
381template <typename Type, typename Dispatch>
382class Handle<Type, NoOwner, Dispatch> {
383public:
384 /// Construct a handle and hold it's ownership.
385 explicit Handle(Type handle_, const Dispatch& dld_) noexcept : handle{handle_}, dld{&dld_} {}
386
387 /// Construct an empty handle.
388 Handle() noexcept = default;
389
390 /// Copying Vulkan objects is not supported and will never be.
391 Handle(const Handle&) = delete;
392 Handle& operator=(const Handle&) = delete;
393
394 /// Construct a handle transfering ownership from another handle.
395 Handle(Handle&& rhs) noexcept : handle{std::exchange(rhs.handle, nullptr)}, dld{rhs.dld} {}
396
397 /// Assign the current handle transfering the ownership from another handle.
398 /// Destroys any previously held object.
399 Handle& operator=(Handle&& rhs) noexcept {
400 Release();
401 handle = std::exchange(rhs.handle, nullptr);
402 dld = rhs.dld;
403 return *this;
404 }
405
406 /// Destroys the current handle if it existed.
407 ~Handle() noexcept {
408 Release();
409 }
410
411 /// Destroys any held object.
412 void reset() noexcept {
413 Release();
414 handle = nullptr;
415 }
416
417 /// Returns the address of the held object.
418 /// Intended for Vulkan structures that expect a pointer to an array.
419 const Type* address() const noexcept {
420 return std::addressof(handle);
421 }
422
423 /// Returns the held Vulkan handle.
424 Type operator*() const noexcept {
425 return handle;
426 }
427
428 /// Returns true when there's a held object.
429 operator bool() const noexcept {
430 return handle != nullptr;
431 }
432
433protected:
434 Type handle = nullptr;
435 const Dispatch* dld = nullptr;
436
437private:
438 /// Destroys the held object if it exists.
439 void Release() noexcept {
440 if (handle) {
441 Destroy(handle, *dld);
442 }
443 }
444};
445
446/// Array of a pool allocation.
447/// Analogue to std::vector
448template <typename AllocationType, typename PoolType>
449class PoolAllocations {
450public:
451 /// Construct an empty allocation.
452 PoolAllocations() = default;
453
454 /// Construct an allocation. Errors are reported through IsOutOfPoolMemory().
455 explicit PoolAllocations(std::unique_ptr<AllocationType[]> allocations, std::size_t num,
456 VkDevice device, PoolType pool, const DeviceDispatch& dld) noexcept
457 : allocations{std::move(allocations)}, num{num}, device{device}, pool{pool}, dld{&dld} {}
458
459 /// Copying Vulkan allocations is not supported and will never be.
460 PoolAllocations(const PoolAllocations&) = delete;
461 PoolAllocations& operator=(const PoolAllocations&) = delete;
462
463 /// Construct an allocation transfering ownership from another allocation.
464 PoolAllocations(PoolAllocations&& rhs) noexcept
465 : allocations{std::move(rhs.allocations)}, num{rhs.num}, device{rhs.device}, pool{rhs.pool},
466 dld{rhs.dld} {}
467
468 /// Assign an allocation transfering ownership from another allocation.
469 /// Releases any previously held allocation.
470 PoolAllocations& operator=(PoolAllocations&& rhs) noexcept {
471 Release();
472 allocations = std::move(rhs.allocations);
473 num = rhs.num;
474 device = rhs.device;
475 pool = rhs.pool;
476 dld = rhs.dld;
477 return *this;
478 }
479
480 /// Destroys any held allocation.
481 ~PoolAllocations() {
482 Release();
483 }
484
485 /// Returns the number of allocations.
486 std::size_t size() const noexcept {
487 return num;
488 }
489
490 /// Returns a pointer to the array of allocations.
491 AllocationType const* data() const noexcept {
492 return allocations.get();
493 }
494
495 /// Returns the allocation in the specified index.
496 /// @pre index < size()
497 AllocationType operator[](std::size_t index) const noexcept {
498 return allocations[index];
499 }
500
501 /// True when a pool fails to construct.
502 bool IsOutOfPoolMemory() const noexcept {
503 return !device;
504 }
505
506private:
507 /// Destroys the held allocations if they exist.
508 void Release() noexcept {
509 if (!allocations) {
510 return;
511 }
512 const Span<AllocationType> span(allocations.get(), num);
513 const VkResult result = Free(device, pool, span, *dld);
514 // There's no way to report errors from a destructor.
515 if (result != VK_SUCCESS) {
516 std::terminate();
517 }
518 }
519
520 std::unique_ptr<AllocationType[]> allocations;
521 std::size_t num = 0;
522 VkDevice device = nullptr;
523 PoolType pool = nullptr;
524 const DeviceDispatch* dld = nullptr;
525};
526
527using BufferView = Handle<VkBufferView, VkDevice, DeviceDispatch>;
528using DebugCallback = Handle<VkDebugUtilsMessengerEXT, VkInstance, InstanceDispatch>;
529using DescriptorSetLayout = Handle<VkDescriptorSetLayout, VkDevice, DeviceDispatch>;
530using DescriptorUpdateTemplateKHR = Handle<VkDescriptorUpdateTemplateKHR, VkDevice, DeviceDispatch>;
531using Framebuffer = Handle<VkFramebuffer, VkDevice, DeviceDispatch>;
532using ImageView = Handle<VkImageView, VkDevice, DeviceDispatch>;
533using Pipeline = Handle<VkPipeline, VkDevice, DeviceDispatch>;
534using PipelineLayout = Handle<VkPipelineLayout, VkDevice, DeviceDispatch>;
535using QueryPool = Handle<VkQueryPool, VkDevice, DeviceDispatch>;
536using RenderPass = Handle<VkRenderPass, VkDevice, DeviceDispatch>;
537using Sampler = Handle<VkSampler, VkDevice, DeviceDispatch>;
538using Semaphore = Handle<VkSemaphore, VkDevice, DeviceDispatch>;
539using ShaderModule = Handle<VkShaderModule, VkDevice, DeviceDispatch>;
540using SurfaceKHR = Handle<VkSurfaceKHR, VkInstance, InstanceDispatch>;
541
542using DescriptorSets = PoolAllocations<VkDescriptorSet, VkDescriptorPool>;
543using CommandBuffers = PoolAllocations<VkCommandBuffer, VkCommandPool>;
544
545/// Vulkan instance owning handle.
546class Instance : public Handle<VkInstance, NoOwner, InstanceDispatch> {
547 using Handle<VkInstance, NoOwner, InstanceDispatch>::Handle;
548
549public:
550 /// Creates a Vulkan instance. Use "operator bool" for error handling.
551 static Instance Create(Span<const char*> layers, Span<const char*> extensions,
552 InstanceDispatch& dld) noexcept;
553
554 /// Enumerates physical devices.
555 /// @return Physical devices and an empty handle on failure.
556 std::optional<std::vector<VkPhysicalDevice>> EnumeratePhysicalDevices();
557
558 /// Tries to create a debug callback messenger. Returns an empty handle on failure.
559 DebugCallback TryCreateDebugCallback(PFN_vkDebugUtilsMessengerCallbackEXT callback) noexcept;
560};
561
562class Queue {
563public:
564 /// Construct an empty queue handle.
565 constexpr Queue() noexcept = default;
566
567 /// Construct a queue handle.
568 constexpr Queue(VkQueue queue, const DeviceDispatch& dld) noexcept : queue{queue}, dld{&dld} {}
569
570 /// Returns the checkpoint data.
571 /// @note Returns an empty vector when the function pointer is not present.
572 std::vector<VkCheckpointDataNV> GetCheckpointDataNV(const DeviceDispatch& dld) const;
573
574 void Submit(Span<VkSubmitInfo> submit_infos, VkFence fence) const {
575 Check(dld->vkQueueSubmit(queue, submit_infos.size(), submit_infos.data(), fence));
576 }
577
578 VkResult Present(const VkPresentInfoKHR& present_info) const noexcept {
579 return dld->vkQueuePresentKHR(queue, &present_info);
580 }
581
582private:
583 VkQueue queue = nullptr;
584 const DeviceDispatch* dld = nullptr;
585};
586
587class Buffer : public Handle<VkBuffer, VkDevice, DeviceDispatch> {
588 using Handle<VkBuffer, VkDevice, DeviceDispatch>::Handle;
589
590public:
591 /// Attaches a memory allocation.
592 void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
593};
594
595class Image : public Handle<VkImage, VkDevice, DeviceDispatch> {
596 using Handle<VkImage, VkDevice, DeviceDispatch>::Handle;
597
598public:
599 /// Attaches a memory allocation.
600 void BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const;
601};
602
603class DeviceMemory : public Handle<VkDeviceMemory, VkDevice, DeviceDispatch> {
604 using Handle<VkDeviceMemory, VkDevice, DeviceDispatch>::Handle;
605
606public:
607 u8* Map(VkDeviceSize offset, VkDeviceSize size) const {
608 void* data;
609 Check(dld->vkMapMemory(owner, handle, offset, size, 0, &data));
610 return static_cast<u8*>(data);
611 }
612
613 void Unmap() const noexcept {
614 dld->vkUnmapMemory(owner, handle);
615 }
616};
617
618class Fence : public Handle<VkFence, VkDevice, DeviceDispatch> {
619 using Handle<VkFence, VkDevice, DeviceDispatch>::Handle;
620
621public:
622 VkResult Wait(u64 timeout = std::numeric_limits<u64>::max()) const noexcept {
623 return dld->vkWaitForFences(owner, 1, &handle, true, timeout);
624 }
625
626 VkResult GetStatus() const noexcept {
627 return dld->vkGetFenceStatus(owner, handle);
628 }
629
630 void Reset() const {
631 Check(dld->vkResetFences(owner, 1, &handle));
632 }
633};
634
635class DescriptorPool : public Handle<VkDescriptorPool, VkDevice, DeviceDispatch> {
636 using Handle<VkDescriptorPool, VkDevice, DeviceDispatch>::Handle;
637
638public:
639 DescriptorSets Allocate(const VkDescriptorSetAllocateInfo& ai) const;
640};
641
642class CommandPool : public Handle<VkCommandPool, VkDevice, DeviceDispatch> {
643 using Handle<VkCommandPool, VkDevice, DeviceDispatch>::Handle;
644
645public:
646 CommandBuffers Allocate(std::size_t num_buffers,
647 VkCommandBufferLevel level = VK_COMMAND_BUFFER_LEVEL_PRIMARY) const;
648};
649
650class SwapchainKHR : public Handle<VkSwapchainKHR, VkDevice, DeviceDispatch> {
651 using Handle<VkSwapchainKHR, VkDevice, DeviceDispatch>::Handle;
652
653public:
654 std::vector<VkImage> GetImages() const;
655};
656
657class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> {
658 using Handle<VkDevice, NoOwner, DeviceDispatch>::Handle;
659
660public:
661 static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
662 Span<const char*> enabled_extensions,
663 const VkPhysicalDeviceFeatures2& enabled_features,
664 DeviceDispatch& dld) noexcept;
665
666 Queue GetQueue(u32 family_index) const noexcept;
667
668 Buffer CreateBuffer(const VkBufferCreateInfo& ci) const;
669
670 BufferView CreateBufferView(const VkBufferViewCreateInfo& ci) const;
671
672 Image CreateImage(const VkImageCreateInfo& ci) const;
673
674 ImageView CreateImageView(const VkImageViewCreateInfo& ci) const;
675
676 Semaphore CreateSemaphore() const;
677
678 Fence CreateFence(const VkFenceCreateInfo& ci) const;
679
680 DescriptorPool CreateDescriptorPool(const VkDescriptorPoolCreateInfo& ci) const;
681
682 RenderPass CreateRenderPass(const VkRenderPassCreateInfo& ci) const;
683
684 DescriptorSetLayout CreateDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo& ci) const;
685
686 PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const;
687
688 Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci) const;
689
690 Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci) const;
691
692 Sampler CreateSampler(const VkSamplerCreateInfo& ci) const;
693
694 Framebuffer CreateFramebuffer(const VkFramebufferCreateInfo& ci) const;
695
696 CommandPool CreateCommandPool(const VkCommandPoolCreateInfo& ci) const;
697
698 DescriptorUpdateTemplateKHR CreateDescriptorUpdateTemplateKHR(
699 const VkDescriptorUpdateTemplateCreateInfoKHR& ci) const;
700
701 QueryPool CreateQueryPool(const VkQueryPoolCreateInfo& ci) const;
702
703 ShaderModule CreateShaderModule(const VkShaderModuleCreateInfo& ci) const;
704
705 SwapchainKHR CreateSwapchainKHR(const VkSwapchainCreateInfoKHR& ci) const;
706
707 DeviceMemory TryAllocateMemory(const VkMemoryAllocateInfo& ai) const noexcept;
708
709 DeviceMemory AllocateMemory(const VkMemoryAllocateInfo& ai) const;
710
711 VkMemoryRequirements GetBufferMemoryRequirements(VkBuffer buffer) const noexcept;
712
713 VkMemoryRequirements GetImageMemoryRequirements(VkImage image) const noexcept;
714
715 void UpdateDescriptorSets(Span<VkWriteDescriptorSet> writes,
716 Span<VkCopyDescriptorSet> copies) const noexcept;
717
718 void UpdateDescriptorSet(VkDescriptorSet set, VkDescriptorUpdateTemplateKHR update_template,
719 const void* data) const noexcept {
720 dld->vkUpdateDescriptorSetWithTemplateKHR(handle, set, update_template, data);
721 }
722
723 VkResult AcquireNextImageKHR(VkSwapchainKHR swapchain, u64 timeout, VkSemaphore semaphore,
724 VkFence fence, u32* image_index) const noexcept {
725 return dld->vkAcquireNextImageKHR(handle, swapchain, timeout, semaphore, fence,
726 image_index);
727 }
728
729 VkResult WaitIdle() const noexcept {
730 return dld->vkDeviceWaitIdle(handle);
731 }
732
733 void ResetQueryPoolEXT(VkQueryPool query_pool, u32 first, u32 count) const noexcept {
734 dld->vkResetQueryPoolEXT(handle, query_pool, first, count);
735 }
736
737 void GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size,
738 void* data, VkDeviceSize stride, VkQueryResultFlags flags) const {
739 Check(dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride,
740 flags));
741 }
742
743 template <typename T>
744 T GetQueryResult(VkQueryPool query_pool, u32 first, VkQueryResultFlags flags) const {
745 static_assert(std::is_trivially_copyable_v<T>);
746 T value;
747 GetQueryResults(query_pool, first, 1, sizeof(T), &value, sizeof(T), flags);
748 return value;
749 }
750};
751
752class PhysicalDevice {
753public:
754 constexpr PhysicalDevice() noexcept = default;
755
756 constexpr PhysicalDevice(VkPhysicalDevice physical_device, const InstanceDispatch& dld) noexcept
757 : physical_device{physical_device}, dld{&dld} {}
758
759 constexpr operator VkPhysicalDevice() const noexcept {
760 return physical_device;
761 }
762
763 VkPhysicalDeviceProperties GetProperties() const noexcept;
764
765 void GetProperties2KHR(VkPhysicalDeviceProperties2KHR&) const noexcept;
766
767 VkPhysicalDeviceFeatures GetFeatures() const noexcept;
768
769 void GetFeatures2KHR(VkPhysicalDeviceFeatures2KHR&) const noexcept;
770
771 VkFormatProperties GetFormatProperties(VkFormat) const noexcept;
772
773 std::vector<VkExtensionProperties> EnumerateDeviceExtensionProperties() const;
774
775 std::vector<VkQueueFamilyProperties> GetQueueFamilyProperties() const;
776
777 bool GetSurfaceSupportKHR(u32 queue_family_index, VkSurfaceKHR) const;
778
779 VkSurfaceCapabilitiesKHR GetSurfaceCapabilitiesKHR(VkSurfaceKHR) const noexcept;
780
781 std::vector<VkSurfaceFormatKHR> GetSurfaceFormatsKHR(VkSurfaceKHR) const;
782
783 std::vector<VkPresentModeKHR> GetSurfacePresentModesKHR(VkSurfaceKHR) const;
784
785 VkPhysicalDeviceMemoryProperties GetMemoryProperties() const noexcept;
786
787private:
788 VkPhysicalDevice physical_device = nullptr;
789 const InstanceDispatch* dld = nullptr;
790};
791
792class CommandBuffer {
793public:
794 CommandBuffer() noexcept = default;
795
796 explicit CommandBuffer(VkCommandBuffer handle, const DeviceDispatch& dld) noexcept
797 : handle{handle}, dld{&dld} {}
798
799 const VkCommandBuffer* address() const noexcept {
800 return &handle;
801 }
802
803 void Begin(const VkCommandBufferBeginInfo& begin_info) const {
804 Check(dld->vkBeginCommandBuffer(handle, &begin_info));
805 }
806
807 void End() const {
808 Check(dld->vkEndCommandBuffer(handle));
809 }
810
811 void BeginRenderPass(const VkRenderPassBeginInfo& renderpass_bi,
812 VkSubpassContents contents) const noexcept {
813 dld->vkCmdBeginRenderPass(handle, &renderpass_bi, contents);
814 }
815
816 void EndRenderPass() const noexcept {
817 dld->vkCmdEndRenderPass(handle);
818 }
819
820 void BeginQuery(VkQueryPool query_pool, u32 query, VkQueryControlFlags flags) const noexcept {
821 dld->vkCmdBeginQuery(handle, query_pool, query, flags);
822 }
823
824 void EndQuery(VkQueryPool query_pool, u32 query) const noexcept {
825 dld->vkCmdEndQuery(handle, query_pool, query);
826 }
827
828 void BindDescriptorSets(VkPipelineBindPoint bind_point, VkPipelineLayout layout, u32 first,
829 Span<VkDescriptorSet> sets, Span<u32> dynamic_offsets) const noexcept {
830 dld->vkCmdBindDescriptorSets(handle, bind_point, layout, first, sets.size(), sets.data(),
831 dynamic_offsets.size(), dynamic_offsets.data());
832 }
833
834 void BindPipeline(VkPipelineBindPoint bind_point, VkPipeline pipeline) const noexcept {
835 dld->vkCmdBindPipeline(handle, bind_point, pipeline);
836 }
837
838 void BindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType index_type) const
839 noexcept {
840 dld->vkCmdBindIndexBuffer(handle, buffer, offset, index_type);
841 }
842
843 void BindVertexBuffers(u32 first, u32 count, const VkBuffer* buffers,
844 const VkDeviceSize* offsets) const noexcept {
845 dld->vkCmdBindVertexBuffers(handle, first, count, buffers, offsets);
846 }
847
848 void BindVertexBuffer(u32 binding, VkBuffer buffer, VkDeviceSize offset) const noexcept {
849 BindVertexBuffers(binding, 1, &buffer, &offset);
850 }
851
852 void Draw(u32 vertex_count, u32 instance_count, u32 first_vertex, u32 first_instance) const
853 noexcept {
854 dld->vkCmdDraw(handle, vertex_count, instance_count, first_vertex, first_instance);
855 }
856
857 void DrawIndexed(u32 index_count, u32 instance_count, u32 first_index, u32 vertex_offset,
858 u32 first_instance) const noexcept {
859 dld->vkCmdDrawIndexed(handle, index_count, instance_count, first_index, vertex_offset,
860 first_instance);
861 }
862
863 void ClearAttachments(Span<VkClearAttachment> attachments, Span<VkClearRect> rects) const
864 noexcept {
865 dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(),
866 rects.data());
867 }
868
869 void BlitImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image,
870 VkImageLayout dst_layout, Span<VkImageBlit> regions, VkFilter filter) const
871 noexcept {
872 dld->vkCmdBlitImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(),
873 regions.data(), filter);
874 }
875
876 void Dispatch(u32 x, u32 y, u32 z) const noexcept {
877 dld->vkCmdDispatch(handle, x, y, z);
878 }
879
880 void PipelineBarrier(VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
881 VkDependencyFlags dependency_flags, Span<VkMemoryBarrier> memory_barriers,
882 Span<VkBufferMemoryBarrier> buffer_barriers,
883 Span<VkImageMemoryBarrier> image_barriers) const noexcept {
884 dld->vkCmdPipelineBarrier(handle, src_stage_mask, dst_stage_mask, dependency_flags,
885 memory_barriers.size(), memory_barriers.data(),
886 buffer_barriers.size(), buffer_barriers.data(),
887 image_barriers.size(), image_barriers.data());
888 }
889
890 void CopyBufferToImage(VkBuffer src_buffer, VkImage dst_image, VkImageLayout dst_image_layout,
891 Span<VkBufferImageCopy> regions) const noexcept {
892 dld->vkCmdCopyBufferToImage(handle, src_buffer, dst_image, dst_image_layout, regions.size(),
893 regions.data());
894 }
895
896 void CopyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer, Span<VkBufferCopy> regions) const
897 noexcept {
898 dld->vkCmdCopyBuffer(handle, src_buffer, dst_buffer, regions.size(), regions.data());
899 }
900
901 void CopyImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image,
902 VkImageLayout dst_layout, Span<VkImageCopy> regions) const noexcept {
903 dld->vkCmdCopyImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(),
904 regions.data());
905 }
906
907 void CopyImageToBuffer(VkImage src_image, VkImageLayout src_layout, VkBuffer dst_buffer,
908 Span<VkBufferImageCopy> regions) const noexcept {
909 dld->vkCmdCopyImageToBuffer(handle, src_image, src_layout, dst_buffer, regions.size(),
910 regions.data());
911 }
912
913 void FillBuffer(VkBuffer dst_buffer, VkDeviceSize dst_offset, VkDeviceSize size, u32 data) const
914 noexcept {
915 dld->vkCmdFillBuffer(handle, dst_buffer, dst_offset, size, data);
916 }
917
918 void PushConstants(VkPipelineLayout layout, VkShaderStageFlags flags, u32 offset, u32 size,
919 const void* values) const noexcept {
920 dld->vkCmdPushConstants(handle, layout, flags, offset, size, values);
921 }
922
923 void SetCheckpointNV(const void* checkpoint_marker) const noexcept {
924 dld->vkCmdSetCheckpointNV(handle, checkpoint_marker);
925 }
926
927 void SetViewport(u32 first, Span<VkViewport> viewports) const noexcept {
928 dld->vkCmdSetViewport(handle, first, viewports.size(), viewports.data());
929 }
930
931 void SetScissor(u32 first, Span<VkRect2D> scissors) const noexcept {
932 dld->vkCmdSetScissor(handle, first, scissors.size(), scissors.data());
933 }
934
935 void SetBlendConstants(const float blend_constants[4]) const noexcept {
936 dld->vkCmdSetBlendConstants(handle, blend_constants);
937 }
938
939 void SetStencilCompareMask(VkStencilFaceFlags face_mask, u32 compare_mask) const noexcept {
940 dld->vkCmdSetStencilCompareMask(handle, face_mask, compare_mask);
941 }
942
943 void SetStencilReference(VkStencilFaceFlags face_mask, u32 reference) const noexcept {
944 dld->vkCmdSetStencilReference(handle, face_mask, reference);
945 }
946
947 void SetStencilWriteMask(VkStencilFaceFlags face_mask, u32 write_mask) const noexcept {
948 dld->vkCmdSetStencilWriteMask(handle, face_mask, write_mask);
949 }
950
951 void SetDepthBias(float constant_factor, float clamp, float slope_factor) const noexcept {
952 dld->vkCmdSetDepthBias(handle, constant_factor, clamp, slope_factor);
953 }
954
955 void SetDepthBounds(float min_depth_bounds, float max_depth_bounds) const noexcept {
956 dld->vkCmdSetDepthBounds(handle, min_depth_bounds, max_depth_bounds);
957 }
958
959 void BindTransformFeedbackBuffersEXT(u32 first, u32 count, const VkBuffer* buffers,
960 const VkDeviceSize* offsets,
961 const VkDeviceSize* sizes) const noexcept {
962 dld->vkCmdBindTransformFeedbackBuffersEXT(handle, first, count, buffers, offsets, sizes);
963 }
964
965 void BeginTransformFeedbackEXT(u32 first_counter_buffer, u32 counter_buffers_count,
966 const VkBuffer* counter_buffers,
967 const VkDeviceSize* counter_buffer_offsets) const noexcept {
968 dld->vkCmdBeginTransformFeedbackEXT(handle, first_counter_buffer, counter_buffers_count,
969 counter_buffers, counter_buffer_offsets);
970 }
971
972 void EndTransformFeedbackEXT(u32 first_counter_buffer, u32 counter_buffers_count,
973 const VkBuffer* counter_buffers,
974 const VkDeviceSize* counter_buffer_offsets) const noexcept {
975 dld->vkCmdEndTransformFeedbackEXT(handle, first_counter_buffer, counter_buffers_count,
976 counter_buffers, counter_buffer_offsets);
977 }
978
979private:
980 VkCommandBuffer handle;
981 const DeviceDispatch* dld;
982};
983
984std::optional<std::vector<VkExtensionProperties>> EnumerateInstanceExtensionProperties(
985 const InstanceDispatch& dld);
986
987} // namespace Vulkan::vk
diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp
index 2fe787d6f..0f4c3103a 100644
--- a/src/video_core/shader/decode/arithmetic_integer.cpp
+++ b/src/video_core/shader/decode/arithmetic_integer.cpp
@@ -235,34 +235,30 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) {
235 case OpCode::Id::LEA_IMM: 235 case OpCode::Id::LEA_IMM:
236 case OpCode::Id::LEA_RZ: 236 case OpCode::Id::LEA_RZ:
237 case OpCode::Id::LEA_HI: { 237 case OpCode::Id::LEA_HI: {
238 const auto [op_a, op_b, op_c] = [&]() -> std::tuple<Node, Node, Node> { 238 auto [op_a, op_b, op_c] = [&]() -> std::tuple<Node, Node, Node> {
239 switch (opcode->get().GetId()) { 239 switch (opcode->get().GetId()) {
240 case OpCode::Id::LEA_R2: { 240 case OpCode::Id::LEA_R2: {
241 return {GetRegister(instr.gpr20), GetRegister(instr.gpr39), 241 return {GetRegister(instr.gpr20), GetRegister(instr.gpr39),
242 Immediate(static_cast<u32>(instr.lea.r2.entry_a))}; 242 Immediate(static_cast<u32>(instr.lea.r2.entry_a))};
243 } 243 }
244
245 case OpCode::Id::LEA_R1: { 244 case OpCode::Id::LEA_R1: {
246 const bool neg = instr.lea.r1.neg != 0; 245 const bool neg = instr.lea.r1.neg != 0;
247 return {GetOperandAbsNegInteger(GetRegister(instr.gpr8), false, neg, true), 246 return {GetOperandAbsNegInteger(GetRegister(instr.gpr8), false, neg, true),
248 GetRegister(instr.gpr20), 247 GetRegister(instr.gpr20),
249 Immediate(static_cast<u32>(instr.lea.r1.entry_a))}; 248 Immediate(static_cast<u32>(instr.lea.r1.entry_a))};
250 } 249 }
251
252 case OpCode::Id::LEA_IMM: { 250 case OpCode::Id::LEA_IMM: {
253 const bool neg = instr.lea.imm.neg != 0; 251 const bool neg = instr.lea.imm.neg != 0;
254 return {Immediate(static_cast<u32>(instr.lea.imm.entry_a)), 252 return {Immediate(static_cast<u32>(instr.lea.imm.entry_a)),
255 GetOperandAbsNegInteger(GetRegister(instr.gpr8), false, neg, true), 253 GetOperandAbsNegInteger(GetRegister(instr.gpr8), false, neg, true),
256 Immediate(static_cast<u32>(instr.lea.imm.entry_b))}; 254 Immediate(static_cast<u32>(instr.lea.imm.entry_b))};
257 } 255 }
258
259 case OpCode::Id::LEA_RZ: { 256 case OpCode::Id::LEA_RZ: {
260 const bool neg = instr.lea.rz.neg != 0; 257 const bool neg = instr.lea.rz.neg != 0;
261 return {GetConstBuffer(instr.lea.rz.cb_index, instr.lea.rz.cb_offset), 258 return {GetConstBuffer(instr.lea.rz.cb_index, instr.lea.rz.cb_offset),
262 GetOperandAbsNegInteger(GetRegister(instr.gpr8), false, neg, true), 259 GetOperandAbsNegInteger(GetRegister(instr.gpr8), false, neg, true),
263 Immediate(static_cast<u32>(instr.lea.rz.entry_a))}; 260 Immediate(static_cast<u32>(instr.lea.rz.entry_a))};
264 } 261 }
265
266 case OpCode::Id::LEA_HI: 262 case OpCode::Id::LEA_HI:
267 default: 263 default:
268 UNIMPLEMENTED_MSG("Unhandled LEA subinstruction: {}", opcode->get().GetName()); 264 UNIMPLEMENTED_MSG("Unhandled LEA subinstruction: {}", opcode->get().GetName());
@@ -275,12 +271,9 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) {
275 UNIMPLEMENTED_IF_MSG(instr.lea.pred48 != static_cast<u64>(Pred::UnusedIndex), 271 UNIMPLEMENTED_IF_MSG(instr.lea.pred48 != static_cast<u64>(Pred::UnusedIndex),
276 "Unhandled LEA Predicate"); 272 "Unhandled LEA Predicate");
277 273
278 const Node shifted_c = 274 Node value = Operation(OperationCode::ILogicalShiftLeft, std::move(op_a), std::move(op_c));
279 Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, Immediate(1), op_c); 275 value = Operation(OperationCode::IAdd, std::move(op_b), std::move(value));
280 const Node mul_bc = Operation(OperationCode::IMul, NO_PRECISE, op_b, shifted_c); 276 SetRegister(bb, instr.gpr0, std::move(value));
281 const Node value = Operation(OperationCode::IAdd, NO_PRECISE, op_a, mul_bc);
282
283 SetRegister(bb, instr.gpr0, value);
284 277
285 break; 278 break;
286 } 279 }
diff --git a/src/video_core/shader/decode/conversion.cpp b/src/video_core/shader/decode/conversion.cpp
index 6ead42070..c72690b2b 100644
--- a/src/video_core/shader/decode/conversion.cpp
+++ b/src/video_core/shader/decode/conversion.cpp
@@ -138,18 +138,23 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) {
138 138
139 value = GetOperandAbsNegFloat(value, instr.conversion.abs_a, instr.conversion.negate_a); 139 value = GetOperandAbsNegFloat(value, instr.conversion.abs_a, instr.conversion.negate_a);
140 140
141 value = [&]() { 141 value = [&] {
142 if (instr.conversion.src_size != instr.conversion.dst_size) {
143 // Rounding operations only matter when the source and destination conversion size
144 // is the same.
145 return value;
146 }
142 switch (instr.conversion.f2f.GetRoundingMode()) { 147 switch (instr.conversion.f2f.GetRoundingMode()) {
143 case Tegra::Shader::F2fRoundingOp::None: 148 case Tegra::Shader::F2fRoundingOp::None:
144 return value; 149 return value;
145 case Tegra::Shader::F2fRoundingOp::Round: 150 case Tegra::Shader::F2fRoundingOp::Round:
146 return Operation(OperationCode::FRoundEven, PRECISE, value); 151 return Operation(OperationCode::FRoundEven, value);
147 case Tegra::Shader::F2fRoundingOp::Floor: 152 case Tegra::Shader::F2fRoundingOp::Floor:
148 return Operation(OperationCode::FFloor, PRECISE, value); 153 return Operation(OperationCode::FFloor, value);
149 case Tegra::Shader::F2fRoundingOp::Ceil: 154 case Tegra::Shader::F2fRoundingOp::Ceil:
150 return Operation(OperationCode::FCeil, PRECISE, value); 155 return Operation(OperationCode::FCeil, value);
151 case Tegra::Shader::F2fRoundingOp::Trunc: 156 case Tegra::Shader::F2fRoundingOp::Trunc:
152 return Operation(OperationCode::FTrunc, PRECISE, value); 157 return Operation(OperationCode::FTrunc, value);
153 default: 158 default:
154 UNIMPLEMENTED_MSG("Unimplemented F2F rounding mode {}", 159 UNIMPLEMENTED_MSG("Unimplemented F2F rounding mode {}",
155 static_cast<u32>(instr.conversion.f2f.rounding.Value())); 160 static_cast<u32>(instr.conversion.f2f.rounding.Value()));
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp
index b5fbc4d58..28a49addd 100644
--- a/src/video_core/shader/decode/memory.cpp
+++ b/src/video_core/shader/decode/memory.cpp
@@ -19,7 +19,6 @@ namespace VideoCommon::Shader {
19using Tegra::Shader::AtomicOp; 19using Tegra::Shader::AtomicOp;
20using Tegra::Shader::AtomicType; 20using Tegra::Shader::AtomicType;
21using Tegra::Shader::Attribute; 21using Tegra::Shader::Attribute;
22using Tegra::Shader::GlobalAtomicOp;
23using Tegra::Shader::GlobalAtomicType; 22using Tegra::Shader::GlobalAtomicType;
24using Tegra::Shader::Instruction; 23using Tegra::Shader::Instruction;
25using Tegra::Shader::OpCode; 24using Tegra::Shader::OpCode;
@@ -28,6 +27,28 @@ using Tegra::Shader::StoreType;
28 27
29namespace { 28namespace {
30 29
30Node GetAtomOperation(AtomicOp op, bool is_signed, Node memory, Node data) {
31 const OperationCode operation_code = [op] {
32 switch (op) {
33 case AtomicOp::Add:
34 return OperationCode::AtomicIAdd;
35 case AtomicOp::Min:
36 return OperationCode::AtomicIMin;
37 case AtomicOp::Max:
38 return OperationCode::AtomicIMax;
39 case AtomicOp::And:
40 return OperationCode::AtomicIAnd;
41 case AtomicOp::Or:
42 return OperationCode::AtomicIOr;
43 case AtomicOp::Xor:
44 return OperationCode::AtomicIXor;
45 case AtomicOp::Exch:
46 return OperationCode::AtomicIExchange;
47 }
48 }();
49 return SignedOperation(operation_code, is_signed, std::move(memory), std::move(data));
50}
51
31bool IsUnaligned(Tegra::Shader::UniformType uniform_type) { 52bool IsUnaligned(Tegra::Shader::UniformType uniform_type) {
32 return uniform_type == Tegra::Shader::UniformType::UnsignedByte || 53 return uniform_type == Tegra::Shader::UniformType::UnsignedByte ||
33 uniform_type == Tegra::Shader::UniformType::UnsignedShort; 54 uniform_type == Tegra::Shader::UniformType::UnsignedShort;
@@ -363,10 +384,13 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
363 break; 384 break;
364 } 385 }
365 case OpCode::Id::ATOM: { 386 case OpCode::Id::ATOM: {
366 UNIMPLEMENTED_IF_MSG(instr.atom.operation != GlobalAtomicOp::Add, "operation={}", 387 UNIMPLEMENTED_IF_MSG(instr.atom.operation == AtomicOp::Inc ||
367 static_cast<int>(instr.atom.operation.Value())); 388 instr.atom.operation == AtomicOp::Dec ||
368 UNIMPLEMENTED_IF_MSG(instr.atom.type != GlobalAtomicType::S32, "type={}", 389 instr.atom.operation == AtomicOp::SafeAdd,
369 static_cast<int>(instr.atom.type.Value())); 390 "operation={}", static_cast<int>(instr.atom.operation.Value()));
391 UNIMPLEMENTED_IF_MSG(instr.atom.type == GlobalAtomicType::S64 ||
392 instr.atom.type == GlobalAtomicType::U64,
393 "type={}", static_cast<int>(instr.atom.type.Value()));
370 394
371 const auto [real_address, base_address, descriptor] = 395 const auto [real_address, base_address, descriptor] =
372 TrackGlobalMemory(bb, instr, true, true); 396 TrackGlobalMemory(bb, instr, true, true);
@@ -375,25 +399,29 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
375 break; 399 break;
376 } 400 }
377 401
402 const bool is_signed =
403 instr.atoms.type == AtomicType::S32 || instr.atoms.type == AtomicType::S64;
378 Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor); 404 Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
379 Node value = Operation(OperationCode::AtomicAdd, std::move(gmem), GetRegister(instr.gpr20)); 405 Node value = GetAtomOperation(static_cast<AtomicOp>(instr.atom.operation), is_signed, gmem,
406 GetRegister(instr.gpr20));
380 SetRegister(bb, instr.gpr0, std::move(value)); 407 SetRegister(bb, instr.gpr0, std::move(value));
381 break; 408 break;
382 } 409 }
383 case OpCode::Id::ATOMS: { 410 case OpCode::Id::ATOMS: {
384 UNIMPLEMENTED_IF_MSG(instr.atoms.operation != AtomicOp::Add, "operation={}", 411 UNIMPLEMENTED_IF_MSG(instr.atoms.operation == AtomicOp::Inc ||
385 static_cast<int>(instr.atoms.operation.Value())); 412 instr.atoms.operation == AtomicOp::Dec,
386 UNIMPLEMENTED_IF_MSG(instr.atoms.type != AtomicType::U32, "type={}", 413 "operation={}", static_cast<int>(instr.atoms.operation.Value()));
387 static_cast<int>(instr.atoms.type.Value())); 414 UNIMPLEMENTED_IF_MSG(instr.atoms.type == AtomicType::S64 ||
388 415 instr.atoms.type == AtomicType::U64,
416 "type={}", static_cast<int>(instr.atoms.type.Value()));
417 const bool is_signed =
418 instr.atoms.type == AtomicType::S32 || instr.atoms.type == AtomicType::S64;
389 const s32 offset = instr.atoms.GetImmediateOffset(); 419 const s32 offset = instr.atoms.GetImmediateOffset();
390 Node address = GetRegister(instr.gpr8); 420 Node address = GetRegister(instr.gpr8);
391 address = Operation(OperationCode::IAdd, std::move(address), Immediate(offset)); 421 address = Operation(OperationCode::IAdd, std::move(address), Immediate(offset));
392 422 Node value =
393 Node memory = GetSharedMemory(std::move(address)); 423 GetAtomOperation(static_cast<AtomicOp>(instr.atoms.operation), is_signed,
394 Node data = GetRegister(instr.gpr20); 424 GetSharedMemory(std::move(address)), GetRegister(instr.gpr20));
395
396 Node value = Operation(OperationCode::AtomicAdd, std::move(memory), std::move(data));
397 SetRegister(bb, instr.gpr0, std::move(value)); 425 SetRegister(bb, instr.gpr0, std::move(value));
398 break; 426 break;
399 } 427 }
diff --git a/src/video_core/shader/decode/xmad.cpp b/src/video_core/shader/decode/xmad.cpp
index fbd7e9a17..6191ffba1 100644
--- a/src/video_core/shader/decode/xmad.cpp
+++ b/src/video_core/shader/decode/xmad.cpp
@@ -31,7 +31,7 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
31 const bool is_signed_b = instr.xmad.sign_b == 1; 31 const bool is_signed_b = instr.xmad.sign_b == 1;
32 const bool is_signed_c = is_signed_a; 32 const bool is_signed_c = is_signed_a;
33 33
34 auto [is_merge, is_psl, is_high_b, mode, op_b, 34 auto [is_merge, is_psl, is_high_b, mode, op_b_binding,
35 op_c] = [&]() -> std::tuple<bool, bool, bool, Tegra::Shader::XmadMode, Node, Node> { 35 op_c] = [&]() -> std::tuple<bool, bool, bool, Tegra::Shader::XmadMode, Node, Node> {
36 switch (opcode->get().GetId()) { 36 switch (opcode->get().GetId()) {
37 case OpCode::Id::XMAD_CR: 37 case OpCode::Id::XMAD_CR:
@@ -67,9 +67,10 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
67 op_a = SignedOperation(OperationCode::IBitfieldExtract, is_signed_a, std::move(op_a), 67 op_a = SignedOperation(OperationCode::IBitfieldExtract, is_signed_a, std::move(op_a),
68 instr.xmad.high_a ? Immediate(16) : Immediate(0), Immediate(16)); 68 instr.xmad.high_a ? Immediate(16) : Immediate(0), Immediate(16));
69 69
70 const Node original_b = op_b; 70 const Node original_b = op_b_binding;
71 op_b = SignedOperation(OperationCode::IBitfieldExtract, is_signed_b, std::move(op_b), 71 const Node op_b =
72 is_high_b ? Immediate(16) : Immediate(0), Immediate(16)); 72 SignedOperation(OperationCode::IBitfieldExtract, is_signed_b, std::move(op_b_binding),
73 is_high_b ? Immediate(16) : Immediate(0), Immediate(16));
73 74
74 // we already check sign_a and sign_b is difference or not before so just use one in here. 75 // we already check sign_a and sign_b is difference or not before so just use one in here.
75 Node product = SignedOperation(OperationCode::IMul, is_signed_a, op_a, op_b); 76 Node product = SignedOperation(OperationCode::IMul, is_signed_a, op_a, op_b);
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h
index a1828546e..5fcc9da60 100644
--- a/src/video_core/shader/node.h
+++ b/src/video_core/shader/node.h
@@ -162,7 +162,21 @@ enum class OperationCode {
162 AtomicImageXor, /// (MetaImage, int[N] coords) -> void 162 AtomicImageXor, /// (MetaImage, int[N] coords) -> void
163 AtomicImageExchange, /// (MetaImage, int[N] coords) -> void 163 AtomicImageExchange, /// (MetaImage, int[N] coords) -> void
164 164
165 AtomicAdd, /// (memory, {u}int) -> {u}int 165 AtomicUExchange, /// (memory, uint) -> uint
166 AtomicUAdd, /// (memory, uint) -> uint
167 AtomicUMin, /// (memory, uint) -> uint
168 AtomicUMax, /// (memory, uint) -> uint
169 AtomicUAnd, /// (memory, uint) -> uint
170 AtomicUOr, /// (memory, uint) -> uint
171 AtomicUXor, /// (memory, uint) -> uint
172
173 AtomicIExchange, /// (memory, int) -> int
174 AtomicIAdd, /// (memory, int) -> int
175 AtomicIMin, /// (memory, int) -> int
176 AtomicIMax, /// (memory, int) -> int
177 AtomicIAnd, /// (memory, int) -> int
178 AtomicIOr, /// (memory, int) -> int
179 AtomicIXor, /// (memory, int) -> int
166 180
167 Branch, /// (uint branch_target) -> void 181 Branch, /// (uint branch_target) -> void
168 BranchIndirect, /// (uint branch_target) -> void 182 BranchIndirect, /// (uint branch_target) -> void
diff --git a/src/video_core/shader/node_helper.cpp b/src/video_core/shader/node_helper.cpp
index 76c56abb5..7bf4ff387 100644
--- a/src/video_core/shader/node_helper.cpp
+++ b/src/video_core/shader/node_helper.cpp
@@ -86,6 +86,20 @@ OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed)
86 return OperationCode::LogicalUNotEqual; 86 return OperationCode::LogicalUNotEqual;
87 case OperationCode::LogicalIGreaterEqual: 87 case OperationCode::LogicalIGreaterEqual:
88 return OperationCode::LogicalUGreaterEqual; 88 return OperationCode::LogicalUGreaterEqual;
89 case OperationCode::AtomicIExchange:
90 return OperationCode::AtomicUExchange;
91 case OperationCode::AtomicIAdd:
92 return OperationCode::AtomicUAdd;
93 case OperationCode::AtomicIMin:
94 return OperationCode::AtomicUMin;
95 case OperationCode::AtomicIMax:
96 return OperationCode::AtomicUMax;
97 case OperationCode::AtomicIAnd:
98 return OperationCode::AtomicUAnd;
99 case OperationCode::AtomicIOr:
100 return OperationCode::AtomicUOr;
101 case OperationCode::AtomicIXor:
102 return OperationCode::AtomicUXor;
89 case OperationCode::INegate: 103 case OperationCode::INegate:
90 UNREACHABLE_MSG("Can't negate an unsigned integer"); 104 UNREACHABLE_MSG("Can't negate an unsigned integer");
91 return {}; 105 return {};
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp
index 425927777..baf7188d2 100644
--- a/src/video_core/shader/shader_ir.cpp
+++ b/src/video_core/shader/shader_ir.cpp
@@ -96,6 +96,7 @@ Node ShaderIR::GetPredicate(bool immediate) {
96} 96}
97 97
98Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, Node buffer) { 98Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, Node buffer) {
99 MarkAttributeUsage(index, element);
99 used_input_attributes.emplace(index); 100 used_input_attributes.emplace(index);
100 return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer)); 101 return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer));
101} 102}
@@ -106,42 +107,8 @@ Node ShaderIR::GetPhysicalInputAttribute(Tegra::Shader::Register physical_addres
106} 107}
107 108
108Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) { 109Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) {
109 if (index == Attribute::Index::LayerViewportPointSize) { 110 MarkAttributeUsage(index, element);
110 switch (element) {
111 case 0:
112 UNIMPLEMENTED();
113 break;
114 case 1:
115 uses_layer = true;
116 break;
117 case 2:
118 uses_viewport_index = true;
119 break;
120 case 3:
121 uses_point_size = true;
122 break;
123 }
124 }
125 if (index == Attribute::Index::TessCoordInstanceIDVertexID) {
126 switch (element) {
127 case 2:
128 uses_instance_id = true;
129 break;
130 case 3:
131 uses_vertex_id = true;
132 break;
133 default:
134 break;
135 }
136 }
137 if (index == Attribute::Index::ClipDistances0123 ||
138 index == Attribute::Index::ClipDistances4567) {
139 const auto clip_index =
140 static_cast<u32>((index == Attribute::Index::ClipDistances4567 ? 1 : 0) + element);
141 used_clip_distances.at(clip_index) = true;
142 }
143 used_output_attributes.insert(index); 111 used_output_attributes.insert(index);
144
145 return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer)); 112 return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer));
146} 113}
147 114
@@ -452,6 +419,54 @@ Node ShaderIR::BitfieldInsert(Node base, Node insert, u32 offset, u32 bits) {
452 Immediate(bits)); 419 Immediate(bits));
453} 420}
454 421
422void ShaderIR::MarkAttributeUsage(Attribute::Index index, u64 element) {
423 switch (index) {
424 case Attribute::Index::LayerViewportPointSize:
425 switch (element) {
426 case 0:
427 UNIMPLEMENTED();
428 break;
429 case 1:
430 uses_layer = true;
431 break;
432 case 2:
433 uses_viewport_index = true;
434 break;
435 case 3:
436 uses_point_size = true;
437 break;
438 }
439 break;
440 case Attribute::Index::TessCoordInstanceIDVertexID:
441 switch (element) {
442 case 2:
443 uses_instance_id = true;
444 break;
445 case 3:
446 uses_vertex_id = true;
447 break;
448 }
449 break;
450 case Attribute::Index::ClipDistances0123:
451 case Attribute::Index::ClipDistances4567: {
452 const u64 clip_index = (index == Attribute::Index::ClipDistances4567 ? 4 : 0) + element;
453 used_clip_distances.at(clip_index) = true;
454 break;
455 }
456 case Attribute::Index::FrontColor:
457 case Attribute::Index::FrontSecondaryColor:
458 case Attribute::Index::BackColor:
459 case Attribute::Index::BackSecondaryColor:
460 uses_legacy_varyings = true;
461 break;
462 default:
463 if (index >= Attribute::Index::TexCoord_0 && index <= Attribute::Index::TexCoord_7) {
464 uses_legacy_varyings = true;
465 }
466 break;
467 }
468}
469
455std::size_t ShaderIR::DeclareAmend(Node new_amend) { 470std::size_t ShaderIR::DeclareAmend(Node new_amend) {
456 const std::size_t id = amend_code.size(); 471 const std::size_t id = amend_code.size();
457 amend_code.push_back(new_amend); 472 amend_code.push_back(new_amend);
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index dde036b40..80fc9b82c 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -137,6 +137,10 @@ public:
137 return uses_vertex_id; 137 return uses_vertex_id;
138 } 138 }
139 139
140 bool UsesLegacyVaryings() const {
141 return uses_legacy_varyings;
142 }
143
140 bool UsesWarps() const { 144 bool UsesWarps() const {
141 return uses_warps; 145 return uses_warps;
142 } 146 }
@@ -343,6 +347,9 @@ private:
343 /// Inserts a sequence of bits from a node 347 /// Inserts a sequence of bits from a node
344 Node BitfieldInsert(Node base, Node insert, u32 offset, u32 bits); 348 Node BitfieldInsert(Node base, Node insert, u32 offset, u32 bits);
345 349
350 /// Marks the usage of a input or output attribute.
351 void MarkAttributeUsage(Tegra::Shader::Attribute::Index index, u64 element);
352
346 void WriteTexInstructionFloat(NodeBlock& bb, Tegra::Shader::Instruction instr, 353 void WriteTexInstructionFloat(NodeBlock& bb, Tegra::Shader::Instruction instr,
347 const Node4& components); 354 const Node4& components);
348 355
@@ -443,6 +450,7 @@ private:
443 bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes 450 bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes
444 bool uses_instance_id{}; 451 bool uses_instance_id{};
445 bool uses_vertex_id{}; 452 bool uses_vertex_id{};
453 bool uses_legacy_varyings{};
446 bool uses_warps{}; 454 bool uses_warps{};
447 bool uses_indexed_samplers{}; 455 bool uses_indexed_samplers{};
448 456
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index d7684e241..940f24dc8 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1034,6 +1034,14 @@ void GMainWindow::BootGame(const QString& filename) {
1034} 1034}
1035 1035
1036void GMainWindow::ShutdownGame() { 1036void GMainWindow::ShutdownGame() {
1037 if (!emulation_running) {
1038 return;
1039 }
1040
1041 if (ui.action_Fullscreen->isChecked()) {
1042 HideFullscreen();
1043 }
1044
1037 AllowOSSleep(); 1045 AllowOSSleep();
1038 1046
1039 discord_rpc->Pause(); 1047 discord_rpc->Pause();
@@ -1716,11 +1724,6 @@ void GMainWindow::OnStartGame() {
1716} 1724}
1717 1725
1718void GMainWindow::OnPauseGame() { 1726void GMainWindow::OnPauseGame() {
1719 Core::System& system{Core::System::GetInstance()};
1720 if (system.GetExitLock() && !ConfirmForceLockedExit()) {
1721 return;
1722 }
1723
1724 emu_thread->SetRunning(false); 1727 emu_thread->SetRunning(false);
1725 1728
1726 ui.action_Start->setEnabled(true); 1729 ui.action_Start->setEnabled(true);
@@ -1803,7 +1806,7 @@ void GMainWindow::ToggleWindowMode() {
1803 // Render in the main window... 1806 // Render in the main window...
1804 render_window->BackupGeometry(); 1807 render_window->BackupGeometry();
1805 ui.horizontalLayout->addWidget(render_window); 1808 ui.horizontalLayout->addWidget(render_window);
1806 render_window->setFocusPolicy(Qt::ClickFocus); 1809 render_window->setFocusPolicy(Qt::StrongFocus);
1807 if (emulation_running) { 1810 if (emulation_running) {
1808 render_window->setVisible(true); 1811 render_window->setVisible(true);
1809 render_window->setFocus(); 1812 render_window->setFocus();