40 fps max for a 2D arkanoid-like game

Started by
22 comments, last by Zack08 18 years, 8 months ago
I've a problem, my game runs at 40 fps max windowed and it's lagging. Even if I remove most of the textures, that wouldn't change anything. I need it to run at 60 fps but can't figure it out. It runs at 50 fps on fullscreen. I'm using D3D to render 2D sprites. I'm not using the ID3DXSprite class, but my own 2D motor using textures on rectangles. Here's the code : Render code :

			// Clear the backbuffer to a black color
			Device_D3D->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 0, 0, 0 ), 1.0f, 0 );

		KeyPressedProcess();

		if ( BALLE.IsMoving == true )
		{
			BallMove();
		}

		Blit( Contour, 0, 0, RectContour, DefaultRect, 0xFFFFFFFF);
		//DrawBG(CONTOURJEU.TextureName, 0.0f, 0.0f);

		if( LaunchPixelTrace == false )
			Blit( Fond, 64, 64, RectFond, DefaultRect, 0xFFFFFFFF);
			//DrawBG(FOND.TextureName, 64.0f, 64.0f);

		Blit( Sprites, (int) RAQUETTE.x, (int) RAQUETTE.y, RectRaquette, DefaultRect, 0xFFFFFFFF);
		Blit( Sprites, (int) BALLE.x, (int) BALLE.y, RectBalle, DefaultRect, 0xFFFF00FF);
		//DrawSprite(TEXTURE.TextureName, RectRaquette, RAQUETTE.x, RAQUETTE.y);
		//DrawSprite(TEXTURE.TextureName, RectBalle, BALLE.x, BALLE.y);

		if( LaunchPixelTrace == true && BALLE.IsMoving == true )
		{
			DrawPixelTest( BALLE.x, BALLE.y );

			for( int i = 0; i < 600; i++ )
			{
				for( int j = 0; j < 800; j++ )
				{
					if( PTRACE[j].IsAlive == true )
						Blit( PxTrace, (int) PTRACE[j].x, (int) PTRACE[j].y, RectPTrace, DefaultRect, 0xFFFFFFFF);
						//DrawSprite(PIXELTRACE.TextureName, RectPTrace, PTRACE[j].x, PTRACE[j].y);
				}
			}
		}

		for( int i = 0; i < 10; i++ )
		{
			for( int j = 0; j < 21; j++ )
			{
				if( BRIQUE[j].IsAlive == true )
					Blit( Sprites, (int) BRIQUE[j].x, (int) BRIQUE[j].y, RectBrique, DefaultRect, 0xFFFFFFFF);
					//DrawSprite(TEXTURE.TextureName, RectBrique, BRIQUE[j].x, BRIQUE[j].y);
			}
		}

		Device_D3D->SetRenderTarget(D3DUSAGE_RENDERTARGET, Contour.lpSurface);
		WriteText( CalculFPS(), 80, 0, 0xFFFFFFFF );
		Device_D3D->SetRenderTarget(D3DUSAGE_RENDERTARGET, BackBuffer_Surface);

        // End the scene
        Device_D3D->EndScene();


Init_D3D code :

HRESULT Init_D3D(HWND hWnd, bool PleinEcran, int Largeur, int Hauteur)
{
	// Crée l'objet D3D, qui est requis pour créer le D3DDevice.
	if( ( Objet_D3D = Direct3DCreate9( D3D_SDK_VERSION ) ) == NULL )
        return E_FAIL;

	// Initialisation de l’objet D3DPRESENT_PARAMETERS 
	ZeroMemory( &d3dpp, sizeof(d3dpp) );

	// Selon le mode désiré, on lance la fonction adéquate
	if( PleinEcran )
	{
		if ( FAILED( Init_PleinEcran( hWnd, Largeur, Hauteur ) ) )
			return E_FAIL;
	}

	else
	{
		if ( FAILED( Init_Fenetre( hWnd, Largeur, Hauteur ) ) )
			return E_FAIL;
	}
	
	// Paramètres d’affichage pour l'utilisation de la clé de couleur et de la transparence
	Device_D3D->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE ); // Lance le test Alpha ( permet de tester chaque pixel )
	Device_D3D->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_NOTEQUAL ); // Permet à l'application d'accepter ou de rejeter un pixel, suivant sa valeur alpha (ici, rejette si non égal à la valeur ci-dessous)
	Device_D3D->SetRenderState( D3DRS_ALPHAREF, 0x00000000 ); // Valeur Alpha de référence (octet sur chaque pixel définissant la transparence)
	Device_D3D->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); // Permet d'autoriser l'alpha blending (couche transparente)
	Device_D3D->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
	Device_D3D->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
	Device_D3D->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
	Device_D3D->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
	Device_D3D->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
	// Filtrage bilinéaire pour un effet d'antialiasing lors des distorsions des sprites
	Device_D3D->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
	Device_D3D->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
	// Désactivation de la lumière (sinon les sprites seront noirs)
	Device_D3D->SetRenderState( D3DRS_LIGHTING, FALSE );

	// On obtient un pointeur sur la surface du BackBuffer
	if ( FAILED( Device_D3D->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &BackBuffer_Surface ) ) )
		return E_FAIL;


	//paramètres définissant les matrices de visualisation
	D3DXMatrixOrthoLH(&Ortho2D, (float)Largeur, (float)Hauteur, 0.0f, 1.0f);
	D3DXMatrixIdentity(&Identity);
	Device_D3D->SetTransform(D3DTS_PROJECTION, &Ortho2D);
	Device_D3D->SetTransform(D3DTS_WORLD, &Identity);
	Device_D3D->SetTransform(D3DTS_VIEW, &Identity);
	pVertices[0].z = pVertices[1].z = pVertices[2].z = pVertices[3].z = 1.0f;

	CurrentWidth = (float) Largeur;
	CurrentHeight = (float) Hauteur;

	return S_OK;
}


The Blit function code, which display the sprites :

void Blit(Texture IDTexture, int x_offset, int y_offset, RECT Rectangle_Source, RECT Rectangle_Destination, UINT Filtre_Transparence)
{
	float	Largeur_Destination=(float)(Rectangle_Destination.right - Rectangle_Destination.left),
			Largeur_Source=(float)(Rectangle_Source.right - Rectangle_Source.left),
			Hauteur_Source=(float)(Rectangle_Source.bottom - Rectangle_Source.top),
			Largeur_Texture=(float)IDTexture.Width,
			Hauteur_Texture=(float)IDTexture.Height;

	D3DXVECTOR2 echelle(1.0f,1.0f);

//dilatation du sprite si nécessaire
	if (Largeur_Destination!=0)
	{
		echelle.x = Largeur_Destination / Largeur_Source;
		echelle.y = (float)(Rectangle_Destination.bottom - Rectangle_Destination.top) / Hauteur_Source;
	}

	//on modifie ici les paramètres de notre rectangle 3D pour le rendu

	//couleur diffuse (avec transparence)
	pVertices[0].color = Filtre_Transparence;
	pVertices[1].color = Filtre_Transparence;
	pVertices[2].color = Filtre_Transparence;
	pVertices[3].color = Filtre_Transparence;

	//coordonnées spatiales
	//ATTENTION: l'offset de 0.5f ajouté sert à éviter un effet de bord désagréable
	pVertices[0].x = pVertices[3].x = x_offset - CurrentWidth / 2.0f - 0.5f ;
	pVertices[1].x = pVertices[2].x = x_offset - CurrentWidth / 2.0f - 0.5f + Largeur_Source * echelle.x;
	pVertices[0].y = pVertices[1].y = CurrentHeight / 2.0f - y_offset + 0.5f ;
	pVertices[2].y = pVertices[3].y = CurrentHeight / 2.0f - y_offset + 0.5f - Hauteur_Source * echelle.y;

	//coordonnées de texture
	pVertices[1].u = pVertices[2].u = Rectangle_Source.right/Largeur_Texture;
	pVertices[0].u = pVertices[3].u = Rectangle_Source.left/Largeur_Texture;
	pVertices[0].v = pVertices[1].v = Rectangle_Source.top/Hauteur_Texture;
	pVertices[2].v = pVertices[3].v = Rectangle_Source.bottom/Hauteur_Texture;

	//rendu des 4 vertices
	Device_D3D->SetVertexShader( NULL );
	Device_D3D->SetFVF( D3DFVF_RECTANGLE_VERTEX );
	Device_D3D->SetTexture( 0, IDTexture.lpTexture );
	Device_D3D->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, pVertices, sizeof(RECTANGLE_VERTEX) );
}


I'm using Visual Studio 2005 beta 2 (sent by Microsoft) and Directx 9 sdk from june 2005. EDIT : Ok, sorry, i've reorganised it. [Edited by - Zack08 on August 2, 2005 6:57:58 AM]
Advertisement
Don't post your entire project here please. Profile the different parts to see what's taking up the most time and then we might be able to help you.
Nobody has time to read through your entire source to find why it doesn't run as fast as you would like. I can tell it's D3D from the top of the code but you don't even tell us this, or what the game is doing, or anything. Is it full-screen or windowed? What resolution are you using? What hardware do you have?

But looking at your vertex/index buffer locking and the creation flags you set for them might be a good start. Are you using DrawPrimitive or DrawPrimitiveUP, and how many triangles are you drawing at once? These are just general pointers though, not specific since I don't have time to wade through your pages of program!
Yep, okay, sorry, I've edited it.

Is there something I'm missing on the Blit code ? I've tried to use ID3DXSprite class before making it by my own, but I've the same problem. I've tried to comment the texture declarations, but even if I have a black screen, the fps will always be 40~ when windowed. That's annoying since 40 fps is not enough for displaying correctly my arkanoid-like test game.
Well, from what i can tell, you call "SetTexture" every time you Blit (eg draw a sprite). Thats a possible performance killer. Try batching.
Also, you manipulate your vertices without locking a vertex buffer. Am i missing something? And why do you call "SetVertexShader( NULL )" and "SetFVF(D3DFVF_RECTANGLE_VERTEX )" everytime before you draw a primitive?
Other than that i can only suggest that maybe its because it runs windowed.
From my experience windowed applications usually have lower FPS.
I don't use VertexBuffer thing :s

Yeah, here's the code missing, Vertices struct and texture struct :

struct RECTANGLE_VERTEX{FLOAT x,y,z;		//coordonnées spatialesDWORD color;	//couleur diffuseFLOAT u, v;		//coordonnées de texture};#define D3DFVF_RECTANGLE_VERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)//matrice de projection, de la caméra (ID) et du monde (ID) D3DXMATRIX Ortho2D, Identity;//vertex buffer pour la structure rectangulaire dessinant un spriteRECTANGLE_VERTEX pVertices[4];typedef struct Texture{	char * File ;				//nom du fichier source	UINT Width,				//largeur de la texture (et non de l'image)		 Height;			//hauteur de la texture (et non de l'image)	LPDIRECT3DTEXTURE9 lpTexture;	//pointeur sur la texture	LPDIRECT3DSURFACE9 lpSurface;	//pointeur sur la surface}Texture;


Sometimes, I get back to 85 fps, but when I reboot my computer, it's running at 40 fps again.
What kind of computer / video card / etc do you have? Are you building Release or Debug? Are you using CRT or LCD and do you have vertical sync swapping enabled?
Quote:Original post by JoshM
What kind of computer / video card / etc do you have? Are you building Release or Debug? Are you using CRT or LCD and do you have vertical sync swapping enabled?


Athlon xp 2600+
1 go DDR
ATI Radeon 9000 pro 128mb

using CRT.
Vsync enabled.


There's not any problems with other games or stuffs, that's just what I've done which is lagging.
In this block of code:
for( int i = 0; i < 600; i++ ){	for( int j = 0; j < 800; j++ )	{		if( PTRACE[j].IsAlive == true )			Blit( PxTrace, (int) PTRACE[j].x, (int) PTRACE[j].y, RectPTrace, DefaultRect, 0xFFFFFFFF);	}}


How many times out of 480,000 iterations does Blit actually get called? What is it blitting in this loop?

You can only probably draw sprites this way a few hundred at a time before it will start to slow down.

If you do the DX9 app wizard and create a default d3d app with the teapot and all that, what FPS do you get? If that runs fine then it must be something with your code.

You said you get bad performance even with just a black screen. Does that imply that the program is doing *nothing*, or just that it isn't drawing? If your app is not doing anything at all and you're getting 40 fps, AND the default appwizard program runs fast enough, then perhaps you are setting up your buffers/surfaces incorrectly or something? I dunno :-/

Well I've installed and recompiled the SimpleSample project, which gives framerate and it runs at 822~ windowed.

Then I've just redone a prog. using my motor, but just displaying FPS on a black screen, without blitting anything or doing anything else : still 40~.

It must be a problem in my 2D motor code :
Well, here's how the windowed mode is initialised :

HRESULT Init_Fenetre( HWND hWnd, int Largeur, int Hauteur ){	// Paramètres définissant le rendu	d3dpp.Windowed = TRUE;	d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;	d3dpp.BackBufferWidth = Largeur;	d3dpp.BackBufferHeight = Hauteur;	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;	d3dpp.BackBufferCount = 2;	d3dpp.EnableAutoDepthStencil = FALSE;	// Création du device DirectGraphics	if( FAILED( Objet_D3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,										 D3DCREATE_SOFTWARE_VERTEXPROCESSING,										 &d3dpp, &Device_D3D ) ) )    {        return E_FAIL;    }	ShowCursor(TRUE);	// Curseur visible par dessus la fenêtre	return S_OK;}

This topic is closed to new replies.

Advertisement