diff options
| author | 2020-12-26 01:26:52 -0300 | |
|---|---|---|
| committer | 2021-01-04 02:22:22 -0300 | |
| commit | d235cf393399c386a59b5e39d39bc9efb161aea0 (patch) | |
| tree | 4b8a3420a94b972dfc0781ed1ba8b197b8b02c95 /src/video_core/vulkan_common | |
| parent | renderer_vulkan: Move device abstraction to vulkan_common (diff) | |
| download | yuzu-d235cf393399c386a59b5e39d39bc9efb161aea0.tar.gz yuzu-d235cf393399c386a59b5e39d39bc9efb161aea0.tar.xz yuzu-d235cf393399c386a59b5e39d39bc9efb161aea0.zip | |
renderer_vulkan/nsight_aftermath_tracker: Move to vulkan_common
Diffstat (limited to 'src/video_core/vulkan_common')
4 files changed, 302 insertions, 4 deletions
diff --git a/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp new file mode 100644 index 000000000..8d10ac29e --- /dev/null +++ b/src/video_core/vulkan_common/nsight_aftermath_tracker.cpp | |||
| @@ -0,0 +1,212 @@ | |||
| 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 | |||
| 31 | namespace Vulkan { | ||
| 32 | |||
| 33 | static constexpr char AFTERMATH_LIB_NAME[] = "GFSDK_Aftermath_Lib.x64.dll"; | ||
| 34 | |||
| 35 | NsightAftermathTracker::NsightAftermathTracker() { | ||
| 36 | if (!dl.Open(AFTERMATH_LIB_NAME)) { | ||
| 37 | LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath DLL"); | ||
| 38 | return; | ||
| 39 | } | ||
| 40 | if (!dl.GetSymbol("GFSDK_Aftermath_DisableGpuCrashDumps", | ||
| 41 | &GFSDK_Aftermath_DisableGpuCrashDumps) || | ||
| 42 | !dl.GetSymbol("GFSDK_Aftermath_EnableGpuCrashDumps", | ||
| 43 | &GFSDK_Aftermath_EnableGpuCrashDumps) || | ||
| 44 | !dl.GetSymbol("GFSDK_Aftermath_GetShaderDebugInfoIdentifier", | ||
| 45 | &GFSDK_Aftermath_GetShaderDebugInfoIdentifier) || | ||
| 46 | !dl.GetSymbol("GFSDK_Aftermath_GetShaderHashSpirv", &GFSDK_Aftermath_GetShaderHashSpirv) || | ||
| 47 | !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_CreateDecoder", | ||
| 48 | &GFSDK_Aftermath_GpuCrashDump_CreateDecoder) || | ||
| 49 | !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_DestroyDecoder", | ||
| 50 | &GFSDK_Aftermath_GpuCrashDump_DestroyDecoder) || | ||
| 51 | !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_GenerateJSON", | ||
| 52 | &GFSDK_Aftermath_GpuCrashDump_GenerateJSON) || | ||
| 53 | !dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_GetJSON", | ||
| 54 | &GFSDK_Aftermath_GpuCrashDump_GetJSON)) { | ||
| 55 | LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath function pointers"); | ||
| 56 | return false; | ||
| 57 | } | ||
| 58 | dump_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir) + "gpucrash"; | ||
| 59 | |||
| 60 | void(Common::FS::DeleteDirRecursively(dump_dir)); | ||
| 61 | if (!Common::FS::CreateDir(dump_dir)) { | ||
| 62 | LOG_ERROR(Render_Vulkan, "Failed to create Nsight Aftermath dump directory"); | ||
| 63 | return; | ||
| 64 | } | ||
| 65 | if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_EnableGpuCrashDumps( | ||
| 66 | GFSDK_Aftermath_Version_API, GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_Vulkan, | ||
| 67 | GFSDK_Aftermath_GpuCrashDumpFeatureFlags_Default, GpuCrashDumpCallback, | ||
| 68 | ShaderDebugInfoCallback, CrashDumpDescriptionCallback, this))) { | ||
| 69 | LOG_ERROR(Render_Vulkan, "GFSDK_Aftermath_EnableGpuCrashDumps failed"); | ||
| 70 | return; | ||
| 71 | } | ||
| 72 | LOG_INFO(Render_Vulkan, "Nsight Aftermath dump directory is \"{}\"", dump_dir); | ||
| 73 | initialized = true; | ||
| 74 | } | ||
| 75 | |||
| 76 | NsightAftermathTracker::~NsightAftermathTracker() { | ||
| 77 | if (initialized) { | ||
| 78 | (void)GFSDK_Aftermath_DisableGpuCrashDumps(); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | void NsightAftermathTracker::SaveShader(const std::vector<u32>& spirv) const { | ||
| 83 | if (!initialized) { | ||
| 84 | return; | ||
| 85 | } | ||
| 86 | |||
| 87 | std::vector<u32> spirv_copy = spirv; | ||
| 88 | GFSDK_Aftermath_SpirvCode shader; | ||
| 89 | shader.pData = spirv_copy.data(); | ||
| 90 | shader.size = static_cast<u32>(spirv_copy.size() * 4); | ||
| 91 | |||
| 92 | std::scoped_lock lock{mutex}; | ||
| 93 | |||
| 94 | GFSDK_Aftermath_ShaderHash hash; | ||
| 95 | if (!GFSDK_Aftermath_SUCCEED( | ||
| 96 | GFSDK_Aftermath_GetShaderHashSpirv(GFSDK_Aftermath_Version_API, &shader, &hash))) { | ||
| 97 | LOG_ERROR(Render_Vulkan, "Failed to hash SPIR-V module"); | ||
| 98 | return; | ||
| 99 | } | ||
| 100 | |||
| 101 | Common::FS::IOFile file(fmt::format("{}/source_{:016x}.spv", dump_dir, hash.hash), "wb"); | ||
| 102 | if (!file.IsOpen()) { | ||
| 103 | LOG_ERROR(Render_Vulkan, "Failed to dump SPIR-V module with hash={:016x}", hash.hash); | ||
| 104 | return; | ||
| 105 | } | ||
| 106 | if (file.WriteArray(spirv.data(), spirv.size()) != spirv.size()) { | ||
| 107 | LOG_ERROR(Render_Vulkan, "Failed to write SPIR-V module with hash={:016x}", hash.hash); | ||
| 108 | return; | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | void NsightAftermathTracker::OnGpuCrashDumpCallback(const void* gpu_crash_dump, | ||
| 113 | u32 gpu_crash_dump_size) { | ||
| 114 | std::scoped_lock lock{mutex}; | ||
| 115 | |||
| 116 | LOG_CRITICAL(Render_Vulkan, "called"); | ||
| 117 | |||
| 118 | GFSDK_Aftermath_GpuCrashDump_Decoder decoder; | ||
| 119 | if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_CreateDecoder( | ||
| 120 | GFSDK_Aftermath_Version_API, gpu_crash_dump, gpu_crash_dump_size, &decoder))) { | ||
| 121 | LOG_ERROR(Render_Vulkan, "Failed to create decoder"); | ||
| 122 | return; | ||
| 123 | } | ||
| 124 | SCOPE_EXIT({ GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder); }); | ||
| 125 | |||
| 126 | u32 json_size = 0; | ||
| 127 | if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_GenerateJSON( | ||
| 128 | decoder, GFSDK_Aftermath_GpuCrashDumpDecoderFlags_ALL_INFO, | ||
| 129 | GFSDK_Aftermath_GpuCrashDumpFormatterFlags_NONE, nullptr, nullptr, nullptr, nullptr, | ||
| 130 | this, &json_size))) { | ||
| 131 | LOG_ERROR(Render_Vulkan, "Failed to generate JSON"); | ||
| 132 | return; | ||
| 133 | } | ||
| 134 | std::vector<char> json(json_size); | ||
| 135 | if (!GFSDK_Aftermath_SUCCEED( | ||
| 136 | GFSDK_Aftermath_GpuCrashDump_GetJSON(decoder, json_size, json.data()))) { | ||
| 137 | LOG_ERROR(Render_Vulkan, "Failed to query JSON"); | ||
| 138 | return; | ||
| 139 | } | ||
| 140 | |||
| 141 | const std::string base_name = [this] { | ||
| 142 | const int id = dump_id++; | ||
| 143 | if (id == 0) { | ||
| 144 | return fmt::format("{}/crash.nv-gpudmp", dump_dir); | ||
| 145 | } else { | ||
| 146 | return fmt::format("{}/crash_{}.nv-gpudmp", dump_dir, id); | ||
| 147 | } | ||
| 148 | }(); | ||
| 149 | |||
| 150 | std::string_view dump_view(static_cast<const char*>(gpu_crash_dump), gpu_crash_dump_size); | ||
| 151 | if (Common::FS::WriteStringToFile(false, base_name, dump_view) != gpu_crash_dump_size) { | ||
| 152 | LOG_ERROR(Render_Vulkan, "Failed to write dump file"); | ||
| 153 | return; | ||
| 154 | } | ||
| 155 | const std::string_view json_view(json.data(), json.size()); | ||
| 156 | if (Common::FS::WriteStringToFile(true, base_name + ".json", json_view) != json.size()) { | ||
| 157 | LOG_ERROR(Render_Vulkan, "Failed to write JSON"); | ||
| 158 | return; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | void NsightAftermathTracker::OnShaderDebugInfoCallback(const void* shader_debug_info, | ||
| 163 | u32 shader_debug_info_size) { | ||
| 164 | std::scoped_lock lock{mutex}; | ||
| 165 | |||
| 166 | GFSDK_Aftermath_ShaderDebugInfoIdentifier identifier; | ||
| 167 | if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GetShaderDebugInfoIdentifier( | ||
| 168 | GFSDK_Aftermath_Version_API, shader_debug_info, shader_debug_info_size, &identifier))) { | ||
| 169 | LOG_ERROR(Render_Vulkan, "GFSDK_Aftermath_GetShaderDebugInfoIdentifier failed"); | ||
| 170 | return; | ||
| 171 | } | ||
| 172 | |||
| 173 | const std::string path = | ||
| 174 | fmt::format("{}/shader_{:016x}{:016x}.nvdbg", dump_dir, identifier.id[0], identifier.id[1]); | ||
| 175 | Common::FS::IOFile file(path, "wb"); | ||
| 176 | if (!file.IsOpen()) { | ||
| 177 | LOG_ERROR(Render_Vulkan, "Failed to create file {}", path); | ||
| 178 | return; | ||
| 179 | } | ||
| 180 | if (file.WriteBytes(static_cast<const u8*>(shader_debug_info), shader_debug_info_size) != | ||
| 181 | shader_debug_info_size) { | ||
| 182 | LOG_ERROR(Render_Vulkan, "Failed to write file {}", path); | ||
| 183 | return; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 187 | void NsightAftermathTracker::OnCrashDumpDescriptionCallback( | ||
| 188 | PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description) { | ||
| 189 | add_description(GFSDK_Aftermath_GpuCrashDumpDescriptionKey_ApplicationName, "yuzu"); | ||
| 190 | } | ||
| 191 | |||
| 192 | void NsightAftermathTracker::GpuCrashDumpCallback(const void* gpu_crash_dump, | ||
| 193 | u32 gpu_crash_dump_size, void* user_data) { | ||
| 194 | static_cast<NsightAftermathTracker*>(user_data)->OnGpuCrashDumpCallback(gpu_crash_dump, | ||
| 195 | gpu_crash_dump_size); | ||
| 196 | } | ||
| 197 | |||
| 198 | void NsightAftermathTracker::ShaderDebugInfoCallback(const void* shader_debug_info, | ||
| 199 | u32 shader_debug_info_size, void* user_data) { | ||
| 200 | static_cast<NsightAftermathTracker*>(user_data)->OnShaderDebugInfoCallback( | ||
| 201 | shader_debug_info, shader_debug_info_size); | ||
| 202 | } | ||
| 203 | |||
| 204 | void NsightAftermathTracker::CrashDumpDescriptionCallback( | ||
| 205 | PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description, void* user_data) { | ||
| 206 | static_cast<NsightAftermathTracker*>(user_data)->OnCrashDumpDescriptionCallback( | ||
| 207 | add_description); | ||
| 208 | } | ||
| 209 | |||
| 210 | } // namespace Vulkan | ||
| 211 | |||
| 212 | #endif // HAS_NSIGHT_AFTERMATH | ||
diff --git a/src/video_core/vulkan_common/nsight_aftermath_tracker.h b/src/video_core/vulkan_common/nsight_aftermath_tracker.h new file mode 100644 index 000000000..cee3847fb --- /dev/null +++ b/src/video_core/vulkan_common/nsight_aftermath_tracker.h | |||
| @@ -0,0 +1,82 @@ | |||
| 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 | |||
| 23 | namespace Vulkan { | ||
| 24 | |||
| 25 | class NsightAftermathTracker { | ||
| 26 | public: | ||
| 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 | void SaveShader(const std::vector<u32>& spirv) const; | ||
| 38 | |||
| 39 | private: | ||
| 40 | #ifdef HAS_NSIGHT_AFTERMATH | ||
| 41 | static void GpuCrashDumpCallback(const void* gpu_crash_dump, u32 gpu_crash_dump_size, | ||
| 42 | void* user_data); | ||
| 43 | |||
| 44 | static void ShaderDebugInfoCallback(const void* shader_debug_info, u32 shader_debug_info_size, | ||
| 45 | void* user_data); | ||
| 46 | |||
| 47 | static void CrashDumpDescriptionCallback( | ||
| 48 | PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description, void* user_data); | ||
| 49 | |||
| 50 | void OnGpuCrashDumpCallback(const void* gpu_crash_dump, u32 gpu_crash_dump_size); | ||
| 51 | |||
| 52 | void OnShaderDebugInfoCallback(const void* shader_debug_info, u32 shader_debug_info_size); | ||
| 53 | |||
| 54 | void OnCrashDumpDescriptionCallback( | ||
| 55 | PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description); | ||
| 56 | |||
| 57 | mutable std::mutex mutex; | ||
| 58 | |||
| 59 | std::string dump_dir; | ||
| 60 | int dump_id = 0; | ||
| 61 | |||
| 62 | bool initialized = false; | ||
| 63 | |||
| 64 | Common::DynamicLibrary dl; | ||
| 65 | PFN_GFSDK_Aftermath_DisableGpuCrashDumps GFSDK_Aftermath_DisableGpuCrashDumps; | ||
| 66 | PFN_GFSDK_Aftermath_EnableGpuCrashDumps GFSDK_Aftermath_EnableGpuCrashDumps; | ||
| 67 | PFN_GFSDK_Aftermath_GetShaderDebugInfoIdentifier GFSDK_Aftermath_GetShaderDebugInfoIdentifier; | ||
| 68 | PFN_GFSDK_Aftermath_GetShaderHashSpirv GFSDK_Aftermath_GetShaderHashSpirv; | ||
| 69 | PFN_GFSDK_Aftermath_GpuCrashDump_CreateDecoder GFSDK_Aftermath_GpuCrashDump_CreateDecoder; | ||
| 70 | PFN_GFSDK_Aftermath_GpuCrashDump_DestroyDecoder GFSDK_Aftermath_GpuCrashDump_DestroyDecoder; | ||
| 71 | PFN_GFSDK_Aftermath_GpuCrashDump_GenerateJSON GFSDK_Aftermath_GpuCrashDump_GenerateJSON; | ||
| 72 | PFN_GFSDK_Aftermath_GpuCrashDump_GetJSON GFSDK_Aftermath_GpuCrashDump_GetJSON; | ||
| 73 | #endif | ||
| 74 | }; | ||
| 75 | |||
| 76 | #ifndef HAS_NSIGHT_AFTERMATH | ||
| 77 | inline NsightAftermathTracker::NsightAftermathTracker() = default; | ||
| 78 | inline NsightAftermathTracker::~NsightAftermathTracker() = default; | ||
| 79 | inline void NsightAftermathTracker::SaveShader(const std::vector<u32>&) const {} | ||
| 80 | #endif | ||
| 81 | |||
| 82 | } // namespace Vulkan | ||
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 67183eed8..f300f22c9 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | 13 | ||
| 14 | #include "common/assert.h" | 14 | #include "common/assert.h" |
| 15 | #include "core/settings.h" | 15 | #include "core/settings.h" |
| 16 | #include "video_core/vulkan_common/nsight_aftermath_tracker.h" | ||
| 16 | #include "video_core/vulkan_common/vulkan_device.h" | 17 | #include "video_core/vulkan_common/vulkan_device.h" |
| 17 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 18 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 18 | 19 | ||
| @@ -412,7 +413,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR | |||
| 412 | 413 | ||
| 413 | VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv; | 414 | VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv; |
| 414 | if (nv_device_diagnostics_config) { | 415 | if (nv_device_diagnostics_config) { |
| 415 | nsight_aftermath_tracker.Initialize(); | 416 | nsight_aftermath_tracker = std::make_unique<NsightAftermathTracker>(); |
| 416 | 417 | ||
| 417 | diagnostics_nv = { | 418 | diagnostics_nv = { |
| 418 | .sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV, | 419 | .sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV, |
| @@ -491,7 +492,9 @@ void Device::ReportLoss() const { | |||
| 491 | } | 492 | } |
| 492 | 493 | ||
| 493 | void Device::SaveShader(const std::vector<u32>& spirv) const { | 494 | void Device::SaveShader(const std::vector<u32>& spirv) const { |
| 494 | nsight_aftermath_tracker.SaveShader(spirv); | 495 | if (nsight_aftermath_tracker) { |
| 496 | nsight_aftermath_tracker->SaveShader(spirv); | ||
| 497 | } | ||
| 495 | } | 498 | } |
| 496 | 499 | ||
| 497 | bool Device::IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const { | 500 | bool Device::IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const { |
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index b2651e049..a973c3ce4 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h | |||
| @@ -10,11 +10,12 @@ | |||
| 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" | ||
| 14 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 13 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 15 | 14 | ||
| 16 | namespace Vulkan { | 15 | namespace Vulkan { |
| 17 | 16 | ||
| 17 | class NsightAftermathTracker; | ||
| 18 | |||
| 18 | /// Format usage descriptor. | 19 | /// Format usage descriptor. |
| 19 | enum class FormatType { Linear, Optimal, Buffer }; | 20 | enum class FormatType { Linear, Optimal, Buffer }; |
| 20 | 21 | ||
| @@ -300,7 +301,7 @@ private: | |||
| 300 | std::unordered_map<VkFormat, VkFormatProperties> format_properties; | 301 | std::unordered_map<VkFormat, VkFormatProperties> format_properties; |
| 301 | 302 | ||
| 302 | /// Nsight Aftermath GPU crash tracker | 303 | /// Nsight Aftermath GPU crash tracker |
| 303 | NsightAftermathTracker nsight_aftermath_tracker; | 304 | std::unique_ptr<NsightAftermathTracker> nsight_aftermath_tracker; |
| 304 | }; | 305 | }; |
| 305 | 306 | ||
| 306 | } // namespace Vulkan | 307 | } // namespace Vulkan |