236 lines
11 KiB
C++
236 lines
11 KiB
C++
// This file is part of the FidelityFX SDK.
|
|
//
|
|
// Copyright (C) 2024 Advanced Micro Devices, Inc.
|
|
//
|
|
// 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 "breadcrumbsrendermodule.h"
|
|
|
|
#include "core/backend_interface.h"
|
|
#include "core/framework.h"
|
|
#include "core/loaders/textureloader.h"
|
|
#include "render/device.h"
|
|
#include "render/dynamicresourcepool.h"
|
|
#include "render/parameterset.h"
|
|
#include "render/pipelineobject.h"
|
|
#include "render/profiler.h"
|
|
#include "render/rasterview.h"
|
|
#include "render/renderdefines.h"
|
|
#include "render/uploadheap.h"
|
|
#include "render/swapchain.h"
|
|
|
|
#include <array>
|
|
#include <limits>
|
|
|
|
using namespace cauldron;
|
|
|
|
BreadcrumbsRenderModule::BreadcrumbsRenderModule()
|
|
: RenderModule(L"BreadcrumbsRenderModule")
|
|
{
|
|
}
|
|
|
|
BreadcrumbsRenderModule::~BreadcrumbsRenderModule()
|
|
{
|
|
if (m_pParams)
|
|
delete m_pParams;
|
|
if (m_pPipeline)
|
|
delete m_pPipeline;
|
|
if (m_pRootSig)
|
|
delete m_pRootSig;
|
|
|
|
// Destroy Breadcrumbs context
|
|
if (m_BreadContextCreated)
|
|
ffxBreadcrumbsContextDestroy(&m_BreadContext);
|
|
|
|
// Release the scratch buffer memory
|
|
if (m_BackendScratchBuffer)
|
|
free(m_BackendScratchBuffer);
|
|
}
|
|
|
|
void BreadcrumbsRenderModule::Init(const json& initData)
|
|
{
|
|
m_pRenderTarget = GetFramework()->GetColorTargetForCallback(GetName());
|
|
m_pRasterView = GetRasterViewAllocator()->RequestRasterView(m_pRenderTarget, ViewDimension::Texture2D);
|
|
GetDevice()->RegisterDeviceRemovedCallback(BreadcrumbsRenderModule::ProcessDeviceRemovedEvent, &m_BreadContext);
|
|
|
|
FfxBreadcrumbsContextDescription contextDesc = {};
|
|
|
|
// Initialize the FFX backend
|
|
size_t scratchBufferSize = SDKWrapper::ffxGetScratchMemorySize(FFX_BREADCRUMBS_CONTEXT_COUNT);
|
|
m_BackendScratchBuffer = calloc(scratchBufferSize, 1);
|
|
FfxErrorCode errorCode = SDKWrapper::ffxGetInterface(&contextDesc.backendInterface, GetDevice(),
|
|
m_BackendScratchBuffer, scratchBufferSize, FFX_BREADCRUMBS_CONTEXT_COUNT);
|
|
CAULDRON_ASSERT(errorCode == FFX_OK);
|
|
CauldronAssert(ASSERT_CRITICAL, contextDesc.backendInterface.fpGetSDKVersion(&contextDesc.backendInterface) == FFX_SDK_MAKE_VERSION(1, 1, 2),
|
|
L"FidelityFX Breadcrumbs 1.0 sample requires linking with a 1.1.2 version SDK backend");
|
|
CauldronAssert(ASSERT_CRITICAL, ffxBreadcrumbsGetEffectVersion() == FFX_SDK_MAKE_VERSION(1, 0, 0),
|
|
L"FidelityFX Breadcrumbs 1.0 sample requires linking with a 1.0 version FidelityFX Breadcrumbs library");
|
|
|
|
contextDesc.backendInterface.fpRegisterConstantBufferAllocator(&contextDesc.backendInterface, SDKWrapper::ffxAllocateConstantBuffer);
|
|
|
|
|
|
// Create Breadcrumbs context
|
|
contextDesc.flags = FFX_BREADCRUMBS_PRINT_FINISHED_LISTS | FFX_BREADCRUMBS_PRINT_NOT_STARTED_LISTS
|
|
| FFX_BREADCRUMBS_PRINT_FINISHED_NODES | FFX_BREADCRUMBS_PRINT_NOT_STARTED_NODES;
|
|
contextDesc.frameHistoryLength = static_cast<uint32_t>(GetFramework()->GetSwapChain()->GetBackBufferCount() * 2);
|
|
contextDesc.maxMarkersPerMemoryBlock = 3;
|
|
contextDesc.usedGpuQueuesCount = 1;
|
|
contextDesc.pUsedGpuQueues = &m_GpuQueue;
|
|
contextDesc.allocCallbacks.fpAlloc = malloc;
|
|
contextDesc.allocCallbacks.fpRealloc = realloc;
|
|
contextDesc.allocCallbacks.fpFree = free;
|
|
errorCode = ffxBreadcrumbsContextCreate(&m_BreadContext, &contextDesc);
|
|
CAULDRON_ASSERT(errorCode == FFX_OK);
|
|
m_BreadContextCreated = true;
|
|
|
|
// Create root signature
|
|
RootSignatureDesc rootSigDesc = {};
|
|
rootSigDesc.AddConstantBufferView(0, ShaderBindStage::Vertex, 1);
|
|
m_pRootSig = RootSignature::CreateRootSignature(L"BreadcrumbsEffect_RootSignature", rootSigDesc);
|
|
|
|
// Create pipeline
|
|
PipelineDesc psoDesc = {};
|
|
psoDesc.SetRootSignature(m_pRootSig);
|
|
psoDesc.AddRasterFormats(GetFramework()->GetColorTargetForCallback(GetName())->GetFormat());
|
|
psoDesc.AddPrimitiveTopology(PrimitiveTopologyType::Triangle);
|
|
|
|
DefineList defines = {};
|
|
psoDesc.AddShaderDesc(ShaderBuildDesc::Vertex(L"crash_vs.hlsl", L"mainVS", ShaderModel::SM6_0, &defines));
|
|
psoDesc.AddShaderDesc(ShaderBuildDesc::Pixel(L"simple_ps.hlsl", L"mainPS", ShaderModel::SM6_0, &defines));
|
|
|
|
m_pPipeline = PipelineObject::CreatePipelineObject(L"BreadcrumbsEffect_Pipeline", psoDesc);
|
|
|
|
// Register pipeline for Breadcrumbs
|
|
FfxBreadcrumbsPipelineStateDescription pipelineDesc = {};
|
|
pipelineDesc.pipeline = SDKWrapper::ffxGetPipeline(m_pPipeline);
|
|
pipelineDesc.name = { "Basic pipeline", true };
|
|
pipelineDesc.vertexShader = { "EndlessLoopVS", true };
|
|
pipelineDesc.pixelShader = { "SolidColorPS", true };
|
|
errorCode = ffxBreadcrumbsRegisterPipeline(&m_BreadContext, &pipelineDesc);
|
|
CAULDRON_ASSERT(errorCode == FFX_OK);
|
|
|
|
// Setup crashing buffer set
|
|
m_pParams = ParameterSet::CreateParameterSet(m_pRootSig);
|
|
m_pParams->SetRootConstantBufferResource(GetDynamicBufferPool()->GetResource(), sizeof(uint32_t), 0);
|
|
|
|
SetModuleReady(true);
|
|
}
|
|
|
|
void BreadcrumbsRenderModule::Execute(double deltaTime, cauldron::CommandList* pCmdList)
|
|
{
|
|
// Crash case: infinite loop in single vertex shader invocation
|
|
uint32_t crashLoopCount = 0;
|
|
// Wait for crash frame to not miss the crash point due to too fast execution
|
|
if (GetFramework()->GetFrameID() == m_CrashFrame - 2)
|
|
GetDevice()->FlushAllCommandQueues();
|
|
if (GetFramework()->GetFrameID() == m_CrashFrame)
|
|
crashLoopCount = UINT32_MAX;
|
|
|
|
// Transition render target
|
|
Barrier barrier = Barrier::Transition(m_pRenderTarget->GetResource(),
|
|
ResourceState::NonPixelShaderResource | ResourceState::PixelShaderResource,
|
|
ResourceState::RenderTargetResource);
|
|
ResourceBarrier(pCmdList, 1, &barrier);
|
|
|
|
// Begin new frame
|
|
FfxErrorCode errorCode = ffxBreadcrumbsStartFrame(&m_BreadContext);
|
|
CAULDRON_ASSERT(errorCode == FFX_OK);
|
|
|
|
// Register command list before using breadcrumbs on it
|
|
FfxBreadcrumbsCommandListDescription listDesc = {};
|
|
listDesc.commandList = SDKWrapper::ffxGetCommandList(pCmdList);
|
|
listDesc.queueType = m_GpuQueue;
|
|
listDesc.name = { "Sample command list", true };
|
|
listDesc.pipeline = nullptr;
|
|
listDesc.submissionIndex = 0;
|
|
errorCode = ffxBreadcrumbsRegisterCommandList(&m_BreadContext, &listDesc);
|
|
CAULDRON_ASSERT(errorCode == FFX_OK);
|
|
|
|
// Create tag for main part of rendering
|
|
const FfxBreadcrumbsNameTag mainTag = { "Main rendering", true };
|
|
errorCode = ffxBreadcrumbsBeginMarker(&m_BreadContext, SDKWrapper::ffxGetCommandList(pCmdList), FFX_BREADCRUMBS_MARKER_PASS, &mainTag);
|
|
CAULDRON_ASSERT(errorCode == FFX_OK);
|
|
{
|
|
// Perform simple clear
|
|
const FfxBreadcrumbsNameTag clearTag = { "Reset current backbuffer contents", true };
|
|
errorCode = ffxBreadcrumbsBeginMarker(&m_BreadContext, SDKWrapper::ffxGetCommandList(pCmdList), FFX_BREADCRUMBS_MARKER_CLEAR_RENDER_TARGET, &clearTag);
|
|
CAULDRON_ASSERT(errorCode == FFX_OK);
|
|
{
|
|
float clearColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
|
ClearRenderTarget(pCmdList, &m_pRasterView->GetResourceView(), clearColor);
|
|
}
|
|
errorCode = ffxBreadcrumbsEndMarker(&m_BreadContext, SDKWrapper::ffxGetCommandList(pCmdList));
|
|
CAULDRON_ASSERT(errorCode == FFX_OK);
|
|
|
|
BeginRaster(pCmdList, 1, &m_pRasterView);
|
|
|
|
BufferAddressInfo bufferInfo = GetDynamicBufferPool()->AllocConstantBuffer(sizeof(uint32_t), &crashLoopCount);
|
|
m_pParams->UpdateRootConstantBuffer(&bufferInfo, 0);
|
|
m_pParams->Bind(pCmdList, m_pPipeline);
|
|
|
|
// Set and register pipeline state for future markers
|
|
SetPipelineState(pCmdList, m_pPipeline);
|
|
errorCode = ffxBreadcrumbsSetPipeline(&m_BreadContext, SDKWrapper::ffxGetCommandList(pCmdList), SDKWrapper::ffxGetPipeline(m_pPipeline));
|
|
CAULDRON_ASSERT(errorCode == FFX_OK);
|
|
|
|
const ResolutionInfo& resInfo = GetFramework()->GetResolutionInfo();
|
|
SetViewportScissorRect(pCmdList, 0, 0, resInfo.DisplayWidth, resInfo.DisplayHeight, 0.f, 1.f);
|
|
SetPrimitiveTopology(pCmdList, PrimitiveTopology::TriangleList);
|
|
|
|
// Perform simple triangle render
|
|
const FfxBreadcrumbsNameTag drawTag = { "Draw simple triangle", true };
|
|
errorCode = ffxBreadcrumbsBeginMarker(&m_BreadContext, SDKWrapper::ffxGetCommandList(pCmdList), FFX_BREADCRUMBS_MARKER_DRAW_INSTANCED, &drawTag);
|
|
CAULDRON_ASSERT(errorCode == FFX_OK);
|
|
{
|
|
DrawInstanced(pCmdList, 3);
|
|
}
|
|
errorCode = ffxBreadcrumbsEndMarker(&m_BreadContext, SDKWrapper::ffxGetCommandList(pCmdList));
|
|
CAULDRON_ASSERT(errorCode == FFX_OK);
|
|
|
|
EndRaster(pCmdList);
|
|
}
|
|
// End top level marker
|
|
errorCode = ffxBreadcrumbsEndMarker(&m_BreadContext, SDKWrapper::ffxGetCommandList(pCmdList));
|
|
CAULDRON_ASSERT(errorCode == FFX_OK);
|
|
|
|
// Transition render target back
|
|
barrier = Barrier::Transition(m_pRenderTarget->GetResource(),
|
|
ResourceState::RenderTargetResource,
|
|
ResourceState::NonPixelShaderResource | ResourceState::PixelShaderResource);
|
|
ResourceBarrier(pCmdList, 1, &barrier);
|
|
}
|
|
|
|
void BreadcrumbsRenderModule::ProcessDeviceRemovedEvent(void* data)
|
|
{
|
|
FfxBreadcrumbsMarkersStatus markerStatus = {};
|
|
FfxErrorCode result = ffxBreadcrumbsPrintStatus((FfxBreadcrumbsContext*)data, &markerStatus);
|
|
CauldronAssert(ASSERT_CRITICAL, result == FFX_OK, L"Failed to retrieve markers buffer!");
|
|
|
|
std::ofstream fout("breadcrumbs_sample_dumpfile.txt", std::ios::binary);
|
|
CauldronAssert(ASSERT_WARNING, fout.good(), L"Failed to create \"breadcrumbs_sample.txt\"!");
|
|
|
|
if (fout.good())
|
|
{
|
|
fout.write(markerStatus.pBuffer, markerStatus.bufferSize);
|
|
fout.close();
|
|
}
|
|
// Freeing markers buffer with same functions as provided in FfxBreadcrumbsContextDescription::allocCallbacks::fpFree
|
|
FFX_SAFE_FREE(markerStatus.pBuffer, free);
|
|
}
|