• Advertisement
Sign in to follow this  

Is DrawPrimitiveUP() Slow ?

This topic is 4616 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi guys, My 2D game will have about 500 moving sprites displayed at any given time. I'm still trying to figure out the best way to set up a 2D environment. If I use a vertex buffer I can either Lock()/Unlock() every time a sprite moves (every frame), or to avoid that I can setup an orthogonal matrix but I still have to apply the transformations for each sprite (every frame). So I was thinking of using DrawPrimitiveUP() for my blits. Do you think that's a good idea ? If not, considering my situation of about 500 moving sprites, what's the best (fastest) method ? Thanks.

Share this post


Link to post
Share on other sites
Advertisement
Applying new values to a matrix is probably much much faster than locking a vertex buffer, so go with that method.

DrawPrimitiveUP() is for when you want culling but are too lazy to deal with winding order. The fastest way would be to apply the correct winding order and culling, then use DrawPrimitive().

Edit: Actually if you had all the vertices in one big VB, locking it might be faster then editing 500 matrices.

Share this post


Link to post
Share on other sites
The fast way to do this is to use a dynamic vertex buffer. Make it big, then each frame lock it with NOOVERWRITE flag and add your new sprites and render them. When you get to the end, you lock with DISCARD and start over.

The huge advantage here is you can have dynamic sprites, update them every frame, AND render them all in one DrawPrimitive call. (Unless you have many textures, then your number of draw calls = number of textures.)

So you could make a VB with room for 5000 vertices, and on the first frame you might fill and render 1-150. Then on the next frame you might render vertices 150-300, etc... and if you want even better speed, make a corresponding dynamic index buffer so you only need to send 4 vertices per sprite instead of 6.

I have to stress that if you get the locking flags correct, this method is VERY FAST for 2D sprites. If you get them wrong things can be SLOW.

If you have large numbers of sprites that won't ever change you can use a static vertex buffer in addition, but in general static VBs aren't as useful for sprites. You have to render each static vertex buffer independently which is more DrawPrimitive calls.

Share this post


Link to post
Share on other sites
Quote:
Original post by Scet
Edit: Actually if you had all the vertices in one big VB, locking it might be faster then editing 500 matrices.


I would say definitely. Matrices are cool but you just can't leverage them with sprites (except to transform your own vertices unrelated to D3D). I tried rendering each sprite individually and its a dead end in terms of performance. There's no way to apply different matrices "within" a DrawPrimitive call, so the dynamic vertex buffer works better. With a dynamic VB rendering your sprites, you can afford a large number of sprites/particles/etc because you are exploiting parallelism with the GPU.

It is important to have a utility or something to combine textures together. You want large sheets of sprites/animations (use texture coordinates to select individual frames) whenever possible so you can minimize the number of times you have to interrupt your rendering to switch texture.

Share this post


Link to post
Share on other sites
To answer your question, DrawPrimitiveUP is slower than creating and maintaining your own vertex buffer. That's because DrawPrimitiveUP creates a new vertex buffer every time it is called.

Share this post


Link to post
Share on other sites
Hi guys,

That helps a lot. But I don't understand how to render two (or more) seperate sprites with one call to DrawPrimitive().

And is this the general idea:

-start frame-

lock vertex buffer
set X and Y values to where the live sprites are
unlock vertex buffer

DrawPrimitive()

-end frame-

That's assuming I have one texture.

I really want to get the hang of this because I have quite a few mini-games I made with DirectDraw that I'd love to update.

More help would be appreciated. Thanks.

Share this post


Link to post
Share on other sites
You pretty much have the right idea here:

Quote:
Original post by Endemoniada
-start frame-

lock vertex buffer
set X and Y values to where the live sprites are
unlock vertex buffer

DrawPrimitive()

-end frame-


You can add as many sprites as you like, in between the lock and unlock calls.

The way I do it, is keep a vector of "drawdata" which contains the data I need to set up the vertices. When I call my "draw" function, all it does is just add a new "drawdata" to my vector.

When I call "endscene", I do all the real work: lock the VB, and set up all the vertices at once, unlock the buffer, and use one drawprimitive call to render them.

(That's kind of simplified, since it assumes I'm only using one texture, but I hope you get the idea)

Share this post


Link to post
Share on other sites
Quote:
Original post by Endemoniada
-start frame-

lock vertex buffer
set X and Y values to where the live sprites are
unlock vertex buffer

DrawPrimitive()

-end frame-

That's assuming I have one texture.


You'll probably have to have one DrawPrimitive() per texture, but that should be it. Sort your sprites before rendering so that all the ones that use the same texture are grouped together and can be rendered with just the one DrawPrimitive() call for that texture.

Share this post


Link to post
Share on other sites
Quote:
Original post by JohnBolton
To answer your question, DrawPrimitiveUP is slower than creating and maintaining your own vertex buffer. That's because DrawPrimitiveUP creates a new vertex buffer every time it is called.

It doesn't create a buffer each frame. It uses a dynamic vertex buffer that's locked and filled every time it's called.

Share this post


Link to post
Share on other sites
Hi guys,

I think I understand everything now. Here is how I set it up:

// initialize vertex buffer (called once)

UINT nVertices=MAX_SPRITES*4;
DWORD dwSize=nVertices*sizeof(CUSTOMVERTEX);

CreateVertexBuffer(dwSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_VB, NULL);

// initialize index buffer (called once)

UINT iSize=MAX_SPRITES*6*2;

CreateIndexBuffer(iSize, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &g_pIB, NULL);

// set all the index values here


// my render loop (called every frame)

Lock(0,0,(void**)&v,D3DLOCK_DISCARD); // vertex buffer

// set the vertices for the live sprites here

UnLock() // vertex buffer

BeginScene()

SetTexture(...)
DrawIndexedPrimitive(...);

SetTexture();
DrawIndexedPrimitive(...);

EndScene(...);

Am I using the flags correctly ? I made the vertex buffer dynamic and the index buffer static, both are write only. About the pools, I can't use managed for the vertex buffer so I just used default, what is recommended ? I can use the D3DLOCK_NOOVERWRITE method but it seems pretty complicated, will it be much faster that way ?

I made it so that I only have to switch textures once (so I have two textures in total).

I didn't set up a performance counter yet, I just want to make sure I have the right idea here.

Thanks again everyone.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement