Replacing glUniform for Vulkan transition

Greetings,

I continue my work on porting an OpenGLES based engine to Vulkan. Now it has come to setting uniforms within a shader. Currently, when the engine user wants to change a uniform he writes the new value into a central buffer. Shortly before the drawcall the engine then takes the buffer and issues a glUniform* call for every entry.

I want to use GL_KHR_vulkan_glsl to compile the existing GLSL shaders into Spirv so as little as possible changes for the engine user.

Problem is that GL_KHR_vulkan_glsl doesn’t allow uniforms outside a uniform block which I currently use heavily. Thus, my intention is to replace the glUniform mechanism with something GL_KHR_vulkan_glsl compatible. Currently two methods come to my mind:

  1. Just wrap all uniforms in something like a default block which is then updated from an ubo once a drawcall.

  2. Replace all glUniform calls by push constants.

The generation of the GLSL code is partially automated, at least when it comes to the generation of the declarations of the uniforms. The GLSL code that accesses the uniforms on the other hand is written by the engine user. That means using a method that merely changes the declaration is acceptable if the way they are accessed within the shader does not change.

I expect several hundred drawcalls a frame with up to 12 uniforms of which roughly half may change from drawcall to drawcall.

Can you tell me if one of the above options is optimal from a performance viewpoint as far as you can tell or do you have a different proposal?

Regards

No, the problem is that Vulkan doesn’t allow that.

That’s not going to work; at least, not as you described it. Vulkan isn’t OpenGL; you can’t modify memory, issue a rendering command, then modify the same memory and expect the previous rendering command to not notice. OpenGL will do the synchronization needed to make that work. Vulkan doesn’t; it forces you to be aware that said synchronization is in fact very expensive.

You would need to use a new area of buffer storage, likely specified by a dynamic UBO or a similar mechanism.

Since each object is going to have to have its own range of per-object memory for its draw call(s), you may as well have your “buffering” mechanism actually write that data when you “buffer” the values. So each object has an associated region of per-object storage within the buffer. Then the draw call just sets the dynamic UBO to the proper offset for that draw.

Of course, because you’re constantly changing which regions of memory you’re writing to, there is no “memory” of unchanged values. So if you want to have unchanged values, you’ll have to do that manually by storing a CPU-side copy, modifying any changes, and memcpying it into the per-object structure.

The push constant equivalent may not need such a thing. But push constant storage tends to be tiny, at most 256 bytes (with many implementations only offering 128).

Thanks for your answer. So how about this:

  • Two UBOs per drawcall. One staging buffer, one device local memory. The UBOs are managed by the engine object representing the shader.
  • When I start setting the uniform data, the staging buffer is mapped and the data is directly written to the mapped staging buffer memory. It is unmapped before rendering starts. Unmapping also triggers synchronization with the device local memory.
    Or could I let the staging buffer be permanently mapped and trigger synchronization when command buffer generation starts?
  • After that, render command buffer is built using the device side ubo.

I have several scenarios where uniforms take less than 256 bytes. So for that case, I could just replace the uniform declarations by push constant declarations, right?

I could still access the uniforms in the same way inside the shader so I won’t have to change this, right?