DrawIndexedPrimitiveUP
-
RandomTiger
- Posts: 1
- Joined: Sat Nov 19, 2005 5:04 pm
DrawIndexedPrimitiveUP
Hi there, I discovered Irrlicht a few days ago and at first it looked ideal for my purposes. However I have had to abandon my plans to use it before even writing a line of code because it looks like all DX rendering (correct me if Im wrong) is done using DrawIndexedPrimitiveUP which the DX docs and practical experience show is a lot slower than using proper buffers.
-
dhenton9000
- Posts: 395
- Joined: Fri Apr 08, 2005 8:46 pm
speed isn't everything. Hitting your design specs is. I just slogged through the Irrlicht internals and the only thing I can guess is that IndexedPrimitiveUP is used because it makes the code for running DX fit the same pipeline as OpenGL
Theres a major requirement in Irrlicht to support OPENGL and software rendering.
As they say, get it fast, get it right, or get it cheap, select 1 out of 3.
Theres a major requirement in Irrlicht to support OPENGL and software rendering.
As they say, get it fast, get it right, or get it cheap, select 1 out of 3.
-
Guest
-
Guest
-
Grey Lantern
- Posts: 34
- Joined: Sat Jul 30, 2005 9:45 am
- Contact:
-
Guest
here is some source:
u32 CD3D9Driver::getFVFSize(video::E_VERTEX_TYPE vType)
{
int leng=0;
if (vType==video::EVT_STANDARD) leng=sizeof(video::S3DVertex);
if (vType==video::EVT_2TCOORDS) leng=sizeof(video::S3DVertex2TCoords);
if (vType==video::EVT_TANGENTS) leng=sizeof(video::S3DVertexTangents);
return leng;
}
bool CD3D9Driver::createHardwareBuffer(scene::IMeshBuffer* buffer)
{
if (((bool)buffer->hwBuffer.indexB)^((bool)buffer->hwBuffer.vertexB)) return false;
HRESULT hr;
int leng=this->getFVFSize(buffer->getVertexType());
leng*=buffer->getVertexCount();
if (leng==0) return false;
if (!buffer->hwBuffer.indexB) {
u32 fv=getFVFID(buffer->getVertexType());
IDirect3DVertexBuffer9* theNewVertexBuffer;
hr=pID3DDevice->CreateVertexBuffer(leng,
D3DUSAGE_WRITEONLY,
fv,
D3DPOOL_MANAGED,
&theNewVertexBuffer,
0);
buffer->hwBuffer.vertexB=theNewVertexBuffer;
int indxcnt=buffer->getIndexCount();
IDirect3DIndexBuffer9* theNewIndexBuffer;
hr= pID3DDevice->CreateIndexBuffer(indxcnt*2,
D3DUSAGE_WRITEONLY,D3DFMT_INDEX16,D3DPOOL_MANAGED,&theNewIndexBuffer, 0);
buffer->hwBuffer.indexB=theNewIndexBuffer;
}
IDirect3DIndexBuffer9* myIndexBuffer=(IDirect3DIndexBuffer9*)buffer->hwBuffer.indexB;
IDirect3DVertexBuffer9* myVertexBuffer=(IDirect3DVertexBuffer9*)buffer->hwBuffer.vertexB;
void* myIndices;
u16* myIndicesu16;
hr=myIndexBuffer->Lock(0,0,&myIndices,0);
myIndicesu16=(u16*)myIndices;
u16* indices=buffer->getIndices();
int extL=buffer->getIndexCount();
for (int cntr=0;cntr<extL;cntr++) {
myIndicesu16[cntr]=indices[cntr];
}
hr=myIndexBuffer->Unlock();
void* bufferVertices;
hr=myVertexBuffer->Lock(0,0,&bufferVertices,0);
int cl=leng/4;
u32* bufferu32=(u32*)bufferVertices;
u32* src=(u32*)buffer->getVertices();
for (s32 count=0;count<cl;count++)
{
bufferu32[count]=src[count];
}
hr=myVertexBuffer->Unlock();
return true;
}
bool CD3D9Driver::deleteHardwareBuffer(scene::IMeshBuffer* buffer)
{
if (!buffer) return false;
if (buffer->hwBuffer.vertexB) {
rc=((IDirect3DVertexBuffer9*)buffer->hwBuffer.vertexB)->Release();
}
if (buffer->hwBuffer.indexB) {
rc=((IDirect3DIndexBuffer9*)buffer->hwBuffer.indexB)->Release();
}
return true;
}
void CD3D9Driver::drawIndexedTriangleListHw(void* indexP,void* vertexP,int indexC,int vertexC,video::E_VERTEX_TYPE vt)
{
setVertexShader(vt);
if (setRenderStates3DMode())
{
PrimitivesDrawn += indexC/3;
HRESULT hr=pID3DDevice->SetIndices((IDirect3DIndexBuffer9*)indexP);
hr=pID3DDevice->SetStreamSource(0,(IDirect3DVertexBuffer9*)vertexP,
0,getFVFSize(vt));
hr=pID3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
0,
0,
vertexC,
0,
indexC/3);
}
}
#####IMESHBUFFER.H#####
struct hwBufferData {
void* vertexB;
void* indexB; //It does not include the type of renderer that created the hardware buffer, that must be added if you plan to use multiple renderers
};
hwBufferData hwBuffer;
#################
### IN THE CONSTRUCTOR OF SMESHBUFFER.H SMESHBUFFERLIGHTMAP.H SMESHBUFFERTANGENT.H####
hwBuffer.indexB=0;
hwBuffer.vertexB=0;
void CNullDriver::drawMeshBuffer(scene::IMeshBuffer* mb)
{
if (!mb)
return;
if ((mb->hwBuffer.indexB!=0)&(mb->hwBuffer.vertexB!=0)) {
this->drawIndexedTriangleListHw(mb->hwBuffer.indexB,mb->hwBuffer.vertexB,mb->getIndexCount(),mb->getVertexCount(),mb->getVertexType());
return;
}
.......................
Then you've got to update the includes of CD3D9Driver with the new functions. Update IVideoDriver.h with createHardwareBuffer and deleteHardwareBuffer if you like, as I did, so that if you want to extend that functions to other renderers you can do it easily. Of course the overloaded functions of other renderers will not do anything.
You must add some code to call ivideodriver::deleteHardwareBuffer when the mesh buffer is deleted, optimally this can be done in the destructors of meshbuffers or of smesh.h, but meshbuffers and smesh don't know the pointer of the videodriver that created the hardware buffers.
You can add that pointer, or call deleteHardwareBuffer from your game when you have got to destroy a mesh,but it is not very handy.
I've almost forgot to tell how to use this: call createHardwareBuffer for every NOT ANIMATED mesh buffer that you want to put in an hardware vertex buffer, and the engine will care about everything else.
If you modify the vertices data of a mesh buffer that has got the hardware buffer, the modifications will not apply until you call createMeshBuffer again, that function will not delete the buffer and create another one, but just lock the old one and upload the new vertices data.
But note that you cannot remove or add vertices in a buffer after the creation of hw vertex buffer.
I hope that this code will give you inspiration
u32 CD3D9Driver::getFVFSize(video::E_VERTEX_TYPE vType)
{
int leng=0;
if (vType==video::EVT_STANDARD) leng=sizeof(video::S3DVertex);
if (vType==video::EVT_2TCOORDS) leng=sizeof(video::S3DVertex2TCoords);
if (vType==video::EVT_TANGENTS) leng=sizeof(video::S3DVertexTangents);
return leng;
}
bool CD3D9Driver::createHardwareBuffer(scene::IMeshBuffer* buffer)
{
if (((bool)buffer->hwBuffer.indexB)^((bool)buffer->hwBuffer.vertexB)) return false;
HRESULT hr;
int leng=this->getFVFSize(buffer->getVertexType());
leng*=buffer->getVertexCount();
if (leng==0) return false;
if (!buffer->hwBuffer.indexB) {
u32 fv=getFVFID(buffer->getVertexType());
IDirect3DVertexBuffer9* theNewVertexBuffer;
hr=pID3DDevice->CreateVertexBuffer(leng,
D3DUSAGE_WRITEONLY,
fv,
D3DPOOL_MANAGED,
&theNewVertexBuffer,
0);
buffer->hwBuffer.vertexB=theNewVertexBuffer;
int indxcnt=buffer->getIndexCount();
IDirect3DIndexBuffer9* theNewIndexBuffer;
hr= pID3DDevice->CreateIndexBuffer(indxcnt*2,
D3DUSAGE_WRITEONLY,D3DFMT_INDEX16,D3DPOOL_MANAGED,&theNewIndexBuffer, 0);
buffer->hwBuffer.indexB=theNewIndexBuffer;
}
IDirect3DIndexBuffer9* myIndexBuffer=(IDirect3DIndexBuffer9*)buffer->hwBuffer.indexB;
IDirect3DVertexBuffer9* myVertexBuffer=(IDirect3DVertexBuffer9*)buffer->hwBuffer.vertexB;
void* myIndices;
u16* myIndicesu16;
hr=myIndexBuffer->Lock(0,0,&myIndices,0);
myIndicesu16=(u16*)myIndices;
u16* indices=buffer->getIndices();
int extL=buffer->getIndexCount();
for (int cntr=0;cntr<extL;cntr++) {
myIndicesu16[cntr]=indices[cntr];
}
hr=myIndexBuffer->Unlock();
void* bufferVertices;
hr=myVertexBuffer->Lock(0,0,&bufferVertices,0);
int cl=leng/4;
u32* bufferu32=(u32*)bufferVertices;
u32* src=(u32*)buffer->getVertices();
for (s32 count=0;count<cl;count++)
{
bufferu32[count]=src[count];
}
hr=myVertexBuffer->Unlock();
return true;
}
bool CD3D9Driver::deleteHardwareBuffer(scene::IMeshBuffer* buffer)
{
if (!buffer) return false;
if (buffer->hwBuffer.vertexB) {
rc=((IDirect3DVertexBuffer9*)buffer->hwBuffer.vertexB)->Release();
}
if (buffer->hwBuffer.indexB) {
rc=((IDirect3DIndexBuffer9*)buffer->hwBuffer.indexB)->Release();
}
return true;
}
void CD3D9Driver::drawIndexedTriangleListHw(void* indexP,void* vertexP,int indexC,int vertexC,video::E_VERTEX_TYPE vt)
{
setVertexShader(vt);
if (setRenderStates3DMode())
{
PrimitivesDrawn += indexC/3;
HRESULT hr=pID3DDevice->SetIndices((IDirect3DIndexBuffer9*)indexP);
hr=pID3DDevice->SetStreamSource(0,(IDirect3DVertexBuffer9*)vertexP,
0,getFVFSize(vt));
hr=pID3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
0,
0,
vertexC,
0,
indexC/3);
}
}
#####IMESHBUFFER.H#####
struct hwBufferData {
void* vertexB;
void* indexB; //It does not include the type of renderer that created the hardware buffer, that must be added if you plan to use multiple renderers
};
hwBufferData hwBuffer;
#################
### IN THE CONSTRUCTOR OF SMESHBUFFER.H SMESHBUFFERLIGHTMAP.H SMESHBUFFERTANGENT.H####
hwBuffer.indexB=0;
hwBuffer.vertexB=0;
void CNullDriver::drawMeshBuffer(scene::IMeshBuffer* mb)
{
if (!mb)
return;
if ((mb->hwBuffer.indexB!=0)&(mb->hwBuffer.vertexB!=0)) {
this->drawIndexedTriangleListHw(mb->hwBuffer.indexB,mb->hwBuffer.vertexB,mb->getIndexCount(),mb->getVertexCount(),mb->getVertexType());
return;
}
.......................
Then you've got to update the includes of CD3D9Driver with the new functions. Update IVideoDriver.h with createHardwareBuffer and deleteHardwareBuffer if you like, as I did, so that if you want to extend that functions to other renderers you can do it easily. Of course the overloaded functions of other renderers will not do anything.
You must add some code to call ivideodriver::deleteHardwareBuffer when the mesh buffer is deleted, optimally this can be done in the destructors of meshbuffers or of smesh.h, but meshbuffers and smesh don't know the pointer of the videodriver that created the hardware buffers.
You can add that pointer, or call deleteHardwareBuffer from your game when you have got to destroy a mesh,but it is not very handy.
I've almost forgot to tell how to use this: call createHardwareBuffer for every NOT ANIMATED mesh buffer that you want to put in an hardware vertex buffer, and the engine will care about everything else.
If you modify the vertices data of a mesh buffer that has got the hardware buffer, the modifications will not apply until you call createMeshBuffer again, that function will not delete the buffer and create another one, but just lock the old one and upload the new vertices data.
But note that you cannot remove or add vertices in a buffer after the creation of hw vertex buffer.
I hope that this code will give you inspiration
Hmm ...
Your code looks realy interesting.
So basicaly it is moving the verticles from ram to the video memory ? or what? what is the hwBuffer?
NOT ANIMATED means that the mesh will not have animation or that the node will not have animations (translations, rotations ... etc of scene node).
Somethink like this cand be applyed for bilboards? and more important for particle scene nodes to obtain an biger fps?
Meybe spintz will try this code because he already played with hardware mesh of opengl i think ..
Your code looks realy interesting.
So basicaly it is moving the verticles from ram to the video memory ? or what? what is the hwBuffer?
NOT ANIMATED means that the mesh will not have animation or that the node will not have animations (translations, rotations ... etc of scene node).
Somethink like this cand be applyed for bilboards? and more important for particle scene nodes to obtain an biger fps?
Meybe spintz will try this code because he already played with hardware mesh of opengl i think ..
-
Guest
with not animated i mean that the mesh cannot be animated, for example you cannot use this for md2 meshes, or X meshes with software skeletal animation. You can move,rotate and scale the node as usual.
The vertices are copied to video ram, but they remains in system memory too; I did think about using only hardware buffers but it needed too much modifications to Irrlicht.
I don't know much about billboards and particle scene nodes, but I think that it would be not useful: hardware vertex buffers show their strength when rendering big chunks of polygons, when rendering very small mesh buffers the direct3d call overhead will probably erase every speed up.
The vertices are copied to video ram, but they remains in system memory too; I did think about using only hardware buffers but it needed too much modifications to Irrlicht.
I don't know much about billboards and particle scene nodes, but I think that it would be not useful: hardware vertex buffers show their strength when rendering big chunks of polygons, when rendering very small mesh buffers the direct3d call overhead will probably erase every speed up.
-
Guest
Now.. how about a DX8 version of your code? 
Actually I have an old D3D engine I was working on before I found irrlicht and was using hardware buffers in that (without software backup) which meant you lost them on deviceloss/reset. I didn't read the long code post - but does yours work robustly like that? I.E recovers from alt/tab ok etc?
YOu probably have it covered - like I say - just woke up and can hardly see straight at the moment let alone read masses of code
Actually I have an old D3D engine I was working on before I found irrlicht and was using hardware buffers in that (without software backup) which meant you lost them on deviceloss/reset. I didn't read the long code post - but does yours work robustly like that? I.E recovers from alt/tab ok etc?
YOu probably have it covered - like I say - just woke up and can hardly see straight at the moment let alone read masses of code
-
Guest
-
Guest
-
Guest
did you mean DEFAULT?
I don't think that managed is slower (or maybe it is just a very little bit) because the buffers are stored in video memory like with default, when they are used.
And there are some extra advantages, for example you can lock the vertex/index buffer a lot of times within a frame, and direct3d will reupload the buffer to video memory just one time when it's needed for rendering.
The only drawback is that actually with Irrlicht you'll have two copies of the vertices data in system memory (the Irrlicht one and the direct3d one) and one copy in video memory, that's not optimal.
But I think that MANAGED saves quite a lot of work efficiently and easily.
I don't think that managed is slower (or maybe it is just a very little bit) because the buffers are stored in video memory like with default, when they are used.
And there are some extra advantages, for example you can lock the vertex/index buffer a lot of times within a frame, and direct3d will reupload the buffer to video memory just one time when it's needed for rendering.
The only drawback is that actually with Irrlicht you'll have two copies of the vertices data in system memory (the Irrlicht one and the direct3d one) and one copy in video memory, that's not optimal.
But I think that MANAGED saves quite a lot of work efficiently and easily.
-
Guest
Yeah - prob 
I am rust on it as I said. There were 3? pool types IIRC.. managed (which helps you out), pure software (safe as houses but slow) and the one that stored it only in VRAM and needed clearing when you lost the device.. which must be default then, but it was the "fastest" for vbuffers etc.
I really need to go and brush up on D3D it was over a year since I last did anything outside of irrlicht (though I have done some In-irrlicht D3D adjustments to the code).
anyway, I'll shut up now - your code obv works so well done!
I am rust on it as I said. There were 3? pool types IIRC.. managed (which helps you out), pure software (safe as houses but slow) and the one that stored it only in VRAM and needed clearing when you lost the device.. which must be default then, but it was the "fastest" for vbuffers etc.
I really need to go and brush up on D3D it was over a year since I last did anything outside of irrlicht (though I have done some In-irrlicht D3D adjustments to the code).
anyway, I'll shut up now - your code obv works so well done!