D3D12 - Root Signature difference between PSO and CmdList ?

Started by
7 comments, last by zalbard 8 years ago

When creating a PSO we must specify a Root Signature


D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.pRootSignature = rootSignature.Get();
// fill out other fields ...

.

And again we must specify a Root Signature before recording commands into a CommandList


commandList->Reset(commandAllocator.Get(), pipelineState.Get());
commandList->SetGraphicsRootSignature(rootSignature.Get());

.

The weird part is that the same PSO is used in calling Reset on the CommandList, meaning the CommandList should already have access to the PSO's Root Signature. If one does not set the CommandList's Root Signature explicitly, then a D3D12 Error is generated due to undefined behavior. I suspect this design was put in place so that the CommandList could override it's parent PSO's Root Signature with a different one, but I have not yet tested this to see if this is the case. Anyone have information on this?

Seems weird that we need to set a Root Signature at all in the PSO if we have to then set the same Root Signature again in the CommandList using said PSO.

Advertisement

When creating a PSO, you have to tell it which root signature it will be used with. The PSO doesn't have to remember this information -- it uses this information to compile/optimize the new PSO, and then is able to forget that pointer, with the assumption that you will only use this PSO with a compatible root signature later on.

When you bind a PSO to a command list, it doesn't also bind a root signature, because the PSO doesn't necessarily have that information (it's allowed to forget).

However, you have to remember. When you bind a PSO, you have to make sure that you also bind a compatible root signature.

As an example, you should have multiple PSO's that share a root-sig:

PSO1 - compatible with Root A

PSO2 - compatible with Root A
PSO3 - compatible with Root B
You could then have a draw command stream that looks like:
Bind(PSO1)
Bind(RootA)
Draw()
Bind(PSO2) -- n.b. no rebinding of the root sig here :)
Draw()
Bind(RootB)
Bind(PSO3)
Draw()

The root signature needs to be set before you draw or dispatch, but you can reset a command list with a null pipeline state if, for some reason, you don't know which pipeline state you're about to use. The command list can change both the rootsig and pipeline states multiple times if it wants.

Thanks for the clarification. Indeed, this seems quite flexible.


The PSO doesn't have to remember this information -- it uses this information to compile/optimize the new PSO, and then is able to forget that pointer

I'm not sure what you mean by this. Of course we can always reuse the the first PSO's descriptor by changing its root signature and using it to create another PSO. Looking at the ID3D12PipelineState interface, there does not seem to be a way to change a PSO's root signature post creation. Is there anyway a PSO can explicitly "forget" its root signature, or is this simply due to the internal representation of a PSO?

No, a PSO can't change which root sig that it's compatible with after it's been created.

What I meant is that the PSO doesn't necessarily retain that pointer. When creating a PSO, it will use some information that's contained within the root signature, but it doesn't retain a pointer to the root signature itself.

e.g.


struct RootSig { int c; }
struct PsoDesc { int a, b; RootSig* root; };
struct Pso { int a, b, c; }
Pso CreatePso( PsoDesc& desc )
{
  Pso newPso = { desc.a, desc.b, desc.root->c };
  return newPso;
}
It's similar to dx11 input layouts which need vs byte code -- the input layout doesn't actually hold onto the vs, but it needs to know how to transform vertex data for the vs.

The input layout and vs are in the same place now, but other things like render target information are in the rootsig. The PS might need to transform data based on render target format, eg rgba8/32? Dx11 likely did this lazily when you drew something for the first time, dx12 does it explicitly.

Perfect. Thanks again.

Your question is answered in detail in this video: Resource Binding in DirectX 12 (pt.2)

In short, when you create a PSO, the RS is only used for validation and PSO compilation (it tells the driver how resources are provided to the PSO).

This topic is closed to new replies.

Advertisement