Jump to content
  • Advertisement
Sign in to follow this  
candidate

OpenGL dynamic data in vertex buffer

This topic is 4494 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi. I am translating my code from OpenGL into DirectX. In OpenGL I dont need to know how many primitives will be known and I call glBegin(PRIMITIVE), glEnd() as many times as I want. Is this possible in DirectX? As far as I learned I first need to create a Vertex Buffer of fixed size and add the primitive data into it. Is there a way to have a dynamic sized Vertex Buffer? Thank you.

Share this post


Link to post
Share on other sites
Advertisement
You can write a wrapper for it, i did this once, proved very useful.

Dave

Share this post


Link to post
Share on other sites
Well, there are a few articles floating around about dynamic vertex buffers. If you want to get things working in a quick and dirty fashion, you could use DrawPrimitiveUP(). Your performance will not be very good at all unless you are drawing very few triangles. The best way is to go with a dynamic vertex buffer. If you go here, about 4/5ths of the way down the page it talks a bit about what you are looking at.

As for multiple BeginScene() and EndScene() calls, I don't think that is a good idea. From what I remember hearing (which may be incorrect, though), you should really only have one BeginScene()/EndScene() pair. That shouldn't be much of a problem at all - just place them around your rendering loop rather than in your rendering loop.

Share this post


Link to post
Share on other sites
What kind of wrapper do you mean? Could you please explain some more or send some example code? Thank you.

Quote:
Original post by Dave
You can write a wrapper for it, i did this once, proved very useful.

Dave


Share this post


Link to post
Share on other sites
I cannot use DrawPrimitiveUP because my primitive data is not stored. Because what I am trying to do is get the primitive data from another program and push it directly into the graphics memory. Then when I need to rotate the scene for example I just call that graphics memory (vertex buffer) so that it is fast.

I also checked the FAQ about dynamic vertex buffer. It is saying that the vertex buffer size cannot be changed. For me it means that I need to connect to my another program to get the primitive data when I exceed the size of the buffer. That connection is very expensive for me. So I want to avoid it.

Is there any other suggestion please? Thank you.

Quote:
Original post by Moe
Well, there are a few articles floating around about dynamic vertex buffers. If you want to get things working in a quick and dirty fashion, you could use DrawPrimitiveUP(). Your performance will not be very good at all unless you are drawing very few triangles. The best way is to go with a dynamic vertex buffer. If you go here, about 4/5ths of the way down the page it talks a bit about what you are looking at.

As for multiple BeginScene() and EndScene() calls, I don't think that is a good idea. From what I remember hearing (which may be incorrect, though), you should really only have one BeginScene()/EndScene() pair. That shouldn't be much of a problem at all - just place them around your rendering loop rather than in your rendering loop.


Share this post


Link to post
Share on other sites
You need to get a good book on DX. I recommend the book by Frank Luna. However, he has a new one coming out soon that is a lot better than the first. However, the first one is really good and will answer questions like this.

Basically, you have various options:

1) Create just a vertex buffer and do a DrawPrimitive;

2) Create a vertex and index buffer and do a DrawIndexedPrimitive;

3) Create a mesh, update the vertex and index buffers with your data, and do a ID3DXMesh->DrawSubset().

4) Put the vertex data into your own array and call DrawPrimitiveUp. You could actually use a STL vector for this, which would enable it to be of variable length. This method is the slowest though, since the vertex data is in the system memory, whereas DX buffers can be dynamic or managed.

Share this post


Link to post
Share on other sites
I already have some books including the one you mentioned. thanks for that suggestion.


1.) I already have the vertex buffer and call to DrawPrimitive. When I rotate the scene I dont want to recreate vertexbuffer but call the only once created one with DrawPrimitive that's why DirectX requires me to set total number of vertices drawn (which I do not know/want to calculate). So it does not work for me.

2.) same as 1

3.) same as 1

4.) I do not have the primitive data stored. So it does not work for me.

Thank you.

Quote:
Original post by DXnut
You need to get a good book on DX. I recommend the book by Frank Luna. However, he has a new one coming out soon that is a lot better than the first. However, the first one is really good and will answer questions like this.

Basically, you have various options:

1) Create just a vertex buffer and do a DrawPrimitive;

2) Create a vertex and index buffer and do a DrawIndexedPrimitive;

3) Create a mesh, update the vertex and index buffers with your data, and do a ID3DXMesh->DrawSubset().

4) Put the vertex data into your own array and call DrawPrimitiveUp. You could actually use a STL vector for this, which would enable it to be of variable length. This method is the slowest though, since the vertex data is in the system memory, whereas DX buffers can be dynamic or managed.


Share this post


Link to post
Share on other sites
By a wrapper i mean something like this...


#ifndef _DYNAMIC_VERTEX_BUFFER_H_
#define _DYNAMIC_VERTEX_BUFFER_H_

#include <vector>
#include <d3dx9.h>

namespace
{
const unsigned int grow_default = 1000;
const unsigned int size_default = 1000;
}

struct Dynamic_Vertexbuffer_Props
{
LPDIRECT3DDEVICE9 device;
DWORD fvf;
D3DPOOL pool;
DWORD usage;
};

template <class T>
class DynamicVertexBuffer
{
public:
DynamicVertexBuffer( unsigned int grow, unsigned int capacity, const Dynamic_Vertexbuffer_Props* props );
~DynamicVertexBuffer();

void Add( T& vertex );
void Add( T vertices[], unsigned int size );
void Add( const std::vector<T>& vec );
void Add( const DynamicVertexBuffer<T>& dvb );

void Extract ( unsigned int first, unsigned int last, std::vector<T>& out );
void Clear();
unsigned int Size() const;
unsigned int Capacity() const;
void Grow();
void Reset();
void Reset( unsigned int grow, unsigned int capacity, const Dynamic_Vertexbuffer_Props* props );

IDirect3DVertexBuffer9* operator&()
{
if ( m_vertexBuffer )
return m_vertexBuffer;
else
return NULL;
}
const IDirect3DVertexBuffer9& operator*()
{
if ( m_vertexBuffer )
return *m_vertexBuffer;
}

inline void operator+=( T& vertex ) { Add( vertex ); };
inline void operator+=( const std::vector<T>& vec ) { Add( vec ); };
inline void operator+=( const DynamicVertexBuffer& dib ) { Add( dib ); };

const LPDIRECT3DVERTEXBUFFER9& Const_Ref() { return m_vertexBuffer; };

private:
Dynamic_Vertexbuffer_Props m_props;
LPDIRECT3DVERTEXBUFFER9 m_vertexBuffer;
unsigned int m_size;
unsigned int m_capacity;
bool m_validProps;
bool m_made;
unsigned int m_grow;

void Create(unsigned int size);
bool ValidateProperties(const Dynamic_Vertexbuffer_Props* props);
};

template<class T>
DynamicVertexBuffer<T>::DynamicVertexBuffer( unsigned int grow, unsigned int capacity, const Dynamic_Vertexbuffer_Props* props )
: m_capacity(0),
m_size(0),
m_made(false),
m_validProps(false),
m_vertexBuffer(NULL)
{
Reset( grow, capacity, props );
}
template<class T>
DynamicVertexBuffer<T>::~DynamicVertexBuffer()
{
Reset();
}

template<class T>
void DynamicVertexBuffer<T>::Add( T& vertex )
{
if ( m_made == true )
{
if ( 1 <= (m_capacity - m_size ) )
{
void* pDest;

m_vertexBuffer->Lock( m_size*sizeof(T), sizeof(T), &pDest, 0);

memcpy( pDest, &vertex, sizeof( T ) );

m_vertexBuffer->Unlock();

#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Single vertex added\n");
#endif

m_size++;
}
else
{
#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Grow needed for single vertex\n");
#endif
Grow();
Add( vertex );
}
}
}
template<class T>
void DynamicVertexBuffer<T>::Add( T vertices[], unsigned int size )
{
if ( m_made == true )
{
if ( size <= (m_capacity - m_size ) )
{
void* pDest;
m_vertexBuffer->Lock( m_size * sizeof(T), size *sizeof( T ), &pDest, 0);
memcpy( pDest, &vertices[0], size * sizeof( T ) );
m_vertexBuffer->Unlock();

#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Vertex array added\n");
#endif

m_size += size;
}
else
{
#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Grow needed for vertex array\n");
#endif
Grow();
Add(vertices, size);
}
}
}
template<class T>
void DynamicVertexBuffer<T>::Add( const std::vector<T>& vec )
{
if ( m_made == true )
{
if ( vec.size() <= (m_capacity - m_size ) )
{
void* pDest;
void* pMCRet = NULL;

m_vertexBuffer->Lock( m_size * sizeof(T), (unsigned int) vec.size() * sizeof(T), &pDest, 0);

pMCRet = memcpy( pDest, &vec[0], vec.size() * sizeof( T ) );

if ( pMCRet == NULL )
{
MessageBox(NULL, "pMCRET","", MB_OK );
}


m_vertexBuffer->Unlock();

#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Vertex std::vector added\n");
#endif

m_size += (unsigned int) vec.size();
}
else
{
#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Grow needed for vertex std::vector\n");
#endif
Grow();
Add( vec );
}
}
}
template<class T>
void DynamicVertexBuffer<T>::Add( const DynamicVertexBuffer<T>& dvb )
{
std::vector<T> tempVertices(dvb.Size());
Extract(0, dvb.Size(), tempVertices);
Add(tempVertices);
}
template<class T>
unsigned int DynamicVertexBuffer<T>::Size() const
{
return m_size;
}
template<class T>
unsigned int DynamicVertexBuffer<T>::Capacity() const
{
return m_capacity;
}
template<class T>
void DynamicVertexBuffer<T>::Grow()
{
if ( m_made == true )
{
Create( m_capacity + m_grow );
}
}
template<class T>
void DynamicVertexBuffer<T>::Reset()
{
m_made = false;
m_size = 0;
m_capacity = 0;
m_validProps = false;

if ( m_vertexBuffer != NULL )
m_vertexBuffer->Release();

#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) DynamicVertexBuffer Reset\n");
#endif
}
template<class T>
void DynamicVertexBuffer<T>::Reset( unsigned int grow, unsigned int capacity, const Dynamic_Vertexbuffer_Props* props )
{
m_made = false;
m_size = 0;
m_capacity = 0;
m_validProps = false;

if ( m_vertexBuffer != NULL )
m_vertexBuffer->Release();

#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) DynamicVertexBuffer Reset\n");
#endif

if ( ValidateProperties( props ) )
{

#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Properties valid\n");
#endif

this->m_props = ( *props );
if ( grow == 0 )
{
m_grow = grow_default;
#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Default grow used\n");
#endif
}
else
{
m_grow = grow;
#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Custom grow used\n");
#endif
}
if ( capacity != 0 )
{
#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Custom capacity used\n");
#endif
Create( capacity );
}
else
{
#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Default capacity used\n");
#endif
Create( size_default );
}
}
}

template<class T>
void DynamicVertexBuffer<T>::Clear()
{
m_size = 0;
#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) DynamicVertexBuffer Clear\n");
#endif
}
template<class T>
void DynamicVertexBuffer<T>::Create( unsigned int capacity )
{
if ( m_validProps == true )
{
if ( m_vertexBuffer != NULL )
{
void* pSource;
void* pDest;
// create a vector to hold the verts
std::vector<T> tempVerts(m_size);
// HERE: Only backup of vertices if m_size > 0;
if ( m_size > 0 )
{
// Lock the current vertex buffer, copy, unlock
m_vertexBuffer->Lock( 0, m_size, &pSource, 0);
memcpy( &tempVerts[0], pSource, m_size * sizeof(T) );
m_vertexBuffer->Unlock();

#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Vertices backed up before grow\n");
#endif
} // BACKUP MADE

// release the old buffer
m_vertexBuffer->Release();
// create a new one
m_props.device->CreateVertexBuffer( capacity * sizeof(T),
m_props.usage,
m_props.fvf,
m_props.pool,
&m_vertexBuffer,
NULL);
#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Larger vertex buffer created\n");
#endif

// set the new size
m_capacity = capacity;
// HERE: Restore the vertices
if ( m_size > 0 )
{
// Lock the current vertex buffer, copy, unlock
m_vertexBuffer->Lock( 0, m_size, &pDest, 0);
memcpy( pDest, &tempVerts[0], m_size * sizeof(T) );
m_vertexBuffer->Unlock();

#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Vertices restored after grow\n");
#endif
}
}
else if ( m_vertexBuffer == NULL )
{
m_props.device->CreateVertexBuffer( (capacity) * sizeof(T),
m_props.usage,
m_props.fvf,
m_props.pool,
&m_vertexBuffer,
NULL);

#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (INFO) Vertex buffer created\n");
#endif

m_capacity = capacity;
m_made = true;
}
}
}
template<class T>
bool DynamicVertexBuffer<T>::ValidateProperties(const Dynamic_Vertexbuffer_Props* props)
{
bool valid = true;
if ( props->device == NULL )
{
valid = false;

#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (ERROR) Device invalid!\n");
#endif
}
if ( props->fvf == NULL )
{
// This is now acceptable for elements
//valid = false;

#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (ERROR) FVF invalid!\n");
#endif
}
if ( ( props->pool < 0 ) || ( props->pool > 3 ) )
{
valid = false;

#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (ERROR) Pool invalid!\n");
#endif
}
if ( props->usage < 0 )
{
valid = false;

#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (ERROR) Usage invalid!\n");
#endif
}
if ( valid == true )
{
m_validProps = true;
}
return valid;
}
template<class T>
void DynamicVertexBuffer<T>::Extract ( unsigned int first, unsigned int last, std::vector<T>& out )
{
// check to see if the buffer is writeonly, if so dont allow this and throw a warning to debug out
if ( !(this->m_props.usage & D3DUSAGE_WRITEONLY) )
{
if ( out.capacity() >= m_size )
{
if ( ( last > first ) && (last <= m_size) )
{
void* pSource;

m_vertexBuffer->Lock( first * sizeof( T ), ( (last-first) * sizeof( T ) ), &pSource, 0);

memcpy( &out[0], pSource, (last-first) * sizeof( T ) );

m_vertexBuffer->Unlock();

#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (ERROR) Extract call - successful\n");
#endif
}
}
else
{
#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (ERROR) Extract call - target std::vector bad size\n");
#endif
}
}
else
{
#ifdef DYNAMICVB_DEBUG
OutputDebugString("DynamicVertexBuffer: (ERROR) Extract call - Write only buffer specified\n");
#endif
}
}

#endif



This was written ages ago, bare that in mind.

Dave

Share this post


Link to post
Share on other sites
Thanks a lot for the code Dave. Actually I was also using the same technique but not growing the vertex buffer thinking that it would be slow. But it looks like that is the only solution for me. I will try it.
Quote:
Original post by Dave
By a wrapper i mean something like this...

*** Source Snippet Removed ***

This was written ages ago, bare that in mind.

Dave


Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!