Archived

This topic is now archived and is closed to further replies.

Framerate to low..why??

This topic is 5337 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, i am trying to make a little Engine by myself (my first steps in 3D)..D3D is amazing. But I have a little (big?) problem with the Framerates. I have a single textured Cube and the Framerates I get dont go above 25 on my GeForce2MX. The Direct3D Examples in the SDK are so much faster! I have tryed a lot...here is the Code of the D3D Init and the Renderloop. I hope you can see whats wrong. Thanks!! The Direct3D Init-Part:
   
//3D Device init

HRESULT DX3D::InitialiseD3D(HWND hWnd)
{
	
	g_Font = NULL;
    //create D3D Object

	g_pD3D = NULL;
	g_pD3DDevice = NULL;
    g_pD3D = Direct3DCreate8(D3D_SDK_VERSION);
    if(g_pD3D == NULL)
    {
        error("DirectX 8.1 not found!");
    }

    //get Screenmode

    D3DDISPLAYMODE d3ddm;
	d3ddm.Format = CheckDisplayMode(resx,resy,32);
	d3ddm.Width = resx;
	d3ddm.Height = resy;

    //Properties

    D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory(&d3dpp, sizeof(d3dpp));


	d3dpp.SwapEffect     = D3DSWAPEFFECT_DISCARD; 
	if(ScreenMode == 1)
	{
		d3dpp.Windowed = TRUE;
		d3dpp.BackBufferFormat = d3ddm.Format;
		d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
		d3dpp.EnableAutoDepthStencil = TRUE; 
	}
	else
	{
		d3dpp.Windowed = FALSE;
		d3dpp.BackBufferCount = 1;
		d3dpp.BackBufferFormat = d3ddm.Format;
		d3dpp.BackBufferWidth = d3ddm.Width;
		d3dpp.BackBufferHeight = d3ddm.Height;
		d3dpp.hDeviceWindow = hWnd;
		d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
		d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_ONE;
		d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
		d3dpp.EnableAutoDepthStencil = TRUE;
	}


		//pure HARDWARE

		if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, 
                                   D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &d3dpp, &g_pD3DDevice)))
		{
			error("Your Card is not supported.");
		}

	//turn on Z-Buffer

	g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
    //back face culling

	g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);

	//turn off Cursor

	ShowCursor(false);
    return S_OK;
}
//Mmethod for getting the displaymode

D3DFORMAT DX3D::CheckDisplayMode(UINT nWidth, UINT nHeight, UINT nDepth)
{
	UINT x;
	D3DDISPLAYMODE d3ddm;

	for(x = 0; x < g_pD3D->GetAdapterModeCount(0); x++)
	{
		g_pD3D->EnumAdapterModes(0, x, &d3ddm);
		if(d3ddm.Width == nWidth)
		{
			if(d3ddm.Height == nHeight)
			{
				if((d3ddm.Format == D3DFMT_R5G6B5) || (d3ddm.Format == D3DFMT_X1R5G5B5) || (d3ddm.Format == D3DFMT_X4R4G4B4))
				{
					if(nDepth == 16)
					{
						return d3ddm.Format;
					}
				}
				else if((d3ddm.Format == D3DFMT_R8G8B8) || (d3ddm.Format == D3DFMT_X8R8G8B8))
				{
					if(nDepth == 32)
					{
						return d3ddm.Format;
					}
				}
			}
		}
	}

	return D3DFMT_UNKNOWN;
}
  
//Renderloop:
  
void Render()
{
	char* fr = GetFrameRate();


    	if(ddo.g_pD3DDevice == NULL)
		{
			return;
		}
	    //clear Backbuffer		

ddo.g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0x000000, 1.0f, 0);
        //begin Frame

		ddo.g_pD3DDevice->BeginScene();
		/*Todo*/
		//set camera & perpective

		ddo.SetupCamera(playerpos_x,playerpos_y,playerpos_z);
		ddo.SetupPerspective();

		cube.rot_y+= 0.5f;
		cube.posx = 81.7f;
		cube.posy = 51.7f;
		cube.posz = playerpos_z+5.5f;
		cube.meshRender(0x3FFFFFFF);

		//Textout

		ddo.TextOut("FPS: ",10,10, 18);
		ddo.TextOut(fr,50,10, 18);


	   //End the scene

		ddo.g_pD3DDevice->EndScene();
        //Hintergrundbuffer flippen

		ddo.g_pD3DDevice->Present(NULL, NULL, NULL, NULL);	

}
  
[edited by - AxelFR on May 7, 2003 1:39:07 AM]

Share this post


Link to post
Share on other sites
I''m not familiar with whatever library you''re using, but if TextOut is like the Win32 TextOut function and uses the HDC of the screen then that might be slowing things down. Grabbing the screen DC is very slow.

What I did before creating a font engine was silently log the number of frames rendered and the time elapsed. When the user presses a key, I save the value (NumFrames/TimeElapsed) to a file. That value is the average FPS and this method doesn''t slow things down at all.

~CGameProgrammer( );

Share this post


Link to post
Share on other sites
I am not using the Win32 Function. I have this from a tutorial:


  
void DX3D::TextOut(char* string, int posx, int posy, int fontSize)
{
//font-definition

LOGFONT LogFont = {fontSize,0,0,0,FW_NORMAL,false,false,false,DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,PROOF_QUALITY,DEFAULT_PITCH,"Arial"};
RECT FontPosition;
//fill font structure

FontPosition.top = 10;
FontPosition.left = 10;
FontPosition.right = resx;
FontPosition.bottom = resy;
D3DXCreateFontIndirect(g_pD3DDevice,&LogFont,&g_Font);
g_Font->Begin();
FontPosition.top = posy;
FontPosition.left = posx;
g_Font->DrawText(string,-1,&FontPosition,DT_LEFT,0xffffffff);
g_Font->End();
}

Share this post


Link to post
Share on other sites
Why are you creating the font every time you want to draw text?

And there''s a much much better way to do text. Basically you draw all the characters in a font (128 or so is all you need) to a texture and keep track of where all the letters are using Win32 functions. Then during runtime you just reference the texture and draw letters using quads. It''s significantly faster. As an added bonus the complete source for doing that is included with the DX8 SDK. With a bit of tweaking it works with OpenGL as well.

For now, stop drawing text and see what frame rate you get by logging it as was suggested. Worry about fancy font tricks after you get your framerate to a reasonable level.

Ben

Share this post


Link to post
Share on other sites
Unless SetupCamera is just for updating the camera it would be called in a setup function rather than internally. Although it should still make no or little difference to the framerate. I also notice that unless you''re going for some trippy special camera-effects, changes to the perspective should also be avoided in the main render loop - should only be done once. (Although if a call to UpdatePerspective was added you could make add to some effects like dreaming, halicinations, warping or nightmare distortions, etc.. )
I''ve also noticed that some text/font rendering classes can cause some considerable slowdown (5-10fps). A really optimized font renderer would be handy.
One thing I''d definately try to do though, is create an external module that intelligently enumerates the devices and display modes for the most optimal settings possible at startup (with option to manually modify settings). You want as much hardware processing and as little default software buffer/reference rasterization as possible.
Still, I find myself puzzled by this 25fps phenomenon. Must be something big. Some huge hidden bottleneck. Maybe some loop that''s nest-looping more than it needs to unoticed somewhere else? I dunno?

Share this post


Link to post
Share on other sites
Yep, ID3DXFont is very slow !
I suggest that you use the CD3DFont (d3dfont.cpp/h) included in the DX SDK. Much faster!

Secondly, creating the font with each call to TextOut is a performance killer.

So,

a) Don''t use ID3DXFont, create your own or use the SDK''s
b) Create your Font Object once at Init time

Share this post


Link to post
Share on other sites
Thanks for your suggestions. I have made these changes:

- font creation in the D3D-init-method..not every frame
- killed setupPerpective and setupCamera from the Renderloop

The result is a gain of 1 single frame/s. :-(

Share this post


Link to post
Share on other sites
Just start remming out lines and see what happens. If the bottleneck isn''t readily apparent then you just have to start taking things out and see how performance is affected.

Ben

Share this post


Link to post
Share on other sites
Ok..the empty Renderloop without any Objects results in 45 Frames/s. I think 450 would be more real.

Maybe the Problem is in the D3DInit Method? Mmhh..

Share this post


Link to post
Share on other sites
Ah, I think I got it. You''re using vsync! For fullscreen, the presentation interval should be D3DPRESENT_INTERVAL_IMMEDIATE.

Otherwise, the problem could be that the Render() function is not called often enough; in other words, your Windows message-loop code could be wrong. You should show us the code that calls Render(), in case it is the problem.

~CGameProgrammer( );

Share this post


Link to post
Share on other sites
Are you sure you are calculating the frame rate correctly? Maybe you''re just off by a factor of ten in the calculation. I doubt the problem is vsync, since 25Hz would be a rather uncommon refresh rate

Share this post


Link to post
Share on other sites
Yeah but technically it was a problem so I pointed it out. But you're right; the framerate counter could be wrong. However if you count a number of frames and take the time elapsed, that will minimize the effect of unprecise timers... if that is the problem.

~CGameProgrammer( );



[edited by - CGameProgrammer on May 7, 2003 7:01:09 PM]

Share this post


Link to post
Share on other sites
why is fr a char*?

You should be returning an int and then sprintf to store the result in a string which is then outputted instead of using 2 TextOuts.

char fr[256];
sprintf (fr,"FPS: %i",GetFrameRate());
TextOut(fr);

Also, how is your framerate being calculated? It''s probably wrong. An empty render loop should get you thousands of frames per second since you''re not drawing anything and therefor not limited by VSYNC.

45 is also not a valid VSYNC. He should be getting at least 60fps if that were the bottleneck.

Ben

Share this post


Link to post
Share on other sites
Hi..its me again. :-) I dont think the calculated framerates are wrong. You SEE it..nearly a slide-show. Maybe the GeForce2 100 cant get any more fps. I changed the D3D Init Method a little bit. Original copy from a tutorial. But no result. Still only 100 fps in an empty scene.
Here are the code-snippets for the FrameCounter and the GameLoop Methods:


  
//calculate the framerate

char* GetFrameRate()
{
CurrentTime = timeGetTime();
TimeElapsed = (int)(CurrentTime - LastTime);
FrameCount++;


if(TimeElapsed > 1000)
{
Frames = (int)(FrameCount / TimeElapsed);
LastTime = CurrentTime;
infoFrame = FrameCount;
FrameCount = 0;
}
sprintf(fps,"%d",infoFrame);
return fps;
}

//starts the gameloop

INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT)
{

//registry windows class

WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_CLASSDC, WinProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
"Axel1", NULL};
RegisterClassEx(&wc);

//create window

int width = GetSystemMetrics(SM_CXFULLSCREEN);
int height = GetSystemMetrics(SM_CXFULLSCREEN);
HWND hWnd;
hWnd= CreateWindow("Axel1", "Axels 3D Engine V0.1a",
WS_OVERLAPPEDWINDOW, 0,0,resx,resy,
GetDesktopWindow(), NULL, wc.hInstance, NULL);
//Direct Input

dInput.InitDirectInput(hWnd);
//D3D Init

if(ddo.InitialiseD3D(hWnd))
{
//show window

ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);


//start gameloop

initObjects();
GameLoop();
}
else
{
error("Error");
}
deInit();

UnregisterClass("Axel1", wc.hInstance);

return 0;
}


//the gameloop

void GameLoop()
{
//Gameloop

MSG msg;
BOOL fMessage;

PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE);

while(msg.message != WM_QUIT)
{
fMessage = PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE);

if(fMessage)
{
//WinAPI Nachrichten abfangen

TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
//Rendern

Render();
}

}
}

Share this post


Link to post
Share on other sites
OK, the first step is to find a Direct3D tutorial which, when compiled, runs fast. Now modify it to make it more and more like your original code and find out what causes the sudden slowdown.

~CGameProgrammer( );

Share this post


Link to post
Share on other sites
All, right. Now we may be looking at vsync. 100 fps for an empty scene. 100-ish Hz is fairly common. Originally, only 45 fps was reported for the empty scene. In your D3DPRESENT_PARAMETERS you have PRESENT_INTERVAL_ONE, which is once per vsync. Try PRESENT_INTERVAL_IMMEDIATE and see if your empty scene fps goes up.

CGameProgrammer: "Mr.Saavik, you go right on quoting regulations."




<

[edited by - Dave Hunt on May 8, 2003 10:31:06 AM]

Share this post


Link to post
Share on other sites