1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2013 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup GHOST
22  *
23  * Definition of GHOST_ContextWGL class.
24  */
25 
26 #include "GHOST_ContextWGL.h"
27 
28 #include <tchar.h>
29 
30 #include <cassert>
31 #include <cstdio>
32 #include <vector>
33 
34 HGLRC GHOST_ContextWGL::s_sharedHGLRC = NULL;
35 int GHOST_ContextWGL::s_sharedCount = 0;
36 
37 /* Some third-generation Intel video-cards are constantly bring problems */
is_crappy_intel_card()38 static bool is_crappy_intel_card()
39 {
40   return strstr((const char *)glGetString(GL_VENDOR), "Intel") != NULL;
41 }
42 
GHOST_ContextWGL(bool stereoVisual,bool alphaBackground,HWND hWnd,HDC hDC,int contextProfileMask,int contextMajorVersion,int contextMinorVersion,int contextFlags,int contextResetNotificationStrategy)43 GHOST_ContextWGL::GHOST_ContextWGL(bool stereoVisual,
44                                    bool alphaBackground,
45                                    HWND hWnd,
46                                    HDC hDC,
47                                    int contextProfileMask,
48                                    int contextMajorVersion,
49                                    int contextMinorVersion,
50                                    int contextFlags,
51                                    int contextResetNotificationStrategy)
52     : GHOST_Context(stereoVisual),
53       m_hWnd(hWnd),
54       m_hDC(hDC),
55       m_contextProfileMask(contextProfileMask),
56       m_contextMajorVersion(contextMajorVersion),
57       m_contextMinorVersion(contextMinorVersion),
58       m_contextFlags(contextFlags),
59       m_alphaBackground(alphaBackground),
60       m_contextResetNotificationStrategy(contextResetNotificationStrategy),
61       m_hGLRC(NULL)
62 #ifndef NDEBUG
63       ,
64       m_dummyVendor(NULL),
65       m_dummyRenderer(NULL),
66       m_dummyVersion(NULL)
67 #endif
68 {
69   assert(m_hDC != NULL);
70 }
71 
~GHOST_ContextWGL()72 GHOST_ContextWGL::~GHOST_ContextWGL()
73 {
74   if (m_hGLRC != NULL) {
75     if (m_hGLRC == ::wglGetCurrentContext())
76       WIN32_CHK(::wglMakeCurrent(NULL, NULL));
77 
78     if (m_hGLRC != s_sharedHGLRC || s_sharedCount == 1) {
79       assert(s_sharedCount > 0);
80 
81       s_sharedCount--;
82 
83       if (s_sharedCount == 0)
84         s_sharedHGLRC = NULL;
85 
86       WIN32_CHK(::wglDeleteContext(m_hGLRC));
87     }
88   }
89 
90 #ifndef NDEBUG
91   if (m_dummyRenderer) {
92     free((void *)m_dummyRenderer);
93     free((void *)m_dummyVendor);
94     free((void *)m_dummyVersion);
95   }
96 #endif
97 }
98 
swapBuffers()99 GHOST_TSuccess GHOST_ContextWGL::swapBuffers()
100 {
101   return WIN32_CHK(::SwapBuffers(m_hDC)) ? GHOST_kSuccess : GHOST_kFailure;
102 }
103 
setSwapInterval(int interval)104 GHOST_TSuccess GHOST_ContextWGL::setSwapInterval(int interval)
105 {
106   if (WGLEW_EXT_swap_control)
107     return WIN32_CHK(::wglSwapIntervalEXT(interval)) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
108   else
109     return GHOST_kFailure;
110 }
111 
getSwapInterval(int & intervalOut)112 GHOST_TSuccess GHOST_ContextWGL::getSwapInterval(int &intervalOut)
113 {
114   if (WGLEW_EXT_swap_control) {
115     intervalOut = ::wglGetSwapIntervalEXT();
116     return GHOST_kSuccess;
117   }
118   else {
119     return GHOST_kFailure;
120   }
121 }
122 
activateDrawingContext()123 GHOST_TSuccess GHOST_ContextWGL::activateDrawingContext()
124 {
125   if (WIN32_CHK(::wglMakeCurrent(m_hDC, m_hGLRC))) {
126     return GHOST_kSuccess;
127   }
128   else {
129     return GHOST_kFailure;
130   }
131 }
132 
releaseDrawingContext()133 GHOST_TSuccess GHOST_ContextWGL::releaseDrawingContext()
134 {
135   if (WIN32_CHK(::wglMakeCurrent(NULL, NULL))) {
136     return GHOST_kSuccess;
137   }
138   else {
139     return GHOST_kFailure;
140   }
141 }
142 
143 /* Ron Fosner's code for weighting pixel formats and forcing software.
144  * See http://www.opengl.org/resources/faq/technical/weight.cpp
145  */
weight_pixel_format(PIXELFORMATDESCRIPTOR & pfd,PIXELFORMATDESCRIPTOR & preferredPFD)146 static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd, PIXELFORMATDESCRIPTOR &preferredPFD)
147 {
148   int weight = 0;
149 
150   /* assume desktop color depth is 32 bits per pixel */
151 
152   /* cull unusable pixel formats */
153   /* if no formats can be found, can we determine why it was rejected? */
154   if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL) || !(pfd.dwFlags & PFD_DRAW_TO_WINDOW) ||
155       !(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */
156       !(pfd.iPixelType == PFD_TYPE_RGBA) ||
157       (pfd.cColorBits > 32) ||            /* 64 bit formats disable aero */
158       (pfd.dwFlags & PFD_GENERIC_FORMAT)) /* no software renderers */
159   {
160     return 0;
161   }
162 
163   weight = 1; /* it's usable */
164 
165   weight += pfd.cColorBits - 8;
166 
167   if (preferredPFD.cAlphaBits > 0 && pfd.cAlphaBits > 0)
168     weight++;
169 #ifdef WIN32_COMPOSITING
170   if ((preferredPFD.dwFlags & PFD_SUPPORT_COMPOSITION) && (pfd.dwFlags & PFD_SUPPORT_COMPOSITION))
171     weight++;
172 #endif
173 
174   return weight;
175 }
176 
177 /*
178  * A modification of Ron Fosner's replacement for ChoosePixelFormat
179  * returns 0 on error, else returns the pixel format number to be used
180  */
choose_pixel_format_legacy(HDC hDC,PIXELFORMATDESCRIPTOR & preferredPFD)181 static int choose_pixel_format_legacy(HDC hDC, PIXELFORMATDESCRIPTOR &preferredPFD)
182 {
183   int iPixelFormat = 0;
184   int weight = 0;
185 
186   int iStereoPixelFormat = 0;
187   int stereoWeight = 0;
188 
189   /* choose a pixel format using the useless Windows function in case we come up empty handed */
190   int iLastResortPixelFormat = ::ChoosePixelFormat(hDC, &preferredPFD);
191 
192   WIN32_CHK(iLastResortPixelFormat != 0);
193 
194   int lastPFD = ::DescribePixelFormat(hDC, 1, sizeof(PIXELFORMATDESCRIPTOR), NULL);
195 
196   WIN32_CHK(lastPFD != 0);
197 
198   for (int i = 1; i <= lastPFD; i++) {
199     PIXELFORMATDESCRIPTOR pfd;
200     int check = ::DescribePixelFormat(hDC, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
201 
202     WIN32_CHK(check == lastPFD);
203 
204     int w = weight_pixel_format(pfd, preferredPFD);
205 
206     if (w > weight) {
207       weight = w;
208       iPixelFormat = i;
209     }
210 
211     if (w > stereoWeight && (preferredPFD.dwFlags & pfd.dwFlags & PFD_STEREO)) {
212       stereoWeight = w;
213       iStereoPixelFormat = i;
214     }
215   }
216 
217   /* choose any available stereo format over a non-stereo format */
218   if (iStereoPixelFormat != 0)
219     iPixelFormat = iStereoPixelFormat;
220 
221   if (iPixelFormat == 0) {
222     fprintf(stderr, "Warning! Using result of ChoosePixelFormat.\n");
223     iPixelFormat = iLastResortPixelFormat;
224   }
225 
226   return iPixelFormat;
227 }
228 
229 /**
230  * Clone a window for the purpose of creating a temporary context to initialize WGL extensions.
231  * There is no generic way to clone the lpParam parameter,
232  * so the caller is responsible for cloning it themselves.
233  */
clone_window(HWND hWnd,LPVOID lpParam)234 static HWND clone_window(HWND hWnd, LPVOID lpParam)
235 {
236   int count;
237 
238   SetLastError(NO_ERROR);
239 
240   DWORD dwExStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
241   WIN32_CHK(GetLastError() == NO_ERROR);
242 
243   WCHAR lpClassName[100] = L"";
244   count = GetClassNameW(hWnd, lpClassName, sizeof(lpClassName));
245   WIN32_CHK(count != 0);
246 
247   WCHAR lpWindowName[100] = L"";
248   count = GetWindowTextW(hWnd, lpWindowName, sizeof(lpWindowName));
249   WIN32_CHK(count != 0);
250 
251   DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
252   WIN32_CHK(GetLastError() == NO_ERROR);
253 
254   RECT rect;
255   GetWindowRect(hWnd, &rect);
256   WIN32_CHK(GetLastError() == NO_ERROR);
257 
258   HWND hWndParent = (HWND)GetWindowLongPtr(hWnd, GWLP_HWNDPARENT);
259   WIN32_CHK(GetLastError() == NO_ERROR);
260 
261   HMENU hMenu = GetMenu(hWnd);
262   WIN32_CHK(GetLastError() == NO_ERROR);
263 
264   HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
265   WIN32_CHK(GetLastError() == NO_ERROR);
266 
267   HWND hwndCloned = CreateWindowExW(dwExStyle,
268                                     lpClassName,
269                                     lpWindowName,
270                                     dwStyle,
271                                     rect.left,
272                                     rect.top,
273                                     rect.right - rect.left,
274                                     rect.bottom - rect.top,
275                                     hWndParent,
276                                     hMenu,
277                                     hInstance,
278                                     lpParam);
279 
280   WIN32_CHK(hwndCloned != NULL);
281 
282   return hwndCloned;
283 }
284 
initContextWGLEW(PIXELFORMATDESCRIPTOR & preferredPFD)285 void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD)
286 {
287   HWND dummyHWND = NULL;
288 
289   HDC dummyHDC = NULL;
290   HGLRC dummyHGLRC = NULL;
291 
292   HDC prevHDC;
293   HGLRC prevHGLRC;
294 
295   int iPixelFormat;
296 
297   SetLastError(NO_ERROR);
298 
299   prevHDC = ::wglGetCurrentDC();
300   WIN32_CHK(GetLastError() == NO_ERROR);
301 
302   prevHGLRC = ::wglGetCurrentContext();
303   WIN32_CHK(GetLastError() == NO_ERROR);
304 
305   iPixelFormat = choose_pixel_format_legacy(m_hDC, preferredPFD);
306 
307   if (iPixelFormat == 0)
308     goto finalize;
309 
310   PIXELFORMATDESCRIPTOR chosenPFD;
311   if (!WIN32_CHK(
312           ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD)))
313     goto finalize;
314 
315   if (m_hWnd) {
316     dummyHWND = clone_window(m_hWnd, NULL);
317 
318     if (dummyHWND == NULL)
319       goto finalize;
320 
321     dummyHDC = GetDC(dummyHWND);
322   }
323 
324   if (!WIN32_CHK(dummyHDC != NULL))
325     goto finalize;
326 
327   if (!WIN32_CHK(::SetPixelFormat(dummyHDC, iPixelFormat, &chosenPFD)))
328     goto finalize;
329 
330   dummyHGLRC = ::wglCreateContext(dummyHDC);
331 
332   if (!WIN32_CHK(dummyHGLRC != NULL))
333     goto finalize;
334 
335   if (!WIN32_CHK(::wglMakeCurrent(dummyHDC, dummyHGLRC)))
336     goto finalize;
337 
338   if (GLEW_CHK(glewInit()) != GLEW_OK)
339     fprintf(stderr, "Warning! Dummy GLEW/WGLEW failed to initialize properly.\n");
340 
341     // the following are not technially WGLEW, but they also require a context to work
342 
343 #ifndef NDEBUG
344   free((void *)m_dummyRenderer);
345   free((void *)m_dummyVendor);
346   free((void *)m_dummyVersion);
347 
348   m_dummyRenderer = _strdup(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
349   m_dummyVendor = _strdup(reinterpret_cast<const char *>(glGetString(GL_VENDOR)));
350   m_dummyVersion = _strdup(reinterpret_cast<const char *>(glGetString(GL_VERSION)));
351 #endif
352 
353 finalize:
354   WIN32_CHK(::wglMakeCurrent(prevHDC, prevHGLRC));
355 
356   if (dummyHGLRC != NULL)
357     WIN32_CHK(::wglDeleteContext(dummyHGLRC));
358 
359   if (dummyHWND != NULL) {
360     if (dummyHDC != NULL)
361       WIN32_CHK(::ReleaseDC(dummyHWND, dummyHDC));
362 
363     WIN32_CHK(::DestroyWindow(dummyHWND));
364   }
365 }
366 
makeAttribList(std::vector<int> & out,bool stereoVisual,bool needAlpha)367 static void makeAttribList(std::vector<int> &out, bool stereoVisual, bool needAlpha)
368 {
369   out.clear();
370   out.reserve(30);
371 
372   out.push_back(WGL_SUPPORT_OPENGL_ARB);
373   out.push_back(GL_TRUE);
374 
375   out.push_back(WGL_DRAW_TO_WINDOW_ARB);
376   out.push_back(GL_TRUE);
377 
378   out.push_back(WGL_DOUBLE_BUFFER_ARB);
379   out.push_back(GL_TRUE);
380 
381   out.push_back(WGL_ACCELERATION_ARB);
382   out.push_back(WGL_FULL_ACCELERATION_ARB);
383 
384   if (stereoVisual) {
385     out.push_back(WGL_STEREO_ARB);
386     out.push_back(GL_TRUE);
387   }
388 
389   out.push_back(WGL_PIXEL_TYPE_ARB);
390   out.push_back(WGL_TYPE_RGBA_ARB);
391 
392   out.push_back(WGL_COLOR_BITS_ARB);
393   out.push_back(24);
394 
395   if (needAlpha) {
396     out.push_back(WGL_ALPHA_BITS_ARB);
397     out.push_back(8);
398   }
399 
400   out.push_back(0);
401 }
402 
_choose_pixel_format_arb_1(bool stereoVisual,bool needAlpha)403 int GHOST_ContextWGL::_choose_pixel_format_arb_1(bool stereoVisual, bool needAlpha)
404 {
405   std::vector<int> iAttributes;
406 
407 #define _MAX_PIXEL_FORMATS 32
408 
409   int iPixelFormat = 0;
410   int iPixelFormats[_MAX_PIXEL_FORMATS];
411 
412   makeAttribList(iAttributes, stereoVisual, needAlpha);
413 
414   UINT nNumFormats;
415   WIN32_CHK(wglChoosePixelFormatARB(
416       m_hDC, &(iAttributes[0]), NULL, _MAX_PIXEL_FORMATS, iPixelFormats, &nNumFormats));
417 
418   if (nNumFormats > 0) {
419     iPixelFormat = iPixelFormats[0];
420 
421 #ifdef WIN32_COMPOSITING
422     if (needAlpha) {
423       // scan through all pixel format to make sure one supports compositing
424       PIXELFORMATDESCRIPTOR pfd;
425       int i;
426 
427       for (i = 0; i < nNumFormats; i++) {
428         if (DescribePixelFormat(m_hDC, iPixelFormats[i], sizeof(PIXELFORMATDESCRIPTOR), &pfd)) {
429           if (pfd.dwFlags & PFD_SUPPORT_COMPOSITION) {
430             iPixelFormat = iPixelFormats[i];
431             break;
432           }
433         }
434       }
435       if (i == nNumFormats) {
436         fprintf(stderr, "Warning! Unable to find a pixel format with compositing capability.\n");
437       }
438     }
439 #endif
440   }
441 
442   // check pixel format
443   if (iPixelFormat != 0) {
444     if (needAlpha) {
445       int alphaBits, iQuery = WGL_ALPHA_BITS_ARB;
446       wglGetPixelFormatAttribivARB(m_hDC, iPixelFormat, 0, 1, &iQuery, &alphaBits);
447       if (alphaBits == 0) {
448         fprintf(stderr, "Warning! Unable to find a frame buffer with alpha channel.\n");
449       }
450     }
451   }
452   return iPixelFormat;
453 }
454 
choose_pixel_format_arb(bool stereoVisual,bool needAlpha)455 int GHOST_ContextWGL::choose_pixel_format_arb(bool stereoVisual, bool needAlpha)
456 {
457   int iPixelFormat;
458 
459   iPixelFormat = _choose_pixel_format_arb_1(stereoVisual, needAlpha);
460 
461   if (iPixelFormat == 0 && stereoVisual) {
462     fprintf(stderr, "Warning! Unable to find a stereo pixel format.\n");
463 
464     iPixelFormat = _choose_pixel_format_arb_1(false, needAlpha);
465 
466     m_stereoVisual = false;  // set context property to actual value
467   }
468 
469   return iPixelFormat;
470 }
471 
choose_pixel_format(bool stereoVisual,bool needAlpha)472 int GHOST_ContextWGL::choose_pixel_format(bool stereoVisual, bool needAlpha)
473 {
474   PIXELFORMATDESCRIPTOR preferredPFD = {
475       sizeof(PIXELFORMATDESCRIPTOR), /* size */
476       1,                             /* version */
477       (DWORD)(
478           PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW |
479           PFD_DOUBLEBUFFER |                /* support double-buffering */
480           (stereoVisual ? PFD_STEREO : 0) | /* support stereo */
481           (
482 #ifdef WIN32_COMPOSITING
483               needAlpha ?
484                   PFD_SUPPORT_COMPOSITION : /* support composition for transparent background */
485 #endif
486                   0)),
487       PFD_TYPE_RGBA,               /* color type */
488       (BYTE)(needAlpha ? 32 : 24), /* preferred color depth */
489       0,
490       0,
491       0,
492       0,
493       0,
494       0,                         /* color bits (ignored) */
495       (BYTE)(needAlpha ? 8 : 0), /* alpha buffer */
496       0,                         /* alpha shift (ignored) */
497       0,                         /* no accumulation buffer */
498       0,
499       0,
500       0,
501       0,              /* accum bits (ignored) */
502       0,              /* depth buffer */
503       0,              /* stencil buffer */
504       0,              /* no auxiliary buffers */
505       PFD_MAIN_PLANE, /* main layer */
506       0,              /* reserved */
507       0,
508       0,
509       0 /* layer, visible, and damage masks (ignored) */
510   };
511 
512   initContextWGLEW(preferredPFD);
513 
514   int iPixelFormat = 0;
515 
516   if (WGLEW_ARB_pixel_format)
517     iPixelFormat = choose_pixel_format_arb(stereoVisual, needAlpha);
518 
519   if (iPixelFormat == 0)
520     iPixelFormat = choose_pixel_format_legacy(m_hDC, preferredPFD);
521 
522   return iPixelFormat;
523 }
524 
525 #ifndef NDEBUG
reportContextString(const char * name,const char * dummy,const char * context)526 static void reportContextString(const char *name, const char *dummy, const char *context)
527 {
528   fprintf(stderr, "%s: %s\n", name, context);
529 
530   if (dummy && strcmp(dummy, context) != 0)
531     fprintf(stderr, "Warning! Dummy %s: %s\n", name, dummy);
532 }
533 #endif
534 
initializeDrawingContext()535 GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
536 {
537   SetLastError(NO_ERROR);
538 
539   HGLRC prevHGLRC = ::wglGetCurrentContext();
540   WIN32_CHK(GetLastError() == NO_ERROR);
541 
542   HDC prevHDC = ::wglGetCurrentDC();
543   WIN32_CHK(GetLastError() == NO_ERROR);
544 
545   if (!WGLEW_ARB_create_context || ::GetPixelFormat(m_hDC) == 0) {
546     const bool needAlpha = m_alphaBackground;
547     int iPixelFormat;
548     int lastPFD;
549 
550     PIXELFORMATDESCRIPTOR chosenPFD;
551 
552     iPixelFormat = choose_pixel_format(m_stereoVisual, needAlpha);
553 
554     if (iPixelFormat == 0) {
555       goto error;
556     }
557 
558     lastPFD = ::DescribePixelFormat(
559         m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD);
560 
561     if (!WIN32_CHK(lastPFD != 0)) {
562       goto error;
563     }
564 
565     if (needAlpha && chosenPFD.cAlphaBits == 0)
566       fprintf(stderr, "Warning! Unable to find a pixel format with an alpha channel.\n");
567 
568     if (!WIN32_CHK(::SetPixelFormat(m_hDC, iPixelFormat, &chosenPFD))) {
569       goto error;
570     }
571   }
572 
573   if (WGLEW_ARB_create_context) {
574     int profileBitCore = m_contextProfileMask & WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
575     int profileBitCompat = m_contextProfileMask & WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
576 
577 #ifdef WITH_GLEW_ES
578     int profileBitES = m_contextProfileMask & WGL_CONTEXT_ES_PROFILE_BIT_EXT;
579 #endif
580 
581     if (!WGLEW_ARB_create_context_profile && profileBitCore)
582       fprintf(stderr, "Warning! OpenGL core profile not available.\n");
583 
584     if (!WGLEW_ARB_create_context_profile && profileBitCompat)
585       fprintf(stderr, "Warning! OpenGL compatibility profile not available.\n");
586 
587 #ifdef WITH_GLEW_ES
588     if (!WGLEW_EXT_create_context_es_profile && profileBitES && m_contextMajorVersion == 1)
589       fprintf(stderr, "Warning! OpenGL ES profile not available.\n");
590 
591     if (!WGLEW_EXT_create_context_es2_profile && profileBitES && m_contextMajorVersion == 2)
592       fprintf(stderr, "Warning! OpenGL ES2 profile not available.\n");
593 #endif
594 
595     int profileMask = 0;
596 
597     if (WGLEW_ARB_create_context_profile && profileBitCore)
598       profileMask |= profileBitCore;
599 
600     if (WGLEW_ARB_create_context_profile && profileBitCompat)
601       profileMask |= profileBitCompat;
602 
603 #ifdef WITH_GLEW_ES
604     if (WGLEW_EXT_create_context_es_profile && profileBitES)
605       profileMask |= profileBitES;
606 #endif
607 
608     if (profileMask != m_contextProfileMask)
609       fprintf(stderr, "Warning! Ignoring untested OpenGL context profile mask bits.");
610 
611     std::vector<int> iAttributes;
612 
613     if (profileMask) {
614       iAttributes.push_back(WGL_CONTEXT_PROFILE_MASK_ARB);
615       iAttributes.push_back(profileMask);
616     }
617 
618     if (m_contextMajorVersion != 0) {
619       iAttributes.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB);
620       iAttributes.push_back(m_contextMajorVersion);
621     }
622 
623     if (m_contextMinorVersion != 0) {
624       iAttributes.push_back(WGL_CONTEXT_MINOR_VERSION_ARB);
625       iAttributes.push_back(m_contextMinorVersion);
626     }
627 
628     if (m_contextFlags != 0) {
629       iAttributes.push_back(WGL_CONTEXT_FLAGS_ARB);
630       iAttributes.push_back(m_contextFlags);
631     }
632 
633     if (m_contextResetNotificationStrategy != 0) {
634       if (WGLEW_ARB_create_context_robustness) {
635         iAttributes.push_back(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
636         iAttributes.push_back(m_contextResetNotificationStrategy);
637       }
638       else {
639         fprintf(stderr, "Warning! Cannot set the reset notification strategy.");
640       }
641     }
642 
643     iAttributes.push_back(0);
644 
645     m_hGLRC = ::wglCreateContextAttribsARB(m_hDC, NULL, &(iAttributes[0]));
646   }
647 
648   /* Silence warnings interpreted as errors by users when trying to get
649    * a context with version higher than 3.3 Core. */
650   {
651     const bool silent = m_contextMajorVersion > 3;
652     if (!WIN32_CHK_SILENT(m_hGLRC != NULL, silent)) {
653       goto error;
654     }
655   }
656 
657   s_sharedCount++;
658 
659   if (s_sharedHGLRC == NULL) {
660     s_sharedHGLRC = m_hGLRC;
661   }
662   else if (!WIN32_CHK(::wglShareLists(s_sharedHGLRC, m_hGLRC))) {
663     goto error;
664   }
665 
666   if (!WIN32_CHK(::wglMakeCurrent(m_hDC, m_hGLRC))) {
667     goto error;
668   }
669 
670   initContextGLEW();
671 
672   if (is_crappy_intel_card()) {
673     /* Some Intel cards with context 4.1 or 4.2
674      * don't have the point sprite enabled by default.
675      *
676      * However GL_POINT_SPRITE was removed in 3.2 and is now permanently ON.
677      * Then use brute force. */
678     glEnable(GL_POINT_SPRITE);
679   }
680 
681   initClearGL();
682   ::SwapBuffers(m_hDC);
683 
684 #ifndef NDEBUG
685   {
686     const char *vendor = reinterpret_cast<const char *>(glGetString(GL_VENDOR));
687     const char *renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
688     const char *version = reinterpret_cast<const char *>(glGetString(GL_VERSION));
689 
690     reportContextString("Vendor", m_dummyVendor, vendor);
691     reportContextString("Renderer", m_dummyRenderer, renderer);
692     reportContextString("Version", m_dummyVersion, version);
693 
694     fprintf(stderr, "Context Version: %d.%d\n", m_contextMajorVersion, m_contextMinorVersion);
695   }
696 #endif
697 
698   return GHOST_kSuccess;
699 error:
700   ::wglMakeCurrent(prevHDC, prevHGLRC);
701   return GHOST_kFailure;
702 }
703 
releaseNativeHandles()704 GHOST_TSuccess GHOST_ContextWGL::releaseNativeHandles()
705 {
706   GHOST_TSuccess success = m_hGLRC != s_sharedHGLRC || s_sharedCount == 1 ? GHOST_kSuccess :
707                                                                             GHOST_kFailure;
708 
709   m_hWnd = NULL;
710   m_hDC = NULL;
711 
712   return success;
713 }
714