0023172: Added workaround for BUGs in Intel OpenGL drivers
authorkgv <kgv@opencascade.com>
Thu, 24 May 2012 06:03:23 +0000 (10:03 +0400)
committerkgv <kgv@opencascade.com>
Fri, 25 May 2012 12:20:51 +0000 (16:20 +0400)
Check GL context already bound before wglMakeCurrent() call.

src/OpenGl/OpenGl_Context.cxx
src/OpenGl/OpenGl_Context.hxx
src/OpenGl/OpenGl_GraphicDriver_Export.cxx
src/OpenGl/OpenGl_Window.cxx

index eb99984..d5c01e6 100644 (file)
@@ -103,23 +103,75 @@ OpenGl_Context::~OpenGl_Context()
 }
 
 // =======================================================================
+// function : IsCurrent
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_Context::IsCurrent() const
+{
+#if (defined(_WIN32) || defined(__WIN32__))
+  if (myWindowDC == NULL || myGContext == NULL)
+  {
+    return Standard_False;
+  }
+  return (( (HDC )myWindowDC == wglGetCurrentDC())
+      && ((HGLRC )myGContext == wglGetCurrentContext()));
+#else
+  if (myDisplay == NULL || myWindow == 0 || myGContext == 0)
+  {
+    return Standard_False;
+  }
+
+  return (   ((Display* )myDisplay  == glXGetCurrentDisplay())
+       &&  ((GLXContext )myGContext == glXGetCurrentContext())
+       && ((GLXDrawable )myWindow   == glXGetCurrentDrawable()));
+#endif
+}
+
+// =======================================================================
 // function : MakeCurrent
 // purpose  :
 // =======================================================================
 Standard_Boolean OpenGl_Context::MakeCurrent()
 {
 #if (defined(_WIN32) || defined(__WIN32__))
-  if (myWindowDC == NULL || myGContext == NULL ||
-      !wglMakeCurrent ((HDC )myWindowDC, (HGLRC )myGContext))
+  if (myWindowDC == NULL || myGContext == NULL)
   {
-    //GLenum anErrCode = glGetError();
-    //const GLubyte* anErrorString = gluErrorString (anErrCode);
-    //std::cerr << "wglMakeCurrent() failed: " << anErrCode << " " << anErrorString << "\n";
+    Standard_ProgramError_Raise_if (myIsInitialized, "OpenGl_Context::Init() should be called before!");
+    return Standard_False;
+  }
+
+  // technically it should be safe to activate already bound GL context
+  // however some drivers (Intel etc.) may FAIL doing this for unknown reason
+  if (IsCurrent())
+  {
+    return Standard_True;
+  }
+  else if (wglMakeCurrent ((HDC )myWindowDC, (HGLRC )myGContext) != TRUE)
+  {
+    // notice that glGetError() couldn't be used here!
+    wchar_t* aMsgBuff = NULL;
+    DWORD anErrorCode = GetLastError();
+    FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+                    NULL, anErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (wchar_t* )&aMsgBuff, 0, NULL);
+    if (aMsgBuff != NULL)
+    {
+      std::wcerr << L"OpenGL interface: wglMakeCurrent() failed. " << aMsgBuff << L" (" << int(anErrorCode) << L")\n";
+      LocalFree (aMsgBuff);
+    }
+    else
+    {
+      std::wcerr << L"OpenGL interface: wglMakeCurrent() failed with #" << int(anErrorCode) << L" error code\n";
+    }
     return Standard_False;
   }
 #else
-  if (myDisplay == NULL || myWindow == 0 || myGContext == 0 ||
-      !glXMakeCurrent ((Display* )myDisplay, (GLXDrawable )myWindow, (GLXContext )myGContext))
+  if (myDisplay == NULL || myWindow == 0 || myGContext == 0)
+  {
+    Standard_ProgramError_Raise_if (myIsInitialized, "OpenGl_Context::Init() should be called before!");
+    return Standard_False;
+  }
+
+  if (!glXMakeCurrent ((Display* )myDisplay, (GLXDrawable )myWindow, (GLXContext )myGContext))
   {
     // if there is no current context it might be impossible to use glGetError() correctly
     //std::cerr << "glXMakeCurrent() failed!\n";
@@ -251,7 +303,7 @@ Standard_Boolean OpenGl_Context::Init (const Aspect_Drawable         theWindow,
 #else
   myDisplay  = theDisplay;
 #endif
-  if (myGContext == NULL)
+  if (myGContext == NULL || !MakeCurrent())
   {
     return Standard_False;
   }
index 9fa6dd8..c054baa 100644 (file)
@@ -121,6 +121,11 @@ public:
   //! Clean up errors stack for this GL context (glGetError() in loop).
   Standard_EXPORT void ResetErrors();
 
+  //! This method uses system-dependent API to retrieve information
+  //! about GL context bound to the current thread.
+  //! @return true if current thread is bound to this GL context
+  Standard_EXPORT Standard_Boolean IsCurrent() const;
+
   //! Activates current context.
   //! Class should be initialized with appropriate info.
   Standard_EXPORT Standard_Boolean MakeCurrent();
index fbcfa98..75a9b8f 100755 (executable)
@@ -20,6 +20,8 @@
 /************************************************************************/
 
 #include <OpenGl_GraphicDriver.hxx>
+#include <OpenGl_Context.hxx>
+#include <OpenGl_CView.hxx>
 #include <OSD_Localizer.hxx>
 
 #ifdef HAVE_CONFIG_H
@@ -49,6 +51,14 @@ Standard_Boolean OpenGl_GraphicDriver::Export (const Standard_CString theFileNam
                                                const Standard_Address /*theProgressObject*/)
 {
 #ifdef HAVE_GL2PS
+  // gl2psBeginPage() will call OpenGL functions
+  // so we should activate correct GL context before redraw scene call
+  const OpenGl_CView* aCView = (const OpenGl_CView* )theView.ptrView;
+  if (aCView == NULL || !aCView->WS->GetGlContext()->MakeCurrent())
+  {
+    return Standard_False;
+  }
+
   Standard_Integer aFormat = -1;
   Standard_Integer aSortType = Graphic3d_ST_BSP_Tree;
   switch (theFormat)
index e777b3b..a250766 100644 (file)
@@ -400,8 +400,12 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_Display)& theDisplay,
   myWindow = aParent;
 #endif
 
+#if (defined(_WIN32) || defined(__WIN32__))
+  myGlContext->Init (myWindow, myWindowDC, myGContext);
+#else
+  myGlContext->Init (myWindow, myDisplay->GetDisplay(), myGContext);
+#endif
   Init();
-  myGlContext->Init();
 }
 
 // =======================================================================
@@ -463,28 +467,7 @@ OpenGl_Window::~OpenGl_Window()
 // =======================================================================
 Standard_Boolean OpenGl_Window::Activate()
 {
-  DISPLAY* aDisp = (DISPLAY* )myDisplay->GetDisplay();
-  if (aDisp == NULL)
-    return Standard_False;
-
-#if (defined(_WIN32) || defined(__WIN32__))
-  if (!wglMakeCurrent (myWindowDC, myGContext))
-  {
-    //GLenum errorcode = glGetError();
-    //const GLubyte *errorstring = gluErrorString(errorcode);
-    //printf("wglMakeCurrent failed: %d %s\n", errorcode, errorstring);
-    return Standard_False;
-  }
-#else
-  if (!glXMakeCurrent (aDisp, myWindow, myGContext))
-  {
-    // if there is no current context it might be impossible to use glGetError correctly
-    //printf("glXMakeCurrent failed!\n");
-    return Standard_False;
-  }
-#endif
-
-  return Standard_True;
+  return myGlContext->MakeCurrent();
 }
 
 // =======================================================================