Sign in to follow this  
simon_brown75

Very quick VertexBuffer question

Recommended Posts

Hi, just a couple of really quick questions -

Can you create a vertex buffer between calls to BeginScene and EndScene? (directx9)

And

Is creating and destroying Vertex Buffers every game loop likely to be too slow to maintain a good framerate, even in a fairly simple game?

Many thanks,
Simon.

Share this post


Link to post
Share on other sites
Well, to answer my own question, yes you can create VBs between BeginScene and EndScene, and yes it's fairly slow, but I can probably live with it. Creating and destroying 5 VB is costing my about 50 fps (300 down to 250) but that includes building some vertices and then copying them to the VBs.

If anyone is curious it's for a text display system for my scrolling space shooter game.

Share this post


Link to post
Share on other sites
The answers would be "yes" and "yes" - but the latter answer is more a case of "it depends". It sounds as though you have something more specific in mind here, and it might be best if you give some details of what exactly it is you want to do, as there are very likely solutions available that don't involve having to create/destroy vertex buffers every frame.

Share this post


Link to post
Share on other sites
Thanks.

Basically I want to be able to display text on screen, for stuff like my options menu, the shop menu (as shown above), maybe some dialogue etc. Obviously the text can change often, so the number of characters drawn per frame changes, so the size of the VB changes. I guess I could just have a VB big enough for say 512 characters and just draw however many polys for the numbers of characters I need to render, but that seems messy to me.

The way I have it setup, I can just call one function from anywhere in my code (as long as it's between BeginScene and EndScene)-

void CFont::Text ( char* text, int length, int FontIndex, float x, float y, float size )

for every line of text and the function handles everything, creating the VB, building the polys for the text (obviously I'm using texture coords to select the appropirate character from a font texture), copying those polys to the VB, drawing the text and then destroying the local vertex array and VB, and it does all that every frame, for every line of text.

It seems like a really clean solution, and it was quick and easy to program, but it is slow, but then again if it's for the menus that doesn't matter, so it depends how much I need to use it during actual gameplay.

Share this post


Link to post
Share on other sites
You can create a large vertex buffer only once, and then depending on how many characters you need to draw ect... you simply change your offset, and size to draw in your draw call. As you already are aware, your current method has a huge impact on performance.

Another idea, you could fill up your vbuffer with a-z(once), and spell out your text using a single vbuffer using multiple draw calls.

Share this post


Link to post
Share on other sites
With D3D9 you can use an ID3DXSprite interface which will manage the vertex buffer for you. Otherwise you want a dynamic buffer with the discard/no-overwrite pattern. You could also use DrawPrimitiveUP which would be better than creating/destroying buffers every frame.

The main point about vertex buffers that you seem to be missing is that you don't have to use the entire buffer for a frame's draw calls. You could create a single buffer big enough for - say - 64k verts, write in however many you need for the first frame, issue draw calls from first to last, then append to the buffer in the next frame. When the buffer is full you lock it with D3DLOCK_DISCARD and start again.

Share this post


Link to post
Share on other sites
I do understand that you can draw a subset of the verts in a VB but I thought it would get messy with multiple fonts (i.e. textures) and needing to sort by texture, but I can just have 1 VB for each font. TBH I'm never going to have more than a few hundred characters on screen so the size of the VBs shouldn't be a problem. I did kinda forget you can append verts to a VB though.

FWIW the framerate hit is smaller than I realized, I'm dropping from 260 to 250 fps during the most demanding part of a level. The drop is numerically higher during less demanding sections, but it's also less relevant there. I do need to figure out why my mesh background tiling system is dropping me from about 800 to 250 fps though :s

Anyway, I'll get my font class fixed tomorrow, thanks for the help guys.

Share this post


Link to post
Share on other sites
Well I finally got round to fixing this, by having one big VB for each font (enough for 512 characters), and appending vertices rather than creating and destroying VBs every frame, and to my shock it's actually much slower this way.

It seems like locking a specific section of a VB is so slow that it's actually quicker to create a VB and lock the whole thing, than already have a VB and lock a subsection. I'm [i]very[/i] surprised about this.

It's quite possible I'm using the wrong flags on either creating or locking my VBs though. I've tried MANAGED and DEFAULT pool, and both DYNAMIC and WRITEONLY usage, but every combination was still a lot slower than the old method. I didn't try any of the lock flags yet though, I dunno if any of them are applicable TBH.

Anyone know what's going on?
Thanks.

Share this post


Link to post
Share on other sites
Nevermind, I've just realized I'm being stupid.

What I should be doing is appending to my local array of vertices (and not the VB) every time my Text function is called and only copying the whole thing to the VB before my Draw function is called. In fact I could just store the text and it's properties each time Text is called and then build all the vertices in memory at the same time, and then copy them to the VB.

uggghh....where's that embarrassed smilie when you need it [img]http://public.gamedev.net//public/style_emoticons/default/biggrin.png[/img]

Share this post


Link to post
Share on other sites
Thanks.

Well I've ammended the code so I'm now creating all my vertices in 5 vertex arrays (1 for each coloured font I have) in system memory, then once per frame I'm copying all those verts to the corresponding 5 VBs and rendering the fonts. So I now have just 5 lock()s and 5 calls to SetStreamSource/SetTexture/DrawPrimitive per frame. I'm also using DYNAMIC VBs in DEFAULT pool and using LOCK_DISCARD.

By doing all this it has just surpassed the old method by about 2%. If you take a look at my options menu above, using the old method of creating, filling, drawing from and destroying a VB for every text entry (there's 28 of them on that screen) I was getting 760 fps and using the new method where I'm not creating or destroying any VBs and just doing 5 locks per frame I'm now getting 780 fps.

It's a better piece of code now, and I guess any amount faster is a good thing, but I really expected more than that.

Oh well, it's not worth worrying about. The text drawing is only a tiny fraction of the time taken per frame while actual gameplay is happening. Time to move on.

Share this post


Link to post
Share on other sites
The only major thing remaining to check is that you have D3DUSAGE_WRITEONLY on the buffers, but to be honest at this kind of framerate and considering the proportion of use of this code compared to the rest of your program, you're not going to see any really huge perf differences. The really important thing here is that you now have a batch of good dynamic buffer code that you can adapt/reuse for any other cases you have that may need it.

Share this post


Link to post
Share on other sites
Thanks very much for the help [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img] Yes the VBs are WRITEONLY.

TBH I should only be rebuilding the VBs when the text on screen changes, but I dunno if it's worth the effort to figure that out since there's greater potential for performance gains elsewhere in the code, and the text does change a lot during gameplay.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this