how many Lock() calls is prohibitive?

Started by
13 comments, last by synth_cat 17 years, 8 months ago
Quote:Original post by synth_cat
How do you swap data between two vertex buffers?

You don´t swap the data between the vertex buffers, you simply have 2 vertex buffers for every vertex buffer you had before (and were changing of course).
Then you use the first for the first frame, the second for the second frame, first for the third frame and so on. Essentially you got one vertex buffer that receives the new data for the _next_ frame and one vertex buffer that is used to draw the _current_ frame. These two swap their roles every frame, but not their data.

Quote:Original post by synth_cat
I recently tried splitting my my Lock() calls from only two into six, and I used six different arrays for storing temporary quads (recall that my engine requires six draw-quad calls). So I had a vb_cells_temp[2][NUM_CELL_QUADS] and a vb_fx_temp[2][2][NUM_FX_QUADS]. (I believe this is more or less what you advised me to do, Zahlman.) At Draw(), I would memcpy() each segment into the buffer and draw it. However, the results were terrible - I couldn't even see most of the quads and the ones I could see were flickering very badly.

Is memcpy() slow, and, if so, would that explain why the above method failed so spectacularly?


I don´t think that memcpy() or your Lock() / Unlock() calls themselves would be causing such behaviour, though I don´t have much experience with dynamic VBs (only used them once yet, which was terribly slow, but worked). The things you describe sound more like an error with the arrangement of the vertices in memory. This could cause wrong winding order for triangles (you wouldn´t see those triangles) or triangles being drawn using vertices that were not supposed to form one (flickering and perhaps some triangles that are too big and so on).
However, as I mentionded, I don´t have too much experience with dynamic VBs, so I might be wrong.

Hope that helped,
good luck!

Advertisement
Quote:
Are there any bad things about DrawPrimitiveUP()?


It effectively does what you are doing internally (it will copy the data you pass it into a location the GPU can access, just as you are copying your quad data from you array to the vertex buffer). So if you pass the same data to it each frame it will be alot less efficent than using a vertex buffer because it will be doing an unnessacary copy each frame. But in your case it should be more effecient as it avoids locking the vertex buffer (though prob. not as efficent as double buffering).

Quote:
How do you swap data between two vertex buffers?

The way I suggested you don't have to. One frame you fill buffer A with quads. The next frame you render buffer A while you are filling buffer B with quads. The next frame you render buffer B, and OVERWRITE the contents of the buffer A (which was rendered the previous frame and can now be discarded) with new data for this frame. This way you never have to transfer data between buffers, you just alternate which buffer is being rendered and which is being filled.
Quote:
- Use IDirect3DDevice9::DrawPrimitiveUP to render your Quads straight from the array your code is accessing (internally the device will copy the data to a location the GPU can access directly, but it will avoid the lock).

I have researched this option and discovered that it can be slow and/or exhibit other problems, so unfortunately I won't be able to use it.

Okay, I tried yet another approach at drawing quads dynamically.

This time I tried to cut out the use of a copy of my vertex buffer (and the subsequent need to make a memcpy() call) and instead created arrays of QUADS, which are written directly to the vertex buffer at draw time. Here is my code, below:

	//DRAW QUADS	VERTEXCELLS* vb_cells_pt=0;	d3ddev->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);	d3ddev->SetTexture(0, t_cells);	d3ddev->SetStreamSource(0, vb_cells, 0, sizeof(VERTEXCELLS));	d3ddev->SetFVF(VERTEX_CELLS);	//draw quads1[]	vb_cells->Lock(0, 3*sizeof(VERTEXCELLS), (void**)&vb_cells_pt, D3DLOCK_DISCARD);	//write quad1 contents to buffer	for(int quad1=0; quad1<NUM_CELL_QUADS; quad1++)	{		vb_cells_pt[quad1*6].color=quads1[quad1].color;		vb_cells_pt[quad1*6].u=quads1[quad1].u;		vb_cells_pt[quad1*6].v=quads1[quad1].v;		vb_cells_pt[quad1*6].pos=quads1[quad1].pos;		vb_cells_pt[quad1*6+1].color=quads1[quad1].color;		vb_cells_pt[quad1*6+1].u=quads1[quad1].u;		vb_cells_pt[quad1*6+1].v=quads1[quad1].v;		vb_cells_pt[quad1*6+1].pos=quads1[quad1].pos;		vb_cells_pt[quad1*6+1].pos.x+=100;		vb_cells_pt[quad1*6+1].pos.z+=0;		vb_cells_pt[quad1*6+2].color=quads1[quad1].color;		vb_cells_pt[quad1*6+2].u=quads1[quad1].u;		vb_cells_pt[quad1*6+2].v=quads1[quad1].v;		vb_cells_pt[quad1*6+2].pos=quads1[quad1].pos;		vb_cells_pt[quad1*6+2].pos.x+=100;		vb_cells_pt[quad1*6+2].pos.z+=100;		vb_cells_pt[quad1*6+3].color=quads1[quad1].color;		vb_cells_pt[quad1*6+3].u=quads1[quad1].u;		vb_cells_pt[quad1*6+3].v=quads1[quad1].v;		vb_cells_pt[quad1*6+3].pos=quads1[quad1].pos;		vb_cells_pt[quad1*6+3].pos.x+=0;		vb_cells_pt[quad1*6+3].pos.z+=0;		vb_cells_pt[quad1*6+4].color=quads1[quad1].color;		vb_cells_pt[quad1*6+4].u=quads1[quad1].u;		vb_cells_pt[quad1*6+4].v=quads1[quad1].v;		vb_cells_pt[quad1*6+4].pos=quads1[quad1].pos;		vb_cells_pt[quad1*6+4].pos.x+=100;		vb_cells_pt[quad1*6+4].pos.z+=100;		vb_cells_pt[quad1*6+5].color=quads1[quad1].color;		vb_cells_pt[quad1*6+5].u=quads1[quad1].u;		vb_cells_pt[quad1*6+5].v=quads1[quad1].v;		vb_cells_pt[quad1*6+5].pos=quads1[quad1].pos;		vb_cells_pt[quad1*6+5].pos.x+=0;		vb_cells_pt[quad1*6+5].pos.z+=100;	}	vb_cells->Unlock();	d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, NUM_CELL_QUADS);	//draw quads2[]	vb_cells->Lock(0, 3*sizeof(VERTEXCELLS), (void**)&vb_cells_pt, D3DLOCK_DISCARD);	//write quad1 contents to buffer	//write quad1 contents to buffer	for(int quad2=0; quad2<NUM_CELL_QUADS; quad2++)	{		vb_cells_pt[quad2*6].color=quads2[quad2].color;		vb_cells_pt[quad2*6].u=quads2[quad2].u;		vb_cells_pt[quad2*6].v=quads2[quad2].v;		vb_cells_pt[quad2*6].pos=quads2[quad2].pos;		vb_cells_pt[quad2*6+1].color=quads2[quad2].color;		vb_cells_pt[quad2*6+1].u=quads2[quad2].u;		vb_cells_pt[quad2*6+1].v=quads2[quad2].v;		vb_cells_pt[quad2*6+1].pos=quads2[quad2].pos;		vb_cells_pt[quad2*6+1].pos.x+=100;		vb_cells_pt[quad2*6+1].pos.z+=0;		vb_cells_pt[quad2*6+2].color=quads2[quad2].color;		vb_cells_pt[quad2*6+2].u=quads2[quad2].u;		vb_cells_pt[quad2*6+2].v=quads2[quad2].v;		vb_cells_pt[quad2*6+2].pos=quads2[quad2].pos;		vb_cells_pt[quad2*6+2].pos.x+=100;		vb_cells_pt[quad2*6+2].pos.z+=100;		vb_cells_pt[quad2*6+3].color=quads2[quad2].color;		vb_cells_pt[quad2*6+3].u=quads2[quad2].u;		vb_cells_pt[quad2*6+3].v=quads2[quad2].v;		vb_cells_pt[quad2*6+3].pos=quads2[quad2].pos;		vb_cells_pt[quad2*6+3].pos.x+=0;		vb_cells_pt[quad2*6+3].pos.z+=0;		vb_cells_pt[quad2*6+4].color=quads2[quad2].color;		vb_cells_pt[quad2*6+4].u=quads2[quad2].u;		vb_cells_pt[quad2*6+4].v=quads2[quad2].v;		vb_cells_pt[quad2*6+4].pos=quads2[quad2].pos;		vb_cells_pt[quad2*6+4].pos.x+=100;		vb_cells_pt[quad2*6+4].pos.z+=100;		vb_cells_pt[quad2*6+5].color=quads2[quad2].color;		vb_cells_pt[quad2*6+5].u=quads2[quad2].u;		vb_cells_pt[quad2*6+5].v=quads2[quad2].v;		vb_cells_pt[quad2*6+5].pos=quads2[quad2].pos;		vb_cells_pt[quad2*6+5].pos.x+=0;		vb_cells_pt[quad2*6+5].pos.z+=100;	}	vb_cells->Unlock();	d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, NUM_CELL_QUADS);	//draw quads3[]	vb_cells->Lock(0, 3*sizeof(VERTEXCELLS), (void**)&vb_cells_pt, D3DLOCK_DISCARD);	//write quad1 contents to buffer	//write quad1 contents to buffer	for(int quad3=0; quad3<NUM_CELL_QUADS; quad3++)	{		vb_cells_pt[quad3*6].color=quads3[quad3].color;		vb_cells_pt[quad3*6].u=quads3[quad3].u;		vb_cells_pt[quad3*6].v=quads3[quad3].v;		vb_cells_pt[quad3*6].pos=quads3[quad3].pos;		vb_cells_pt[quad3*6+1].color=quads3[quad3].color;		vb_cells_pt[quad3*6+1].u=quads3[quad3].u;		vb_cells_pt[quad3*6+1].v=quads3[quad3].v;		vb_cells_pt[quad3*6+1].pos=quads3[quad3].pos;		vb_cells_pt[quad3*6+1].pos.x+=100;		vb_cells_pt[quad3*6+1].pos.z+=0;		vb_cells_pt[quad3*6+2].color=quads3[quad3].color;		vb_cells_pt[quad3*6+2].u=quads3[quad3].u;		vb_cells_pt[quad3*6+2].v=quads3[quad3].v;		vb_cells_pt[quad3*6+2].pos=quads3[quad3].pos;		vb_cells_pt[quad3*6+2].pos.x+=100;		vb_cells_pt[quad3*6+2].pos.z+=100;		vb_cells_pt[quad3*6+3].color=quads3[quad3].color;		vb_cells_pt[quad3*6+3].u=quads3[quad3].u;		vb_cells_pt[quad3*6+3].v=quads3[quad3].v;		vb_cells_pt[quad3*6+3].pos=quads3[quad3].pos;		vb_cells_pt[quad3*6+3].pos.x+=0;		vb_cells_pt[quad3*6+3].pos.z+=0;		vb_cells_pt[quad3*6+4].color=quads3[quad3].color;		vb_cells_pt[quad3*6+4].u=quads3[quad3].u;		vb_cells_pt[quad3*6+4].v=quads3[quad3].v;		vb_cells_pt[quad3*6+4].pos=quads3[quad3].pos;		vb_cells_pt[quad3*6+4].pos.x+=100;		vb_cells_pt[quad3*6+4].pos.z+=100;		vb_cells_pt[quad3*6+5].color=quads3[quad3].color;		vb_cells_pt[quad3*6+5].u=quads3[quad3].u;		vb_cells_pt[quad3*6+5].v=quads3[quad3].v;		vb_cells_pt[quad3*6+5].pos=quads1[quad3].pos;		vb_cells_pt[quad3*6+5].pos.x+=0;		vb_cells_pt[quad3*6+5].pos.z+=100;	}	vb_cells->Unlock();	d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, NUM_CELL_QUADS);


Not only does this run much slower than my old write-to-copy-of-vertex-buffer method, but I don't even see any quads! Plus, this new method seems to be crunching the whole app - my DirectInput starts to read keystates incorrectly, causing the camera to keep moving for a second after I let go of the move key, etc. Can anyone please explain why it does this?

I am amazed at how difficult it has become just to figure out how to draw my quads.

-DrawPrimitiveUP won't work because it's too slow

-Memcpy()'ing a copy of the vertex buffer to the vertex buffer at draw time doesn't work because it behaves strangely and won't work properly when I do it more than once with multiple copies - something I must be able to do.) - See my previous post.

Can anyone please help me out here? All I want to do is to be able to call some sort of AddQuadToBeDrawn() function from anywhere within the game (within the handling of cells, shots, lightning, weather, etc.) I cannot just lock the vertex buffer and then iterate through all my entities, writing directly to the vbuffer, for two reasons.

#1, the quads need to be split into 6 different DrawPrimitive() calls based on whether they are additive/subtractive/source_blend/high/low.

#2, adding quads in my game is more complicated than just "draw a quad for each entity" - in short, if I were to just write directly to the vbuffer while it was locked, there would need to be a large amount of game logic run while the vbuffer was locked, which would obviously be bad.

I'm sorry to keep bothering you all about this. . .

Thanks!
-synth_cat

Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith
Quote:
-DrawPrimitiveUP won't work because it's too slow

Personally I'd test this.. Its very easy to implement (you just have to pass your quad arrays directly to DrawPrimitiveUP)

Quote:
#1, the quads need to be split into 6 different DrawPrimitive() calls based on whether they are additive/subtractive/source_blend/high/low.

If you went the double buffering route each vertex buffer would have to be doubled-up.


Quote:
need to be a large amount of game logic run while the vbuffer was locked, which would obviously be bad.

If you are not trying to render while this is going on that should not be a big problem.


Well, after a lot of tinkering with this, I have come to the conclusion that all the errors and problems resulted from locking a vertex buffer more than once per step.

To tell the truth, I like my method of writing to an array of vertices and then memcpy()'ing it into my vertex buffer at draw time. This method allows me to only lock my vertex buffer once, which is good for performance.

So I have only one question to ask - Is there any problem at all with doing memcpy() to a vertex buffer? (Does it crash on some video cards, is it extraordinarily slow on some video cards, etc.)

Thanks to all of you for helping me out with this problem - I just hope that the answer to the above question can put this issue to rest for good!

Thanks,
synth_cat
Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith

This topic is closed to new replies.

Advertisement