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