Can I update individual descriptors array elements that are not being used? - vulkan

If I want to have one big array of descriptors for sampled images, and index into them. The descriptor layout looks like:
binding = 0;
descriptorCount = 8192;
descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
This means much less binding of descriptors, everything is indexed with information passed to a shader or read from a storage buffer. The problem is in updating the entries this image table/descriptors. Let's just say I issue a draw call that reads from this descriptor array from range [0 - 16]. The draw call is still being processed, and I want to update descriptor array element [28]. No previous commands are using element [28]. Is my understanding correct that this is illegal/undefined because you are NOT ALLOWED to update a descriptor set (the entire set) if it's still being used? Does this mean every time I want to update an element in the descriptor array I need to allocate a new descriptor? If I have to wait for the command buffer to be finished with using that descriptor set to update the descriptor then it's likely I'll have to wait on a fence, because descriptor updates are immediate.
This system of having one large descriptor array when draw calls simply index into the large array to get the right texture seems ideal as you don't bind descriptors as much, but I want to know whether updating it like this is illegal/undefined.

As with many things, this is covered by the descriptor indexing feature. If this feature is not available, then you're out of luck.
With descriptor indexing, the VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT flag does exactly what it says. It allows you to update unused descriptors while a command buffer the descriptor is bound to is pending.
What "unused" means depends on a separate flag. If VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT is set, then "unused" refers to any descriptor which is not "dynamically used". That is, the rendering command will not access it based on any of the data used by that rendering command. If this bit is set, then "unused" refers to any descriptor which is "statically used". And "statically used" is rather more broad: if your SPIR-V has any instruction that accesses the OpVariable containing the descriptor at all, then it is considered "static use".
And yes, since an arrayed descriptor is a single OpVariable, unless you use the partially bound bit, you cannot use the array at all if you want to modify even part of it. But then again, the partially bound bit also is what makes it possible to have descriptors in the array that do not have valid values. So you probably already have that anyway if you're trying to do this sort of thing at all.
These flags are part of the descriptor set layout's creation info (using an extension structure).

Related

Concurrent use of VkSamplers?

So a VkSampler is created with a VkSamplerCreateInfo that just has a bunch of configuration settings, that as far as I can see would just define a pure function of some input image.
They are described as:
VkSampler objects represent the state of an image sampler which is used by the implementation to
read image data and apply filtering and other transformations for the shader.
One use (possibly only use) of VkSampler is to write them to descriptors (such as VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER) for use in descriptor sets that are bound to pipelines/shaders.
My question is: can you write the same VkSampler to multiple different descriptors? from the same or multiple different descriptor pools? even if one of the current descriptors is in use in some currently executing render pass?
Can you use the same VkSampler concurrently from multiple different render passes / subpasses / pipelines?
Put another way, are VkSamplers stateless? or do they represent some stateful memory on the device and so you shouldn't use the same one concurrently?
VkSampler objects definitely have data associated with them, so it would be wrong to call them "stateless". What they are is immutable. Like VkRenderPass, VkPipeline, and similar objects, once they are created, their contents cannot be changed.
Synchronization between accesses is (generally) needed only for cases when one of the accesses is a modification operation. Since VkSamplers are immutable, there are no modification operations. So synchronization is not needed for cases where you're accessing a VkSampler from different threads, commands, or whathaveyou.
The only exception is the obvious one: vkDestroySampler, which requires that submitted commands that use the sampler have completed before calling the function.

What is the purpose of multiple setLayoutCounts of vulkan VkPipelineLayoutCreateInfo?

I wondering why it's possible to specify multiple descriptors set layouts in VkPipelineLayoutCreateInfo because a single one already includes all of the bindings.
A descriptor set layout describes the layout for a single descriptor set. But a pipeline can have multiple descriptor sets. This is what the layout(set = #) part of the qualifier in GLSL means: it specifies which set that this particular resource gets its descriptor from. The set is an index into the VkPipelineLayoutCreateInfo::pSetLayouts array. The descriptor is the index into that set's list of descriptors. The two of them combined identify the specific descriptor within the pipeline layout.
So your assumption that a single descriptor set "already includes all of the bindings" is incorrect.
As stated in the specification, the point of having multiple descriptor sets is to allow users to change one set of descriptors without changing another, and to allow pipelines to be partially layout compatible with one another.
For example, you might have per-scene information like the location of lights and the camera/projection matrices. But you might also have per-object information like the matrices. If all of that information is in the same descriptor set, then if you want different objects to have different per-object descriptor sets, they would also have to have different per-scene info in those same sets.
You can instead split them up into separate descriptor sets, with the less frequently changing information in set 0 (per-scene) and the more frequently changing data in set 1 (per-object). That way, you don't have to change every descriptor just to change your per-object data.
Also, you can change pipelines without having to restore the per-scene sets. For example, let's say you're switching from your non-skinned pipeline to your skinned pipeline. Well, obviously they have fundamentally different kinds of per-object data. But their per-scene data is the same. If you have these data in different descriptor sets, then you don't need another descriptor set for the per-scene data. You don't even need to bind a new set 0 when you change the program binding. Because set 0 is compatible with both programs, set 0's binding is valid in both.
The specification even has a notation specifically about this scenario:
Place the least frequently changing descriptor sets near the start of the pipeline layout, and place the descriptor sets representing the most frequently changing resources near the end. When pipelines are switched, only the descriptor set bindings that have been invalidated will need to be updated and the remainder of the descriptor set bindings will remain in place.

Vulkan: Descriptor set compatibility

In the chapter 'Descriptor Set Binding' in the Vulkan spec the following statement is made:
A compatible descriptor set must be bound for all set numbers that any shaders in a pipeline access, at the time that a draw or dispatch command is recorded to execute using that pipeline.
Where is 'compatible descriptor' defined? I haven't found the definition in the spec. I wonder whether a descriptor set must match the set layout in the shader exactly or whether the descriptor set is allowed to have a resource bound to a binding point which does not exist in the shader.
The reason for this question is the following: assume I have two shaders which are almost identical (consider them 'variations' of a template shader), they have the same layouts, except one of them doesn't use one particular binding point (i.e. this could be a 'fast path', derived from the generic path by an #ifdef, resulting into one binding point being optimized away). Assume I have two draw calls, the first using one shader and the second using the other, and assume the resources required are identical, except that there is an additional resource for that one shader which has that special binding point. Also assume that I use the same descriptor set layout which maps exactly to the one shader which has the additional binding point. In this situation I would prefer to use the same descriptor set for both shaders to reduce the number of updates/binds of descriptor sets. The set would match the one shader exactly and it would contain a resource binding which does not exist in the other shader.
Shaders do not have a layout; pipelines have a layout. When you build a pipeline, the VkPipelineLayout has to agree with what is defined in the shader... to some extent.
That is, the resources a shader declares have to match the resources specified by the VkPipelineLayout. But the pipeline layout can also define other resources that aren't used by the shaders in that pipeline.
The descriptor sets bound when rendering with a pipeline have to exactly match the descriptor set layouts defined for that pipeline (you can bind descriptors for sets higher than the highest set used by the pipeline, but everything up to the highest set used by the pipeline must match). So if you want to do what you're trying to do, just give both pipelines the same layout.

Is this understanding of VkDescriptorPoolCreateInfo.pPoolSizes correct?

In Vulkan, I understand that a descriptor pool is used to allocate descriptor sets of some layout for use in a shader, but in the VkDescriptorPoolCreateInfo passed to vkCreateDescriptorPool, there is a field pPoolSizes that takes a bunch of objects containing a descriptor type and a number.
The documentation seems somewhat vague, but is this saying that a given descriptor pool can only have a certain, predetermined amount of each type of descriptor allocated from it in descriptor sets? If so, how do I determine how many I will need beforehand? What happens if it runs out?
Your understanding of descriptor pools is correct.
If so, how do I determine how many I will need beforehand?
That's up to you and your application's needs.
If your application needs to be completely flexible and freeform, then you will need to create descriptor pools dynamically as needed. If your application has greater foreknowledge of what the scene will look like, then your application will need fewer of such gymnastics.
Many serious Vulkan applications try to avoid having the number of descriptor sets be based on the number of objects in the scene. Push constants and/or dynamic UBO/SSBO descriptors allow different per-object state to be used without changing the descriptor itself. Textures for lots of objects can be bundled together into array textures, or depending on the hardware, arrays of textures.
In a perfect world, all meshes of a type (say, skinned meshes) could be rendered with the exact same descriptor set, using some per-object state to fetch the right matrix/texture data for that object.
But that's how they render. Such applications have firm control over the kinds of objects they render, what per-object data looks like, and so forth. Other applications may have different needs.
Vulkan is a tool; how you use it is entirely up to you.
What happens if it runs out?
Then you cannot allocate more descriptors from that pool. If you need to allocate another descriptor set, you will need to create another pool.
My approach was to have a class that initially allocates N of the descriptor, and if it runs out, it'll create another pool with N*2 entries. It'll keep doubling in size. It uses a simple linked lists and when it comes to allocating, it just tries the first one, and then moves onto the next if it's full.
That's all pretty inefficient, so I also had my code fire an assert if it ever had to create a second pool, that way I can make sure I choose a value of N that's big enough so that the retail version should never have to do it (but if it does somehow manage to due to some unforeseen set of circumstances, it'll still render correctly).
At the time, I remember cursing the spec and wishing descriptor pools would auto grow like command pools do. Still I imagine there's a good reason that they are like they are.

glVertexAttributePointer scope?

I'm currently programming an OpenGL ES 2.0 application on both iOS and Android platforms.
In this application I render multiple meshes that all use VBOs. In the process of optimizing the rendering, I realized that the meshes I render share two vertex formats. So I wanted to do the following:
First, setup all vertex attribute pointer offsets, and then simply bind each VBO that uses this vertex format and render it without calling the glVertexAttribPointer function again.
But it gives me strange results.
My question is: Do we have to do the calls glVertexAttribPointer each time we bind a new VBO?
First of all, like every OpenGL state, the state set with glVertexAttribPointer keeps unchanged until someone else calls glVertexAttribPointer again (for the same attribute index). But the important thing here is, that the internal state changed with glVertexAttribPointer doesn't just store the buffer offset to be used for rendering, offsetting into the VBO bound when calling glDraw.... It also stores the actual buffer object bound when calling glVertexAttribPointer.
So yes, whenever you want your vertex data sourced from another VBO, you need to bind this VBO and do the appropriate glVertexAttribPointer calls while this VBO is bound. While this may seem cumbersome in your case, this is in fact a good thing. This way you don't need to worry about the currently bound buffer when rendering something, but only about the things set up with glVertexAttribPointer. And even more important it let's bind a different VBO before rendering, thus you can source different vertex attributes from different VBOs in a single render call (how else would you do that?).
EDIT: You can however use Vertex Array Objects to ease the process of setting up your vertex data. They encapsulate all the state neccessary for rendering from a bunch of arrays (and thus all the things changed by glVertexAttribPointer, gl(En/Dis)ableVertexAttribArray and the buffer bound to GL_ELEMENT_ARRAY_BUFFER, but like said, not the buffer bound to GL_ARRAY_BUFFER). You still have to properly bind the buffer before calling glVertexAttribPointer of course. But using a VAO you only need this code in some set up routine and all you need to do for rendering is calling glBindVertexArray. Though I don't know if your particular ES device supports them.
Some cool resource I found on drawing with VAO / VBO
http://www.arcsynthesis.org/gltut/Positioning/Tutorial%2005.html#d0e4720
It shows how you can drive several objects, with several VAOs and a single VBO for example (each VAO holding pointers with different offsets to the same VBO)
Definitively worth a look, not mentioning the part where you learn that
glBindBuffer(GL_ARRAY_BUFFER...doesn't bind any data, it's just a
global pointer for the following glVertexAttribPointer calls which do the actual data binding
BUT
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER...DOES bind/save the element array into the current VAO