From dc8a779880611e82c461999e3bf279e6d05ead42 Mon Sep 17 00:00:00 2001 From: Justin Kim Date: Tue, 24 Sep 2024 08:03:46 -0700 Subject: [PATCH] Aftermath crash dump support --- CMakeLists.txt | 46 +++++++-- cmake/FindAftermath.cmake | 80 ++++++++++++++++ include/nvrhi/common/aftermath.h | 92 ++++++++++++++++++ include/nvrhi/d3d11.h | 1 + include/nvrhi/d3d12.h | 1 + include/nvrhi/nvrhi.h | 8 +- include/nvrhi/vulkan.h | 1 + src/common/aftermath.cpp | 138 +++++++++++++++++++++++++++ src/d3d11/d3d11-backend.h | 26 ++++- src/d3d11/d3d11-commandlist.cpp | 23 +++++ src/d3d11/d3d11-device.cpp | 43 ++++++++- src/d3d12/d3d12-backend.h | 19 +++- src/d3d12/d3d12-buffer.cpp | 5 + src/d3d12/d3d12-commandlist.cpp | 28 ++++++ src/d3d12/d3d12-device.cpp | 23 ++++- src/d3d12/d3d12-texture.cpp | 5 + src/validation/validation-backend.h | 4 +- src/validation/validation-device.cpp | 14 ++- src/vulkan/vulkan-backend.h | 17 +++- src/vulkan/vulkan-commandlist.cpp | 12 +++ src/vulkan/vulkan-device.cpp | 30 +++++- src/vulkan/vulkan-queries.cpp | 10 ++ src/vulkan/vulkan-queue.cpp | 8 +- 23 files changed, 609 insertions(+), 25 deletions(-) create mode 100644 cmake/FindAftermath.cmake create mode 100644 include/nvrhi/common/aftermath.h create mode 100644 src/common/aftermath.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c60a179..d1e32a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ cmake_dependent_option(NVRHI_INSTALL_EXPORTS "Install CMake exports" OFF "NVRHI_ option(NVRHI_WITH_VALIDATION "Build NVRHI the validation layer" ON) option(NVRHI_WITH_VULKAN "Build the NVRHI Vulkan backend" ON) option(NVRHI_WITH_RTXMU "Use RTXMU for acceleration structure management" OFF) +option(NVRHI_WITH_AFTERMATH "Include Aftermath support (requires NSight Aftermath SDK)" OFF) cmake_dependent_option(NVRHI_WITH_NVAPI "Include NVAPI support (requires NVAPI SDK)" OFF "WIN32" OFF) cmake_dependent_option(NVRHI_WITH_DX11 "Build the NVRHI D3D11 backend" ON "WIN32" OFF) @@ -80,19 +81,36 @@ if (NVRHI_WITH_NVAPI AND NOT TARGET nvapi) endif() endif() +if (NVRHI_WITH_AFTERMATH AND NOT TARGET aftermath) + find_package(Aftermath REQUIRED) + + if (AFTERMATH_FOUND) + add_library(aftermath SHARED IMPORTED GLOBAL) + target_include_directories(aftermath INTERFACE "${AFTERMATH_INCLUDE_DIR}") + if (WIN32) + set_property(TARGET aftermath PROPERTY IMPORTED_IMPLIB "${AFTERMATH_LIBRARY}") + endif() + set_property(TARGET aftermath PROPERTY IMPORTED_LOCATION "${AFTERMATH_RUNTIME_LIBRARY}") + file(COPY ${AFTERMATH_RUNTIME_LIBRARY} DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + else() + message(FATAL_ERROR "NVRHI_WITH_AFTERMATH is enabled but cmake cannot find the Aftermath SDK in AFTERMATH_SEARCH_PATHS") + endif() +endif() set(include_common include/nvrhi/nvrhi.h include/nvrhi/utils.h include/nvrhi/common/containers.h include/nvrhi/common/misc.h - include/nvrhi/common/resource.h) + include/nvrhi/common/resource.h + include/nvrhi/common/aftermath.h) set(src_common src/common/format-info.cpp src/common/misc.cpp src/common/state-tracking.cpp src/common/state-tracking.h - src/common/utils.cpp) + src/common/utils.cpp + src/common/aftermath.cpp) if(MSVC) set(misc_common @@ -208,6 +226,8 @@ target_include_directories(nvrhi PUBLIC set_target_properties(nvrhi PROPERTIES FOLDER "NVRHI") +target_compile_definitions(nvrhi PRIVATE NVRHI_WITH_AFTERMATH=$) + # implementations if (NVRHI_WITH_DX11) @@ -232,10 +252,13 @@ if (NVRHI_WITH_DX11) if (NVRHI_WITH_NVAPI) target_link_libraries(${nvrhi_d3d11_target} PUBLIC nvapi) - target_compile_definitions(${nvrhi_d3d11_target} PRIVATE NVRHI_D3D11_WITH_NVAPI=1) - else() - target_compile_definitions(${nvrhi_d3d11_target} PRIVATE NVRHI_D3D11_WITH_NVAPI=0) endif() + target_compile_definitions(${nvrhi_d3d11_target} PRIVATE NVRHI_D3D11_WITH_NVAPI=$) + + if (NVRHI_WITH_AFTERMATH) + target_link_libraries(${nvrhi_d3d11_target} PUBLIC aftermath) + endif() + target_compile_definitions(${nvrhi_d3d11_target} PRIVATE NVRHI_WITH_AFTERMATH=$) endif() if (NVRHI_WITH_DX12) @@ -265,10 +288,13 @@ if (NVRHI_WITH_DX12) if (NVRHI_WITH_NVAPI) target_link_libraries(${nvrhi_d3d12_target} PUBLIC nvapi) - target_compile_definitions(${nvrhi_d3d12_target} PRIVATE NVRHI_D3D12_WITH_NVAPI=1) - else() - target_compile_definitions(${nvrhi_d3d12_target} PRIVATE NVRHI_D3D12_WITH_NVAPI=0) endif() + target_compile_definitions(${nvrhi_d3d12_target} PRIVATE NVRHI_D3D12_WITH_NVAPI=$) + + if (NVRHI_WITH_AFTERMATH) + target_link_libraries(${nvrhi_d3d12_target} PUBLIC aftermath) + endif() + target_compile_definitions(${nvrhi_d3d12_target} PRIVATE NVRHI_WITH_AFTERMATH=$) endif() if (NVRHI_WITH_VULKAN) @@ -305,6 +331,10 @@ if (NVRHI_WITH_VULKAN) target_link_libraries(${nvrhi_vulkan_target} PRIVATE Vulkan::Headers) endif() + if (NVRHI_WITH_AFTERMATH) + target_link_libraries(${nvrhi_vulkan_target} PUBLIC aftermath) + endif() + target_compile_definitions(${nvrhi_vulkan_target} PRIVATE NVRHI_WITH_AFTERMATH=$) endif() diff --git a/cmake/FindAftermath.cmake b/cmake/FindAftermath.cmake new file mode 100644 index 0000000..9b2ec28 --- /dev/null +++ b/cmake/FindAftermath.cmake @@ -0,0 +1,80 @@ +# +# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + + +find_package(PackageHandleStandardArgs) + + +if (NOT AFTERMATH_SEARCH_PATHS) + set (AFTERMATH_SEARCH_PATHS + "${CMAKE_SOURCE_DIR}/aftermath" + "${CMAKE_PROJECT_DIR}/aftermath") +endif() + +if (WIN32) + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + find_library(AFTERMATH_LIBRARY GFSDK_Aftermath_Lib.x64 + PATHS ${AFTERMATH_SEARCH_PATHS} + PATH_SUFFIXES "lib/x64") + find_file(AFTERMATH_RUNTIME_LIBRARY GFSDK_Aftermath_Lib.x64.dll + PATHS ${AFTERMATH_SEARCH_PATHS} + PATH_SUFFIXES "lib/x64") + else() + find_library(AFTERMATH_LIBRARY GFSDK_Aftermath_Lib.x86 + PATHS ${AFTERMATH_SEARCH_PATHS} + PATH_SUFFIXES "lib/x86") + find_library(AFTERMATH_RUNTIME_LIBRARY GFSDK_Aftermath_Lib.x86.dll + PATHS ${AFTERMATH_SEARCH_PATHS} + PATH_SUFFIXES "lib/x86") + endif() +else() + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + find_library(AFTERMATH_RUNTIME_LIBRARY libGFSDK_Aftermath_Lib.x64.so + PATHS ${AFTERMATH_SEARCH_PATHS} + PATH_SUFFIXES "lib/x64") + else() + find_library(AFTERMATH_RUNTIME_LIBRARY libGFSDK_Aftermath_Lib.x86.so + PATHS ${AFTERMATH_SEARCH_PATHS} + PATH_SUFFIXES "lib/x86") + endif() +endif() + +find_path(AFTERMATH_INCLUDE_DIR GFSDK_Aftermath.h + PATHS ${AFTERMATH_SEARCH_PATHS} + PATH_SUFFIXES "include") + +include(FindPackageHandleStandardArgs) + +if (WIN32) + find_package_handle_standard_args(Aftermath + REQUIRED_VARS + AFTERMATH_INCLUDE_DIR + AFTERMATH_LIBRARY + AFTERMATH_RUNTIME_LIBRARY + ) +else() + find_package_handle_standard_args(Aftermath + REQUIRED_VARS + AFTERMATH_INCLUDE_DIR + AFTERMATH_RUNTIME_LIBRARY + ) +endif() + diff --git a/include/nvrhi/common/aftermath.h b/include/nvrhi/common/aftermath.h new file mode 100644 index 0000000..5f827ca --- /dev/null +++ b/include/nvrhi/common/aftermath.h @@ -0,0 +1,92 @@ +/* +* Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace nvrhi +{ + typedef std::pair> ResolvedMarker; + typedef std::pair BinaryBlob; + typedef std::function ShaderHashGeneratorFunction; + typedef std::function ShaderBinaryLookupCallback; + + // Aftermath will return the payload of the last marker the GPU executed, so in cases of nested regimes, + // we want the marker payloads to represent the whole "stack" of regimes, not just the last one + // AftermathMarkerTracker pushes/pops regimes to this stack + // The payload itself is a 64bit value, so AftermathMarkerTracker stores the mappings of strings<->hashes + // There should be one AftermathMarkerTracker per graphics API-level command list + class AftermathMarkerTracker + { + public: + AftermathMarkerTracker(); + + size_t pushEvent(const char* name); + void popEvent(); + + ResolvedMarker getEventString(size_t hash); + private: + // using a filesystem path to track the event stack since that automatically inserts "/" separators + // and is easy to push/pop entries + std::filesystem::path m_EventStack; + + // Some apps have unique marker text on every frame (for example, by appending the frame number to the marker) + // In these cases, we want to cap the max number of strings stored to prevent memory usage from growing + const static size_t MaxEventStrings = 128; + std::array m_EventHashes; + size_t m_OldestHashIndex; + std::unordered_map m_EventStrings; + }; + + // AftermathCrashDumpHelper tracks all nvrhi::IDevice-level constructs that we need when generating a crash dump + // It provides two services: resolving a marker hash to the original string, and getting the specific shader bytecode + // of a requested shader hash + // There should be one AftermathCrashDumpHelper per nvrhi::IDevice + // All command lists will register their AftermathMarkerTrackers with the AftermathCrashDumpHelper + // Any shader bytecode loading and management code (e.g. donut's ShaderFactory) should register a shader binary lookup callback + class AftermathCrashDumpHelper + { + public: + AftermathCrashDumpHelper(); + + void registerAftermathMarkerTracker(AftermathMarkerTracker* tracker); + void unRegisterAftermathMarkerTracker(AftermathMarkerTracker* tracker); + void registerShaderBinaryLookupCallback(void* client, ShaderBinaryLookupCallback lookupCallback); + void unRegisterShaderBinaryLookupCallback(void* client); + + ResolvedMarker ResolveMarker(size_t markerHash); + BinaryBlob findShaderBinary(uint64_t shaderHash, ShaderHashGeneratorFunction hashGenerator); + private: + std::set m_MarkerTrackers; + // Command lists that are deleted on the CPU-side could still be executing (and crashing) GPU side, + // so we keep around a small number of recently destroyed marker trackers just in case + std::deque m_DestroyedMarkerTrackers; + std::unordered_map m_ShaderBinaryLookupCallbacks; + }; +} // namespace nvrhi \ No newline at end of file diff --git a/include/nvrhi/d3d11.h b/include/nvrhi/d3d11.h index 58d1f79..7b17183 100644 --- a/include/nvrhi/d3d11.h +++ b/include/nvrhi/d3d11.h @@ -41,6 +41,7 @@ namespace nvrhi::d3d11 { IMessageCallback* messageCallback = nullptr; ID3D11DeviceContext* context = nullptr; + bool aftermathEnabled = false; }; NVRHI_API DeviceHandle createDevice(const DeviceDesc& desc); diff --git a/include/nvrhi/d3d12.h b/include/nvrhi/d3d12.h index 6f48853..688f897 100644 --- a/include/nvrhi/d3d12.h +++ b/include/nvrhi/d3d12.h @@ -117,6 +117,7 @@ namespace nvrhi::d3d12 uint32_t shaderResourceViewHeapSize = 16384; uint32_t samplerHeapSize = 1024; uint32_t maxTimerQueries = 256; + bool aftermathEnabled = false; }; NVRHI_API DeviceHandle createDevice(const DeviceDesc& desc); diff --git a/include/nvrhi/nvrhi.h b/include/nvrhi/nvrhi.h index 08d582d..5b40531 100644 --- a/include/nvrhi/nvrhi.h +++ b/include/nvrhi/nvrhi.h @@ -2635,6 +2635,8 @@ namespace nvrhi // IDevice ////////////////////////////////////////////////////////////////////////// + class AftermathCrashDumpHelper; + class IDevice : public IResource { public: @@ -2711,7 +2713,8 @@ namespace nvrhi virtual CommandListHandle createCommandList(const CommandListParameters& params = CommandListParameters()) = 0; virtual uint64_t executeCommandLists(ICommandList* const* pCommandLists, size_t numCommandLists, CommandQueue executionQueue = CommandQueue::Graphics) = 0; virtual void queueWaitForCommandList(CommandQueue waitQueue, CommandQueue executionQueue, uint64_t instance) = 0; - virtual void waitForIdle() = 0; + // returns true if the wait completes successfully, false if detecting a problem (e.g. device removal) + virtual bool waitForIdle() = 0; // Releases the resources that were referenced in the command lists that have finished executing. // IMPORTANT: Call this method at least once per frame. @@ -2725,6 +2728,9 @@ namespace nvrhi virtual IMessageCallback* getMessageCallback() = 0; + virtual bool isAftermathEnabled() = 0; + virtual AftermathCrashDumpHelper& getAftermathCrashDumpHelper() = 0; + // Front-end for executeCommandLists(..., 1) for compatibility and convenience uint64_t executeCommandList(ICommandList* commandList, CommandQueue executionQueue = CommandQueue::Graphics) { diff --git a/include/nvrhi/vulkan.h b/include/nvrhi/vulkan.h index eb6b17a..4aceb28 100644 --- a/include/nvrhi/vulkan.h +++ b/include/nvrhi/vulkan.h @@ -77,6 +77,7 @@ namespace nvrhi::vulkan // Indicates if VkPhysicalDeviceVulkan12Features::bufferDeviceAddress was set to 'true' at device creation time bool bufferDeviceAddressSupported = false; + bool aftermathEnabled = false; }; NVRHI_API DeviceHandle createDevice(const DeviceDesc& desc); diff --git a/src/common/aftermath.cpp b/src/common/aftermath.cpp new file mode 100644 index 0000000..26b6bca --- /dev/null +++ b/src/common/aftermath.cpp @@ -0,0 +1,138 @@ +/* +* Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the "Software"), +* to deal in the Software without restriction, including without limitation +* the rights to use, copy, modify, merge, publish, distribute, sublicense, +* and/or sell copies of the Software, and to permit persons to whom the +* Software is furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +*/ + +#include + +namespace nvrhi +{ + AftermathMarkerTracker::AftermathMarkerTracker() : + m_EventStack{}, + m_EventHashes{}, + m_OldestHashIndex(0), + m_EventStrings{} + { + } + + size_t AftermathMarkerTracker::pushEvent(const char* name) + { + m_EventStack.append(name); + std::string eventString = m_EventStack.generic_string(); + size_t hash = std::hash{}(eventString); + if (m_EventStrings.find(hash) == m_EventStrings.end()) + { + m_EventStrings.erase(m_EventHashes[m_OldestHashIndex]); + m_EventStrings[hash] = eventString; + m_EventHashes[m_OldestHashIndex] = hash; + m_OldestHashIndex = (m_OldestHashIndex + 1) % MaxEventStrings; + } + return hash; + } + + void AftermathMarkerTracker::popEvent() + { + m_EventStack = m_EventStack.parent_path(); + } + + const static std::string NotFoundMarkerString = "ERROR: could not resolve marker"; + + std::pair> AftermathMarkerTracker::getEventString(size_t hash) + { + auto const& found = m_EventStrings.find(hash); + if (found != m_EventStrings.end()) + { + return std::make_pair>(true, found->second); + } + else + { + // could technically return a string literal according to the spec, but compiler complains, so using static + return std::make_pair(false, NotFoundMarkerString); + } + } + + AftermathCrashDumpHelper::AftermathCrashDumpHelper(): + m_MarkerTrackers{}, + m_ShaderBinaryLookupCallbacks{} + { + } + + void AftermathCrashDumpHelper::registerAftermathMarkerTracker(AftermathMarkerTracker* tracker) + { + m_MarkerTrackers.insert(tracker); + } + + void AftermathCrashDumpHelper::unRegisterAftermathMarkerTracker(AftermathMarkerTracker* tracker) + { + // it's possible that a destroyed command list's markers might still be executing on the GPU, + // so will keep the last few of them around to search in case of a crash + const static size_t NumDestroyedMarkerTrackers = 2; + if (m_DestroyedMarkerTrackers.size() >= NumDestroyedMarkerTrackers) + { + m_DestroyedMarkerTrackers.pop_front(); + } + // copying by value to keep the tracker contents after command list is destroyed + m_DestroyedMarkerTrackers.push_back(*tracker); + m_MarkerTrackers.erase(tracker); + } + + void AftermathCrashDumpHelper::registerShaderBinaryLookupCallback(void* client, ShaderBinaryLookupCallback lookupCallback) + { + m_ShaderBinaryLookupCallbacks[client] = lookupCallback; + } + + void AftermathCrashDumpHelper::unRegisterShaderBinaryLookupCallback(void* client) + { + m_ShaderBinaryLookupCallbacks.erase(client); + } + + ResolvedMarker AftermathCrashDumpHelper::ResolveMarker(size_t markerHash) + { + for (auto markerTracker : m_MarkerTrackers) + { + auto [found, markerString] = markerTracker->getEventString(markerHash); + if (found) + return std::make_pair(found, markerString); + } + for (auto markerTracker : m_DestroyedMarkerTrackers) + { + auto [found, markerString] = markerTracker.getEventString(markerHash); + if (found) + return std::make_pair(found, markerString); + } + return std::make_pair(false, NotFoundMarkerString); + } + + BinaryBlob AftermathCrashDumpHelper::findShaderBinary(uint64_t shaderHash, ShaderHashGeneratorFunction hashGenerator) + { + for (auto shaderLookupClientCallback : m_ShaderBinaryLookupCallbacks) + { + auto [ptr, size] = shaderLookupClientCallback.second(shaderHash, hashGenerator); + if (size > 0) + { + return std::make_pair(ptr, size); + } + } + return std::make_pair(nullptr, 0); + } + + + +} // namespace nvrhi \ No newline at end of file diff --git a/src/d3d11/d3d11-backend.h b/src/d3d11/d3d11-backend.h index 686ee77..e32e03a 100644 --- a/src/d3d11/d3d11-backend.h +++ b/src/d3d11/d3d11-backend.h @@ -39,6 +39,11 @@ #include #endif +#include +#if NVRHI_WITH_AFTERMATH +#include +#endif + namespace nvrhi::d3d11 { void SetDebugName(ID3D11DeviceChild* pObject, const char* name); @@ -59,6 +64,9 @@ namespace nvrhi::d3d11 RefCountPtr pushConstantBuffer; IMessageCallback* messageCallback = nullptr; bool nvapiAvailable = false; +#if NVRHI_WITH_AFTERMATH + GFSDK_Aftermath_ContextHandle aftermathContext = nullptr; +#endif void error(const std::string& message) const; }; @@ -277,6 +285,7 @@ namespace nvrhi::d3d11 { public: explicit CommandList(const Context& context, IDevice* device, const CommandListParameters& params); + ~CommandList() override; // IResource implementation @@ -364,6 +373,9 @@ namespace nvrhi::d3d11 CommandListParameters m_Desc; RefCountPtr m_UserDefinedAnnotation; +#if NVRHI_WITH_AFTERMATH + AftermathMarkerTracker m_AftermathTracker; +#endif int m_NumUAVOverlapCommands = 0; void enterUAVOverlapSection(); @@ -410,11 +422,12 @@ namespace nvrhi::d3d11 { public: explicit Device(const DeviceDesc& desc); - + ~Device() override; + // IResource implementation Object getNativeObject(ObjectType objectType) override; - + // IDevice implementation HeapHandle createHeap(const HeapDesc& d) override; @@ -483,16 +496,18 @@ namespace nvrhi::d3d11 rt::AccelStructHandle createAccelStruct(const rt::AccelStructDesc& desc) override; MemoryRequirements getAccelStructMemoryRequirements(rt::IAccelStruct* as) override; bool bindAccelStructMemory(rt::IAccelStruct* as, IHeap* heap, uint64_t offset) override; - + CommandListHandle createCommandList(const CommandListParameters& params = CommandListParameters()) override; uint64_t executeCommandLists(ICommandList* const* pCommandLists, size_t numCommandLists, CommandQueue executionQueue = CommandQueue::Graphics) override { (void)pCommandLists; (void)numCommandLists; (void)executionQueue; return 0; } void queueWaitForCommandList(CommandQueue waitQueue, CommandQueue executionQueue, uint64_t instance) override { (void)waitQueue; (void)executionQueue; (void)instance; } - void waitForIdle() override; + bool waitForIdle() override; void runGarbageCollection() override { } bool queryFeatureSupport(Feature feature, void* pInfo = nullptr, size_t infoSize = 0) override; FormatSupport queryFormatSupport(Format format) override; Object getNativeQueue(ObjectType objectType, CommandQueue queue) override { (void)objectType; (void)queue; return nullptr; } IMessageCallback* getMessageCallback() override { return m_Context.messageCallback; } + bool isAftermathEnabled() override { return m_AftermathEnabled; } + AftermathCrashDumpHelper& getAftermathCrashDumpHelper() override { return m_AftermathCrashDumpHelper; } private: Context m_Context; @@ -514,6 +529,9 @@ namespace nvrhi::d3d11 ID3D11BlendState* getBlendState(const BlendState& blendState); ID3D11DepthStencilState* getDepthStencilState(const DepthStencilState& depthStencilState); ID3D11RasterizerState* getRasterizerState(const RasterState& rasterState); + + bool m_AftermathEnabled = false; + AftermathCrashDumpHelper m_AftermathCrashDumpHelper; }; } // namespace nvrhi::d3d11 diff --git a/src/d3d11/d3d11-commandlist.cpp b/src/d3d11/d3d11-commandlist.cpp index 85f916f..edf5af4 100644 --- a/src/d3d11/d3d11-commandlist.cpp +++ b/src/d3d11/d3d11-commandlist.cpp @@ -31,6 +31,18 @@ namespace nvrhi::d3d11 , m_Desc(params) { m_Context.immediateContext->QueryInterface(IID_PPV_ARGS(&m_UserDefinedAnnotation)); +#if NVRHI_WITH_AFTERMATH + if (m_Device->isAftermathEnabled()) + m_Device->getAftermathCrashDumpHelper().registerAftermathMarkerTracker(&m_AftermathTracker); +#endif + } + + CommandList::~CommandList() + { +#if NVRHI_WITH_AFTERMATH + if (m_Device->isAftermathEnabled()) + m_Device->getAftermathCrashDumpHelper().unRegisterAftermathMarkerTracker(&m_AftermathTracker); +#endif } Object CommandList::getNativeObject(ObjectType objectType) @@ -131,6 +143,13 @@ namespace nvrhi::d3d11 m_UserDefinedAnnotation->BeginEvent(bufW); } +#if NVRHI_WITH_AFTERMATH + if (m_Device->isAftermathEnabled()) + { + const size_t aftermathMarker = m_AftermathTracker.pushEvent(name); + GFSDK_Aftermath_SetEventMarker(m_Context.aftermathContext, (const void*)aftermathMarker, 0); + } +#endif } void CommandList::endMarker() @@ -139,6 +158,10 @@ namespace nvrhi::d3d11 { m_UserDefinedAnnotation->EndEvent(); } +#if NVRHI_WITH_AFTERMATH + if (m_Device->isAftermathEnabled()) + m_AftermathTracker.popEvent(); +#endif } static char g_PushConstantPaddingBuffer[c_MaxPushConstantSize] = {}; diff --git a/src/d3d11/d3d11-device.cpp b/src/d3d11/d3d11-device.cpp index 1dda2a6..4cfc195 100644 --- a/src/d3d11/d3d11-device.cpp +++ b/src/d3d11/d3d11-device.cpp @@ -74,6 +74,29 @@ namespace nvrhi::d3d11 } #endif +#if NVRHI_WITH_AFTERMATH + if (desc.aftermathEnabled) + { + auto CheckAftermathResult = [this](GFSDK_Aftermath_Result result) + { + if (!GFSDK_Aftermath_SUCCEED(result)) + { + std::stringstream ss; + ss << "Aftermath initialize call failed, result = 0x" << std::hex << std::setw(8) << result; + m_Context.error(ss.str()); + return false; + } + return true; + }; + const uint32_t aftermathFlags = GFSDK_Aftermath_FeatureFlags_EnableMarkers | GFSDK_Aftermath_FeatureFlags_EnableResourceTracking | GFSDK_Aftermath_FeatureFlags_GenerateShaderDebugInfo | GFSDK_Aftermath_FeatureFlags_EnableShaderErrorReporting; + bool success = CheckAftermathResult(GFSDK_Aftermath_DX11_Initialize(GFSDK_Aftermath_Version_API, aftermathFlags, m_Context.device)); + if (success) + success = CheckAftermathResult(GFSDK_Aftermath_DX11_CreateContextHandle(m_Context.immediateContext, &m_Context.aftermathContext)); + if (success) + m_AftermathEnabled = true; + } +#endif + D3D11_BUFFER_DESC bufferDesc = {}; bufferDesc.ByteWidth = c_MaxPushConstantSize; bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; @@ -91,6 +114,21 @@ namespace nvrhi::d3d11 m_ImmediateCommandList = CommandListHandle::Create(new CommandList(m_Context, this, CommandListParameters())); } + Device::~Device() + { + // Release the command list so that it unregisters the Aftermath marker tracker before the device is destroyed + m_ImmediateCommandList = nullptr; + +#if NVRHI_WITH_AFTERMATH + if (m_Context.aftermathContext) + { + GFSDK_Aftermath_ReleaseContextHandle(m_Context.aftermathContext); + m_Context.aftermathContext = nullptr; + } + m_AftermathEnabled = false; +#endif + } + GraphicsAPI Device::getGraphicsAPI() { return GraphicsAPI::D3D11; @@ -243,7 +281,7 @@ namespace nvrhi::d3d11 return nullptr; } - void Device::waitForIdle() + bool Device::waitForIdle() { if (!m_WaitForIdleQuery) { @@ -251,11 +289,12 @@ namespace nvrhi::d3d11 } if (!m_WaitForIdleQuery) - return; + return false; setEventQuery(m_WaitForIdleQuery, CommandQueue::Graphics); waitEventQuery(m_WaitForIdleQuery); resetEventQuery(m_WaitForIdleQuery); + return true; } SamplerHandle Device::createSampler(const SamplerDesc& d) diff --git a/src/d3d12/d3d12-backend.h b/src/d3d12/d3d12-backend.h index 1fe6556..9acc9ef 100644 --- a/src/d3d12/d3d12-backend.h +++ b/src/d3d12/d3d12-backend.h @@ -33,6 +33,11 @@ #include #endif +#include +#if NVRHI_WITH_AFTERMATH +#include +#endif + // There's no version check available in the nvapi header, // instead to check if the NvAPI linked is OMM compatible version (>520) we look for one of the defines it adds... #if NVRHI_D3D12_WITH_NVAPI && defined(NVAPI_GET_RAYTRACING_OPACITY_MICROMAP_ARRAY_PREBUILD_INFO_PARAMS_VER) @@ -829,6 +834,9 @@ namespace nvrhi::d3d12 RefCountPtr commandList4; RefCountPtr commandList6; uint64_t lastSubmittedInstance = 0; +#if NVRHI_WITH_AFTERMATH + GFSDK_Aftermath_ContextHandle aftermathContext; +#endif }; class CommandListInstance @@ -857,6 +865,7 @@ namespace nvrhi::d3d12 // Internal interface functions CommandList(class Device* device, const Context& context, DeviceResources& resources, const CommandListParameters& params); + ~CommandList() override; std::shared_ptr executed(Queue* pQueue); void requireTextureState(ITexture* texture, TextureSubresourceSet subresources, ResourceStates state); void requireBufferState(IBuffer* buffer, ResourceStates state); @@ -977,6 +986,9 @@ namespace nvrhi::d3d12 std::list> m_CommandListPool; std::shared_ptr m_Instance; uint64_t m_RecordingVersion = 0; +#if NVRHI_WITH_AFTERMATH + AftermathMarkerTracker m_AftermathTracker; +#endif // Cache for user-provided state @@ -1102,12 +1114,14 @@ namespace nvrhi::d3d12 nvrhi::CommandListHandle createCommandList(const CommandListParameters& params = CommandListParameters()) override; uint64_t executeCommandLists(nvrhi::ICommandList* const* pCommandLists, size_t numCommandLists, CommandQueue executionQueue = CommandQueue::Graphics) override; void queueWaitForCommandList(CommandQueue waitQueue, CommandQueue executionQueue, uint64_t instance) override; - void waitForIdle() override; + bool waitForIdle() override; void runGarbageCollection() override; bool queryFeatureSupport(Feature feature, void* pInfo = nullptr, size_t infoSize = 0) override; FormatSupport queryFormatSupport(Format format) override; Object getNativeQueue(ObjectType objectType, CommandQueue queue) override; IMessageCallback* getMessageCallback() override { return m_Context.messageCallback; } + bool isAftermathEnabled() override { return m_AftermathEnabled; } + AftermathCrashDumpHelper& getAftermathCrashDumpHelper() override { return m_AftermathCrashDumpHelper; } // d3d12::IDevice implementation @@ -1146,6 +1160,8 @@ namespace nvrhi::d3d12 bool m_VariableRateShadingSupported = false; bool m_OpacityMicromapSupported = false; bool m_ShaderExecutionReorderingSupported = false; + bool m_AftermathEnabled = false; + AftermathCrashDumpHelper m_AftermathCrashDumpHelper; D3D12_FEATURE_DATA_D3D12_OPTIONS m_Options = {}; D3D12_FEATURE_DATA_D3D12_OPTIONS5 m_Options5 = {}; @@ -1156,6 +1172,7 @@ namespace nvrhi::d3d12 RefCountPtr createPipelineState(const GraphicsPipelineDesc& desc, RootSignature* pRS, const FramebufferInfo& fbinfo) const; RefCountPtr createPipelineState(const ComputePipelineDesc& desc, RootSignature* pRS) const; RefCountPtr createPipelineState(const MeshletPipelineDesc& desc, RootSignature* pRS, const FramebufferInfo& fbinfo) const; + }; } // namespace nvrhi::d3d12 diff --git a/src/d3d12/d3d12-buffer.cpp b/src/d3d12/d3d12-buffer.cpp index 59ccd54..0cbc3a8 100644 --- a/src/d3d12/d3d12-buffer.cpp +++ b/src/d3d12/d3d12-buffer.cpp @@ -176,6 +176,11 @@ namespace nvrhi::d3d12 { std::wstring wname(desc.debugName.begin(), desc.debugName.end()); resource->SetName(wname.c_str()); +#if NVRHI_WITH_AFTERMATH + // the driver will track the resource internally so don't need to keep the handle around + GFSDK_Aftermath_ResourceHandle resourceHandle = {}; + GFSDK_Aftermath_DX12_RegisterResource(resource, &resourceHandle); +#endif } } diff --git a/src/d3d12/d3d12-commandlist.cpp b/src/d3d12/d3d12-commandlist.cpp index 0698172..0bb8afc 100644 --- a/src/d3d12/d3d12-commandlist.cpp +++ b/src/d3d12/d3d12-commandlist.cpp @@ -38,6 +38,18 @@ namespace nvrhi::d3d12 , m_StateTracker(context.messageCallback) , m_Desc(params) { +#if NVRHI_WITH_AFTERMATH + if (m_Device->isAftermathEnabled()) + m_Device->getAftermathCrashDumpHelper().registerAftermathMarkerTracker(&m_AftermathTracker); +#endif + } + + CommandList::~CommandList() + { +#if NVRHI_WITH_AFTERMATH + if (m_Device->isAftermathEnabled()) + m_Device->getAftermathCrashDumpHelper().unRegisterAftermathMarkerTracker(&m_AftermathTracker); +#endif } Object CommandList::getNativeObject(ObjectType objectType) @@ -93,6 +105,11 @@ namespace nvrhi::d3d12 commandList->commandList->QueryInterface(IID_PPV_ARGS(&commandList->commandList4)); commandList->commandList->QueryInterface(IID_PPV_ARGS(&commandList->commandList6)); +#if NVRHI_WITH_AFTERMATH + if (m_Device->isAftermathEnabled()) + GFSDK_Aftermath_DX12_CreateContextHandle(commandList->commandList, &commandList->aftermathContext); +#endif + return commandList; } @@ -153,11 +170,22 @@ namespace nvrhi::d3d12 void CommandList::beginMarker(const char* name) { PIXBeginEvent(m_ActiveCommandList->commandList, 0, name); +#if NVRHI_WITH_AFTERMATH + if (m_Device->isAftermathEnabled()) + { + const size_t aftermathMarker = m_AftermathTracker.pushEvent(name); + GFSDK_Aftermath_SetEventMarker(m_ActiveCommandList->aftermathContext, (const void*)aftermathMarker, 0); + } +#endif } void CommandList::endMarker() { PIXEndEvent(m_ActiveCommandList->commandList); +#if NVRHI_WITH_AFTERMATH + if (m_Device->isAftermathEnabled()) + m_AftermathTracker.popEvent(); +#endif } void CommandList::setPushConstants(const void* data, size_t byteSize) diff --git a/src/d3d12/d3d12-device.cpp b/src/d3d12/d3d12-device.cpp index c9900fb..98c0291 100644 --- a/src/d3d12/d3d12-device.cpp +++ b/src/d3d12/d3d12-device.cpp @@ -208,6 +208,24 @@ namespace nvrhi::d3d12 #endif // #if NVRHI_WITH_NVAPI_OPACITY_MICROMAPS #endif // #if NVRHI_D3D12_WITH_NVAPI + +#if NVRHI_WITH_AFTERMATH + if (desc.aftermathEnabled) + { + const uint32_t aftermathFlags = GFSDK_Aftermath_FeatureFlags_EnableMarkers | GFSDK_Aftermath_FeatureFlags_EnableResourceTracking | GFSDK_Aftermath_FeatureFlags_GenerateShaderDebugInfo | GFSDK_Aftermath_FeatureFlags_EnableShaderErrorReporting; + GFSDK_Aftermath_Result aftermathResult = GFSDK_Aftermath_DX12_Initialize(GFSDK_Aftermath_Version_API, aftermathFlags, m_Context.device); + if (!GFSDK_Aftermath_SUCCEED(aftermathResult)) + { + std::stringstream ss; + ss << "Aftermath initialize call failed, result = 0x" << std::hex << std::setw(8) << aftermathResult; + m_Context.error(ss.str()); + } + else + { + m_AftermathEnabled = true; + } + } +#endif } Device::~Device() @@ -221,7 +239,7 @@ namespace nvrhi::d3d12 } } - void Device::waitForIdle() + bool Device::waitForIdle() { // Wait for every queue to reach its last submitted instance for (const auto& pQueue : m_Queues) @@ -234,6 +252,7 @@ namespace nvrhi::d3d12 WaitForFence(pQueue->fence, pQueue->lastSubmittedInstance, m_FenceEvent); } } + return true; } Object RootSignature::getNativeObject(ObjectType objectType) @@ -345,7 +364,7 @@ namespace nvrhi::d3d12 HRESULT hr = m_Context.device->GetDeviceRemovedReason(); if (FAILED(hr)) { - m_Context.messageCallback->message(MessageSeverity::Fatal, "Device Removed!"); + m_Context.messageCallback->message(MessageSeverity::Error, "Device Removed!"); } return pQueue->lastSubmittedInstance; diff --git a/src/d3d12/d3d12-texture.cpp b/src/d3d12/d3d12-texture.cpp index 2445202..1672ba5 100644 --- a/src/d3d12/d3d12-texture.cpp +++ b/src/d3d12/d3d12-texture.cpp @@ -444,6 +444,11 @@ namespace nvrhi::d3d12 { std::wstring wname(desc.debugName.begin(), desc.debugName.end()); resource->SetName(wname.c_str()); +#if NVRHI_WITH_AFTERMATH + // the driver will track the resource internally so don't need to keep the handle around + GFSDK_Aftermath_ResourceHandle resourceHandle = {}; + GFSDK_Aftermath_DX12_RegisterResource(resource, &resourceHandle); +#endif } if (desc.isUAV) diff --git a/src/validation/validation-backend.h b/src/validation/validation-backend.h index 63205fa..52a317f 100644 --- a/src/validation/validation-backend.h +++ b/src/validation/validation-backend.h @@ -318,12 +318,14 @@ namespace nvrhi::validation CommandListHandle createCommandList(const CommandListParameters& params = CommandListParameters()) override; uint64_t executeCommandLists(ICommandList* const* pCommandLists, size_t numCommandLists, CommandQueue executionQueue = CommandQueue::Graphics) override; void queueWaitForCommandList(CommandQueue waitQueue, CommandQueue executionQueue, uint64_t instance) override; - void waitForIdle() override; + bool waitForIdle() override; void runGarbageCollection() override; bool queryFeatureSupport(Feature feature, void* pInfo = nullptr, size_t infoSize = 0) override; FormatSupport queryFormatSupport(Format format) override; Object getNativeQueue(ObjectType objectType, CommandQueue queue) override; IMessageCallback* getMessageCallback() override; + bool isAftermathEnabled() override; + AftermathCrashDumpHelper& getAftermathCrashDumpHelper() override; }; } // namespace nvrhi::validation diff --git a/src/validation/validation-device.cpp b/src/validation/validation-device.cpp index f2420c5..b7c38e3 100644 --- a/src/validation/validation-device.cpp +++ b/src/validation/validation-device.cpp @@ -1906,9 +1906,9 @@ namespace nvrhi::validation m_Device->queueWaitForCommandList(waitQueue, executionQueue, instance); } - void DeviceWrapper::waitForIdle() + bool DeviceWrapper::waitForIdle() { - m_Device->waitForIdle(); + return m_Device->waitForIdle(); } void DeviceWrapper::runGarbageCollection() @@ -1936,6 +1936,16 @@ namespace nvrhi::validation return m_MessageCallback; } + bool DeviceWrapper::isAftermathEnabled() + { + return m_Device->isAftermathEnabled(); + } + + AftermathCrashDumpHelper& DeviceWrapper::getAftermathCrashDumpHelper() + { + return m_Device->getAftermathCrashDumpHelper(); + } + void Range::add(uint32_t item) { min = std::min(min, item); diff --git a/src/vulkan/vulkan-backend.h b/src/vulkan/vulkan-backend.h index 672a5a1..f9cf394 100644 --- a/src/vulkan/vulkan-backend.h +++ b/src/vulkan/vulkan-backend.h @@ -24,6 +24,7 @@ #include #include +#include #include "../common/state-tracking.h" #include "../common/versioning.h" #include @@ -171,6 +172,11 @@ namespace nvrhi::vulkan bool EXT_conservative_rasterization = false; bool EXT_opacity_micromap = false; bool NV_ray_tracing_invocation_reorder = false; +#if NVRHI_WITH_AFTERMATH + bool EXT_debug_utils = false; + bool NV_device_diagnostic_checkpoints = false; + bool NV_device_diagnostics_config= false; +#endif } extensions; vk::PhysicalDeviceProperties physicalDeviceProperties; @@ -1128,12 +1134,14 @@ namespace nvrhi::vulkan CommandListHandle createCommandList(const CommandListParameters& params = CommandListParameters()) override; uint64_t executeCommandLists(ICommandList* const* pCommandLists, size_t numCommandLists, CommandQueue executionQueue = CommandQueue::Graphics) override; void queueWaitForCommandList(CommandQueue waitQueue, CommandQueue executionQueue, uint64_t instance) override; - void waitForIdle() override; + bool waitForIdle() override; void runGarbageCollection() override; bool queryFeatureSupport(Feature feature, void* pInfo = nullptr, size_t infoSize = 0) override; FormatSupport queryFormatSupport(Format format) override; Object getNativeQueue(ObjectType objectType, CommandQueue queue) override; IMessageCallback* getMessageCallback() override { return m_Context.messageCallback; } + bool isAftermathEnabled() override { return m_AftermathEnabled; } + AftermathCrashDumpHelper& getAftermathCrashDumpHelper() override { return m_AftermathCrashDumpHelper; } // vulkan::IDevice implementation VkSemaphore getQueueSemaphore(CommandQueue queue) override; @@ -1156,6 +1164,8 @@ namespace nvrhi::vulkan std::array, uint32_t(CommandQueue::Count)> m_Queues; void *mapBuffer(IBuffer* b, CpuAccessMode flags, uint64_t offset, size_t size) const; + bool m_AftermathEnabled = false; + AftermathCrashDumpHelper m_AftermathCrashDumpHelper; }; class CommandList : public RefCounter @@ -1164,6 +1174,7 @@ namespace nvrhi::vulkan // Internal backend methods CommandList(Device* device, const VulkanContext& context, const CommandListParameters& parameters); + ~CommandList() override; void executed(Queue& queue, uint64_t submissionID); @@ -1260,6 +1271,10 @@ namespace nvrhi::vulkan // current internal command buffer TrackedCommandBufferPtr m_CurrentCmdBuf = nullptr; +#if NVRHI_WITH_AFTERMATH + AftermathMarkerTracker m_AftermathTracker; +#endif + vk::PipelineLayout m_CurrentPipelineLayout; vk::ShaderStageFlags m_CurrentPushConstantsVisibility; GraphicsState m_CurrentGraphicsState{}; diff --git a/src/vulkan/vulkan-commandlist.cpp b/src/vulkan/vulkan-commandlist.cpp index c23249b..bbe92cd 100644 --- a/src/vulkan/vulkan-commandlist.cpp +++ b/src/vulkan/vulkan-commandlist.cpp @@ -33,6 +33,18 @@ namespace nvrhi::vulkan , m_UploadManager(std::make_unique(device, parameters.uploadChunkSize, 0, false)) , m_ScratchManager(std::make_unique(device, parameters.scratchChunkSize, parameters.scratchMaxMemory, true)) { +#if NVRHI_WITH_AFTERMATH + if (m_Device->isAftermathEnabled()) + m_Device->getAftermathCrashDumpHelper().registerAftermathMarkerTracker(&m_AftermathTracker); +#endif + } + + CommandList::~CommandList() + { +#if NVRHI_WITH_AFTERMATH + if (m_Device->isAftermathEnabled()) + m_Device->getAftermathCrashDumpHelper().unRegisterAftermathMarkerTracker(&m_AftermathTracker); +#endif } nvrhi::Object CommandList::getNativeObject(ObjectType objectType) diff --git a/src/vulkan/vulkan-device.cpp b/src/vulkan/vulkan-device.cpp index bec6acd..a2f96f5 100644 --- a/src/vulkan/vulkan-device.cpp +++ b/src/vulkan/vulkan-device.cpp @@ -84,6 +84,11 @@ namespace nvrhi::vulkan { VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, &m_Context.extensions.KHR_fragment_shading_rate }, { VK_EXT_OPACITY_MICROMAP_EXTENSION_NAME, &m_Context.extensions.EXT_opacity_micromap }, { VK_NV_RAY_TRACING_INVOCATION_REORDER_EXTENSION_NAME, &m_Context.extensions.NV_ray_tracing_invocation_reorder }, +#if NVRHI_WITH_AFTERMATH + { VK_EXT_DEBUG_UTILS_EXTENSION_NAME, &m_Context.extensions.EXT_debug_utils }, + { VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME, &m_Context.extensions.NV_device_diagnostic_checkpoints }, + { VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME, &m_Context.extensions.NV_device_diagnostics_config } +#endif }; // parse the extension/layer lists and figure out which extensions are enabled @@ -220,6 +225,10 @@ namespace nvrhi::vulkan { m_Context.error("Failed to create an empty descriptor set layout"); } + +#if NVRHI_WITH_AFTERMATH + m_AftermathEnabled = desc.aftermathEnabled; +#endif } Device::~Device() @@ -259,9 +268,16 @@ namespace nvrhi::vulkan return GraphicsAPI::VULKAN; } - void Device::waitForIdle() + bool Device::waitForIdle() { - m_Context.device.waitIdle(); + try { + m_Context.device.waitIdle(); + } + catch (vk::DeviceLostError e) + { + return false; + } + return true; } void Device::runGarbageCollection() @@ -498,6 +514,16 @@ namespace nvrhi::vulkan (void)device.debugMarkerSetObjectNameEXT(&info); } +#if NVRHI_WITH_AFTERMATH + if (extensions.EXT_debug_utils && name && *name) + { + auto info = vk::DebugUtilsObjectNameInfoEXT() + .setObjectType(vk::ObjectType::eUnknown) + .setObjectHandle(reinterpret_cast(handle)) + .setPObjectName(name); + device.setDebugUtilsObjectNameEXT(info); + } +#endif } void VulkanContext::error(const std::string& message) const diff --git a/src/vulkan/vulkan-queries.cpp b/src/vulkan/vulkan-queries.cpp index f8255ef..06593f5 100644 --- a/src/vulkan/vulkan-queries.cpp +++ b/src/vulkan/vulkan-queries.cpp @@ -217,6 +217,13 @@ namespace nvrhi::vulkan .setPMarkerName(name); m_CurrentCmdBuf->cmdBuf.debugMarkerBeginEXT(&markerInfo); } +#if NVRHI_WITH_AFTERMATH + if (m_Device->isAftermathEnabled()) + { + const size_t aftermathMarker = m_AftermathTracker.pushEvent(name); + m_CurrentCmdBuf->cmdBuf.setCheckpointNV((const void*)aftermathMarker); + } +#endif } void CommandList::endMarker() @@ -227,6 +234,9 @@ namespace nvrhi::vulkan m_CurrentCmdBuf->cmdBuf.debugMarkerEndEXT(); } +#if NVRHI_WITH_AFTERMATH + m_AftermathTracker.popEvent(); +#endif } } // namespace nvrhi::vulkan \ No newline at end of file diff --git a/src/vulkan/vulkan-queue.cpp b/src/vulkan/vulkan-queue.cpp index f77355f..b719b41 100644 --- a/src/vulkan/vulkan-queue.cpp +++ b/src/vulkan/vulkan-queue.cpp @@ -167,7 +167,13 @@ namespace nvrhi::vulkan .setSignalSemaphoreCount(uint32_t(m_SignalSemaphores.size())) .setPSignalSemaphores(m_SignalSemaphores.data()); - m_Queue.submit(submitInfo); + try { + m_Queue.submit(submitInfo); + } + catch (vk::DeviceLostError e) + { + m_Context.messageCallback->message(MessageSeverity::Error, "Device Removed!"); + } m_WaitSemaphores.clear(); m_WaitSemaphoreValues.clear();