# Calling DrawPrimitive Heaps

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

## Recommended Posts

Hi all,

In my voxel engine similar to Minecraft, I draw each side of each block separately, like this:

for(unsigned int i = 0; i < BLOCKS_PER_CHUNK; i++)
{
if(blocks[i].type == BLOCKTYPE_AIR)
continue;

if(blocks[i].BackFaceVisible)
{
g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, (i * VERTICES_PER_BLOCK) + 4, 2);
}
if(blocks[i].FrontFaceVisible)
{
g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, (i * VERTICES_PER_BLOCK), 2);
}
if(blocks[i].LeftFaceVisible)
{
g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, (i * VERTICES_PER_BLOCK) + 8, 2);
}
if(blocks[i].RightFaceVisible)
{
g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, (i * VERTICES_PER_BLOCK) + 12, 2);
}
if(blocks[i].TopFaceVisible)
{
g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, (i * VERTICES_PER_BLOCK) + 16, 2);
}
if(blocks[i].BottomFaceVisible)
{
g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, (i * VERTICES_PER_BLOCK) + 20, 2);
}
}


Is it a bad idea to call DrawPrimitive so much like this? Should I use an index buffer and just make one call to DrawIndexedPrimitive?

Edited by BMW

##### Share on other sites

Yes, it's a very bad idea.

You should render the whole scene with the minimum possible calls to DrawPrimitive. That is, render various cubes at once if possible otherwise performance will degrade very fast.

Reducing DrawPrimitive calls by grouping geometry/materials is called batching. You should find lots of info by google for "geometry batching" and similar terms.

##### Share on other sites

Ok, I will see if I can render an entire chunk using one DrawPrimitive() call. That should help.

##### Share on other sites

You might be much happier doing a DIP call for each block type, so you don't have to mess up to much with shader parameters.

Doing a whole chunk per-DIP is excessive in my opinion and the issues involved in managing the multiple textures have to be carefully considered.

edit: oh, I see you're using a texture atlas from the other thread. No problem then, go ahead!

Edited by Krohm

##### Share on other sites

You might be much happier doing a DIP call for each block type, so you don't have to mess up to much with shader parameters.

Doing a whole chunk per-DIP is excessive in my opinion and the issues involved in managing the multiple textures have to be carefully considered.

edit: oh, I see you're using a texture atlas from the other thread. No problem then, go ahead!

WOW WOWOWOWOWOWOWOWOWOWOWOW

Using the inferior method as discussed earlier (heaps of draw primitive calls) = 62FPS.

Using new method - 1 DIP call per chunk = 320FPS. THATS IT, THREE HUNDRED AND TWENTY FRAMES PER SECOND. (Considering my laptop has integrated graphics, NOT TOO FOUL!!!!)

THIS IS THE BEST DAY OF MY LIFE.

THANK YOU EVERYONE.

I love game development.

EDIT: Is updating the entire index buffer for the chunk every time a block changes a good idea? It seems to run ok.

This is how I update index buffer:

void Chunk::UpdateIndices()
{
void* IB = NULL;

unsigned int* pIBEntry = NULL;

PrimitiveCount = 0;

if(g_pIB->Lock(0, BLOCKS_PER_CHUNK * INDICES_PER_BLOCK * 4, &IB, D3DLOCK_DISCARD) != D3D_OK)
return;

pIBEntry = (unsigned int*)IB;

for(unsigned int i = 0; i < BLOCKS_PER_CHUNK; i++)
{
if(blocks[i].type == BLOCKTYPE_AIR)
continue;

if(blocks[i].FrontFaceVisible)
{
*pIBEntry = i * VERTICES_PER_BLOCK;
*(pIBEntry + 1) = i * VERTICES_PER_BLOCK + 1;
*(pIBEntry + 2) = i * VERTICES_PER_BLOCK + 2;
*(pIBEntry + 3) = i * VERTICES_PER_BLOCK + 1;
*(pIBEntry + 4) = i * VERTICES_PER_BLOCK + 3;
*(pIBEntry + 5) = i * VERTICES_PER_BLOCK + 2;
pIBEntry += 6;
PrimitiveCount += 2;
}
if(blocks[i].BackFaceVisible)
{
*pIBEntry = i * VERTICES_PER_BLOCK + 4;
*(pIBEntry + 1) = i * VERTICES_PER_BLOCK + 4 + 1;
*(pIBEntry + 2) = i * VERTICES_PER_BLOCK + 4 + 2;
*(pIBEntry + 3) = i * VERTICES_PER_BLOCK + 4 + 1;
*(pIBEntry + 4) = i * VERTICES_PER_BLOCK + 4 + 3;
*(pIBEntry + 5) = i * VERTICES_PER_BLOCK + 4 + 2;
pIBEntry += 6;
PrimitiveCount += 2;
}
if(blocks[i].LeftFaceVisible)
{
*pIBEntry = i * VERTICES_PER_BLOCK + 8;
*(pIBEntry + 1) = i * VERTICES_PER_BLOCK + 8 + 1;
*(pIBEntry + 2) = i * VERTICES_PER_BLOCK + 8 + 2;
*(pIBEntry + 3) = i * VERTICES_PER_BLOCK + 8 + 1;
*(pIBEntry + 4) = i * VERTICES_PER_BLOCK + 8 + 3;
*(pIBEntry + 5) = i * VERTICES_PER_BLOCK + 8 + 2;
pIBEntry += 6;
PrimitiveCount += 2;
}
if(blocks[i].RightFaceVisible)
{
*pIBEntry = i * VERTICES_PER_BLOCK + 12;
*(pIBEntry + 1) = i * VERTICES_PER_BLOCK + 12 + 1;
*(pIBEntry + 2) = i * VERTICES_PER_BLOCK + 12 + 2;
*(pIBEntry + 3) = i * VERTICES_PER_BLOCK + 12 + 1;
*(pIBEntry + 4) = i * VERTICES_PER_BLOCK + 12 + 3;
*(pIBEntry + 5) = i * VERTICES_PER_BLOCK + 12 + 2;
pIBEntry += 6;
PrimitiveCount += 2;
}
if(blocks[i].TopFaceVisible)
{
*pIBEntry = i * VERTICES_PER_BLOCK + 16;
*(pIBEntry + 1) = i * VERTICES_PER_BLOCK + 16 + 1;
*(pIBEntry + 2) = i * VERTICES_PER_BLOCK + 16 + 2;
*(pIBEntry + 3) = i * VERTICES_PER_BLOCK + 16 + 1;
*(pIBEntry + 4) = i * VERTICES_PER_BLOCK + 16 + 3;
*(pIBEntry + 5) = i * VERTICES_PER_BLOCK + 16 + 2;
pIBEntry += 6;
PrimitiveCount += 2;
}
if(blocks[i].BottomFaceVisible)
{
*pIBEntry = i * VERTICES_PER_BLOCK + 20;
*(pIBEntry + 1) = i * VERTICES_PER_BLOCK + 20 + 1;
*(pIBEntry + 2) = i * VERTICES_PER_BLOCK + 20 + 2;
*(pIBEntry + 3) = i * VERTICES_PER_BLOCK + 20 + 1;
*(pIBEntry + 4) = i * VERTICES_PER_BLOCK + 20 + 3;
*(pIBEntry + 5) = i * VERTICES_PER_BLOCK + 20 + 2;
pIBEntry += 6;
PrimitiveCount += 2;
}
}

g_pIB->Unlock();
}

Edited by BMW