Skip to main content
GameDev.net gamedev.net
🔒 Locked

Very quick VertexBuffer question

Started by simon_brown75 Apr 27, 2012 at 12:35 AM 11 replies 3.2k views
Original Post
simon_brown75
simon_brown75
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.
simon_brown75
simon_brown75
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.
21st Century Moose
21st Century Moose
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.
Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls. 
simon_brown75
simon_brown75
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.
LevyDee
LevyDee
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.
21st Century Moose
21st Century Moose
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.
Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls. 
simon_brown75
simon_brown75
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.
simon_brown75
simon_brown75
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 very 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.
simon_brown75
simon_brown75
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 biggrin.png
Adam_42
Adam_42
When writing to a dynamic vertex buffer you should always specifiy either D3DLOCK_DISCARD or D3DLOCK_NOOVERWRITE when locking it.
simon_brown75
simon_brown75
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.
21st Century Moose
21st Century Moose
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.
Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls. 
simon_brown75
simon_brown75
Thanks very much for the help smile.png 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.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.