I take the code that is causing this issue is very similar to the old cubemapping sample from the 2.0 samples?
I'm almost sure there should be one RTT entry for each cube face. I need to debug it since these barriers need to be thought carefully.
Small remarks (for better understanding):
Traditional RTTs are in order. That means the following sequence:
- Write red to RTT A
- Sample from RTT A, write the value to RTT B
- Write yellow to RTT A
At the end of rendering, B = red, A = yellow.
However when using UAVs (using UAV semantics, UAVs can also be used as RTT and then they become in order, assuming the barriers when transitioning from UAV to RTT are correct):
- Write red to UAV A
- Sample from UAV A, write the value to RTT B
- Write yellow to UAV A
The the end of rendering, B could contain red, could contain yellow, or could contain some pixels red and some pixels yellow. 'A' may end up containing red instead of yellow although that's unlikely. Good old race conditions.
That's why UAV barriers are needed for: We need to place a barrier between step 1 and 2 to ensure writes to A finish before we start reading from it, and another barrier between 2 and 3 to guarantee we don't start writing to A before we've done reading from it.
Additionally, in D3D12 and Vulkan we need to tell the API if a resource is going to be transitioned (from being a Texture to being an RTT, from being an RTT to being a Texture, from being a RTT to being... whatever, e.g. a vertex buffer, since D3D12 & Vulkan are very flexible and allow to reinterpret_cast memory); the logic is very similar.
That's all in theory, very easy to understand. In practice it is incredibly difficult to get right (and you learn to appreciate what D3D11 and OpenGL drivers where doing behind your back) because it's all about race conditions and parallel programming. And parallel programming is hard.
The easy way is to issue a barrier every time you detect you're about to transition (e.g. move the logic to setTexture, setRenderTarget, setUav, etc). But if you do that, you're adding all the overhead, throwing away every possible advantage from using D3D12 & Vulkan, you're better off using D3D11 drivers. So we bake the barriers, evaluating the hazards during workspace initialization (also GPUs like that, when possible, we put all barriers together instead of putting unrelated commands in the middle).