cb580f60bd7ca38314c24c6613e1921ef7a08b64
[blender.git] / intern / ghost / intern / GHOST_ContextWGL.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2013 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Jason Wilkins
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file ghost/intern/GHOST_ContextWGL.cpp
29  *  \ingroup GHOST
30  *
31  * Definition of GHOST_ContextWGL class.
32  */
33
34 #include "GHOST_ContextWGL.h"
35
36 #include <tchar.h>
37
38 #include <cstdio>
39 #include <cassert>
40 #include <vector>
41
42
43 #ifdef WITH_GLEW_MX
44 WGLEWContext *wglewContext = NULL;
45 #endif
46
47 HGLRC GHOST_ContextWGL::s_sharedHGLRC = NULL;
48 int   GHOST_ContextWGL::s_sharedCount = 0;
49
50 bool GHOST_ContextWGL::s_singleContextMode = false;
51
52
53 /* Intel video-cards don't work fine with multiple contexts and
54  * have to share the same context for all windows.
55  * But if we just share context for all windows it could work incorrect
56  * with multiple videocards configuration. Suppose, that Intel videocards
57  * can't be in multiple-devices configuration. */
58 static bool is_crappy_intel_card()
59 {
60         return strstr((const char *)glGetString(GL_VENDOR), "Intel") != NULL;
61 }
62
63
64 GHOST_ContextWGL::GHOST_ContextWGL(
65         bool stereoVisual,
66         GHOST_TUns16 numOfAASamples,
67         HWND hWnd,
68         HDC hDC,
69         int contextProfileMask,
70         int contextMajorVersion,
71         int contextMinorVersion,
72         int contextFlags,
73         int contextResetNotificationStrategy)
74     : GHOST_Context(stereoVisual, numOfAASamples),
75       m_hWnd(hWnd),
76       m_hDC(hDC),
77       m_contextProfileMask(contextProfileMask),
78       m_contextMajorVersion(contextMajorVersion),
79       m_contextMinorVersion(contextMinorVersion),
80       m_contextFlags(contextFlags),
81       m_contextResetNotificationStrategy(contextResetNotificationStrategy),
82       m_hGLRC(NULL)
83 #ifdef WITH_GLEW_MX
84       ,
85       m_wglewContext(NULL)
86 #endif
87 #ifndef NDEBUG
88       ,
89       m_dummyVendor(NULL),
90       m_dummyRenderer(NULL),
91       m_dummyVersion(NULL)
92 #endif
93 {
94         assert(m_hWnd);
95         assert(m_hDC);
96 }
97
98
99 GHOST_ContextWGL::~GHOST_ContextWGL()
100 {
101         if (m_hGLRC != NULL) {
102                 if (m_hGLRC == ::wglGetCurrentContext())
103                         WIN32_CHK(::wglMakeCurrent(NULL, NULL));
104
105                 if (m_hGLRC != s_sharedHGLRC || s_sharedCount == 1) {
106                         assert(s_sharedCount > 0);
107
108                         s_sharedCount--;
109
110                         if (s_sharedCount == 0)
111                                 s_sharedHGLRC = NULL;
112
113                         WIN32_CHK(::wglDeleteContext(m_hGLRC));
114                 }
115         }
116
117 #ifdef WITH_GLEW_MX
118         delete m_wglewContext;
119 #endif
120
121 #ifndef NDEBUG
122         free((void*)m_dummyRenderer);
123         free((void*)m_dummyVendor);
124         free((void*)m_dummyVersion);
125 #endif
126 }
127
128
129 GHOST_TSuccess GHOST_ContextWGL::swapBuffers()
130 {
131         return WIN32_CHK(::SwapBuffers(m_hDC)) ? GHOST_kSuccess : GHOST_kFailure;
132 }
133
134
135 GHOST_TSuccess GHOST_ContextWGL::setSwapInterval(int interval)
136 {
137         if (WGLEW_EXT_swap_control)
138                 return WIN32_CHK(::wglSwapIntervalEXT(interval)) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
139         else
140                 return GHOST_kFailure;
141 }
142
143
144 GHOST_TSuccess GHOST_ContextWGL::getSwapInterval(int &intervalOut)
145 {
146         if (WGLEW_EXT_swap_control) {
147                 intervalOut = ::wglGetSwapIntervalEXT();
148                 return GHOST_kSuccess;
149         }
150         else {
151                 return GHOST_kFailure;
152         }
153 }
154
155
156 GHOST_TSuccess GHOST_ContextWGL::activateDrawingContext()
157 {
158         if (WIN32_CHK(::wglMakeCurrent(m_hDC, m_hGLRC))) {
159                 activateGLEW();
160                 return GHOST_kSuccess;
161         }
162         else {
163                 return GHOST_kFailure;
164         }
165 }
166
167
168 /* Ron Fosner's code for weighting pixel formats and forcing software.
169  * See http://www.opengl.org/resources/faq/technical/weight.cpp
170  */
171 static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd)
172 {
173         int weight = 0;
174
175         /* assume desktop color depth is 32 bits per pixel */
176
177         /* cull unusable pixel formats */
178         /* if no formats can be found, can we determine why it was rejected? */
179         if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL)  ||
180             !(pfd.dwFlags & PFD_DRAW_TO_WINDOW)  ||
181             !(pfd.dwFlags & PFD_DOUBLEBUFFER)    || /* Blender _needs_ this */
182             !(pfd.iPixelType == PFD_TYPE_RGBA)   ||
183              (pfd.cDepthBits < 16)               ||
184              (pfd.dwFlags & PFD_GENERIC_FORMAT))    /* no software renderers */
185         {
186                 return 0;
187         }
188
189         weight = 1;  /* it's usable */
190
191         /* the bigger the depth buffer the better */
192         /* give no weight to a 16-bit depth buffer, because those are crap */
193         weight += pfd.cDepthBits - 16;
194
195         weight += pfd.cColorBits -  8;
196
197 #ifdef GHOST_OPENGL_ALPHA
198         if (pfd.cAlphaBits > 0)
199                 weight++;
200 #endif
201
202 #ifdef GHOST_OPENGL_STENCIL
203         if (pfd.cStencilBits >= 8)
204                 weight++;
205 #endif
206
207         /* want swap copy capability -- it matters a lot */
208         if (pfd.dwFlags & PFD_SWAP_COPY)
209                 weight += 16;
210
211         return weight;
212 }
213
214
215 /*
216  * A modification of Ron Fosner's replacement for ChoosePixelFormat
217  * returns 0 on error, else returns the pixel format number to be used
218  */
219 static int choose_pixel_format_legacy(HDC hDC, PIXELFORMATDESCRIPTOR &preferredPFD)
220 {
221         int iPixelFormat = 0;
222         int weight = 0;
223
224         int iStereoPixelFormat = 0;
225         int stereoWeight = 0;
226
227         /* choose a pixel format using the useless Windows function in case we come up empty handed */
228         int iLastResortPixelFormat = ::ChoosePixelFormat(hDC, &preferredPFD);
229
230         WIN32_CHK(iLastResortPixelFormat != 0);
231
232         int lastPFD = ::DescribePixelFormat(hDC, 1, sizeof(PIXELFORMATDESCRIPTOR), NULL);
233
234         WIN32_CHK(lastPFD != 0);
235
236         for (int i = 1; i <= lastPFD; i++) {
237                 PIXELFORMATDESCRIPTOR pfd;
238                 int check = ::DescribePixelFormat(hDC, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
239
240                 WIN32_CHK(check == lastPFD);
241
242                 int w = weight_pixel_format(pfd);
243
244                 if (w > weight) {
245                         weight = w;
246                         iPixelFormat = i;
247                 }
248
249                 if (w > stereoWeight && (preferredPFD.dwFlags & pfd.dwFlags & PFD_STEREO)) {
250                         stereoWeight = w;
251                         iStereoPixelFormat = i;
252                 }
253         }
254
255         /* choose any available stereo format over a non-stereo format */
256         if (iStereoPixelFormat != 0)
257                 iPixelFormat = iStereoPixelFormat;
258
259         if (iPixelFormat == 0) {
260                 fprintf(stderr, "Warning! Using result of ChoosePixelFormat.\n");
261                 iPixelFormat = iLastResortPixelFormat;
262         }
263
264         return iPixelFormat;
265 }
266
267
268 /*
269  * Clone a window for the purpose of creating a temporary context to initialize WGL extensions.
270  * There is no generic way to clone the lpParam parameter, so the caller is responsible for cloning it themselves.
271  */
272
273 static HWND clone_window(HWND hWnd, LPVOID lpParam)
274 {
275         int count;
276
277         SetLastError(NO_ERROR);
278
279         DWORD dwExStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
280         WIN32_CHK(GetLastError() == NO_ERROR);
281
282         WCHAR lpClassName[100] = L"";
283         count = GetClassNameW(hWnd, lpClassName, sizeof(lpClassName));
284         WIN32_CHK(count != 0);
285
286         WCHAR lpWindowName[100] = L"";
287         count = GetWindowTextW(hWnd, lpWindowName, sizeof(lpWindowName));
288         WIN32_CHK(count != 0);
289
290         DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
291         WIN32_CHK(GetLastError() == NO_ERROR);
292
293         RECT rect;
294         GetWindowRect(hWnd, &rect);
295         WIN32_CHK(GetLastError() == NO_ERROR);
296
297         HWND hWndParent = (HWND)GetWindowLongPtr(hWnd, GWLP_HWNDPARENT);
298         WIN32_CHK(GetLastError() == NO_ERROR);
299
300         HMENU hMenu = GetMenu(hWnd);
301         WIN32_CHK(GetLastError() == NO_ERROR);
302
303         HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtr(hWnd, GWLP_HINSTANCE);
304         WIN32_CHK(GetLastError() == NO_ERROR);
305
306         HWND hwndCloned = CreateWindowExW(
307                 dwExStyle,
308                 lpClassName,
309                 lpWindowName,
310                 dwStyle,
311                 rect.left,
312                 rect.top,
313                 rect.right - rect.left,
314                 rect.bottom - rect.top,
315                 hWndParent,
316                 hMenu,
317                 hInstance,
318                 lpParam);
319
320         WIN32_CHK(hwndCloned != NULL);
321
322         return hwndCloned;
323 }
324
325
326 void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD)
327 {
328         HWND  dummyHWND  = NULL;
329         HDC   dummyHDC   = NULL;
330         HGLRC dummyHGLRC = NULL;
331
332         HDC   prevHDC;
333         HGLRC prevHGLRC;
334
335         int iPixelFormat;
336
337
338 #ifdef WITH_GLEW_MX
339         wglewContext = new WGLEWContext;
340         memset(wglewContext, 0, sizeof(WGLEWContext));
341
342         delete m_wglewContext;
343         m_wglewContext = wglewContext;
344 #endif
345
346         SetLastError(NO_ERROR);
347
348         prevHDC = ::wglGetCurrentDC();
349         WIN32_CHK(GetLastError() == NO_ERROR);
350
351         prevHGLRC = ::wglGetCurrentContext();
352         WIN32_CHK(GetLastError() == NO_ERROR);
353
354         dummyHWND = clone_window(m_hWnd, NULL);
355
356         if (dummyHWND == NULL)
357                 goto finalize;
358
359         dummyHDC = GetDC(dummyHWND);
360
361         if (!WIN32_CHK(dummyHDC != NULL))
362                 goto finalize;
363
364         iPixelFormat = choose_pixel_format_legacy(dummyHDC, preferredPFD);
365
366         if (iPixelFormat == 0)
367                 goto finalize;
368
369         PIXELFORMATDESCRIPTOR chosenPFD;
370         if (!WIN32_CHK(::DescribePixelFormat(dummyHDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD)))
371                 goto finalize;
372
373         if (!WIN32_CHK(::SetPixelFormat(dummyHDC, iPixelFormat, &chosenPFD)))
374                 goto finalize;
375
376         dummyHGLRC = ::wglCreateContext(dummyHDC);
377
378         if (!WIN32_CHK(dummyHGLRC != NULL))
379                 goto finalize;
380
381         if (!WIN32_CHK(::wglMakeCurrent(dummyHDC, dummyHGLRC)))
382                 goto finalize;
383
384 #ifdef WITH_GLEW_MX
385         if (GLEW_CHK(wglewInit()) != GLEW_OK)
386                 fprintf(stderr, "Warning! WGLEW failed to initialize properly.\n");
387 #else
388         if (GLEW_CHK(glewInit()) != GLEW_OK)
389                 fprintf(stderr, "Warning! Dummy GLEW/WGLEW failed to initialize properly.\n");
390 #endif
391
392         // the following are not technially WGLEW, but they also require a context to work
393
394 #ifndef NDEBUG
395         free((void*)m_dummyRenderer);
396         free((void*)m_dummyVendor);
397         free((void*)m_dummyVersion);
398
399         m_dummyRenderer = _strdup(reinterpret_cast<const char *>(glGetString(GL_RENDERER)));
400         m_dummyVendor   = _strdup(reinterpret_cast<const char *>(glGetString(GL_VENDOR)));
401         m_dummyVersion  = _strdup(reinterpret_cast<const char *>(glGetString(GL_VERSION)));
402 #endif
403
404         s_singleContextMode = is_crappy_intel_card();
405
406 finalize:
407         WIN32_CHK(::wglMakeCurrent(prevHDC, prevHGLRC));
408
409         if (dummyHGLRC != NULL)
410                 WIN32_CHK(::wglDeleteContext(dummyHGLRC));
411
412         if (dummyHWND != NULL) {
413                 if (dummyHDC != NULL)
414                         WIN32_CHK(::ReleaseDC(dummyHWND, dummyHDC));
415
416                 WIN32_CHK(::DestroyWindow(dummyHWND));
417         }
418 }
419
420
421 static void makeAttribList(
422         std::vector<int>& out,
423         bool stereoVisual,
424         int numOfAASamples,
425         int swapMethod,
426         bool needAlpha,
427         bool needStencil,
428         bool sRGB)
429 {
430         out.clear();
431         out.reserve(30);
432
433         out.push_back(WGL_SUPPORT_OPENGL_ARB);
434         out.push_back(GL_TRUE);
435
436         out.push_back(WGL_DRAW_TO_WINDOW_ARB);
437         out.push_back(GL_TRUE);
438
439         out.push_back(WGL_DOUBLE_BUFFER_ARB);
440         out.push_back(GL_TRUE);
441
442         out.push_back(WGL_ACCELERATION_ARB);
443         out.push_back(WGL_FULL_ACCELERATION_ARB);
444
445         out.push_back(WGL_SWAP_METHOD_ARB);
446         out.push_back(swapMethod);
447
448         if (stereoVisual) {
449                 out.push_back(WGL_STEREO_ARB);
450                 out.push_back(GL_TRUE);
451         }
452
453         out.push_back(WGL_PIXEL_TYPE_ARB);
454         out.push_back(WGL_TYPE_RGBA_ARB);
455
456         out.push_back(WGL_COLOR_BITS_ARB);
457         out.push_back(24);
458
459         out.push_back(WGL_DEPTH_BITS_ARB);
460         out.push_back(24);
461
462         if (needAlpha) {
463                 out.push_back(WGL_ALPHA_BITS_ARB);
464                 out.push_back(8);
465         }
466
467         if (needStencil) {
468                 out.push_back(WGL_STENCIL_BITS_ARB);
469                 out.push_back(8);
470         }
471
472         if (numOfAASamples > 0) {
473                 out.push_back(WGL_SAMPLES_ARB);
474                 out.push_back(numOfAASamples);
475
476                 out.push_back(WGL_SAMPLE_BUFFERS_ARB);
477                 out.push_back(GL_TRUE);
478         }
479
480         if (sRGB) {
481                 out.push_back(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB);
482                 out.push_back(GL_TRUE);
483         }
484
485         out.push_back(0);
486 }
487
488
489 int GHOST_ContextWGL::_choose_pixel_format_arb_2(
490         bool stereoVisual,
491         int *numOfAASamples,
492         bool needAlpha,
493         bool needStencil,
494         bool sRGB,
495         int swapMethod)
496 {
497         std::vector<int> iAttributes;
498
499         int iPixelFormat = 0;
500
501         int samples;
502
503         // guard against some insanely high number of samples
504         if (*numOfAASamples > 64) {
505                 fprintf(stderr, "Warning! Clamping number of samples to 64.\n");
506                 samples = 64;
507         }
508         else {
509                 samples = *numOfAASamples;
510         }
511
512         // request a format with as many samples as possible, but not more than requested
513         while (samples >= 0) {
514                 makeAttribList(
515                         iAttributes,
516                         stereoVisual,
517                         samples,
518                         swapMethod,
519                         needAlpha,
520                         needStencil,
521                         sRGB);
522
523                 UINT nNumFormats;
524                 WIN32_CHK(wglChoosePixelFormatARB(m_hDC, &(iAttributes[0]), NULL, 1, &iPixelFormat, &nNumFormats));
525
526                 /* total number of formats that match (regardless of size of iPixelFormat array)
527                  * see: WGL_ARB_pixel_format extension spec */
528                 if (nNumFormats > 0)
529                         break;
530
531                 /* if not reset, then the state of iPixelFormat is undefined after call to wglChoosePixelFormatARB
532                  * see: WGL_ARB_pixel_format extension spec */
533                 iPixelFormat = 0;
534
535                 samples--;
536         }
537
538         // check how many samples were actually gotten
539         if (iPixelFormat != 0) {
540                 int iQuery[] = { WGL_SAMPLES_ARB };
541                 int actualSamples;
542                 wglGetPixelFormatAttribivARB(m_hDC, iPixelFormat, 0, 1, iQuery, &actualSamples);
543
544                 if (actualSamples != *numOfAASamples) {
545                         fprintf(stderr,
546                                 "Warning! Unable to find a multisample pixel format that supports exactly %d samples. "
547                                 "Substituting one that uses %d samples.\n",
548                                 *numOfAASamples, actualSamples);
549
550                         *numOfAASamples = actualSamples; // set context property to actual value
551                 }
552         }
553         else {
554                 *numOfAASamples = 0;
555         }
556         return iPixelFormat;
557 }
558
559
560 int GHOST_ContextWGL::_choose_pixel_format_arb_1(bool stereoVisual,
561         int numOfAASamples,
562         bool needAlpha,
563         bool needStencil,
564         bool sRGB,
565         int *swapMethodOut)
566 {
567         int iPixelFormat;
568         int copyPixelFormat = 0;
569         int undefPixelFormat = 0;
570         int exchPixelFormat = 0;
571         int copyNumOfAASamples = 0;
572         int undefNumOfAASamples = 0;
573         int exchNumOfAASamples = 0;
574
575         *swapMethodOut = WGL_SWAP_COPY_ARB;
576         copyNumOfAASamples = numOfAASamples;
577         copyPixelFormat  = _choose_pixel_format_arb_2(
578                 stereoVisual, &copyNumOfAASamples, needAlpha, needStencil, sRGB, *swapMethodOut);
579
580         if (copyPixelFormat == 0 || copyNumOfAASamples < numOfAASamples) {
581                 *swapMethodOut = WGL_SWAP_UNDEFINED_ARB;
582                 undefNumOfAASamples = numOfAASamples;
583                 undefPixelFormat = _choose_pixel_format_arb_2(
584                         stereoVisual, &undefNumOfAASamples, needAlpha, needStencil, sRGB, *swapMethodOut);
585
586                 if (undefPixelFormat == 0 || undefNumOfAASamples < numOfAASamples) {
587                         *swapMethodOut = WGL_SWAP_EXCHANGE_ARB;
588                         exchNumOfAASamples = numOfAASamples;
589                         exchPixelFormat = _choose_pixel_format_arb_2(
590                                 stereoVisual, &exchNumOfAASamples, needAlpha, needStencil, sRGB, *swapMethodOut);
591                         if (exchPixelFormat == 0 || exchNumOfAASamples < numOfAASamples) {
592                                 // the number of AA samples cannot be met, take the highest
593                                 if (undefPixelFormat != 0 && undefNumOfAASamples >= exchNumOfAASamples) {
594                                         exchNumOfAASamples = undefNumOfAASamples;
595                                         exchPixelFormat = undefPixelFormat;
596                                         *swapMethodOut = WGL_SWAP_UNDEFINED_ARB;
597                                 }
598                                 if (copyPixelFormat != 0 && copyNumOfAASamples >= exchNumOfAASamples) {
599                                         exchNumOfAASamples = copyNumOfAASamples;
600                                         exchPixelFormat = copyPixelFormat;
601                                         *swapMethodOut = WGL_SWAP_COPY_ARB;
602                                 }
603                         }
604                         iPixelFormat = exchPixelFormat;
605                         m_numOfAASamples = exchNumOfAASamples;
606                 }
607                 else {
608                         iPixelFormat = undefPixelFormat;
609                         m_numOfAASamples = undefNumOfAASamples;
610                 }
611         }
612         else {
613                 iPixelFormat = copyPixelFormat;
614                 m_numOfAASamples = copyNumOfAASamples;
615         }
616         return iPixelFormat;
617 }
618
619
620 int GHOST_ContextWGL::choose_pixel_format_arb(
621         bool stereoVisual,
622         int numOfAASamples,
623         bool needAlpha,
624         bool needStencil,
625         bool sRGB)
626 {
627         int iPixelFormat;
628         int swapMethodOut;
629
630         iPixelFormat = _choose_pixel_format_arb_1(
631                 stereoVisual,
632                 numOfAASamples,
633                 needAlpha,
634                 needStencil,
635                 sRGB,
636                 &swapMethodOut);
637
638         if (iPixelFormat == 0 && stereoVisual) {
639                 fprintf(stderr, "Warning! Unable to find a stereo pixel format.\n");
640
641                 iPixelFormat = _choose_pixel_format_arb_1(
642                         false,
643                         numOfAASamples,
644                         needAlpha,
645                         needStencil,
646                         sRGB,
647                         &swapMethodOut);
648
649                 m_stereoVisual = false;  // set context property to actual value
650         }
651
652         if (swapMethodOut != WGL_SWAP_COPY_ARB) {
653                 fprintf(stderr,
654                         "Warning! Unable to find a pixel format that supports WGL_SWAP_COPY_ARB. "
655                         "Substituting one that uses %s.\n",
656                         swapMethodOut == WGL_SWAP_UNDEFINED_ARB ? "WGL_SWAP_UNDEFINED_ARB" : "WGL_SWAP_EXCHANGE_ARB");
657         }
658
659         return iPixelFormat;
660 }
661
662
663 int GHOST_ContextWGL::choose_pixel_format(
664         bool stereoVisual,
665         int  numOfAASamples,
666         bool needAlpha,
667         bool needStencil,
668         bool sRGB)
669 {
670         PIXELFORMATDESCRIPTOR preferredPFD = {
671                 sizeof(PIXELFORMATDESCRIPTOR),   /* size */
672                 1,                               /* version */
673                 PFD_SUPPORT_OPENGL |
674                 PFD_DRAW_TO_WINDOW |
675                 PFD_SWAP_COPY      |             /* support swap copy */
676                 PFD_DOUBLEBUFFER   |             /* support double-buffering */
677                 (stereoVisual ? PFD_STEREO : 0), /* support stereo */
678                 PFD_TYPE_RGBA,                   /* color type */
679                 24,                              /* preferred color depth */
680                 0, 0, 0, 0, 0, 0,                /* color bits (ignored) */
681                 needAlpha ? 8 : 0,               /* alpha buffer */
682                 0,                               /* alpha shift (ignored) */
683                 0,                               /* no accumulation buffer */
684                 0, 0, 0, 0,                      /* accum bits (ignored) */
685                 24,                              /* depth buffer */
686                 needStencil ? 8 : 0,             /* stencil buffer */
687                 0,                               /* no auxiliary buffers */
688                 PFD_MAIN_PLANE,                  /* main layer */
689                 0,                               /* reserved */
690                 0, 0, 0                          /* layer, visible, and damage masks (ignored) */
691         };
692
693         initContextWGLEW(preferredPFD);
694
695         if (numOfAASamples > 0 && !WGLEW_ARB_multisample) {
696                 fprintf(stderr, "Warning! Unable to request a multisample framebuffer.\n");
697                 numOfAASamples = 0;
698         }
699
700         if (sRGB && !(WGLEW_ARB_framebuffer_sRGB || WGLEW_EXT_framebuffer_sRGB)) {
701                 fprintf(stderr, "Warning! Unable to request an sRGB framebuffer.\n");
702                 sRGB = false;
703         }
704
705         int iPixelFormat = 0;
706
707         if (WGLEW_ARB_pixel_format)
708                 iPixelFormat = choose_pixel_format_arb(stereoVisual, numOfAASamples, needAlpha, needStencil, sRGB);
709
710         if (iPixelFormat == 0)
711                 iPixelFormat = choose_pixel_format_legacy(m_hDC, preferredPFD);
712
713         return iPixelFormat;
714 }
715
716
717 #ifndef NDEBUG
718 static void reportContextString(const char *name, const char *dummy, const char *context)
719 {
720         fprintf(stderr, "%s: %s\n", name, context);
721
722         if (strcmp(dummy, context) != 0)
723                 fprintf(stderr, "Warning! Dummy %s: %s\n", name, dummy);
724 }
725 #endif
726
727
728 GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext()
729 {
730 #ifdef GHOST_OPENGL_ALPHA
731         const bool needAlpha = true;
732 #else
733         const bool needAlpha = false;
734 #endif
735
736 #ifdef GHOST_OPENGL_STENCIL
737         const bool needStencil = true;
738 #else
739         const bool needStencil = false;
740 #endif
741
742 #ifdef GHOST_OPENGL_SRGB
743         const bool sRGB = true;
744 #else
745         const bool sRGB = false;
746 #endif
747
748         HGLRC prevHGLRC;
749         HDC   prevHDC;
750
751         int iPixelFormat;
752         int lastPFD;
753
754         PIXELFORMATDESCRIPTOR chosenPFD;
755
756
757         SetLastError(NO_ERROR);
758
759         prevHGLRC = ::wglGetCurrentContext();
760         WIN32_CHK(GetLastError() == NO_ERROR);
761
762         prevHDC   = ::wglGetCurrentDC();
763         WIN32_CHK(GetLastError() == NO_ERROR);
764
765         iPixelFormat = choose_pixel_format(m_stereoVisual, m_numOfAASamples, needAlpha, needStencil, sRGB);
766
767         if (iPixelFormat == 0) {
768                 ::wglMakeCurrent(prevHDC, prevHGLRC);
769                 return GHOST_kFailure;
770         }
771
772         lastPFD = ::DescribePixelFormat(m_hDC, iPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &chosenPFD);
773
774         if (!WIN32_CHK(lastPFD != 0)) {
775                 ::wglMakeCurrent(prevHDC, prevHGLRC);
776                 return GHOST_kFailure;
777         }
778
779         if (needAlpha && chosenPFD.cAlphaBits == 0)
780                 fprintf(stderr, "Warning! Unable to find a pixel format with an alpha channel.\n");
781
782         if (needStencil && chosenPFD.cStencilBits == 0)
783                 fprintf(stderr, "Warning! Unable to find a pixel format with a stencil buffer.\n");
784
785         if (!WIN32_CHK(::SetPixelFormat(m_hDC, iPixelFormat, &chosenPFD))) {
786                 ::wglMakeCurrent(prevHDC, prevHGLRC);
787                 return GHOST_kFailure;
788         }
789
790         activateWGLEW();
791
792         if (WGLEW_ARB_create_context) {
793                 int profileBitCore   = m_contextProfileMask & WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
794                 int profileBitCompat = m_contextProfileMask & WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
795
796 #ifdef WITH_GLEW_ES
797                 int profileBitES     = m_contextProfileMask & WGL_CONTEXT_ES_PROFILE_BIT_EXT;
798 #endif
799
800                 if (!WGLEW_ARB_create_context_profile && profileBitCore)
801                         fprintf(stderr, "Warning! OpenGL core profile not available.\n");
802
803                 if (!WGLEW_ARB_create_context_profile && profileBitCompat)
804                         fprintf(stderr, "Warning! OpenGL compatibility profile not available.\n");
805
806 #ifdef WITH_GLEW_ES
807                 if (!WGLEW_EXT_create_context_es_profile && profileBitES && m_contextMajorVersion == 1)
808                         fprintf(stderr, "Warning! OpenGL ES profile not available.\n");
809
810                 if (!WGLEW_EXT_create_context_es2_profile && profileBitES && m_contextMajorVersion == 2)
811                         fprintf(stderr, "Warning! OpenGL ES2 profile not available.\n");
812 #endif
813
814                 int profileMask = 0;
815
816                 if (WGLEW_ARB_create_context_profile && profileBitCore)
817                         profileMask |= profileBitCore;
818
819                 if (WGLEW_ARB_create_context_profile && profileBitCompat)
820                         profileMask |= profileBitCompat;
821
822 #ifdef WITH_GLEW_ES
823                 if (WGLEW_EXT_create_context_es_profile && profileBitES)
824                         profileMask |= profileBitES;
825 #endif
826
827                 if (profileMask != m_contextProfileMask)
828                         fprintf(stderr, "Warning! Ignoring untested OpenGL context profile mask bits.");
829
830                 std::vector<int> iAttributes;
831
832                 if (profileMask) {
833                         iAttributes.push_back(WGL_CONTEXT_PROFILE_MASK_ARB);
834                         iAttributes.push_back(profileMask);
835                 }
836
837                 if (m_contextMajorVersion != 0) {
838                         iAttributes.push_back(WGL_CONTEXT_MAJOR_VERSION_ARB);
839                         iAttributes.push_back(m_contextMajorVersion);
840                 }
841
842                 if (m_contextMinorVersion != 0) {
843                         iAttributes.push_back(WGL_CONTEXT_MINOR_VERSION_ARB);
844                         iAttributes.push_back(m_contextMinorVersion);
845                 }
846
847                 if (m_contextFlags != 0) {
848                         iAttributes.push_back(WGL_CONTEXT_FLAGS_ARB);
849                         iAttributes.push_back(m_contextFlags);
850                 }
851
852                 if (m_contextResetNotificationStrategy != 0) {
853                         if (WGLEW_ARB_create_context_robustness) {
854                                 iAttributes.push_back(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
855                                 iAttributes.push_back(m_contextResetNotificationStrategy);
856                         }
857                         else {
858                                 fprintf(stderr, "Warning! Cannot set the reset notification strategy.");
859                         }
860                 }
861
862                 iAttributes.push_back(0);
863
864                 if (!s_singleContextMode || s_sharedHGLRC == NULL)
865                         m_hGLRC = ::wglCreateContextAttribsARB(m_hDC, NULL, &(iAttributes[0]));
866                 else
867                         m_hGLRC = s_sharedHGLRC;
868         }
869         else {
870                 if (m_contextProfileMask  != 0)
871                         fprintf(stderr, "Warning! Legacy WGL is unable to select between OpenGL profiles.");
872
873                 if (m_contextMajorVersion != 0 || m_contextMinorVersion != 0)
874                         fprintf(stderr, "Warning! Legacy WGL is unable to select between OpenGL versions.");
875
876                 if (m_contextFlags != 0)
877                         fprintf(stderr, "Warning! Legacy WGL is unable to set context flags.");
878
879                 if (!s_singleContextMode || s_sharedHGLRC == NULL)
880                         m_hGLRC = ::wglCreateContext(m_hDC);
881                 else
882                         m_hGLRC = s_sharedHGLRC;
883         }
884
885         if (!WIN32_CHK(m_hGLRC != NULL)) {
886                 ::wglMakeCurrent(prevHDC, prevHGLRC);
887                 return GHOST_kFailure;
888         }
889
890         if (s_sharedHGLRC == NULL)
891                 s_sharedHGLRC = m_hGLRC;
892
893         s_sharedCount++;
894
895         if (!s_singleContextMode && s_sharedHGLRC != m_hGLRC && !WIN32_CHK(::wglShareLists(s_sharedHGLRC, m_hGLRC))) {
896                 ::wglMakeCurrent(prevHDC, prevHGLRC);
897                 return GHOST_kFailure;
898         }
899
900         if (!WIN32_CHK(::wglMakeCurrent(m_hDC, m_hGLRC))) {
901                 ::wglMakeCurrent(prevHDC, prevHGLRC);
902                 return GHOST_kFailure;
903         }
904
905         initContextGLEW();
906
907         initClearGL();
908         ::SwapBuffers(m_hDC);
909
910         const char *vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
911         const char *renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
912         const char *version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
913
914 #ifndef NDEBUG
915         reportContextString("Vendor",   m_dummyVendor,   vendor);
916         reportContextString("Renderer", m_dummyRenderer, renderer);
917         reportContextString("Version",  m_dummyVersion,  version);
918 #endif
919
920         if ((strcmp(vendor, "Microsoft Corporation") == 0 ||
921              strcmp(renderer, "GDI Generic") == 0) && version[0] == '1' && version[2] == '1')
922         {
923                 MessageBox(m_hWnd, "Your system does not use 3D hardware acceleration.\n"
924                                    "Blender requires a graphics driver with OpenGL 2.1 support.\n\n"
925                                    "This may be caused by:\n"
926                                    "* A missing or faulty graphics driver installation.\n"
927                                    "  Blender needs a graphics card driver to work correctly.\n"
928                                    "* Accessing Blender through a remote connection.\n"
929                                    "* Using Blender through a virtual machine.\n\n"
930                                    "The program will now close.",
931                            "Blender - Can't detect 3D hardware accelerated Driver!",
932                            MB_OK | MB_ICONERROR);
933                 exit(0);
934         }
935         else if (version[0] < '2' || (version[0] == '2' && version[2] < '1')) {
936                 MessageBox(m_hWnd, "Blender requires a graphics driver with OpenGL 2.1 support.\n\n"
937                                    "The program will now close.",
938                            "Blender - Unsupported Graphics Driver!",
939                            MB_OK | MB_ICONERROR);
940                 exit(0);
941         }
942
943         return GHOST_kSuccess;
944 }
945
946
947 GHOST_TSuccess GHOST_ContextWGL::releaseNativeHandles()
948 {
949         GHOST_TSuccess success = m_hGLRC != s_sharedHGLRC || s_sharedCount == 1 ? GHOST_kSuccess : GHOST_kFailure;
950
951         m_hWnd = NULL;
952         m_hDC  = NULL;
953
954         return success;
955 }