Browse Source
Merge pull request #3653 from ReinUsesLisp/nsight-aftermath
Merge pull request #3653 from ReinUsesLisp/nsight-aftermath
renderer_vulkan: Integrate Nvidia Nsight Aftermath on Windowsnce_cpp
committed by
GitHub
12 changed files with 389 additions and 77 deletions
-
19src/video_core/CMakeLists.txt
-
220src/video_core/renderer_vulkan/nsight_aftermath_tracker.cpp
-
87src/video_core/renderer_vulkan/nsight_aftermath_tracker.h
-
2src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
-
35src/video_core/renderer_vulkan/vk_device.cpp
-
14src/video_core/renderer_vulkan/vk_device.h
-
2src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
-
15src/video_core/renderer_vulkan/vk_query_cache.cpp
-
10src/video_core/renderer_vulkan/vk_rasterizer.cpp
-
10src/video_core/renderer_vulkan/vk_scheduler.cpp
-
18src/video_core/renderer_vulkan/wrapper.cpp
-
34src/video_core/renderer_vulkan/wrapper.h
@ -0,0 +1,220 @@ |
|||
// Copyright 2020 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#ifdef HAS_NSIGHT_AFTERMATH
|
|||
|
|||
#include <mutex>
|
|||
#include <string>
|
|||
#include <string_view>
|
|||
#include <utility>
|
|||
#include <vector>
|
|||
|
|||
#include <fmt/format.h>
|
|||
|
|||
#define VK_NO_PROTOTYPES
|
|||
#include <vulkan/vulkan.h>
|
|||
|
|||
#include <GFSDK_Aftermath.h>
|
|||
#include <GFSDK_Aftermath_Defines.h>
|
|||
#include <GFSDK_Aftermath_GpuCrashDump.h>
|
|||
#include <GFSDK_Aftermath_GpuCrashDumpDecoding.h>
|
|||
|
|||
#include "common/common_paths.h"
|
|||
#include "common/common_types.h"
|
|||
#include "common/file_util.h"
|
|||
#include "common/logging/log.h"
|
|||
#include "common/scope_exit.h"
|
|||
|
|||
#include "video_core/renderer_vulkan/nsight_aftermath_tracker.h"
|
|||
|
|||
namespace Vulkan { |
|||
|
|||
static constexpr char AFTERMATH_LIB_NAME[] = "GFSDK_Aftermath_Lib.x64.dll"; |
|||
|
|||
NsightAftermathTracker::NsightAftermathTracker() = default; |
|||
|
|||
NsightAftermathTracker::~NsightAftermathTracker() { |
|||
if (initialized) { |
|||
(void)GFSDK_Aftermath_DisableGpuCrashDumps(); |
|||
} |
|||
} |
|||
|
|||
bool NsightAftermathTracker::Initialize() { |
|||
if (!dl.Open(AFTERMATH_LIB_NAME)) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath DLL"); |
|||
return false; |
|||
} |
|||
|
|||
if (!dl.GetSymbol("GFSDK_Aftermath_DisableGpuCrashDumps", |
|||
&GFSDK_Aftermath_DisableGpuCrashDumps) || |
|||
!dl.GetSymbol("GFSDK_Aftermath_EnableGpuCrashDumps", |
|||
&GFSDK_Aftermath_EnableGpuCrashDumps) || |
|||
!dl.GetSymbol("GFSDK_Aftermath_GetShaderDebugInfoIdentifier", |
|||
&GFSDK_Aftermath_GetShaderDebugInfoIdentifier) || |
|||
!dl.GetSymbol("GFSDK_Aftermath_GetShaderHashSpirv", &GFSDK_Aftermath_GetShaderHashSpirv) || |
|||
!dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_CreateDecoder", |
|||
&GFSDK_Aftermath_GpuCrashDump_CreateDecoder) || |
|||
!dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_DestroyDecoder", |
|||
&GFSDK_Aftermath_GpuCrashDump_DestroyDecoder) || |
|||
!dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_GenerateJSON", |
|||
&GFSDK_Aftermath_GpuCrashDump_GenerateJSON) || |
|||
!dl.GetSymbol("GFSDK_Aftermath_GpuCrashDump_GetJSON", |
|||
&GFSDK_Aftermath_GpuCrashDump_GetJSON)) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to load Nsight Aftermath function pointers"); |
|||
return false; |
|||
} |
|||
|
|||
dump_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir) + "gpucrash"; |
|||
|
|||
(void)FileUtil::DeleteDirRecursively(dump_dir); |
|||
if (!FileUtil::CreateDir(dump_dir)) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to create Nsight Aftermath dump directory"); |
|||
return false; |
|||
} |
|||
|
|||
if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_EnableGpuCrashDumps( |
|||
GFSDK_Aftermath_Version_API, GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_Vulkan, |
|||
GFSDK_Aftermath_GpuCrashDumpFeatureFlags_Default, GpuCrashDumpCallback, |
|||
ShaderDebugInfoCallback, CrashDumpDescriptionCallback, this))) { |
|||
LOG_ERROR(Render_Vulkan, "GFSDK_Aftermath_EnableGpuCrashDumps failed"); |
|||
return false; |
|||
} |
|||
|
|||
LOG_INFO(Render_Vulkan, "Nsight Aftermath dump directory is \"{}\"", dump_dir); |
|||
|
|||
initialized = true; |
|||
return true; |
|||
} |
|||
|
|||
void NsightAftermathTracker::SaveShader(const std::vector<u32>& spirv) const { |
|||
if (!initialized) { |
|||
return; |
|||
} |
|||
|
|||
std::vector<u32> spirv_copy = spirv; |
|||
GFSDK_Aftermath_SpirvCode shader; |
|||
shader.pData = spirv_copy.data(); |
|||
shader.size = static_cast<u32>(spirv_copy.size() * 4); |
|||
|
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
GFSDK_Aftermath_ShaderHash hash; |
|||
if (!GFSDK_Aftermath_SUCCEED( |
|||
GFSDK_Aftermath_GetShaderHashSpirv(GFSDK_Aftermath_Version_API, &shader, &hash))) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to hash SPIR-V module"); |
|||
return; |
|||
} |
|||
|
|||
FileUtil::IOFile file(fmt::format("{}/source_{:016x}.spv", dump_dir, hash.hash), "wb"); |
|||
if (!file.IsOpen()) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to dump SPIR-V module with hash={:016x}", hash.hash); |
|||
return; |
|||
} |
|||
if (file.WriteArray(spirv.data(), spirv.size()) != spirv.size()) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to write SPIR-V module with hash={:016x}", hash.hash); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
void NsightAftermathTracker::OnGpuCrashDumpCallback(const void* gpu_crash_dump, |
|||
u32 gpu_crash_dump_size) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
LOG_CRITICAL(Render_Vulkan, "called"); |
|||
|
|||
GFSDK_Aftermath_GpuCrashDump_Decoder decoder; |
|||
if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_CreateDecoder( |
|||
GFSDK_Aftermath_Version_API, gpu_crash_dump, gpu_crash_dump_size, &decoder))) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to create decoder"); |
|||
return; |
|||
} |
|||
SCOPE_EXIT({ GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder); }); |
|||
|
|||
u32 json_size = 0; |
|||
if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GpuCrashDump_GenerateJSON( |
|||
decoder, GFSDK_Aftermath_GpuCrashDumpDecoderFlags_ALL_INFO, |
|||
GFSDK_Aftermath_GpuCrashDumpFormatterFlags_NONE, nullptr, nullptr, nullptr, nullptr, |
|||
this, &json_size))) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to generate JSON"); |
|||
return; |
|||
} |
|||
std::vector<char> json(json_size); |
|||
if (!GFSDK_Aftermath_SUCCEED( |
|||
GFSDK_Aftermath_GpuCrashDump_GetJSON(decoder, json_size, json.data()))) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to query JSON"); |
|||
return; |
|||
} |
|||
|
|||
const std::string base_name = [this] { |
|||
const int id = dump_id++; |
|||
if (id == 0) { |
|||
return fmt::format("{}/crash.nv-gpudmp", dump_dir); |
|||
} else { |
|||
return fmt::format("{}/crash_{}.nv-gpudmp", dump_dir, id); |
|||
} |
|||
}(); |
|||
|
|||
std::string_view dump_view(static_cast<const char*>(gpu_crash_dump), gpu_crash_dump_size); |
|||
if (FileUtil::WriteStringToFile(false, base_name, dump_view) != gpu_crash_dump_size) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to write dump file"); |
|||
return; |
|||
} |
|||
const std::string_view json_view(json.data(), json.size()); |
|||
if (FileUtil::WriteStringToFile(true, base_name + ".json", json_view) != json.size()) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to write JSON"); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
void NsightAftermathTracker::OnShaderDebugInfoCallback(const void* shader_debug_info, |
|||
u32 shader_debug_info_size) { |
|||
std::scoped_lock lock{mutex}; |
|||
|
|||
GFSDK_Aftermath_ShaderDebugInfoIdentifier identifier; |
|||
if (!GFSDK_Aftermath_SUCCEED(GFSDK_Aftermath_GetShaderDebugInfoIdentifier( |
|||
GFSDK_Aftermath_Version_API, shader_debug_info, shader_debug_info_size, &identifier))) { |
|||
LOG_ERROR(Render_Vulkan, "GFSDK_Aftermath_GetShaderDebugInfoIdentifier failed"); |
|||
return; |
|||
} |
|||
|
|||
const std::string path = |
|||
fmt::format("{}/shader_{:016x}{:016x}.nvdbg", dump_dir, identifier.id[0], identifier.id[1]); |
|||
FileUtil::IOFile file(path, "wb"); |
|||
if (!file.IsOpen()) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to create file {}", path); |
|||
return; |
|||
} |
|||
if (file.WriteBytes(static_cast<const u8*>(shader_debug_info), shader_debug_info_size) != |
|||
shader_debug_info_size) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to write file {}", path); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
void NsightAftermathTracker::OnCrashDumpDescriptionCallback( |
|||
PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description) { |
|||
add_description(GFSDK_Aftermath_GpuCrashDumpDescriptionKey_ApplicationName, "yuzu"); |
|||
} |
|||
|
|||
void NsightAftermathTracker::GpuCrashDumpCallback(const void* gpu_crash_dump, |
|||
u32 gpu_crash_dump_size, void* user_data) { |
|||
static_cast<NsightAftermathTracker*>(user_data)->OnGpuCrashDumpCallback(gpu_crash_dump, |
|||
gpu_crash_dump_size); |
|||
} |
|||
|
|||
void NsightAftermathTracker::ShaderDebugInfoCallback(const void* shader_debug_info, |
|||
u32 shader_debug_info_size, void* user_data) { |
|||
static_cast<NsightAftermathTracker*>(user_data)->OnShaderDebugInfoCallback( |
|||
shader_debug_info, shader_debug_info_size); |
|||
} |
|||
|
|||
void NsightAftermathTracker::CrashDumpDescriptionCallback( |
|||
PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description, void* user_data) { |
|||
static_cast<NsightAftermathTracker*>(user_data)->OnCrashDumpDescriptionCallback( |
|||
add_description); |
|||
} |
|||
|
|||
} // namespace Vulkan
|
|||
|
|||
#endif // HAS_NSIGHT_AFTERMATH
|
|||
@ -0,0 +1,87 @@ |
|||
// Copyright 2020 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <mutex> |
|||
#include <string> |
|||
#include <vector> |
|||
|
|||
#define VK_NO_PROTOTYPES |
|||
#include <vulkan/vulkan.h> |
|||
|
|||
#ifdef HAS_NSIGHT_AFTERMATH |
|||
#include <GFSDK_Aftermath_Defines.h> |
|||
#include <GFSDK_Aftermath_GpuCrashDump.h> |
|||
#include <GFSDK_Aftermath_GpuCrashDumpDecoding.h> |
|||
#endif |
|||
|
|||
#include "common/common_types.h" |
|||
#include "common/dynamic_library.h" |
|||
|
|||
namespace Vulkan { |
|||
|
|||
class NsightAftermathTracker { |
|||
public: |
|||
NsightAftermathTracker(); |
|||
~NsightAftermathTracker(); |
|||
|
|||
NsightAftermathTracker(const NsightAftermathTracker&) = delete; |
|||
NsightAftermathTracker& operator=(const NsightAftermathTracker&) = delete; |
|||
|
|||
// Delete move semantics because Aftermath initialization uses a pointer to this. |
|||
NsightAftermathTracker(NsightAftermathTracker&&) = delete; |
|||
NsightAftermathTracker& operator=(NsightAftermathTracker&&) = delete; |
|||
|
|||
bool Initialize(); |
|||
|
|||
void SaveShader(const std::vector<u32>& spirv) const; |
|||
|
|||
private: |
|||
#ifdef HAS_NSIGHT_AFTERMATH |
|||
static void GpuCrashDumpCallback(const void* gpu_crash_dump, u32 gpu_crash_dump_size, |
|||
void* user_data); |
|||
|
|||
static void ShaderDebugInfoCallback(const void* shader_debug_info, u32 shader_debug_info_size, |
|||
void* user_data); |
|||
|
|||
static void CrashDumpDescriptionCallback( |
|||
PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description, void* user_data); |
|||
|
|||
void OnGpuCrashDumpCallback(const void* gpu_crash_dump, u32 gpu_crash_dump_size); |
|||
|
|||
void OnShaderDebugInfoCallback(const void* shader_debug_info, u32 shader_debug_info_size); |
|||
|
|||
void OnCrashDumpDescriptionCallback( |
|||
PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription add_description); |
|||
|
|||
mutable std::mutex mutex; |
|||
|
|||
std::string dump_dir; |
|||
int dump_id = 0; |
|||
|
|||
bool initialized = false; |
|||
|
|||
Common::DynamicLibrary dl; |
|||
PFN_GFSDK_Aftermath_DisableGpuCrashDumps GFSDK_Aftermath_DisableGpuCrashDumps; |
|||
PFN_GFSDK_Aftermath_EnableGpuCrashDumps GFSDK_Aftermath_EnableGpuCrashDumps; |
|||
PFN_GFSDK_Aftermath_GetShaderDebugInfoIdentifier GFSDK_Aftermath_GetShaderDebugInfoIdentifier; |
|||
PFN_GFSDK_Aftermath_GetShaderHashSpirv GFSDK_Aftermath_GetShaderHashSpirv; |
|||
PFN_GFSDK_Aftermath_GpuCrashDump_CreateDecoder GFSDK_Aftermath_GpuCrashDump_CreateDecoder; |
|||
PFN_GFSDK_Aftermath_GpuCrashDump_DestroyDecoder GFSDK_Aftermath_GpuCrashDump_DestroyDecoder; |
|||
PFN_GFSDK_Aftermath_GpuCrashDump_GenerateJSON GFSDK_Aftermath_GpuCrashDump_GenerateJSON; |
|||
PFN_GFSDK_Aftermath_GpuCrashDump_GetJSON GFSDK_Aftermath_GpuCrashDump_GetJSON; |
|||
#endif |
|||
}; |
|||
|
|||
#ifndef HAS_NSIGHT_AFTERMATH |
|||
inline NsightAftermathTracker::NsightAftermathTracker() = default; |
|||
inline NsightAftermathTracker::~NsightAftermathTracker() = default; |
|||
inline bool NsightAftermathTracker::Initialize() { |
|||
return false; |
|||
} |
|||
inline void NsightAftermathTracker::SaveShader(const std::vector<u32>&) const {} |
|||
#endif |
|||
|
|||
} // namespace Vulkan |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue