Quickest way to render a custom sprite

Started by
8 comments, last by Goodlife 20 years ago
Hi all, I''m looking for the faster, least bandwidth way to render some sprites. Right now, what I''m basically doing is this: Loading... 1) Load the sprite graphic 2) Create a dynamic vertex buffer Rendering: 1) Lock the vertex buffer 2) Write my xyz/rhw/diffuse/uv info into the buffer (4 vertices) 3) Set the stream and draw the primitive It runs pretty fast, except on one of my machines, where it runs a little slow. PART of the problem is that I sometimes get cases where I need to change a *lot* of textures (I''ll be optimizing that soon, but not yet). But, what I wanted to know is... is there some better way to display sprites? I considered using an ortho view matrix to transform them, but the problem is that at times I need control of all four vertices that represent the sprite''s corner-- my sprites distort in shape. I considered using vertex shaders, but I''ve heard they''re not very backwards compatible. I want this program to work on older machines. So, can anyone suggest anything? Thanks in advance!
-- Goodlife-----------------------------Those whom the gods would destroy, they first drive mad.--DirectX design team official motto
Advertisement
If you''re using Direct 3d, all i can suggest is dont use a vertex buffer, but if all you want to do is display a bmp or jpeg to the screen, revert back to DirectX 7 and do some simple initiation of direct draw and blit the pic to a back buffer.

Hope that helps
Ace
I will also add,

One of the first things i learned was direct draw and i forget the barebones now but it is extremely easy to do a kinda slideshow system by loading all the pics in at once or on the fly.

Back to D3D, if you are loading the pics in as BMP try using jpg, maybe its quicker i dont know.

Another quick idea is that maybe if you programmed any of the basic maths in assembler it would speed up for sure. I learned this year at university how much crap the windows compiler produces when it compiles to assembler. Assembler isnt tricky. I can help if you e-mail me at Ace_lovegrove@hotmail.com.

Lastly, if you use the keyword "register" before variable names you can entice the compiler into trying to put that variable into the CPU registers. The compiler has no obligation to do this, but its worth a try. Simply write:

register int var1;

regards ACE
I''m sorry, I should have specified: I''m using a *lot* of alpha, so all my images are nicely anti-aliased.

Otherwise, believe me, I''d be using DX3 !!
-- Goodlife-----------------------------Those whom the gods would destroy, they first drive mad.--DirectX design team official motto
Create a vertex buffer for every object, perhaps? It''d save you the constant locking just to copy in 4 vertices.
quote:Original post by Goodlife
Otherwise, believe me, I''d be using DX3 !!
I guess that means you aren''t using D3D9, right? Otherwise, you could use ID3DXSprite (which is already optimized by Microsoft, so you''re probably not going to get much faster).

Also, optimizing your math in asm is a waste of your time. The D3DX has already been optimized by Intel and AMD to use SSE, SSE2, and all those super-fast CPU libraries.


Dustin Franklin
Mircrosoft DirectX MVP
Dustin Franklin ( circlesoft :: KBase :: Mystic GD :: ApolloNL )
quote:Original post by ace_lovegrove
Back to D3D, if you are loading the pics in as BMP try using jpg, maybe its quicker i dont know.

Regardless of whether it is a jpeg or a bmp on disk, it''s stored the same way as a texture. And since a jpeg is compressed it will generally be slower to load.
quote:
Another quick idea is that maybe if you programmed any of the basic maths in assembler it would speed up for sure.

This is crap.
quote:
I learned this year at university how much crap the windows compiler produces when it compiles to assembler. Assembler isnt tricky.

If they didn''t teach you that the largest gains are algorithmic, NOT code optimizations, you should ask for your money back.
quote:
Lastly, if you use the keyword "register" before variable names you can entice the compiler into trying to put that variable into the CPU registers. The compiler has no obligation to do this, but its worth a try. Simply write:

First, you can''t put all your variables in registers, there aren''t that many of them. You need to understand which ones would actually benefit from being in registers. And, as you noted, the compiler is free to ignore you. Which in this case would be a good thing.

Rendering 1 sprite at a time is an incredibly inefficient thing to do. What you need to do is draw many sprites at a time.
1)Batching. If 3 sprites use the same texture, draw all 3 at the same time. This means you''d need a larger VB to hold the vertices. Use TriangleLists not Strips. Obviously you need to somehow sort your textures into groups.
2)Texture pages. Combine multiple textures into a single page. By adjusting the tu/tv coords you can now batch a larger number of sprites.

Your absolute minimum goal should be drawing about 100 triangles per Draw call. Depending on the hardware the sweet spot can be in the hundreds or the thousands. Obviously in a sprite-based app you will not always hit that goal, but it is where you should be aiming.


Stay Casual,

Ken
Drunken Hyena
Stay Casual,KenDrunken Hyena
Just on the comment about using register. Not only is the compiler free to ignore you, it will in all cases. This key word is depricated for Microsoft compilers.

Cheers
Chris
CheersChris
Hm-mmm... currently I *do* lock the vertex buffer each time, to write in the sprite''s location. Each sprite has its own vertex buffer.

Are you suggesting that I can just leave a dynamic vertex buffer locked, and render without problems?

Pseudocoded, this is my sprite program:

CreateSpriteRoutine()
{
Load_The_Image();
Make_The_Vertexbuffer(4Vertices,Dynamic);
}

DrawRoutine(x,y)
{
Lock_The_VertexBuffer();
Vertex[0]=(x,y);
Vertex[1]=(x+width,y);
Vertex[2]=(x,y+height);
Vertex[3]=(x+width,y+height);
Unlock_The_VertexBuffer();
Do_The_DrawPrimitive();
}

Again, psuedocoded, there. They point being that every time I draw a sprite, I lock it, set up the vertices, unlock it, and render. This has turned out to be quite a bit faster than DrawPrimitiveUP, I guess because DrawPrimitiveUP makes a vertex buffer each time.

So, what''s the deal, can I really leave it unlocked?
-- Goodlife-----------------------------Those whom the gods would destroy, they first drive mad.--DirectX design team official motto
No, rather than having 1 VB per sprite, create a VB can can hold a number of sprites. Sort your sprites by texture, then do something like (lame pseudocode):
foreach (texture in list_of_visible_textures)   Lock BigVB (with DISCARD flag)   foreach(sprite in sprites_that_use_texture)      Write vertices for sprite to BigVB   end   Unlock BigVB   DrawPrimitive with BigVBend 


BigVB will need to be created with the DYNAMIC flag. There''s a lot more you can do to optimize things further but this is a good start.


Stay Casual,

Ken
Drunken Hyena
Stay Casual,KenDrunken Hyena

This topic is closed to new replies.

Advertisement