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?
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.