Sign in to follow this  
RavenITA

OpenGL SwapBuffers is slow... but only in debug!

Recommended Posts

Hi everyone, let me take the chance to say hello as this is my first post :-) I've been programming with OpenGL on and off for the last three years, and I've always used GLUT. A few months ago I decided I'd discard GLUT and do things my way, and since my most common dev platform is Windows (XP SP2) I switched to Win32 API, following NeHe's tutorials. Everything went kinda smoothly until a few days ago. After completing the basis of a 2D GUI system, I edited the code to provide an abstract interface to the graphics library to remove dependencies from OpenGL calls (in case I ever need to switch to something else). Since then, my application flickers, but only when compiled in debug mode: release build does not flicker, and the previous version (the one with OpenGL dependencies) does not flicker, neither in debug nor in release. I'm using immediate mode rendering, and I'm drawing quads which are actually made up of two triangles: i.e., I define the vertices of a quad but then draw two triangles in a single glBegin(GL_TRIANGLES)/glEnd() batch. I have texture mapping on, depth test on, alpha test on (rendering only values greater than 0). I can actually see the two triangles of each quad flicker independently. Simple benchmarking shows that SwapBuffer takes like 28 ms, which may explain flickering at 30 fps; but when I run the application at a lower frame rate, like 3 fps, the triangles still flicker once a frame. I've read that a slow SwapBuffers indicates that OpenGL is rendering slow; but if that was the problem a lower frame rate would make the flickering go away. Also, if it's not a problem of my code being slow, then release optimizations shouldn't make any difference. In release mode, SwapBuffers takes about 1ms, which is similar to what it did in the previous version of my code. I am pretty sure that the abstraction layer I added is not the cause of the problem: the number and the order of GL function calls hasn't changed, and I'm using the exact same orthogonal projection with the exact same modelview matrix. Also, I've tried to change the compiler configurations to make release and debug more similar to each other, to no avail. I'm using VC++ Express 2008. Debug and release link to the same OpenGL32 and GLu32 libraries (no debug version involved). I've tried rendering only some of the quads. By the way, the main test I do draws the astonishing amount of 6 (six) quads, i.e. 12 triangles with colors and textures. They don't overlap, so the flickering is not due to Z-fighting. V-Sync is not enabled; I'm drawing into a window anyway. If I draw only certain exact combinations of said 6 quads, the flickering goes away, but all the quads are drawn the same way, and all the textures have widths and heights which are power of two. As you can see, I've tried pretty much everything I could think of. Does anybody have a clue of what could be the cause of the problem? Thanks to those who will try to help me. Sorry that I didn't post my code, but it's spread around quite a lot of files, and I'd have to pretty much share my whole VS solution to give you the complete picture of the code.

Share this post


Link to post
Share on other sites
Quote:
Original post by bubu LV
Have you selected pixel format with double buffering when creating OpenGL context?


Hi bubu,

yes, of course I'm using double buffering. Here's my PixelFormatDescriptor structure:

	m_oPFD.nSize = sizeof(PIXELFORMATDESCRIPTOR);
m_oPFD.nVersion = 1;
m_oPFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_TYPE_RGBA;
m_oPFD.cColorBits = m_uiBitDepth;
m_oPFD.cAlphaBits = 8;
m_oPFD.cAccumBits = 0;
m_oPFD.cDepthBits = 16;
m_oPFD.cStencilBits = 1;
m_oPFD.cAuxBuffers = 0;
m_oPFD.dwLayerMask = PFD_MAIN_PLANE;
m_oPFD.bReserved = 0;

Share this post


Link to post
Share on other sites
I'm bumping the thread... does anyone has any idea? I've tried drawing a single quad (with textures and colors on each vertex) and the flickering stays. Clues?

Share this post


Link to post
Share on other sites
Could you post the code, both for the new abstraction as well as the opengl implementation of the abstraction? Basically all the code relevant to drawing the stuff that flickers. If I could see it and/or run it locally I can probably help you out.

Share this post


Link to post
Share on other sites
I'll try to show you as much code as possible. As I said, it is spread around several files, and a complete example that actually compiles would involve at least three/four projects. If this code isn't enough, I'll try to create a minimal example and post that.

Initialization of my GraphicsManager:
	glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.0f);

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

glShadeModel(GL_SMOOTH);


Frame-time loop (capped at 30 FPS with a timer): first the screen is cleared
	glClearColor(0, 0, 0, 1);
glClearDepth(1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


Then the Render function of my UI system is called. Here is the code:
	void GSceneRenderer::DoProjectionMatrix()
{
m_poGraphicWrapper->OrthogonalProjection(0, 1, 0, 1, 1, 100);
}

void GSceneRenderer::DoModelMatrix()
{
m_poGraphicWrapper->ResetViewMatrix();
m_poGraphicWrapper->ApplyTranslationMatrix(0, 0, -100);
}

void GSceneRenderer::Render()
{
DoProjectionMatrix();
DoModelMatrix();

GUInt32 uiCount = m_poScene->GetObjectsCount();
for (GUInt32 i = 0; i < uiCount; ++i)
{
m_poScene->GetObject(i)->Draw();
}
}


The objects I get from the Scene in this final loop are all GlRectangles. This is their Draw function:
	void GlRectangle::Draw()
{
if (m_poTexture != NULL)
{
m_poTexture->Use();
}
else
{
// Unbind texture;
}

glBegin(GL_TRIANGLES);

glColor3f(
static_cast<float>(m_aoVertices[0].GetColor().GetRed()),
static_cast<float>(m_aoVertices[0].GetColor().GetGreen()),
static_cast<float>(m_aoVertices[0].GetColor().GetBlue()));
glTexCoord2f(
static_cast<float>(m_aoVertices[0].GetU()),
static_cast<float>(m_aoVertices[0].GetV()));
glVertex3f(
static_cast<float>(m_aoVertices[0].GetX()),
static_cast<float>(m_aoVertices[0].GetY()),
static_cast<float>(m_aoVertices[0].GetZ()));

glColor3f(
static_cast<float>(m_aoVertices[1].GetColor().GetRed()),
static_cast<float>(m_aoVertices[1].GetColor().GetGreen()),
static_cast<float>(m_aoVertices[1].GetColor().GetBlue()));
glTexCoord2f(
static_cast<float>(m_aoVertices[1].GetU()),
static_cast<float>(m_aoVertices[1].GetV()));
glVertex3f(
static_cast<float>(m_aoVertices[1].GetX()),
static_cast<float>(m_aoVertices[1].GetY()),
static_cast<float>(m_aoVertices[1].GetZ()));

glColor3f(
static_cast<float>(m_aoVertices[2].GetColor().GetRed()),
static_cast<float>(m_aoVertices[2].GetColor().GetGreen()),
static_cast<float>(m_aoVertices[2].GetColor().GetBlue()));
glTexCoord2f(
static_cast<float>(m_aoVertices[2].GetU()),
static_cast<float>(m_aoVertices[2].GetV()));
glVertex3f(
static_cast<float>(m_aoVertices[2].GetX()),
static_cast<float>(m_aoVertices[2].GetY()),
static_cast<float>(m_aoVertices[2].GetZ()));

//////////////////////////////////////////

glColor3f(
static_cast<float>(m_aoVertices[2].GetColor().GetRed()),
static_cast<float>(m_aoVertices[2].GetColor().GetGreen()),
static_cast<float>(m_aoVertices[2].GetColor().GetBlue()));
glTexCoord2f(
static_cast<float>(m_aoVertices[2].GetU()),
static_cast<float>(m_aoVertices[2].GetV()));
glVertex3f(
static_cast<float>(m_aoVertices[2].GetX()),
static_cast<float>(m_aoVertices[2].GetY()),
static_cast<float>(m_aoVertices[2].GetZ()));

glColor3f(
static_cast<float>(m_aoVertices[3].GetColor().GetRed()),
static_cast<float>(m_aoVertices[3].GetColor().GetGreen()),
static_cast<float>(m_aoVertices[3].GetColor().GetBlue()));
glTexCoord2f(
static_cast<float>(m_aoVertices[3].GetU()),
static_cast<float>(m_aoVertices[3].GetV()));
glVertex3f(
static_cast<float>(m_aoVertices[3].GetX()),
static_cast<float>(m_aoVertices[3].GetY()),
static_cast<float>(m_aoVertices[3].GetZ()));

glColor3f(
static_cast<float>(m_aoVertices[0].GetColor().GetRed()),
static_cast<float>(m_aoVertices[0].GetColor().GetGreen()),
static_cast<float>(m_aoVertices[0].GetColor().GetBlue()));
glTexCoord2f(
static_cast<float>(m_aoVertices[0].GetU()),
static_cast<float>(m_aoVertices[0].GetV()));
glVertex3f(
static_cast<float>(m_aoVertices[0].GetX()),
static_cast<float>(m_aoVertices[0].GetY()),
static_cast<float>(m_aoVertices[0].GetZ()));

glEnd();
}


Finally, the code of the wrapper:
	void GlWrapper::OrthogonalProjection(GReal i_fLeft, GReal i_fRight, 
GReal i_fTop, GReal i_fBottom,
GReal i_fNear, GReal i_fFar)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(i_fLeft, i_fRight, i_fBottom, i_fTop, i_fNear, i_fFar);
}

void GlWrapper::ResetProjection()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
}

void GlWrapper::ResetViewMatrix()
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

void GlWrapper::ApplyTranslationMatrix(GReal i_fX, GReal i_fY, GReal i_fZ)
{
glTranslatef(i_fX, i_fY, i_fZ);
}


Before introducing the wrapper, the code of GSceneRenderer called directly the gl* functions:
	void GSceneRenderer::DoProjectionMatrix()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1, 1, 0, 100, 0);
}

void GSceneRenderer::DoModelMatrix()
{
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

void GSceneRenderer::Render()
{
DoProjectionMatrix();
DoModelMatrix();

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1, 1, 0, 0, 100);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0, 0, -100);

GUInt32 uiCount = m_poScene->GetObjectsCount();
for (GUInt32 i = 0; i < uiCount; ++i)
{
m_poScene->GetObject(i)->Draw();
}
}


Ignore the fact that a few costants have changed (for example, the near and far ortho plane, and the translation along the Z axis); the changes are consistent, or at least the visual results I get are. The only difference is that, in debug mode only, the two triangles of each quad flicker independently :-s

PS: A few details. The m_poTexture variable points to a GlTexture object that simply wraps the creation and the binding of a GL texture object; the Use() method simply calls glBindTexture with the proper texture id. I'm aware that there are details to polish; for example the "unbinding" of the texture, or the fact that I'm using a reverse Y-axis than is normally used (i.e., with positive values going down from the top of the screen). While they may be peculiar and possibly incorrect, they work as intended in both versions.

Share this post


Link to post
Share on other sites
Yeah, nothing really looks amiss there. Where is SwapBuffers called from, by the way?

If this is a personal project (no NDA breakage please :)), you can zip it up and PM me the link since it's too big to post and I'll work through it on my box.

Share this post


Link to post
Share on other sites

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