Jump to content
  • Advertisement
Sign in to follow this  
Deathscythe_HC

OpenGL VSync/Refresh problem

This topic is 4551 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 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!

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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...

Share this post


Link to post
Share on other sites
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...

Share this post


Link to post
Share on other sites
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...

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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;
}


Share this post


Link to post
Share on other sites
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..

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!