Skip to main content
gamedev.net
🔒 Locked

DrawIndexedPrimitive batching problem

Started by Dynaguy Sep 28, 2002 at 7:17 PM 3 replies 750+ views
Original Post
Dynaguy
Dynaguy
I'm been working on a particle system, using indexed primitives to draw each particle as a quad. I fill the buffer as a tri list, so it uses 4 vertices and 6 indices to create a quad. It works great when I fill the entire buffer with 1 lock, then pass it to DIP. However, I'm trying to fill chunks and feeding them to DIP, to make it run faster, and so I can wrap around the buffer later on (to support larger particlesystems while keeping the buffer reasonably small). I've tried using the discard/nooverwrite method to fill a chunk of the buffer then pass it to DIP. It doesn't work, I get weird artifacts all over the screen, whatever values I pass to DIP. Since the indices are fine when the buffer is filled and DIP'd in 1 go, it seems the DIP offsets or locks are somehow faulty. Here's the important part(s) of the Render() function:
    

pd3dDevice->SetVertexShader(D3DFVF_DEFAULTVERTEX);
pd3dDevice->SetStreamSource(0, pd3dVB, sizeof(DefaultVertex));
pd3dDevice->SetIndices(pd3dIB, 0);

dwBaseVertex   = 0;   // start at offset 0 in vb

// if I set flush to be 4 * aliveparticles, it fills the entire 

// buffer in 1 go and works...

dwFlushVB      = 4 * 32; // draw buffer after this many vertices

dwNumVertices  = 0;
// currently the buffer and particles are allocated on creation, so we know

the max number of vertices
dwMaxVertices  = 4 * dwMaxParticleCount;

dwBaseIndex   = (dwBaseVertex * 6) / 4;
dwFlushIB     = (dwFlushVB * 6) / 4;
dwNumIndices  = (dwNumVertices * 6) / 4;
dwMaxIndices  = (dwMaxVertices * 6) / 4;

pd3dVB->Lock(dwBaseVertex * sizeof(D3DFVF_DEFAULTVERTEX), dwFlushVB * sizeof(D3DFVF_DEFAULTVERTEX), (BYTE **)&vb, D3DLOCK_DISCARD);

pd3dIB->Lock(dwBaseIndex * sizeof(WORD), dwFlushIB * sizeof(WORD), (BYTE **)&ib, D3DLOCK_DISCARD);

for each particle
  {
  if alive
  {
    fill vb[dwNumVertices...dwNumVertices+3]
    ib[dwNumIndices++] = (WORD)(dwBaseVertex+dwNumVertices);
    ib[dwNumIndices++] = (WORD)(dwBaseVertex+dwNumVertices+1);
    ib[dwNumIndices++] = (WORD)(dwBaseVertex+dwNumVertices+2);
    ib[dwNumIndices++] = (WORD)(dwBaseVertex+dwNumVertices);
    ib[dwNumIndices++] = (WORD)(dwBaseVertex+dwNumVertices+2);
    ib[dwNumIndices++] = (WORD)(dwBaseVertex+dwNumVertices+3);

    dwNumVertices += 4;

    if (dwNumVertices >= dwFlushVB)
    {
      pd3dVB->Unlock();
      pd3dIB->Unlock();

      pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
        dwBaseVertex, dwNumVertices, 
        dwBaseIndex, dwNumVertices / 2);

      dwBaseVertex += dwNumVertices;
      dwBaseIndex += dwNumIndices;
      dwNumVertices = 0;
      dwNumIndices = 0;

      if (dwBaseVertex + dwFlushVB > dwMaxVertices) dwFlushVB =
                     dwMaxVertices - dwBaseVertex;
      if (dwBaseIndex + dwFlushIB > dwMaxIndices) dwFlushIB =
                     dwMaxIndices - dwBaseIndex;

      pd3dVB->Lock(dwBaseVertex * sizeof(D3DFVF_DEFAULTVERTEX), 
          dwFlushVB * sizeof(D3DFVF_DEFAULTVERTEX),
         (BYTE **)&vb, D3DLOCK_NOOVERWRITE);

      pd3dIB->Lock(dwBaseIndex * sizeof(WORD), 
          dwFlushIB * sizeof(WORD),
         (BYTE **)&ib, D3DLOCK_NOOVERWRITE);
      }
    }
  }
}

pd3dVB->Unlock();
pd3dIB->Unlock();

// remaining particles

// this is the only part that is called when I fill the entire buffer in 1

go, and works...
if (dwNumVertices > 0)
{
  pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 
           dwBaseVertex, dwNumVertices,
           dwBaseIndex, dwNumVertices / 2);
}
    
[edited by - Dynaguy on September 29, 2002 8:19:25 AM]
Santharn
Santharn
First: Sorry for my bad english

You're using in your solution one big vertex buffer, that you are overwriting only once in the beginning of the algorithm.

Related to the DirectX-Docu from Microsoft, the usage of the flags D3DLOCK_DISCARD & D3DLOCK_NOOVERWRITE are indicated (outlined) like this:

    
Usage Style 3:

for loop()
{
If there is space in the buffer
{
// Append vertices/indices.

pBuffer->Lock(…D3DLOCK_NOOVERWRITE…);
}
Else
{
// Reset to beginning.

pBuffer->Lock(…D3DLOCK_DISCARD…);
}
Fill few 10s of vertices/indices in pBuffer
pBuffer->Unlock
Change State
DrawPrimitive() or DrawIndexedPrimitive() // A few primitives


}


Here is an article relating index-Buffering, that i have found while searching for that topic in the internet:

http://www.mvps.org/directx/articles/vcache.htm

Maybe it helps!


I have for myself too a problem with the function DrawIndexedPrimitive, since i don't understand the parameter-description in the DX8-MS-manual. This was from the first time on i saw the description of this function, i have read it again and again, and again, and it makes still no sense to me
I have only achieved the DrawIndexedPrimitive-function to work with the parameters: 0,NumOfVertices,0,NumOfIndices/3


Parameter MinIndex, the manual says:
"Minimum vertex index for vertices used during this call."
To what is this related? To the Vertex-Buffer? Does the BaseVertexIndex set in the SetIndices-Function affect this?

Parameter NumVertices, the manual says:
"The number of vertices indexed during this call, starting from BaseVertexIndex + StartIndex"
The StartIndex is an INDEX, how can this parameter be implicated with the number of vertices??? Makes no sense to me Same with the BaseVertexIndex (again an INDEX), set with the SetIndices-Function.

Parameter StartIndex, the manual says:
"Location in the index array to start reading indices."
I suggest you only will have to set this parameter to another value than 0, if you are rendering NOT the whole IB? Is this true?

Parameter PrimitiveCount
"Number of primitives to render. The number of vertices used is a function of the primitive count and the primitive type. The maximum number of primitives allowed is determined by checking the MaxPrimitiveCount member of the D3DCAPS8 structure."
The only Parameter that makes sense so far

In the remarks section it says:
"The minIndex and NumVertices parameters specify the range of vertex indices used for each DrawIndexedPrimitive call. These are used to optimize vertex processing of indexed primitives by processing a sequential range of vertices prior to indexing into these vertices. It is invalid for any indices used during this call to reference any vertices outside of this range."
...outside of this Range...outside of what range? A range that consits of an beginning-index (minIndex) and NumVertices? Sounds like totally nonsense to me

[edited by - Santharn on September 29, 2002 3:02:50 PM]
Dynaguy
Dynaguy
Thanks for the reply!

I had read both the docs and that link you provided already. The part of the doc you quoted implies that what I''m doing is a possible and viable method. However, DIP seems to be either bugged or is suffering from extremely bad documentation.

What I''ve gathered from several resources on DIP is this; the first 2 parameters MinIndex and NumVertices are actually only used for optimization. They specify the first and last vertex referenced in the part of the indexbuffer you use for this call of DIP. The third parameter controls the position in the IB where DIP starts reading indices, whereas the fourth parameters controls how many indices it reads. This is NOT the same as the number of indices. In my case I use 3 indices for every tri, so it''s NumIndices/3.

I''ll be damned if DIP would actually work like this. Maybe someone can shed more light on the matter?
Igilima
Igilima
Santharn, I read the sdk doc and here is what I understand from that.

In the call to SetIndices() the BaseVertexIndex parameter is a value that will be added to all index values loaded into the index buffer.

For example, if your vertex buffer contains 8 vertices:
0, 0, 0,
1, 0, 0,
0, 1, 0,
1, 1, 0,

0, 0, 0,
2, 0, 0,
0, 2, 0,
2, 2, 0

and your index buffer contains:
0, 1, 2,
2, 1, 3

If you call SetIndices with BaseVertexIndex = 0;
then DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 4, 0, 2); will draw the first pair of triangles with the first 4 vertices which is a 1x1 square.

If you call SetIndices with BaseVertexIndex = 4; then DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 4, 0, 2); will draw the second pair of triangles with the last 4 vertices which is a 2x2 square. This is because BaseVertexIndex (4) is added to each value in the index buffer. It would be the same as putting
4, 5, 6,
6, 5, 7
in your index buffer.

The reason for this is so that you can have multiple sets of vertices in the vertex buffer and use the same index buffer to reference each of them by just changing BaseVertexIndex value.



In DrawIndexedPrimitive() the MinIndex parameter is used for optimized loading or something. MinIndex and NumVertices determine the set of vertices that DrawIndexedPrimitive() will be using.

For example, if your vertex buffer contains 8 vertices:
0, 0, 0,
1, 0, 0,
0, 1, 0,
1, 1, 0,

0, 0, 0,
2, 0, 0,
0, 2, 0,
2, 2, 0

and your index buffer contains:
4, 5, 6,
6, 5, 7

then you would call DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 4, 4, 0, 2); MinIndex = 4 because you are starting at the 5th (0 based) vertex and NumVertices is 4 because you want the last 4 vertices. This would draw the bigger 2x2 square.



BaseVertexIndex and MinIndex are added together when you call DrawIndexedPrimitive().

For example, if your vertex buffer contains 12 vertices:
0, 0, 0,
1, 0, 0,
0, 1, 0,
1, 1, 0,

0, 0, 0,
2, 0, 0,
0, 2, 0,
2, 2, 0,

0, 0, 0,
5, 0, 0,
0, 5, 0,
5, 5, 0

and your index buffer contains:
4, 5, 6,
6, 5, 7

You call SetIndices() with BaseVertexIndex = 4.

Then you would call DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 4, 4, 0, 2); MinIndex(4) + BaseVertexIndex(4) = 8 means you are starting at the 9th (0 based) vertex and NumVertices is 4 because you want the last 4 vertices. This would draw the biggest 5x5 square.
Santharn
Santharn
Thanks Igilima! I believe that i understand the parameters now and i will print out your excellent explaination for my personal purpose

According to your explaination, MinIndex is the vertex to which the first indexbuffer-element relates - that's indeed redundant information and i understand now this (NON)sense of an opimization-purpose

But by explaining the parameter MinIndex with: "Minimum vertex index for vertices used during this call" life is again and again a hard challenge, thanks to microsoft


[edited by - Santharn on September 30, 2002 8:28:05 PM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.