<p>A good way to improve sprite rendering efficiency is <a href="https://en.wikipedia.org/wiki/Geometry_instancing">geometry instancing</a>. This lets you define a mesh using one vertex/index buffer pair, then render many instances of that mesh in a single draw call using a second vertex buffer whose elements define the instances. This is more widely supported than geometry shaders; in particular, it's is supported in WebGL via the <a href="https://developer.mozilla.org/en-US/docs/Web/API/ANGLE_instanced_arrays">ANGLE_instanced_arrays extension</a>.</p>

<p>To apply this to sprites, one vertex buffer could define the shape of a sprite (i.e. a quad made of two triangles), then another vertex buffer could contain per-sprite information such as position, rotation, size, and so on.</p>

<p>If there are 4 vertices per sprite and N sprites, the vertex shader will be called a total of 4N times, onces for each vertex in each sprite. You'd use the vertex shader to put the information from the two buffers together, transforming each vertex appropriately to the sprite's properties. This allows the GPU to do the work of generating all the vertices for the sprites, and saves on data uploaded from the CPU.</p>

<p>Coincidentally, I published a small <a href="https://github.com/Reedbeta/gfx-workshops/">OpenGL instancing demo</a> recently.</p>

<p>Using instancing this way does require that all the sprites are drawn with the same state, i.e. the same shader, textures, blending mode and so on. If different states are needed for some sprites, a separate batch of instances will be needed for each state combination.</p>

CC BY-SA 3.0
2016-08-08T03:00:39.677Z
Could point sprites be used in place of 2x triangle vertices? The instance data could be a vec2 to define both the orientation and the size. Although you might need another float in there for rectangular sprites.
PaulHK
CC BY-SA 3.0
2016-08-08T03:32:17.280Z
@PaulHK Point sprites are very limited—they sometimes have a small maximum size depending on GPU, and they don't support rotation or any non-square shapes. Also, they get clipped based on their center point, so they pop out too soon when they move off the edge of the screen. I would not bother with them.
Nathan Reed
CC BY-SA 3.0
2016-08-08T03:51:36.223Z
Yeah I thought they would be a little inflexible, you could rotate in the frag shader but then you need to over-project the size to fit the diagonal..
PaulHK
CC BY-SA 3.0
2016-08-08T19:14:12.373Z
I've seen it commented before that instancing can be slow if you're dealing with very small meshes (like a single pair of triangles). Can you comment on that at all?
porglezomp
CC BY-SA 3.0
2016-08-08T19:19:12.977Z
@porglezomp Hmm, I haven't heard that before, and in fact my experience is the opposite: instancing is a _more_ efficient way to draw small meshes, as it allows the GPU to pack verts from different instances together in each warp/wave. AFAIK, verts from different draws can't be packed together that way.
Nathan Reed
CC BY-SA 3.0
2016-08-08T20:53:01.457Z
@NathanReed I didn't mean as opposed to individual draw calls, just in contrast with larger meshes. If you've had success using instancing on such small meshes, then it seems like it'd be worth trying since it's a really clean solution.
porglezomp
CC BY-SA 3.0
2016-08-07T22:06:03.660Z
2016-08-07T22:06:03.660Z
Nathan Reed
<p>In order to naïvely render sprites, you can send single rectangles with their position, rotation, size, and texture. This is very easy, but given that reducing state changes, draw calls, and data uploads are good ways to improve rendering performance, it's clearly not an efficient solution.
Some techniques like passing each sprite as a single primitive and assembling a rectangle in the geometry shader are very appealing but aren't available if targeting a platform like WebGL or even just older hardware.</p>

<p>On top of issues like batching and texture aliases, how do you efficiently submit geometry to render sprites?</p>

<p>I'm interested in answers that are rendering API agnostic, but using a specific API like OpenGL or Direct X is fine for illustration purposes.</p>

CC BY-SA 3.0
2016-08-07T08:06:15.780Z
Are you talking specifically about OpenGL? Specifically about WebGL? Is instancing available for you?
Rotem
CC BY-SA 3.0
2016-08-07T14:26:07.770Z
Good question, let me clarify that. I'm not particularly interested in a specific graphics API, although I do want the work done on the GPU.
porglezomp
<rendering><efficiency>
Efficiently rendering sprites
porglezomp
# Efficiently rendering sprites

(Asked by: username_0 on 2016-08-06)

In order to naïvely render sprites, you can send single rectangles with their position, rotation, size, and texture. This is very easy, but given that reducing state changes, draw calls, and data uploads are good ways to improve rendering performance, it's clearly not an efficient solution.
Some techniques like passing each sprite as a single primitive and assembling a rectangle in the geometry shader are very appealing but aren't available if targeting a platform like WebGL or even just older hardware.

On top of issues like batching and texture aliases, how do you efficiently submit geometry to render sprites?

I'm interested in answers that are rendering API agnostic, but using a specific API like OpenGL or Direct X is fine for illustration purposes.

**Tags:** rendering, efficiency

> **Comments:**
> **username_1**: Are you talking specifically about OpenGL? Specifically about WebGL? Is instancing available for you?  
> **username_0**: Good question, let me clarify that. I'm not particularly interested in a specific graphics API, although I do want the work done on the GPU.  

---

## 1 answers

### Answer by username_2 on 2016-08-07. Score: 5

A good way to improve sprite rendering efficiency is [geometry instancing](https://en.wikipedia.org/wiki/Geometry_instancing). This lets you define a mesh using one vertex/index buffer pair, then render many instances of that mesh in a single draw call using a second vertex buffer whose elements define the instances. This is more widely supported than geometry shaders; in particular, it's is supported in WebGL via the [ANGLE\_instanced\_arrays extension](https://developer.mozilla.org/en-US/docs/Web/API/ANGLE_instanced_arrays).

To apply this to sprites, one vertex buffer could define the shape of a sprite (i.e. a quad made of two triangles), then another vertex buffer could contain per-sprite information such as position, rotation, size, and so on.

If there are 4 vertices per sprite and N sprites, the vertex shader will be called a total of 4N times, onces for each vertex in each sprite. You'd use the vertex shader to put the information from the two buffers together, transforming each vertex appropriately to the sprite's properties. This allows the GPU to do the work of generating all the vertices for the sprites, and saves on data uploaded from the CPU.

Coincidentally, I published a small [OpenGL instancing demo](https://github.com/Reedbeta/gfx-workshops/) recently.

Using instancing this way does require that all the sprites are drawn with the same state, i.e. the same shader, textures, blending mode and so on. If different states are needed for some sprites, a separate batch of instances will be needed for each state combination.

> **Comments:**
> **username_3**: Could point sprites be used in place of 2x triangle vertices? The instance data could be a vec2 to define both the orientation and the size. Although you might need another float in there for rectangular sprites.  
> **username_2**: @username_3 Point sprites are very limited—they sometimes have a small maximum size depending on GPU, and they don't support rotation or any non-square shapes. Also, they get clipped based on their center point, so they pop out too soon when they move off the edge of the screen. I would not bother with them.  
> **username_3**: Yeah I thought they would be a little inflexible, you could rotate in the frag shader but then you need to over-project the size to fit the diagonal..  
> **username_0**: I've seen it commented before that instancing can be slow if you're dealing with very small meshes (like a single pair of triangles). Can you comment on that at all?  
> **username_2**: @username_0 Hmm, I haven't heard that before, and in fact my experience is the opposite: instancing is a _more_ efficient way to draw small meshes, as it allows the GPU to pack verts from different instances together in each warp/wave. AFAIK, verts from different draws can't be packed together that way.  
> **username_0**: @username_2 I didn't mean as opposed to individual draw calls, just in contrast with larger meshes. If you've had success using instancing on such small meshes, then it seems like it'd be worth trying since it's a really clean solution.  

---

