8
$\begingroup$

I'm sort of struggling to understand the conceptual difference between uniform buffers and push constants. From what I can gather by reading the spec, the main differences are:

  1. Uniform buffers can be much larger than push constants.
  2. UBOs use std140, PCs use std430.
  3. UBOs can be updated at any time with vkCmdUpdateBuffer (or host mapping) and persist their values otherwise, PCs have to be re-pushed for each render pass. (Which surprised me - based on the name. I thought I would literally be updating constants in the pipeline in-place, and have those changes persist)

In my scenario, I have about ~200 bytes worth of data that I expect to be mostly constant. That is, I will change them very infrequently. Would it be better to (assuming the size permits) use push constants even though I have to re-send them in every command buffer? Or would it be better to use a 200-byte UBO and only update it infrequently with vkCmdUpdatebuffer?

Also. what if I have e.g. a float random_seed that I will update every time the shader is run? Assuming I already have a UBO, would it be better to lump that in with the UBO, even though the rest of the UBO is constant, or would I gain a benefit from using push constants for specifically this variable, so I can avoid having to vkCmdUpdateBuffer before every render pass?

$\endgroup$
  • $\begingroup$ Welcome to the Computer Graphics Stack Exchange site! I am not familiar with Vulkan but it seems using an UBO would be more efficient in your case (you can try to compare the performances of both approaches in a sample program). Which graphic APIs are you familiar with? Also you might be interested by this GDC 2012 presentation: Don't Throw it all Away: Efficient Buffer Management $\endgroup$ – wip Aug 28 '17 at 13:29
  • $\begingroup$ From Vulkan documentation: while an UBO allocates a block of video memory on the GPU (that you can update at a later timing), the Push Constant does not use video memory (which is why it must be provided during every draw/compute call, or else the shader would not know which value to use). I guess it is stored in an other short-term, fast storage area on the GPU, though the details might depend on your GPU vendor. $\endgroup$ – wip Aug 28 '17 at 13:44
8
$\begingroup$

UBOs can be updated at any time with vkCmdUpdateBuffer

From the specification: "vkCmdUpdateBuffer is only allowed outside of a render pass." So "at any time" is not the case.

Even if it were allowed inside of a render pass, it's still a transfer operation. Which means you need to synchronize the memory transfer with the commands that use it. Which slows down performance.

For the general Push Constant vs. Uniform thing, use your judgment. By "judgment", I mean just look at how they work. Push Constants allow you to change their data at any time without doing heavy-weight processes like memory operations, synchronization, or altering the descriptor state. Clearly, they are for frequently changing data. How frequently is "frequently"? Well, that's a judgment call.

Failing that, profile the performance difference.

$\endgroup$
2
$\begingroup$

I have about ~200 bytes worth of data that I expect to be mostly constant. That is, I will change them very infrequently.

If the data changes infrequently, you can use Specialization Constants. They are set when the pipeline is created, and a new pipeline must be created if you need to change the values. For an infrequent event, like a window resize, this may be an acceptable cost.

what if I have e.g. a float random_seed that I will update every time the shader is run?

That's a perfect use case for Push Constants. You can keep all the other data in the UBO (or in the Specialization Constants) and change this value with VkCmdPushConstants.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.