Quicker way to draw sprites?

Started by
6 comments, last by MatthewDiaz 12 years, 7 months ago
First my question then the code. In C++/Directx 11 I want to draw multiple textboxes on the screen in one draw call but don't know how to do it. I currently have the code set to call draw for each box rendered. It works like this. I have a vector of textboxobjects. Each of those textboxes contain a vector of 2 sprites(one for highlighted text box and one not), which contain all the code needed to project the world matrix, screen positioning, buffers etc. All the information for these sprites is correct.



bool DrawTextBoxes()
{
unsigned int size = currenttextboxes_.size();
if(size == 0)
return true;

unsigned int stride = sizeof(VertexPos);
unsigned int offset = 0;

for(unsigned int i = 0; i < size; i++)
{




//When a new screen begins the new textbox vector replaces values in these buffer arrays during Update one time.
d3dContext_->IASetInputLayout( textboxinputLayout_ );
d3dContext_->IASetVertexBuffers( 0, 1, &textboxvertexBuffer_, &stride, &offset);
d3dContext_->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

d3dContext_->VSSetShader( textboxsolidColorVS_, 0, 0 );
d3dContext_->PSSetShader( textboxsolidColorPS_, 0, 0 );
d3dContext_->PSSetShaderResources( 0, 1, &textboxcolorMap_ );
d3dContext_->PSSetSamplers( 0, 1, &textboxcolorMapSampler_ );

/*I am gonna move the following 4 lines of code to an update function(ifi can) so this won't be done every frame
It's here now so you can see what I am doing. */

XMMATRIX world = currenttextboxes_.at(i).GetSprite().at(0).GetWorldMatrix( );
mvp_ = XMMatrixMultiply( world, vpMatrix_ );
mvp_ = XMMatrixTranspose( mvp_ );

d3dContext_->UpdateSubresource( textboxmvpCB_, 0, 0, &mvp_, 0, 0 );

d3dContext_->VSSetConstantBuffers( 0, 1, &textboxmvpCB_ );
d3dContext_->Draw( 6 , 0);

}



return true;

}


The code works,. I get 3 text boxes in the positions I wanted. If I benefit later form learning a better way could someone help me to do so?
Advertisement
There are many different ways to do what ask, I am not sure what the standard defacto way is. My method is;
My Ui is made up of textured and untextured quads, cpu side each of these is one vertex a point primitive, on the gpu the geom shader turns this into a quad.
I optimise this by having each logical group render to a texture, which is only updated it when required.
If this optimisation is unsuitable, maybe you have an animated UI, the you could condense your calls by having primitives share vertex buffer(s), or alternative use DrawInstaced.

One easy direct optimisation to what you have;
Instead of;
"d3dContext_[color="#666600"]->[color="#660066"]IASetPrimitiveTopology[color="#666600"]( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST [color="#666600"]);"
Look into ; D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP





There are many different ways to do what ask, I am not sure what the standard defacto way is. My method is;
My Ui is made up of textured and untextured quads, cpu side each of these is one vertex a point primitive, on the gpu the geom shader turns this into a quad.
I optimise this by having each logical group render to a texture, which is only updated it when required.
If this optimisation is unsuitable, maybe you have an animated UI, the you could condense your calls by having primitives share vertex buffer(s), or alternative use DrawInstaced.

One easy direct optimisation to what you have;
Instead of;
"d3dContext_[color="#666600"]->[color="#660066"]IASetPrimitiveTopology[color="#666600"]( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST [color="#666600"]);"
Look into ; D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP







I tried using DrawInstanced with just the bufferarray names, without the [x], and putting the currect numbers of indexs in all the Set functiions. All I get is 3 of one box drawn 3 times on top of itself. I don't know how to draw all 3 of my boxes seperately through instancing.
Assuming your postioning infromation comes from a world matrix then for instancing you will need to send the shader your three different world matrices.
E.g. In your shader you have an array of matrices and you index them via the SV_InstanceId semantic. (That might not be spelt correctly)
Do you have separate textures set up for each text-box, so that the texture contains the actual text in the box?
Perhaps you can show a screenshot of how it looks like. It's hard to say exactly what is the best way, but it sounds like you should be able to do it without changing any states between text-boxes, except for the textures which could be put in a texture-atlas, and the positions. Since you probably don't have very many vertices and if your text-boxes are controlled on the CPU anyway, it might be better to use a dynamic vertex-buffer and update the vertices every time they change instead of updating the constant-buffer for every box.

Do you have separate textures set up for each text-box, so that the texture contains the actual text in the box?
Perhaps you can show a screenshot of how it looks like. It's hard to say exactly what is the best way, but it sounds like you should be able to do it without changing any states between text-boxes, except for the textures which could be put in a texture-atlas, and the positions. Since you probably don't have very many vertices and if your text-boxes are controlled on the CPU anyway, it might be better to use a dynamic vertex-buffer and update the vertices every time they change instead of updating the constant-buffer for every box.


I do have seperate textures, and no the text needs to be drawn seperately because my game will have different text in the same textboxes. I am gonna code an alighnment system for my textboxes which my draw font function will access. I draw my fonts using a mapped dynamic vertex buffer which allows me to draw many sprites in one draw call. I could resort to that, however, keeping the way I have these textboxes drawn keeps things simple for me. So I decided to just keep it simple for now. While I continue to code my game I will research more about DX11 because I clearly have a lot to learn. I checked out instancing and it is way over my head. Same goes for any other method of doing multiple sprites in one draw call.

As far as the constant buffer is concerned I am gonna try to move that code to an update function which is called only when the screen state changes. This will change the values of the constant buffers very seldom. So like as long as the title screen is on, the constant buffer array is already set and never changes. When I press like "Start New Game" new textboxes are replaced in the currenttextboxes vector and loaded in one update function. Should reduce some overhead.
You at least be able to remove most of the state-changes from the loop, as I assume text-boxes usually use the same shader, input layout, topology, and sampler state?

You at least be able to remove most of the state-changes from the loop, as I assume text-boxes usually use the same shader, input layout, topology, and sampler state?


Each textbox class has already loaded it's own resources, buffers etc. in program startup. The arrays in the draw textbox function are redefined whenever thevector <textbox> currenttextbox changes. It gets changed once whenever a new screen begins(combat screen, load game screen etc.). It was the fastest way I could think of.

This topic is closed to new replies.

Advertisement