adding aftermath debugging and fixing forward plus
This commit is contained in:
@@ -162,7 +162,7 @@ typedef uint32 KeyModifierFlags;
|
||||
namespace Gfx
|
||||
{
|
||||
static constexpr bool useAsyncCompute = true;
|
||||
static constexpr bool waitIdleOnSubmit = false;
|
||||
static constexpr bool waitIdleOnSubmit = true;
|
||||
static constexpr uint32 numFramesBuffered = 8;
|
||||
extern uint32 currentFrameIndex;
|
||||
extern double currentFrameDelta;
|
||||
|
||||
@@ -212,13 +212,25 @@ bool UniformBuffer::updateContents(const BulkResourceData& resourceData)
|
||||
return true;
|
||||
}
|
||||
|
||||
StructuredBuffer::StructuredBuffer(QueueFamilyMapping mapping, QueueType startQueueType)
|
||||
: Buffer(mapping, startQueueType)
|
||||
StructuredBuffer::StructuredBuffer(QueueFamilyMapping mapping, const BulkResourceData& resourceData)
|
||||
: Buffer(mapping, resourceData.owner)
|
||||
, contents(resourceData.size)
|
||||
{
|
||||
}
|
||||
StructuredBuffer::~StructuredBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
bool StructuredBuffer::updateContents(const BulkResourceData& resourceData)
|
||||
{
|
||||
assert(contents.size() == resourceData.size);
|
||||
if(std::memcmp(contents.data(), resourceData.data, contents.size()) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::memcpy(contents.data(), resourceData.data, contents.size());
|
||||
return true;
|
||||
}
|
||||
VertexBuffer::VertexBuffer(QueueFamilyMapping mapping, uint32 numVertices, uint32 vertexSize, QueueType startQueueType)
|
||||
: Buffer(mapping, startQueueType)
|
||||
, numVertices(numVertices)
|
||||
|
||||
@@ -405,9 +405,27 @@ DEFINE_REF(IndexBuffer)
|
||||
class StructuredBuffer : public Buffer
|
||||
{
|
||||
public:
|
||||
StructuredBuffer(QueueFamilyMapping mapping, QueueType startQueueType);
|
||||
StructuredBuffer(QueueFamilyMapping mapping, const BulkResourceData& bulkResourceData);
|
||||
virtual ~StructuredBuffer();
|
||||
virtual bool updateContents(const BulkResourceData& resourceData);
|
||||
bool isDataEquals(StructuredBuffer* other)
|
||||
{
|
||||
if(other == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(contents.size() != other->contents.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(std::memcmp(contents.data(), other->contents.data(), contents.size()) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
protected:
|
||||
Array<uint8> contents;
|
||||
// Inherited via QueueOwnedResource
|
||||
virtual void executeOwnershipBarrier(QueueType newOwner) = 0;
|
||||
virtual void executePipelineBarrier(SeAccessFlags srcAccess, SePipelineStageFlags srcStage,
|
||||
|
||||
@@ -92,7 +92,7 @@ BasePass::BasePass(PRenderGraph renderGraph, const PScene scene, Gfx::PGraphics
|
||||
basePassLayout = graphics->createPipelineLayout();
|
||||
|
||||
lightLayout = graphics->createDescriptorLayout("LightLayout");
|
||||
lightLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
lightLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
|
||||
lightLayout->addDescriptorBinding(1, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
lightLayout->addDescriptorBinding(2, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_IMAGE);
|
||||
lightLayout->create();
|
||||
@@ -133,6 +133,10 @@ void BasePass::beginFrame()
|
||||
uniformUpdate.size = sizeof(ViewParameter);
|
||||
uniformUpdate.data = (uint8*)&viewParams;
|
||||
viewParamBuffer->updateContents(uniformUpdate);
|
||||
viewLayout->reset();
|
||||
lightLayout->reset();
|
||||
descriptorSets[INDEX_LIGHT_ENV] = lightLayout->allocateDescriptorSet();
|
||||
descriptorSets[INDEX_VIEW_PARAMS] = viewLayout->allocateDescriptorSet();
|
||||
descriptorSets[INDEX_VIEW_PARAMS]->updateBuffer(0, viewParamBuffer);
|
||||
descriptorSets[INDEX_VIEW_PARAMS]->writeChanges();
|
||||
for(auto &&meshBatch : scene->getStaticMeshes())
|
||||
@@ -143,7 +147,6 @@ void BasePass::beginFrame()
|
||||
|
||||
void BasePass::render()
|
||||
{
|
||||
descriptorSets[INDEX_LIGHT_ENV]->updateBuffer(0, scene->getLightBuffer());
|
||||
|
||||
oLightIndexList->pipelineBarrier(
|
||||
Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
@@ -151,6 +154,8 @@ void BasePass::render()
|
||||
oLightGrid->pipelineBarrier(
|
||||
Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||
|
||||
descriptorSets[INDEX_LIGHT_ENV]->updateBuffer(0, scene->getLightBuffer());
|
||||
descriptorSets[INDEX_LIGHT_ENV]->updateBuffer(1, oLightIndexList);
|
||||
descriptorSets[INDEX_LIGHT_ENV]->updateTexture(2, oLightGrid);
|
||||
descriptorSets[INDEX_LIGHT_ENV]->writeChanges();
|
||||
|
||||
@@ -99,7 +99,6 @@ DepthPrepass::DepthPrepass(PRenderGraph renderGraph, const PScene scene, Gfx::PG
|
||||
viewParamBuffer = graphics->createUniformBuffer(uniformInitializer);
|
||||
viewLayout->create();
|
||||
depthPrepassLayout->addDescriptorLayout(INDEX_VIEW_PARAMS, viewLayout);
|
||||
descriptorSets[INDEX_VIEW_PARAMS] = viewLayout->allocateDescriptorSet();
|
||||
|
||||
primitiveLayout = graphics->createDescriptorLayout("PrimitiveLayout");
|
||||
primitiveLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
|
||||
@@ -125,6 +124,8 @@ void DepthPrepass::beginFrame()
|
||||
uniformUpdate.size = sizeof(ViewParameter);
|
||||
uniformUpdate.data = (uint8*)&viewParams;
|
||||
viewParamBuffer->updateContents(uniformUpdate);
|
||||
viewLayout->reset();
|
||||
descriptorSets[INDEX_VIEW_PARAMS] = viewLayout->allocateDescriptorSet();
|
||||
descriptorSets[INDEX_VIEW_PARAMS]->updateBuffer(0, viewParamBuffer);
|
||||
descriptorSets[INDEX_VIEW_PARAMS]->writeChanges();
|
||||
for(auto &&meshBatch : scene->getStaticMeshes())
|
||||
|
||||
@@ -23,20 +23,32 @@ LightCullingPass::~LightCullingPass()
|
||||
|
||||
void LightCullingPass::beginFrame()
|
||||
{
|
||||
uint32_t viewportWidth = viewport->getSizeX();
|
||||
uint32_t viewportHeight = viewport->getSizeY();
|
||||
|
||||
BulkResourceData uniformUpdate;
|
||||
viewParams.viewMatrix = source->getViewMatrix();
|
||||
viewParams.projectionMatrix = source->getProjectionMatrix();
|
||||
viewParams.cameraPosition = Vector4(source->getCameraPosition(), 0);
|
||||
viewParams.inverseProjectionMatrix = glm::inverse(viewParams.projectionMatrix);
|
||||
viewParams.screenDimensions = Vector2(static_cast<float>(viewport->getSizeX()), static_cast<float>(viewport->getSizeY()));
|
||||
viewParams.screenDimensions = Vector2(static_cast<float>(viewportWidth), static_cast<float>(viewportHeight));
|
||||
uniformUpdate.size = sizeof(ViewParameter);
|
||||
uniformUpdate.data = (uint8*)&viewParams;
|
||||
viewParamsBuffer->updateContents(uniformUpdate);
|
||||
|
||||
BulkResourceData counterReset;
|
||||
uint32 reset = 0;
|
||||
counterReset.data = (uint8*)&reset;
|
||||
counterReset.size = sizeof(uint32);
|
||||
oLightIndexCounter->updateContents(counterReset);
|
||||
tLightIndexCounter->updateContents(counterReset);
|
||||
|
||||
|
||||
cullingDescriptorLayout->reset();
|
||||
lightEnvDescriptorLayout->reset();
|
||||
cullingDescriptorSet = cullingDescriptorLayout->allocateDescriptorSet();
|
||||
lightEnvDescriptorSet = lightEnvDescriptorLayout->allocateDescriptorSet();
|
||||
|
||||
cullingDescriptorSet->updateBuffer(0, viewParamsBuffer);
|
||||
cullingDescriptorSet->updateBuffer(1, dispatchParamsBuffer);
|
||||
cullingDescriptorSet->updateBuffer(3, frustumBuffer);
|
||||
@@ -61,7 +73,6 @@ void LightCullingPass::render()
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
depthAttachment->changeLayout(Gfx::SE_IMAGE_LAYOUT_GENERAL);
|
||||
depthAttachment->transferOwnership(Gfx::QueueType::COMPUTE);
|
||||
|
||||
cullingDescriptorSet->updateTexture(2, depthAttachment);
|
||||
cullingDescriptorSet->writeChanges();
|
||||
lightEnvDescriptorSet->updateBuffer(0, scene->getLightBuffer());
|
||||
@@ -85,16 +96,29 @@ void LightCullingPass::endFrame()
|
||||
void LightCullingPass::publishOutputs()
|
||||
{
|
||||
setupFrustums();
|
||||
uint32_t viewportWidth = viewport->getSizeX();
|
||||
uint32_t viewportHeight = viewport->getSizeY();
|
||||
glm::uvec3 numThreadGroups = glm::ceil(glm::vec3(viewportWidth / (float)BLOCK_SIZE, viewportHeight / (float)BLOCK_SIZE, 1));
|
||||
dispatchParams.numThreadGroups = numThreadGroups;
|
||||
dispatchParams.numThreads = numThreadGroups * glm::uvec3(BLOCK_SIZE, BLOCK_SIZE, 1);
|
||||
|
||||
BulkResourceData resourceData;
|
||||
StructuredBufferCreateInfo createInfo;
|
||||
uint32 counterReset = 0;
|
||||
resourceData.size = sizeof(uint32);
|
||||
resourceData.data = nullptr;
|
||||
resourceData.data = (uint8*)&counterReset;
|
||||
resourceData.owner = Gfx::QueueType::COMPUTE;
|
||||
createInfo.bDynamic = false;
|
||||
createInfo.bDynamic = true;
|
||||
createInfo.resourceData = resourceData;
|
||||
oLightIndexCounter = graphics->createStructuredBuffer(createInfo);
|
||||
tLightIndexCounter = graphics->createStructuredBuffer(createInfo);
|
||||
resourceData.size = sizeof(uint32_t) * dispatchParams.numThreadGroups.x * dispatchParams.numThreadGroups.y * dispatchParams.numThreadGroups.z * 1024;
|
||||
resourceData.data = nullptr;
|
||||
resourceData.size = sizeof(uint32_t)
|
||||
* dispatchParams.numThreadGroups.x
|
||||
* dispatchParams.numThreadGroups.y
|
||||
* dispatchParams.numThreadGroups.z * 200;
|
||||
createInfo.resourceData = resourceData;
|
||||
createInfo.bDynamic = false;
|
||||
oLightIndexList = graphics->createStructuredBuffer(createInfo);
|
||||
tLightIndexList = graphics->createStructuredBuffer(createInfo);
|
||||
renderGraph->registerBufferOutput("LIGHTCULLING_OLIGHTLIST", oLightIndexList);
|
||||
@@ -102,7 +126,7 @@ void LightCullingPass::publishOutputs()
|
||||
TextureCreateInfo textureInfo;
|
||||
textureInfo.width = dispatchParams.numThreadGroups.x;
|
||||
textureInfo.height = dispatchParams.numThreadGroups.y;
|
||||
textureInfo.format = Gfx::SE_FORMAT_R16G16_UINT;
|
||||
textureInfo.format = Gfx::SE_FORMAT_R32G32_UINT;
|
||||
textureInfo.usage = Gfx::SE_IMAGE_USAGE_STORAGE_BIT;
|
||||
oLightGrid = graphics->createTexture2D(textureInfo);
|
||||
tLightGrid = graphics->createTexture2D(textureInfo);
|
||||
@@ -139,7 +163,7 @@ void LightCullingPass::createRenderPass()
|
||||
|
||||
lightEnvDescriptorLayout = graphics->createDescriptorLayout("LightEnv");
|
||||
//LightEnv
|
||||
lightEnvDescriptorLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER);
|
||||
lightEnvDescriptorLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
|
||||
|
||||
cullingLayout = graphics->createPipelineLayout();
|
||||
cullingLayout->addDescriptorLayout(0, cullingDescriptorLayout);
|
||||
@@ -251,5 +275,6 @@ void LightCullingPass::setupFrustums()
|
||||
command->dispatch(numThreadGroups.x, numThreadGroups.y, numThreadGroups.z);
|
||||
Array<Gfx::PComputeCommand> commands = {command};
|
||||
graphics->executeCommands(commands);
|
||||
frustumBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
frustumBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
@@ -17,13 +17,13 @@ public:
|
||||
virtual void publishOutputs() = 0;
|
||||
virtual void createRenderPass() = 0;
|
||||
protected:
|
||||
struct ViewParameter
|
||||
_declspec(align(16)) struct ViewParameter
|
||||
{
|
||||
Matrix4 viewMatrix;
|
||||
Matrix4 projectionMatrix;
|
||||
Matrix4 inverseProjectionMatrix;
|
||||
Vector2 screenDimensions;
|
||||
Vector4 cameraPosition;
|
||||
Vector2 screenDimensions;
|
||||
} viewParams;
|
||||
Gfx::PRenderPass renderPass;
|
||||
PRenderGraph renderGraph;
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
target_sources(SeeleEngine
|
||||
PRIVATE
|
||||
NsightAftermathGpuCrashTracker.h
|
||||
NsightAftermathGpuCrashTracker.cpp
|
||||
NsightAftermathHelpers.h
|
||||
NsightAftermathShaderDatabase.h
|
||||
NsightAftermathShaderDatabase.cpp
|
||||
VulkanAllocator.h
|
||||
VulkanAllocator.cpp
|
||||
VulkanBuffer.cpp
|
||||
|
||||
@@ -0,0 +1,346 @@
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) 2019-2020, 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 <fstream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
|
||||
#include "NsightAftermathGpuCrashTracker.h"
|
||||
|
||||
//*********************************************************
|
||||
// GpuCrashTracker implementation
|
||||
//*********************************************************
|
||||
|
||||
GpuCrashTracker::GpuCrashTracker()
|
||||
: m_initialized(false)
|
||||
, m_mutex()
|
||||
, m_shaderDebugInfo()
|
||||
, m_shaderDatabase()
|
||||
{
|
||||
}
|
||||
|
||||
GpuCrashTracker::~GpuCrashTracker()
|
||||
{
|
||||
// If initialized, disable GPU crash dumps
|
||||
if (m_initialized)
|
||||
{
|
||||
GFSDK_Aftermath_DisableGpuCrashDumps();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the GPU Crash Dump Tracker
|
||||
void GpuCrashTracker::Initialize()
|
||||
{
|
||||
// Enable GPU crash dumps and set up the callbacks for crash dump notifications,
|
||||
// shader debug information notifications, and providing additional crash
|
||||
// dump description data.Only the crash dump callback is mandatory. The other two
|
||||
// callbacks are optional and can be omitted, by passing nullptr, if the corresponding
|
||||
// functionality is not used.
|
||||
// The DeferDebugInfoCallbacks flag enables caching of shader debug information data
|
||||
// in memory. If the flag is set, ShaderDebugInfoCallback will be called only
|
||||
// in the event of a crash, right before GpuCrashDumpCallback. If the flag is not set,
|
||||
// ShaderDebugInfoCallback will be called for every shader that is compiled.
|
||||
AFTERMATH_CHECK_ERROR(GFSDK_Aftermath_EnableGpuCrashDumps(
|
||||
GFSDK_Aftermath_Version_API,
|
||||
GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_Vulkan,
|
||||
GFSDK_Aftermath_GpuCrashDumpFeatureFlags_DeferDebugInfoCallbacks, // Let the Nsight Aftermath library cache shader debug information.
|
||||
GpuCrashDumpCallback, // Register callback for GPU crash dumps.
|
||||
ShaderDebugInfoCallback, // Register callback for shader debug information.
|
||||
CrashDumpDescriptionCallback, // Register callback for GPU crash dump description.
|
||||
this)); // Set the GpuCrashTracker object as user data for the above callbacks.
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
// Handler for GPU crash dump callbacks from Nsight Aftermath
|
||||
void GpuCrashTracker::OnCrashDump(const void* pGpuCrashDump, const uint32_t gpuCrashDumpSize)
|
||||
{
|
||||
// Make sure only one thread at a time...
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
// Write to file for later in-depth analysis with Nsight Graphics.
|
||||
WriteGpuCrashDumpToFile(pGpuCrashDump, gpuCrashDumpSize);
|
||||
}
|
||||
|
||||
// Handler for shader debug information callbacks
|
||||
void GpuCrashTracker::OnShaderDebugInfo(const void* pShaderDebugInfo, const uint32_t shaderDebugInfoSize)
|
||||
{
|
||||
// Make sure only one thread at a time...
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
// Get shader debug information identifier
|
||||
GFSDK_Aftermath_ShaderDebugInfoIdentifier identifier = {};
|
||||
AFTERMATH_CHECK_ERROR(GFSDK_Aftermath_GetShaderDebugInfoIdentifier(
|
||||
GFSDK_Aftermath_Version_API,
|
||||
pShaderDebugInfo,
|
||||
shaderDebugInfoSize,
|
||||
&identifier));
|
||||
|
||||
// Store information for decoding of GPU crash dumps with shader address mapping
|
||||
// from within the application.
|
||||
std::vector<uint8_t> data((uint8_t*)pShaderDebugInfo, (uint8_t*)pShaderDebugInfo + shaderDebugInfoSize);
|
||||
m_shaderDebugInfo[identifier].swap(data);
|
||||
|
||||
// Write to file for later in-depth analysis of crash dumps with Nsight Graphics
|
||||
WriteShaderDebugInformationToFile(identifier, pShaderDebugInfo, shaderDebugInfoSize);
|
||||
}
|
||||
|
||||
// Handler for GPU crash dump description callbacks
|
||||
void GpuCrashTracker::OnDescription(PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription addDescription)
|
||||
{
|
||||
// Add some basic description about the crash. This is called after the GPU crash happens, but before
|
||||
// the actual GPU crash dump callback. The provided data is included in the crash dump and can be
|
||||
// retrieved using GFSDK_Aftermath_GpuCrashDump_GetDescription().
|
||||
addDescription(GFSDK_Aftermath_GpuCrashDumpDescriptionKey_ApplicationName, "VkHelloNsightAftermath");
|
||||
addDescription(GFSDK_Aftermath_GpuCrashDumpDescriptionKey_ApplicationVersion, "v1.0");
|
||||
addDescription(GFSDK_Aftermath_GpuCrashDumpDescriptionKey_UserDefined, "This is a GPU crash dump example.");
|
||||
addDescription(GFSDK_Aftermath_GpuCrashDumpDescriptionKey_UserDefined + 1, "Engine State: Rendering.");
|
||||
addDescription(GFSDK_Aftermath_GpuCrashDumpDescriptionKey_UserDefined + 2, "More user-defined information...");
|
||||
}
|
||||
|
||||
// Helper for writing a GPU crash dump to a file
|
||||
void GpuCrashTracker::WriteGpuCrashDumpToFile(const void* pGpuCrashDump, const uint32_t gpuCrashDumpSize)
|
||||
{
|
||||
// Create a GPU crash dump decoder object for the GPU crash dump.
|
||||
GFSDK_Aftermath_GpuCrashDump_Decoder decoder = {};
|
||||
AFTERMATH_CHECK_ERROR(GFSDK_Aftermath_GpuCrashDump_CreateDecoder(
|
||||
GFSDK_Aftermath_Version_API,
|
||||
pGpuCrashDump,
|
||||
gpuCrashDumpSize,
|
||||
&decoder));
|
||||
|
||||
// Use the decoder object to read basic information, like application
|
||||
// name, PID, etc. from the GPU crash dump.
|
||||
GFSDK_Aftermath_GpuCrashDump_BaseInfo baseInfo = {};
|
||||
AFTERMATH_CHECK_ERROR(GFSDK_Aftermath_GpuCrashDump_GetBaseInfo(decoder, &baseInfo));
|
||||
|
||||
// Use the decoder object to query the application name that was set
|
||||
// in the GPU crash dump description.
|
||||
uint32_t applicationNameLength = 0;
|
||||
AFTERMATH_CHECK_ERROR(GFSDK_Aftermath_GpuCrashDump_GetDescriptionSize(
|
||||
decoder,
|
||||
GFSDK_Aftermath_GpuCrashDumpDescriptionKey_ApplicationName,
|
||||
&applicationNameLength));
|
||||
|
||||
std::vector<char> applicationName(applicationNameLength, '\0');
|
||||
|
||||
AFTERMATH_CHECK_ERROR(GFSDK_Aftermath_GpuCrashDump_GetDescription(
|
||||
decoder,
|
||||
GFSDK_Aftermath_GpuCrashDumpDescriptionKey_ApplicationName,
|
||||
uint32_t(applicationName.size()),
|
||||
applicationName.data()));
|
||||
|
||||
// Create a unique file name for writing the crash dump data to a file.
|
||||
// Note: due to an Nsight Aftermath bug (will be fixed in an upcoming
|
||||
// driver release) we may see redundant crash dumps. As a workaround,
|
||||
// attach a unique count to each generated file name.
|
||||
static int count = 0;
|
||||
const std::string baseFileName =
|
||||
std::string(applicationName.data())
|
||||
+ "-"
|
||||
+ std::to_string(baseInfo.pid)
|
||||
+ "-"
|
||||
+ std::to_string(++count);
|
||||
|
||||
// Write the the crash dump data to a file using the .nv-gpudmp extension
|
||||
// registered with Nsight Graphics.
|
||||
const std::string crashDumpFileName = baseFileName + ".nv-gpudmp";
|
||||
std::ofstream dumpFile(crashDumpFileName, std::ios::out | std::ios::binary);
|
||||
if (dumpFile)
|
||||
{
|
||||
dumpFile.write((const char*)pGpuCrashDump, gpuCrashDumpSize);
|
||||
dumpFile.close();
|
||||
}
|
||||
|
||||
// Decode the crash dump to a JSON string.
|
||||
// Step 1: Generate the JSON and get the size.
|
||||
uint32_t jsonSize = 0;
|
||||
AFTERMATH_CHECK_ERROR(GFSDK_Aftermath_GpuCrashDump_GenerateJSON(
|
||||
decoder,
|
||||
GFSDK_Aftermath_GpuCrashDumpDecoderFlags_ALL_INFO,
|
||||
GFSDK_Aftermath_GpuCrashDumpFormatterFlags_NONE,
|
||||
ShaderDebugInfoLookupCallback,
|
||||
ShaderLookupCallback,
|
||||
nullptr,
|
||||
ShaderSourceDebugInfoLookupCallback,
|
||||
this,
|
||||
&jsonSize));
|
||||
// Step 2: Allocate a buffer and fetch the generated JSON.
|
||||
std::vector<char> json(jsonSize);
|
||||
AFTERMATH_CHECK_ERROR(GFSDK_Aftermath_GpuCrashDump_GetJSON(
|
||||
decoder,
|
||||
uint32_t(json.size()),
|
||||
json.data()));
|
||||
|
||||
// Write the the crash dump data as JSON to a file.
|
||||
const std::string jsonFileName = crashDumpFileName + ".json";
|
||||
std::ofstream jsonFile(jsonFileName, std::ios::out | std::ios::binary);
|
||||
if (jsonFile)
|
||||
{
|
||||
jsonFile.write(json.data(), json.size());
|
||||
jsonFile.close();
|
||||
}
|
||||
|
||||
// Destroy the GPU crash dump decoder object.
|
||||
AFTERMATH_CHECK_ERROR(GFSDK_Aftermath_GpuCrashDump_DestroyDecoder(decoder));
|
||||
}
|
||||
|
||||
// Helper for writing shader debug information to a file
|
||||
void GpuCrashTracker::WriteShaderDebugInformationToFile(
|
||||
GFSDK_Aftermath_ShaderDebugInfoIdentifier identifier,
|
||||
const void* pShaderDebugInfo,
|
||||
const uint32_t shaderDebugInfoSize)
|
||||
{
|
||||
// Create a unique file name.
|
||||
const std::string filePath = "shader-" + std::to_string(identifier) + ".nvdbg";
|
||||
|
||||
std::ofstream f(filePath, std::ios::out | std::ios::binary);
|
||||
if (f)
|
||||
{
|
||||
f.write((const char*)pShaderDebugInfo, shaderDebugInfoSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Handler for shader debug information lookup callbacks.
|
||||
// This is used by the JSON decoder for mapping shader instruction
|
||||
// addresses to DXIL lines or HLSl source lines.
|
||||
void GpuCrashTracker::OnShaderDebugInfoLookup(
|
||||
const GFSDK_Aftermath_ShaderDebugInfoIdentifier& identifier,
|
||||
PFN_GFSDK_Aftermath_SetData setShaderDebugInfo) const
|
||||
{
|
||||
// Search the list of shader debug information blobs received earlier.
|
||||
auto i_debugInfo = m_shaderDebugInfo.find(identifier);
|
||||
if (i_debugInfo == m_shaderDebugInfo.end())
|
||||
{
|
||||
// Early exit, nothing found. No need to call setShaderDebugInfo.
|
||||
return;
|
||||
}
|
||||
|
||||
// Let the GPU crash dump decoder know about the shader debug information
|
||||
// that was found.
|
||||
setShaderDebugInfo(i_debugInfo->second.data(), uint32_t(i_debugInfo->second.size()));
|
||||
}
|
||||
|
||||
// Handler for shader lookup callbacks.
|
||||
// This is used by the JSON decoder for mapping shader instruction
|
||||
// addresses to DXIL lines or HLSL source lines.
|
||||
// NOTE: If the application loads stripped shader binaries (-Qstrip_debug),
|
||||
// Aftermath will require access to both the stripped and the not stripped
|
||||
// shader binaries.
|
||||
void GpuCrashTracker::OnShaderLookup(
|
||||
const GFSDK_Aftermath_ShaderHash& shaderHash,
|
||||
PFN_GFSDK_Aftermath_SetData setShaderBinary) const
|
||||
{
|
||||
// Find shader binary data for the shader hash in the shader database.
|
||||
std::vector<uint8_t> shaderBinary;
|
||||
if (!m_shaderDatabase.FindShaderBinary(shaderHash, shaderBinary))
|
||||
{
|
||||
// Early exit, nothing found. No need to call setShaderBinary.
|
||||
return;
|
||||
}
|
||||
|
||||
// Let the GPU crash dump decoder know about the shader data
|
||||
// that was found.
|
||||
setShaderBinary(shaderBinary.data(), uint32_t(shaderBinary.size()));
|
||||
}
|
||||
|
||||
// Handler for shader source debug info lookup callbacks.
|
||||
// This is used by the JSON decoder for mapping shader instruction addresses to
|
||||
// HLSL source lines, if the shaders used by the application were compiled with
|
||||
// separate debug info data files.
|
||||
void GpuCrashTracker::OnShaderSourceDebugInfoLookup(
|
||||
const GFSDK_Aftermath_ShaderDebugName& shaderDebugName,
|
||||
PFN_GFSDK_Aftermath_SetData setShaderBinary) const
|
||||
{
|
||||
// Find source debug info for the shader DebugName in the shader database.
|
||||
std::vector<uint8_t> shaderBinary;
|
||||
if (!m_shaderDatabase.FindShaderBinaryWithDebugData(shaderDebugName, shaderBinary))
|
||||
{
|
||||
// Early exit, nothing found. No need to call setShaderBinary.
|
||||
return;
|
||||
}
|
||||
|
||||
// Let the GPU crash dump decoder know about the shader debug data that was
|
||||
// found.
|
||||
setShaderBinary(shaderBinary.data(), uint32_t(shaderBinary.size()));
|
||||
}
|
||||
|
||||
// Static callback wrapper for OnCrashDump
|
||||
void GpuCrashTracker::GpuCrashDumpCallback(
|
||||
const void* pGpuCrashDump,
|
||||
const uint32_t gpuCrashDumpSize,
|
||||
void* pUserData)
|
||||
{
|
||||
GpuCrashTracker* pGpuCrashTracker = reinterpret_cast<GpuCrashTracker*>(pUserData);
|
||||
pGpuCrashTracker->OnCrashDump(pGpuCrashDump, gpuCrashDumpSize);
|
||||
}
|
||||
|
||||
// Static callback wrapper for OnShaderDebugInfo
|
||||
void GpuCrashTracker::ShaderDebugInfoCallback(
|
||||
const void* pShaderDebugInfo,
|
||||
const uint32_t shaderDebugInfoSize,
|
||||
void* pUserData)
|
||||
{
|
||||
GpuCrashTracker* pGpuCrashTracker = reinterpret_cast<GpuCrashTracker*>(pUserData);
|
||||
pGpuCrashTracker->OnShaderDebugInfo(pShaderDebugInfo, shaderDebugInfoSize);
|
||||
}
|
||||
|
||||
// Static callback wrapper for OnDescription
|
||||
void GpuCrashTracker::CrashDumpDescriptionCallback(
|
||||
PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription addDescription,
|
||||
void* pUserData)
|
||||
{
|
||||
GpuCrashTracker* pGpuCrashTracker = reinterpret_cast<GpuCrashTracker*>(pUserData);
|
||||
pGpuCrashTracker->OnDescription(addDescription);
|
||||
}
|
||||
|
||||
// Static callback wrapper for OnShaderDebugInfoLookup
|
||||
void GpuCrashTracker::ShaderDebugInfoLookupCallback(
|
||||
const GFSDK_Aftermath_ShaderDebugInfoIdentifier* pIdentifier,
|
||||
PFN_GFSDK_Aftermath_SetData setShaderDebugInfo,
|
||||
void* pUserData)
|
||||
{
|
||||
GpuCrashTracker* pGpuCrashTracker = reinterpret_cast<GpuCrashTracker*>(pUserData);
|
||||
pGpuCrashTracker->OnShaderDebugInfoLookup(*pIdentifier, setShaderDebugInfo);
|
||||
}
|
||||
|
||||
// Static callback wrapper for OnShaderLookup
|
||||
void GpuCrashTracker::ShaderLookupCallback(
|
||||
const GFSDK_Aftermath_ShaderHash* pShaderHash,
|
||||
PFN_GFSDK_Aftermath_SetData setShaderBinary,
|
||||
void* pUserData)
|
||||
{
|
||||
GpuCrashTracker* pGpuCrashTracker = reinterpret_cast<GpuCrashTracker*>(pUserData);
|
||||
pGpuCrashTracker->OnShaderLookup(*pShaderHash, setShaderBinary);
|
||||
}
|
||||
|
||||
// Static callback wrapper for OnShaderSourceDebugInfoLookup
|
||||
void GpuCrashTracker::ShaderSourceDebugInfoLookupCallback(
|
||||
const GFSDK_Aftermath_ShaderDebugName* pShaderDebugName,
|
||||
PFN_GFSDK_Aftermath_SetData setShaderBinary,
|
||||
void* pUserData)
|
||||
{
|
||||
GpuCrashTracker* pGpuCrashTracker = reinterpret_cast<GpuCrashTracker*>(pUserData);
|
||||
pGpuCrashTracker->OnShaderSourceDebugInfoLookup(*pShaderDebugName, setShaderBinary);
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) 2019-2020, 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 <map>
|
||||
#include <mutex>
|
||||
|
||||
#include "NsightAftermathHelpers.h"
|
||||
#include "NsightAftermathShaderDatabase.h"
|
||||
|
||||
//*********************************************************
|
||||
// Implements GPU crash dump tracking using the Nsight
|
||||
// Aftermath API.
|
||||
//
|
||||
class GpuCrashTracker
|
||||
{
|
||||
public:
|
||||
GpuCrashTracker();
|
||||
~GpuCrashTracker();
|
||||
|
||||
// Initialize the GPU crash dump tracker.
|
||||
void Initialize();
|
||||
|
||||
private:
|
||||
|
||||
//*********************************************************
|
||||
// Callback handlers for GPU crash dumps and related data.
|
||||
//
|
||||
|
||||
// Handler for GPU crash dump callbacks.
|
||||
void OnCrashDump(const void* pGpuCrashDump, const uint32_t gpuCrashDumpSize);
|
||||
|
||||
// Handler for shader debug information callbacks.
|
||||
void OnShaderDebugInfo(const void* pShaderDebugInfo, const uint32_t shaderDebugInfoSize);
|
||||
|
||||
// Handler for GPU crash dump description callbacks.
|
||||
void OnDescription(PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription addDescription);
|
||||
|
||||
//*********************************************************
|
||||
// Helpers for writing a GPU crash dump and debug information
|
||||
// data to files.
|
||||
//
|
||||
|
||||
// Helper for writing a GPU crash dump to a file.
|
||||
void WriteGpuCrashDumpToFile(const void* pGpuCrashDump, const uint32_t gpuCrashDumpSize);
|
||||
|
||||
// Helper for writing shader debug information to a file
|
||||
void WriteShaderDebugInformationToFile(
|
||||
GFSDK_Aftermath_ShaderDebugInfoIdentifier identifier,
|
||||
const void* pShaderDebugInfo,
|
||||
const uint32_t shaderDebugInfoSize);
|
||||
|
||||
//*********************************************************
|
||||
// Helpers for decoding GPU crash dump to JSON.
|
||||
//
|
||||
|
||||
// Handler for shader debug info lookup callbacks.
|
||||
void OnShaderDebugInfoLookup(
|
||||
const GFSDK_Aftermath_ShaderDebugInfoIdentifier& identifier,
|
||||
PFN_GFSDK_Aftermath_SetData setShaderDebugInfo) const;
|
||||
|
||||
// Handler for shader lookup callbacks.
|
||||
void OnShaderLookup(
|
||||
const GFSDK_Aftermath_ShaderHash& shaderHash,
|
||||
PFN_GFSDK_Aftermath_SetData setShaderBinary) const;
|
||||
|
||||
// Handler for shader instructions lookup callbacks.
|
||||
void OnShaderInstructionsLookup(
|
||||
const GFSDK_Aftermath_ShaderInstructionsHash& shaderInstructionsHash,
|
||||
PFN_GFSDK_Aftermath_SetData setShaderBinary) const;
|
||||
|
||||
// Handler for shader source debug info lookup callbacks.
|
||||
void OnShaderSourceDebugInfoLookup(
|
||||
const GFSDK_Aftermath_ShaderDebugName& shaderDebugName,
|
||||
PFN_GFSDK_Aftermath_SetData setShaderBinary) const;
|
||||
|
||||
//*********************************************************
|
||||
// Static callback wrappers.
|
||||
//
|
||||
|
||||
// GPU crash dump callback.
|
||||
static void GpuCrashDumpCallback(
|
||||
const void* pGpuCrashDump,
|
||||
const uint32_t gpuCrashDumpSize,
|
||||
void* pUserData);
|
||||
|
||||
// Shader debug information callback.
|
||||
static void ShaderDebugInfoCallback(
|
||||
const void* pShaderDebugInfo,
|
||||
const uint32_t shaderDebugInfoSize,
|
||||
void* pUserData);
|
||||
|
||||
// GPU crash dump description callback.
|
||||
static void CrashDumpDescriptionCallback(
|
||||
PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription addDescription,
|
||||
void* pUserData);
|
||||
|
||||
// Shader debug information lookup callback.
|
||||
static void ShaderDebugInfoLookupCallback(
|
||||
const GFSDK_Aftermath_ShaderDebugInfoIdentifier* pIdentifier,
|
||||
PFN_GFSDK_Aftermath_SetData setShaderDebugInfo,
|
||||
void* pUserData);
|
||||
|
||||
// Shader lookup callback.
|
||||
static void ShaderLookupCallback(
|
||||
const GFSDK_Aftermath_ShaderHash* pShaderHash,
|
||||
PFN_GFSDK_Aftermath_SetData setShaderBinary,
|
||||
void* pUserData);
|
||||
|
||||
// Shader instructions lookup callback.
|
||||
static void ShaderInstructionsLookupCallback(
|
||||
const GFSDK_Aftermath_ShaderInstructionsHash* pShaderInstructionsHash,
|
||||
PFN_GFSDK_Aftermath_SetData setShaderBinary,
|
||||
void* pUserData);
|
||||
|
||||
// Shader source debug info lookup callback.
|
||||
static void ShaderSourceDebugInfoLookupCallback(
|
||||
const GFSDK_Aftermath_ShaderDebugName* pShaderDebugName,
|
||||
PFN_GFSDK_Aftermath_SetData setShaderBinary,
|
||||
void* pUserData);
|
||||
|
||||
//*********************************************************
|
||||
// GPU crash tracker state.
|
||||
//
|
||||
|
||||
// Is the GPU crash dump tracker initialized?
|
||||
bool m_initialized;
|
||||
|
||||
// For thread-safe access of GPU crash tracker state.
|
||||
mutable std::mutex m_mutex;
|
||||
|
||||
// List of Shader Debug Information by ShaderDebugInfoIdentifier.
|
||||
std::map<GFSDK_Aftermath_ShaderDebugInfoIdentifier, std::vector<uint8_t>> m_shaderDebugInfo;
|
||||
|
||||
// The mock shader database.
|
||||
ShaderDatabase m_shaderDatabase;
|
||||
};
|
||||
@@ -0,0 +1,142 @@
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) 2019, 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 <iomanip>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
#include "GFSDK_Aftermath.h"
|
||||
#include "GFSDK_Aftermath_GpuCrashDump.h"
|
||||
#include "GFSDK_Aftermath_GpuCrashDumpDecoding.h"
|
||||
|
||||
//*********************************************************
|
||||
// Some std::to_string overloads for some Nsight Aftermath
|
||||
// API types.
|
||||
//
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<typename T>
|
||||
inline std::string to_hex_string(T n)
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << std::setfill('0') << std::setw(2 * sizeof(T)) << std::hex << n;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
inline std::string to_string(GFSDK_Aftermath_Result result)
|
||||
{
|
||||
return std::string("0x") + to_hex_string(static_cast<uint32_t>(result));
|
||||
}
|
||||
|
||||
inline std::string to_string(const GFSDK_Aftermath_ShaderDebugInfoIdentifier& identifier)
|
||||
{
|
||||
return to_hex_string(identifier.id[0]) + "-" + to_hex_string(identifier.id[1]);
|
||||
}
|
||||
|
||||
inline std::string to_string(const GFSDK_Aftermath_ShaderHash& hash)
|
||||
{
|
||||
return to_hex_string(hash.hash);
|
||||
}
|
||||
|
||||
inline std::string to_string(const GFSDK_Aftermath_ShaderInstructionsHash& hash)
|
||||
{
|
||||
return to_hex_string(hash.hash) + "-" + to_hex_string(hash.hash);
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
//*********************************************************
|
||||
// Helper for comparing shader hashes and debug info identifier.
|
||||
//
|
||||
|
||||
// Helper for comparing GFSDK_Aftermath_ShaderDebugInfoIdentifier.
|
||||
inline bool operator<(const GFSDK_Aftermath_ShaderDebugInfoIdentifier& lhs, const GFSDK_Aftermath_ShaderDebugInfoIdentifier& rhs)
|
||||
{
|
||||
if (lhs.id[0] == rhs.id[0])
|
||||
{
|
||||
return lhs.id[1] < rhs.id[1];
|
||||
}
|
||||
return lhs.id[0] < rhs.id[0];
|
||||
}
|
||||
|
||||
// Helper for comparing GFSDK_Aftermath_ShaderHash.
|
||||
inline bool operator<(const GFSDK_Aftermath_ShaderHash& lhs, const GFSDK_Aftermath_ShaderHash& rhs)
|
||||
{
|
||||
return lhs.hash < rhs.hash;
|
||||
}
|
||||
|
||||
// Helper for comparing GFSDK_Aftermath_ShaderInstructionsHash.
|
||||
inline bool operator<(const GFSDK_Aftermath_ShaderInstructionsHash& lhs, const GFSDK_Aftermath_ShaderInstructionsHash& rhs)
|
||||
{
|
||||
return lhs.hash < rhs.hash;
|
||||
}
|
||||
|
||||
// Helper for comparing GFSDK_Aftermath_ShaderDebugName.
|
||||
inline bool operator<(const GFSDK_Aftermath_ShaderDebugName& lhs, const GFSDK_Aftermath_ShaderDebugName& rhs)
|
||||
{
|
||||
return strncmp(lhs.name, rhs.name, sizeof(lhs.name)) < 0;
|
||||
}
|
||||
|
||||
//*********************************************************
|
||||
// Helper for checking Nsight Aftermath failures.
|
||||
//
|
||||
|
||||
inline std::string AftermathErrorMessage(GFSDK_Aftermath_Result result)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case GFSDK_Aftermath_Result_FAIL_DriverVersionNotSupported:
|
||||
return "Unsupported driver version - requires a recent NVIDIA R445 display driver or newer.";
|
||||
default:
|
||||
return "Aftermath Error 0x" + std::to_hex_string(result);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper macro for checking Nsight Aftermath results and throwing exception
|
||||
// in case of a failure.
|
||||
#ifdef _WIN32
|
||||
#define AFTERMATH_CHECK_ERROR(FC) \
|
||||
[&]() { \
|
||||
GFSDK_Aftermath_Result _result = FC; \
|
||||
if (!GFSDK_Aftermath_SUCCEED(_result)) \
|
||||
{ \
|
||||
std::cout << AftermathErrorMessage(_result).c_str() << std::endl; \
|
||||
exit(1); \
|
||||
} \
|
||||
}()
|
||||
#else
|
||||
#define AFTERMATH_CHECK_ERROR(FC) \
|
||||
[&]() { \
|
||||
GFSDK_Aftermath_Result _result = FC; \
|
||||
if (!GFSDK_Aftermath_SUCCEED(_result)) \
|
||||
{ \
|
||||
printf("%s\n", AftermathErrorMessage(_result).c_str()); \
|
||||
fflush(stdout); \
|
||||
exit(1); \
|
||||
} \
|
||||
}()
|
||||
#endif
|
||||
@@ -0,0 +1,147 @@
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) 2019-2020, 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 <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "NsightAftermathShaderDatabase.h"
|
||||
|
||||
//*********************************************************
|
||||
// ShaderDatabase implementation
|
||||
//*********************************************************
|
||||
|
||||
ShaderDatabase::ShaderDatabase()
|
||||
: m_shaderBinaries()
|
||||
, m_shaderBinariesWithDebugInfo()
|
||||
{
|
||||
// Add shader binaries to database
|
||||
AddShaderBinary("cube.vert.spirv");
|
||||
AddShaderBinary("cube.frag.spirv");
|
||||
|
||||
// Add the not stripped shader binaries to the database, too.
|
||||
AddShaderBinaryWithDebugInfo("cube.vert.spirv", "cube.vert.full.spirv");
|
||||
AddShaderBinaryWithDebugInfo("cube.frag.spirv", "cube.frag.full.spirv");
|
||||
}
|
||||
|
||||
ShaderDatabase::~ShaderDatabase()
|
||||
{
|
||||
}
|
||||
|
||||
bool ShaderDatabase::ReadFile(const char* filename, std::vector<uint8_t>& data)
|
||||
{
|
||||
std::ifstream fs(filename, std::ios::in | std::ios::binary);
|
||||
if (!fs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
fs.seekg(0, std::ios::end);
|
||||
data.resize(fs.tellg());
|
||||
fs.seekg(0, std::ios::beg);
|
||||
fs.read(reinterpret_cast<char*>(data.data()), data.size());
|
||||
fs.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShaderDatabase::AddShaderBinary(const char* shaderFilePath)
|
||||
{
|
||||
// Read the shader binary code from the file
|
||||
std::vector<uint8_t> data;
|
||||
if (!ReadFile(shaderFilePath, data))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Create shader hash for the shader
|
||||
const GFSDK_Aftermath_SpirvCode shader{ data.data(), uint32_t(data.size()) };
|
||||
GFSDK_Aftermath_ShaderHash shaderHash;
|
||||
AFTERMATH_CHECK_ERROR(GFSDK_Aftermath_GetShaderHashSpirv(
|
||||
GFSDK_Aftermath_Version_API,
|
||||
&shader,
|
||||
&shaderHash));
|
||||
|
||||
// Store the data for shader mapping when decoding GPU crash dumps.
|
||||
// cf. FindShaderBinary()
|
||||
m_shaderBinaries[shaderHash].swap(data);
|
||||
}
|
||||
|
||||
void ShaderDatabase::AddShaderBinaryWithDebugInfo(const char* strippedShaderFilePath, const char* shaderFilePath)
|
||||
{
|
||||
// Read the shader debug data from the file
|
||||
std::vector<uint8_t> data;
|
||||
if (!ReadFile(shaderFilePath, data))
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::vector<uint8_t> strippedData;
|
||||
if (!ReadFile(strippedShaderFilePath, strippedData))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate shader debug name.
|
||||
GFSDK_Aftermath_ShaderDebugName debugName;
|
||||
const GFSDK_Aftermath_SpirvCode shader{ data.data(), uint32_t(data.size()) };
|
||||
const GFSDK_Aftermath_SpirvCode strippedShader{ strippedData.data(), uint32_t(strippedData.size()) };
|
||||
AFTERMATH_CHECK_ERROR(GFSDK_Aftermath_GetShaderDebugNameSpirv(
|
||||
GFSDK_Aftermath_Version_API,
|
||||
&shader,
|
||||
&strippedShader,
|
||||
&debugName));
|
||||
|
||||
// Store the data for shader instruction address mapping when decoding GPU crash dumps.
|
||||
// cf. FindShaderBinaryWithDebugData()
|
||||
m_shaderBinariesWithDebugInfo[debugName].swap(data);
|
||||
}
|
||||
|
||||
// Find a shader binary by shader hash.
|
||||
bool ShaderDatabase::FindShaderBinary(const GFSDK_Aftermath_ShaderHash& shaderHash, std::vector<uint8_t>& shader) const
|
||||
{
|
||||
// Find shader binary data for the shader hash
|
||||
auto i_shader = m_shaderBinaries.find(shaderHash);
|
||||
if (i_shader == m_shaderBinaries.end())
|
||||
{
|
||||
// Nothing found.
|
||||
return false;
|
||||
}
|
||||
|
||||
shader = i_shader->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find a shader binary with debug information by shader debug name.
|
||||
bool ShaderDatabase::FindShaderBinaryWithDebugData(const GFSDK_Aftermath_ShaderDebugName& shaderDebugName, std::vector<uint8_t>& shader) const
|
||||
{
|
||||
// Find shader binary for the shader debug name.
|
||||
auto i_shader = m_shaderBinariesWithDebugInfo.find(shaderDebugName);
|
||||
if (i_shader == m_shaderBinariesWithDebugInfo.end())
|
||||
{
|
||||
// Nothing found.
|
||||
return false;
|
||||
}
|
||||
|
||||
shader = i_shader->second;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) 2019, 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 <vector>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
#include "NsightAftermathHelpers.h"
|
||||
|
||||
//*********************************************************
|
||||
// Implements a very simple shader database to help demonstrate
|
||||
// how to use the Nsight Aftermath GPU crash dump decoder API.
|
||||
//
|
||||
// In a real world scenario this would be part of an offline
|
||||
// analysis tool. This is for demonstration purposes only!
|
||||
//
|
||||
class ShaderDatabase
|
||||
{
|
||||
public:
|
||||
ShaderDatabase();
|
||||
~ShaderDatabase();
|
||||
|
||||
// Find a shader bytecode binary by shader hash.
|
||||
bool FindShaderBinary(const GFSDK_Aftermath_ShaderHash& shaderHash, std::vector<uint8_t>& shader) const;
|
||||
|
||||
// Find a source shader debug info by shader debug name generated by the DXC compiler.
|
||||
bool FindShaderBinaryWithDebugData(const GFSDK_Aftermath_ShaderDebugName& shaderDebugName, std::vector<uint8_t>& shader) const;
|
||||
|
||||
private:
|
||||
|
||||
void AddShaderBinary(const char* shaderFilePath);
|
||||
void AddShaderBinaryWithDebugInfo(const char* strippedShaderFilePath, const char* shaderFilePath);
|
||||
|
||||
static bool ReadFile(const char* filename, std::vector<uint8_t>& data);
|
||||
|
||||
// List of shader binaries by ShaderHash.
|
||||
std::map<GFSDK_Aftermath_ShaderHash, std::vector<uint8_t>> m_shaderBinaries;
|
||||
|
||||
// List of available shader binaries with source debug information by ShaderDebugName.
|
||||
std::map<GFSDK_Aftermath_ShaderDebugName, std::vector<uint8_t>> m_shaderBinariesWithDebugInfo;
|
||||
};
|
||||
@@ -350,7 +350,7 @@ VkAccessFlags UniformBuffer::getDestAccessMask()
|
||||
}
|
||||
|
||||
StructuredBuffer::StructuredBuffer(PGraphics graphics, const StructuredBufferCreateInfo &resourceData)
|
||||
: Gfx::StructuredBuffer(graphics->getFamilyMapping(), resourceData.resourceData.owner)
|
||||
: Gfx::StructuredBuffer(graphics->getFamilyMapping(), resourceData.resourceData)
|
||||
, Vulkan::ShaderBuffer(graphics, resourceData.resourceData.size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, currentOwner, resourceData.bDynamic)
|
||||
{
|
||||
if (resourceData.resourceData.data != nullptr)
|
||||
@@ -365,6 +365,44 @@ StructuredBuffer::~StructuredBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
bool StructuredBuffer::updateContents(const BulkResourceData &resourceData)
|
||||
{
|
||||
Gfx::StructuredBuffer::updateContents(resourceData);
|
||||
//We always want to update, as the contents could be different on the GPU
|
||||
void* data = lock();
|
||||
std::memcpy(data, resourceData.data, resourceData.size);
|
||||
unlock();
|
||||
return true;
|
||||
}
|
||||
void* StructuredBuffer::lock(bool bWriteOnly)
|
||||
{
|
||||
if(dedicatedStagingBuffer != nullptr)
|
||||
{
|
||||
return dedicatedStagingBuffer->getMappedPointer();
|
||||
}
|
||||
return ShaderBuffer::lock(bWriteOnly);
|
||||
}
|
||||
|
||||
void StructuredBuffer::unlock()
|
||||
{
|
||||
if(dedicatedStagingBuffer != nullptr)
|
||||
{
|
||||
dedicatedStagingBuffer->flushMappedMemory();
|
||||
PCmdBuffer cmdBuffer = graphics->getQueueCommands(currentOwner)->getCommands();
|
||||
VkCommandBuffer cmdHandle = cmdBuffer->getHandle();
|
||||
|
||||
VkBufferCopy region;
|
||||
std::memset(®ion, 0, sizeof(VkBufferCopy));
|
||||
region.size = ShaderBuffer::size;
|
||||
vkCmdCopyBuffer(cmdHandle, dedicatedStagingBuffer->getHandle(), buffers[currentBuffer].buffer, 1, ®ion);
|
||||
graphics->getQueueCommands(currentOwner)->submitCommands();
|
||||
}
|
||||
else
|
||||
{
|
||||
ShaderBuffer::unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void StructuredBuffer::requestOwnershipTransfer(Gfx::QueueType newOwner)
|
||||
{
|
||||
Gfx::QueueOwnedResource::transferOwnership(newOwner);
|
||||
|
||||
@@ -91,13 +91,12 @@ void CmdBuffer::executeCommands(const Array<Gfx::PRenderCommand>& commands)
|
||||
for (uint32 i = 0; i < commands.size(); ++i)
|
||||
{
|
||||
auto command = commands[i].cast<RenderCommand>();
|
||||
// Cache array and size to save on pointer access
|
||||
for(auto boundDescriptor : command->boundDescriptors)
|
||||
{
|
||||
boundDescriptor->currentlyBound = this;
|
||||
}
|
||||
command->end();
|
||||
executingRenders.add(command);
|
||||
for(auto descriptor : command->boundDescriptors)
|
||||
{
|
||||
boundDescriptors.add(descriptor);
|
||||
}
|
||||
cmdBuffers[i] = command->getHandle();
|
||||
}
|
||||
vkCmdExecuteCommands(handle, (uint32)cmdBuffers.size(), cmdBuffers.data());
|
||||
@@ -109,13 +108,12 @@ void CmdBuffer::executeCommands(const Array<Gfx::PComputeCommand>& commands)
|
||||
for (uint32 i = 0; i < commands.size(); ++i)
|
||||
{
|
||||
auto command = commands[i].cast<ComputeCommand>();
|
||||
// Cache array and size to save on pointer access
|
||||
for(auto boundDescriptor : command->boundDescriptors)
|
||||
{
|
||||
boundDescriptor->currentlyBound = this;
|
||||
}
|
||||
command->end();
|
||||
executingComputes.add(command);
|
||||
for(auto descriptor : command->boundDescriptors)
|
||||
{
|
||||
boundDescriptors.add(descriptor);
|
||||
}
|
||||
cmdBuffers[i] = command->getHandle();
|
||||
}
|
||||
vkCmdExecuteCommands(handle, (uint32)cmdBuffers.size(), cmdBuffers.data());
|
||||
@@ -145,6 +143,10 @@ void CmdBuffer::refreshFence()
|
||||
command->reset();
|
||||
}
|
||||
executingRenders.clear();
|
||||
for(auto descriptor : boundDescriptors)
|
||||
{
|
||||
descriptor->unbind();
|
||||
}
|
||||
state = State::ReadyBegin;
|
||||
}
|
||||
}
|
||||
@@ -196,10 +198,6 @@ void SecondaryCmdBuffer::end()
|
||||
void SecondaryCmdBuffer::reset()
|
||||
{
|
||||
vkResetCommandBuffer(handle, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
|
||||
for(auto boundDescriptor : boundDescriptors)
|
||||
{
|
||||
boundDescriptor->currentlyBound = nullptr;
|
||||
}
|
||||
boundDescriptors.clear();
|
||||
ready = true;
|
||||
}
|
||||
@@ -251,6 +249,8 @@ void RenderCommand::bindDescriptor(Gfx::PDescriptorSet descriptorSet)
|
||||
{
|
||||
auto descriptor = descriptorSet.cast<DescriptorSet>();
|
||||
boundDescriptors.add(descriptor.getHandle());
|
||||
descriptor->bind();
|
||||
//std::cout << "Binding descriptor " << descriptor->getHandle() << " to cmd " << handle << std::endl;
|
||||
VkDescriptorSet setHandle = descriptor->getHandle();
|
||||
vkCmdBindDescriptorSets(handle, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getLayout(), descriptorSet->getSetIndex(), 1, &setHandle, 0, nullptr);
|
||||
}
|
||||
@@ -260,6 +260,8 @@ void RenderCommand::bindDescriptor(const Array<Gfx::PDescriptorSet>& descriptorS
|
||||
for(uint32 i = 0; i < descriptorSets.size(); ++i)
|
||||
{
|
||||
auto descriptorSet = descriptorSets[i].cast<DescriptorSet>();
|
||||
descriptorSet->bind();
|
||||
//std::cout << "Binding descriptor " << descriptorSet->getHandle() << " to cmd " << handle << std::endl;
|
||||
boundDescriptors.add(descriptorSet.getHandle());
|
||||
sets[descriptorSet->getSetIndex()] = descriptorSet->getHandle();
|
||||
}
|
||||
@@ -326,6 +328,8 @@ void ComputeCommand::bindDescriptor(Gfx::PDescriptorSet descriptorSet)
|
||||
{
|
||||
auto descriptor = descriptorSet.cast<DescriptorSet>();
|
||||
boundDescriptors.add(descriptor.getHandle());
|
||||
descriptor->bind();
|
||||
//std::cout << "Binding descriptor " << descriptor->getHandle() << " to cmd " << handle << std::endl;
|
||||
VkDescriptorSet setHandle = descriptor->getHandle();
|
||||
vkCmdBindDescriptorSets(handle, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->getLayout(), descriptorSet->getSetIndex(), 1, &setHandle, 0, nullptr);
|
||||
}
|
||||
@@ -337,6 +341,8 @@ void ComputeCommand::bindDescriptor(const Array<Gfx::PDescriptorSet>& descriptor
|
||||
{
|
||||
auto descriptorSet = descriptorSets[i].cast<DescriptorSet>();
|
||||
boundDescriptors.add(descriptorSet.getHandle());
|
||||
descriptorSet->bind();
|
||||
//std::cout << "Binding descriptor " << descriptorSet->getHandle() << " to cmd " << handle << std::endl;
|
||||
sets[descriptorSet->getSetIndex()] = descriptorSet->getHandle();
|
||||
}
|
||||
vkCmdBindDescriptorSets(handle, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->getLayout(), 0, (uint32)descriptorSets.size(), sets, 0, nullptr);
|
||||
|
||||
@@ -31,6 +31,7 @@ DEFINE_REF(CmdBufferBase)
|
||||
|
||||
DECLARE_REF(RenderCommand)
|
||||
DECLARE_REF(ComputeCommand)
|
||||
DECLARE_REF(DescriptorSet)
|
||||
DECLARE_REF(CommandBufferManager)
|
||||
class CmdBuffer : public CmdBufferBase
|
||||
{
|
||||
@@ -68,6 +69,7 @@ private:
|
||||
Array<VkPipelineStageFlags> waitFlags;
|
||||
Array<PRenderCommand> executingRenders;
|
||||
Array<PComputeCommand> executingComputes;
|
||||
Array<DescriptorSet*> boundDescriptors;
|
||||
friend class RenderCommand;
|
||||
friend class CommandBufferManager;
|
||||
friend class Queue;
|
||||
@@ -76,7 +78,6 @@ DEFINE_REF(CmdBuffer)
|
||||
|
||||
DECLARE_REF(GraphicsPipeline)
|
||||
DECLARE_REF(ComputePipeline)
|
||||
DECLARE_REF(DescriptorSet)
|
||||
|
||||
class SecondaryCmdBuffer: public CmdBufferBase
|
||||
{
|
||||
|
||||
@@ -220,7 +220,7 @@ void DescriptorSet::writeChanges()
|
||||
{
|
||||
if(isCurrentlyBound())
|
||||
{
|
||||
currentlyBound->waitForCommand(1000000000u);
|
||||
std::cout << "Descriptor currently bound, allocate a new one instead" << std::endl;
|
||||
assert(!isCurrentlyBound());
|
||||
}
|
||||
vkUpdateDescriptorSets(graphics->getDevice(), (uint32)writeDescriptors.size(), writeDescriptors.data(), 0, nullptr);
|
||||
@@ -289,7 +289,6 @@ void DescriptorAllocator::allocateDescriptorSet(Gfx::PDescriptorSet &descriptorS
|
||||
{
|
||||
//If it hasnt been initialized, allocate it
|
||||
VK_CHECK(vkAllocateDescriptorSets(graphics->getDevice(), &allocInfo, &cachedHandles[setIndex]->setHandle));
|
||||
|
||||
}
|
||||
cachedHandles[setIndex]->currentlyInUse = true;
|
||||
descriptorSet = cachedHandles[setIndex];
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
, graphics(graphics)
|
||||
, owner(owner)
|
||||
, currentlyInUse(false)
|
||||
, currentlyBound(nullptr)
|
||||
, currentlyBound(false)
|
||||
{
|
||||
}
|
||||
virtual ~DescriptorSet();
|
||||
@@ -77,12 +77,20 @@ public:
|
||||
|
||||
inline bool isCurrentlyBound() const
|
||||
{
|
||||
return currentlyBound != nullptr;
|
||||
return currentlyBound;
|
||||
}
|
||||
inline bool isCurrentlyInUse() const
|
||||
{
|
||||
return currentlyInUse;
|
||||
}
|
||||
void bind()
|
||||
{
|
||||
currentlyBound = true;
|
||||
}
|
||||
void unbind()
|
||||
{
|
||||
currentlyBound = false;
|
||||
}
|
||||
void free()
|
||||
{
|
||||
currentlyInUse = false;
|
||||
@@ -104,7 +112,8 @@ private:
|
||||
VkDescriptorSet setHandle;
|
||||
PGraphics graphics;
|
||||
PDescriptorAllocator owner;
|
||||
PCmdBuffer currentlyBound;
|
||||
//PCmdBuffer currentlyBound;
|
||||
bool currentlyBound;
|
||||
bool currentlyInUse;
|
||||
friend class DescriptorAllocator;
|
||||
friend class CmdBuffer;
|
||||
|
||||
@@ -412,6 +412,8 @@ void Graphics::setupDebugCallback()
|
||||
VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT);
|
||||
|
||||
VK_CHECK(CreateDebugReportCallbackEXT(instance, &createInfo, nullptr, &callback));
|
||||
|
||||
crashTracker.Initialize();
|
||||
}
|
||||
|
||||
void Graphics::pickPhysicalDevice()
|
||||
@@ -537,6 +539,16 @@ void Graphics::createDevice(GraphicsInitializer initializer)
|
||||
queueInfos.data(),
|
||||
(uint32)queueInfos.size(),
|
||||
&features);
|
||||
#if ENABLE_VALIDATION
|
||||
VkDeviceDiagnosticsConfigCreateInfoNV crashDiagInfo;
|
||||
crashDiagInfo.sType = VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV;
|
||||
crashDiagInfo.pNext = nullptr;
|
||||
crashDiagInfo.flags =
|
||||
VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV |
|
||||
VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV |
|
||||
VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV;
|
||||
deviceInfo.pNext = &crashDiagInfo;
|
||||
#endif
|
||||
deviceInfo.enabledExtensionCount = (uint32)initializer.deviceExtensions.size();
|
||||
deviceInfo.ppEnabledExtensionNames = initializer.deviceExtensions.data();
|
||||
deviceInfo.enabledLayerCount = (uint32_t)initializer.layers.size();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "VulkanGraphicsResources.h"
|
||||
#include "Graphics/Graphics.h"
|
||||
#include "NsightAftermathGpuCrashTracker.h"
|
||||
|
||||
namespace Seele
|
||||
{
|
||||
@@ -98,6 +99,7 @@ protected:
|
||||
Map<uint32, PFramebuffer> allocatedFramebuffers;
|
||||
PAllocator allocator;
|
||||
PStagingManager stagingManager;
|
||||
GpuCrashTracker crashTracker;
|
||||
|
||||
friend class Window;
|
||||
};
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
VkResult res = (f); \
|
||||
if (res != VK_SUCCESS) \
|
||||
{ \
|
||||
if(res == VK_ERROR_DEVICE_LOST) \
|
||||
{ \
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3)); \
|
||||
} \
|
||||
std::cout << "Fatal : VkResult is \"" << res << "\" in " << __FILE__ << " at line " << __LINE__ << std::endl; \
|
||||
assert(res == VK_SUCCESS); \
|
||||
} \
|
||||
|
||||
@@ -160,7 +160,10 @@ class StructuredBuffer : public Gfx::StructuredBuffer, public ShaderBuffer
|
||||
public:
|
||||
StructuredBuffer(PGraphics graphics, const StructuredBufferCreateInfo &resourceData);
|
||||
virtual ~StructuredBuffer();
|
||||
virtual bool updateContents(const BulkResourceData &resourceData);
|
||||
|
||||
virtual void* lock(bool bWriteOnly = true) override;
|
||||
virtual void unlock() override;
|
||||
protected:
|
||||
// Inherited via Vulkan::Buffer
|
||||
virtual VkAccessFlags getSourceAccessMask();
|
||||
|
||||
@@ -370,7 +370,11 @@ PComputePipeline PipelineCache::createPipeline(const ComputePipelineCreateInfo&
|
||||
computeStage->getModuleHandle(),
|
||||
computeStage->getEntryPointName());
|
||||
VkPipeline pipelineHandle;
|
||||
auto beginTime = std::chrono::high_resolution_clock::now();
|
||||
VK_CHECK(vkCreateComputePipelines(graphics->getDevice(), cache, 1, &createInfo, nullptr, &pipelineHandle));
|
||||
auto endTime = std::chrono::high_resolution_clock::now();
|
||||
int64 delta = std::chrono::duration_cast<std::chrono::microseconds>(endTime - beginTime).count();
|
||||
std::cout << "Compute creation time: " << delta << std::endl;
|
||||
PComputePipeline result = new ComputePipeline(graphics, pipelineHandle, layout, computeInfo);
|
||||
return result;
|
||||
}
|
||||
@@ -22,44 +22,44 @@ Queue::~Queue()
|
||||
|
||||
void Queue::submitCommandBuffer(PCmdBuffer cmdBuffer, uint32 numSignalSemaphores, VkSemaphore *signalSemaphores)
|
||||
{
|
||||
|
||||
std::scoped_lock lck(queueLock);
|
||||
assert(cmdBuffer->state == CmdBuffer::State::Ended);
|
||||
|
||||
PFence fence = cmdBuffer->fence;
|
||||
assert(!fence->isSignaled());
|
||||
|
||||
const VkCommandBuffer cmdBuffers[] = {cmdBuffer->handle};
|
||||
|
||||
VkSubmitInfo submitInfo =
|
||||
init::SubmitInfo();
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = cmdBuffers;
|
||||
submitInfo.signalSemaphoreCount = static_cast<uint32>(numSignalSemaphores);
|
||||
submitInfo.pSignalSemaphores = signalSemaphores;
|
||||
|
||||
Array<VkSemaphore> waitSemaphores;
|
||||
if (cmdBuffer->waitSemaphores.size() > 0)
|
||||
{
|
||||
std::scoped_lock lck(queueLock);
|
||||
assert(cmdBuffer->state == CmdBuffer::State::Ended);
|
||||
|
||||
PFence fence = cmdBuffer->fence;
|
||||
assert(!fence->isSignaled());
|
||||
|
||||
const VkCommandBuffer cmdBuffers[] = {cmdBuffer->handle};
|
||||
|
||||
VkSubmitInfo submitInfo =
|
||||
init::SubmitInfo();
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = cmdBuffers;
|
||||
submitInfo.signalSemaphoreCount = static_cast<uint32>(numSignalSemaphores);
|
||||
submitInfo.pSignalSemaphores = signalSemaphores;
|
||||
|
||||
Array<VkSemaphore> waitSemaphores;
|
||||
if (cmdBuffer->waitSemaphores.size() > 0)
|
||||
for (PSemaphore semaphore : cmdBuffer->waitSemaphores)
|
||||
{
|
||||
for (PSemaphore semaphore : cmdBuffer->waitSemaphores)
|
||||
{
|
||||
waitSemaphores.add(semaphore->getHandle());
|
||||
}
|
||||
submitInfo.waitSemaphoreCount = static_cast<uint32>(cmdBuffer->waitSemaphores.size());
|
||||
submitInfo.pWaitSemaphores = waitSemaphores.data();
|
||||
submitInfo.pWaitDstStageMask = cmdBuffer->waitFlags.data();
|
||||
waitSemaphores.add(semaphore->getHandle());
|
||||
}
|
||||
VK_CHECK(vkQueueSubmit(queue, 1, &submitInfo, fence->getHandle()));
|
||||
cmdBuffer->state = CmdBuffer::State::Submitted;
|
||||
cmdBuffer->waitFlags.clear();
|
||||
cmdBuffer->waitSemaphores.clear();
|
||||
|
||||
if (Gfx::waitIdleOnSubmit)
|
||||
{
|
||||
fence->wait(200 * 1000ull);
|
||||
}
|
||||
|
||||
cmdBuffer->refreshFence();
|
||||
graphics->getStagingManager()->clearPending();
|
||||
submitInfo.waitSemaphoreCount = static_cast<uint32>(cmdBuffer->waitSemaphores.size());
|
||||
submitInfo.pWaitSemaphores = waitSemaphores.data();
|
||||
submitInfo.pWaitDstStageMask = cmdBuffer->waitFlags.data();
|
||||
}
|
||||
VK_CHECK(vkQueueSubmit(queue, 1, &submitInfo, fence->getHandle()));
|
||||
cmdBuffer->state = CmdBuffer::State::Submitted;
|
||||
cmdBuffer->waitFlags.clear();
|
||||
cmdBuffer->waitSemaphores.clear();
|
||||
|
||||
if (Gfx::waitIdleOnSubmit)
|
||||
{
|
||||
fence->wait(200 * 1000ull);
|
||||
}
|
||||
|
||||
cmdBuffer->refreshFence();
|
||||
graphics->getStagingManager()->clearPending();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user