0030364: Visualization, TKOpenGl - allow initializing a Surface-less EGL context
[occt.git] / src / OpenGl / OpenGl_Window.cxx
index 73891f2..c812775 100644 (file)
@@ -18,6 +18,7 @@
 #include <OpenGl_Context.hxx>
 #include <OpenGl_GraphicDriver.hxx>
 #include <OpenGl_Window.hxx>
+#include <OpenGl_FrameBuffer.hxx>
 
 #include <Aspect_GraphicDeviceDefinitionError.hxx>
 #include <Graphic3d_TransformUtils.hxx>
@@ -181,14 +182,15 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
   EGLConfig  anEglConfig  = (EGLConfig  )theDriver->getRawGlConfig();
   if (anEglDisplay == EGL_NO_DISPLAY
    || anEglContext == EGL_NO_CONTEXT
-   || anEglConfig == NULL)
+   || (anEglConfig == NULL
+    && (EGLContext )theGContext == EGL_NO_CONTEXT))
   {
     throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL does not provide compatible configurations!");
     return;
   }
 
   EGLSurface anEglSurf = EGL_NO_SURFACE;
-  if (theGContext == (EGLContext )EGL_NO_CONTEXT)
+  if ((EGLContext )theGContext == EGL_NO_CONTEXT)
   {
     // create new surface
     anEglSurf = eglCreateWindowSurface (anEglDisplay,
@@ -211,8 +213,24 @@ OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
     anEglSurf = eglGetCurrentSurface(EGL_DRAW);
     if (anEglSurf == EGL_NO_SURFACE)
     {
-      throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is unable to retrieve current surface!");
-      return;
+      // window-less EGL context (off-screen)
+      //throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is unable to retrieve current surface!");
+      if (anEglConfig != NULL)
+      {
+        const int aSurfAttribs[] =
+        {
+          EGL_WIDTH,  myWidth,
+          EGL_HEIGHT, myHeight,
+          EGL_NONE
+        };
+        anEglSurf = eglCreatePbufferSurface (anEglDisplay, anEglConfig, aSurfAttribs);
+        if (anEglSurf == EGL_NO_SURFACE)
+        {
+          throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is unable to create off-screen surface!");
+        }
+      }
+      myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW,
+                                "OpenGl_Window::CreateWindow: WARNING, a Window is created without a EGL Surface!");
     }
   }
 
@@ -715,7 +733,30 @@ void OpenGl_Window::Init()
     return;
 
 #if defined(HAVE_EGL)
-  if (!myPlatformWindow->IsVirtual())
+  if ((EGLSurface )myGlContext->myWindow == EGL_NO_SURFACE)
+  {
+    // define an offscreen default FBO to avoid rendering into EGL_NO_SURFACE;
+    // note that this code is currently never called, since eglCreatePbufferSurface() is used instead as more robust solution
+    // for offscreen rendering on bugged OpenGL ES drivers
+    Handle(OpenGl_FrameBuffer) aDefFbo = myGlContext->SetDefaultFrameBuffer (Handle(OpenGl_FrameBuffer)());
+    if (!aDefFbo.IsNull())
+    {
+      aDefFbo->Release (myGlContext.operator->());
+    }
+    else
+    {
+      aDefFbo = new OpenGl_FrameBuffer();
+    }
+
+    if (!aDefFbo->InitWithRB (myGlContext, myWidth, myHeight, GL_RGBA8, GL_DEPTH24_STENCIL8))
+    {
+      TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: default FBO creation failed");
+      throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
+    }
+    myGlContext->SetDefaultFrameBuffer (aDefFbo);
+    aDefFbo->BindBuffer (myGlContext);
+  }
+  else if (!myPlatformWindow->IsVirtual())
   {
     eglQuerySurface ((EGLDisplay )myGlContext->myDisplay, (EGLSurface )myGlContext->myWindow, EGL_WIDTH,  &myWidth);
     eglQuerySurface ((EGLDisplay )myGlContext->myDisplay, (EGLSurface )myGlContext->myWindow, EGL_HEIGHT, &myHeight);