VSync/Refresh problem

Started by
6 comments, last by Deathscythe_HC 17 years, 10 months ago
I have a weird problem in my OpenGL application ( which is a game engine ). One of the options in this application is to render in multiple screens at different frame rates with a single game thread ( which is the application main thread ). First of all, I've disabled the vsync option with the GL extension "wglSwapIntervalEXT". Everything works fine here even though there is some screen-shearing ( a understandable problem with the vsync disabled ). Then I coded my own system to synchronize the rendering using the multimedia timer. The timer callback does nothing by itself, it just increments a value by a value determined by the fastest FPS. The main code that chooses if the rendering should be done is called in the main thread. Here again, the rendering works fine if my used-defined vsync is disabled ( but the multimedia timer is still running with a callback that does nothing ). The problem occurs when I enable my user-defined vsync. The screens are not refresh. All the calls to OpenGL ( including glFlush, glFinish and SwapBuffers ) are done at the correct framerate. It looks like Windows does not receive any drawing message to update the screen ( WM_PAINT or something like that ) in windowed mode and in full screen. I've run my application in gDebugger ( a great OpenGL debugging tool, I migh add ) and I see the OpenGL frame counter is always at 0. But as soon as I resize the window, the screen is updated for 1 frame. Like I said, if I disable my vsync code, the screens are updated correctly. Anyone can shed some light on this problem??? I've been trying to find the probleme for the last 2 weeks or so... Thankx!
Advertisement
The contents of the frame buffer are displayed in a window with a call to SwapBuffers, not a message like WM_PAINT (although WM_PAINT can call the render code to display a frame).

Are you sure you're not accidentally not calling it when you enable your vsync code?
I've checked and I'm really sure that I call SwapBuffers() after each render. The content of the framebuffer is displayed only after I resized the window. When I put another window in front the application window and I return to my application, the screen is blank and stays that way until I force a redraw by resizing it.

While I checked to be sure that SwapBuffers was call, I did another test. I run my application with different fps. Down to 13 fps, the screen is not refreshed but I can see the first rendered frame. For the framerates of 12 and 11 fps, I cannot even seen the content of the first rendered frame until I resize the window. But from 10 to 1 fps, the screen is updated correctly at each frame ( the bug disappears )... It gives me an headache...
Hmm... I'm afraid you'll have to post some code in order for me to be any more helpful.

Can't think of anything else off-hand...
That's gonna be a problem... I've been working on this engine for the last year. So there is a lot code... I don't think it would be good to post the entire rendering code that is contained in more than 50 files ( and that's just the renderer, not the rendering data structures ). If you have any idea of something specific you want to see, I'm sure I could do something...
Try testing. Setup keys so you can execute glFinish with one key and SwapBuffers with another. Set the front and back buffers to distinct images, i.e. two differant solid colors, then see if SwapBuffers actually does anything on it's own with vertical sync disabled. Execute the SwapBuffers and see if the screen changes. If it doesn't then try a glFinish. If that causes the screen to change then the SwapBuffers is simply queued pending a glFinish and you need to move your glFinish after the SwapBuffers.

As far as code your message loop would be a good start. If your timer message is just updating a count then it isn't clear exactly how you are rendering the frame. Are you peeking for messages and every pass checking the time? If so then what is the point of the timer messages since you are going to be pegged at 100% CPU. If you are actually waiting on messages then you really need to check if you should render on every message. If you're only checking on certain messages, i.e. WM_PAINT, then you're only going to render when those messages arrive. Since the time only changes on the timer messages it would be a good idea to check if it's time to render when you process that message rather than just updating the count.
Keys to success: Ability, ambition and opportunity.
Quote:
Try testing. Setup keys so you can execute glFinish with one key and SwapBuffers with another. Set the front and back buffers to distinct images, i.e. two differant solid colors, then see if SwapBuffers actually does anything on it's own with vertical sync disabled. Execute the SwapBuffers and see if the screen changes. If it doesn't then try a glFinish. If that causes the screen to change then the SwapBuffers is simply queued pending a glFinish and you need to move your glFinish after the SwapBuffers.


I tested everything I could think in my render to try to pinpoint the problem. Without a call to SwapBuffers(), the screen is never updated (with or without vsync). I tried to put glFinish() before and after SwapBuffers(). I even coded a debug console that sends debugs string over the network to see if the renderer is called without having asserting message box cluttering the application. After, I played with the HDC by getting and releasing a new one at each rendered frame. I'm beginning to run out of idea for testing...

Quote:As far as code your message loop would be a good start.


Well, there it is with some comments:

	while( b_Done == DSFALSE )	{		if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) != FALSE )		{			if( msg.message == WM_QUIT )			{				b_Done = DSTRUE;			}			else			{				TranslateMessage( &msg );				DispatchMessage( &msg );			}		}		else		{			// HardwareStartFrame() & HardwareEndFrame() are just			// for performance reviewing purposes using the RTDSC.			HardwareManager::HardwareStartFrame();			// Update inputs properties & check vsync			HardwareManager::HardwareMain();			if( HardwareManager::CanApplicationBeRunned() != DSFALSE )			{				po_Application->Main();			}			HardwareManager::HardwareEndFrame();			if( po_Application->IsApplicationToBeTerminated() != DSFALSE )			{				PostQuitMessage( 0 );			}		}	}


And this is the window message callback:

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ){	switch ( message ) 	{/*	case WM_PAINT:		{			PAINTSTRUCT ps;			HDC hdc;			hdc = BeginPaint( hWnd, &ps );			EndPaint( hWnd, &ps );		}		break;*/	case WM_DESTROY:		PostQuitMessage( 0 );		break;	case WM_MOUSEMOVE:		Mouse::UpdateMousePosition( Vector2D( ( Real ) LOWORD( lParam ), ( Real ) HIWORD( lParam ) ) );		break;	case WM_LBUTTONDOWN:		Mouse::UpdateMouseButtonDown( Mouse::MBID_LEFT );		break;	case WM_LBUTTONUP:		Mouse::UpdateMouseButtonUp( Mouse::MBID_LEFT );		break;	case WM_RBUTTONDOWN:		Mouse::UpdateMouseButtonDown( Mouse::MBID_RIGHT );		break;	case WM_RBUTTONUP:		Mouse::UpdateMouseButtonUp( Mouse::MBID_RIGHT );		break;	case WM_MBUTTONDOWN:		Mouse::UpdateMouseButtonDown( Mouse::MBID_MIDDLE );		break;	case WM_MBUTTONUP:		Mouse::UpdateMouseButtonUp( Mouse::MBID_MIDDLE );		break;	case WM_KEYDOWN:		Keyboard::UpdateKeyboardKeyDown( ( u16 ) wParam );		break;	case WM_KEYUP:		Keyboard::UpdateKeyboardKeyUp( ( u16 ) wParam );		break;/*	ToDo: Fix mouse wheel message	case WM_MOUSEWHEEL:		if( HIWORD( wParam ) > 0 )		{			Mouse::UpdateMouseWheel( Mouse::MWS_UP );		}		else		{			Mouse::UpdateMouseWheel( Mouse::MWS_DOWN );		}		break;*/	case WM_SIZE:		{			DynamicArray< RegisteredDisplay* >::Iterator o_Iter = go_RegisteredDisplayArray.GetIteratorStartPoint();			while( o_Iter != go_RegisteredDisplayArray.GetIteratorEndPoint() )			{				if( ( *o_Iter )->mo_WindowHandle == hWnd )				{						// Width = LOWORD( lParam ), Height = HIWORD( lParam )					( *o_Iter )->mpo_Display->SetDisplayDimensions( Vector2D( ( Real ) LOWORD( lParam ), ( Real ) HIWORD( lParam ) ) );					break;				}				o_Iter++;			}		}		break;	default:		return DefWindowProc( hWnd, message, wParam, lParam );	}	return 0;}
Well... I found out the problem... there was two problems. First, my vsync code was not entirely correct: as soon I debugged line by line, the time between each frame went from milliseconds to seconds so the code would pass over the error. And a memory-overwritting bug was causing other kinds of problem when I was debugging. Thankx anyways for your help... Now, if I could find a way to track a bug concerning the NVidia OpenGL driver I have from time to time... I've runned some memory & error checking program and they my application is OK... weird..

This topic is closed to new replies.

Advertisement