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