Trouble with hardware vertex processing

Started by
9 comments, last by crucifer 19 years, 6 months ago
I have been doing a little game with dynamic terrain. When I create my directX device using software vertex processing, I can change the positions of the vertex in my vertex buffer and the changes are reflected correctly when I render. But when I set my device to hardware vertex processing, the rendering stays unchanged. The terrain will stay exactly as it was when the vertex buffer was originally created even though I modified it many times. Does anyone thinks of a solution ?
Advertisement
You have probably already done this, but are you unlocking the vertex buffer once you have done stuff with it, to update the video memory.
Yeah, I lock, modify, unlock.

As I said, It works perfectly in Software Vertex Processing. The terrain is modified perfectly.

It also renders in Hardware letting me believe that everything worked OK. But when I render in Hardware, the terrain is unchanged even though the vertex buffer is modified.
It might be an issue with your lock flags (DISCARD, etc). In SW processing mode, since your vbufs/ibufs live in system memory, it probably wouldn't matter if the lock flags were wrong. From the syptoms, it sounds (just a guess) like your doing a NOOVERWRITE lock on the entire buffer?

joe
image space
Since I never read from the buffer, the only flag I knowingly set when I create the buffer is "D3DUSAGE_WRITEONLY". Also, I create the vertex buffer in the default d3d pool (so I don't have to care when the device is lost).

Where would you think a "NOOVERWRITE" flag be located (or changed) ?
The NOOVERWRITE flags is a parameter to the Lock method, but wouldn't matter since it seems you are creating a static, default pool vbuf. What does your lock call look like?

Note:
You should create your vbuf with D3DUSAGE_DYNAMIC if you're going to be locking more than once per frame. Also, creating in DEFAULT pool will not relieve the responsibility of restoring after device loss. For that, you should use the MANAGED pool.

joe
image space
You are right about the "MANAGED" buffer. That's what I meant and should have written.

For the lock, I currently do not have my source code. Could you give me an example of the "correct" way to do the lock knowing what I intend to do with it?

P.S: Give me an example for if I intend to write only once per frame vs if I intend to write multiple times per frame.

Thanks
default pool means you DO have to worry about lost devices.
managed pool means you DON'T have to worry about lost devices.
Dynamic VBs cannot be in the managed pool (you haven't said what type of VB you're using (do you specify DYNAMIC as a flag on Create?))

You really should be using a dynamic VB if your mesh is contantly changing, and using correct NOOVERWRITE/DISCARD flags on lock. Dynamic VBs aren't really meant to hold meshes for long periods of time. They hold the data long enough for you to render it. Their typical use is as follows:
nOffset = 0bFirstInFrame = truewhile (stuff to draw){  if (nOffset + nMeshSize > VBSize || bFirstInFrame)  {    flags = discard    bFirstInFrame = false    nOffset = 0;  }  else  {    flags = nooverwrite  }  Lock(noffset,size,flags,buffer)  memcpy to buffer (pointer should be offset already because of offset in lock)  Unlock()  nOffset += size;}


In other words... when the VB is full, or it's the first draw of the frame, throw away the contents of the VB (discard). Otherwise, append data to the remaining space in the VB (nooverwrite).

If your data only changes rarely, this will create an unnessary strain on your graphics card (mesh data needs transferring for each render). However, changing the mesh ever will create a stall when you lock the buffer... one solution is to cycle between 3 or 4 static buffers. This lets the graphics card finish dealing with the old buffer before you attempt to reuse it. You could try using only 2 buffers, but if two changes occur in rapid succession, you'll be forced to stall... which may be acceptable to you.

Another solution would be to use a single static buffer, but when you need to modify the data, use a dynamic buffer for a few frames (allowing the queued draw calls on the static buffer to finish), then copy the new data into the static buffer. This has the advantage of only putting the extra strain on the graphics card for a few frames whenever a change in needed, and should take less GPU memory than cycling between 3-4 buffers.

There is no ideal DX or OpenGL buffer for dealing with occasionally dynamic data such as changes to landscape, leaving you to come up with your own hackish solutions like those above.
That makes a lot of sense. I will try that.

Also, thanks for the advices about the multiple buffer-switching. I didn't knew about the stalling. But it is logical knowing that the CPU and GPU are working in parallel. One cannot access the other memory simultaneously without slowing it/himself down.
Kinda an edit, but here to be more visible. When I say "However, changing the mesh ever will create a stall when you lock the buffer", I meant

"However, if you use a static buffer, changing the mesh ever will create a stall when you lock the buffer", this puts you in the situation of choosing between a) Dynamic buffer, and sending lots of data to the card each frame and b) Static buffer, and stalling on changes... then I present methods to overcome those limits.

This topic is closed to new replies.

Advertisement