Sign in to follow this  

Cant 'restore' window after full screen minimize

This topic is 3625 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

I'm running into a funny problem where I cannot restore the window after minimizing from full screen. After the device is lost, it goes into a loop periodically checking TestCooperativeLevel, but for some reason it never never restores the window and never changes from the 'D3DERR_DEVICENOTRESET' state.
#pragma warning (disable : 4996)

#define WIN32_LEAN_AND_MEAN
#define DIRECTINPUT_VERSION 0x0800
#define D3D_DEBUG_INFO
//#define _SCL_SECURE 0 //dont check iterators, faster performance

//direct 3d libs
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9d.lib")

//direct input libs
#pragma comment(lib, "dinput8")
#pragma comment(lib, "dxguid")

#include <d3d9.h>
#include <d3dx9.h>
#include <dinput.h>
#include <windows.h>

#include <ctime>
#include <iostream>
using namespace std;

#define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }
#define SAFE_DELETE(p)	{ if(p) { delete (p); (p)=NULL; } }

//globals
bool quit = false;
HANDLE hRenderThread = NULL;
HWND hWnd = NULL;
LPDIRECT3DDEVICE9 pDevice = NULL;
LPDIRECT3D9 pD3D = NULL;
D3DPRESENT_PARAMETERS dx_PresParams;

//forward decl
void MakeDirectXWindow(const char *windowTitle, bool windowed, int width = 640, int height = 480);
DWORD WINAPI RenderThread(LPVOID lpParameter);
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void InvalidateDeviceObjects();
void RestoreDeviceObjects();
void Cleanup();
void WaitForDevice();
void Quit(int code = 0){ Cleanup(); exit(code); }

int main(int argc, char *argv[])
{
	hRenderThread = CreateThread(NULL, 0, RenderThread, NULL, 0, NULL);

	clock_t lastTick = 0;
	while (!quit)
	{
		clock_t tick = clock();
		if (tick - lastTick >= 30 )
		{
			//CODE HERE: check for input with directinput, do logic and networking..

			lastTick = tick;
		}
	}

	WaitForSingleObject(hRenderThread, INFINITE);
	return 0;
}

DWORD WINAPI RenderThread(LPVOID lpParameter)
{
	MakeDirectXWindow("Simple Framework", false);

	while(!quit)
	{
		MSG msg;
		if(PeekMessage(&msg, hWnd,0,0,PM_REMOVE))
			DispatchMessage(&msg);

		pDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(0,0,0,1), 1.0f, 0);
		pDevice->BeginScene();

		//CODE HERE: scene rendering code

		pDevice->EndScene();
		
		if( pDevice->Present(NULL, NULL, NULL, NULL) != D3D_OK )
			WaitForDevice();
	}
	Cleanup();
	ExitThread(0);
}

LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	//if (msg == WM_KEYDOWN), dont process input in the render thread
	if (msg == WM_DESTROY || msg == WM_CLOSE ) 
	{
		OutputDebugString("Quiting...");
		quit = true;
	} else return DefWindowProc(hWnd, msg, wParam, lParam);
}

void WaitForDevice()
{
	cout << "Device lost" << endl;
	InvalidateDeviceObjects();
	do {
		Sleep(100);
		if (quit) return;
	} while( pDevice->TestCooperativeLevel() != D3DERR_DEVICENOTRESET );

	if (D3D_OK != pDevice->Reset(&dx_PresParams) )
		cout << "Unable to reset device!" << endl;
	else {
		RestoreDeviceObjects();
		cout << "Device reset" << endl;
	}
}

void InvalidateDeviceObjects()
{
	//CODE HERE: OnLostDevice and/or safe release
}

void RestoreDeviceObjects()
{
	//CODE HERE: OnResetDevice and/or create
}

void Cleanup()
{
	//CODE HERE: safe release / delete /free
	SAFE_RELEASE(pDevice);
	SAFE_RELEASE(pD3D);
}

void MakeDirectXWindow(const char *windowTitle, bool windowed, int width, int height)
{
	WNDCLASSEX wnd_Structure;
	wnd_Structure.cbSize = sizeof(WNDCLASSEX);
	wnd_Structure.style = CS_HREDRAW | CS_VREDRAW;
	wnd_Structure.lpfnWndProc = WindowProcedure;
	wnd_Structure.cbClsExtra = 0;
	wnd_Structure.cbWndExtra = 0;
	HINSTANCE hInst = GetModuleHandle(NULL);
	wnd_Structure.hInstance = hInst;
	wnd_Structure.hIcon = LoadIcon(hInst, IDI_APPLICATION);
	wnd_Structure.hIconSm = NULL;
	wnd_Structure.hCursor = NULL;
	wnd_Structure.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
	wnd_Structure.lpszMenuName = NULL;
	wnd_Structure.lpszClassName = "WindowClassName";
	
	RegisterClassEx(&wnd_Structure);
	DWORD style;

	int screenWidth = GetSystemMetrics(SM_CXSCREEN),
		screenHeight = GetSystemMetrics(SM_CYSCREEN);
	int ul_x=0, ul_y = 0;

	if (!windowed)
	{
		width = screenWidth;
		height = screenHeight;
		style = WS_POPUP | WS_VISIBLE;
	} else {
		ul_x = (screenWidth - width)/2;
		ul_y = (screenHeight - height)/2;
		style = WS_MAXIMIZE | WS_MAXIMIZEBOX  | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE;
	}

	hWnd = CreateWindowEx(NULL, "WindowClassName", windowTitle, 
			style, ul_x, ul_y, width, height, NULL, NULL, GetModuleHandle(NULL), NULL);

	pD3D = Direct3DCreate9(D3D_SDK_VERSION);
	if (pD3D == NULL){
		printf("Direct3D9 runtime not installed.");
		Quit();
	}

	ZeroMemory( &dx_PresParams, sizeof(dx_PresParams) );
	dx_PresParams.BackBufferFormat = D3DFMT_UNKNOWN;
	dx_PresParams.BackBufferCount = 1;
	dx_PresParams.MultiSampleType = D3DMULTISAMPLE_4_SAMPLES;
	dx_PresParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
	dx_PresParams.hDeviceWindow = hWnd;
	dx_PresParams.Windowed = windowed;
	dx_PresParams.EnableAutoDepthStencil = TRUE;
	dx_PresParams.AutoDepthStencilFormat = D3DFMT_D24S8;//D3DFMT_D16 or D3DFMT_D24S8
	dx_PresParams.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; //D3DPRESENT_INTERVAL_IMMEDIATE;

	//select compatible adapter for full screen
	if (!windowed)
	{
		UINT nModes = pD3D->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8);

		for(UINT i=nModes-1; i>=0; --i)
		{
			D3DDISPLAYMODE eMode;
			if ( pD3D->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, i, &eMode) == D3D_OK )
			{
				char strAdapter[255];
				sprintf(strAdapter, "%d x %d : %d hz\n", eMode.Width, eMode.Height, eMode.RefreshRate );
				int resp = MessageBox(hWnd, strAdapter, "Select Hardware Adapter Mode", MB_YESNOCANCEL );

				if (resp == IDCANCEL) 
					Quit();
				else if (resp == IDYES){
					dx_PresParams.BackBufferWidth = eMode.Width;
					dx_PresParams.BackBufferHeight = eMode.Height;
					dx_PresParams.FullScreen_RefreshRateInHz = eMode.RefreshRate;
					dx_PresParams.BackBufferFormat = eMode.Format;	
					break;
				}
			}
		}
	}

	if (D3D_OK != pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, &dx_PresParams, &pDevice) )
	{
		printf("Unable to create graphics device");
		Quit();
	}	
}

Share this post


Link to post
Share on other sites
You're not processing window messages when waiting for the device to be reset. The window is frozen because of that, so it'll never be restored, so your device will never become un-lost.

Instead of the following:

do {
Sleep(100);
if (quit) return;
} while( pDevice->TestCooperativeLevel() != D3DERR_DEVICENOTRESET );


I'd do this:

do {
MSG msg;
if(GetMessage(&msg, NULL,0,0))
DispatchMessage(&msg);
else
{
quit = true;
return;
}
} while( pDevice->TestCooperativeLevel() != D3DERR_DEVICENOTRESET );


(Untested). That way you're using GetMessage() to block, waiting for a message to arrive, then processing it and then checking the device.

Also, slightly off topic - you should be passing NULL for the HWND parameter to PeekMessage(), otherwise you won't get thread messages like WM_QUIT.

Share this post


Link to post
Share on other sites

This topic is 3625 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this