D3D12: Can we really not have a 1-dimensional buffer/texture of size > 25000?

79 Views Asked by At

So, what I actually want is rather simple in theory, but I can't get it to work in practice.

I simply want read and write access to a dynamically-sized array of floats from (raytracing) shaders. I think the right thing is to declare this array as an UAV.

However, I've tried to declare it as a RWTexture1D<float> as well as a RWBuffer<float>. But for both I'm receiving the error that the dimension is too large. The dimension I specified was around 100k, but it seems like RWBuffer<float> is limited to 25k and RWTexture1D<float> is limited to 16384. What can I do?

EDIT: This is the code:

    D3D12_UNORDERED_ACCESS_VIEW_DESC unordered_access_view_desc{};
    unordered_access_view_desc.Buffer.NumElements = 100000;
    unordered_access_view_desc.Format = DXGI_FORMAT_R32_FLOAT;
    unordered_access_view_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
    
    d3d.device->CreateUnorderedAccessView(resource, nullptr, &unordered_access_view_desc, handle);

and the error:

The Dimensions of the View are invalid due to at least one of the following conditions. Assuming this Format (0x29, R32_FLOAT), FirstElement (value = 0) must be between 0 and the maximum offset of the Buffer, 24999, inclusively.

I don't get this. If the format would be DXGI_FORMAT_R32G32B32A32_FLOAT instead and I would choose Buffer.NumElements = 25000 I would end up with allocating the same amount of memory.

But even when I use this hack, is it really not possible to create a 1-dimensional array of size > 25000? Even a simple 2-dimensional texture of size 512x512 has more values (262144). Do I really need to create such a 2-dimensional texture and reindex appropriately?


EDIT: This is the code with CreateBuffer I'm using:

D3D12_HEAP_PROPERTIES heapDesc = {};
heapDesc.Type = D3D12_HEAP_TYPE_DEFAULT;
heapDesc.CreationNodeMask = 1;
heapDesc.VisibleNodeMask = 1;

D3D12_RESOURCE_DESC resourceDesc = {};
resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
resourceDesc.Height = 1;
resourceDesc.DepthOrArraySize = 1;
resourceDesc.MipLevels = 1;
resourceDesc.Format = DXGI_FORMAT_UNKNOWN;
resourceDesc.SampleDesc.Count = 1;
resourceDesc.SampleDesc.Quality = 0;
resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
resourceDesc.Width = /* ... */;
resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;

device->CreateCommittedResource(&heapDesc, D3D12_HEAP_FLAG_NONE, &resourceDesc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, IID_PPV_ARGS(&myresource));

and this is the one for CreateCommitedResource:

D3D12_HEAP_PROPERTIES const DefaultHeapProperties =
{
    D3D12_HEAP_TYPE_DEFAULT,
    D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
    D3D12_MEMORY_POOL_UNKNOWN,
    0, 0
};

D3D12_RESOURCE_DESC resource_desc{};
resource_desc.DepthOrArraySize = 1;
resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
//resource_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
resource_desc.Format = DXGI_FORMAT_UNKNOWN;
//resource_desc.Format = DXGI_FORMAT_R32_FLOAT;
resource_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
resource_desc.Width = static_cast<UINT64>(resources.raytracingData.bootstrap_sample_count);
resource_desc.Height = 1;
//resource_desc.Width = /* ... */;
resource_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
resource_desc.MipLevels = 1;
resource_desc.SampleDesc.Count = 1;

device->CreateCommittedResource(&DefaultHeapProperties, D3D12_HEAP_FLAG_NONE, &resource_desc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, IID_PPV_ARGS(&myresource));
2

There are 2 best solutions below

2
mrvux On

In order to use more elements, you need to use structuredBuffers, so in your hlsl code you need to use

RWStructuredBuffer<float>

Also the code to setup the view is different, this needs to be set as :

    D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
    uavDesc.Format = DXGI_FORMAT_UNKNOWN;
    uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
    uavDesc.Buffer.FirstElement = 0;
    uavDesc.Buffer.NumElements = ElementCount; // number of elements you need in your buffer
    uavDesc.Buffer.StructureByteStride = sizeof(float); //size of one element
    uavDesc.Buffer.CounterOffsetInBytes = 0;
    uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;

To create the resource you can continue using CreateCommittedResource:

D3D12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(elementCount * elmentSize , D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
2
Soonts On

Another approach which supports large buffer is raw buffers.

They are exposed to HLSL as RWByteAddressBuffer (read+write access) or ByteAddressBuffer (read only access) objects. Note you will need byte offsets instead of elements offsets (i.e. multiply element offset by 4), and asfloat / asuint when loading / storing data in your shaders.

You need to specify DXGI_FORMAT_R32_TYPELESS for the format of the buffer, and D3D12_BUFFER_UAV_FLAG_RAW or D3D12_BUFFER_SRV_FLAG_RAW flags when creating the views.