[SOLVED] problem while changing windowed/fullscreen mode

Started by
16 comments, last by fabry 14 years, 9 months ago
Hi, I'm developing a 2d game engine with directx and cpp language. By pressing the F2 key the player can switch between fullscreen and windowed mode. I correctly use the TestCooperativeLevel and device Reset, releasing and reacquiring all textures, I obtain the switch between the two modes but i have a problem when i change the window style. The code, (inside an Update function called every window main loop) after device reset and objects reallocation is as follow:

if(this->full_screen_mode){
   ::SetWindowLongPtr(this->hWnd, GWL_EXstyle, 0);
   ::SetWindowLongPtr(this->hWnd, GWL_style, WS_EX_TOPMOST | WS_VISIBLE | WS_POPUP);
}
else{
   ::SetWindowLongPtr(this->hWnd, GWL_EXstyle, 256);
   ::SetWindowLongPtr(this->hWnd, GWL_style, WS_OVERLAPPEDWINDOW);
}

::SetWindowPos(this->hWnd, NULL, CW_USEDEFAULT, CW_USEDEFAULT, this->Get_screen_width(), 
    this->Get_screen_height(), SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW);


I start in windowed mode and send to a text file the GWL_style and GWL_EXstyle by using getWindowLong, the value of GWL_EXstyle is 256 as set by the initial CreateWindow winapi. After switching to full screen mode i find the correct value for GWL_style but the value 8 for GWL_EXstyle in place of 0. Then, switching to windowed mode again i find inside the logfile the GWL_style with the correct value but the GWL_EXstyle with value 264 (=256 + 8 (00001000 binary coded)) in place of 256. Why are my settings ignored by windows? A collateral effect is that after switching from the initial windowed mode to fullscreen and windowed mode again, the fps drops from 60fps to 34fps, my window remains always on top and if i press ALT-TAB my window loose focus but the other windows remains always behind it. I've tryed lots of changes without having the right result. I'm coming crazy! Thank you for your help (i'm sorry, this problem was formerly posted in the wrong section "General Programming", now i moved it into the more appropriate Directx section; i've tried to find between other posts but anyone seems to have the same problem) [Edited by - fabry on June 25, 2009 4:53:52 AM]
Advertisement
8 in the extended style is WS_EX_TOPMOST. That explains why your window is always on top. As for why you get a lower FPS; is the window the correct size? You'll probably have to resize the window when going to windowed mode, since you'll need to account for the window borders (Much like how you need to use AdjustWindowRectEx when you create the window).

Also, this looks wrong to me:
::SetWindowLongPtr(this->hWnd, GWL_style, WS_EX_TOPMOST | WS_VISIBLE | WS_POPUP);
You can't mix extended and non-extended styles like that.
Hi Steve, thank you very much for your quickly answer.

mmmhhhh the size should be correct, i use the same variables, screen_width and screen_height, used inside the initialization function (the one which contains the CreateWindow). I sent the two values to the log file and seem to be ok (1024x768).
I've also tryed to reduce the size of the window with ::SetWindowPos(.......,screen_width - 200, screen_height - 200,....) to see what happens but i still obtain a maximized window. Windows simply ignore the setting.

Is the ::SetWindowPos ok for resizing the window? Or it must be replaced by the AdjustWindowRectEx api?

I'll take a deeper look at the ::SetWindowLongPtr api documentation

What sounds strange to me is that while toggling to windowed mode, I change the GWL_EXstyle to 256 to avoid the flag WS_EX_TOPMOST but the log reports to me that the GWL_EXstyle is still 264 so the flag i set
Quote:Original post by fabry
Hi Steve, thank you very much for your quickly answer.

mmmhhhh the size should be correct, i use the same variables, screen_width and screen_height, used inside the initialization function (the one which contains the CreateWindow). I sent the two values to the log file and seem to be ok (1024x768).
I've also tryed to reduce the size of the window with ::SetWindowPos(.......,screen_width - 200, screen_height - 200,....) to see what happens but i still obtain a maximized window. Windows simply ignore the setting.

Is the ::SetWindowPos ok for resizing the window? Or it must be replaced by the AdjustWindowRectEx api?
SetWindowPos is fine; but if your window has borders (I.e. has the WS_OVERLAPPED style) you should be using AdjustWindowRectEx to determine the correct window size to use - If you pass 1024,768 to CreateWindowEx, the window is 1024x768, but the client area will be something like 1018x742 because of the size of the borders and title bar. That means that if your backbuffer is 1024x768, you don't have a 1 to 1 mapping of backbuffer pixels to window pixels, which can give you weird effects, and totally breaks picking.
When you're specifying the size for the window with SetWindowPos(), you are removing the SWP_NOSIZE flag, right?

Quote:Original post by fabry
What sounds strange to me is that while toggling to windowed mode, I change the GWL_EXstyle to 256 to avoid the flag WS_EX_TOPMOST but the log reports to me that the GWL_EXstyle is still 264 so the flag i set
Why do you set it to 256? You should be using WS_EX_WINDOWEDGE or nothing at all - depending on what you want.

My fullscreen toggle code is:
// Change window style to remove border in fullscreen modeDWORD dwStyle;if(m_thePresentParams.Windowed)	dwStyle = (WS_OVERLAPPEDWINDOW | WS_VISIBLE) & ~WS_THICKFRAME;else	dwStyle = WS_POPUP;SetWindowLongPtr(m_hWnd, GWL_STYLE, dwStyle);// Make sure the changes are flushedSetWindowPos(m_hWnd, NULL, 0, 0, 0, 0,	SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
I never touch the extended style, because my code doesn't need any extended style bits set.
Hi Steve, I have no need in my code to change the size of the window. I have a resolution of 1024x768 and i'd like to use the same resolution as for fullscreen as for the size of the window; the size is initially set in the winmain CreateWindow and i'd like that the winodowed mode maintains the same size (borders and titlebar included). I call the SetWindowPos only for having the changes made by SetWindowLongPtr flushed.

I changed my code according to your advices and now the style changing during toggle is made as you do in your engine but I always have the same problem with some important changes:

1° case: start in windowed mode, 60fps, the window is 1024x768 and hides the win taskbar, it's big as the entire screen. If I press ALT-TAB another window get the focus and correctly covers my window. I ALT-TAB to gain focus again and I double-click on the titlebar of my window. At this point the win taskbar appears at the bottom of the screen cutting the bottom of my, the fps drops from 60 to 34 but ALT-TAB works, my window is covered by another window. I regain focus and i double-click again on my titlebar, my window covers the win taskbar and the frame rate come back from 34 to 60fps. I've also noticed, placing a timer that starts before the device->Present() and stops just after the device->Preset() to calculate the swap time between the front and backbuffer, that when 60fps the swap time is 13ms, when 34fps it raises to 25ms. I don't know the reason because the Presentation interval is always the same.

When at 34fps the sprite objects have a jerkily movements and anyway I have a better fluid motion in windowed mode at initial 60fps than in fullscreen at 50fps.

2° case: start in windowed mode at 60fps, toggle to fullscreen at 50fps and back to windowed mode again with a drop to 34fps with a swap buffers time raised from 13ms to 25ms. In this case, the window remains always on top, if I ALT-TAB the other windows stay behind my window. I formerly changed the extended style (now removed from my code) just for this reason, hoping to prevent this behaviour, unsetting the topmost flag, but as i told, it didn't work, my window was still on top. Now if I'm in windowed mode and I drag my window with one or two borders out of the screen the image starts to flicker and the flickering amount is as more as a bigger portion of the window is outside the edges of the screen (The weird effects you were talking about in your previous post?). It seems like at every frame swap, the images in the front and backbuffer are not aligned.

This is what happens in details during the toggle, I used alt-tab to minimize the window and use Win Spy++ to watch the style and extended style of the window (I cut the WS_MINIMIZE flag because it's due to the alt-tab to watch the Spy++)
- start in winmode with 60fps:
style: 34cb 0000 (WS_CAPTION, WS_VISIBLE, WS_CLIPSIBLING, WS_SYSMENU, WS_OVERLAPPED, WS_MINIMIZEBOX, WS_MAXIMIZEBOX)
ex_style: 0000 0100 (WS_EX_LEFT, WS_LTRREADING, WS_EX_RIGHTSCROLLBAR, WS_EX_WINDOWEDGE)
- hit F2 to toggle to full screen mode with 50fps:
style: b400 0000 (WS_POPUP, WS_VISIBLE, WS_CLIPSIBILINGS)
ex_style: 0000 0008 (WS_EX_LEFT, WS_LTRREADING, WS_EX_RIGHTSCROLLBAR, WS_EX_TOPMOST)
- hit F2 to come back to windowed mode, 34fps, here the problem starts:
style: 34cb 0000 (WS_CAPTION, WS_VISIBLE, WS_CLIPSIBLING, WS_SYSMENU, WS_OVERLAPPED, WS_MINIMIZEBOX, WS_MAXIMIZEBOX)
ex_style: 0000 0108 (WS_EX_LEFT, WS_LTRREADING, WS_EX_RIGHTSCROLLBAR, WS_EX_TOPMOST, WS_EX_WINDOWEDGE)
NOTE: also without change the extended style I find the WS_EX_TOPMOST flag set

I post some code hoping you could help me to understand

winmain.cpp:
int WINAPI WinMain(....){	MSG msg; WNDCLASSEX wc;	HWND hWnd; DWORD dw_style;	//RegisterClass(hInstance);	wc.cbSize=sizeof(WNDCLASSEX);	wc.style=CS_HREDRAW | CS_VREDRAW;		wc.lpfnWndProc=(WNDPROC)WinProc;	wc.cbClsExtra=0;	wc.cbWndExtra=0;	wc.hInstance=hInstance;	wc.hIcon=NULL;	wc.hCursor=LoadCursor(NULL, IDC_ARROW);	wc.hbrBackground=NULL;	wc.lpszMenuName=NULL;	wc.lpszClassName=g_engine->GetWinTitle();	wc.hIconSm=NULL;	RegisterClassEx(&wc);	//at the beginning g_engine->Get_full_screen_mode() returns false, we start always in windowed mode	if(g_engine->Get_full_screen_mode())		dw_style = WS_POPUP;	else		dw_style = (WS_OVERLAPPEDWINDOW | WS_VISIBLE) & ~WS_THICKFRAME;		//window creation	hWnd=CreateWindow(		g_engine->GetWinTitle(),				//win class		g_engine->GetWinTitle(),				//title bar		dw_style,				//style		CW_USEDEFAULT,			//win x pos		CW_USEDEFAULT,			//win y pos		g_engine->Get_screen_width(),			//width		g_engine->Get_screen_height(),			//height		NULL,					//parent win		NULL,					//menu		hInstance,				//istanza applicazione		NULL);					//win parameters	if(hWnd==NULL)		return 0;		//display win	ShowWindow(hWnd, nCmdShow);	UpdateWindow(hWnd);	//Create an instance of Engine class called g_engine        g_engine = new Engine();		//Game initialization	if(!g_engine->Init(hWnd))		return 0;				bGame_Over=false;		//Message Loop	while( !bGame_Over )	{		if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))		{			TranslateMessage(&msg);			DispatchMessage(&msg);		}				g_engine->Update();		//Process game loop	} //end while true	g_engine->End();			//Game cleanup	delete g_engine;	return msg.wParam;} //WinMain end


Engine class:
Engine::Engine(){	..........	this->deviceLost = false;	this->toggling_WinFullScreenMode = false;}void Engine::Shutdown(void){	bGame_Over = true;}int Engine::Init(HWND hWnd)	//D3D Initialization{	D3DDISPLAYMODE dm; this->hWnd = hWnd;	......	this->d3d->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dm);	//this->p_d3dpp_windowedMode holds Presentation_parameters for windowed mode	ZeroMemory(&(this->p_d3dpp_windowedMode), sizeof(this->p_d3dpp_windowedMode));	this->p_d3dpp_windowedMode.Windowed = true;	this->p_d3dpp_windowedMode.SwapEffect = D3DSWAPEFFECT_DISCARD;	this->p_d3dpp_windowedMode.BackBufferFormat=D3DFMT_UNKNOWN;	this->p_d3dpp_windowedMode.PresentationInterval = D3DPRESENT_INTERVAL_ONE;	this->p_d3dpp_windowedMode.hDeviceWindow = this->hWnd;	//and this->p_d3dpp_fullScreenMode for fullscreen mode	ZeroMemory(&(this->p_d3dpp_fullScreenMode), sizeof(this->p_d3dpp_fullScreenMode));	this->p_d3dpp_fullScreenMode.Windowed = false;	this->p_d3dpp_fullScreenMode.SwapEffect = D3DSWAPEFFECT_DISCARD;	this->p_d3dpp_fullScreenMode.BackBufferFormat=dm.Format;	this->p_d3dpp_fullScreenMode.BackBufferCount = 1;	this->p_d3dpp_fullScreenMode.BackBufferWidth = this->screen_width;	this->p_d3dpp_fullScreenMode.BackBufferHeight = this->screen_height;	this->p_d3dpp_fullScreenMode.PresentationInterval = D3DPRESENT_INTERVAL_ONE;	this->p_d3dpp_fullScreenMode.hDeviceWindow = this->hWnd;		//this->p_d3dpp holds the parameters for device->Reset and device->CreateDevice	if(this->full_screen_mode){		//FULL screen mode		::ShowCursor(FALSE);		this->p_d3dpp = this->p_d3dpp_fullScreenMode;	}	else		this->p_d3dpp = this->p_d3dpp_windowedMode;	//Create device D3D device	this->d3d->CreateDevice(		D3DADAPTER_DEFAULT,		D3DDEVTYPE_HAL,		this->hWnd,		D3DCREATE_SOFTWARE_VERTEXPROCESSING,		&this->p_d3dpp,		&(this->d3ddev));	if(this->d3ddev==NULL){		MessageBox(NULL, "Engine::Init - Error creating D3D Device", "ERROR", MB_OK);		return 0;	}	.... }void Engine::ToggleScreenMode(void){	//function called if F2 key hit by user to toggle between windowed and fullcreen mode	this->full_screen_mode = !this->full_screen_mode;	this->deviceLost = true;	this->toggling_WinFullScreenMode = true;	if(this->full_screen_mode)		this->p_d3dpp = this->p_d3dpp_fullScreenMode;	else		this->p_d3dpp = this->p_d3dpp_windowedMode;}void Engine::Update(){	//Called in the window main loop at every frame	HRESULT result;	//Check if the device is lost (ALT-TAB in fullscreen mode) or user hits F2 for toggling	if(this->deviceLost)	{		result = this->d3ddev->TestCooperativeLevel();		if(result == D3DERR_DEVICELOST){			::Sleep(100);			return;		//leave Update method and go to the win main loop		} //endif(result == D3DERR_DEVICELOST)		if( (result == D3DERR_DEVICENOTRESET) || (this->toggling_WinFullScreenMode) ){			//device->Reset can be tried or user hits F2 key			//Release of all resources and call device->Reset			this->onLostDevice();						result = this->d3ddev->Reset(&this->p_d3dpp);			if(result == D3D_OK){	//Reset is OK				this->deviceLost = false;								//Try to reacquire all resources previously released				if( !this->onResetDevice() ) {					this->Shutdown(); //something wrong, shutdown and kill the application				}				if(this->toggling_WinFullScreenMode) { //if true the user press F2 for toggling mode					this->toggling_WinFullScreenMode = false;					DWORD dwStyle;					if(this->full_screen_mode){	//change style for full screen mode						dwStyle = WS_POPUP;						::ShowCursor(FALSE);					}					else{	//change win style for windowed mode						dwStyle = (WS_OVERLAPPEDWINDOW | WS_VISIBLE) & ~WS_THICKFRAME;						::ShowCursor(TRUE);					}					//change the win style and flush changes					::SetWindowLongPtr(this->hWnd, GWL_STYLE, dwStyle);						::SetWindowPos(this->hWnd, NULL, 0, 0, 0, 0,						SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);				} //endif(this->toggling_WinFullScreenMode)			}			else{ //the device->Reset goes wrong, return, leave Update method and go back to the win main loop				return;			} //endif(result == D3D_OK)		}//endif(result == D3DERR_DEVICENOTRESET)		if(result != D3D_OK){			////something wrong, shutdown and kill the application			this->Shutdown();		} //endif(result != D3D_OK)	} //endif(this->deviceLost) --- end of section that manages the devicelost and the toggle mode 	//Call the extern function Game_Run() wich update 2d objects position according to the keys hit by user	Game_Run();		//it updates objects not managed by the Engine class but managed by the extern functions	//automatically update the objects managed by the Engine class contained inside a std::list object	this->Update2D_Entities();	//Perform collision detection testing, I omitted the code	//update with 60fps timing using a stopwatch of 14ms. If from the previous call the time passed is less than 	//14ms sleep(1) and jump the code below	if (!timedUpdate.stopwatch(14)) {		Sleep(1);	}	else {  //more than 14ms passed before last call, I can write on backbuffer and present the scene		//update input devices and audio system, code omitted		//Render objects		if(this->Start_Render()) //execute this->d3ddev->BeginScene();		{			this->d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 200), 1.0f, 0); //Clear the scene			this->Start_Render2d(); //execute D3DXSprite->Begin(D3DXSPRITE_ALPHABLEND))			this->Draw2D_Entities(); //execute the D3DXSprite->Draw() for the objects managed by the Engine class contained inside a std::list object			Game_Render2d(); //extern function that does the D3DXSprite->Draw() for the objects not managed by the Engine class but managed by the extern functions			this->Stop_Render2d(); //execute D3DXSprite->End();			this->Stop_Render(); //execute the this->d3ddev->EndScene() and the this->d3ddev->Present(NULL, NULL, NULL, NULL);			//if the d3ddev->Present() get back a D3DERR_DEVICELOST =====> this->deviceLost = true;		}				//automatically remove the dead objects managed by the Engine class and contained inside a std::list object		this->Bury2D_Entities();	} //endelse} //End of Engine::Update


[Edited by - fabry on June 23, 2009 2:57:39 AM]
Hi,
also tryed leaving the screen res to 1024x768 but change the game res to 800x600.
I always start in win mode, toggle to fullscreen and go back to window mode: the fps is ok(60) but the window is always on top (i have no code portion for it).

Also tryed to drag the window outside the screen edge. This causes some weird effects, the image flickers and the center of the image is not aligned with the bottom and the top. It doesn't happen when i first start the game but only after coming back to win mode after double toggling from the first win mode and the second full screen mode. Maybe something wrong with the backbuffer? I've tryed different solutions but without a good result.

I posted the code in the previous post.

I hope you can help, thanks in advance...
What CPU, GPU and OS do you have? In windowed mode, Present() causes a BitBlt() from the backbuffer to the window client area, but only if the client area size matches the backbuffer. If the sizes differ, Present() will be forced to call StretchBlt(), which will obviously be slower - perhaps substantially.

So - have you checked that the size of your client area (From GetClientRect()) is always the same as your backbuffer size?
It's a notebook with an Intel Pentium M (centrino running at 1.7Ghz), an integrated GPU Intel 82855 GME Graphics controller running Windows XP Pro.

Between the window mode at the beginning (where all is ok, fps is good, there is no flickering and no weird effects) and the window mode after double toggling, there's no change of the size of the client area and backbuffer, i always use the same variables and I restore the same win styles and d3d settings, for this reason this fact sounds so strange to me.
Anyway i try to send to logfile these details and check again.

Thank you
Quote:Original post by fabry
It's a notebook with an Intel Pentium M (centrino running at 1.7Ghz), an integrated GPU Intel 82855 GME Graphics controller running Windows XP Pro.

Between the window mode at the beginning (where all is ok, fps is good, there is no flickering and no weird effects) and the window mode after double toggling, there's no change of the size of the client area and backbuffer, i always use the same variables and I restore the same win styles and d3d settings, for this reason this fact sounds so strange to me.
Anyway i try to send to logfile these details and check again.

Thank you
That's exactly the sort of spec where I'd expect to see a difference between BitBlt and StretchBlt performance. You could also try explicitly specifying a backbuffer size for windowed mode, in case the backbuffer is being created at say 1024x768 when re-entering windowed mode, but then the window is resized to 1024x768 which will make the client area smaller than that.
Quote:
That's exactly the sort of spec where I'd expect to see a difference between BitBlt and StretchBlt performance. You could also try explicitly specifying a backbuffer size for windowed mode, in case the backbuffer is being created at say 1024x768 when re-entering windowed mode, but then the window is resized to 1024x768 which will make the client area smaller than that

Great!!!!!! The second time i switch to win mode i have the backbuffer at 800x600 and the client area size of 794x575.
Why does it happen if i use the same identical style used in CreateWindow?

This topic is closed to new replies.

Advertisement