Issue with dynamic VertexBuffer reuse in Direct3D9

07b9e9e8483468e4a0e1bac1843e6e74
0
Snoob 105 Jan 06, 2013 at 07:14 c++ directx

In my application I create a simple dynamic vertex buffer :

// calculate the number of bytes of data
size = m_sizeVertex*m_numVertices;

HRESULT hr = d3ddev->CreateVertexBuffer(size,
                        D3DUSAGE_DYNAMIC,
                        0,   // DON'T pass the FVF code we using vertex decleration
                        D3DPOOL_DEFAULT,
                        &m_buffer,
                        NULL);

I add data to my buffer in this way:

writeData(unsigned int offset, unsigned int length, void* data)
{                         
     // store the length of actual data length
     m_length = length;
      
     // determine required buffer size in bytes
     unsigned int size = length*m_sizeVertex;
      
     // lock v_buffer and load the vertices into it
     void* vertices = 0;
     HRESULT hr = m_buffer->Lock(offset, size, &vertices, D3DLOCK_DISCARD);
     if (FAILED(hr)){
           throw exception("Could not lock buffer!");
     }

     memcpy(vertices, data, size);

    hr = m_buffer->Unlock();
    if (FAILED(hr)){
           throw exception("Could not unlock buffer!");
    }
}

Everything is working fine until I try to reuse the buffer, which has rendered other data before. In that case I got fragments of the old render data as garbage between new render data. If I everytime create a new buffer on data switch anything is working fine. It looks to me that the discard flag is ignored.

Thanks for any help.

9 Replies

Please log in or register to post a reply.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Jan 06, 2013 at 17:28

Are your writes are contiguous? I.e. when you call writeData you pass in an offset and length, so I guess you are only overwriting a portion of the data each time; is it possible you’re leaving unwritten space between sections of data?

350d397466e93a8ca8dac72b068fc5fb
0
Brac 101 Jan 06, 2013 at 17:32

@Reedbeta

Are your writes are contiguous? I.e. when you call writeData you pass in an offset and length, so I guess you are only overwriting a portion of the data each time; is it possible you’re leaving unwritten space between sections of data?

That was also my first thought.
When you want to discard the buffer contents, make sure you discard it completely.
Passing incoherent offset/length is most likely the problem here.

07b9e9e8483468e4a0e1bac1843e6e74
0
Snoob 105 Jan 06, 2013 at 18:38

I pass first 6 Vertices, at 2nd also six (changed texture) and finally 12 Vertices using same texture as data from first pass. The issue occurs rendering the final content. Each pass has zero offset. I thought the discard flag ensures that the content of the buffer is discard completely.

350d397466e93a8ca8dac72b068fc5fb
0
Brac 101 Jan 06, 2013 at 19:18

@Snoob

I pass first 6 Vertices, at 2nd also six (changed texture) and finally 12 Vertices using same texture as data from first pass. The issue occurs rendering the final content. Each pass has zero offset. I thought the discard flag ensures that the content of the buffer is discard completely.

You’re right of course… Discard flag will drop the complete buffer. Sorry for the confusion.
I’ve got a feeling this thread contains your answer (JeffFs answer in particular):

http://www.gamedev.net/topic/212599-question-about-the-idirect3dvertexbuffer9lockmethod/

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Jan 06, 2013 at 20:53

@Snoob

I thought the discard flag ensures that the content of the buffer is discard completely.

That’s not really what it does. The discard flag just tells D3D that you don’t depend on the previous contents of the buffer still being there, and therefore allows the driver to make certain performance optimizations. It does NOT guarantee that the buffer is zero-filled or anything like that.

In fact, the driver is probably internally maintaining 2 or more instances of the buffer, so that the GPU can read from one while your application is filling another. In this case you may find that when you lock the buffer, it contains the vertices you rendered 2 or 3 frames ago.

By the way, to render multiple times from the same vertex buffer in the same frame, it may be better (faster) to make the buffer longer and use successive sections of it rather than re-using the same area (the beginning). For instance, your first draw would use vertices 0-5, the second 6-11, and the third 12-23. If you do this you should use D3DLOCK_DISCARD the first time you lock the buffer in each frame, and D3DLOCK_NOOVERWRITE each subsequent time until the next frame. This lets the driver know you’re writing to disjoint sections of the buffer, so it can avoid doing extra memory allocations. For more information see this MSDN article.

07b9e9e8483468e4a0e1bac1843e6e74
0
Snoob 105 Jan 06, 2013 at 21:47

Thanks for your detailed informations. If I can’t follow your advise with the sections, what is the better way I should go? Should I zero fill the entire buffer before each write call or should I recreate a new one?

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 167 Jan 06, 2013 at 21:51

Zero-filling would certainly be more efficient. However, you shouldn’t need to zero-fill it at all assuming you draw only parts you have written to. I still suspect some issue with your offets and lengths being incorrect. One thing that bites people sometimes is getting confused between length in vertices and length in bytes, so you might want to double-check that your length is in the correct units at each D3D9 call.

07b9e9e8483468e4a0e1bac1843e6e74
0
Snoob 105 Jan 06, 2013 at 22:30

I’ve checked my values multiple times, they should be correct (I use the same values as base on GL buffers where all is perfect). The offset is allways zero and I use length in bytes… I will try out the zero filling.

07b9e9e8483468e4a0e1bac1843e6e74
0
Snoob 105 Jan 07, 2013 at 20:42

I checked my render data again, anything is correct. I also tried to lock the entire buffer with discard flag, but this solves not the problem.
Finally i’ve implemented a zero fill of the entire buffer before writing the data to the buffer, now it works. Thanks for your support.