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