Search code examples
offsetvulkanvertex-buffer

What are the advantages of using offsets in vkCmdBindVertexBuffers vkCmdDraw?


In the vulkan, I have a vertex buffer which stores 6 vertices. The first 3 belong to one triangle and the other 3 to another. Each vertex has two floats specifying the x and y positions and another 3 for the rgb.

If I'd like to draw only one triangle, it seems I can achieve the same result by either specifying an offset of 3*5*sizeof(float) to poffsets of vkCmdBindVertexBuffers or alternatively specify firstVertex as 3 to vkCmdDraw.

Are their any advantages to either of the methods?


Solution

  • It's not obvious there's an advantage either way in the scenario you describe. On some architectures, if you're doing a bunch of back-to-back draw calls that use attributes from the same VkBuffer, using firstVertex instead of having to call vkCmdBindVertexBuffers between each draw might have lower overhead.

    The functional difference is that with the offset, you're changing where "vertex 0" is, i.e. adjusting the the logical start of the vertex buffer. If you were using vkCmdDrawIndexed, an index value of 0 would refer to the vertex at that offset. In the vertex shader, the VertexId builtin variable would be 0.

    By using firstVertex, you're saying that the logical vertex buffer starts at offset 0 into the VkBuffer, but that you want to draw geometry starting from some vertex not at the beginning of the buffer. The vertex shader would see VertexId values in the range [firstVertex .. firstVertex+vertexCount-1].

    So if you have a large VkBuffer that you just append different unrelated/independent meshes to, especially if they have different layouts, you might want to just use the offset as you bind each one: you've essentially got different logical vertex buffers stored in a single VkBuffer. Or alternately, if you have a vertex layout with non-interleaved attributes (e.g. position in one "binding", other attributes in another "binding") but want to store them in the same VkBuffer, you'd need to bind the same VkBuffer as two different vertex buffers, but with different offsets.

    On the other hand, if for example you collect dynamically-generated mesh geometry into a vertex buffer each frame, you might want to just bind the vertex buffer once and then use firstVertex to issue the draw call for each mesh. Or if you need to use VertexId for some calculation (e.g. indexing into a storage buffer) you'd want to use firstVertex so each vertex gets the expected VertexId value.