Skip to main content
gamedev.net
🔒 Locked

Question regarding buffers

Started by DadleFish 3 replies 500+ views
Original Post
DadleFish
DadleFish
Hi all, First of all - great forum. I've been a quiet reader for some time now and I'm very impressed with the technical level of some of you people. On to my question(s). I'm currently working towards creating a DirectX9 based renderer. I got stomped by several concepts, and I'd appreciate any help/reference/etc. Note that I have read everything I could find in the SDK but still I am a bit puzzled. I guess I'm lacking some background here. First of all, I'd like to know if I got something right. Suppose I've set up a simple vertex buffer and an index buffer, which together create a box. Now I want a simple application that will just rotate the box each frame in all three axes. If I am correct, then if I've used a non-transformed VF, like D3DFMT_XYZ, then I do not need to change the vertices myself - I just set all these matrices correctly, and my vertices will be transformed correctly. If however I use D3DFMT_XYZRHW, then I need to take care of transforming the vertices myself. Is that correct? Supposing I am right, I'll continue to other questions. Why would I want to use a dynamic vertex buffer, if the mesh does not change? I mean, take the box I've mentioned - I guess I don't really need the vertex buffer to be dynamic, because I will not change it, right? As far as I can understand, the only reason to use a dynamic vertex buffer is if my mesh changes - but why would that happen? I'd love to hear a real-life example for something like that (docs I've seen are talking about "a change that occurs many times per frame" - ???). I think that my major problem is that I have several open source references and several books, and each one of these is acting differently. This is very confusing for a beginner. Yet another question is - do I need to create a VB/IB every time I render it? This is the way it's done in Eberly's wild magic, and it looks like a really huge waste of ticks - isn't it? Last question - I saw that you can use a static vertex buffer to host many of your meshes together, while changing the index buffer for rendering the "correct" mesh. Now, making this magic happen would require some kind of "stacking" meshes by a manager, that will collect all the meshes and keep offsets etc. Is this really worth the effort, or should I aim at a buffer-per-mesh? What are the real advantages in a single static vertex buffer? This is quite a lot of questions and I hope I didn't bore you all up. Any help would be greatly appreciated. Thanks a lot, Eldad.
Dubito, Cogito ergo sum.
ScootA
ScootA
I can probably answer some of those quickly and simply:

1) Yes you're right: only untransformed vertexes will be transformed by the matrix stack, so you will need to use a function such as D3DXVec3Transform() (or similar) to transform other vertex types (you will also need to light them), engines such as the unreal engine do their own transformations.

2) I've tested static vertex buffers recently: They seem to render marginally faster than dynamic ones, although they will give you a SEVERE performance penalty if you try to alter them. A simple use for dynamic buffers: A game I wrote recently used a prelighting technique to achieve dynamic terrain lighting without using dynamic lights: over a series of frames we would precompute the lighting values, and then update the colour components of each vertex in the terrain's vertex buffer - thus not allowing us to make it static. You should look at hardware vertex processing whilst you research this topic - HWVP is much more strict on your VB creation and locking flags.

3) NEVER create/destroy any buffers in your main game loop. This is very bad practice. If you need a constantly changing buffer, create a huge dynamic cache buffer at startup and refill each frame with new information. You can certainly re-use a buffer infinite times without having to recreate it. The only time you should need to do this in normal gameflow is during a device reset (eg resolution change).

4) Optimsation practice dictates you should try to keep vertex buffer switches to a minimum - of course its not always possible to keep your entire geometry in a single buffer (it may be too large for a start). Most of the time you will be instancing versions of the same geometry anyway, so if you can group them together at render-time then you need only switch the vertex buffer once anyway. Lowering things such as texture-switches are equally important.

-hope this helps

[S]

[Edited by - ScootA on April 15, 2005 11:19:42 AM]
-Scoot
DadleFish
DadleFish
Thanks for the prompt reply. It clears up a lot.

Now, why would an engine calculate its own transformations? Is that for using shaders (instead of the fixed pipeline), or is there some other reason?

The dynamic example really helped. I was focused on position and didn't really think about all the other vertex components.

Regarding recreation of the buffers when resetting the device, this reminds me another question. D3DPOOL has the Default and the Managed options (and the system memory which sounds less useful) - The documentation says that managed is the preferred way for most applications. Now, I believe managed is slower, but what ARE the consequences for using the default (besides having to recreate them)?

I'll keep the vertex/texture switches in mind, thanks. How does memory really react with that aspect? All the tutorials are saying "just create a VB". But what if we're talking about a really large scene, with many VBs/IBs? I presume that at some point the VRAM will end, right? Will DX take care of it itself or should I take care of it? I've read about managing resources (regarding D3DPOOL_MANAGED) that DX will use LRU to move resources out of VRAM, and switch to MRU when the scene itself is too packed with data. Does this mean that I have to use D3DPOOL_MANAGED or I'd have to deal with the memory issues myself?

Thanks again!
Dubito, Cogito ergo sum.
c t o a n
c t o a n
With regard to your last question, I offer my experience. When you issue a state change or command, such as SetStreamSource, or DrawPrimitives, the GPU doesn't jump straight to it, and the CPU won't wait for the VPU to finish, ideally.

The video card maintains an internal 'queue' of render commands and state changes, and runs through them as fast as it can. The only time the CPU has to wait for the GPU to finish is if it tries to access something the GPU either a) is currently using or b) has to use further along in its command queue.

In this case, the CPU has to wait for the GPU to finish with the resource before it can return, for example, a pointer to locked vertex buffer memory. So as long as the CPU stays clear of the GPU's resources WHILE the GPU is using them, you can get very efficient performance from your application.

For example, locking a static vertex buffer doesn't incur any significant CPU penalty compared to a dynamic vertex buffer, except that the CPU may simultaneously access a dynamic buffer at the same time as the GPU, as long as you promise not to modify old vertices (D3DLOCK_NOOVERWRITE and D3DLOCK_DISCARD). Try and keep the GPU and CPU working in parallel.

Now your next question, which I just noticed, has to do with the mysterious VRAM. There is no way of knowing for certain how much memory there is available on the card (only the driver and DirectX can discern this information) so you're pretty much in a pickle. You can use dynamic resources, which are placed directly in fast-access video memory, so the GPU can access them easily with almost no limitations. The CPU however, has to send vertices and other info across the AGP bus whenever it writes to these resources. Bandwidth is limited, so theres a potential bottleneck. Managed resources reside in system memory, meaning they are easily accessed by the CPU, not the GPU. To get around this, DirectX will upload these managed resources to GPU-accessible memory when the resource is needed. You can hint to the API that you'll need a resource soon with PreLoad(). If VRAM is filled with dynamic resources, the GPU will have to make do with getting the data from the AGP bus, which is damn slow!

The AGP bus is designed so data going TO the video card has alot more bandwidth then data going back across, which is what happens when the GPU accesses system RAM.

I have the buffers I need to be dynamic placed in default memory (VRAM) and those resources that are static or might otherwise not be used for periods of time in managed memory (system RAM) until they're needed. So you have an almost constant updating of the data in VRAM - old buffers getting overwritten with new ones.

Its easier to manage the limited VRAM if you have smaller buffers, but this goes back to GPU state changes and commands, you have to issue alot more SetStreamSource(), DrawPrimitive() calls if you're using small buffers. Its very per-applicaion =/

Hope this helps ya out!
Chris PergrossiMy Realm | "Good Morning, Dave"
DadleFish
DadleFish
Well, if there's one thing I've picked from this thread is that you have to experiment on your application to get the best results. It sounds as if there is no such thing as "one right way" in here. There are many, many cases and you have to get it right for your specific problem.

Thanks a lot, guys, you've really enlightened me with many good tips.
Dubito, Cogito ergo sum.

Topic Locked

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

Sign in to reply to this topic.