dynamic data in vertex buffer

Started by
8 comments, last by dave 18 years, 1 month ago
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.
Advertisement
You can write a wrapper for it, i did this once, proved very useful.

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


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.


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.
--------------------------Most of what I know came from Frank D. Luna's DirectX books
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.


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


No problems :D

This topic is closed to new replies.

Advertisement