'I want to use a UAV in a pixel shader to read the data in the buffer with the CPU

I would like to have information on the number of vertices that have been increased by doing Tessellation. To do this, we send the vertex information from the Domain Shader to the Pixel Shader and use the RWStructureBuffer in the Pixel Shader as shown below.

struct Data
{
    float3 position;
};


RWStructuredBuffer<Data> rwBuffer0 : register(u1);

・・・

    Data data;
    data.position = input.position;
    rwBuffer0[id] = data;
・・・

}

On the CPU side, we are trying to receive the following.

struct ReternUAV
{
    DirectX::XMFLOA3 position;
};

HRESULT hr = S_OK;
Microsoft::WRL::ComPtr<ID3D11Buffer> outputBuffer;
D3D11_BUFFER_DESC outputDesc;
outputDesc.Usage = D3D11_USAGE_DEFAULT;
outputDesc.ByteWidth = sizeof(ReternUAV) * 10000;
outputDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS;
outputDesc.CPUAccessFlags = 0;
outputDesc.StructureByteStride = sizeof(ReternUAV);
outputDesc.MiscFlags = 0;
device->CreateBuffer(&outputDesc, nullptr, outputBuffer.GetAddressOf());

Microsoft::WRL::ComPtr<ID3D11Buffer> outputResultBuffer;

outputDesc.Usage = D3D11_USAGE_STAGING;
outputDesc.BindFlags = 0;
outputDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;

device->CreateBuffer(&outputDesc, nullptr, outputResultBuffer.GetAddressOf());

D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
uavDesc.Buffer.FirstElement = 0;
uavDesc.Buffer.Flags = 0;
uavDesc.Buffer.NumElements = 10000;
uavDesc.Format = DXGI_FORMAT_R32G32B32_FLOAT;
uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
            Microsoft::WRL::ComPtr<ID3D11UnorderedAccessVie>unorderedAccessView;

hr = device->CreateUnorderedAccessView(outputBuffer.Get(), &uavDesc, unorderedAccessView.GetAddressOf());
if (FAILED(hr))
{
    assert(!"CreateUnorderedAccessView"); // <ーFailed to create
}

ID3D11RenderTargetView* renderTarget = GameScene::GetRenderTargetView();
ID3D11DepthStencilView* deStencilView = GameScene::GetDepthStencilView();
context>OMSetRenderTargetsAndUnorderedAccessViews(1, &renderTarget, deStencilView,1, 1, unorderedAccessView.GetAddressOf(),NULL);


context->DrawIndexed(subset.indexCount, subset.indexStart, 0);

Microsoft::WRL::ComPtr<ID3D11UnorderedAccessView> unCom = nullptr;

context->OMSetRenderTargetsAndUnorderedAccessViews(1, &renderTarget, deStencilView,1, 1, unCom.GetAddressOf(),NULL);

context->CopyResource(outputResultBuffer.Get(), outputBuffer.Get());

D3D11_MAPPED_SUBRESOURCE mappedBuffer;
D3D11_MAP map = D3D11_MAP_READ;

hr = context->Map(outputResultBuffer.Get(), 0, map, 0, &mappedBuffer);

ReternUAV* copy = reinterpret_cast<ReternUAV*>(mappedBuffer.pData);
UINT num = sizeof(copy);
for (int i = 0; i < num; i++)
{

    ReternUAV a = copy[i];
    a = a;
}
context->Unmap(outputResultBuffer.Get(), 0);

It may be that the CreateUnorderedAccessView is failing to create it, but I couldn't figure out what was causing it.

If I ignore this and run, The data in "copy" that I mapped and read is all 0,0,0 and there are only 8 elements.

I would like to ask you where I am going wrong.

If there is a better way to achieve the goal, I would like to hear about it. Eventually, I would like to tessellation and handle the newly obtained data with the CPU.

Thank you very much for your help.



Solution 1:[1]

  1. uavDesc.Format must be DXGI_FORMAT_UNKNOWN when creating a View of a Structured Buffer. Also "UINT num = sizeof(copy);" will not return the number of written vertices. :)

  2. I recommend to create a device using D3D11_CREATE_DEVICE_DEBUG flag and then you will get an explanation why it failed to create the UAV. Just pass the flag to the D3D11CreateDevice().

  3. The best way is to use D3D11_QUERY if you need only the number of vertices.

https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_query https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ns-d3d11-d3d11_query_data_pipeline_statistics

    D3D11_QUERY_DESC qdesc = {D3D11_QUERY_PIPELINE_STATISTICS};
    ID3D11Query* query = 0;
    device->CreateQuery(&qdesc, &query);
    
    context->Begin(query);
    context->DrawIndexed(index_count, 0, 0);
    context->End(query);
    
    D3D11_QUERY_DATA_PIPELINE_STATISTICS stats = {};
    while (S_FALSE == context->GetData(query, &stats, sizeof(stats), 0))
            ;
    query->Release();

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1