Tearing in OpenGL? - c++

I'm using win32 and opengl and I have a window set up with the projection at glOrtho of the window's coordinates. I have double buffering enabled, tested it with glGet as well. My program always seems to tear any primitives that I try to draw on it if it's being constantly translated.
Here is my OpenGL initialization function:
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glViewport(0, 0, 640, 480);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 640, 0, 480, 0, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDrawBuffer(GL_BACK);
glLoadIdentity();
And this is my rendering function, gMouseX and gMouseY are the coordinates of the mouse:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glTranslatef(gMouseX, gMouseY, 0.0f);
glColor3f(0.5f, 0.5f, 0.5f);
glBegin(GL_TRIANGLES);
glVertex2f(0.0f, 128.0f);
glVertex2f(128.0f, 0.0f);
glVertex2f(0.0f, 0.0f);
glEnd();
SwapBuffers(hDC);
The same tearing problem occurs regardless of how often the rendering function runs. Is there something I'm doing wrong or missing here?

If you're just rendering one or two trianges, you're going to have an insanely high framerate (in the thousands of FPS probably), which means it's SwapBuffering like hell, which means you're probably always swapping during the screen refresh (even with double buffering on). Once your scene gets going with more content and the framerate falls to more realistic values, it should stop tearing. Alternatively, look in to enabling V-Sync, such as with wglSwapIntervalEXT on Windows.

This issue doesn't have to be strictly connected to VSync, as all people around the internet try to suggest. In my case the problem was caused by the way in which the window was initialized. I noticed, that getting rid off dwStyle=WS_POPUP solved the problem, but only partially because then the window wasn't in the fullscreen mode. What worked for me in the end was using SetWindowLong(hwnd, GWL_STYLE, 0); after creating the window. It basically clears the window style. So my code for initializing the window looks like that:
dwStyle=WS_POPUP; //Windows Style
ShowCursor(FALSE); //Hide Mouse Pointer
//Create the Window
hwnd= CreateWindowEx(NULL,
"GLClass",
appName,
dwStyle,
0, 0,
(long)windowWidth,
(long)windowHeight,
NULL,
NULL,
hInstance,
NULL);
SetWindowLong(hwnd, GWL_STYLE, 0);
After this modification all my problems with tearing and also not being able to PrintScreen, were solved. I didn't need to touch VSync anywhere.

When defining your win32 application window styles, don't include WS_POPUP
After debugging a problem where full screen would introduce screen tearing, I discovered the styles for full screen, after removing WS_POPUP it seemed to have stop tearing single handedly, without having to force the rendering loop to the refresh rate. WS_POPUP is known for being problematic, I guess. It would also block any full screen screenshots to complete white.

Tearing is caused by not synchronizing your updates with the monitor's vertical blanking interval. It's a bit hardware dependent in OpenGL (I think, not an expert), start with looking for glXWaitVideoSyncSGI. Googling "opengl sync to vblank" pays off too.

Try to putting a cap / limiting on the frame rate or yielding it probably (if you don't have a vsync):
Here is the pseudo code:
let tick equals new_tick
if tick is less than last_tick do
yield
done
calculate last_tick
Try the sleep function and setting it to one, so to yield:
Sleep(1);
Also remember limiting or capping frame rate is not that advisable as there is certain functions that are really meant for reducing frame calculations.

Related

How do I create two main windows with GLUT?

I am doing an excercise where I draw three boxes across three windows using GLUT. They draw individually, but in the same project, the three windows display correctly, but immediately close the program with code 1.
glutInitWindowPosition(x,y);
windowOne = glutCreateWindow("windowOne");
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
glOrtho(-400, 400, -400, 400, -500, 500);
glutInitWindowPosition(x,y);
windowTwo = glutCreateWindow("windowTwo");
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
glFrustum(-60, 60, -60, 60, 60, 200);
gluLookAt(0, 0, 120, 0, 0, 0, 0, 1, 0);
With each window in a separate file loaded in by itself, they each display exactly as they are meant to. I have a feeling I should be setting the window at some point between each init, but I don't know why. I do not have a draw function in at the moment, as I wanted to confirm this happens without the drawing code.
I should also note that I have to create separate windows, exactly as I have done, so other window drawing functions are useless.
I found the answer scouring through examples, so I'll post it just in case anyone else is having similar problems.
the draw function needs to be added after each window, in the style of
// window one
glutInitWindowPosition(50, 50);
WindowOne = glutCreateWindow("orthogonal projection");
glutDisplayFunc(drawWindowOne);
// window two
glutInitWindowPosition(650, 50);
WindowThree = glutCreateWindow("3D viewing system with glFrustum()");
glutDisplayFunc(drawWindowTwo);
I was using a draw function that shuffles through each window and generates its specific draw after using glutSetWindow. each draw takes place after each window is initialized, and multiple glutDisplayFunc() can be called after eachother.
I originally thought I was using glutDisplayFunc to set a pointer, so that when the display routine went through for the frame, it would only generate the last display function called, as opposed to all of them.
Never do OpenGL drawing operations in the same function in which you also create GLUT windows. It doesn't work. You need to register a display callback function for each window and do all drawing there. Calling glutMainLoop is mandatory if you want to see something sensible using GLUT.

Fullscreening a window in SDL2 with openGL

My program starts with a loading window while it is compiling shaders, loading textures etc. I then want to be able to launch a fullscreen application and use these resources. My understanding is that the openGL context must be the same before and after. I tried two methods for this: first of all I tried making a second window which was fullscreen, and used the SDL_GL_makecurrent command on this window to 'transfer' the context across (couldn't find where I read about this method), and secondly tried just fullscreening the loading window. Both of these methods resulted in the loading screen being moved to the top left corner of the screen. However opengl commands no longer ran properly in fullscreen, including clearing buffers which meant that the window contained the contents of my desktop/background applications.
Is there a proper way of doing this? Or is this a strange bug in sdl/opengl drivers?
Code to fullscreen original window:
//opengl commands work fine up to here
//now to fullscreen
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_SetWindowSize(window, 1366, 768); //tried this on either side of line above and without either line
glViewport(0, 0, 1366, 768); //update viewport
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
//window should be whited, other draw commands tried and all fail or distort
SDL_GL_SwapWindow(window);
Creating a new window and using previous context:
//Fine up to here
window2 = SDL_CreateWindow("Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1366, 768, SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_SHOWN);
SDL_GL_MakeCurrent(window2, glContext); //created with SDL_GL_CreateContext(oldwindow);
//draw commands dont work
PS: running ubuntu
Update: In the second code, reusing the context in a new window, it returns an error saying 'invalid window' when it fails, which is most of the time but not always. When it fails, the screen ends up completely corrupted(black with weird white squares and patterns), ending the program will not clear the screen of this (although screenshots are perfectly fine?), but it can be restored by ctrl+f1 to terminal then ctrl+f7 back
I dont really know if its a bug. I experienced the same issue with sdl2 and opengl.
Create an regular window
attach to opengl context.
fullscreen
BOOM. black screen and crashed window.
I only noticed that issue in ubuntu.
Trought some tests i found a quick way to fix it:
Uint32 flags = 0;
flags |= SDL_WINDOW_RESIZABLE;
//bla bla bla your tags
flags |= SDL_WINDOW_OPENGL;
m_window = SDL_CreateWindow( "hello gl", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, m_screen.x, m_screen.y,flags);
m_glContext = SDL_GL_CreateContext(m_window);
//Set right the way the screen to fullscrene false
SDL_SetWindowFullscreen(m_window, SDL_FALSE);
Now the fullscreen seems to work without problem.

DWM being disabled causes front-buffer corruption in OpenGL window

I'm experiencing some weird graphical corruption with my SDL2 + OpenGL GUI application. Now I apologize if I'm not using the appropriate term to describe the situation. It seems that the front buffer is being invalidated and other applications are being drawn in the buffer?
Important note: this corruption only occurs in Windows XP or when using the Windows Basic theme in Windows 7.
The corruption can be reproduced in a few ways:
by moving the window around. It seems that the front buffer gets corrupted with the image of other applications in front or behind it.
if there's an application behind, it'll occasionally flash into the front buffer.
I can load up a google webpage in Chrome above the opengl application, close the chrome process, and then move the opengl application around and I'll see the google homepage covering the whole inside of the window.
by moving another application over the opengl window.
It seems that I also see the corruption when I'm moving other windows around, even if they don't overlap the opengl window, so long as I've already tried one of the ones posted just above.
inline int UI::RenderingThread()
{
UI::Window::Instance().RenderingThreadEnter();
while( UI::Window::Instance().RenderingThreadActive() )
{
unsigned int ticks = SDL_GetTicks();
UI::Window::Instance().RenderingThreadUpdate();
UI::Window::Instance().RenderingThreadRender();
ticks = SDL_GetTicks() - ticks;
if( ticks < 33 )
{
SDL_Delay( 33 - ticks );
}
}
UI::Window::Instance().RenderingThreadExit();
return 0;
}
As you probably guessed, I'm using multithreading and I have my rendering in a separate thread. Within the RenderingThreadRender() function, I only redraw if there's a change in content, or I've requested a redraw.
case SDL_WINDOWEVENT:
switch( sdl_event.window.event )
{
default:
UI::Window::Instance().Redraw();
break;
}
This is done to allow all SDL_WINDOWEVENT events to redraw in hopes that one of them would fix the problem. Unfortunately that has not solved the issue.
I'm hesitant to simply constantly redraw my application at 30 or 60 fps since I've noticed that by doing so, other application would be sluggish when moving them around.
Initialization:
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
this->window = SDL_CreateWindow( this->caption.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
UI::WindowSize::Instance().GetWindowWidth(), UI::WindowSize::Instance().GetWindowHeight(),
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE );
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glViewport(0, 0, UI::WindowSize::Instance().GetWindowWidth(), UI::WindowSize::Instance().GetWindowHeight());
// Set the OpenGL view
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho( 0, UI::WindowSize::Instance().GetWindowWidth(), UI::WindowSize::Instance().GetWindowHeight(), 0, -1, 1 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glDisable( GL_DITHER );
Rendering:
if( this->redraw )
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// a few DrawArrays
SDL_GL_SwapWindow( this->window );
}
Does anyone have any idea what could be causing this issue, and how to fix it?
EDIT: Some more research has pointed me to the following two questions:
https://superuser.com/questions/316738/what-happens-with-the-off-screen-front-buffers-in-windows-7-when-dwm-is-disabled
C++ OpenGL window only tracks background
However, this doesn't solve my problem since I'm already using Double Buffering.
I've found the solution to my problem. It's unlikely that anyone will experience the same issue that I was having, but you never know. Essentially a C# Window of size equal or larger than my application, was being created before. This window was hidden, however because XP has a global framebuffer instead of a composition, there was a conflict causing the corruption.
All in all, if you're having a similar issue, make sure there isn't another context.

QGLWidget refuses to draw anything

I've looked at a ton of articles and SO questions about OpenGL not drawing, common mistakes, etc. This one is stumping me.
I've tried several different settings for glOrtho, different vertex positions, colors, etc., all to no avail.
I can confirm the OpenGL state is valid because the clear color is purple in the code (meaning the window is purple). gDEBugger is also confirming frames are being updated (so is Fraps).
Here is the code. Lines marked as "didn't help" were not there originally, and were things that I tried and failed.
QTWindow::QTWindow( )
{
// Enable mouse tracking
this->setMouseTracking(true);
}
void QTWindow::initializeGL()
{
// DEBUG
debug("Init'ing GL");
this->makeCurrent(); ///< Didn't help
this->resizeGL(0, 0); ///< Didn't help
glDisable(GL_CULL_FACE); ///< Didn't help
glClearColor(1, 0, 1, 0);
}
void QTWindow::paintGL()
{
// DEBUG
debug("Painting GL");
this->makeCurrent(); ///< Didn't help
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0,1,1);
glBegin(GL_TRIANGLES);
glVertex2f(500,100);
glVertex2f(100,500);
glVertex2f(0,0);
glEnd();
this->swapBuffers(); ///< Didn't help
}
void QTWindow::resizeGL(int width, int height)
{
// DEBUG
debug("Resizing GL");
this->makeCurrent(); ///< Didn't help
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1000, 0, 1000, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
The triangle is not being displayed at all, even with culling turned off. However, all three debug logs are called exactly how they should be.
What am I missing?
Try calling glViewport() function at the very beginning of the QTWindow::resizeGL() function:
glViewport(0, 0, width, height);
And don't ever call resizeGL() with width and height set to 0 ;) Besides that, it is not necessary for you to call resizeGL() directly as it is being called by Qt whenever the window is being resized.
You can remove all calls to the swapBuffers() function - it is being called internally by Qt.
The makeCurrent() function should be called before all other GL calls, so it is good that you have called it in initializeGL(), but you don't have to call it in the paintGL() function (unless paintGL() is being called from another thread, but I bet it isn't in your code).
The issue ended up being versions. The version string returned with glGetString(GL_VERSION) indicated 4.2 compatibility context was being used.
Since the triangle calls in the paintGL method were removed in 3.1 (if I recall correctly), it was obvious why they weren't drawing anything. Further, no errors were being thrown because it was in compat. mode.
Because I couldn't get the version down below 3.0 on the QGLWidget (due to the fact that QT requires 2.1, as I was informed on another message board), I set the version to 3.0 and tried using some 3.0 drawing calls and it ended up working.

Painting Text above OpenGL context in MFC

I work on an MFC app containing OpenGL context.I am new to MFC that is why I am asking it.OpenGL works fine ,but when I want to draw a text above the 3D window using this code inside WindowProc:
case WM_PAINT:
hDC=BeginPaint(window,&paintStr);
GetClientRect(window,&aRect);
SetBkMode(hDC,TRANSPARENT);
DrawText(hDC,L"He He I am a text on top of OpenGL",-1,&aRect,DT_SINGLELINE|DT_CENTER|DT_VCENTER);
EndPaint(window,&paintStr);
return 0;
it is shown beneath the OpenGL context.I can see it only when resizing the window as the OpenGL rendering pauses than.
What you're doing is wrong and also harder than doing it all in OpenGL. To solve the problem of adding text to an OpenGL-drawn window, it's better to just make OpenGL draw the text. You can even use the exact same font you were using in MFC by creating a CFont instance when you handle WM_CREATE, selecting the font into the DC, and calling wglUseFontBitmaps, which will make a series of rasterized bitmaps that you can use with glCallLists. (While you're at it, call GetCharABCWidths and GetTextMetrics to determine the width and height of each glyph, respectively.)
ABC glyphInfo[256]; // for font widths
TEXTMETRIC tm; // for font heights
// create a bitmap font
CFont myFont;
myFont.CreateFont(
16, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
_T("Arial") // lpszFacename
);
// change the current font in the DC
CDC* pDC = CDC::FromHandle(hdc);
// make the system font the device context's selected font
CFont *pOldFont = (CFont *)pDC->SelectObject (&myFont);
// the display list numbering starts at 1000, an arbitrary choice
wglUseFontBitmaps (hdc, 0, 255, 1000);
VERIFY( GetCharABCWidths (hdc, 0, 255, &glyphInfo[0]) );
pDC->GetTextMetrics(&tm);
if(pOldFont)
pDC->SelectObject(pOldFont);
myFont.DeleteObject();
Then when you handle WM_PAINT, reset your matrices and use glRasterPos2d to put the text where you need it to go. I suggest calculating the exact width of your string using code similar to the one below if you want it to be horizontally centered.
// indicate start of glyph display lists
glListBase (1000);
CRect r;
GetWindowRect(r);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, r.Width(), 0, r.Height());
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
CString formattedString;
formattedString.Format("Pi is about %1.2f", 3.1415);
int stringWidth=0; // pixels
for(int j=0; j < formattedString.GetLength(); ++j)
stringWidth += glyphInfo[ formattedString.GetAt(j) ].abcA + glyphInfo[ formattedString.GetAt(j) ].abcB + glyphInfo[ formattedString.GetAt(j) ].abcC;
double textXPosition, textYPosition;
textXPosition = r.Width()/2-stringWidth/2; // horizontally centered
textYPosition = r.Height()/2-tm.tmHeight/2; // vertically centered
glRasterPos2d(textXPosition,textYPosition);
// this is what actually draws the text (as a series of rasterized bitmaps)
glCallLists (formattedString.GetLength(), GL_UNSIGNED_BYTE, (LPCSTR)formattedString);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
While the setup is annoying, you only have to do it once, and I think it's less frustrating than dealing with GDI. Mixing GDI and OpenGL is really asking for trouble, and OpenGL does a very good job of displaying text -- you get sub-pixel accuracy for free, among other benefits.
Edit: In response to your request for including GUI elements, I will assume that you meant that you want to have both OpenGL-drawn windows and also standard Windows controls (edit boxes, check boxes, buttons, list controls, etc.) inside the same parent window. I will also assume that you intend OpenGL to draw only part of the window, not the background of the window.
Since you said you're using MFC, I suggest that you create a dialog window, add all of your standard Windows controls to it, and then add in a CWnd-derived class where you handle WM_PAINT. Use the resource editor to move the control to where you want it. Effectively, you're making an owner-draw custom control where OpenGL is doing the drawing. So OpenGL will draw that window, and the standard MFC classes (CEdit, CButton, etc.) will draw themselves. This works well in my experience, and it's really not much different from what GDI does in an owner-draw control.
What if instead you want OpenGL to draw the background of the window, and you want standard Windows controls to appear on top of it? I don't think this is a great idea, but you can handle WM_PAINT and WM_ERASE for your CDialog-derived class. In WM_ERASE, call OpenGL to draw your 3D content, which will be overwritten by the standard Windows controls when WM_PAINT is called. Alternatively in WM_PAINT you could call OpenGL before calling CDialog::OnDraw, which would be similar.
Please clarify your statement "I want to add some 2s graphics overlay (like labels ,gui elements)" if you want me to write more.
Looking at your code I assume the OpenGL rendering is called from a timer or as idel loop action. Naturally OpenGL execution will probably contain some clearing, thus taking anything else drawn with it.
Mixing GDI text drawing with OpenGL is not recommended, but can be done. But of course you then need to include that code into the OpenGL drawing function, too, placing all GDI operations after the buffer swap.