Performance of geometry shaders for sprites instead of batching.

Started by
2 comments, last by Stuntdk 11 years, 6 months ago
I haven't really used the Geometry Shader stuff before. I'm old and don't like change. It frightens me.

But, currently with Gorgon I'm recycling a dynamic vertex buffer to display my sprites. Basically if the sprites use the same texture, shader, etc... it adds the sprite to the buffer until it's full or until there's a state change. If the buffer is full, then it's discarded, otherwise more sprites get appended until full. Upon state change or discard, it gets flushed to the render target in one draw primitive call. This seems pretty standard to me, and it's been working quite well for me.

However, I've been giving some thought to using a geometry shader to stream out the sprites. I've done a little reading and it seems that this is an ideal use case for GS. But, apparently there's a few gotcha's with these shaders? Notably, the 1024 32 bit float limit. I understand that the size of data out might an issue as well?

Currently, I'm using a position, color and uv coordinates for my sprites vertices. I suspect I'd need to send all of these, and more besides to shader to meet my needs. So would that cause an issue? I pre-transform my vertices before sending them to the vertex buffer (i.e. no world matrix, I've found this to improve performance), and update the vertex position by the camera and projection matrix in the vertex shader. Will this cause an issue?

Has anyone here used a GS to power a sprite renderer? Did you compare its performance to a batched solution (like the one I presented above)? I'm not able to set up a test project for the time being, so if I could get some feedback, that'd be swell.

Thanks.
Advertisement
I must be missing something...why would you want to stream out your sprite vertices? Stream-out is generally only useful in the case where you want to do some heavy per-vertex work in the vertex shader, then "save" the results so that you can re-use them later. The more common case for a geometry shader is to expand a single point into quad, so that you can send less data to the GPU. It's mostly used for particles, and probably not as useful for a more flexible sprite renderer that might need to handle more complex transformations that are directly specified on the CPU side of things. Either way you need to be careful with the GS. It's implemented sub-optimally on a lot of hardware, particularly first-generation DX10 GPU's. Using it can easily degrade GPU performance to the point of where it's not worth it. Using a compute shader is often a preferred alternative over GS stream out.

Another possible option is to use instancing, where you'd set up vertices + indices for a single quad and then pass all of the "extra" data in the instance buffer (or in a StructuredBuffer or constant buffer). This can allow you to possible pass less data to the GPU and/or do more work on the GPU, while still batching.

I must be missing something...why would you want to stream out your sprite vertices?

Yeah, sorry, it's been a long day. I actually meant expanding a single vertex into a quad.

But your response makes sense and confirms what I've been reading about the GS, so I'll scratch that idea. I may consider trying to implement instancing to see if there's a performance increase.
I haven't personally looked into this, but in the Windows 8 SDK it looks like Microsoft is actually using GS (if supported) in their Spritebatch routine.
http://code.msdn.microsoft.com/windowsapps/Direct3D-sprite-sample-97ae6262

This topic is closed to new replies.

Advertisement