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