glFlush()?

Started by
7 comments, last by Seabolt 13 years ago
Hey guys, I recently had an issue with glClear not working and dropping my framerate down to about nothing. My program is doing nothing but trying to clear the screen, so this was quite the riddle. I now have it working, but it only works if I call glFlush() after I swap buffers. Now after reading into glFlush() it seems that it causes all functions that have yet to execute to execute. Now I'm wondering, what would cause glClear() not to execute without a glFlush()? I don't want to use glFlush() because I want to eventually multi-thread my program and I know glFlush() conflicts with this. Do you guys have any suggestions?
Perception is when one imagination clashes with another
Advertisement
There's nothing in the opengl specification that would indicate the problem you've been having, so I think trying to look for explanations could be fruitless. I think you've either got a buggy driver or maybe a bad driver install, but you're unlikely to find a rational explanation.

Calling glFlush after swapping buffers shouldn't do anything anyway, because swapping buffers should flush the pipeline anyway, so you'll be flushing an empty pipe.

I wish I had a way for you to fix your problem, but I suspect that this is going to come back and bite you at some point anyway unless you get it worked out without adding weird unexplainable hacks. Have you tried maybe doing a full driver uninstall/reinstall, or trying to install an older driver version?
[size=2]My Projects:
[size=2]Portfolio Map for Android - Free Visual Portfolio Tracker
[size=2]Electron Flux for Android - Free Puzzle/Logic Game
I now have it working, but it only works if I call glFlush() after I swap buffers.[/quote]What do you mean by "it only works if"? The screen doesn't get cleared if you don't flush?

Can you post your main/rendering loop?
Yeah it doesn't clear otherwise. And its drops framerate a to unusable. Posting now. It's broken up into a lot of pieces so please be patient.




Here's WinMain.cpp




// WinMain
// - The first function called by windows; serves as the main loop for the program
int APIENTRY
WinMain( HINSTANCE hInstance, // The current instance of the program
HINSTANCE hPrevInstance, // The previous instance of the program
LPSTR lpCmdLine, // Any command line arguments
int nCmdCount ) // How many arguments the are
{
// Save our global copies
g_hInstance = hInstance;

// Create a window
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = (WNDPROC)MainWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = (HCURSOR)LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = TEXT("Thunderclad Engine"); // Should be unique
wcex.hIconSm = NULL;

// Select window styles
UINT unStyle,unStyleX;
unStyleX = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style
unStyle = WS_OVERLAPPEDWINDOW;

// Describe our window placement
WINDOWPLACEMENT wndPlacement;
wndPlacement.length = sizeof(WINDOWPLACEMENT);
wndPlacement.ptMaxPosition.x = 0;
wndPlacement.ptMaxPosition.y = 0;
wndPlacement.ptMinPosition.x = 0;
wndPlacement.ptMinPosition.y = 0;
wndPlacement.rcNormalPosition.bottom = g_nWindowHeight;
wndPlacement.rcNormalPosition.left = 0;
wndPlacement.rcNormalPosition.top = 0;
wndPlacement.rcNormalPosition.right = g_nWindowWidth;

// Create our instance of our main window
g_cWindow.Init( g_hWnd,
wndPlacement,
&wcex,
unStyle,
unStyleX,
g_nWindowWidth,
g_nWindowHeight,
TEXT("Thunderclad Engine"),
g_hInstance );

// Initialize the game here
CGame::GetInstance()->Initialize();

// Start the message loop
MSG msg;
while( CGame::GetInstance()->IsGameActive() )
{
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
if( msg.message == WM_QUIT )
{
break;
}

TranslateMessage( &msg );
DispatchMessage( &msg );
}

if( CGame::GetInstance()->IsGameActive() )
{
CGame::GetInstance()->Update();
CGame::GetInstance()->Render();
}
}

// Clean up our classes
CGame::GetInstance()->Destroy();
CDeviceManager::GetInstance()->Destroy();
g_cWindow.Destroy();

// return from the program
return msg.wParam;
}

// MainWndProc
// - This will be the message proc for the main window
LRESULT CALLBACK
MainWndProc( HWND handleWindow, // The handle to the window
UINT unMessage, // The message to process
WPARAM wParam, // An additional parameter
LPARAM lParam ) // An additional parameter
{
g_hWnd = handleWindow;

switch( unMessage )
{
case WM_CREATE:
g_cWindow.SetWindowHandle( g_hWnd );
g_cWindow.SetHDC( GetDC( g_hWnd ) );
CDeviceManager::GetInstance()->Initialize( &g_cWindow );
break;
case WM_SIZE:
// Resize the window
CDeviceManager::GetInstance()->Resize( LOWORD( lParam ),
HIWORD( lParam ) );
return 0;
break;
case WM_CLOSE:
// Free up resources if the red x is pressed
CGame::GetInstance()->Destroy();
CDeviceManager::GetInstance()->Destroy();
g_cWindow.Destroy();

break;
default:
return DefWindowProc( g_hWnd,
unMessage,
wParam,
lParam );
}

return 0;
}







Here's my window class:



void
CWindow::Init( HWND &out_handleWindow, // The handle to the window
WINDOWPLACEMENT in_wndPlacement, // The class that describes the window's placement
const WNDCLASSEX* in_wndClassDescription, // The class that describes the class's functionality
UINT in_unWindowStyle, // The window style
UINT in_unWindowExStyle, // The windowEx style
int in_nWindowWidth, // The window width
int in_nWindowHeight, // The window height
LPCWSTR in_szProgramName, // The name of the program
HINSTANCE in_handleCurrentInstance ) // The current instance of the program
{

// Store our copies
SetWindowWidth( in_nWindowWidth );
SetWindowHeight( in_nWindowHeight );
// Store our copies of relevant info
m_wndClassDescription = *in_wndClassDescription;
m_handleInstance = in_handleCurrentInstance;
m_lpWindowName = in_szProgramName;
m_unWindowStyle = in_unWindowStyle;
m_unWindowStyleEX = in_unWindowExStyle;

// First we must register the class
assert( RegisterClassEx( &m_wndClassDescription ) != 0 );

RECT windowRect; // Grabs Rectangle Upper Left / Lower Right Values
windowRect.left=(long)0; // Set Left Value To 0
windowRect.right=(long)GetWindowWidth(); // Set Right Value To Requested Width
windowRect.top=(long)0; // Set Top Value To 0
windowRect.bottom=(long)GetWindowHeight(); // Set Bottom Value To Requested Height

// Get a pixel perfect window
AdjustWindowRectEx( &windowRect, m_unWindowStyle, FALSE, m_unWindowStyleEX );

// Then we must create the window from the data provided;
SetWindowHandle( CreateWindowEx( m_unWindowStyleEX,
m_wndClassDescription.lpszClassName,
in_szProgramName,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | in_unWindowStyle,
0,
0,
GetWindowWidth(),
GetWindowHeight(),
NULL,
NULL,
m_handleInstance,
NULL ) );

assert( GetWindowHandle() != NULL );


// Show the window and start updating it
ShowWindow( GetWindowHandle(), SW_SHOW );
UpdateWindow( GetWindowHandle() );
}





Here's my DeviceManager



//////////////////////////////////////////////////////////////////////////
// Function Definitions
//////////////////////////////////////////////////////////////////////////
STATUS
COpenGLDeviceManager::Initialize( CWindow* programWindow )
{
m_bIsFullScreen = programWindow->IsFullScreen();

//////////////////////////////////////////////////////////////////////////
// Platform Specific Initialization (Windows)
#if USING_WINDOWS

// Store the HWND
m_handleWindowHandle = programWindow->GetWindowHandle();

// Do a NULL check if we are in Debug
ASSERT_NULL( m_handleWindowHandle );

// Get the Device Context
m_handleDeviceContext = programWindow->GetHDC();

// Null check the DC
ASSERT_NULL( m_handleDeviceContext );

//////////////////////////////////////////////////////////////////////////
// Set the pixel format
m_tPixelFormat.nSize = sizeof( PIXELFORMATDESCRIPTOR ); // Size of the PFD
m_tPixelFormat.nVersion = 1; // Set the version number
m_tPixelFormat.dwFlags = PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
m_tPixelFormat.iPixelType = PFD_TYPE_RGBA; // Set the color format
m_tPixelFormat.cColorBits = 32; // Set the color depth
m_tPixelFormat.cDepthBits = 24; // Set the depth buffer depth
m_tPixelFormat.cStencilBits = 8; // Set the stencil buffer depth
m_tPixelFormat.iLayerType = PFD_MAIN_PLANE; // Set the layer for the app

// See if there is a pixel format that will match our requests
int nPixelFormat = 0;
ASSERT_FALSE( nPixelFormat = ChoosePixelFormat( m_handleDeviceContext,
&m_tPixelFormat ) );

ASSERT_FALSE( SetPixelFormat( m_handleDeviceContext,
nPixelFormat,
&m_tPixelFormat ) );
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
// So far so good... Now we try to create our RenderContext (HRC)
m_handleGLRenderContext = wglCreateContext( m_handleDeviceContext );
ASSERT_NULL( m_handleGLRenderContext );

// See if the tempContext will work
ASSERT_FALSE( wglMakeCurrent( m_handleDeviceContext, m_handleGLRenderContext ) );

//GLenum error = glewInit();
//if( error != GLEW_OK )
//{
// fprintf(stderr, "Error: %s\n", glewGetErrorString(error));
//}

//if( wglewIsSupported( "WGL_ARB_create_context" ) == 1 )
//{
// // Define our attributes for using OpenGL 3.0 and forward
// int attribs[] = {
// WGL_CONTEXT_MAJOR_VERSION_ARB, 3,//we want a 3.0 context
// WGL_CONTEXT_MINOR_VERSION_ARB, 0,
// //and it shall be forward compatible so that we can only use up to date functionality
// WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
// 0}; //zero indicates the end of the array

// ASSERT_FALSE( wglMakeCurrent( m_handleDeviceContext, NULL ) );
// ASSERT_FALSE( wglDeleteContext( m_handleGLRenderContext ) );

// m_handleGLRenderContext = wglCreateContextAttribsARB( m_handleDeviceContext, 0, attribs );
// ASSERT_NULL( m_handleGLRenderContext );
// ASSERT_FALSE( wglMakeCurrent( m_handleDeviceContext, m_handleGLRenderContext ) );
//}
////////////////////////////////////////////////////////////////////////////
#endif

Resize( programWindow->GetWindowWidth(), programWindow->GetWindowHeight() );

return OK;
}





STATUS
COpenGLDeviceManager::Present()
{
//////////////////////////////////////////////////////////////////////////
// Platform Specific Present
#if USING_WINDOWS

glPopMatrix();
ASSERT_FALSE( SwapBuffers( m_handleDeviceContext ) );

#else
#endif
//////////////////////////////////////////////////////////////////////////
return OK;
}






And here's the Renderer



//////////////////////////////////////////////////////////////////////////
// Function Definitions
//////////////////////////////////////////////////////////////////////////

// Initialize
// - This will handle all the initialization needed for the renderer
STATUS
COpenGLRenderer::Initialize()
{
//glEnable(GL_DEPTH_TEST); // Enable depth testing
//glDepthFunc( GL_LEQUAL ); // Reject anything less than or equal to the current depth
//glClearDepth( 1.0f ); // We clear to full depth
//glClearStencil( 0 ); // We clear the stencil buffer to false
//glCullFace(GL_FRONT); // Enable culling
glClearColor(0.5f, 0.5f, 1.0f, 1.0f); // The color to clear the background to
return OK;
}

// Destroy
// - This will free all the memory used by the renderer
STATUS
COpenGLRenderer::Destroy()
{
return OK;
}

// Clear
// - This will clear the buffers specified
STATUS
COpenGLRenderer::Clear( int4 nBuffersToClear )
{
//////////////////////////////////////////////////////////////////////////
// Determine which buffers to clear
GLbitfield glBitToClear = 0;
if( COLOR_BUFFER_MASK( nBuffersToClear ) )
{
glBitToClear |= GL_COLOR_BUFFER_BIT;
}

if( DEPTH_BUFFER_MASK( nBuffersToClear ) )
{
glBitToClear |= GL_DEPTH_BUFFER_BIT;
}

if( STENCIL_BUFFER_MASK( nBuffersToClear ) )
{
glBitToClear |= GL_STENCIL_BUFFER_BIT;
}
//////////////////////////////////////////////////////////////////////////

// Finally we can clear the buffers
glClear( GL_COLOR_BUFFER_BIT );

// Ensure the initial matrix on the stack is an identity matrix
glPushMatrix();

return OK;
}







It's a lot of code, I know, but I'm trying for modularity and cross platform.

The logic flow goes like so:

WinMain creates a Window class.

The Window class create the window

The Window is passed to the DeviceManager

The DeviceManager sets up the HGLRC

The Renderer uses the functionality set by the DeviceManager

The DeviceManager presents the backbuffer.

Perception is when one imagination clashes with another
What does glGetError() say? Are you checking for errors?
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
Yeah I am, and it's not saying anything... :/
Perception is when one imagination clashes with another
Ok if there are no errors reported.
Did you check the GL information? http://www.opengl.org/wiki/FAQ#How_do_I_tell_what_version_of_OpenGL_I.27m_using.3F

Also, can you run games that use GL?
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
It may not be related, but this isn't healthy in your clear routine:

// Ensure the initial matrix on the stack is an identity matrix
glPushMatrix();


glPushMatrix doesn't do what you think it does; matrixes are implemented as a stack, with typically a stack depth of 32 for the modelview. Each push without a matching pop will quickly lead to you overflowing the stack, and this is probably where your driver is going berserk.

Push also doesn't set to identity; it increments the stack depth and copies up the matrix from the previous level. So you probably want to be using glLoadIdentity instead, making sure that your glMatrixMode is set to the matrix for which you wish to set to identity.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Good call, though I did have a matching pop matrix in the present, I didn't realize it wouldn't push an identity. I added load matrix, and while it didn't fix the problem you definitely saved me on a bug later on :)

Right now after all my profiling it just seems like my the game is stuck on processing something. It maxes out the core that I'm on, so I think I'm somehow I'm trying to clear something I can't so the game gets stuck on that...

Perception is when one imagination clashes with another

This topic is closed to new replies.

Advertisement