0030364: Visualization, TKOpenGl - allow initializing a Surface-less EGL context
[occt.git] / src / OpenGl / OpenGl_Window.cxx
1 // Created on: 2011-09-20
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <OpenGl_GlCore12.hxx>
17
18 #include <OpenGl_Context.hxx>
19 #include <OpenGl_GraphicDriver.hxx>
20 #include <OpenGl_Window.hxx>
21 #include <OpenGl_FrameBuffer.hxx>
22
23 #include <Aspect_GraphicDeviceDefinitionError.hxx>
24 #include <Graphic3d_TransformUtils.hxx>
25 #include <TCollection_AsciiString.hxx>
26 #include <TCollection_ExtendedString.hxx>
27 #include <Graphic3d_GraphicDriver.hxx>
28
29 #include <memory>
30
31 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Window,Standard_Transient)
32
33 #if defined(HAVE_EGL)
34   #include <EGL/egl.h>
35 #endif
36
37
38 #if !defined(__APPLE__) || defined(MACOSX_USE_GLX)
39
40 namespace
41 {
42
43 #if defined(HAVE_EGL)
44   //
45 #elif defined(_WIN32)
46
47   // WGL_ARB_pixel_format
48 #ifndef WGL_NUMBER_PIXEL_FORMATS_ARB
49   #define WGL_NUMBER_PIXEL_FORMATS_ARB            0x2000
50   #define WGL_DRAW_TO_WINDOW_ARB                  0x2001
51   #define WGL_DRAW_TO_BITMAP_ARB                  0x2002
52   #define WGL_ACCELERATION_ARB                    0x2003
53   #define WGL_NEED_PALETTE_ARB                    0x2004
54   #define WGL_NEED_SYSTEM_PALETTE_ARB             0x2005
55   #define WGL_SWAP_LAYER_BUFFERS_ARB              0x2006
56   #define WGL_SWAP_METHOD_ARB                     0x2007
57   #define WGL_NUMBER_OVERLAYS_ARB                 0x2008
58   #define WGL_NUMBER_UNDERLAYS_ARB                0x2009
59   #define WGL_TRANSPARENT_ARB                     0x200A
60   #define WGL_TRANSPARENT_RED_VALUE_ARB           0x2037
61   #define WGL_TRANSPARENT_GREEN_VALUE_ARB         0x2038
62   #define WGL_TRANSPARENT_BLUE_VALUE_ARB          0x2039
63   #define WGL_TRANSPARENT_ALPHA_VALUE_ARB         0x203A
64   #define WGL_TRANSPARENT_INDEX_VALUE_ARB         0x203B
65   #define WGL_SHARE_DEPTH_ARB                     0x200C
66   #define WGL_SHARE_STENCIL_ARB                   0x200D
67   #define WGL_SHARE_ACCUM_ARB                     0x200E
68   #define WGL_SUPPORT_GDI_ARB                     0x200F
69   #define WGL_SUPPORT_OPENGL_ARB                  0x2010
70   #define WGL_DOUBLE_BUFFER_ARB                   0x2011
71   #define WGL_STEREO_ARB                          0x2012
72   #define WGL_PIXEL_TYPE_ARB                      0x2013
73   #define WGL_COLOR_BITS_ARB                      0x2014
74   #define WGL_RED_BITS_ARB                        0x2015
75   #define WGL_RED_SHIFT_ARB                       0x2016
76   #define WGL_GREEN_BITS_ARB                      0x2017
77   #define WGL_GREEN_SHIFT_ARB                     0x2018
78   #define WGL_BLUE_BITS_ARB                       0x2019
79   #define WGL_BLUE_SHIFT_ARB                      0x201A
80   #define WGL_ALPHA_BITS_ARB                      0x201B
81   #define WGL_ALPHA_SHIFT_ARB                     0x201C
82   #define WGL_ACCUM_BITS_ARB                      0x201D
83   #define WGL_ACCUM_RED_BITS_ARB                  0x201E
84   #define WGL_ACCUM_GREEN_BITS_ARB                0x201F
85   #define WGL_ACCUM_BLUE_BITS_ARB                 0x2020
86   #define WGL_ACCUM_ALPHA_BITS_ARB                0x2021
87   #define WGL_DEPTH_BITS_ARB                      0x2022
88   #define WGL_STENCIL_BITS_ARB                    0x2023
89   #define WGL_AUX_BUFFERS_ARB                     0x2024
90
91   #define WGL_NO_ACCELERATION_ARB                 0x2025
92   #define WGL_GENERIC_ACCELERATION_ARB            0x2026
93   #define WGL_FULL_ACCELERATION_ARB               0x2027
94
95   #define WGL_SWAP_EXCHANGE_ARB                   0x2028
96   #define WGL_SWAP_COPY_ARB                       0x2029
97   #define WGL_SWAP_UNDEFINED_ARB                  0x202A
98
99   #define WGL_TYPE_RGBA_ARB                       0x202B
100   #define WGL_TYPE_COLORINDEX_ARB                 0x202C
101 #endif // WGL_NUMBER_PIXEL_FORMATS_ARB
102
103   // WGL_ARB_create_context_profile
104 #ifndef WGL_CONTEXT_MAJOR_VERSION_ARB
105   #define WGL_CONTEXT_MAJOR_VERSION_ARB           0x2091
106   #define WGL_CONTEXT_MINOR_VERSION_ARB           0x2092
107   #define WGL_CONTEXT_LAYER_PLANE_ARB             0x2093
108   #define WGL_CONTEXT_FLAGS_ARB                   0x2094
109   #define WGL_CONTEXT_PROFILE_MASK_ARB            0x9126
110
111   // WGL_CONTEXT_FLAGS bits
112   #define WGL_CONTEXT_DEBUG_BIT_ARB               0x0001
113   #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB  0x0002
114
115   // WGL_CONTEXT_PROFILE_MASK_ARB bits
116   #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB          0x00000001
117   #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
118 #endif // WGL_CONTEXT_MAJOR_VERSION_ARB
119
120   static LRESULT CALLBACK wndProcDummy (HWND theWin, UINT theMsg, WPARAM theParamW, LPARAM theParamL)
121   {
122     return DefWindowProcW (theWin, theMsg, theParamW, theParamL);
123   }
124 #else
125
126   // GLX_ARB_create_context
127 #ifndef GLX_CONTEXT_MAJOR_VERSION_ARB
128   #define GLX_CONTEXT_DEBUG_BIT_ARB         0x00000001
129   #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
130   #define GLX_CONTEXT_MAJOR_VERSION_ARB     0x2091
131   #define GLX_CONTEXT_MINOR_VERSION_ARB     0x2092
132   #define GLX_CONTEXT_FLAGS_ARB             0x2094
133
134   // GLX_ARB_create_context_profile
135   #define GLX_CONTEXT_CORE_PROFILE_BIT_ARB  0x00000001
136   #define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
137   #define GLX_CONTEXT_PROFILE_MASK_ARB      0x9126
138 #endif
139
140   //! Dummy XError handler which just skips errors
141   static int xErrorDummyHandler (Display*     /*theDisplay*/,
142                                  XErrorEvent* /*theErrorEvent*/)
143   {
144     return 0;
145   }
146
147   //! Auxiliary method to format list.
148   static void addMsgToList (TCollection_ExtendedString&       theList,
149                             const TCollection_ExtendedString& theMsg)
150   {
151     if (!theList.IsEmpty())
152     {
153       theList += ", ";
154     }
155     theList += theMsg;
156   }
157 #endif
158
159 }
160
161 // =======================================================================
162 // function : OpenGl_Window
163 // purpose  :
164 // =======================================================================
165 OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
166                               const Handle(Aspect_Window)&  thePlatformWindow,
167                               Aspect_RenderingContext       theGContext,
168                               const Handle(OpenGl_Caps)&    theCaps,
169                               const Handle(OpenGl_Context)& theShareCtx)
170 : myGlContext (new OpenGl_Context (theCaps)),
171   myOwnGContext (theGContext == 0),
172   myPlatformWindow (thePlatformWindow),
173   mySwapInterval (theCaps->swapInterval)
174 {
175   myPlatformWindow->Size (myWidth, myHeight);
176
177   Standard_Boolean isCoreProfile = Standard_False;
178
179 #if defined(HAVE_EGL)
180   EGLDisplay anEglDisplay = (EGLDisplay )theDriver->getRawGlDisplay();
181   EGLContext anEglContext = (EGLContext )theDriver->getRawGlContext();
182   EGLConfig  anEglConfig  = (EGLConfig  )theDriver->getRawGlConfig();
183   if (anEglDisplay == EGL_NO_DISPLAY
184    || anEglContext == EGL_NO_CONTEXT
185    || (anEglConfig == NULL
186     && (EGLContext )theGContext == EGL_NO_CONTEXT))
187   {
188     throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL does not provide compatible configurations!");
189     return;
190   }
191
192   EGLSurface anEglSurf = EGL_NO_SURFACE;
193   if ((EGLContext )theGContext == EGL_NO_CONTEXT)
194   {
195     // create new surface
196     anEglSurf = eglCreateWindowSurface (anEglDisplay,
197                                         anEglConfig,
198                                         (EGLNativeWindowType )myPlatformWindow->NativeHandle(),
199                                         NULL);
200     if (anEglSurf == EGL_NO_SURFACE)
201     {
202       throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is unable to create surface for window!");
203       return;
204     }
205   }
206   else if (theGContext != anEglContext)
207   {
208     throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is used in unsupported combination!");
209     return;
210   }
211   else
212   {
213     anEglSurf = eglGetCurrentSurface(EGL_DRAW);
214     if (anEglSurf == EGL_NO_SURFACE)
215     {
216       // window-less EGL context (off-screen)
217       //throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is unable to retrieve current surface!");
218       if (anEglConfig != NULL)
219       {
220         const int aSurfAttribs[] =
221         {
222           EGL_WIDTH,  myWidth,
223           EGL_HEIGHT, myHeight,
224           EGL_NONE
225         };
226         anEglSurf = eglCreatePbufferSurface (anEglDisplay, anEglConfig, aSurfAttribs);
227         if (anEglSurf == EGL_NO_SURFACE)
228         {
229           throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is unable to create off-screen surface!");
230         }
231       }
232       myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW,
233                                 "OpenGl_Window::CreateWindow: WARNING, a Window is created without a EGL Surface!");
234     }
235   }
236
237   myGlContext->Init ((Aspect_Drawable )anEglSurf, (Aspect_Display )anEglDisplay, (Aspect_RenderingContext )anEglContext, isCoreProfile);
238 #elif defined(_WIN32)
239   (void )theDriver;
240   HWND  aWindow   = (HWND )myPlatformWindow->NativeHandle();
241   HDC   aWindowDC = GetDC (aWindow);
242   HGLRC aGContext = (HGLRC )theGContext;
243
244   PIXELFORMATDESCRIPTOR aPixelFrmt;
245   memset (&aPixelFrmt, 0, sizeof(aPixelFrmt));
246   aPixelFrmt.nSize        = sizeof(PIXELFORMATDESCRIPTOR);
247   aPixelFrmt.nVersion     = 1;
248   aPixelFrmt.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
249   aPixelFrmt.iPixelType   = PFD_TYPE_RGBA;
250   aPixelFrmt.cColorBits   = 24;
251   aPixelFrmt.cDepthBits   = 24;
252   aPixelFrmt.cStencilBits = 8;
253   aPixelFrmt.iLayerType   = PFD_MAIN_PLANE;
254   if (theCaps->contextStereo)
255   {
256     aPixelFrmt.dwFlags |= PFD_STEREO;
257   }
258
259   int aPixelFrmtId = ChoosePixelFormat (aWindowDC, &aPixelFrmt);
260
261   // in case of failure try without stereo if any
262   const Standard_Boolean hasStereo = aPixelFrmtId != 0 && theCaps->contextStereo;
263   if (aPixelFrmtId == 0 && theCaps->contextStereo)
264   {
265     TCollection_ExtendedString aMsg ("OpenGl_Window::CreateWindow: "
266                                      "ChoosePixelFormat is unable to find stereo supported pixel format. "
267                                      "Choosing similar non stereo format.");
268     myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
269                               GL_DEBUG_TYPE_OTHER,
270                               0, GL_DEBUG_SEVERITY_HIGH, aMsg);
271
272     aPixelFrmt.dwFlags &= ~PFD_STEREO;
273     aPixelFrmtId = ChoosePixelFormat (aWindowDC, &aPixelFrmt);
274   }
275
276   if (aPixelFrmtId == 0)
277   {
278     ReleaseDC (aWindow, aWindowDC);
279
280     TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: ChoosePixelFormat failed. Error code: ");
281     aMsg += (int )GetLastError();
282     throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
283     return;
284   }
285
286   DescribePixelFormat (aWindowDC, aPixelFrmtId, sizeof(aPixelFrmt), &aPixelFrmt);
287
288   HGLRC aSlaveCtx = !theShareCtx.IsNull() ? (HGLRC )theShareCtx->myGContext : NULL;
289   if (aGContext == NULL)
290   {
291     // create temporary context to retrieve advanced context creation procedures
292     HMODULE aModule = GetModuleHandleW(NULL);
293     WNDCLASSW aClass; memset (&aClass, 0, sizeof(aClass));
294     aClass.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
295     aClass.lpfnWndProc   = wndProcDummy;
296     aClass.hInstance     = aModule;
297     aClass.lpszClassName = L"OpenGl_WindowTmp";
298     HWND  aWinTmp     = NULL;
299     HDC   aDevCtxTmp  = NULL;
300     HGLRC aRendCtxTmp = NULL;
301     if ((!theCaps->contextDebug && !theCaps->contextNoAccel && theCaps->contextCompatible)
302      || RegisterClassW (&aClass) == 0)
303     {
304       aClass.lpszClassName = NULL;
305     }
306     if (aClass.lpszClassName != NULL)
307     {
308       DWORD anExStyle = WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE;
309     #if (_WIN32_WINNT >= 0x0500)
310       anExStyle |= WS_EX_NOACTIVATE;
311     #endif
312       aWinTmp = CreateWindowExW(anExStyle,
313                                 aClass.lpszClassName, L"OpenGl_WindowTmp",
314                                 WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED,
315                                 2, 2, 4, 4,
316                                 NULL, NULL, aModule, NULL);
317     }
318     if (aWinTmp != NULL)
319     {
320       aDevCtxTmp = GetDC (aWinTmp);
321       SetPixelFormat (aDevCtxTmp, aPixelFrmtId, &aPixelFrmt);
322       aRendCtxTmp = wglCreateContext (aDevCtxTmp);
323     }
324
325     typedef BOOL (WINAPI *wglChoosePixelFormatARB_t)(HDC           theDevCtx,
326                                                      const int*    theIntAttribs,
327                                                      const float*  theFloatAttribs,
328                                                      unsigned int  theMaxFormats,
329                                                      int*          theFormatsOut,
330                                                      unsigned int* theNumFormatsOut);
331     typedef HGLRC (WINAPI *wglCreateContextAttribsARB_t)(HDC        theDevCtx,
332                                                          HGLRC      theShareContext,
333                                                          const int* theAttribs);
334     wglChoosePixelFormatARB_t    aChoosePixProc = NULL;
335     wglCreateContextAttribsARB_t aCreateCtxProc = NULL;
336     if (aRendCtxTmp != NULL)
337     {
338       wglMakeCurrent (aDevCtxTmp, aRendCtxTmp);
339
340       typedef const char* (WINAPI *wglGetExtensionsStringARB_t)(HDC theDeviceContext);
341       wglGetExtensionsStringARB_t aGetExtensions = (wglGetExtensionsStringARB_t  )wglGetProcAddress ("wglGetExtensionsStringARB");
342       const char* aWglExts = (aGetExtensions != NULL) ? aGetExtensions (wglGetCurrentDC()) : NULL;
343       if (OpenGl_Context::CheckExtension (aWglExts, "WGL_ARB_pixel_format"))
344       {
345         aChoosePixProc = (wglChoosePixelFormatARB_t    )wglGetProcAddress ("wglChoosePixelFormatARB");
346       }
347       if (OpenGl_Context::CheckExtension (aWglExts, "WGL_ARB_create_context_profile"))
348       {
349         aCreateCtxProc = (wglCreateContextAttribsARB_t )wglGetProcAddress ("wglCreateContextAttribsARB");
350       }
351     }
352
353     // choose extended pixel format
354     if (aChoosePixProc != NULL)
355     {
356       const int aPixAttribs[] =
357       {
358         WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
359         WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
360         WGL_DOUBLE_BUFFER_ARB,  GL_TRUE,
361         WGL_STEREO_ARB,         hasStereo ? GL_TRUE : GL_FALSE,
362         WGL_PIXEL_TYPE_ARB,     WGL_TYPE_RGBA_ARB,
363         //WGL_SAMPLE_BUFFERS_ARB, 1,
364         //WGL_SAMPLES_ARB,        8,
365         WGL_COLOR_BITS_ARB,     24,
366         WGL_DEPTH_BITS_ARB,     24,
367         WGL_STENCIL_BITS_ARB,   8,
368         WGL_ACCELERATION_ARB,   theCaps->contextNoAccel ? WGL_NO_ACCELERATION_ARB : WGL_FULL_ACCELERATION_ARB,
369         0, 0,
370       };
371       unsigned int aFrmtsNb = 0;
372       aChoosePixProc (aWindowDC, aPixAttribs, NULL, 1, &aPixelFrmtId, &aFrmtsNb);
373     }
374
375     // setup pixel format - may be set only once per window
376     if (!SetPixelFormat (aWindowDC, aPixelFrmtId, &aPixelFrmt))
377     {
378       ReleaseDC (aWindow, aWindowDC);
379
380       TCollection_AsciiString aMsg("OpenGl_Window::CreateWindow: SetPixelFormat failed. Error code: ");
381       aMsg += (int )GetLastError();
382       throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
383       return;
384     }
385
386     // create GL context with extra options
387     if (aCreateCtxProc != NULL)
388     {
389       if (!theCaps->contextCompatible)
390       {
391         int aCoreCtxAttribs[] =
392         {
393           WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
394           WGL_CONTEXT_MINOR_VERSION_ARB, 2,
395           WGL_CONTEXT_PROFILE_MASK_ARB,  WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
396           WGL_CONTEXT_FLAGS_ARB,         theCaps->contextDebug ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
397           0, 0
398         };
399
400         // Try to create the core profile of highest OpenGL version supported by OCCT
401         // (this will be done automatically by some drivers when requesting 3.2,
402         //  but some will not (e.g. AMD Catalyst) since WGL_ARB_create_context_profile specification allows both implementations).
403         for (int aLowVer4 = 5; aLowVer4 >= 0 && aGContext == NULL; --aLowVer4)
404         {
405           aCoreCtxAttribs[1] = 4;
406           aCoreCtxAttribs[3] = aLowVer4;
407           aGContext = aCreateCtxProc (aWindowDC, aSlaveCtx, aCoreCtxAttribs);
408         }
409         for (int aLowVer3 = 3; aLowVer3 >= 2 && aGContext == NULL; --aLowVer3)
410         {
411           aCoreCtxAttribs[1] = 3;
412           aCoreCtxAttribs[3] = aLowVer3;
413           aGContext = aCreateCtxProc (aWindowDC, aSlaveCtx, aCoreCtxAttribs);
414         }
415         isCoreProfile = aGContext != NULL;
416       }
417
418       if (aGContext == NULL)
419       {
420         int aCtxAttribs[] =
421         {
422           // Beware! NVIDIA drivers reject context creation when WGL_CONTEXT_PROFILE_MASK_ARB are specified
423           // but not WGL_CONTEXT_MAJOR_VERSION_ARB/WGL_CONTEXT_MINOR_VERSION_ARB.
424           //WGL_CONTEXT_PROFILE_MASK_ARB,  WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
425           WGL_CONTEXT_FLAGS_ARB,         theCaps->contextDebug ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
426           0, 0
427         };
428         isCoreProfile = Standard_False;
429         aGContext = aCreateCtxProc (aWindowDC, aSlaveCtx, aCtxAttribs);
430
431         if (aGContext != NULL
432         && !theCaps->contextCompatible)
433         {
434           TCollection_ExtendedString aMsg("OpenGl_Window::CreateWindow: core profile creation failed.");
435           myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
436         }
437       }
438
439       if (aGContext != NULL)
440       {
441         aSlaveCtx = NULL;
442       }
443     }
444
445     if (aRendCtxTmp != NULL)
446     {
447       wglDeleteContext (aRendCtxTmp);
448     }
449     if (aDevCtxTmp != NULL)
450     {
451       ReleaseDC (aWinTmp, aDevCtxTmp);
452     }
453     if (aWinTmp != NULL)
454     {
455       DestroyWindow (aWinTmp);
456     }
457     if (aClass.lpszClassName != NULL)
458     {
459       UnregisterClassW (aClass.lpszClassName, aModule);
460     }
461
462     if (aGContext == NULL)
463     {
464       // create context using obsolete functionality
465       aGContext = wglCreateContext (aWindowDC);
466     }
467     if (aGContext == NULL)
468     {
469       ReleaseDC (aWindow, aWindowDC);
470
471       TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: wglCreateContext failed. Error code: ");
472       aMsg += (int )GetLastError();
473       throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
474       return;
475     }
476   }
477
478   // all GL context within one OpenGl_GraphicDriver should be shared!
479   if (aSlaveCtx != NULL && wglShareLists (aSlaveCtx, aGContext) != TRUE)
480   {
481     TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: wglShareLists failed. Error code: ");
482     aMsg += (int )GetLastError();
483     throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
484     return;
485   }
486
487   myGlContext->Init ((Aspect_Handle )aWindow, (Aspect_Handle )aWindowDC, (Aspect_RenderingContext )aGContext, isCoreProfile);
488 #else
489   Window     aWindow   = (Window )myPlatformWindow->NativeHandle();
490   Display*   aDisp     = theDriver->GetDisplayConnection()->GetDisplay();
491   GLXContext aGContext = (GLXContext )theGContext;
492   GLXContext aSlaveCtx = !theShareCtx.IsNull() ? (GLXContext )theShareCtx->myGContext : NULL;
493
494   XWindowAttributes aWinAttribs;
495   XGetWindowAttributes (aDisp, aWindow, &aWinAttribs);
496   XVisualInfo aVisInfo;
497   aVisInfo.visualid = aWinAttribs.visual->visualid;
498   aVisInfo.screen   = DefaultScreen (aDisp);
499   int aNbItems;
500   std::unique_ptr<XVisualInfo, int(*)(void*)> aVis (XGetVisualInfo (aDisp, VisualIDMask | VisualScreenMask, &aVisInfo, &aNbItems), &XFree);
501   int isGl = 0;
502   if (aVis.get() == NULL)
503   {
504     throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window::CreateWindow: XGetVisualInfo is unable to choose needed configuration in existing OpenGL context. ");
505     return;
506   }
507   else if (glXGetConfig (aDisp, aVis.get(), GLX_USE_GL, &isGl) != 0 || !isGl)
508   {
509     throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window::CreateWindow: window Visual does not support GL rendering!");
510     return;
511   }
512
513   // create new context
514   GLXFBConfig anFBConfig = myPlatformWindow->NativeFBConfig();
515   const char* aGlxExts   = glXQueryExtensionsString (aDisp, aVisInfo.screen);
516   if (myOwnGContext
517    && anFBConfig != NULL
518    && OpenGl_Context::CheckExtension (aGlxExts, "GLX_ARB_create_context_profile"))
519   {
520     // Replace default XError handler to ignore errors.
521     // Warning - this is global for all threads!
522     typedef int (*xerrorhandler_t)(Display* , XErrorEvent* );
523     xerrorhandler_t anOldHandler = XSetErrorHandler(xErrorDummyHandler);
524
525     typedef GLXContext (*glXCreateContextAttribsARB_t)(Display* dpy, GLXFBConfig config,
526                                                        GLXContext share_context, Bool direct,
527                                                        const int* attrib_list);
528     glXCreateContextAttribsARB_t aCreateCtxProc = (glXCreateContextAttribsARB_t )glXGetProcAddress((const GLubyte* )"glXCreateContextAttribsARB");
529     if (!theCaps->contextCompatible)
530     {
531       int aCoreCtxAttribs[] =
532       {
533         GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
534         GLX_CONTEXT_MINOR_VERSION_ARB, 2,
535         GLX_CONTEXT_PROFILE_MASK_ARB,  GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
536         GLX_CONTEXT_FLAGS_ARB,         theCaps->contextDebug ? GLX_CONTEXT_DEBUG_BIT_ARB : 0,
537         0, 0
538       };
539
540       // try to create the core profile of highest OpenGL version supported by OCCT
541       for (int aLowVer4 = 5; aLowVer4 >= 0 && aGContext == NULL; --aLowVer4)
542       {
543         aCoreCtxAttribs[1] = 4;
544         aCoreCtxAttribs[3] = aLowVer4;
545         aGContext = aCreateCtxProc (aDisp, anFBConfig, aSlaveCtx, True, aCoreCtxAttribs);
546       }
547       for (int aLowVer3 = 3; aLowVer3 >= 2 && aGContext == NULL; --aLowVer3)
548       {
549         aCoreCtxAttribs[1] = 3;
550         aCoreCtxAttribs[3] = aLowVer3;
551         aGContext = aCreateCtxProc (aDisp, anFBConfig, aSlaveCtx, True, aCoreCtxAttribs);
552       }
553       isCoreProfile = aGContext != NULL;
554     }
555
556     if (aGContext == NULL)
557     {
558       int aCtxAttribs[] =
559       {
560         GLX_CONTEXT_FLAGS_ARB, theCaps->contextDebug ? GLX_CONTEXT_DEBUG_BIT_ARB : 0,
561         0, 0
562       };
563       isCoreProfile = Standard_False;
564       aGContext = aCreateCtxProc (aDisp, anFBConfig, aSlaveCtx, True, aCtxAttribs);
565
566       if (aGContext != NULL
567       && !theCaps->contextCompatible)
568       {
569         TCollection_ExtendedString aMsg("OpenGl_Window::CreateWindow: core profile creation failed.");
570         myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
571       }
572     }
573     XSetErrorHandler(anOldHandler);
574   }
575
576   if (myOwnGContext
577    && aGContext == NULL)
578   {
579     aGContext = glXCreateContext (aDisp, aVis.get(), aSlaveCtx, GL_TRUE);
580     if (aGContext == NULL)
581     {
582       throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window::CreateWindow: glXCreateContext failed.");
583       return;
584     }
585   }
586
587   // check Visual for OpenGl context's parameters compatibility
588   TCollection_ExtendedString aList;
589   int isDoubleBuffer = 0, isRGBA = 0, isStereo = 0;
590   int aDepthSize = 0, aStencilSize = 0;
591   glXGetConfig (aDisp, aVis.get(), GLX_RGBA,         &isRGBA);
592   glXGetConfig (aDisp, aVis.get(), GLX_DOUBLEBUFFER, &isDoubleBuffer);
593   glXGetConfig (aDisp, aVis.get(), GLX_STEREO,       &isStereo);
594   glXGetConfig (aDisp, aVis.get(), GLX_DEPTH_SIZE,   &aDepthSize);
595   glXGetConfig (aDisp, aVis.get(), GLX_STENCIL_SIZE, &aStencilSize);
596   if (aDepthSize < 1)      addMsgToList (aList, "no depth buffer");
597   if (aStencilSize < 1)    addMsgToList (aList, "no stencil buffer");
598   if (isRGBA == 0)         addMsgToList (aList, "no RGBA color buffer");
599   if (isDoubleBuffer == 0) addMsgToList (aList, "no Double Buffer");
600   if (theCaps->contextStereo && isStereo == 0)
601   {
602     addMsgToList (aList, "no Quad Buffer");
603   }
604   else if (!theCaps->contextStereo && isStereo == 1)
605   {
606     addMsgToList (aList, "extra Quad Buffer");
607   }
608   if (!aList.IsEmpty())
609   {
610     TCollection_ExtendedString aMsg = TCollection_ExtendedString ("OpenGl_Window::CreateWindow: window Visual is incomplete: ") + aList;
611     myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
612                               GL_DEBUG_TYPE_OTHER,
613                               0, GL_DEBUG_SEVERITY_MEDIUM, aMsg);
614   }
615
616   myGlContext->Init ((Aspect_Drawable )aWindow, (Aspect_Display )aDisp, (Aspect_RenderingContext )aGContext, isCoreProfile);
617 #endif
618   myGlContext->Share (theShareCtx);
619   myGlContext->SetSwapInterval (mySwapInterval);
620   Init();
621 }
622
623 // =======================================================================
624 // function : ~OpenGl_Window
625 // purpose  :
626 // =======================================================================
627 OpenGl_Window::~OpenGl_Window()
628 {
629   if (!myOwnGContext
630    ||  myGlContext.IsNull())
631   {
632     myGlContext.Nullify();
633     return;
634   }
635
636   // release "GL" context if it is owned by window
637   // Mesa implementation can fail to destroy GL context if it set for current thread.
638   // It should be safer to unset thread GL context before its destruction.
639 #if defined(HAVE_EGL)
640   if ((EGLSurface )myGlContext->myWindow != EGL_NO_SURFACE)
641   {
642     eglDestroySurface ((EGLDisplay )myGlContext->myDisplay,
643                        (EGLSurface )myGlContext->myWindow);
644   }
645 #elif defined(_WIN32)
646   HWND  aWindow          = (HWND  )myGlContext->myWindow;
647   HDC   aWindowDC        = (HDC   )myGlContext->myWindowDC;
648   HGLRC aWindowGContext  = (HGLRC )myGlContext->myGContext;
649   HGLRC aThreadGContext  = wglGetCurrentContext();
650   myGlContext.Nullify();
651
652   if (aThreadGContext != NULL)
653   {
654     if (aThreadGContext == aWindowGContext)
655     {
656       wglMakeCurrent (NULL, NULL);
657     }
658
659     wglDeleteContext (aWindowGContext);
660   }
661   ReleaseDC (aWindow, aWindowDC);
662 #else
663   Display*    aDisplay        = (Display*    )myGlContext->myDisplay;
664   GLXContext  aWindowGContext = (GLXContext  )myGlContext->myGContext;
665   GLXContext  aThreadGContext = glXGetCurrentContext();
666   myGlContext.Nullify();
667
668   if (aDisplay != NULL)
669   {
670     if (aThreadGContext == aWindowGContext)
671     {
672       glXMakeCurrent (aDisplay, None, NULL);
673     }
674
675     // FSXXX sync necessary if non-direct rendering
676     glXWaitGL();
677     glXDestroyContext (aDisplay, aWindowGContext);
678   }
679 #endif
680 }
681
682 #endif // !__APPLE__
683
684 // =======================================================================
685 // function : Activate
686 // purpose  :
687 // =======================================================================
688 Standard_Boolean OpenGl_Window::Activate()
689 {
690   return myGlContext->MakeCurrent();
691 }
692
693 #if !defined(__APPLE__) || defined(MACOSX_USE_GLX)
694
695 // =======================================================================
696 // function : Resize
697 // purpose  : call_subr_resize
698 // =======================================================================
699 void OpenGl_Window::Resize()
700 {
701 #if !defined(_WIN32) && !defined(HAVE_EGL)
702   Display* aDisp = (Display* )myGlContext->myDisplay;
703   if (aDisp == NULL)
704     return;
705 #endif
706
707   Standard_Integer aWidth  = 0;
708   Standard_Integer aHeight = 0;
709   myPlatformWindow->Size (aWidth, aHeight);
710
711   // If the size is not changed - do nothing
712   if ((myWidth == aWidth) && (myHeight == aHeight))
713     return;
714
715   myWidth  = aWidth;
716   myHeight = aHeight;
717
718 #if !defined(_WIN32) && !defined(HAVE_EGL)
719   XResizeWindow (aDisp, myGlContext->myWindow, (unsigned int )myWidth, (unsigned int )myHeight);
720   XSync (aDisp, False);
721 #endif
722
723   Init();
724 }
725
726 // =======================================================================
727 // function : Init
728 // purpose  :
729 // =======================================================================
730 void OpenGl_Window::Init()
731 {
732   if (!Activate())
733     return;
734
735 #if defined(HAVE_EGL)
736   if ((EGLSurface )myGlContext->myWindow == EGL_NO_SURFACE)
737   {
738     // define an offscreen default FBO to avoid rendering into EGL_NO_SURFACE;
739     // note that this code is currently never called, since eglCreatePbufferSurface() is used instead as more robust solution
740     // for offscreen rendering on bugged OpenGL ES drivers
741     Handle(OpenGl_FrameBuffer) aDefFbo = myGlContext->SetDefaultFrameBuffer (Handle(OpenGl_FrameBuffer)());
742     if (!aDefFbo.IsNull())
743     {
744       aDefFbo->Release (myGlContext.operator->());
745     }
746     else
747     {
748       aDefFbo = new OpenGl_FrameBuffer();
749     }
750
751     if (!aDefFbo->InitWithRB (myGlContext, myWidth, myHeight, GL_RGBA8, GL_DEPTH24_STENCIL8))
752     {
753       TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: default FBO creation failed");
754       throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
755     }
756     myGlContext->SetDefaultFrameBuffer (aDefFbo);
757     aDefFbo->BindBuffer (myGlContext);
758   }
759   else if (!myPlatformWindow->IsVirtual())
760   {
761     eglQuerySurface ((EGLDisplay )myGlContext->myDisplay, (EGLSurface )myGlContext->myWindow, EGL_WIDTH,  &myWidth);
762     eglQuerySurface ((EGLDisplay )myGlContext->myDisplay, (EGLSurface )myGlContext->myWindow, EGL_HEIGHT, &myHeight);
763   }
764 #elif defined(_WIN32)
765   //
766 #else
767   Window aRootWin;
768   int aDummy;
769   unsigned int aDummyU;
770   unsigned int aNewWidth  = 0;
771   unsigned int aNewHeight = 0;
772   Display* aDisp = (Display* )myGlContext->myDisplay;
773   XGetGeometry (aDisp, myGlContext->myWindow, &aRootWin, &aDummy, &aDummy, &aNewWidth, &aNewHeight, &aDummyU, &aDummyU);
774   myWidth  = aNewWidth;
775   myHeight = aNewHeight;
776 #endif
777
778   glDisable (GL_DITHER);
779   glDisable (GL_SCISSOR_TEST);
780   const Standard_Integer aViewport[4] = { 0, 0, myWidth, myHeight };
781   myGlContext->ResizeViewport (aViewport);
782 #if !defined(GL_ES_VERSION_2_0)
783   myGlContext->SetDrawBuffer (GL_BACK);
784   if (myGlContext->core11 != NULL)
785   {
786     glMatrixMode (GL_MODELVIEW);
787   }
788 #endif
789 }
790
791 // =======================================================================
792 // function : SetSwapInterval
793 // purpose  :
794 // =======================================================================
795 void OpenGl_Window::SetSwapInterval()
796 {
797   if (mySwapInterval != myGlContext->caps->swapInterval)
798   {
799     mySwapInterval = myGlContext->caps->swapInterval;
800     myGlContext->SetSwapInterval (mySwapInterval);
801   }
802 }
803
804 #endif // !__APPLE__