NRDSample
NRDSample copied to clipboard
Implementing NRI/NRD command context
I am adding real-time denoising support to my CPU(Yes CPU) path tracer. I already have Optix denoising running and it works like a charm. Now i need a solution for AMD GPUs. I chose NRD. I have a budget of 0.5 sec/ frame to perform denoising.
How to properly execute an NRI/NRD command context? Basically i have a native DX12 command context:
struct CommandContext
{
IDXGIFactory4* factory;
ID3D12Device* device;
ID3D12CommandAllocator* commandAllocator;
ID3D12GraphicsCommandList* commandList;
ID3D12CommandQueue* commandQueue;
ID3D12Fence* fence;
HANDLE fenceEvent;
UINT64 fenceValue;
} m_cmdContext;
I use that native context to create an NRI/NRD command context
void NvidiaNRDDenoiser::createNRDContext(nbUint32 imageWidth, nbUint32 imageHeight)
{
m_NRD = new NrdIntegration(1, false, "NvidiaNRDDenoiser NrdIntegration");
//=======================================================================================================
// INITIALIZATION - WRAP NATIVE DEVICE
//=======================================================================================================
// Wrap the device
nri::DeviceCreationD3D12Desc deviceDesc = {};
deviceDesc.d3d12Device = m_cmdContext.device;
deviceDesc.d3d12GraphicsQueue = m_cmdContext.commandQueue;
#if defined (_DEBUG)
deviceDesc.enableNRIValidation = true;
#else
deviceDesc.enableNRIValidation = false;
#endif
nri::Result nriResult = nri::nriCreateDeviceFromD3D12Device(deviceDesc, m_nriDevice);
// Get core functionality
nriResult = nri::nriGetInterface(*m_nriDevice,
NRI_INTERFACE(nri::CoreInterface), (nri::CoreInterface*)&m_NRI);
nriResult = nri::nriGetInterface(*m_nriDevice,
NRI_INTERFACE(nri::HelperInterface), (nri::HelperInterface*)&m_NRI);
// Get appropriate "wrapper" extension (XXX - can be D3D11, D3D12 or VULKAN)
nriResult = nri::nriGetInterface(*m_nriDevice,
NRI_INTERFACE(nri::WrapperD3D12Interface), (nri::WrapperD3D12Interface*)&m_NRI);
//=======================================================================================================
// INITIALIZATION - INITIALIZE NRD
//=======================================================================================================
const nrd::DenoiserDesc denoiserDescs[] =
{
{ NRD_ID(REBLUR_DIFFUSE_SPECULAR), nrd::Denoiser::REBLUR_DIFFUSE_SPECULAR },
};
nrd::InstanceCreationDesc instanceCreationDesc = {};
instanceCreationDesc.denoisers = denoiserDescs;
instanceCreationDesc.denoisersNum = _countof(denoiserDescs);
// NRD itself is flexible and supports any kind of dynamic resolution scaling, but NRD INTEGRATION pre-
// allocates resources with statically defined dimensions. DRS is only supported by adjusting the viewport
// via "CommonSettings::rectSize"
bool result = m_NRD->Initialize((uint16_t)imageWidth, (uint16_t)imageHeight, instanceCreationDesc, *m_nriDevice, m_NRI, m_NRI);
ASSERT(result);
//=======================================================================================================
// INITIALIZATION or RENDER - WRAP NATIVE POINTERS
//=======================================================================================================
// Wrap the command buffer
nri::CommandBufferD3D12Desc commandBufferDesc = {};
commandBufferDesc.d3d12CommandList = m_cmdContext.commandList;
// Not needed for NRD integration layer, but needed for NRI validation layer
commandBufferDesc.d3d12CommandAllocator = m_cmdContext.commandAllocator;
m_NRI.CreateCommandBufferD3D12(*m_nriDevice, commandBufferDesc, m_nriCommandBuffer);
}
Now I need to implement denoising. Execution should look like this:
startCommandRecording()
PerformDensoising()
EndCommandRecording()
WaitForGPU()
So i Need to implement startCommandRecording, EndCommandRecording, and WaitForGPU for NRI
With my native DX12 context it would look like this:
void NvidiaNRDDenoiser::startCommandRecording()
{
HRESULT hr = m_cmdContext.commandAllocator->Reset();
ASSERT(SUCCEEDED(hr));
hr = m_cmdContext.commandList->Reset(m_cmdContext.commandAllocator, nullptr);
ASSERT(SUCCEEDED(hr));
}
void NvidiaNRDDenoiser::endCommandRecording()
{
HRESULT hr = m_cmdContext.commandList->Close();
ASSERT(SUCCEEDED(hr));
// Execute the command lists
ID3D12CommandList* ppCommandLists[] = { m_cmdContext.commandList };
m_cmdContext.commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
}
void NvidiaNRDDenoiser::WaitForGPU()
{
const UINT64 fence = m_cmdContext.fenceValue;
HRESULT hr = m_cmdContext.commandQueue->Signal(m_cmdContext.fence, fence);
// Wait until GPU finish with command queue.
if (m_cmdContext.fence->GetCompletedValue() < fence)
{
hr = m_cmdContext.fence->SetEventOnCompletion(fence, m_cmdContext.fenceEvent);
ASSERT(SUCCEEDED(hr));
WaitForSingleObject(m_cmdContext.fenceEvent, INFINITE);
}
++m_cmdContext.fenceValue;
}
How to implement these 3 for NRI?
Thanks for helping!