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