The VertexBufferLayout shipped in #186310 only supports per-vertex stepping. There is no way today to mark a vertex buffer slot as supplying per-instance data, which is the primitive every modern asset-heavy renderer (sprite batchers, particles, foliage and decal scattering, light volumes, GPU-driven UI lists) leans on for cheap instanced draws.
Proposal
Extend VertexBufferLayout with two new named parameters:
enum VertexStepMode { vertex, instance }
class VertexBufferLayout {
const VertexBufferLayout({
required this.binding,
required this.strideInBytes,
this.stepMode = VertexStepMode.vertex,
this.stepRate = 1,
});
final int binding;
final int strideInBytes;
final VertexStepMode stepMode;
final int stepRate;
}
stepMode defaults to vertex (today's behavior). stepRate defaults to 1 and only takes effect when stepMode == VertexStepMode.instance; a value of 2 means "the same attribute is reused across two consecutive instances before advancing", which is what every other modern HAL with instanced rendering exposes.
Both parameters default to their no-op values, so adding them is a non-breaking change.
Validation
createRenderPipeline should throw a Dart exception if:
stepMode == VertexStepMode.vertex and stepRate != 1.
stepRate < 1.
HAL dependency
ShaderStageBufferLayout in impeller/core/shader_types.h would need an inputRate field (mirroring the VkVertexInputRate/MTLVertexStepFunction cross-HAL primitive), and the Vulkan backend would need VK_KHR_vertex_attribute_divisor (or 1.4 core) plumbing for stepRate > 1. The Metal and OpenGLES backends already have native support.
Out of scope
- Per-attribute step mode. None of the modern HALs expose this; the step mode lives on the buffer layout.
stepRate = 0 ('broadcast a single attribute value across every instance'). Useful but rare; can be added later via a third enum value (VertexStepMode.constant) without breaking this proposal.
References
The
VertexBufferLayoutshipped in #186310 only supports per-vertex stepping. There is no way today to mark a vertex buffer slot as supplying per-instance data, which is the primitive every modern asset-heavy renderer (sprite batchers, particles, foliage and decal scattering, light volumes, GPU-driven UI lists) leans on for cheap instanced draws.Proposal
Extend
VertexBufferLayoutwith two new named parameters:stepModedefaults tovertex(today's behavior).stepRatedefaults to 1 and only takes effect whenstepMode == VertexStepMode.instance; a value of 2 means "the same attribute is reused across two consecutive instances before advancing", which is what every other modern HAL with instanced rendering exposes.Both parameters default to their no-op values, so adding them is a non-breaking change.
Validation
createRenderPipelineshould throw a Dart exception if:stepMode == VertexStepMode.vertexandstepRate != 1.stepRate < 1.HAL dependency
ShaderStageBufferLayoutinimpeller/core/shader_types.hwould need aninputRatefield (mirroring theVkVertexInputRate/MTLVertexStepFunctioncross-HAL primitive), and the Vulkan backend would needVK_KHR_vertex_attribute_divisor(or 1.4 core) plumbing forstepRate > 1. The Metal and OpenGLES backends already have native support.Out of scope
stepRate = 0('broadcast a single attribute value across every instance'). Useful but rare; can be added later via a third enum value (VertexStepMode.constant) without breaking this proposal.References