7
\$\begingroup\$

Am considering porting over from XNA to the Stage3D API's (Molehill). So as a performance examination I've implemented sprite-batching, but the performance is not all that great, while with XNA i can easily draw up to 500 000 quads but with my Molehill implementation i can draw around a measly 1000 quads and while a rather dramatic performance difference was expected on the CPU side this is due to being GPU bound.

So currently the implementation is as follows.

set render states

let texture be null
let batchSize be arbitrary

for each sprite in queue
    if texture is not sprite texture
    or buffers are full

        upload vertex data to index buffer
        upload index data to vertex buffer

        bind texture
        draw triangles

        flush vertex data
        flush index data
    

    add sprite vertices to vertex data
    add sprite indices to index data
end

upload remaining vertex data to vertex buffer
upload remaining index data to index buffer
draw remaining triangles

flush data

The bottleneck is uploading the buffers, but as for a better implementation I'm hoping for a discussion here.

Cheers.

Revision:

One optimization that comes to mind is to persist the index buffer, since the indices are predictable and will always follow the same format. Am going to benchmark that now.


Caching the index buffer had no noticeable performance gains, so in an effort to try to understand where the bottleneck is, I ported it over to C#/XNA, ever so slightly slower than Microsoft's implementation but still has a GPU capacity over 500 times more than the Molehill implementation.

Is Molehill simply an extremely bad abstraction layer?

\$\endgroup\$
7
  • \$\begingroup\$ Making the Index Buffer persistent is a good idea, that may help gain a bit of perf. The only other thing I can think of from looking at your pseudo code is that you always re-bind the texture. You should check if the texture has changed between calls and only then bind a new texture, otherwise you'll get no performance gain from using a Texture Altas for example. \$\endgroup\$ Nov 2, 2011 at 7:34
  • \$\begingroup\$ Actually, the texture is only bound once, perhaps read over it again. \$\endgroup\$ Nov 2, 2011 at 8:39
  • \$\begingroup\$ Oh yeah, it's implied that "texture" is assigned to the sprite's texture on binding. \$\endgroup\$ Nov 2, 2011 at 23:45
  • \$\begingroup\$ You have 'Bind Texture' in the for each loop. I was saying that it should be if'd so that you don't call Bind Texture when the texture hasn't changed between two sprites. At the moment you're asking the GPU to re-bind a texture in every loop; it's a costly operation and may not be needed. \$\endgroup\$ Nov 3, 2011 at 16:38
  • \$\begingroup\$ Again, it's only bound once. A conditional check is hardly a costly operation. \$\endgroup\$ Nov 4, 2011 at 0:44

1 Answer 1

2
\$\begingroup\$

You could have a multi-map of sprites in which their key is the texture, then when rendering, go through each key in the map and render each group of sprites that are associated with that texture. If sprites all share the same texture then you can represent every sprite with two triangles and texture coordinates, which means you can draw all sprites that use the same texture in a single pass, with a single vertex buffer and index buffer.

Although I'm using XNA, I've rolled my own rendering and batching process rather than using sprite batch, and I'm rendering about 3000 sprites at a time and currently getting about 600 fps on an Nvidia GTX 275, using the process I described above. When I was just passing the sprites to the spritebatch method XNA gives it was about 25 fps.

In my case, rather than a multimap I have a class (SpriteData) that contains the texture and a list of vertices. Whenever a sprite registers with the renderer, the renderer goes through a List of SpriteData until it finds a matching texture type, and adds that sprite to vertex list.

I'm also doing spatial partitioning to make sure that only sprites in view are being considered.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .