Truly terrible rendering performance...

Started by
21 comments, last by Mace 18 years ago
I'm starting to pull my hair out over this terrible performance I am getting. If anyone is willing to take a look at this stuff and see if they can figure out why it is rendering so slowly, I would appreciate it. Here is some information that can help: Here is some of the pix information from a frame. This is similar to what is rendered: My main rendering function:

int gameclass::render()
{

if( NULL == d3ddevice )
        return 1;

d3ddevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,               
				 D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );


 d3ddevice->BeginScene();
setupmatrices(x,20,y);//y);
                   

my=my-300; //  convert the world x and y coordinates into a
mx=mx-400; //  grid


if (bx<10) bx=10;
if (bx>13) bx=13;

if (by<10) by=10;
if (by>13) by=13;


rendermodel(skybox,camx,15,camy,0.0f,0.0f,0.0f,5.0f,false);  
if (alive) rendermodel(tanks[0],(float)x,(float)(height-1),(float)y,0.0f,(float)(rot),0.0f,1.0f,false);

for (int i =by-10;i<by+7;i++)
 for (int j=bx-10;j<bx+7;j++)	 
 	 for (int c=0;c<heights[j];c++)	   
       	 if (blocks[j]>-1)rendermodel(block[blocks[j]],(float)(j-10)*2,(float)c,(float)(i-10)*2,0.0f,0.0f,0.0f,1.1f,false);  
   

for ( i =by-10;i<by+7;i++)
 for ( int j=bx-10;j<bx+7;j++)	 
 { 	 
	 if (build[j]==1) rendermodel(city,(float)(j-10)*2,(float)heights[j]-1,(float)(i-10)*2,0.0f,0.0f,0.0f,1.1f,false);  
	 if (build[j]==2) rendermodel(xxx,(float)(j-10)*2,(float)heights[j]-1,(float)(i-10)*2,0.0f,0.0f,0.0f,1.1f,false);  
 }

for ( i =by-10;i<by+7;i++)
 for (int j=bx-10;j<bx+7;j++)	  
     if ((tops[j]>0)||(heights[j]>0)){
			rendermodel(top[tops[j]],(float)(j-10)*2,(float)heights[j]-1,(float)(i-10)*2,0.0f,0.0f,0.0f,1.1f,false);  
	 }



//rendermodel(expl,(float)2,(float)heights[2][2]-1,(float)(2),0.0f,0.0f,0.0f,1.0f,true);  

 


	  
RECT srcrect;
srcrect.top=0;
srcrect.left=0;
srcrect.right=800;
srcrect.bottom=50;
hudsprite->Draw(hud,&srcrect,NULL,NULL,NULL,&D3DXVECTOR2(0,548.0),D3DCOLOR_ARGB(200,255,255,255));

srcrect.right=51;
srcrect.bottom=45;
srcrect.top=0;
srcrect.left=0;
hudselsprite->Draw(hudsel,&srcrect,NULL,NULL,NULL,&D3DXVECTOR2((sel*50)+2,550.0),D3DCOLOR_ARGB(75,255,255,255));
char buffer[10];

char buffer2[5];
sprintf(buffer2,"%d",fps);
sprintf(buffer,"FPS: %s",&buffer2);//[strlen(buffer)-8]);	

drawtext(buffer,D3DCOLOR_RGBA(255,0,0,105),0,0,600,50);

  char buffer3[10];
char buffer4[5];

setupmatrices(40,20,0);
POINT lp;
GetCursorPos(&lp);
mousex=lp.x;
mousey=lp.y;
D3DXVECTOR3 v,vf,vn;
D3DVIEWPORT9 vp;
d3ddevice->GetViewport(&vp);
D3DXMATRIX matproj;
D3DXMATRIX matview;
D3DXMATRIX matworld;
D3DXMatrixIdentity(&matworld);
if (d3ddevice->GetTransform(D3DTS_VIEW,&matview)!=D3D_OK) quit=1;
if (d3ddevice->GetTransform(D3DTS_PROJECTION,&matproj)!=D3D_OK)quit=1;

bool b=false;
for (int I =0;I<20;I++)
 for (int J=0;J<20;J++)	 
	 {


int C=heights[J];


	// int	C=heights[J*2+11][I*2+9];
	 
D3DXVec3Unproject(&vn,&D3DXVECTOR3(lp.x,lp.y,0),&vp,&matproj,&matview,&matworld);
D3DXVec3Unproject(&vf,&D3DXVECTOR3(lp.x,lp.y,1),&vp,&matproj,&matview,&matworld);
D3DXVec3Subtract(&v,&vf,&vn);


int close=0;
BOOL hit1=false;
BOOL hit2=false;
float dist;
hit1= D3DXBoxBoundProbe(&D3DXVECTOR3((J-10)*2-1,1,(I-10)*2-1),
    &D3DXVECTOR3((J-10)*2+1,C,(I-10)*2+1),
    &D3DXVECTOR3(cos(rad(camrot))*20+camx,camh+20,sin(rad(camrot))*20+camy),
    &v
);


if (((b==false) || (I<close))&& ((hit1)||(hit2))) {mxa=J;mya=I;close=I;b=true; rendermodel(select,(J-10)*2,C-1,(I-10)*2,0.0f,0,0.0f,1.1f,false);	
 sprintf(buffer4,"%d",C);
 
 
 sprintf(buffer3,"Coords: %s",&buffer4);//[strlen(buffer)-8]);	
    
	 drawtext(buffer3,D3DCOLOR_RGBA(255,0,0,105),0,50,150,100);
}	 
}	

	 d3ddevice->EndScene();
d3ddevice->Present(NULL,NULL,NULL,NULL);

return 0;
}




Which calls this to render models:

int gameclass::rendermodel(model mod,float x=0,float y=0,float z=0, float rx=0, float ry=0, float rz=0,float sc=0, bool tr=false)
{  
    D3DXMATRIX matWorld,matTrans;
    
D3DXMatrixTransformation( &matTrans,NULL,NULL,NULL,NULL,NULL,
&D3DXVECTOR3(x,y,z));

D3DXMatrixRotationYawPitchRoll(&matWorld,(float)rad(ry),(float)rad(rx),(float)rad(rz));

D3DXMatrixMultiply( &matWorld, &matWorld, &matTrans );

D3DXMatrixScaling( &matTrans,sc,sc,sc);
D3DXMatrixMultiply( &matWorld, &matWorld, &matTrans );

    d3ddevice->SetTransform( D3DTS_WORLD, &matWorld );
    

//d3ddevice->SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE,   D3DMCS_MATERIAL );


for( DWORD i=0; i<mod.num; i++ )
    {
        //Set the material and texture for this subset
        D3DMATERIAL9 m = mod.materials;
	    //if (infront)
		 D3DCOLORVALUE c;
		 
		 c.r =mod.materials.Diffuse.r;
		 c.g=mod.materials.Diffuse.g;
		 c.b=mod.materials.Diffuse.b;

  if (tr==1) c.a= .5; else c.a=1;
	
		m.Diffuse=c;
        
		c.r =mod.materials.Ambient.r+.02;
		c.g=mod.materials.Ambient.g+.02;
		c.b=mod.materials.Ambient.b+.02;
		
		  if (tr==1) c.a= .5; else c.a=1;
		/*	c.r =1;
		c.g=1;
		c.b=1;
		  */
		m.Ambient=c;

        c.r =mod.materials.Specular.r;
		 c.g=mod.materials.Specular.g;
		 c.b=mod.materials.Specular.b;
		if (tr==1) c.a= .5; else c.a=1;
		m.Specular=c;


		//d3ddevice->SetMaterial( &mod.materials );
        d3ddevice->SetMaterial( &m);
		d3ddevice->SetTexture( 0, mod.textures );      
if (tr==1)   d3ddevice->SetTextureStageState(0,D3DTSS_ALPHAOP,.5); 
		//Draw the mesh subset
        mod.mesh->DrawSubset( i );
    }
if (tr==1)        d3ddevice->SetTextureStageState(0,D3DTSS_ALPHAOP,1); 
return 0;
}





Which are stored in this:

int gameclass::createmesh(model &mod, char *file)
{
    LPD3DXBUFFER pD3DXMtrlBuffer;

    if( FAILED( D3DXLoadMeshFromX( file, D3DXMESH_SYSTEMMEM, 
                                   d3ddevice, NULL, 
                                   &pD3DXMtrlBuffer,NULL, &mod.num,
								   &mod.mesh)))
    {
        return 1;
    }

    D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
    mod.materials = new D3DMATERIAL9[mod.num];
    mod.textures  = new LPDIRECT3DTEXTURE9[mod.num];
 _chdir("textures");
    for( DWORD i=0; i<mod.num; i++ )
    {
        mod.materials = d3dxMaterials.MatD3D;

        //mod.materials.Ambient = mod.materials.Diffuse;
       
        if( FAILED( D3DXCreateTextureFromFile( d3ddevice, 
                                               d3dxMaterials.pTextureFilename, 
                                               &mod.textures ) ) )
        {
            mod.textures = NULL;
        }
    }

 
    pD3DXMtrlBuffer->Release();

D3DXComputeNormals(mod.mesh,NULL);

DWORD *pAdj=new DWORD[mod.mesh->GetNumFaces()*3];
        

mod.mesh->GenerateAdjacency(0.0f,pAdj);
            
        // optimize the mesh with attribute sorting
        // D3DXMESHOPT_ATTRSORT
        //pMesh->OptimizeInPlace(D3DXMESHOPT_VERTEXCACHE,pAdj,NULL,NULL,NULL) 
            
        // de-allocate adjacency data storage

mod.mesh->OptimizeInplace(D3DXMESHOPT_COMPACT || D3DXMESHOPT_ATTRSORT ||
						  D3DXMESHOPT_STRIPREORDER,pAdj,NULL,NULL,NULL);
 
	
D3DXCleanMesh(
  mod.mesh,
  pAdj,
  &mod.mesh,
  pAdj,
  NULL);
/*

D3DXSimplifyMesh(mod.mesh,
  pAdj,
  NULL,
  NULL,
  (mod.mesh->GetNumVertices()/5)*4,
  D3DXMESHSIMP_FACE,
  &mod.mesh);
*/
	delete pAdj;
_chdir("..");
	return 0;
}




[Piebert Entertainment] [Ask The All-Knowing Oracle A Question]------------------------------------------------------------GDSFUBY GameDev Society For UnBanning YodaTheCodaIf you want to see yoda unbanned then put this in your sig ------------------------------------------------------------DAIAGA Dave Astle is a God Association. To join, put this in your sig!Founder and High Priest of DAIAGA[edited by - YodaTheCoda on December 10, 2003 1:57:54 PM]
Advertisement
Hey,

Your top clickster is broken :).

I am finding it hard to tell what methods you are using for the rendering from that code.

- Are you rendering in big batches?
- Are you rendering using triangle strips?
- Are you creating/manually modifying the contents of non-dynamically create vertex buffers at run time?

Dave
Top imageryOhtehyay fixed.

The middle code segment should show you how I am rendering using DrawSubset. that is the function I call each time I want to render a model (gameclass::rendermodel)
[Piebert Entertainment] [Ask The All-Knowing Oracle A Question]------------------------------------------------------------GDSFUBY GameDev Society For UnBanning YodaTheCodaIf you want to see yoda unbanned then put this in your sig ------------------------------------------------------------DAIAGA Dave Astle is a God Association. To join, put this in your sig!Founder and High Priest of DAIAGA[edited by - YodaTheCoda on December 10, 2003 1:57:54 PM]
I am only guess but is it possible that you render the blocks of your “terrain“ one by one?
Quote:Original post by Demirug
I am only guess but is it possible that you render the blocks of your “terrain“ one by one?


Yes, I render each block by calling rendermesh. is there some more efficient way that i should be rendering all of the blocks?
[Piebert Entertainment] [Ask The All-Knowing Oracle A Question]------------------------------------------------------------GDSFUBY GameDev Society For UnBanning YodaTheCodaIf you want to see yoda unbanned then put this in your sig ------------------------------------------------------------DAIAGA Dave Astle is a God Association. To join, put this in your sig!Founder and High Priest of DAIAGA[edited by - YodaTheCoda on December 10, 2003 1:57:54 PM]
That means that each block is done in at least one Draw[Indexed]Primitive() call, probably more. How many times is DrawSubset called per frame? Try adding a counter to check that. Any more than 500/frame is bad, anything more than 1000 is really bad.

The best way would be to not use meshes to render like this, and use raw triangles instead. Then you could render the whole map in N calls to Draw[Indexed]Primitive, where N is the number of textures in your map.
While I'm no expert in optimization, I can see that you're constantly setting your materials and textures with each call to the renderMesh function. You should at the very least batch your rendering calls by texture/material.

This pseudo-code really is not the best way to do this (some far more knowledgable people on here can probably point out the best way) but it should give a rough idea:
void renderMesh(Mesh *mesh){  // Draw polygons...}void setShader(Shader *shader){  // Set material, set texture.}void sortByShader(){  // Sort each model/mesh and group the ones that use the same texture.  // i.e.  // Mesh tank uses Tank_Shader (combination of your material/texture)  // Bricks 1 to (maximum brick count) uses Brick_Shader  // so you group the bricks together and set the texture/material ONCE.}void Render(){  sortByShader();  // Call this only when you need it.  for every mesh in the sorted mesh list  {     if (lastShader != mesh->shader)     {       lastShader = mesh->shader;       setShader(mesh->shader);     }     // Set your transforms , blah    renderMesh(mesh);  }}


Hopefully this will bring up those frame rates even just a little. Another thing to do is to batch your DrawPrimitive calls, that is put as much common vertex data/index data you can into a single vertex/index buffer and draw it once (this however will mean you MAY have to pre-transform your vertices). Again, I'm no expert and I'm probably way off. So use at your own risk.
It looks like I am using drawsubset once for each "block", then when i draw a house or something it is like 19.

So i'm guessing i'm callig drawsubset ~800 times for a frame. Is that too much?
[Piebert Entertainment] [Ask The All-Knowing Oracle A Question]------------------------------------------------------------GDSFUBY GameDev Society For UnBanning YodaTheCodaIf you want to see yoda unbanned then put this in your sig ------------------------------------------------------------DAIAGA Dave Astle is a God Association. To join, put this in your sig!Founder and High Priest of DAIAGA[edited by - YodaTheCoda on December 10, 2003 1:57:54 PM]
Yeah, it is. You're probably completely CPU bound.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Clicky
"10k - 40k batches/s = 100% 1GHz CPU"
I.e. 10,000 to 40,000 calls to Draw[Indexed]Primitive per second (not frame) uses up 100% of a 1GHz CPU, meaning the CPU is so busy submitting batches to the GPU, it doesn't have time for anything else.

This topic is closed to new replies.

Advertisement