Bottlenecks and instancing.

Bottleneck

While testing the client\server network aspect of my game Shoe String Shooter, my tester was experiencing a slow down in the frame rate. He was getting 30 FPS(Frames Per Second) instead of 60 FPS.

The issue was not because of the network but rather the GPU. But he has quite a powerful GPU and moreover he was getting 60 FPS when he tested the server.

So why was the client slower?
I was drawing text into the screen by having a draw call for each character in the string. The client is simply drawing more text to the screen so this in turn made it slower.
From all the beautiful tessellated graphics, the text was having a really big performance hit.

“Waiting connection…” been drawn many times.

In order to draw the text more efficiently I could either use Direct2D or use instancing.
Instancing allows you to draw the same vertex buffer several times with a single draw call.

Instancing in DirectX11

DirectX11 has support for instancing. As mentioned, you can load a single vertex buffer offline and draw it multiple times in a single draw call.

In order to draw the text we will have a vertex buffer with a single quad and we will draw a string of text by drawing instances of the quads as the same amount of characters in the string.

Instancing allows you to use additional vertex buffers with per instance vertex data. This is data that is added to the vertex parameter in the vertex shader.
We won’t add additional per instance data. Moreover, this will allow us to call as many or as little instances we want regardless of the vertex buffer size.

But how will we differenciate between vertices if they all use the same vertex data? Well, HLSL provide us with a reserved type that gives us the vertex instance ID.
We then use that to access a constant array buffer we will set to the vertex shader before calling the draw call.

struct VertexIn
{
float3 PosL : POSITION;
float2 Tex : TEXCOORD;
uint InstanceID : SV_InstanceID; // A reserved type that is set to the instance ID.
};

For the sake of completion I am including the vertex and pixel shaders code. Notice that color2 is the velocity map vector. I am setting it to 0 because I don’t want the text to be blurred by the motion blur.

VertexOut VS(VertexIn vin)
{
VertexOut vout;
vout.PosH = mul(float4(vin.PosL+float3(gXPos[vin.InstanceID], 0, 0), 1.0f), gWorldViewProj);
vout.Tex = vin.Tex;
vout.Index = gChar[vin.InstanceID];
return vout;
}
struct PS_OUTPUT {
float4 color : SV_Target0;
float4 color2 : SV_Target1;
};
PS_OUTPUT PS(VertexOut pin)
{
PS_OUTPUT pout;
float4 texColor = float4(1, 1, 1, 1);
texColor = gAtlas.Sample( samAnisotropic, float3 (pin.Tex, pin.Index) );
clip(texColor.a - 0.1f);
pout.color = texColor*gColor;
pout.color2 = 0;
return pout;
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s