Questions about PushConstants

Hello,
i want to know a litte bit more about push-constants. The spec says

Push constants represent a high speed path to modify constant data in pipelines that is expected to outperform memory-backed resource updates

But what does this exactly mean? What are the best use-cases for push-constants? When should i use them and when not?
When are push-constants more efficiently than descriptor-sets?

Thanks in advance!
SH

Push constants are static and updated inside of a command buffer. That’s the biggest logical difference between them and memory-backed resources like uniform buffers that can be updated by the application at any point (and have to be synced properly). So for dynamic data go with UBOs and SSBOs and if you have data you can pass static inside of a command buffer (and that is known at that time) you can use push constants. Note that the min. supported size of a push constant block is 128 bytes.

Also note that you have to specify push constant ranges at pipeline creation time (via the pipeline’s layout), so the ranges are fixed throughout a pipeline’s lifetime.

What is a “SSBO”?
I am using push-constants for my per object-data (currently only a world-matrix). Does that mean i have to put another matrice into it to have at at least the 128 bytes?
Do you think it is better to use dynamic descriptor-sets for my per-object data? How fast are push-constants in compare to a dynamic ubo?

A Shader Storage Buffer Object. If you want to pass larg(er) amounts of data to a shader, you should use a SSBO instead of a UBO. In Vulkan this would be a (preferably device local) buffer with the VK_BUFFER_USAGE_STORAGE_BUFFER_BIT usage bit specified at creation time.

No. The spec says that an implementation must support at least 128 bytes for push constant blocks. Always using less is fine, but if you’re using larger push constant blocks (>128 bytes) you must check if the implementation supports it.

They should be faster on most implementations due to their nature, though I have no data on that. Hard to tell what’s better for your use-case without detailed knowledge of what you want to do. But if you have static data that is known at command buffer creation time then use push constants. Often you’ll be using both, uniform buffer objects via descriptor sets and push constants at the pipeline level, so you have to plan in advance (like with most things in Vulkan) what to use.

I will leave it at this then. Thanks for your knowledge :slight_smile:
P.S. i am rendering with a static/dynamic object-system.
Static-Objects gets rendered in a separate primary-cmd which is prebuilded.
Dynamic objects will be rendered through secondary-cmds build from multiple-threads before each VkQueueSubmit.

My first intention was to use a secondary-cmd aswell for static-objects and just “push it” to the dynamic-cmds. This worked… almost.
It produced very rare “artifacts”. Kind of a mesh deformation and i could not track it down what causes this, so i changed it to use a primary-cmd aswell.
Do you have any idea? Is it possible to use a secondary-cmd aswell for my static-objects?

[QUOTE=Twanks123;40665]My first intention was to use a secondary-cmd aswell for static-objects and just “push it” to the dynamic-cmds. This worked… almost.
It produced very rare “artifacts”. Kind of a mesh deformation and i could not track it down what causes this, so i changed it to use a primary-cmd aswell.
Do you have any idea? Is it possible to use a secondary-cmd aswell for my static-objects?[/QUOTE]

This should work fine. It doesn’t matter if you rebuild your secondary CBs every draw or build your static CB as secondary once and reuse it. If you see corruption this may be a synchronization issue that may be caused by e.g. a missing memory barrier.

Did the validation layers report anything?

[QUOTE=Sascha Willems;40666]This should work fine. It doesn’t matter if you rebuild your secondary CBs every draw or build your static CB as secondary once and reuse it. If you see corruption this may be a synchronization issue that may be caused by e.g. a missing memory barrier.

Did the validation layers report anything?[/QUOTE]

No they did not :confused:

I will retry it using a secondary-cmd for my statics-objects this evening and post my results here.

If validation doesn’t complain it’s proably a synchronization issue, which can’t be caught by the layers. So try to add a memory barrier where required and see if it helps.

So i did it again with using a secondary-cmd for the static-objects, the “very rare mesh-deformations” are gone, but i have still another problem.
When i have a large amount of objects in my scene (~1000) and the secondary-cmds from the static-renderer gets recorded and executed with the other secondary cmd rendering the normal scene, “VkQueuePresentKHR” return always
VK_ERROR_DEVICE_LOST.

This is what i know so far:

  • this happens only if BOTH the secondary-cmd with the static-objects and the secondary-cmd with the dynamic objects gets executed.
    So if change this code:
      // Get pre-recorded secondary-cmd. Rerecord if num static-objects has changed to last frame.
        VkCommandBuffer staticCmd = staticRenderer->getSecCmd(frameDataIndex);
        if(staticCmd != nullptr)
            secondaryCmds.push_back(staticCmd);

        // using only the first worker cmd for now
        secondaryCmds.push_back(frameResources[frameDataIndex].workerCmds[0].get());

        vkCmdExecuteCommands(cmd, static_cast<uint32_t>(secondaryCmds.size()), secondaryCmds.data());

to this:

      // Get pre-recorded secondary-cmd. Rerecord if num static-objects has changed to last frame.
        VkCommandBuffer staticCmd = staticRenderer->getSecCmd(frameDataIndex);
        if(staticCmd != nullptr)
            secondaryCmds.push_back(staticCmd);
        else
            secondaryCmds.push_back(frameResources[frameDataIndex].workerCmds[0].get());

        vkCmdExecuteCommands(cmd, static_cast<uint32_t>(secondaryCmds.size()), secondaryCmds.data());

it works.

I cant figure out why it crashes only with a large amount of objects when both secondary-cmds gets executed. :confused: please help me!

Although hard to tell without seeing the code that builds the command buffers in detail, even a large amount of secondary command buffers should not crash, no matter what type of objects and how you upload data.

A VK_ERROR_DEVICE_LOST from queue presentation is usually a driver crash. So unless you’re running into a driver bug it’s possible that you pass in some invalid values at some point that aren’t caught by the validation layers yet. What validation layers are you using? The ones from the SDK, or are you building from source? If SDK, try building from source and see if these report any errors.

If even the latest validation does not report anything, you may have stumbled upon a driver bug that may be worth reporting to your IHV. Even though most Vulkan implementations are mostly stable right now it’s still a pretty new API and driver bugs are to be expected.

Btw. what GPU are you running on? Did you test with other vendors?

I am using AMD Radeon HD 7870 OC.
I tested it on my laptop using a nvidia card. And it works perfectly fine there <.< has to be a driver bug then
Thanks for your help.

I tested it on my laptop using a nvidia card. And it works perfectly fine there <.< has to be a driver bug then

That is a terrible assumption. Vulkan is not OpenGL; just because it works on one implementation doesn’t mean you code was fine (indeed, even OpenGL isn’t like that). While driver bugs certainly do exist, you shouldn’t assume that your code working on one platform means that it is fine.

I didnt know that! Thanks, i will keep this in mind and hopefully understand soon enough whats going on in my code :slight_smile:

Just wanted to weigh in on Alfonse’s good point, as that mirrors my experience. To ensure that everything works fine I usually test on three different vendors on three different platforms, and even with similar GPUs (Maxwell on Desktop and Android) there are still differences (mostly down to the driver). So if validation is 100% clean, you still should test on different vendors. During Vulkan development I had stuff that worked fine on AMD and not on NVIDIA and vice versa, but in the end they both may have certain constellations that work although they’re not supposed to be correct :wink: