Push constants

The spec (version 1.0.9) says the following in “13.2.6. Push Constant Updates”:

The contents of the push constants are undefined at the start of a command buffer.

Does that mean I have to do vkCmdPushConstants() in the very same command buffer where I do vkCmdDraw()?

Also, the spec is not clear on what vkCmdPushConstants() does with its pValues argument. Does it take a copy of user-provided data to be used at submission time or does it read from the user-provided address at submission time?

Does that mean I have to do vkCmdPushConstants() in the very same command buffer where I do vkCmdDraw()?

If the pipeline you’re using uses push constants… yes. What else could it mean?

Also, the spec is not clear on what vkCmdPushConstants() does with its pValues argument.

Well, there is no general statement on that in the specification. However, it is highly unlikely that the intent of the specification is to store a user-allocated pointer inside the command buffer, as that can create a race condition on the state of that memory. Plus, it’s unlikely that user-allocated memory could be directly access by the GPU’s command processor, thus making it even harder to make work.

So I would say that you should assume it works in the way that is most reasonable; that the function copies the data out of the pointer and into the command buffer.

That would imply I can reuse command buffers that access push constants only as long as those push constants don’t change. Whenever I need to update my push constants, I would have to build a new command buffer. Is that correct?

First thing to note is that Vulkan never holds on to your pointers the only exception being the void* userdata in the allocation struct.

This means that when you call vkCmdPushConstants the contents of the constants are copied over into the command buffer. and even after you change the struct later the values will remain as they were when you called vkCmdPushConstants.

Yes push constants will remain constant for as long as the buffer is valid.

1 Like

First thing to note is that Vulkan never holds on to your pointers the only exception being the void* userdata in the allocation struct.

I missed that statement in the spec. But to be fair, it is in an odd place: a section titled “Object Lifetime”. It’s in 2.3.1.

That would imply I can reuse command buffers that access push constants only as long as those push constants don’t change. Whenever I need to update my push constants, I would have to build a new command buffer. Is that correct?

The whole point of push constants is that they are part of the command buffer. If you wanted modifications of memory to alter the effects of a command buffer, you would have just used a UBO.

Static command buffers are not the be-all-end-all of performance.

Perhaps the spec should explicitly state that in “vkCmdPushConstants” section, even though it’s documented elsewhere. In fact, the section on “vkCmdUpdateBuffer” does just that, except it uses confusing language:

The source data is copied from the user pointer to the command buffer when the command is called.

The “command is called” part can well be interpreted as “command is submitted”. Did they mean “when the command is recorded”?

That would be a good reason not to repeat the information. Because, as you point out, it is ambiguous. Whereas 2.3.1 is rather unambiguous about it:

That being said, the Vulkan specification consistently uses the word “command” to mean “calling a Vulkan API function”. So really, the section you read is unambiguous too.

Fair enough, the spec as a whole is unambiguous and gives you enough details to figure out the behaviour of vkCmdPushConstants() and vkCmdUpdateBuffer(). Unfortunately, you have to read and remember the whole spec in order to do so. Individual sections don’t give you enough information. In my book, that just doesn’t count as good documentation. When it comes to reference documentation, repeating yourself is actually a good thing.