I am trying to implement Photon-Mapping in DXR using DX12. Details aside, I have a RWStructured buffer that I store Photons in. The buffer is written to from within a closest hit shader, and I synchronize writes to this buffer from multiple thread groups via a counter. This works, and my photons are happily stored. I then call an instanced draw for all photons within this buffer, which rasterises their splatting radius on the screen. Theoretically, I should be able to decrement the counter within the vertex shader for this draw, and have it return to 0. However, even when I do this, the counter does not reset to 0. This means that when I move the light source per frame, the photon buffer doesn't update as it's already full from the initial frame. Any help on what I'm doing wrong would be great. :)
Note - I have tried using InterlockedAdd(countingBufferIndex, 1, dstIndex) in hlsl to synchronize access to the buffer, instead of calling dstIndex = Buffer.IncrementCounter(), however in this case, only a small number of photons are pushed to the buffer - looking at the memory in Pix, or NSight, only about 1/100th of the buffer is filled.
//create the counting buffer for the photons
void Application::CreateCountBuffer() {
auto device = m_deviceResources->GetD3DDevice();
UINT size = 4;
D3D12_RESOURCE_DESC desc = {};
desc.Alignment = 0;
desc.DepthOrArraySize = 1;
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
desc.Format = DXGI_FORMAT_UNKNOWN;
desc.Height = 1;
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
desc.MipLevels = 1;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Width = (UINT64)size;
auto heapProps = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
ThrowIfFailed(device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, IID_PPV_ARGS(&photonCountBuffer)));
photonCountBuffer->SetName(L"CountingPhotonsBuffer");
photonCounterDescriptorHeapIndex = AllocateDescriptor(&photonCountCPUDescriptor, photonCounterDescriptorHeapIndex);
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
uavDesc.Buffer.NumElements = 1;
uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
device->CreateUnorderedAccessView(photonCountBuffer.Get(), nullptr, &uavDesc, photonCountCPUDescriptor);
photonCounterGpuDescriptor = CD3DX12_GPU_DESCRIPTOR_HANDLE(m_descriptorHeap->GetGPUDescriptorHandleForHeapStart(), photonCountUavDescriptorHeapIndex, m_descriptorSize);
}
//create the RWStructuredBuffer for storing the photons
void Application::CreatePhotonStructuredBuffer() {
auto device = m_deviceResources->GetD3DDevice();
auto backBufferFormat = m_deviceResources->GetBackBufferFormat();
{
UINT64 size = sizeof(Photon);
UINT64 bufferSize = PHOTON_COUNT * size;
auto uavDesc = CD3DX12_RESOURCE_DESC::Buffer(bufferSize, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
auto defaultHeapProperties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
ThrowIfFailed(device->CreateCommittedResource(&defaultHeapProperties, D3D12_HEAP_FLAG_NONE, &uavDesc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, IID_PPV_ARGS(&photonStructBuffer)));
NAME_D3D12_OBJECT(photonStructBuffer);
photonStructGpuHeapIndex = AllocateDescriptor(&photonStructCPUDescriptor, photonStructGpuHeapIndex);
D3D12_UNORDERED_ACCESS_VIEW_DESC uavPhotonDesc = {};
uavPhotonDesc.Buffer.NumElements = PHOTON_COUNT;
uavPhotonDesc.Buffer.FirstElement = 0;
uavPhotonDesc.Buffer.StructureByteStride = size;
uavPhotonDesc.Buffer.CounterOffsetInBytes = 0;
uavPhotonDesc.Format = DXGI_FORMAT_UNKNOWN;
uavPhotonDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
device->CreateUnorderedAccessView(photonStructBuffer.Get(),photonCountBuffer.Get(), &uavPhotonDesc, photonStructCPUDescriptor);
photonStructGPUDescriptor = CD3DX12_GPU_DESCRIPTOR_HANDLE(m_descriptorHeap->GetGPUDescriptorHandleForHeapStart(), photonStructGpuHeapIndex, m_descriptorSize);
}
}
///////////Registers for Photon Structured Buffer and counter buffer within Ray-Tracing shader/////////////
RWStructuredBuffer<Photon> photonBuffer : register(u1);
RWByteAddressBuffer photonBufferCounter : register(u2);
////////////Storing Photons - called within a Closest Hit shader/////////////////
uint dstIndex = photonBuffer.IncrementCounter();
float raySize = sqrt(dot(pos - WorldRayOrigin(), pos - WorldRayOrigin()));
Photon p = { float4(pos, raySize), float4(dir, 1), float4(colour, 1), float4(attr.normal, 1) };
if (dstIndex < PHOTON_COUNT) {
photonBuffer[dstIndex] = p;
}
else {
uint decr = photonBuffer.DecrementCounter();
}
}
/////////////Register for Photon Buffer within Raster Pipeline //////////////////////////////////////////////////////////////////////
RWStructuredBuffer<Photon> photons : register(u1);
//////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
///////////Decrement Counter - called within the vertex shader of an instanced draw (called per photon)//////
/////////////////////////////////////////////////////////////////////////////////////////////////////
PSInput VSMain(float4 position : POSITION, uint instanceID : SV_InstanceID, float4 color : COLOR)
{
float lMax = 50;
float maxMajorKernelRadius = 10;
float minMajKernelRadius = 0.1;
float pi = 3.1415926535897932384626422832795028841971f;
PSInput result;
Photon photon = photons[instanceID];
uint decr = photons.DecrementCounter();
.
.
.
}