0032308: Configuration - make Xlib dependency optional
[occt.git] / src / OpenGl / OpenGl_Window.cxx
CommitLineData
b311480e 1// Created on: 2011-09-20
2// Created by: Sergey ZERCHANINOV
973c2be1 3// Copyright (c) 2011-2014 OPEN CASCADE SAS
b311480e 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
b311480e 6//
d5f74e42 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
973c2be1 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.
b311480e 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
b311480e 15
b5ac8292 16#include <OpenGl_GlCore12.hxx>
2166f0fa 17
2166f0fa 18#include <OpenGl_Context.hxx>
25b97fac 19#include <OpenGl_GraphicDriver.hxx>
c827ea3a 20#include <OpenGl_Window.hxx>
39235bed 21#include <OpenGl_FrameBuffer.hxx>
2166f0fa
SK
22
23#include <Aspect_GraphicDeviceDefinitionError.hxx>
825aa485 24#include <Graphic3d_TransformUtils.hxx>
2166f0fa 25#include <TCollection_AsciiString.hxx>
b5ac8292 26#include <TCollection_ExtendedString.hxx>
c04c30b3 27#include <Graphic3d_GraphicDriver.hxx>
2166f0fa 28
2f690078 29#include <memory>
30
f4a7308f 31#include <Standard_WarningDisableFunctionCast.hxx>
32
25e59720 33IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Window,Standard_Transient)
92efcf78 34
1ce0716b 35#if defined(HAVE_EGL)
25b97fac 36 #include <EGL/egl.h>
b69e576a 37#elif defined(HAVE_XLIB)
38 #include <GL/glx.h>
25b97fac 39#endif
40
b69e576a 41#if !defined(__APPLE__) || defined(HAVE_XLIB)
4fe56619 42
2166f0fa
SK
43namespace
44{
2166f0fa 45
1ce0716b 46#if defined(HAVE_EGL)
25b97fac 47 //
48#elif defined(_WIN32)
58655684 49
abe46077 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
58655684 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 }
b69e576a 127#elif defined(HAVE_XLIB)
b6bf4ec1 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)
2166f0fa 153 {
b6bf4ec1 154 if (!theList.IsEmpty())
155 {
156 theList += ", ";
157 }
158 theList += theMsg;
2166f0fa
SK
159 }
160#endif
161
5640d653 162}
2166f0fa
SK
163
164// =======================================================================
165// function : OpenGl_Window
166// purpose :
167// =======================================================================
25b97fac 168OpenGl_Window::OpenGl_Window (const Handle(OpenGl_GraphicDriver)& theDriver,
c357e426 169 const Handle(Aspect_Window)& thePlatformWindow,
5e27df78 170 Aspect_RenderingContext theGContext,
58655684 171 const Handle(OpenGl_Caps)& theCaps,
5e27df78 172 const Handle(OpenGl_Context)& theShareCtx)
73192b37 173: myGlContext (new OpenGl_Context (theCaps)),
2166f0fa 174 myOwnGContext (theGContext == 0),
c357e426 175 myPlatformWindow (thePlatformWindow),
f978241f 176 mySwapInterval (theCaps->swapInterval)
2166f0fa 177{
c357e426 178 myPlatformWindow->Size (myWidth, myHeight);
2166f0fa 179
4e1523ef 180 Standard_Boolean isCoreProfile = Standard_False;
181
1ce0716b 182#if defined(HAVE_EGL)
25b97fac 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
39235bed 188 || (anEglConfig == NULL
189 && (EGLContext )theGContext == EGL_NO_CONTEXT))
25b97fac 190 {
9775fa61 191 throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL does not provide compatible configurations!");
25b97fac 192 return;
193 }
194
195 EGLSurface anEglSurf = EGL_NO_SURFACE;
39235bed 196 if ((EGLContext )theGContext == EGL_NO_CONTEXT)
25b97fac 197 {
ba00aab7 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
25b97fac 205 // create new surface
c357e426 206 anEglSurf = eglCreateWindowSurface (anEglDisplay,
207 anEglConfig,
208 (EGLNativeWindowType )myPlatformWindow->NativeHandle(),
209 NULL);
b69e576a 210 if (anEglSurf == EGL_NO_SURFACE
211 && myPlatformWindow->NativeHandle() != 0)
25b97fac 212 {
9775fa61 213 throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is unable to create surface for window!");
b69e576a 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!");
25b97fac 239 }
240 }
241 else if (theGContext != anEglContext)
242 {
9775fa61 243 throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window, EGL is used in unsupported combination!");
25b97fac 244 }
245 else
246 {
247 anEglSurf = eglGetCurrentSurface(EGL_DRAW);
248 if (anEglSurf == EGL_NO_SURFACE)
249 {
39235bed 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 {
565baee6 254 #if !defined(__EMSCRIPTEN__) // eglCreatePbufferSurface() is not implemented by Emscripten EGL
39235bed 255 const int aSurfAttribs[] =
256 {
257 EGL_WIDTH, myWidth,
258 EGL_HEIGHT, myHeight,
ba00aab7 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,
39235bed 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 }
565baee6 268 #endif
39235bed 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!");
25b97fac 272 }
273 }
274
4e1523ef 275 myGlContext->Init ((Aspect_Drawable )anEglSurf, (Aspect_Display )anEglDisplay, (Aspect_RenderingContext )anEglContext, isCoreProfile);
25b97fac 276#elif defined(_WIN32)
277 (void )theDriver;
c357e426 278 HWND aWindow = (HWND )myPlatformWindow->NativeHandle();
5e27df78 279 HDC aWindowDC = GetDC (aWindow);
280 HGLRC aGContext = (HGLRC )theGContext;
281
3d8969b1 282 PIXELFORMATDESCRIPTOR aPixelFrmt;
abe46077 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);
b5ac8292 298
299 // in case of failure try without stereo if any
4e1523ef 300 const Standard_Boolean hasStereo = aPixelFrmtId != 0 && theCaps->contextStereo;
b5ac8292 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.");
3b523c4c 306 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
307 GL_DEBUG_TYPE_OTHER,
308 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
b5ac8292 309
310 aPixelFrmt.dwFlags &= ~PFD_STEREO;
311 aPixelFrmtId = ChoosePixelFormat (aWindowDC, &aPixelFrmt);
312 }
313
3d8969b1 314 if (aPixelFrmtId == 0)
5e27df78 315 {
316 ReleaseDC (aWindow, aWindowDC);
317
318 TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: ChoosePixelFormat failed. Error code: ");
319 aMsg += (int )GetLastError();
9775fa61 320 throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
5e27df78 321 return;
322 }
323
abe46077 324 DescribePixelFormat (aWindowDC, aPixelFrmtId, sizeof(aPixelFrmt), &aPixelFrmt);
5e27df78 325
58655684 326 HGLRC aSlaveCtx = !theShareCtx.IsNull() ? (HGLRC )theShareCtx->myGContext : NULL;
5e27df78 327 if (aGContext == NULL)
328 {
58655684 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;
4e1523ef 339 if ((!theCaps->contextDebug && !theCaps->contextNoAccel && theCaps->contextCompatible)
58655684 340 || RegisterClassW (&aClass) == 0)
341 {
342 aClass.lpszClassName = NULL;
343 }
344 if (aClass.lpszClassName != NULL)
345 {
229c0b6a 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,
58655684 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 }
abe46077 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;
58655684 374 if (aRendCtxTmp != NULL)
375 {
376 wglMakeCurrent (aDevCtxTmp, aRendCtxTmp);
377
378 typedef const char* (WINAPI *wglGetExtensionsStringARB_t)(HDC theDeviceContext);
abe46077 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,
4e1523ef 399 WGL_STEREO_ARB, hasStereo ? GL_TRUE : GL_FALSE,
abe46077 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,
ba00aab7 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,
abe46077 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();
9775fa61 424 throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
abe46077 425 return;
426 }
427
428 // create GL context with extra options
429 if (aCreateCtxProc != NULL)
430 {
4e1523ef 431 if (!theCaps->contextCompatible)
abe46077 432 {
4e1523ef 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).
72ed0644 445 for (int aLowVer4 = 6; aLowVer4 >= 0 && aGContext == NULL; --aLowVer4)
4e1523ef 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.");
3b523c4c 477 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
4e1523ef 478 }
479 }
abe46077 480
abe46077 481 if (aGContext != NULL)
58655684 482 {
abe46077 483 aSlaveCtx = NULL;
58655684 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 {
abe46077 506 // create context using obsolete functionality
58655684 507 aGContext = wglCreateContext (aWindowDC);
508 }
5e27df78 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();
9775fa61 515 throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
5e27df78 516 return;
517 }
518 }
519
520 // all GL context within one OpenGl_GraphicDriver should be shared!
58655684 521 if (aSlaveCtx != NULL && wglShareLists (aSlaveCtx, aGContext) != TRUE)
5e27df78 522 {
523 TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: wglShareLists failed. Error code: ");
524 aMsg += (int )GetLastError();
9775fa61 525 throw Aspect_GraphicDeviceDefinitionError(aMsg.ToCString());
5e27df78 526 return;
527 }
528
4e1523ef 529 myGlContext->Init ((Aspect_Handle )aWindow, (Aspect_Handle )aWindowDC, (Aspect_RenderingContext )aGContext, isCoreProfile);
b69e576a 530#elif defined(HAVE_XLIB)
b6bf4ec1 531 Window aWindow = (Window )myPlatformWindow->NativeHandle();
b69e576a 532 Display* aDisp = (Display* )theDriver->GetDisplayConnection()->GetDisplayAspect();
5e27df78 533 GLXContext aGContext = (GLXContext )theGContext;
b6bf4ec1 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;
2f690078 542 std::unique_ptr<XVisualInfo, int(*)(void*)> aVis (XGetVisualInfo (aDisp, VisualIDMask | VisualScreenMask, &aVisInfo, &aNbItems), &XFree);
b6bf4ec1 543 int isGl = 0;
2f690078 544 if (aVis.get() == NULL)
2166f0fa 545 {
9775fa61 546 throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window::CreateWindow: XGetVisualInfo is unable to choose needed configuration in existing OpenGL context. ");
b6bf4ec1 547 return;
2166f0fa 548 }
2f690078 549 else if (glXGetConfig (aDisp, aVis.get(), GLX_USE_GL, &isGl) != 0 || !isGl)
2166f0fa 550 {
9775fa61 551 throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window::CreateWindow: window Visual does not support GL rendering!");
b6bf4ec1 552 return;
553 }
3d8969b1 554
b6bf4ec1 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)
95db72f1 572 {
b6bf4ec1 573 int aCoreCtxAttribs[] =
95db72f1 574 {
b6bf4ec1 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
72ed0644 583 for (int aLowVer4 = 6; aLowVer4 >= 0 && aGContext == NULL; --aLowVer4)
2166f0fa 584 {
b6bf4ec1 585 aCoreCtxAttribs[1] = 4;
586 aCoreCtxAttribs[3] = aLowVer4;
587 aGContext = aCreateCtxProc (aDisp, anFBConfig, aSlaveCtx, True, aCoreCtxAttribs);
2166f0fa 588 }
b6bf4ec1 589 for (int aLowVer3 = 3; aLowVer3 >= 2 && aGContext == NULL; --aLowVer3)
95db72f1 590 {
b6bf4ec1 591 aCoreCtxAttribs[1] = 3;
592 aCoreCtxAttribs[3] = aLowVer3;
593 aGContext = aCreateCtxProc (aDisp, anFBConfig, aSlaveCtx, True, aCoreCtxAttribs);
95db72f1 594 }
b6bf4ec1 595 isCoreProfile = aGContext != NULL;
2166f0fa 596 }
2166f0fa 597
b6bf4ec1 598 if (aGContext == NULL)
2166f0fa 599 {
b6bf4ec1 600 int aCtxAttribs[] =
b5ac8292 601 {
b6bf4ec1 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);
b5ac8292 607
b6bf4ec1 608 if (aGContext != NULL
609 && !theCaps->contextCompatible)
95db72f1 610 {
b6bf4ec1 611 TCollection_ExtendedString aMsg("OpenGl_Window::CreateWindow: core profile creation failed.");
3b523c4c 612 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW, aMsg);
95db72f1 613 }
2166f0fa 614 }
b6bf4ec1 615 XSetErrorHandler(anOldHandler);
616 }
2166f0fa 617
b6bf4ec1 618 if (myOwnGContext
619 && aGContext == NULL)
620 {
2f690078 621 aGContext = glXCreateContext (aDisp, aVis.get(), aSlaveCtx, GL_TRUE);
b6bf4ec1 622 if (aGContext == NULL)
2166f0fa 623 {
9775fa61 624 throw Aspect_GraphicDeviceDefinitionError("OpenGl_Window::CreateWindow: glXCreateContext failed.");
2166f0fa
SK
625 return;
626 }
b6bf4ec1 627 }
2166f0fa 628
b6bf4ec1 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;
2f690078 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);
b6bf4ec1 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;
3b523c4c 653 myGlContext->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
654 GL_DEBUG_TYPE_OTHER,
655 0, GL_DEBUG_SEVERITY_MEDIUM, aMsg);
2166f0fa
SK
656 }
657
4e1523ef 658 myGlContext->Init ((Aspect_Drawable )aWindow, (Aspect_Display )aDisp, (Aspect_RenderingContext )aGContext, isCoreProfile);
b69e576a 659#else
660 // not implemented
661 (void )isCoreProfile;
2166f0fa 662#endif
5e27df78 663 myGlContext->Share (theShareCtx);
f978241f 664 myGlContext->SetSwapInterval (mySwapInterval);
2166f0fa 665 Init();
2166f0fa
SK
666}
667
668// =======================================================================
669// function : ~OpenGl_Window
670// purpose :
671// =======================================================================
672OpenGl_Window::~OpenGl_Window()
673{
25b97fac 674 if (!myOwnGContext
675 || myGlContext.IsNull())
fd4a6963 676 {
677 myGlContext.Nullify();
678 return;
679 }
680
681 // release "GL" context if it is owned by window
544da5a4 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.
1ce0716b 684#if defined(HAVE_EGL)
25b97fac 685 if ((EGLSurface )myGlContext->myWindow != EGL_NO_SURFACE)
686 {
687 eglDestroySurface ((EGLDisplay )myGlContext->myDisplay,
688 (EGLSurface )myGlContext->myWindow);
689 }
690#elif defined(_WIN32)
fd4a6963 691 HWND aWindow = (HWND )myGlContext->myWindow;
b69e576a 692 HDC aWindowDC = (HDC )myGlContext->myDisplay;
fd4a6963 693 HGLRC aWindowGContext = (HGLRC )myGlContext->myGContext;
544da5a4 694 HGLRC aThreadGContext = wglGetCurrentContext();
5e27df78 695 myGlContext.Nullify();
2166f0fa 696
544da5a4 697 if (aThreadGContext != NULL)
2166f0fa 698 {
544da5a4 699 if (aThreadGContext == aWindowGContext)
2166f0fa 700 {
fd4a6963 701 wglMakeCurrent (NULL, NULL);
2166f0fa 702 }
fd4a6963 703
704 wglDeleteContext (aWindowGContext);
2166f0fa 705 }
fd4a6963 706 ReleaseDC (aWindow, aWindowDC);
b69e576a 707#elif defined(HAVE_XLIB)
544da5a4 708 Display* aDisplay = (Display* )myGlContext->myDisplay;
709 GLXContext aWindowGContext = (GLXContext )myGlContext->myGContext;
710 GLXContext aThreadGContext = glXGetCurrentContext();
5e27df78 711 myGlContext.Nullify();
712
fd4a6963 713 if (aDisplay != NULL)
2166f0fa 714 {
544da5a4 715 if (aThreadGContext == aWindowGContext)
716 {
717 glXMakeCurrent (aDisplay, None, NULL);
718 }
719
5e27df78 720 // FSXXX sync necessary if non-direct rendering
721 glXWaitGL();
544da5a4 722 glXDestroyContext (aDisplay, aWindowGContext);
2166f0fa 723 }
b69e576a 724#else
725 // not implemented
2166f0fa
SK
726#endif
727}
728
4fe56619 729#endif // !__APPLE__
730
2166f0fa
SK
731// =======================================================================
732// function : Activate
733// purpose :
734// =======================================================================
735Standard_Boolean OpenGl_Window::Activate()
736{
86fa64d9 737 return myGlContext->MakeCurrent();
2166f0fa
SK
738}
739
b69e576a 740#if !defined(__APPLE__) || defined(HAVE_XLIB)
4fe56619 741
2166f0fa
SK
742// =======================================================================
743// function : Resize
744// purpose : call_subr_resize
745// =======================================================================
c357e426 746void OpenGl_Window::Resize()
2166f0fa 747{
e89202ea 748 Standard_Integer aWidth = 0, aHeight = 0;
c357e426 749 myPlatformWindow->Size (aWidth, aHeight);
e89202ea 750 if (myWidth == aWidth
751 && myHeight == aHeight)
752 {
753 // if the size is not changed - do nothing
2166f0fa 754 return;
e89202ea 755 }
2166f0fa 756
c357e426 757 myWidth = aWidth;
758 myHeight = aHeight;
2166f0fa 759
2166f0fa
SK
760 Init();
761}
762
2166f0fa
SK
763// =======================================================================
764// function : Init
765// purpose :
766// =======================================================================
767void OpenGl_Window::Init()
768{
769 if (!Activate())
770 return;
771
1ce0716b 772#if defined(HAVE_EGL)
39235bed 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())
6cde53c4 797 {
798 eglQuerySurface ((EGLDisplay )myGlContext->myDisplay, (EGLSurface )myGlContext->myWindow, EGL_WIDTH, &myWidth);
799 eglQuerySurface ((EGLDisplay )myGlContext->myDisplay, (EGLSurface )myGlContext->myWindow, EGL_HEIGHT, &myHeight);
800 }
2166f0fa 801#else
e89202ea 802 //
2166f0fa
SK
803#endif
804
5bd9ed93 805 glDisable (GL_DITHER);
ca3c13d1 806 glDisable (GL_SCISSOR_TEST);
3bffef55 807 const Standard_Integer aViewport[4] = { 0, 0, myWidth, myHeight };
808 myGlContext->ResizeViewport (aViewport);
ca3c13d1 809#if !defined(GL_ES_VERSION_2_0)
3bffef55 810 myGlContext->SetDrawBuffer (GL_BACK);
43eddb47 811 if (myGlContext->core11ffp != NULL)
4e1523ef 812 {
813 glMatrixMode (GL_MODELVIEW);
814 }
ca3c13d1 815#endif
2166f0fa
SK
816}
817
2166f0fa 818// =======================================================================
c357e426 819// function : SetSwapInterval
2166f0fa
SK
820// purpose :
821// =======================================================================
b40cdc2b 822void OpenGl_Window::SetSwapInterval (Standard_Boolean theToForceNoSync)
2166f0fa 823{
b40cdc2b 824 const Standard_Integer aSwapInterval = theToForceNoSync ? 0 : myGlContext->caps->swapInterval;
825 if (mySwapInterval != aSwapInterval)
b5ac8292 826 {
b40cdc2b 827 mySwapInterval = aSwapInterval;
c357e426 828 myGlContext->SetSwapInterval (mySwapInterval);
b5ac8292 829 }
2166f0fa 830}
c357e426 831
832#endif // !__APPLE__