summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-03-30 05:21:59 -0300
committerGravatar ReinUsesLisp2020-04-14 00:39:21 -0300
commit0e232cfdc111d7a3dcbe590acdbd35f7e1f7645d (patch)
tree92dfc9678bea4dc53fe99931c57d412e61ac35e3 /src
parentrenderer_vulkan: Remove Nvidia checkpoints (diff)
downloadyuzu-0e232cfdc111d7a3dcbe590acdbd35f7e1f7645d.tar.gz
yuzu-0e232cfdc111d7a3dcbe590acdbd35f7e1f7645d.tar.xz
yuzu-0e232cfdc111d7a3dcbe590acdbd35f7e1f7645d.zip
renderer_vulkan: Integrate Nvidia Nsight Aftermath on Windows
Adds optional support for Nsight Aftermath. It is enabled through ENABLE_NSIGHT_AFTERMATH in cmake. A path to the SDK has to be provided by the environment variable NSIGHT_AFTERMATH_SDK. Nsight Aftermath allows an application to generate "minidumps" of the GPU state when a device loss happens. By analysing these on Nsight we can know what a game was doing and why it triggered a device loss. The dump is generated inside %APPDATA%\yuzu\log\gpucrash and this directory is deleted every time a new instance is initialized with Nsight enabled. To enable it on yuzu there has a to be a driver and device capable of running Nsight Aftermath on Vulkan. That means only Turing based GPUs on the latest stable driver, beta drivers won't work for now. It is manually enabled in Configuration>Debug>Enable Graphics Debugging because when using all debugging capabilities there is a runtime cost.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/CMakeLists.txt19
-rw-r--r--src/video_core/renderer_vulkan/nsight_aftermath_tracker.cpp220
-rw-r--r--src/video_core/renderer_vulkan/nsight_aftermath_tracker.h87
-rw-r--r--src/video_core/renderer_vulkan/vk_compute_pipeline.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp35
-rw-r--r--src/video_core/renderer_vulkan/vk_device.h9
-rw-r--r--src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp2
-rw-r--r--src/video_core/renderer_vulkan/wrapper.cpp5
-rw-r--r--src/video_core/renderer_vulkan/wrapper.h3
9 files changed, 360 insertions, 22 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 258d58eba..c0e8f6ab1 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -160,6 +160,8 @@ if (ENABLE_VULKAN)
160 renderer_vulkan/fixed_pipeline_state.h 160 renderer_vulkan/fixed_pipeline_state.h
161 renderer_vulkan/maxwell_to_vk.cpp 161 renderer_vulkan/maxwell_to_vk.cpp
162 renderer_vulkan/maxwell_to_vk.h 162 renderer_vulkan/maxwell_to_vk.h
163 renderer_vulkan/nsight_aftermath_tracker.cpp
164 renderer_vulkan/nsight_aftermath_tracker.h
163 renderer_vulkan/renderer_vulkan.h 165 renderer_vulkan/renderer_vulkan.h
164 renderer_vulkan/renderer_vulkan.cpp 166 renderer_vulkan/renderer_vulkan.cpp
165 renderer_vulkan/vk_blit_screen.cpp 167 renderer_vulkan/vk_blit_screen.cpp
@@ -213,19 +215,30 @@ if (ENABLE_VULKAN)
213 renderer_vulkan/wrapper.cpp 215 renderer_vulkan/wrapper.cpp
214 renderer_vulkan/wrapper.h 216 renderer_vulkan/wrapper.h
215 ) 217 )
216
217 target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include)
218 target_compile_definitions(video_core PRIVATE HAS_VULKAN)
219endif() 218endif()
220 219
221create_target_directory_groups(video_core) 220create_target_directory_groups(video_core)
222 221
223target_link_libraries(video_core PUBLIC common core) 222target_link_libraries(video_core PUBLIC common core)
224target_link_libraries(video_core PRIVATE glad) 223target_link_libraries(video_core PRIVATE glad)
224
225if (ENABLE_VULKAN) 225if (ENABLE_VULKAN)
226 target_include_directories(video_core PRIVATE sirit ../../externals/Vulkan-Headers/include)
227 target_compile_definitions(video_core PRIVATE HAS_VULKAN)
226 target_link_libraries(video_core PRIVATE sirit) 228 target_link_libraries(video_core PRIVATE sirit)
227endif() 229endif()
228 230
231if (ENABLE_NSIGHT_AFTERMATH)
232 if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK})
233 message(ERROR "Environment variable NSIGHT_AFTERMATH_SDK has to be provided")
234 endif()
235 if (NOT WIN32)
236 message(ERROR "Nsight Aftermath doesn't support non-Windows platforms")
237 endif()
238 target_compile_definitions(video_core PRIVATE HAS_NSIGHT_AFTERMATH)
239 target_include_directories(video_core PRIVATE "$ENV{NSIGHT_AFTERMATH_SDK}/include")
240endif()
241
229if (MSVC) 242if (MSVC)
230 target_compile_options(video_core PRIVATE /we4267) 243 target_compile_options(video_core PRIVATE /we4267)
231else() 244else()
diff --git a/src/video_core/renderer_vulkan/nsight_aftermath_tracker.cpp b/src/video_core/renderer_vulkan/nsight_aftermath_tracker.cpp
new file mode 100644
index 000000000..435c8c1b8
--- /dev/null
+++ b/src/video_core/renderer_vulkan/nsight_aftermath_tracker.cpp
@@ -0,0 +1,220 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#ifdef HAS_NSIGHT_AFTERMATH
6
7#include <mutex>
8#include <string>
9#include <string_view>
10#include <utility>
11#include <vector>
12
13#include <fmt/format.h>
14
15#define VK_NO_PROTOTYPES
16#include <vulkan/vulkan.h>
17
18#include <GFSDK_Aftermath.h>
19#include <GFSDK_Aftermath_Defines.h>
20#include <GFSDK_Aftermath_GpuCrashDump.h>
21#include <GFSDK_Aftermath_GpuCrashDumpDecoding.h>
22
23#include "common/common_paths.h"
24#include "common/common_types.h"
25#include "common/file_util.h"
26#include "common/logging/log.h"
27#include "common/scope_exit.h"
28
29#include "video_core/renderer_vulkan/nsight_aftermath_tracker.h"
30
31namespace Vulkan {
32
33static constexpr char AFTERMATH_LIB_NAME[] = "GFSDK_Aftermath_Lib.x64.dll";
34
35NsightAftermathTracker::NsightAftermathTracker() = default;
36
37NsightAftermathTracker::~NsightAftermathTracker() {
38 if (initialized) {
39 (void)GFSDK_Aftermath_DisableGpuCrashDumps();
40 }
41}
42
43bool NsightAftermathTracker::Initialize() {
44 if (!dl.Open(AFTERMATH_LIB_NAME)) {
45 LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath DLL");
46 return false;
47 }
48
49 if (!dl.GetSymbol("GFSDK_Aftermath_DisableGpuCrashDumps",
50 &GFSDK_Aftermath_DisableGpuCrashDumps) ||
51 !dl.GetSymbol("GFSDK_Aftermath_EnableGpuCrashDumps",
52 &GFSDK_Aftermath_EnableGpuCrashDumps) ||
53 !dl.GetSymbol("GFSDK_Aftermath_GetShaderDebugInfoIdentifier",
54 &GFSDK_Aftermath_GetShaderDebugInfoIdentifier) ||
55 !dl.GetSymbol("GFSDK_Aftermath_GetShaderHashSpirv", &GFSDK_Aftermath_GetShaderHashSpirv) ||
56 !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_CreateDecoder",
57 &GFSDK_Aftermath_GpuCrashDump_CreateDecoder) ||
58 !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_DestroyDecoder",
59 &GFSDK_Aftermath_GpuCrashDump_DestroyDecoder) ||
60 !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_GenerateJSON",
61 &GFSDK_Aftermath_GpuCrashDump_GenerateJSON) ||
62 !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_GetJSON",
63 &GFSDK_Aftermath_GpuCrashDump_GetJSON)) {
64 LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath function pointers");
65 return false;
66 }
67
68 dump_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir) + "gpucrash";
69
70 (void)FileUtil::DeleteDirRecursively(dump_dir);
71 if (!FileUtil::CreateDir(dump_dir)) {
72 LOG_ERROR(Render_Vulkan, "Failed to create Nsight Aftermath dump directory");
73 return false;
74 }
75
76 if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_EnableGpuCrashDumps(
77 GFSDK_Aftermath_Version_API, GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_Vulkan,
78 GFSDK_Aftermath_GpuCrashDumpFeatureFlags_Default, GpuCrashDumpCallback,
79 ShaderDebugInfoCallback, CrashDumpDescriptionCallback, this))) {
80 LOG_ERROR(Render_Vulkan, "GFSDK_Aftermath_EnableGpuCrashDumps failed");
81 return false;
82 }
83
84 LOG_INFO(Render_Vulkan, "Nsight Aftermath dump directory is \"{}\"", dump_dir);
85
86 initialized = true;
87 return true;
88}
89
90void NsightAftermathTracker::SaveShader(const std::vector<u32>& spirv) const {
91 if (!initialized) {
92 return;
93 }
94
95 std::vector<u32> spirv_copy = spirv;
96 GFSDK_Aftermath_SpirvCode shader;
97 shader.pData = spirv_copy.data();
98 shader.size = static_cast<u32>(spirv_copy.size() * 4);
99
100 std::scoped_lock lock{mutex};
101
102 GFSDK_Aftermath_ShaderHash hash;
103 if (!GFSDK_Aftermath_SUCCEED(
104 GFSDK_Aftermath_GetShaderHashSpirv(GFSDK_Aftermath_Version_API, &shader, &hash))) {
105 LOG_ERROR(Render_Vulkan, "Failed to hash SPIR-V module");
106 return;
107 }
108
109 FileUtil::IOFile file(fmt::format("{}/source_{:016x}.spv", dump_dir, hash.hash), "wb");
110 if (!file.IsOpen()) {
111 LOG_ERROR(Render_Vulkan, "Failed to dump SPIR-V module with hash={:016x}", hash.hash);
112 return;
113 }
114 if (file.WriteArray(spirv.data(), spirv.size()) != spirv.size()) {
115 LOG_ERROR(Render_Vulkan, "Failed to write SPIR-V module with hash={:016x}", hash.hash);
116 return;
117 }
118}
119
120void NsightAftermathTracker::OnGpuCrashDumpCallback(const void* gpu_crash_dump,
121 u32 gpu_crash_dump_size) {
122 std::scoped_lock lock{mutex};
123
124 LOG_CRITICAL(Render_Vulkan, "called");
125
126 GFSDK_Aftermath_GpuCrashDump_Decoder decoder;
127 if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_CreateDecoder(
128 GFSDK_Aftermath_Version_API, gpu_crash_dump, gpu_crash_dump_size, &decoder))) {
129 LOG_ERROR(Render_Vulkan, "Failed to create decoder");
130 return;
131 }
132 SCOPE_EXIT({ GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder); });
133
134 u32 json_size = 0;
135 if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_GenerateJSON(
136 decoder, GFSDK_Aftermath_GpuCrashDumpDecoderFlags_ALL_INFO,
137 GFSDK_Aftermath_GpuCrashDumpFormatterFlags_NONE, nullptr, nullptr, nullptr, nullptr,
138 this, &json_size))) {
139 LOG_ERROR(Render_Vulkan, "Failed to generate JSON");
140 return;
141 }
142 std::vector<char> json(json_size);
143 if (!GFSDK_Aftermath_SUCCEED(
144 GFSDK_Aftermath_GpuCrashDump_GetJSON(decoder, json_size, json.data()))) {
145 LOG_ERROR(Render_Vulkan, "Failed to query JSON");
146 return;
147 }
148
149 const std::string base_name = [this] {
150 const int id = dump_id++;
151 if (id == 0) {
152 return fmt::format("{}/crash.nv-gpudmp", dump_dir);
153 } else {
154 return fmt::format("{}/crash_{}.nv-gpudmp", dump_dir, id);
155 }
156 }();
157
158 std::string_view dump_view(static_cast<const char*>(gpu_crash_dump), gpu_crash_dump_size);
159 if (FileUtil::WriteStringToFile(false, base_name, dump_view) != gpu_crash_dump_size) {
160 LOG_ERROR(Render_Vulkan, "Failed to write dump file");
161 return;
162 }
163 const std::string_view json_view(json.data(), json.size());
164 if (FileUtil::WriteStringToFile(true, base_name + ".json", json_view) != json.size()) {
165 LOG_ERROR(Render_Vulkan, "Failed to write JSON");
166 return;
167 }
168}
169
170void NsightAftermathTracker::OnShaderDebugInfoCallback(const void* shader_debug_info,
171 u32 shader_debug_info_size) {
172 std::scoped_lock lock{mutex};
173
174 GFSDK_Aftermath_ShaderDebugInfoIdentifier identifier;
175 if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GetShaderDebugInfoIdentifier(
176 GFSDK_Aftermath_Version_API, shader_debug_info, shader_debug_info_size, &identifier))) {
177 LOG_ERROR(Render_Vulkan, "GFSDK_Aftermath_GetShaderDebugInfoIdentifier failed");
178 return;
179 }
180
181 const std::string path =
182 fmt::format("{}/shader_{:016x}{:016x}.nvdbg", dump_dir, identifier.id[0], identifier.id[1]);
183 FileUtil::IOFile file(path, "wb");
184 if (!file.IsOpen()) {
185 LOG_ERROR(Render_Vulkan, "Failed to create file {}", path);
186 return;
187 }
188 if (file.WriteBytes(static_cast<const u8*>(shader_debug_info), shader_debug_info_size) !=
189 shader_debug_info_size) {
190 LOG_ERROR(Render_Vulkan, "Failed to write file {}", path);
191 return;
192 }
193}
194
195void NsightAftermathTracker::OnCrashDumpDescriptionCallback(
196 PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description) {
197 add_description(GFSDK_Aftermath_GpuCrashDumpDescriptionKey_ApplicationName, "yuzu");
198}
199
200void NsightAftermathTracker::GpuCrashDumpCallback(const void* gpu_crash_dump,
201 u32 gpu_crash_dump_size, void* user_data) {
202 static_cast<NsightAftermathTracker*>(user_data)->OnGpuCrashDumpCallback(gpu_crash_dump,
203 gpu_crash_dump_size);
204}
205
206void NsightAftermathTracker::ShaderDebugInfoCallback(const void* shader_debug_info,
207 u32 shader_debug_info_size, void* user_data) {
208 static_cast<NsightAftermathTracker*>(user_data)->OnShaderDebugInfoCallback(
209 shader_debug_info, shader_debug_info_size);
210}
211
212void NsightAftermathTracker::CrashDumpDescriptionCallback(
213 PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description, void* user_data) {
214 static_cast<NsightAftermathTracker*>(user_data)->OnCrashDumpDescriptionCallback(
215 add_description);
216}
217
218} // namespace Vulkan
219
220#endif // HAS_NSIGHT_AFTERMATH
diff --git a/src/video_core/renderer_vulkan/nsight_aftermath_tracker.h b/src/video_core/renderer_vulkan/nsight_aftermath_tracker.h
new file mode 100644
index 000000000..afe7ae99e
--- /dev/null
+++ b/src/video_core/renderer_vulkan/nsight_aftermath_tracker.h
@@ -0,0 +1,87 @@
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 <mutex>
8#include <string>
9#include <vector>
10
11#define VK_NO_PROTOTYPES
12#include <vulkan/vulkan.h>
13
14#ifdef HAS_NSIGHT_AFTERMATH
15#include <GFSDK_Aftermath_Defines.h>
16#include <GFSDK_Aftermath_GpuCrashDump.h>
17#include <GFSDK_Aftermath_GpuCrashDumpDecoding.h>
18#endif
19
20#include "common/common_types.h"
21#include "common/dynamic_library.h"
22
23namespace Vulkan {
24
25class NsightAftermathTracker {
26public:
27 NsightAftermathTracker();
28 ~NsightAftermathTracker();
29
30 NsightAftermathTracker(const NsightAftermathTracker&) = delete;
31 NsightAftermathTracker& operator=(const NsightAftermathTracker&) = delete;
32
33 // Delete move semantics because Aftermath initialization uses a pointer to this.
34 NsightAftermathTracker(NsightAftermathTracker&&) = delete;
35 NsightAftermathTracker& operator=(NsightAftermathTracker&&) = delete;
36
37 bool Initialize();
38
39 void SaveShader(const std::vector<u32>& spirv) const;
40
41private:
42#ifdef HAS_NSIGHT_AFTERMATH
43 static void GpuCrashDumpCallback(const void* gpu_crash_dump, u32 gpu_crash_dump_size,
44 void* user_data);
45
46 static void ShaderDebugInfoCallback(const void* shader_debug_info, u32 shader_debug_info_size,
47 void* user_data);
48
49 static void CrashDumpDescriptionCallback(
50 PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description, void* user_data);
51
52 void OnGpuCrashDumpCallback(const void* gpu_crash_dump, u32 gpu_crash_dump_size);
53
54 void OnShaderDebugInfoCallback(const void* shader_debug_info, u32 shader_debug_info_size);
55
56 void OnCrashDumpDescriptionCallback(
57 PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description);
58
59 mutable std::mutex mutex;
60
61 std::string dump_dir;
62 int dump_id = 0;
63
64 bool initialized = false;
65
66 Common::DynamicLibrary dl;
67 PFN_GFSDK_Aftermath_DisableGpuCrashDumps GFSDK_Aftermath_DisableGpuCrashDumps;
68 PFN_GFSDK_Aftermath_EnableGpuCrashDumps GFSDK_Aftermath_EnableGpuCrashDumps;
69 PFN_GFSDK_Aftermath_GetShaderDebugInfoIdentifier GFSDK_Aftermath_GetShaderDebugInfoIdentifier;
70 PFN_GFSDK_Aftermath_GetShaderHashSpirv GFSDK_Aftermath_GetShaderHashSpirv;
71 PFN_GFSDK_Aftermath_GpuCrashDump_CreateDecoder GFSDK_Aftermath_GpuCrashDump_CreateDecoder;
72 PFN_GFSDK_Aftermath_GpuCrashDump_DestroyDecoder GFSDK_Aftermath_GpuCrashDump_DestroyDecoder;
73 PFN_GFSDK_Aftermath_GpuCrashDump_GenerateJSON GFSDK_Aftermath_GpuCrashDump_GenerateJSON;
74 PFN_GFSDK_Aftermath_GpuCrashDump_GetJSON GFSDK_Aftermath_GpuCrashDump_GetJSON;
75#endif
76};
77
78#ifndef HAS_NSIGHT_AFTERMATH
79inline NsightAftermathTracker::NsightAftermathTracker() = default;
80inline NsightAftermathTracker::~NsightAftermathTracker() = default;
81inline bool NsightAftermathTracker::Initialize() {
82 return false;
83}
84inline void NsightAftermathTracker::SaveShader(const std::vector<u32>&) const {}
85#endif
86
87} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
index 23beafa4f..52566bb79 100644
--- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
@@ -105,6 +105,8 @@ vk::DescriptorUpdateTemplateKHR VKComputePipeline::CreateDescriptorUpdateTemplat
105} 105}
106 106
107vk::ShaderModule VKComputePipeline::CreateShaderModule(const std::vector<u32>& code) const { 107vk::ShaderModule VKComputePipeline::CreateShaderModule(const std::vector<u32>& code) const {
108 device.SaveShader(code);
109
108 VkShaderModuleCreateInfo ci; 110 VkShaderModuleCreateInfo ci;
109 ci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; 111 ci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
110 ci.pNext = nullptr; 112 ci.pNext = nullptr;
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp
index 52d29e49d..e90c76492 100644
--- a/src/video_core/renderer_vulkan/vk_device.cpp
+++ b/src/video_core/renderer_vulkan/vk_device.cpp
@@ -9,6 +9,7 @@
9#include <string_view> 9#include <string_view>
10#include <thread> 10#include <thread>
11#include <unordered_set> 11#include <unordered_set>
12#include <utility>
12#include <vector> 13#include <vector>
13 14
14#include "common/assert.h" 15#include "common/assert.h"
@@ -167,6 +168,7 @@ bool VKDevice::Create() {
167 VkPhysicalDeviceFeatures2 features2; 168 VkPhysicalDeviceFeatures2 features2;
168 features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; 169 features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
169 features2.pNext = nullptr; 170 features2.pNext = nullptr;
171 const void* first_next = &features2;
170 void** next = &features2.pNext; 172 void** next = &features2.pNext;
171 173
172 auto& features = features2.features; 174 auto& features = features2.features;
@@ -296,7 +298,19 @@ bool VKDevice::Create() {
296 LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted"); 298 LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted");
297 } 299 }
298 300
299 logical = vk::Device::Create(physical, queue_cis, extensions, features2, dld); 301 VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv;
302 if (nv_device_diagnostics_config) {
303 nsight_aftermath_tracker.Initialize();
304
305 diagnostics_nv.sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV;
306 diagnostics_nv.pNext = &features2;
307 diagnostics_nv.flags = VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV |
308 VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV |
309 VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV;
310 first_next = &diagnostics_nv;
311 }
312
313 logical = vk::Device::Create(physical, queue_cis, extensions, first_next, dld);
300 if (!logical) { 314 if (!logical) {
301 LOG_ERROR(Render_Vulkan, "Failed to create logical device"); 315 LOG_ERROR(Render_Vulkan, "Failed to create logical device");
302 return false; 316 return false;
@@ -344,17 +358,12 @@ VkFormat VKDevice::GetSupportedFormat(VkFormat wanted_format, VkFormatFeatureFla
344void VKDevice::ReportLoss() const { 358void VKDevice::ReportLoss() const {
345 LOG_CRITICAL(Render_Vulkan, "Device loss occured!"); 359 LOG_CRITICAL(Render_Vulkan, "Device loss occured!");
346 360
347 // Wait some time to let the log flush 361 // Wait for the log to flush and for Nsight Aftermath to dump the results
348 std::this_thread::sleep_for(std::chrono::seconds{1}); 362 std::this_thread::sleep_for(std::chrono::seconds{3});
349 363}
350 if (!nv_device_diagnostic_checkpoints) {
351 return;
352 }
353 364
354 [[maybe_unused]] const std::vector data = graphics_queue.GetCheckpointDataNV(dld); 365void VKDevice::SaveShader(const std::vector<u32>& spirv) const {
355 // Catch here in debug builds (or with optimizations disabled) the last graphics pipeline to be 366 nsight_aftermath_tracker.SaveShader(spirv);
356 // executed. It can be done on a debugger by evaluating the expression:
357 // *(VKGraphicsPipeline*)data[0]
358} 367}
359 368
360bool VKDevice::IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const { 369bool VKDevice::IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const {
@@ -527,8 +536,8 @@ std::vector<const char*> VKDevice::LoadExtensions() {
527 Test(extension, has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, 536 Test(extension, has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME,
528 false); 537 false);
529 if (Settings::values.renderer_debug) { 538 if (Settings::values.renderer_debug) {
530 Test(extension, nv_device_diagnostic_checkpoints, 539 Test(extension, nv_device_diagnostics_config,
531 VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME, true); 540 VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, true);
532 } 541 }
533 } 542 }
534 543
diff --git a/src/video_core/renderer_vulkan/vk_device.h b/src/video_core/renderer_vulkan/vk_device.h
index f596a6086..a4d841e26 100644
--- a/src/video_core/renderer_vulkan/vk_device.h
+++ b/src/video_core/renderer_vulkan/vk_device.h
@@ -10,6 +10,7 @@
10#include <vector> 10#include <vector>
11 11
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "video_core/renderer_vulkan/nsight_aftermath_tracker.h"
13#include "video_core/renderer_vulkan/wrapper.h" 14#include "video_core/renderer_vulkan/wrapper.h"
14 15
15namespace Vulkan { 16namespace Vulkan {
@@ -43,6 +44,9 @@ public:
43 /// Reports a device loss. 44 /// Reports a device loss.
44 void ReportLoss() const; 45 void ReportLoss() const;
45 46
47 /// Reports a shader to Nsight Aftermath.
48 void SaveShader(const std::vector<u32>& spirv) const;
49
46 /// Returns the dispatch loader with direct function pointers of the device. 50 /// Returns the dispatch loader with direct function pointers of the device.
47 const vk::DeviceDispatch& GetDispatchLoader() const { 51 const vk::DeviceDispatch& GetDispatchLoader() const {
48 return dld; 52 return dld;
@@ -228,7 +232,7 @@ private:
228 bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. 232 bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted.
229 bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer. 233 bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer.
230 bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. 234 bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback.
231 bool nv_device_diagnostic_checkpoints{}; ///< Support for VK_NV_device_diagnostic_checkpoints. 235 bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config.
232 236
233 // Telemetry parameters 237 // Telemetry parameters
234 std::string vendor_name; ///< Device's driver name. 238 std::string vendor_name; ///< Device's driver name.
@@ -236,6 +240,9 @@ private:
236 240
237 /// Format properties dictionary. 241 /// Format properties dictionary.
238 std::unordered_map<VkFormat, VkFormatProperties> format_properties; 242 std::unordered_map<VkFormat, VkFormatProperties> format_properties;
243
244 /// Nsight Aftermath GPU crash tracker
245 NsightAftermathTracker nsight_aftermath_tracker;
239}; 246};
240 247
241} // namespace Vulkan 248} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
index b540b838d..b2b794096 100644
--- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
+++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
@@ -147,6 +147,8 @@ std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules(
147 continue; 147 continue;
148 } 148 }
149 149
150 device.SaveShader(stage->code);
151
150 ci.codeSize = stage->code.size() * sizeof(u32); 152 ci.codeSize = stage->code.size() * sizeof(u32);
151 ci.pCode = stage->code.data(); 153 ci.pCode = stage->code.data();
152 modules.push_back(device.GetLogical().CreateShaderModule(ci)); 154 modules.push_back(device.GetLogical().CreateShaderModule(ci));
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp
index f88eaad6b..3a52a3a6f 100644
--- a/src/video_core/renderer_vulkan/wrapper.cpp
+++ b/src/video_core/renderer_vulkan/wrapper.cpp
@@ -456,12 +456,11 @@ std::vector<VkImage> SwapchainKHR::GetImages() const {
456} 456}
457 457
458Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, 458Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
459 Span<const char*> enabled_extensions, 459 Span<const char*> enabled_extensions, const void* next,
460 const VkPhysicalDeviceFeatures2& enabled_features,
461 DeviceDispatch& dld) noexcept { 460 DeviceDispatch& dld) noexcept {
462 VkDeviceCreateInfo ci; 461 VkDeviceCreateInfo ci;
463 ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 462 ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
464 ci.pNext = &enabled_features; 463 ci.pNext = next;
465 ci.flags = 0; 464 ci.flags = 0;
466 ci.queueCreateInfoCount = queues_ci.size(); 465 ci.queueCreateInfoCount = queues_ci.size();
467 ci.pQueueCreateInfos = queues_ci.data(); 466 ci.pQueueCreateInfos = queues_ci.data();
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h
index 62e252c43..6fe0294d8 100644
--- a/src/video_core/renderer_vulkan/wrapper.h
+++ b/src/video_core/renderer_vulkan/wrapper.h
@@ -653,8 +653,7 @@ class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> {
653 653
654public: 654public:
655 static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, 655 static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci,
656 Span<const char*> enabled_extensions, 656 Span<const char*> enabled_extensions, const void* next,
657 const VkPhysicalDeviceFeatures2& enabled_features,
658 DeviceDispatch& dld) noexcept; 657 DeviceDispatch& dld) noexcept;
659 658
660 Queue GetQueue(u32 family_index) const noexcept; 659 Queue GetQueue(u32 family_index) const noexcept;