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