RWStructuredBuffer in hlsl/DX12 - difficulties with atomic adding - can't reset counter.

Started by
1 comment, last by MJP 3 years, 8 months ago

Hi everyone,

I am trying to implement Photon Mapping in DXR using DX12 - I am fairly new to DX12 (about 6 months experience), so am having a bit of difficulty with dynamically adding elements to a RWStructuredBuffer. For this I am storing ‘photons’ in a RWStructuredBuffer<Photon> on the GPU. I have an attached counter to the buffer, and deposit photons into it via calling IncrementCounter. This works, and my photons are happily stored. I then call an instanced draw for all photons and rasterise 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, meaning no dynamic GI. Any help on what I'm doing wrong would be awesome. I have attached my resource setup, as well as my storing code below.:)

//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(&amp;heapProps, D3D12_HEAP_FLAG_NONE, &amp;desc, 	D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, IID_PPV_ARGS(&amp;photonCountBuffer)));

    photonCountBuffer->SetName(L"CountingPhotonsBuffer");
    photonCounterDescriptorHeapIndex = AllocateDescriptor(&amp;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, &amp;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(&amp;defaultHeapProperties, D3D12_HEAP_FLAG_NONE, &amp;uavDesc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, IID_PPV_ARGS(&amp;photonStructBuffer)));
        NAME_D3D12_OBJECT(photonStructBuffer);

        photonStructGpuHeapIndex = AllocateDescriptor(&amp;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(), &amp;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();
    .
    .
    .
    }
Advertisement

What kind of primitives are you actually drawing when you use that vertex shader that decrements the counter? Depending on what you're drawing and how you're indexing it's possible that the VS is executing more times than expect, which would cause the counter to underflow.

Either way, this would probably be simpler and easier if you just clear the counter with a compute shader or with ClearUnorderedAccessViewUint.

This topic is closed to new replies.

Advertisement