Very quick VertexBuffer question

Started by
11 comments, last by simon_brown75 11 years, 11 months ago
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.
Advertisement
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.
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.

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.
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.
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.

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.
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.
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
When writing to a dynamic vertex buffer you should always specifiy either D3DLOCK_DISCARD or D3DLOCK_NOOVERWRITE when locking it.

This topic is closed to new replies.

Advertisement