diff options
| -rw-r--r-- | src/video_core/CMakeLists.txt | 19 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/nsight_aftermath_tracker.cpp | 220 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/nsight_aftermath_tracker.h | 87 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_compute_pipeline.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_device.cpp | 35 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_device.h | 14 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_query_cache.cpp | 15 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_rasterizer.cpp | 10 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_scheduler.cpp | 10 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/wrapper.cpp | 18 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/wrapper.h | 34 |
12 files changed, 389 insertions, 77 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) | ||
| 219 | endif() | 218 | endif() |
| 220 | 219 | ||
| 221 | create_target_directory_groups(video_core) | 220 | create_target_directory_groups(video_core) |
| 222 | 221 | ||
| 223 | target_link_libraries(video_core PUBLIC common core) | 222 | target_link_libraries(video_core PUBLIC common core) |
| 224 | target_link_libraries(video_core PRIVATE glad) | 223 | target_link_libraries(video_core PRIVATE glad) |
| 224 | |||
| 225 | if (ENABLE_VULKAN) | 225 | if (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) |
| 227 | endif() | 229 | endif() |
| 228 | 230 | ||
| 231 | if (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") | ||
| 240 | endif() | ||
| 241 | |||
| 229 | if (MSVC) | 242 | if (MSVC) |
| 230 | target_compile_options(video_core PRIVATE /we4267) | 243 | target_compile_options(video_core PRIVATE /we4267) |
| 231 | else() | 244 | else() |
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 | |||
| 31 | namespace Vulkan { | ||
| 32 | |||
| 33 | static constexpr char AFTERMATH_LIB_NAME[] = "GFSDK_Aftermath_Lib.x64.dll"; | ||
| 34 | |||
| 35 | NsightAftermathTracker::NsightAftermathTracker() = default; | ||
| 36 | |||
| 37 | NsightAftermathTracker::~NsightAftermathTracker() { | ||
| 38 | if (initialized) { | ||
| 39 | (void)GFSDK_Aftermath_DisableGpuCrashDumps(); | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 43 | bool 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 | |||
| 90 | void 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 | |||
| 120 | void 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 | |||
| 170 | void 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 | |||
| 195 | void NsightAftermathTracker::OnCrashDumpDescriptionCallback( | ||
| 196 | PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description) { | ||
| 197 | add_description(GFSDK_Aftermath_GpuCrashDumpDescriptionKey_ApplicationName, "yuzu"); | ||
| 198 | } | ||
| 199 | |||
| 200 | void 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 | |||
| 206 | void 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 | |||
| 212 | void 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 | |||
| 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 | bool Initialize(); | ||
| 38 | |||
| 39 | void SaveShader(const std::vector<u32>& spirv) const; | ||
| 40 | |||
| 41 | private: | ||
| 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 | ||
| 79 | inline NsightAftermathTracker::NsightAftermathTracker() = default; | ||
| 80 | inline NsightAftermathTracker::~NsightAftermathTracker() = default; | ||
| 81 | inline bool NsightAftermathTracker::Initialize() { | ||
| 82 | return false; | ||
| 83 | } | ||
| 84 | inline 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 | ||
| 107 | vk::ShaderModule VKComputePipeline::CreateShaderModule(const std::vector<u32>& code) const { | 107 | vk::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 | |||
| 344 | void VKDevice::ReportLoss() const { | 358 | void 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); | 365 | void 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 | ||
| 360 | bool VKDevice::IsOptimalAstcSupported(const VkPhysicalDeviceFeatures& features) const { | 369 | bool 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 60d64572a..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 | ||
| 15 | namespace Vulkan { | 16 | namespace 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; |
| @@ -173,11 +177,6 @@ public: | |||
| 173 | return ext_transform_feedback; | 177 | return ext_transform_feedback; |
| 174 | } | 178 | } |
| 175 | 179 | ||
| 176 | /// Returns true if the device supports VK_NV_device_diagnostic_checkpoints. | ||
| 177 | bool IsNvDeviceDiagnosticCheckpoints() const { | ||
| 178 | return nv_device_diagnostic_checkpoints; | ||
| 179 | } | ||
| 180 | |||
| 181 | /// Returns the vendor name reported from Vulkan. | 180 | /// Returns the vendor name reported from Vulkan. |
| 182 | std::string_view GetVendorName() const { | 181 | std::string_view GetVendorName() const { |
| 183 | return vendor_name; | 182 | return vendor_name; |
| @@ -233,7 +232,7 @@ private: | |||
| 233 | 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. |
| 234 | 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. |
| 235 | bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. | 234 | bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. |
| 236 | 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. |
| 237 | 236 | ||
| 238 | // Telemetry parameters | 237 | // Telemetry parameters |
| 239 | std::string vendor_name; ///< Device's driver name. | 238 | std::string vendor_name; ///< Device's driver name. |
| @@ -241,6 +240,9 @@ private: | |||
| 241 | 240 | ||
| 242 | /// Format properties dictionary. | 241 | /// Format properties dictionary. |
| 243 | 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; | ||
| 244 | }; | 246 | }; |
| 245 | 247 | ||
| 246 | } // 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 343999cf5..8332b42aa 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -148,6 +148,8 @@ std::vector<vk::ShaderModule> VKGraphicsPipeline::CreateShaderModules( | |||
| 148 | continue; | 148 | continue; |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | device.SaveShader(stage->code); | ||
| 152 | |||
| 151 | ci.codeSize = stage->code.size() * sizeof(u32); | 153 | ci.codeSize = stage->code.size() * sizeof(u32); |
| 152 | ci.pCode = stage->code.data(); | 154 | ci.pCode = stage->code.data(); |
| 153 | modules.push_back(device.GetLogical().CreateShaderModule(ci)); | 155 | modules.push_back(device.GetLogical().CreateShaderModule(ci)); |
diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 0966c7ff7..813f7c162 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp | |||
| @@ -113,8 +113,19 @@ u64 HostCounter::BlockingQuery() const { | |||
| 113 | if (ticks >= cache.Scheduler().Ticks()) { | 113 | if (ticks >= cache.Scheduler().Ticks()) { |
| 114 | cache.Scheduler().Flush(); | 114 | cache.Scheduler().Flush(); |
| 115 | } | 115 | } |
| 116 | return cache.Device().GetLogical().GetQueryResult<u64>( | 116 | u64 data; |
| 117 | query.first, query.second, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); | 117 | const VkResult result = cache.Device().GetLogical().GetQueryResults( |
| 118 | query.first, query.second, 1, sizeof(data), &data, sizeof(data), | ||
| 119 | VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT); | ||
| 120 | switch (result) { | ||
| 121 | case VK_SUCCESS: | ||
| 122 | return data; | ||
| 123 | case VK_ERROR_DEVICE_LOST: | ||
| 124 | cache.Device().ReportLoss(); | ||
| 125 | [[fallthrough]]; | ||
| 126 | default: | ||
| 127 | throw vk::Exception(result); | ||
| 128 | } | ||
| 118 | } | 129 | } |
| 119 | 130 | ||
| 120 | } // namespace Vulkan | 131 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 71007bbe8..b58a88664 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -347,11 +347,6 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) { | |||
| 347 | 347 | ||
| 348 | buffer_bindings.Bind(scheduler); | 348 | buffer_bindings.Bind(scheduler); |
| 349 | 349 | ||
| 350 | if (device.IsNvDeviceDiagnosticCheckpoints()) { | ||
| 351 | scheduler.Record( | ||
| 352 | [&pipeline](vk::CommandBuffer cmdbuf) { cmdbuf.SetCheckpointNV(&pipeline); }); | ||
| 353 | } | ||
| 354 | |||
| 355 | BeginTransformFeedback(); | 350 | BeginTransformFeedback(); |
| 356 | 351 | ||
| 357 | const auto pipeline_layout = pipeline.GetLayout(); | 352 | const auto pipeline_layout = pipeline.GetLayout(); |
| @@ -478,11 +473,6 @@ void RasterizerVulkan::DispatchCompute(GPUVAddr code_addr) { | |||
| 478 | TransitionImages(image_views, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, | 473 | TransitionImages(image_views, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, |
| 479 | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); | 474 | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT); |
| 480 | 475 | ||
| 481 | if (device.IsNvDeviceDiagnosticCheckpoints()) { | ||
| 482 | scheduler.Record( | ||
| 483 | [&pipeline](vk::CommandBuffer cmdbuf) { cmdbuf.SetCheckpointNV(nullptr); }); | ||
| 484 | } | ||
| 485 | |||
| 486 | scheduler.Record([grid_x = launch_desc.grid_dim_x, grid_y = launch_desc.grid_dim_y, | 476 | scheduler.Record([grid_x = launch_desc.grid_dim_x, grid_y = launch_desc.grid_dim_y, |
| 487 | grid_z = launch_desc.grid_dim_z, pipeline_handle = pipeline.GetHandle(), | 477 | grid_z = launch_desc.grid_dim_z, pipeline_handle = pipeline.GetHandle(), |
| 488 | layout = pipeline.GetLayout(), | 478 | layout = pipeline.GetLayout(), |
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 900f551b3..ae7ba3eb5 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp | |||
| @@ -166,7 +166,15 @@ void VKScheduler::SubmitExecution(VkSemaphore semaphore) { | |||
| 166 | submit_info.pCommandBuffers = current_cmdbuf.address(); | 166 | submit_info.pCommandBuffers = current_cmdbuf.address(); |
| 167 | submit_info.signalSemaphoreCount = semaphore ? 1 : 0; | 167 | submit_info.signalSemaphoreCount = semaphore ? 1 : 0; |
| 168 | submit_info.pSignalSemaphores = &semaphore; | 168 | submit_info.pSignalSemaphores = &semaphore; |
| 169 | device.GetGraphicsQueue().Submit(submit_info, *current_fence); | 169 | switch (const VkResult result = device.GetGraphicsQueue().Submit(submit_info, *current_fence)) { |
| 170 | case VK_SUCCESS: | ||
| 171 | break; | ||
| 172 | case VK_ERROR_DEVICE_LOST: | ||
| 173 | device.ReportLoss(); | ||
| 174 | [[fallthrough]]; | ||
| 175 | default: | ||
| 176 | vk::Check(result); | ||
| 177 | } | ||
| 170 | } | 178 | } |
| 171 | 179 | ||
| 172 | void VKScheduler::AllocateNewContext() { | 180 | void VKScheduler::AllocateNewContext() { |
diff --git a/src/video_core/renderer_vulkan/wrapper.cpp b/src/video_core/renderer_vulkan/wrapper.cpp index 9b94dfff1..3a52a3a6f 100644 --- a/src/video_core/renderer_vulkan/wrapper.cpp +++ b/src/video_core/renderer_vulkan/wrapper.cpp | |||
| @@ -61,7 +61,6 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { | |||
| 61 | X(vkCmdPipelineBarrier); | 61 | X(vkCmdPipelineBarrier); |
| 62 | X(vkCmdPushConstants); | 62 | X(vkCmdPushConstants); |
| 63 | X(vkCmdSetBlendConstants); | 63 | X(vkCmdSetBlendConstants); |
| 64 | X(vkCmdSetCheckpointNV); | ||
| 65 | X(vkCmdSetDepthBias); | 64 | X(vkCmdSetDepthBias); |
| 66 | X(vkCmdSetDepthBounds); | 65 | X(vkCmdSetDepthBounds); |
| 67 | X(vkCmdSetScissor); | 66 | X(vkCmdSetScissor); |
| @@ -116,7 +115,6 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept { | |||
| 116 | X(vkGetFenceStatus); | 115 | X(vkGetFenceStatus); |
| 117 | X(vkGetImageMemoryRequirements); | 116 | X(vkGetImageMemoryRequirements); |
| 118 | X(vkGetQueryPoolResults); | 117 | X(vkGetQueryPoolResults); |
| 119 | X(vkGetQueueCheckpointDataNV); | ||
| 120 | X(vkMapMemory); | 118 | X(vkMapMemory); |
| 121 | X(vkQueueSubmit); | 119 | X(vkQueueSubmit); |
| 122 | X(vkResetFences); | 120 | X(vkResetFences); |
| @@ -409,17 +407,6 @@ DebugCallback Instance::TryCreateDebugCallback( | |||
| 409 | return DebugCallback(messenger, handle, *dld); | 407 | return DebugCallback(messenger, handle, *dld); |
| 410 | } | 408 | } |
| 411 | 409 | ||
| 412 | std::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 | |||
| 423 | void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { | 410 | void Buffer::BindMemory(VkDeviceMemory memory, VkDeviceSize offset) const { |
| 424 | Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); | 411 | Check(dld->vkBindBufferMemory(owner, handle, memory, offset)); |
| 425 | } | 412 | } |
| @@ -469,12 +456,11 @@ std::vector<VkImage> SwapchainKHR::GetImages() const { | |||
| 469 | } | 456 | } |
| 470 | 457 | ||
| 471 | Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, | 458 | Device Device::Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, |
| 472 | Span<const char*> enabled_extensions, | 459 | Span<const char*> enabled_extensions, const void* next, |
| 473 | const VkPhysicalDeviceFeatures2& enabled_features, | ||
| 474 | DeviceDispatch& dld) noexcept { | 460 | DeviceDispatch& dld) noexcept { |
| 475 | VkDeviceCreateInfo ci; | 461 | VkDeviceCreateInfo ci; |
| 476 | ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; | 462 | ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; |
| 477 | ci.pNext = &enabled_features; | 463 | ci.pNext = next; |
| 478 | ci.flags = 0; | 464 | ci.flags = 0; |
| 479 | ci.queueCreateInfoCount = queues_ci.size(); | 465 | ci.queueCreateInfoCount = queues_ci.size(); |
| 480 | 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 fb3657819..6fe0294d8 100644 --- a/src/video_core/renderer_vulkan/wrapper.h +++ b/src/video_core/renderer_vulkan/wrapper.h | |||
| @@ -197,7 +197,6 @@ struct DeviceDispatch : public InstanceDispatch { | |||
| 197 | PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; | 197 | PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; |
| 198 | PFN_vkCmdPushConstants vkCmdPushConstants; | 198 | PFN_vkCmdPushConstants vkCmdPushConstants; |
| 199 | PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; | 199 | PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; |
| 200 | PFN_vkCmdSetCheckpointNV vkCmdSetCheckpointNV; | ||
| 201 | PFN_vkCmdSetDepthBias vkCmdSetDepthBias; | 200 | PFN_vkCmdSetDepthBias vkCmdSetDepthBias; |
| 202 | PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; | 201 | PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; |
| 203 | PFN_vkCmdSetScissor vkCmdSetScissor; | 202 | PFN_vkCmdSetScissor vkCmdSetScissor; |
| @@ -252,7 +251,6 @@ struct DeviceDispatch : public InstanceDispatch { | |||
| 252 | PFN_vkGetFenceStatus vkGetFenceStatus; | 251 | PFN_vkGetFenceStatus vkGetFenceStatus; |
| 253 | PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; | 252 | PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; |
| 254 | PFN_vkGetQueryPoolResults vkGetQueryPoolResults; | 253 | PFN_vkGetQueryPoolResults vkGetQueryPoolResults; |
| 255 | PFN_vkGetQueueCheckpointDataNV vkGetQueueCheckpointDataNV; | ||
| 256 | PFN_vkMapMemory vkMapMemory; | 254 | PFN_vkMapMemory vkMapMemory; |
| 257 | PFN_vkQueueSubmit vkQueueSubmit; | 255 | PFN_vkQueueSubmit vkQueueSubmit; |
| 258 | PFN_vkResetFences vkResetFences; | 256 | PFN_vkResetFences vkResetFences; |
| @@ -567,12 +565,8 @@ public: | |||
| 567 | /// Construct a queue handle. | 565 | /// Construct a queue handle. |
| 568 | constexpr Queue(VkQueue queue, const DeviceDispatch& dld) noexcept : queue{queue}, dld{&dld} {} | 566 | constexpr Queue(VkQueue queue, const DeviceDispatch& dld) noexcept : queue{queue}, dld{&dld} {} |
| 569 | 567 | ||
| 570 | /// Returns the checkpoint data. | 568 | VkResult Submit(Span<VkSubmitInfo> submit_infos, VkFence fence) const noexcept { |
| 571 | /// @note Returns an empty vector when the function pointer is not present. | 569 | return dld->vkQueueSubmit(queue, submit_infos.size(), submit_infos.data(), fence); |
| 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 | } | 570 | } |
| 577 | 571 | ||
| 578 | VkResult Present(const VkPresentInfoKHR& present_info) const noexcept { | 572 | VkResult Present(const VkPresentInfoKHR& present_info) const noexcept { |
| @@ -659,8 +653,7 @@ class Device : public Handle<VkDevice, NoOwner, DeviceDispatch> { | |||
| 659 | 653 | ||
| 660 | public: | 654 | public: |
| 661 | static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, | 655 | static Device Create(VkPhysicalDevice physical_device, Span<VkDeviceQueueCreateInfo> queues_ci, |
| 662 | Span<const char*> enabled_extensions, | 656 | Span<const char*> enabled_extensions, const void* next, |
| 663 | const VkPhysicalDeviceFeatures2& enabled_features, | ||
| 664 | DeviceDispatch& dld) noexcept; | 657 | DeviceDispatch& dld) noexcept; |
| 665 | 658 | ||
| 666 | Queue GetQueue(u32 family_index) const noexcept; | 659 | Queue GetQueue(u32 family_index) const noexcept; |
| @@ -734,18 +727,11 @@ public: | |||
| 734 | dld->vkResetQueryPoolEXT(handle, query_pool, first, count); | 727 | dld->vkResetQueryPoolEXT(handle, query_pool, first, count); |
| 735 | } | 728 | } |
| 736 | 729 | ||
| 737 | void GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size, | 730 | VkResult GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size, |
| 738 | void* data, VkDeviceSize stride, VkQueryResultFlags flags) const { | 731 | void* data, VkDeviceSize stride, VkQueryResultFlags flags) const |
| 739 | Check(dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride, | 732 | noexcept { |
| 740 | flags)); | 733 | return dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride, |
| 741 | } | 734 | flags); |
| 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 | } | 735 | } |
| 750 | }; | 736 | }; |
| 751 | 737 | ||
| @@ -920,10 +906,6 @@ public: | |||
| 920 | dld->vkCmdPushConstants(handle, layout, flags, offset, size, values); | 906 | dld->vkCmdPushConstants(handle, layout, flags, offset, size, values); |
| 921 | } | 907 | } |
| 922 | 908 | ||
| 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 { | 909 | void SetViewport(u32 first, Span<VkViewport> viewports) const noexcept { |
| 928 | dld->vkCmdSetViewport(handle, first, viewports.size(), viewports.data()); | 910 | dld->vkCmdSetViewport(handle, first, viewports.size(), viewports.data()); |
| 929 | } | 911 | } |