fps problem, code included

Started by
6 comments, last by ursus 18 years, 4 months ago
Good day, I’m aware of the fact that this subject has been mentioned hundreds of times before but my search, that took half a day, produced results that gave no solution to the problem. The problem concerns weird frames per second counts. In windowed mode application appears to run much faster than in full screen mode. I am not talking about vsync here since in full screen mode fps drops to something like 20 while in window the result is around 500. This is no the question of hardware (I tested my application on different pcs) or drivers. Reading the historical posts on this forum I’ve learned that people using opengl or DX libraries also face this problem every now or then. So my best guess is that the problem is in the code itself or a compiler. I use MinGW. Have anyone solved the problem and can give me some directions to deal with it? If no can I ask as many different programmers to compile the code below on different compilers and post the results (full screen and windowed modes)? Thank you in advance Peter


#include <windows.h>

double time_factor;		// Time Scaling Factor
double time_span;		// time elapsed since last frame
LONGLONG last_time;		// Previous timer value	
LONGLONG cur_time;		// current timer value
int fps;			// number of frames per second
float dwTime;			// time elapsed since last second tick
int dwFramesDrawn;		// number of frames drawn since last second tick

LONGLONG perf_cnt;


HDC hdc;
HDC backbuffer_dc;

HBITMAP backbuffer;


char szBuffer [40];


LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprev, PSTR cmdline, int ishow)
{	
    HWND hwnd;
    MSG msg;
    WNDCLASSEX wndclassex = {0};
	
    char class_name[] = "fps";

    wndclassex.cbSize = sizeof(WNDCLASSEX);
    wndclassex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wndclassex.lpfnWndProc = WinProc;
    wndclassex.hInstance = hinstance;
    wndclassex.hIcon = LoadIcon(hinstance,IDI_APPLICATION);
    wndclassex.hbrBackground = NULL;
    wndclassex.lpszClassName = class_name;
    wndclassex.hCursor = LoadCursor(NULL, IDC_ARROW);


    RegisterClassEx(&wndclassex);


    hwnd = CreateWindowEx(WS_EX_APPWINDOW, class_name, "fps test", WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hinstance, NULL);

		if(!hwnd)
		{
			UnregisterClass(class_name,hinstance);
				return EXIT_FAILURE;
		}

    ShowWindow(hwnd, ishow);
    UpdateWindow(hwnd);

	
	
	while(1)	// main window loop
	{
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			if(msg.message == WM_QUIT)
				break;
				
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			QueryPerformanceCounter((LARGE_INTEGER *) &cur_time);
			
			if (cur_time>last_time)
			{
				time_span=(cur_time-last_time)*time_factor;
			
				dwTime+=time_span;
				dwFramesDrawn++;
		
				if (dwTime>=1.0f)
				{
					fps=dwFramesDrawn;
					dwFramesDrawn=0;
					dwTime=0;
				}
			
				BitBlt(backbuffer_dc,0,0,800,600,NULL,0,0,WHITENESS);
			
				TextOut (backbuffer_dc, 100, 100, szBuffer, sprintf (szBuffer, "fps: %d",fps));


								
				//backbuffer to the screen
				BitBlt(hdc,0,0,800,600,backbuffer_dc,0,0,SRCCOPY);
		
				last_time=cur_time;
		
			}
			else
				Sleep(0);
		}	// end of main window else
	}	// end of main window loop


	UnregisterClass(class_name,hinstance);

		return msg.wParam;
}


LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
    PAINTSTRUCT ps;
			
	switch(message)
    {
	    case WM_CREATE:
	    {			
			//checking for QPC
			if (QueryPerformanceFrequency((LARGE_INTEGER *) &perf_cnt))
			{
				time_factor=1.0/perf_cnt;
				QueryPerformanceCounter((LARGE_INTEGER *) &last_time);
			}
			
			hdc = GetDC(hwnd);
			backbuffer_dc = CreateCompatibleDC(hdc);
			backbuffer = CreateCompatibleBitmap(hdc, 800, 600);
			
			backbuffer = (HBITMAP)SelectObject(backbuffer_dc,backbuffer);


			if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDYES)
			{
				//switching to the full screen display mode
				DEVMODE dmScreenSettings;								// device mode
				memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));	// clear memory
				dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// size of devmode structure
				dmScreenSettings.dmPelsWidth = 800;						// selected screen width
				dmScreenSettings.dmPelsHeight = 600;					// selected screen height
				dmScreenSettings.dmBitsPerPel = 32;						// selected bits per pixel
				dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
		
				ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);	    
			}
	    }
	    
	    case WM_KEYDOWN:
	    {
		    if (wparam==VK_ESCAPE)
		    {
				ChangeDisplaySettings(NULL,0);	//switch back to the window mode
				PostQuitMessage(0);
			}
		}
		
		case WM_PAINT:
			BeginPaint(hwnd, &ps);
			EndPaint(hwnd, &ps);
				return 0;
				

		case WM_CLOSE:
		case WM_DESTROY:
		{
			ChangeDisplaySettings(NULL,0);	//switch back to the window mode
			
			PostQuitMessage(0);
				return 0;
		}
		break;
    
	}

    return(DefWindowProc(hwnd, message, wparam, lparam));
}



ps. forgive me if the code isn't formated extremally well, it's the first time i put source here
Advertisement
I would move the QPC detection and time_factor initialisation out of the WM_CREATE section and to the start of WinMain where you initialise all of the other variables.

I can't be entirely sure because my Windows API knowledge is weak, but I think this might be related to how you initialise your timer in the WM_CREATE section (the last parameter of CreateWindow being NULL has some effect on WM_CREATE being called or not I think).

hth
F451

*Edit* Not the above. The code above runs with 200fps fullscreen and 1500fps windowed as is. The problem is you are missing two style settings (WS_CLIPSIBLINGS | WS_CLIPCHILDREN) on your CreateWindow call. Change it to this:

hwnd = CreateWindowExA(WS_EX_APPWINDOW, class_name, "fps test", WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, SCREENWIDTH, SCREENHEIGHT, NULL, NULL, hinstance, NULL);

and it will run the same FPS in both windowed and fullscreen modes.

[Edited by - Fahrenheit451 on November 25, 2005 6:18:48 AM]
You are using GDI, which I don't think cares about fullscreen or not. It's possible you are in 16 bit mode when windowed which would probably speed things up. Also, when windowed you might not be displaying the full 800x600, I forget what the WS_* flags all do, look up AdjustWindowRectEx in the msdn for info on how to create a windowed display 800x600 area. It could also be that your refresh rate changes when you change display modes, dmScreenSettings.dmDisplayFrequency.
I'd appiciate a lot if someone using Visual C++ could compile and test the fps results.

I suspect the copiler and your answers would help me a lot!

Thank you

Peter
Peter, I used Visual C++ to run the code you gave above. Works fine with a minor fix. See my note above for that. Thanks.
Kind of bumping this subject.

Bezben, thank you for your suggestions but nothing worked.

Fahrenheit451, that CreateWindowExA didn't change anything actually.

I managed to compile the code using MS Visual C++ 6 over the weekend and the problem still appears. This way compiler faults are excluded.

I also noticed (perhaps that's some lead) that changing display mode works fine (fps rate higher in full screen) when rendering graphics with OpenGL. The problem with lower fps rate occurs when switching uder Win32 only.

The CDS code is taken from NeHe tutorials.

Any suggestions will be highly appriciated.

Peter
Quote:Original post by ursus
Fahrenheit451, that CreateWindowExA didn't change anything actually.


That's odd. Sorry to hear that. For me it resolved the issue. I initially had 200fps fullscreen, and 1500 windowed. With the inclusion of the two WS_CLIP* parameters I went to 1500fps for both. Let me retest tonight when I get home to see if anything else was the issue, and send you my project settings.

F451

Edit. Ok I figured out what else I did. I moved the "if fullscreen" settings block from out of the WM_CREATE section and put it *before* the CreateWindow call. WM_CREATE is called after the window is created, so the fullscreen settings and the ChangeDisplaySettings call come too late to be properly effective.

The first part of your WinMain should look like this.
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprev, PSTR cmdline, int ishow){	    HWND hwnd;    MSG msg;    WNDCLASSEX wndclassex = {0};	    char class_name[] = "fps";    wndclassex.cbSize = sizeof(WNDCLASSEX);    wndclassex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;    wndclassex.lpfnWndProc = WinProc;    wndclassex.hInstance = hinstance;    wndclassex.hIcon = LoadIcon(hinstance,IDI_APPLICATION);    wndclassex.hbrBackground = NULL;    wndclassex.lpszClassName = class_name;    wndclassex.hCursor = LoadCursor(NULL, IDC_ARROW);    RegisterClassEx(&wndclassex);	// F451 - start 11/25/05 - moved from WM_CREATE in WinProc section	if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?",MB_YESNO|MB_ICONQUESTION)==IDYES)	{		//switching to the full screen display mode		DEVMODE dmScreenSettings;								// device mode		memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));	// clear memory		dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// size of devmode structure		dmScreenSettings.dmPelsWidth = 800;						// selected screen width		dmScreenSettings.dmPelsHeight = 600;					// selected screen height		dmScreenSettings.dmBitsPerPel = 32;						// selected bits per pixel		dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;			ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);	    	}	// F451 - end 11/25/05    hwnd = CreateWindowEx(WS_EX_APPWINDOW, class_name, "fps test", WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hinstance, NULL);		if(!hwnd)		{			UnregisterClass(class_name,hinstance);				return EXIT_FAILURE;		}


Apologies for not spotting the other change I made.

hope that helps
F451

[Edited by - Fahrenheit451 on November 28, 2005 9:09:48 PM]
yes! YES! This is it !!!

Finally things are the way they should be! Thank yo very much Fahrenheit451. I can't even describe how happy I am to see the full screen performance working properly.

Weird mistake. I was looking for an answer for over 3 months now. Respectful bow my firend

This topic is closed to new replies.

Advertisement