40 fps max for a 2D arkanoid-like game

Recommended Posts

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[i][j].IsAlive == true )
Blit( PxTrace, (int) PTRACE[i][j].x, (int) PTRACE[i][j].y, RectPTrace, DefaultRect, 0xFFFFFFFF);
//DrawSprite(PIXELTRACE.TextureName, RectPTrace, PTRACE[i][j].x, PTRACE[i][j].y);
}
}
}

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

Share on other sites
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.

Share on other sites
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!

Share on other sites
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.

Share on other sites
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.

Share on other sites
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.

Share on other sites
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?

Share on other sites
Quote:
 Original post by JoshMWhat 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

using CRT.
Vsync enabled.

There's not any problems with other games or stuffs, that's just what I've done which is lagging.

Share on other sites
In this block of code:
for( int i = 0; i < 600; i++ ){	for( int j = 0; j < 800; j++ )	{		if( PTRACE[i][j].IsAlive == true )			Blit( PxTrace, (int) PTRACE[i][j].x, (int) PTRACE[i][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 :-/

Share on other sites
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;}

Share on other sites
I don't think Vsync could be limiting you to 40 fps, but try this anyway:

d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

Share on other sites
You could maybe try using D3DFMT_UNKNOWN instead of A8R8G8B8 when in windowed mode. If your desktop is not actually in format that's compatible with A8R8G8B8 for some reason then it may have to do color conversions when swapping, which could slow it down. But I doubt that's the problem. You could also try HARDWARE_VERTEXPROCESSING instead of SOFTWARE to see what happens.

I would load up that appwizard app that runs a 800fps and put a breakpoint on CreateDevice to see what the actual parameters are that it uses, and then try the same ones in your app to see if that makes any difference.

Share on other sites
Quote:
 Original post by Nuget5555I don't think Vsync could be limiting you to 40 fps, but try this anyway:d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

Thanks, now it's acting faster, maybe too fast but I'll correct it. Now, the framerate is independant from the video refresh, is that it ?

Quote:
 Original post by JoshMYou could maybe try using D3DFMT_UNKNOWN instead of A8R8G8B8 when in windowed mode. If your desktop is not actually in format that's compatible with A8R8G8B8 for some reason then it may have to do color conversions when swapping, which could slow it down. But I doubt that's the problem. You could also try HARDWARE_VERTEXPROCESSING instead of SOFTWARE to see what happens. I would load up that appwizard app that runs a 800fps and put a breakpoint on CreateDevice to see what the actual parameters are that it uses, and then try the same ones in your app to see if that makes any difference.

I previously did set the D3D format to UNKNOWN, but I've changed it, to see if it was the problem. Forgot to change it back :s

About HARDWARE_VERTEXPROCESSING, that's not changing anything :(
On the wiz app, HARDWARE_VPROC enables 822 fps while SOFT one enables 200~ fps.

Well, I will try to put a breakpoint there.

EDIT again :

d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;

is what would be needed for windowed mode, my fps would be set back to 85, my actual screen refresh rate.
However, the framerate will stay at 50 in fullscreen mode, even with that...

[Edited by - Zack08 on August 2, 2005 6:11:14 PM]

Share on other sites
Again, i suggest you to change your code.
One, i can't believe you using vertice and no vertexbuffer.
Two, this one looks scary:
for( int i = 0; i < 600; i++ ){	for( int j = 0; j < 800; j++ )	{		if( PTRACE[i][j].IsAlive == true )			Blit( PxTrace, (int) PTRACE[i][j].x, (int) PTRACE[i][j].y, RectPTrace, DefaultRect, 0xFFFFFFFF);	}}

Thats max. 480000 x calling "Blit", which again calling SetTexture.
Even if not all of those PTRACE objects are "alive", you're calling Settexture too damn often.
Believe me, setting your texture that often per frame will slow you down. Why not have a list, filled with your sprite/game objects, sort it by texture and then traverse for drawing. Doing so, you call SetTexture only once per texture, not once per sprite. Especially since you seem to use the very same texture in that loop. Think about it, you loop several 1000 times, setting the same texture over and over again (only changing its offset).

Share on other sites
Yep, I'll change it.

That PTrace stuff isn't really used, it was just made for testing something. It's activated only if a key is pressed. I'll remove it.

Share on other sites
Keep this in mind, while it's still good to optimize your code, a windowed game running at a steady 40fps is not that bad, especially if you have a screen full of tiles, sprites, background, score, etc. After coding in "2d via 3d" for quite a while now, I've come to the conclusion some 2D games push the 3d pipleline as hard or harder than some 3d fps games. Especially 2d games with alot of tile/sprite animation. As long as you're coding in time based movement, 40fps is not THAT bad in windowed mode. In full screen mode, every 1 or 2 vsyncs is still ok.

Share on other sites
I can see your using an ati card. If you have an nvidia laying around put it in and go grab NV Perf HUD stat. Thatll tell you where yer lagging. Also how many Triangles a second are you performing at? I could tell ya my game runs at 1 fps... but I could be trying to render the USA.

Also grab a profiler like GlowCode. It will let yer program run and then tell ya where all the time is spent. Profilers are a programmer's best friend.

Other idea was the present immediate, but sum1 took care of that one.

Last idea without going through all the code is I saw a DrawPrimitiveUp(...). Goto msdn.microsoft.com and checkup on DrawIndexedPrimitive(...). Ya gotta do that before you get to many things rendering.

Another note, this is in RELEASE right? not debug, because if you have any lists or vectors they wont be optimized. I can get 1 fps max in debug... but in release I hit high hundreds.

Share on other sites
Quote:
 Original post by 2dcoderKeep this in mind, while it's still good to optimize your code, a windowed game running at a steady 40fps is not that bad, especially if you have a screen full of tiles, sprites, background, score, etc. After coding in "2d via 3d" for quite a while now, I've come to the conclusion some 2D games push the 3d pipleline as hard or harder than some 3d fps games. Especially 2d games with alot of tile/sprite animation. As long as you're coding in time based movement, 40fps is not THAT bad in windowed mode. In full screen mode, every 1 or 2 vsyncs is still ok.

Yeah, I know but the fact is that there's only 3 textures loaded and nothing else. Plus, when I'm just displaying framerate on a black screen (no textures loaded, nothing else done), it gives me 40 fps.

I've just tried displaying the framerate on the tutorial2 "Vertices" of the DirectX SDK (see the DX Doc for C++), just added the CalculateFPS function and my text displaying function. It gives me 40 fps :\.
Maybe it's my font engine which is bad or my CalculFPS() function.

Here it is :

CalculFPS :

// enables to calculate the frameratedouble current_time = 0; double last_time = 0; int n = 0;double fps = 0;int Dec;int Sign;char FPSDisplay[10];char *CalculFPS() {     n++;     current_time = (timeGetTime() / 1000);    if( (current_time - last_time) >= 1.0 )     {         // number of frames per sec        fps = n / (current_time - last_time);         n = 0;         last_time = current_time;    }	_fcvt_s( FPSDisplay, _countof( FPSDisplay ), fps, 1, &Dec, &Sign );	FPSDisplay[3] = FPSDisplay[2];	FPSDisplay[2] = '.';	FPSDisplay[4] = NULL;	return FPSDisplay;    // ... }

InitFont

VOID InitText(int PointSize, bool Italic){	HRESULT hr;	HDC hDC;	int Height;	hDC = GetDC( NULL );	Height = -( MulDiv( PointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72 ) );	ReleaseDC( NULL, hDC );	// Create a font for statistics and help output	hr = D3DXCreateFont( g_pd3dDevice, Height, 0, FW_BOLD, 0, Italic, 		                 DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 		                 DEFAULT_PITCH | FF_DONTCARE, TEXT("Arial"), 		                 &g_pd3dxFont );	if( FAILED( hr ) )		MessageBox(NULL,"Impossible de créer la fonte!", "ERROR",MB_OK|MB_ICONEXCLAMATION);}

Write Text

VOID WriteText(char *Text, int x, int y, D3DCOLOR TextColor){	RECT RectText;	SetRect( &RectText, x, y, 0, 0 );	g_pd3dxFont->DrawText( NULL, Text, -1, &RectText, DT_NOCLIP, 						   TextColor );}

Quote:
 Original post by xsirxxI can see your using an ati card. If you have an nvidia laying around put it in and go grab NV Perf HUD stat. Thatll tell you where yer lagging. Also how many Triangles a second are you performing at? I could tell ya my game runs at 1 fps... but I could be trying to render the USA.Also grab a profiler like GlowCode. It will let yer program run and then tell ya where all the time is spent. Profilers are a programmer's best friend.Other idea was the present immediate, but sum1 took care of that one.Last idea without going through all the code is I saw a DrawPrimitiveUp(...). Goto msdn.microsoft.com and checkup on DrawIndexedPrimitive(...). Ya gotta do that before you get to many things rendering.Another note, this is in RELEASE right? not debug, because if you have any lists or vectors they wont be optimized. I can get 1 fps max in debug... but in release I hit high hundreds.

I'm just displaying 3 textures on 3D rectangles, with 4 Vertices (see the code).
Is there any profiler included with visual studio 2005 beta 2 ? Does Glowcode works with it ?
Yeah I'll change it to DrawIndexedPrimitive if I have to render more things, thanks.

Both RELEASE and DEBUG will run at 40 fps.

Share on other sites
Is it possible that the program is being stupid and if it misses the vsync, it waits until the next one... So it will jump back and forth between 85 (I assume this is your refresh rate) and 42.5... I have no idea what could cause this, but worth looking into.

Share on other sites
Quote:
 Original post by Sr_GuapoIs it possible that the program is being stupid and if it misses the vsync, it waits until the next one... So it will jump back and forth between 85 (I assume this is your refresh rate) and 42.5... I have no idea what could cause this, but worth looking into.

Don't know.. The strange thing is when I use the PTrace thing, before it's slowing down, the framerate will accelerate to 85 fps after some sprites displayed, 5 or 10 secs. Then it will start to slow down.

Share on other sites
So does the framerate just skip around randomly, or does it jump back and forth from 40 to 85?

Share on other sites
Start to slow down? So it gradually gets slower and slower? Have you checked for memory leaks?

Share on other sites
Quote:
 Original post by Sr_GuapoIs it possible that the program is being stupid and if it misses the vsync, it waits until the next one... So it will jump back and forth between 85 (I assume this is your refresh rate) and 42.5... I have no idea what could cause this, but worth looking into.

That seems very possible.

Share on other sites
The framerate is at 40. Then some hours later, I should get back 85, then 40 later and so on..
I'll use D3DPRESENT_INTERVAL_ONE for the windowed mode but I dunno how I'll do it for the fullscreen mode :\

Create an account

Register a new account

• Partner Spotlight

• Forum Statistics

• Total Topics
627660
• Total Posts
2978488

• 10
• 12
• 22
• 13
• 33