Sign in to follow this  
CarlML

Strange slowdown when model(s) goes off screen

Recommended Posts

Got a pretty strange issue, perhaps someone recognizes it.

 

I have a model that I created the vertex and index buffers for and that I render using DrawIndexedPrimitive, after that I render a bunch of models that are loaded from .x files. Whatever I render after the first model gets really slow when all the models goes off screen, the fps goes from 150 to 20. What could be causing this?

 

If I render the first model after the "bunch of other models" the issue goes away but if I render another bunch of models after that the issue is seen again.

 

 

Share this post


Link to post
Share on other sites

What does your debugger and graphics debugger tell you?

I'm figuring out how to use PIX directx debugging tool now (I'm using directx 9), comparing the calls of different frames, but have not found anything useful so far. Any tips on what to look for?

Share this post


Link to post
Share on other sites

Any tips on what to look for?
 

 

It should show some amount of timing information indicating whether the slowdown is on the GPU/shader or in the driver. You'll possibly have to use a CPU-side profiler as well and correlate date to see some types of problems.

 

If you have DX warning levels turned up, you should also see anything about misuse of the APIs that could lead to issues.

 

I'm not sure I fully understand your problem; it sounds super weird. At this point I'd just be digging for every piece of information I could get my hands on and looking for anything that seems remotely abnormal. 

Share this post


Link to post
Share on other sites

According to PIX, in the frames where it is slow there are thousands of more calls to:

 

IDirect3DQuery9::GetData(NULL, 0x00000000, 0x00000001)

 

The rest seems to be the same between the fast and slow frames.

 

 

Edit: This was because I was flushing commands between each render call for profiling purposes. When I remove all such calls all the GetData commands go away but the slowdown issue remains. The search continues...

Edited by CarlML

Share this post


Link to post
Share on other sites

How are you storing and updating your objects?

The object that seems to be causing the issue is setup like this:

 

A model is loaded form an .x file, then x number of instances of that model is stored in a batch model.

 

The class basically looks like this:

class Model
{
public:
    LPDIRECT3DVERTEXBUFFER9 vertexBuffer;
    LPDIRECT3DINDEXBUFFER9 indexBuffer;
    DWORD numBytesPerVertex;
    int numVerts;
    int numFaces;

    LPDIRECT3DTEXTURE9 diffuseTexture;
    LPDIRECT3DTEXTURE9 normalTexture;

    //Some functions here
};

The .x model mesh is loaded like this:

LPD3DXBUFFER materialBuffer;
D3DXLoadMeshFromX(meshFileName, D3DXMESH_SYSTEMMEM, d3d.device, NULL, &materialBuffer, NULL, &numSubsets, &mesh);

The vertex and index buffers are intitialized like this:

numBytesPerVertex = mesh->GetNumBytesPerVertex();
int numModelVerts = mesh->GetNumVertices();
int numModelFaces = mesh->GetNumFaces();
numVerts = numModelVerts * numInstances;
numFaces = numModelFaces * numInstances;

//Create vertex buffer
d3d.device->CreateVertexBuffer(numVerts * numBytesPerVertex, D3DUSAGE_WRITEONLY, FVF_MESHVERTEX, D3DPOOL_DEFAULT, &vertexBuffer, NULL));

//Fill vertex buffer
MeshVertex* vertBuf = NULL;
vertexBuffer->Lock(0, 0, (void**)&vertBuf, 0);

MeshVertex* modelVertBuf = NULL;
mesh->LockVertexBuffer(0, (VOID**)&modelVertBuf);

int currentVertex = 0;
for(int i=0; i < numInstances; i++)
{
    for(int d=0; d < numModelVerts; d++)
    {
        vertBuf[currentVertex] = modelVertBuf[d];
        currentVertex++;
    }
}
mesh->UnlockVertexBuffer();
vertexBuffer->Unlock();


//Create index buffer
d3d.device->CreateIndexBuffer(numFaces * 3 * sizeof(short), 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &indexBuffer, NULL);


//Fill in index buffer
int currentStartIndex = 0;
int currentIndexIndex = 0;
int numIndices = numModelFaces * 3;

short* indexBuf = NULL;
indexBuffer->Lock(0, 0, (void**)&indexBuf, 0);

short* modelIndeXBuf = NULL;
mesh->LockIndexBuffer(0, (void**)&modelIndeXBuf);
for(int i=0; i < numInstances; i++)
{
    for(int d=0; d < numIndices; d++)
    {
        indexBuf[currentIndexIndex] = modelIndeXBuf[d] + currentStartIndex;
        currentIndexIndex++;
    }
    currentStartIndex += numModelVerts;
}

mesh->UnlockIndexBuffer();
indexBuffer->Unlock();

The vertex declaration looks like this:

#define FVF_MESHVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE3(1) | D3DFVF_TEXCOORDSIZE3(2) | D3DFVF_TEXCOORDSIZE2(3))

struct MeshVertex
{
    D3DXVECTOR3 pos;
    D3DXVECTOR3 normal;
    D3DXVECTOR3 tangent;
    D3DXVECTOR3 binormal;
    D3DXVECTOR2 tex;
};

const D3DVERTEXELEMENT9 vertexDecl[] =
{
    { 0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
    { 0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0 },
    { 0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT,  0 },
    { 0, 36, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0 },
    { 0, 48, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
    D3DDECL_END()
};

The model is rendered like this:

d3d.effectScene->SetTexture( "diffuseMap", diffuseTexture );
d3d.effectScene->SetTexture( "normalMap", normalTexture );

D3DXMATRIX worldMat;
D3DXMatrixIdentity(&worldMat);

d3d.effectScene->SetMatrix( "worldMatrix", &worldMat);
D3DXMATRIX worldViewProjMatrix = worldMat * camera.viewMatrix * camera.projMatrix;
d3d.effectScene->SetMatrix( "worldViewProjMatrix", &worldViewProjMatrix);
d3d.effectScene->CommitChanges();

d3d.device->SetVertexDeclaration(d3d.vertDecl);
d3d.device->SetStreamSource(0, vertexBuffer, 0, numBytesPerVertex);
d3d.device->SetIndices(indexBuffer);

d3d.device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, numVerts, 0, numFaces);

 

Edited by CarlML

Share this post


Link to post
Share on other sites

It has something to do with clipping because if I move the camera back until part of an object (or sometimes all of the objects) goes outside the view frustum the slowdown happens (as well as if I move to the side). I'm guessing the vertex buffer is not setup correctly for clipping or something like that. If you see an issue with how it is setup above let me know.

 

 

The slowdown happens in the GPU during the Present() call. My vertex and pixel shaders for testing are pretty simple though.

 

 

PIX shows the same function calls for the fast and slow frames, although as I pointed out, if I use:

 

pEvent->Issue(D3DISSUE_END); while(S_FALSE == pEvent->GetData( NULL, 0, D3DGETDATA_FLUSH ));

 

...before the Present() PIX shows that a lot more of GetData calls are made in the slow frames than in the fast frames.

Edited by CarlML

Share this post


Link to post
Share on other sites

The issue goes away if I set:

device->SetRenderState(D3DRS_CLIPPING, FALSE);

That is probably not the solution I want since it probably just hides the bug. It at least shows that the issue is related to clipping.

Share this post


Link to post
Share on other sites

I doubt it has to do with clipping for many reasons including if it was clipping the order of draws wouldn't matter.  Stick with profiling to give you hints as to what is happening.

 

edit - also what videocard are you running on?

Edited by Infinisearch

Share this post


Link to post
Share on other sites

I doubt it has to do with clipping for many reasons including if it was clipping the order of draws wouldn't matter.  Stick with profiling to give you hints as to what is happening.

 

edit - also what videocard are you running on?

I'm using GeForce GTX 1080 with the latest drivers.

 

In my test case I'm getting 500+ fps now in the fast frames while in the slow frames it crawls to 20-30 fps.

Share this post


Link to post
Share on other sites

Can you try it on a different machine with a different videocard?  or try rolling back your drivers to a previous version?  Just to be sure its not a hardware/driver issue.

Also how is your code organized is there one draw function or is the code to draw each object spread out?  Maybe you're setting some state by accident when rendering that one particular model.

Share this post


Link to post
Share on other sites

I may have found the source of the issue. I was creating the Direct3D device using D3DCREATE_SOFTWARE_VERTEXPROCESSING. If I use D3DCREATE_HARDWARE_VERTEXPROCESSING the issue goes away.

 

Turns out it was not the object above that was causing an issue since when I removed it I was able to reproduce the slowdown with other models when they were partially outside the view frustum. I'm guessing that the clipping of many polygons using "software vertex processing" is very slow.

 

What do you think, does it sound like a likely cause of the issue?

Share this post


Link to post
Share on other sites

You will get much greater performance with hardware vertex processing so it might become a non-issue.  But does it still drop frame rate depending on the order of that model?  Because that really is a strange issue.  Also when you replaced that model and still got the slowdown did you use the same code to draw the new model?

 

edit - also how many vertices is the model/s causing the problem?  And you said you duplicate it a few times? how many?

Edited by Infinisearch

Share this post


Link to post
Share on other sites

You will get much greater performance with hardware vertex processing so it might become a non-issue.  But does it still drop frame rate depending on the order of that model?  Because that really is a strange issue. 

No, any hint of the issue goes away with hardware processing but I'm not entirely convinced it is fixed since it was behaving pretty strange.

 

Also when you replaced that model and still got the slowdown did you use the same code to draw the new model?

 

I used the same shader code. The other models are drawn using "mesh->DrawSubset();", which as far as I can tell from looking at PIX calls the same functions as the 4 last functions I call in the render function I posted above.

Edited by CarlML

Share this post


Link to post
Share on other sites

edit - also how many vertices is the model/s causing the problem?  And you said you duplicate it a few times? how many?

I was rendering a model with about 800 faces and 461 verts 35 times in the same spot.

 

The batchmodel that I initially though was causing the problem was a single model of about 8000 faces and about 12000 verts.

Edited by CarlML

Share this post


Link to post
Share on other sites

Still trying to figure this out, I have stripped the project down to its bare minimum to render the objects and I can still reproduce the issue.

 

If any of you would like to take a look and see if you can reproduce the issue then here is the Visual Studio 2012 project with the .x object included (72 kB total):

 

http://www2.zippyshare.com/v/mI5AarI7/file.html

 

It should be ready to build if you just set the directories for the directx SDK on your computer. There is also an already built .exe in the Release folder.

 

The camera is controlled with WSAD, if you go backwards slightly you will see the object cross over the far clipping plane. At that point you will see the fps (in the upper left corner) go down drastically if the behavior is the same as for me.

 

You can try changing the device creation to use "D3DCREATE_HARDWARE_VERTEXPROCESSING" to see if the issue goes away.

 

Of course, if there are any debugging gurus out there that have a few minutes to spare to determine if this is actually a bug  that would be great. :)

Edited by CarlML

Share this post


Link to post
Share on other sites

If the problem went away with hardware vertex processing, you haven't got any problems..

It sounds like a simple "CPU does no justice here", which is why we have got GPUs :)

 

I would just leave it be, and be happy it works now - unless you need software vertex processing for some reason?

Share this post


Link to post
Share on other sites

If the problem went away with hardware vertex processing, you haven't got any problems..

It sounds like a simple "CPU does no justice here", which is why we have got GPUs :)

 

I would just leave it be, and be happy it works now - unless you need software vertex processing for some reason?

Yeah I might have to leave it be. I'm considering rewriting my engine to use Directx 11 anyway so a lot of things will probably change. Thanks for the input.

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