XBox:Framework:Faster Sprites
From MadoxLabs
|
Edit Downloads:XBox (http://www.madox.ca/mediawiki2/index.php?title=Template:Downloads:XBox&action=edit)
|
I seem to have found a way to render sprite significantly faster. I have been playing with different ways to handle UI textures when rendering UI widgets (which a just sprites really). If I have many UI skin textures, is it better to combine them all into one or use many textures and set each sprite to use the appropriate one?
I tried playing with the case of using many textures. In this setup, I render 2000 quads each using a 200x200 texture. I create 7 extra copies of the texture, and create 7 texture samplers in the shader.
In the vertex declaration, I hijack one of the bytes to store which texture to use. Since these sprites are 2D, the Z and W coordinates are free to use. This is where I stuck the texture index. Then to sample the right texture, I have a big if/else block.
Some code explaining this:
The vertex definition:
struct CrapVertex
{
// Each vertex contains the following:
public Vector4 Position; // The W coordinate is the flag for which texture to use
public Vector2 Texture;
public static int SizeInBytes
{
get { return 6 * sizeof(float); }
}
public static readonly VertexElement[] VertexElements = new VertexElement[] {
new VertexElement(0, 0, VertexElementFormat.Vector4, VertexElementMethod.Default, VertexElementUsage.Position, 0),
new VertexElement(0, 16, VertexElementFormat.Vector2, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 0),
};
}
A portion of the shader that uses this:
texture tex0;
texture tex1;
// continue tex2 - tex7
sampler2D sam0 = sampler_state { Texture = <tex0>; };
sampler2D sam1 = sampler_state { Texture = <tex1>; };
// continue sam2 - sam7
struct VertexShaderInput
{
float4 Position : POSITION0;
float2 Texture : TEXCOORD0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float2 Texture : TEXCOORD0;
float3 Location : COLOR1;
};
VertexShaderOutput VS(VertexShaderInput vertex)
{
VertexShaderOutput output;
// snip - setting the output.position
output.Texture = vertex.Texture;
output.Location.xy = float2(pos.x, pos.y); // copy the untranslated position for use in PS
output.Location.z = vertex.Position.w; // pass the texture flag on
return output;
}
float4 PS(VertexShaderOutput pixel) : COLOR0
{
float4 ret;
// get the color from the image in the flag
if (pixel.Location.z == 0)
ret = tex2D(sam0, pixel.Texture);
else
ret = tex2D(sam1, pixel.Texture);
// continue if/else for 2 to 7
return ret;
}
When I set up the vertex stream, I set Position.W to be a number from 0 to 7 for which texture to use in PS().
Before doing this, rendering 2000 quads all at once with a single texture, the time per frame was ~120ms. After adding 7 more identical textures and spreading out the quads evenly across textures, the time per frame was 16ms.
It seems to me, if you are render a large number of prims all using the same texture, you will get great speed increase by using this multi texture method. This kind of thing is great for things like particles, grass, or anything with lots of the same geometry on screen.
2010-06-06
Disregard this page. I had messed up the vertexbuffer so that it was rendering far fewer quads than I though, as I added textures. Once I fixed the error, the multi-texture method was running 3x slower on average. The reason for this is that the shader will sample all 8 textures for all pixels and then pick one from the 8 samples.