How to access UAVs from any shader stage

Started by
6 comments, last by Akenre 7 years, 7 months ago

Hi,

i am trying to find concrete info about the Directx 11.1 feature:

Unordered access views can be accessed from any shader stage

https://msdn.microsoft.com/en-us/library/windows/hardware/dn653328(v=vs.85).aspx

The name of the feature seems to imply that it is not necessary to bind uavs from C++ side for

additional shaders once it is bound to one shader, but i cannot verify if i misunderstood this.

In that case what register(s) would be used for that sharing of the uav?

What i am trying to do is to use a uav/RWByteAddressBuffer written to in a compute shader directly in a vertex shader for vertex, color, texture data without mapping the results and unnecessarily transferring the data between GPU and CPU.

However, even if that would have to be done from C++, there would be no directx device method available such as:

dc->VSSetUnorderedAccessViews()

I also cannot use a constant buffer slot because the bind-flags uav and constant buffer together are not allowed.

Has anyone succesfuly done this and could enlighten me on how to do this?

Thank you

Advertisement

You just need to create a shader resource view for the same buffer and set that for the vertex shader.

IIRC the only way to bind UAV's in D3D11 is to the OM stage. With this feature, I assume every shader stage gets its UAV bindings from the OM stage. If my assumption is right, you'd bind them for your VS the same way that you'd usually bind them for a PS in vanilla D3D11.

However, yeah as mentioned by Syntac_, if your vertex shader does not need to write to the resource, then it should use a SRV (or IA-stage vertex buffer binding if the buffer contains per-vertex or per-instance data) instead of a UAV.

Note that D3D's **V's are just "views" of a particular resource - they are not the resource. One resource can have several views -- such as a UAV that's used by a compute shader, and an SRV used by a vertex shader.

IIRC the only way to bind UAV's in D3D11 is to the OM stage. With this feature, I assume every shader stage gets its UAV bindings from the OM stage. If my assumption is right, you'd bind them for your VS the same way that you'd usually bind them for a CS in vanilla D3D11.

However, yeah as mentioned by Syntac_, if your vertex shader does not need to write to the resource, then it should use a SRV (or IA-stage vertex buffer binding if the buffer contains per-vertex or per-instance data) instead of a UAV.

Note that D3D's **V's are just "views" of a particular resource - they are not the resource. One resource can have several views -- such as a UAV that's used by a compute shader, and an SRV used by a vertex shader.

This is correct, UAVs bound at the OM stage are visible to the entire graphics pipeline. But do also be aware that you can't bind the same resource for input and output at the same time, so if your PS needs to use it as a UAV, then your VS can't bind it as an SRV - but it can access the same UAV slot.

Just to be sure, you can't use a d3d11 resource view, you need an unordered access view.

Crealysm game & engine development: http://www.crealysm.com

Looking for a passionate, disciplined and structured producer? PM me

Thanks for the many answers.

I am trying Syntac's suggestion.

After the dispatch of the compute shader i "unbind" the buffer from the uav by passing a nullptr array to the view:

ID3D11UnorderedAccessView* ppUAViewnullptr[2] = { nullptr, nullptr };
dc->CSSetUnorderedAccessViews(0, 2, ppUAViewnullptr, nullptr);

Then this code is used:

D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc2;
ZeroMemory(&srvDesc2, sizeof(srvDesc2));
srvDesc2.ViewDimension = D3D11_SRV_DIMENSION_BUFFEREX;
srvDesc2.BufferEx.FirstElement = 0;
srvDesc2.Format = DXGI_FORMAT_R32_TYPELESS;
srvDesc2.BufferEx.Flags = D3D11_BUFFEREX_SRV_FLAG_RAW;
srvDesc2.BufferEx.NumElements = NUM_ELEMENTS * 36 / 4; // 36 bytes Stride for raw buffer
ID3D11ShaderResourceView *ppSRVOut;
ZeroMemory(&ppSRVOut, sizeof(ppSRVOut));

m_device->CreateShaderResourceView(g_pBufResult, &srvDesc2, &ppSRVOut);

dc->VSSetShaderResources(0, 1, &SRView);

to bind the buffer to the shader resource view.

In the vertex shader i declare:

RWByteAddressBuffer patchInput : register(u1);

using u0 or t0 creates an exception:

D3D11 ERROR: ID3D11DeviceContext::DrawIndexed: The Vertex Shader unit expects an Unordered Access View at Slot 0, but the first 1 slots are currently used for Render Target Views. [ EXECUTION ERROR #2097374: DEVICE_DRAW_UNORDEREDACCESSVIEW_RENDERTARGETVIEW_OVERLAP]

The compiler output of HLSL Shader Compiler in the Visual Studio Graphics Analyzer reads:

Resource Bindings:
//
// Name Type Format Dim HLSL Bind Count
// ------------------------------ ---------- ------- ----------- -------------- ------
// patchInput UAV byte r/w u1 1
// cbPerFrame cbuffer NA NA cb0 1
However in the debugger of the vertex shader, i get

patchInput = Not set

when hovering over the raw buffer name.

And trying to read data from that raw buffer like so:

float p1 = asfloat(patchInput.Load(vertexId));

yields always:

p1 = 0.000000000

So it look like the buffer is not ending up in the correct slot due to the overlap issue for slot0.

Also the srv view desc might be incorrect.

You're using an RW buffer, which is a UAV. If you're following the SRV suggestion, then just remove the "RW" from the buffer declaration in the shader, and declare it in the 't' namespace.

You're using an RW buffer, which is a UAV. If you're following the SRV suggestion, then just remove the "RW" from the buffer declaration in the shader, and declare it in the 't' namespace.

Jesse, thanks to your suggestion, i can now bind to t0 without exception using:

ByteAddressBuffer patchInput : register(t0);

Turns out that i used a wrong shader resource view reference, where it should have been

dc->VSSetShaderResources(0, 1, &ppSRVOut);

Thanks a lot for the help. I am able to use the buffer now in the vs.

This topic is closed to new replies.

Advertisement