depth buffer final flicker

Started by
7 comments, last by synth_cat 17 years, 10 months ago
I've just noticed an annoying problem in my game and was wondering if anyone could help me out. This problem happens whenever I run my app in fullscreen mode. I use the escape key to quit, and just as the program shuts down I see an instantaneous flicker of green. Sometimes the green fills the whole screen, sometimes it is only a bar across the screen, and sometimes it is not there at all. But it always happens for only an instant and only when I exit the program. This only ever happens in fullscreen mode. I know that the green color indicates a problem with the depth buffer not being cleared correctly. Thus, I'm guessing that something about my Windows functions is incorrect, so that D3D is somehow being allowed to keep running a millisecond after the window has killed itself, or something like that. I don't know if this problem represents something dangerous going on in my code. Whether or not it does, it is very irritating and definitely not professional-looking. Does someone know what is going on? Is there some big flaw in my Windows functions? I have isolated the problem in a small piece of code below:


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


LPDIRECT3D9 d3d=0;
LPDIRECT3DDEVICE9 d3ddev=0;
bool quit_game=0;

bool SetupD3D(HWND hWnd)
{
	//create D3D object
	d3d=Direct3DCreate9(D3D_SDK_VERSION);
	if(!d3d) return FALSE;

	//create device
	D3DPRESENT_PARAMETERS d3dpp;
	ZeroMemory(&d3dpp, sizeof(d3dpp));
	d3dpp.BackBufferWidth=800;
	d3dpp.BackBufferHeight=600;
	d3dpp.BackBufferFormat=D3DFMT_A8R8G8B8;
	d3dpp.BackBufferCount=1;
	d3dpp.MultiSampleType=D3DMULTISAMPLE_NONE;
	d3dpp.MultiSampleQuality=0;
	d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
	d3dpp.hDeviceWindow=hWnd;
	d3dpp.Windowed=FALSE;
	d3dpp.EnableAutoDepthStencil=TRUE;
	d3dpp.AutoDepthStencilFormat=D3DFMT_D16;
	d3dpp.Flags=0;
	d3dpp.FullScreen_RefreshRateInHz=D3DPRESENT_RATE_DEFAULT;
	d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_IMMEDIATE;
	d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL ,
		hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING,
		 &d3dpp, &d3ddev);
	if(!d3ddev) {return FALSE;}


    return TRUE;
}

void CleanupD3D()
{
	if(d3ddev) {d3ddev->Release(); }
	if(d3d) {d3d->Release(); }

}

bool DrawD3D()
{
	if(!d3ddev) return FALSE;


	d3ddev->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffccccff, 1.0f, 0);
	d3ddev->Present(0, 0, 0, 0);


	return TRUE;
}


///////////////////////////////////////////////////////////////
///////////////////////////WINDOWS FUNCTIONS///////////////////
///////////////////////////////////////////////////////////////

LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{

	case WM_CLOSE:
		DestroyWindow(hWnd);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_KEYUP:
		if(wParam==VK_ESCAPE)
		{
			PostQuitMessage(0);
		}
		return 0;

	}

	return DefWindowProc(hWnd, msg, wParam, lParam);
}


INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, INT)
{
	WNDCLASS wc;
	wc.cbClsExtra=0;
	wc.cbWndExtra=0;
	wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.hCursor=LoadCursor(0, IDC_ARROW);
	wc.hIcon=LoadIcon(0, IDI_APPLICATION);
	wc.hInstance=hInst;
	wc.lpfnWndProc=WinProc;
	wc.lpszClassName="synth";
	wc.lpszMenuName=0;
	wc.style=CS_HREDRAW | CS_VREDRAW;
	RegisterClass(&wc);
	HWND hwnd=CreateWindow("synth", "the_synth", WS_VISIBLE | WS_OVERLAPPEDWINDOW, 100, 100,
		800, 600, 0, 0, hInst, 0);
    
	//setup stuff
	if(!SetupD3D(hwnd))
	{
		MessageBox(hwnd,"setup_d3d() failed","error",MB_OK);
		quit_game=1;
	}

	MSG msg;
	ZeroMemory(&msg, sizeof(msg));
	while(msg.message!=WM_QUIT)
	{
		if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{

			if(quit_game)
			{
				PostQuitMessage(0);
				break;
			}

			DrawD3D();

		}
	}

	UnregisterClass("synth", hInst);
	CleanupD3D();
	return 0;
}













Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith
Advertisement
Uhm, as far as I remember the green only indicates that nothing has been drawn to notify you of holes or problems with drawing... some time since I last did this.

But either way, this should only be because you run debug DLLs, checking your code then everything seems fine unless it is because some "nitpick value". I cannot recall that this happened to me while running D3D in debug mode, but it could be because of your DISCARD mode.

Try changing the mode, I'm not saying you should keep it, just try and see if it changes, either way it shouldn't be a problem unless D3D debug complains since this shouldn't show up at all when running release.

Only thing that otherwise comes to mind that is remotely possible is that you close the window first and then close D3D, I admit this sounds strange and it probably is too (but once again, some time since I last touched D3D).

(Side note, you should never unregister window classes as stated in the MSDN, they are automatically unregistered and cannot be unregistered, I bet that function returns FALSE)


You could try checking that your window is valid before you render to D3D. Try something simple like setting a global bool in the WM_DESTRPOY handler, and if that bool is true, don't render.
Thanks for the help!

I will definitely look into whether or not debug/retail D3D makes any difference. By the way, Syranide, were you referring to the Direct3D debug/retail options on the Control Panel or did you mean that I should set my compiler to "release" version? Or did you mean that I should change my .lib directory to "d3dx9.lib" instead of "d3dx9d.lib?"

Is it really true that I'm never supposed to unregister my window class? If I chose not to, would it make the app buggy on some OS? On an aside, is it possible that the error I was asking about was caused by this?

UnregisterClass("synth", hInst);CleanupD3D();return 0;


I had never noticed before that I was unregistering my windows class _before_ releasing all the direct3d stuff.

I just have one more question: Is my MsgProc() redundant? Is there really any point in adding code for WM_CLOSE, WM_DESTROY, and WM_QUIT? I remember hearing somewhere that MsgProc() never receives WM_QUIT anyway...

Please forgive me, but I guess everyone has to ask these questions at some point...
Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith
Well, I've done some more testing. I added this check to my main loop in order to
verify if the window handle was valid or not:


if(hwnd){    DrawD3D();}


However, this didn't fix the problem. Evil Steve, does this check even work to say if a window handle is valid once the main loop has started?

I also switched the last two lines of the program so they read:
CleanupD3D();UnregisterClass("synth", hInst);

instead of:
UnregisterClass("synth", hInst);CleanupD3D();


but this didn't solve the problem either.

I'm still not sure what you mean by "debug" lib files, but I'm figuring this must be the problem. Could someone please tell me how to test that? Of course, it is always possible that my Windows code is buggy. I know I probably shouldn't bring that up in the DirectX forum, but it's just that Windows and DirectX seem to get a bit blended together.
Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith
  • You don't have to call UnregisterClass() (Windows will clean it up when your app exits), but it's good practice. If you're going to call it, you should call it once your window has been completely destroyed. So I'd call it after CleanupD3D().
  • if(hwnd) won't work. I'd set a global boolean called g_hwndValid in your WM_DESTROY handler to true, and then do if(g_hwndValid) to test instead.
  • By "debug runtimes", people mean changing the DirectX runtime in the control pannel -> DirectX - but I wouldn't bother. This probably won't show the problem, but that's a bad thing. Since you're using DISCARD (as you should be), it's possible that on some cards/drivers, the backbuffer will be filled with noise or something rather than the contents of the previous frame. So some user may see something as bad or worse than your green screen using release runtimes.
  • By "debug libs", people mean using d3dx9d.lib instead of d3dx9.lib. The former contains more error checking. You can also #define D3D_DEBUG_INFO in your preprocessor definitions (project settings) to view the contents of some DX objects in the debugger (E.g. you can view the presentation parameters in your IDirect3DDevice9).
  • Thanks for the info, Evil Steve!

    I had already done as you suggest; I added a boolean variable that is switched on in the WM_DESTROY event and checked that instead of hwnd, but the problem persisted.

    Is it normal for people to be forced to not use SWAPEFFECT_DISCARD? Most importantly, has any other person actually had this problem before? I'm starting to wonder if the problem might be my video card; I run a GeForce MX440, which I hear is not native to D3D9.

    Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith
    I switched my .lib directory from "d3dx9.lib" to "d3dx9d.lib" and then ran my program with the "Go" button (I'm in VC++6.) The output was as follows (I've taken out non-D3D stuff):

    Direct3D9: :====> ENTER: DLLMAIN(00ae36a0): Process Attach: 00000ca8, tid=00000cac
    Direct3D9: :====> EXIT: DLLMAIN(00ae36a0): Process Attach: 00000ca8
    Direct3D9: (INFO) :Direct3D9 Debug Runtime selected.
    D3D9 Helper: Enhanced D3DDebugging disabled; Application was not compiled with D3D_DEBUG_INFO
    Direct3D9: (INFO) :======================= Hal HWVP device selected

    Direct3D9: (INFO) :HalDevice Driver style 9

    Direct3D9: :Subclassing window 00020128
    Direct3D9: :StartExclusiveMode
    Direct3D9: :WM_DISPLAYCHANGE: 800x600x32

    Direct3D9: :DoneExclusiveMode
    Direct3D9: :INACTIVE: 00000ca8: Restoring original mode (1024x768x22x60) at adapter index 0
    Direct3D9: :WM_DISPLAYCHANGE: 1024x768x32
    Direct3D9: :Unsubclassing window 00020128
    Direct3D9: :====> ENTER: DLLMAIN(00ae36a0): Process Detach 00000ca8, tid=00000cac
    Direct3D9: (INFO) :MemFini!
    Direct3D9: :====> EXIT: DLLMAIN(00ae36a0): Process Detach 00000ca8
    The thread 0xCAC has exited with code 0 (0x0).
    The program 'C:\Program Files\Microsoft Visual Studio\engine_tester\Debug\engine_tester.exe' has exited with code 0 (0x0).

    And that's all.

    Is there anything suspicious-looking in here? Is all this "WM_DISPLAYCHANGE: 1024X768X32" and "window unsubclassing" perhaps the cause of my green flicker problem? What really bothers me is that D3D detects no errors at all.
    Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith
    I just wanted to add that this problem seems to happen more often when I press the ESCAPE key very soon after starting up the program. If I wait a while, the green flicker at the end doesn't happen as often.

    Any ideas?
    Greg Philbrick, Game Developercoming soon . . . Overhauled CellZenith

    This topic is closed to new replies.

    Advertisement