D3D Hardware Instance
This demo shows how D3D hardware instance works. HW Instance means call DrawIndexedPrimitive on time, but with a group of geometry rendered. Those geometries could be positioned in different place and different appearance. With this technology, you could gain a lots of performance improved than draw those group of geometry with a loop. HW Instance will split those geometry into two part, one part is shared by all geometries and the other part is specified one that hold all different properties for each. Usually, those shared part will be created on the vertex stream 0, and the other part called instance data will be placed on the vertex stream 1. So the vertex declaration will be look like this:
static D3DVERTEXELEMENT9 _2_tex_normal_decl[] = { // offsets in bytes {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, {0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, {1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1}, // translation {1, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2}, // color D3DDECL_END() };
Of course, two vertex buffer will be created. And they will be filled with corresponding data. At the rendering time, vertex buffers will be set up with frequency, just like following:
Device->SetStreamSource(0, mVetexBuffer, 0, mVertexSize); Device->SetStreamSourceFreq( 0, D3DSTREAMSOURCE_INDEXEDDATA | mNumInstance ); Device->SetStreamSource( 1, mInstanceVB, 0, mInstanceVSize ); Device->SetStreamSourceFreq( 1, D3DSTREAMSOURCE_INSTANCEDATA | 1ul ) ; Device->SetIndices(mIndexBuffer); Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, mNumVertices, 0, mPrimitiveCount);
Very similar with the Non HW instance rendering one. One thing need to mention here is that HW Instance need vs 3.0 shader mode support. There is no hardware device acceleration work with DrawPrimitve, only DrawIndexedPrimitive could do that.
Something More
In addition to HW Instance technology, here are something that I need to write down:
1) D3D Vertex layout or FVF. Most of time, we will customize our vertex layout struct. For example:
struct MyVertex { float3 _Pos; float3 _Normal; float2 _UV; };
// Flexible vertex format bits // #define D3DFVF_RESERVED0 0×001 #define D3DFVF_POSITION_MASK 0x400E #define D3DFVF_XYZ 0×002 #define D3DFVF_XYZRHW 0×004 #define D3DFVF_XYZB1 0×006 #define D3DFVF_XYZB2 0×008 #define D3DFVF_XYZB3 0x00a #define D3DFVF_XYZB4 0x00c #define D3DFVF_XYZB5 0x00e #define D3DFVF_XYZW 0×4002 #define D3DFVF_NORMAL 0×010 #define D3DFVF_PSIZE 0×020 #define D3DFVF_DIFFUSE 0×040 #define D3DFVF_SPECULAR 0×080 #define D3DFVF_TEXCOUNT_MASK 0xf00 #define D3DFVF_TEXCOUNT_SHIFT 8 #define D3DFVF_TEX0 0×000 #define D3DFVF_TEX1 0×100 #define D3DFVF_TEX2 0×200
#define D3DFVF_TEX0 0×000
ZERO 0×000 will not give any effect for an OR operation. Do not be confused with TEXCOORD0 that appeared in the shader source code. They are two different things.
3) Try to use the same version for Vertex shader and Pixel shader. If you want to use ps_3_0 for pxiel shader, then you need to set vs_3_0 in used. I tried to use vs_3_0 for vertex shader and ps_2_0 for the pixel shader, but it did not work at all.
4) To make the HW Instance work correctly, you should at least write some code to make those instance vertex elements are used in the vertex shader or pixel shader. Otherwise, there will be nothing display on the screen. No instance data need to deal with, so no geometry need to display. It make sense.
The full source code could be download from here.