Bound descriptor sets across command buffer boundaries?

I am wondering if it is possible to bind a descriptor in command buffer 1 (cb1) via vkCmdBindDescriptorSets and use that binding recorded in cb1 in a draw call (e.g. vkCmdDrawIndexed) recorded in command buffer 2 (cb2), given that cb1 is submitted to the same queue before cb2. (But no descriptor bindings are performed in cb2, only in cb1.)

I couldn’t find anything in the specification that would explicitly disallow this, except maybe the following:

Once bound, a descriptor set affects rendering of subsequent commands that interact with the given pipeline type in the command buffer until either a different set is bound to the same set number, or the set is disturbed as described in Pipeline Layout Compatibility.

where the specification says “in the command buffer”, which could indicate that the descriptor binding must happen inside the same command buffer as the draw call. But I’d say the wording is not unambiguously disallowing it.

In practice, the “cb1 then cb2” approach works on Nvidia, but does not work on AMD. A validation error is raised claiming that no descriptor set was bound during the draw call in cb2. I guess that this is not a false positive and the approach described above is, indeed, disallowed and only coincidentally works on Nvidia. Could that be the case? What’s the reasoning behind disallowing descriptor set bindings in a
different command buffer than issuing draw calls which use the descriptors?

With the exception of secondary CBs that explicitly inherit certain state from a primary CB, all state is local to a command buffer. The bound pipelines, vertex buffers, and yes, descriptors too, are all local to a CB:

Each command buffer manages state independently of other command buffers. There is no inheritance of state across primary and secondary command buffers, or between secondary command buffers.

Similarly, state is not preserved between CBs, except that the current render pass from a primary CB is preserved in a secondary CB that is executed within the render pass.

1 Like

Thanks for pointing to the command buffer state! I wasn’t aware that descriptor bindings are a state of a command buffer. I assumed that descriptor sets are bound at queue-level per bind point due to the following wording in the specification:

vkCmdBindDescriptorSets causes the sets numbered [firstSetfirstSet +descriptorSetCount -1] to use the bindings stored in pDescriptorSets [0…descriptorSetCount-1] for subsequent bound pipeline commands set by pipelineBindPoint . Any bindings that were previously applied via these sets are no longer valid.

It does not mention queue-level, though. So my assumption about queue-level was wrong as it appears. Instead, descriptor sets are bound at command buffer-level per bind point.

All state is command buffer state.

1 Like