Closed kvnnap closed 1 year ago
Are you using modified state after invoking denoising?
// User inputs / outputs are not mipmapped, thus only 1 entry is needed.
// "TextureTransitionBarrierDesc::texture" is used to store the resource.
// "TextureTransitionBarrierDesc::next..." are used to represent current state of the subresource.
struct NrdIntegrationTexture
{
nri::TextureTransitionBarrierDesc* subresourceStates;
nri::Format format;
};
Yes, after calling the denoiser I add transition barriers if the state changed (see sync states section below). However, this code never gets to execute - the state is not changing at all. The only time that the state changes is when I examine the call stack after the break issued by the debug layer, but when that happens the denoiser function has not yet returned. I slightly refactored the code for readability.
The following is the part of code where I invoke the denoiser per frame.
struct DenoiserResource
{
Resource* resource;
D3D12_RESOURCE_STATES requiredState;
nrd::ResourceType resourceType;
nri::Format format;
};
// .
// .
nri::CommandBufferD3D12Desc cmdDesc = {};
cmdDesc.d3d12CommandList = pCurrentCommandList.Get();
cmdDesc.d3d12CommandAllocator = nullptr; // rendererResources->commandQueue->getCommandAllocator(pCurrentCommandList); // Not needed for NRD integration layer
nri::CommandBuffer* cmdBuffer = nullptr;
NRI->CreateCommandBufferD3D12(*nriDevice, cmdDesc, cmdBuffer);
// Wrap required textures
constexpr int N = 5;
nri::TextureTransitionBarrierDesc entryDescs[N] = {};
nri::Format entryFormat[N] = {};
DenoiserResource denoiserResources[N] = {
{ in_mv, D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE, nrd::ResourceType::IN_MV, nri::Format::RGBA32_SFLOAT },
{ in_normal_roughness, D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE, nrd::ResourceType::IN_NORMAL_ROUGHNESS, nri::Format::RGBA32_SFLOAT },
{ in_view_z, D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE, nrd::ResourceType::IN_VIEWZ, nri::Format::R32_SFLOAT },
{ in_diff_radiance_hitdist, D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE, nrd::ResourceType::IN_DIFF_RADIANCE_HITDIST, nri::Format::RGBA32_SFLOAT },
{ out_diff_radiance_hitdist, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nrd::ResourceType::OUT_DIFF_RADIANCE_HITDIST, nri::Format::RGBA32_SFLOAT }
};
for (uint32_t i = 0; i < N; i++)
{
// You need to specify the current state of the resource here, after denoising NRD can modify
// this state. Application must continue state tracking from this point.
// Useful information:
// SRV = nri::AccessBits::SHADER_RESOURCE, nri::TextureLayout::SHADER_RESOURCE
// UAV = nri::AccessBits::SHADER_RESOURCE_STORAGE, nri::TextureLayout::GENERAL
auto& denResource = denoiserResources[i];
nri::TextureD3D12Desc textureDesc = {};
textureDesc.d3d12Resource = *denResource.resource;
NRI->CreateTextureD3D12(*nriDevice, textureDesc, (nri::Texture*&)entryDescs[i].texture);
entryDescs[i].nextAccess = GetResourceState(denResource.requiredState);
entryDescs[i].nextLayout = entryDescs[i].nextAccess == nri::AccessBits::SHADER_RESOURCE ? nri::TextureLayout::SHADER_RESOURCE : nri::TextureLayout::GENERAL;
}
// Currently there is no animation, so passing same matrices for previous and current in the common settings
nrd::CommonSettings commonSettings{};
auto camera = rendererResources->camera;
memcpy(&commonSettings.worldToViewMatrix, &camera->getViewMatrix(), sizeof(commonSettings.worldToViewMatrix));
memcpy(&commonSettings.worldToViewMatrixPrev, &camera->getViewMatrix(), sizeof(commonSettings.worldToViewMatrixPrev));
memcpy(&commonSettings.viewToClipMatrix, &camera->getPerspectiveMatrix(), sizeof(commonSettings.viewToClipMatrix));
memcpy(&commonSettings.viewToClipMatrixPrev, &camera->getPerspectiveMatrix(), sizeof(commonSettings.viewToClipMatrixPrev));
nrd::ReblurSettings settings{};
settings.enableReferenceAccumulation = true;
NRD->SetMethodSettings(nrd::Method::REBLUR_DIFFUSE, &settings);
// Populate the user pool
NrdUserPool userPool = {};
for (uint32_t i = 0; i < N; i++)
{
auto& denResource = denoiserResources[i];
NrdIntegrationTexture tex{};
tex.format = denResource.format;
tex.subresourceStates = &entryDescs[i];
NrdIntegration_SetResource(userPool, denResource.resourceType, tex);
}
//bool isUAV = pDbgCmdList->AssertResourceState(*out_diff_radiance_hitdist, 0, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
NRD->Denoise(currentBackBufferIndex, *cmdBuffer, commonSettings, userPool);
//isUAV = pDbgCmdList->AssertResourceState(*out_diff_radiance_hitdist, 0, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
// Sync states
for (uint32_t i = 0; i < N; i++)
{
auto& denResource = denoiserResources[i];
auto reqState = GetResourceState(denResource.requiredState);
auto reqLayout = reqState == nri::AccessBits::SHADER_RESOURCE ? nri::TextureLayout::SHADER_RESOURCE : nri::TextureLayout::GENERAL;
if (entryDescs[i].nextAccess != reqState || entryDescs[i].nextLayout != reqLayout)
{
denResource.resource->rewriteState(GetResourceState(entryDescs[i].nextAccess));
denResource.resource->transistionBarrier(pCurrentCommandList, denResource.requiredState);
}
}
//bool isUAV = pDbgCmdList->AssertResourceState(*out_diff_radiance_hitdist, 0, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
for (uint32_t i = 0; i < N; i++)
NRI->DestroyTexture(*(nri::Texture*&)entryDescs[i].texture);
NRI->DestroyCommandBuffer(*cmdBuffer);
I am currently using these functions to translate between DirectX and NRI states;
D3D12_RESOURCE_STATES GetResourceState(nri::AccessBits accessBits)
{
D3D12_RESOURCE_STATES result{};
if (accessBits & nri::AccessBits::SHADER_RESOURCE)
result |= D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;
if (accessBits & nri::AccessBits::SHADER_RESOURCE_STORAGE)
result |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
if (result == 0)
throw std::runtime_error("Cannot convert nri::AccessBits");
return result;
}
nri::AccessBits GetResourceState(D3D12_RESOURCE_STATES d3dResourceState)
{
nri::AccessBits result{};
if (d3dResourceState & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE)
result |= nri::AccessBits::SHADER_RESOURCE;
if (d3dResourceState & D3D12_RESOURCE_STATE_UNORDERED_ACCESS)
result |= nri::AccessBits::SHADER_RESOURCE_STORAGE;
if (result == nri::AccessBits::UNKNOWN)
throw std::runtime_error("Cannot convert D3D12_RESOURCE_STATES");
return result;
}
Found the issue. The problem here is that enableDescriptorCaching
(the fifth parameter of NRD->Denoise
) is passed with default value true
. However, the texture wrappers are being created per frame using NRI->CreateTextureD3D12
and hence enableDescriptorCaching
needs to be false
. I was also getting erroneous visual output due to this. Passing enableDescriptorCaching
as false
in this case solves the issue.
Thanks for not giving up. Since you are not the only one bumping into this, I will clarify enableDescriptorCaching
even better (in the doc and code) in the upcoming update.
Hi,
I am experiencing issues with the resource state of the output texture passed to the denoiser. The DirectX debug layer breaks with
ERROR RESOURCE_MANIPULATION #527: RESOURCE_BARRIER_BEFORE_AFTER_MISMATCH
. It seems as if the current state of the resource is different from the barrier being issued. This error is not deterministic, it sometimes occurs at frame 2, frame 3, frame 6, etc.All input textures are in
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
and the output texture is inD3D12_RESOURCE_STATE_UNORDERED_ACCESS
before executing the denoiser (with methodnrd::Method::REBLUR_DIFFUSE
). I usedID3D12DebugCommandList
to verify this is the case. The NRI mapping of the textures is shown below:I am using the NRD integration code and have compiled NRD (3.4.1.0) and NRI (1.84.0.0) DLLs for use with my renderer (running on 2080 Ti).
Part of the call stack:
Error:
Additionally, if I perform resource state assertions prior to calling the denoiser I get the following:
I am not sure why this is happening and I hope someone can help. Please do let me know should you require any further information.