Sign in to follow this  
fure

DrawPrimitive CPU load

Recommended Posts

Hello!

I noticed that drawing tens of thousands triangles with DrawPrimitive produces a high CPU load. With an AND X4 955 the number of triangles is limited to ~300,000 at 30fps.

The triangles are used for terrain and are stored in a VerticleBuffer which is filled at startup. There are no textures (only color and light). Terrain is devided in pieces of 600 verticles (which make 200 triangles) to reduce computing when parts of the terrain get changed.

Important code:
[spoiler]types:
[code]
struct CUSTOMVERTEX {FLOAT X, Y, Z; D3DVECTOR NORMAL; DWORD COLOR;};
#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE)
[/code]

init:
[code]
d3ddev->SetRenderState(D3DRS_LIGHTING, true);
d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE);
d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
d3ddev->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(50, 50, 50));
d3ddev->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, true);

CUSTOMVERTEX verticles[10*10*6];
// vertex filling

void* pvoid;
vBuffer->Lock(0, 0, &pvoid, 0);
std::memcpy(pvoid, verticles, countPrimitives*3*sizeof(CUSTOMVERTEX));
vBuffer->Unlock();
[/code]

render:
[code]
// view etc

d3ddev->SetFVF(CUSTOMFVF);
d3ddev->SetStreamSource(0, vBuffer, 0, sizeof(CUSTOMVERTEX));
d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, countPrimitives);
[/code]
[/spoiler]


How can I increase the performance? Currentry it's not sufficient, especially for slower PCs. Will the behavior change if I use greater/smaller terrain chunks? Thank you.

Share this post


Link to post
Share on other sites
How many draw calls you make per frame?

I mean, you show your draw code, where you can't do much of improvements. You should show bigger parts of the logic.
The key is to reduce the number of draw. Either you should use larger chunks or different sorts of geometry instancing.

Also can you verify the CPU load while the program is running (check from Task Manager gives you rough indication whether you are CPU bound).

Seems that you push roughly 9 million triangles per second which is quite low year 2012.

Best regards!

Share this post


Link to post
Share on other sites
One thing to note is that DrawIndexedPrimitive() is significantly faster than DrawPrimitive() when rendering larger numbers of primitives because the hardware vertex cache doesn't work for non-indexed primitives.

Share this post


Link to post
Share on other sites
Seems odd. When creating your VB, what is your usage flag being set to? Do you update the VB every frame? I'd also change to DrawIndexedPrimitive() like was stated in a prev post.

Share this post


Link to post
Share on other sites
[quote name='fure' timestamp='1335890203' post='4936455']
With an AND X4 955 the number of triangles is limited to ~300,000 at 30fps.

The triangles are used for terrain and are stored in a VerticleBuffer which is filled at startup. There are no textures (only color and light). Terrain is devided in pieces of 600 verticles (which make 200 triangles) to reduce computing when parts of the terrain get changed.
[/quote]300,000 : 60 = 5000 batches / frame. I think you need to at least halve them. At least.
Rendering less than 1000 unique vertices per batch is a waste on anything that is at least a GeForce 4 - it will never reach optimal performance. Even in GL - which is far more efficient than D3D9 at dispatching batches - there is going to be performance loss.

Share this post


Link to post
Share on other sites
It helped to avoid DrawPrimitive calls.

But what helped a lot more was switching from D3DCREATE_SOFTWARE_VERTEXPROCESSING to D3DCREATE_HARDWARE_VERTEXPROCESSING.


Thank you for the help!

Share this post


Link to post
Share on other sites
[quote name='fure' timestamp='1336150932' post='4937418']
But what helped a lot more was switching from D3DCREATE_SOFTWARE_VERTEXPROCESSING to D3DCREATE_HARDWARE_VERTEXPROCESSING.
[/quote]

Well, that has definetely something to do with poor performance ...

Share this post


Link to post
Share on other sites
Avoiding API calls setting the same state as the previous draw call is pretty import in D3D8 and D3D9. Basically D3D keeps a set of dirty flags any state changes have been made since the last draw call, and the Draw functions look at what is dirty and blindly do additional processing. D3D generally does not check if things really changed or not, as the application is more able to do it at a higher level and earlier, as calling D3D itself has a lot of overhead which is good to avoid. Setting things like the FVF or vertex decl, textures, buffers, unnecessarily has a pretty large impact on performance as a result.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this