1 
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 #include "SkWGL.h"
10 
11 #include "SkTDArray.h"
12 #include "SkTSearch.h"
13 #include "SkTSort.h"
14 
hasExtension(HDC dc,const char * ext) const15 bool SkWGLExtensions::hasExtension(HDC dc, const char* ext) const {
16     if (NULL == this->fGetExtensionsString) {
17         return false;
18     }
19     if (!strcmp("WGL_ARB_extensions_string", ext)) {
20         return true;
21     }
22     const char* extensionString = this->getExtensionsString(dc);
23     size_t extLength = strlen(ext);
24 
25     while (true) {
26         size_t n = strcspn(extensionString, " ");
27         if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
28             return true;
29         }
30         if (0 == extensionString[n]) {
31             return false;
32         }
33         extensionString += n+1;
34     }
35 
36     return false;
37 }
38 
getExtensionsString(HDC hdc) const39 const char* SkWGLExtensions::getExtensionsString(HDC hdc) const {
40     return fGetExtensionsString(hdc);
41 }
42 
choosePixelFormat(HDC hdc,const int * piAttribIList,const FLOAT * pfAttribFList,UINT nMaxFormats,int * piFormats,UINT * nNumFormats) const43 BOOL SkWGLExtensions::choosePixelFormat(HDC hdc,
44                                         const int* piAttribIList,
45                                         const FLOAT* pfAttribFList,
46                                         UINT nMaxFormats,
47                                         int* piFormats,
48                                         UINT* nNumFormats) const {
49     return fChoosePixelFormat(hdc, piAttribIList, pfAttribFList,
50                               nMaxFormats, piFormats, nNumFormats);
51 }
52 
getPixelFormatAttribiv(HDC hdc,int iPixelFormat,int iLayerPlane,UINT nAttributes,const int * piAttributes,int * piValues) const53 BOOL SkWGLExtensions::getPixelFormatAttribiv(HDC hdc,
54                                              int iPixelFormat,
55                                              int iLayerPlane,
56                                              UINT nAttributes,
57                                              const int *piAttributes,
58                                              int *piValues) const {
59     return fGetPixelFormatAttribiv(hdc, iPixelFormat, iLayerPlane,
60                                    nAttributes, piAttributes, piValues);
61 }
62 
getPixelFormatAttribfv(HDC hdc,int iPixelFormat,int iLayerPlane,UINT nAttributes,const int * piAttributes,float * pfValues) const63 BOOL SkWGLExtensions::getPixelFormatAttribfv(HDC hdc,
64                                              int iPixelFormat,
65                                              int iLayerPlane,
66                                              UINT nAttributes,
67                                              const int *piAttributes,
68                                              float *pfValues) const {
69     return fGetPixelFormatAttribfv(hdc, iPixelFormat, iLayerPlane,
70                                    nAttributes, piAttributes, pfValues);
71 }
createContextAttribs(HDC hDC,HGLRC hShareContext,const int * attribList) const72 HGLRC SkWGLExtensions::createContextAttribs(HDC hDC,
73                                             HGLRC hShareContext,
74                                             const int *attribList) const {
75     return fCreateContextAttribs(hDC, hShareContext, attribList);
76 }
77 
swapInterval(int interval) const78 BOOL SkWGLExtensions::swapInterval(int interval) const {
79     return fSwapInterval(interval);
80 }
81 
createPbuffer(HDC hDC,int iPixelFormat,int iWidth,int iHeight,const int * piAttribList) const82 HPBUFFER SkWGLExtensions::createPbuffer(HDC hDC,
83                                         int iPixelFormat,
84                                         int iWidth,
85                                         int iHeight,
86                                         const int *piAttribList) const {
87     return fCreatePbuffer(hDC, iPixelFormat, iWidth, iHeight, piAttribList);
88 }
89 
getPbufferDC(HPBUFFER hPbuffer) const90 HDC SkWGLExtensions::getPbufferDC(HPBUFFER hPbuffer) const {
91     return fGetPbufferDC(hPbuffer);
92 }
93 
releasePbufferDC(HPBUFFER hPbuffer,HDC hDC) const94 int SkWGLExtensions::releasePbufferDC(HPBUFFER hPbuffer, HDC hDC) const {
95     return fReleasePbufferDC(hPbuffer, hDC);
96 }
97 
destroyPbuffer(HPBUFFER hPbuffer) const98 BOOL SkWGLExtensions::destroyPbuffer(HPBUFFER hPbuffer) const {
99     return fDestroyPbuffer(hPbuffer);
100 }
101 
102 namespace {
103 
104 struct PixelFormat {
105     int fFormat;
106     int fSampleCnt;
107     int fChoosePixelFormatRank;
108 };
109 
pf_less(const PixelFormat & a,const PixelFormat & b)110 bool pf_less(const PixelFormat& a, const PixelFormat& b) {
111     if (a.fSampleCnt < b.fSampleCnt) {
112         return true;
113     } else if (b.fSampleCnt < a.fSampleCnt) {
114         return false;
115     } else if (a.fChoosePixelFormatRank < b.fChoosePixelFormatRank) {
116         return true;
117     }
118     return false;
119 }
120 }
121 
selectFormat(const int formats[],int formatCount,HDC dc,int desiredSampleCount) const122 int SkWGLExtensions::selectFormat(const int formats[],
123                                   int formatCount,
124                                   HDC dc,
125                                   int desiredSampleCount) const {
126     PixelFormat desiredFormat = {
127         0,
128         desiredSampleCount,
129         0,
130     };
131     SkTDArray<PixelFormat> rankedFormats;
132     rankedFormats.setCount(formatCount);
133     for (int i = 0; i < formatCount; ++i) {
134         static const int kQueryAttr = SK_WGL_SAMPLES;
135         int numSamples;
136         this->getPixelFormatAttribiv(dc,
137                                      formats[i],
138                                      0,
139                                      1,
140                                      &kQueryAttr,
141                                      &numSamples);
142         rankedFormats[i].fFormat =  formats[i];
143         rankedFormats[i].fSampleCnt = numSamples;
144         rankedFormats[i].fChoosePixelFormatRank = i;
145     }
146     SkTQSort(rankedFormats.begin(),
147              rankedFormats.begin() + rankedFormats.count() - 1,
148              SkTLessFunctionToFunctorAdaptor<PixelFormat, pf_less>());
149     int idx = SkTSearch<PixelFormat, pf_less>(rankedFormats.begin(),
150                                               rankedFormats.count(),
151                                               desiredFormat,
152                                               sizeof(PixelFormat));
153     if (idx < 0) {
154         idx = ~idx;
155     }
156     return rankedFormats[idx].fFormat;
157 }
158 
159 
160 namespace {
161 
162 #if defined(UNICODE)
163     #define STR_LIT(X) L## #X
164 #else
165     #define STR_LIT(X) #X
166 #endif
167 
168 #define DUMMY_CLASS STR_LIT("DummyClass")
169 
create_dummy_window()170 HWND create_dummy_window() {
171     HMODULE module = GetModuleHandle(NULL);
172     HWND dummy;
173     RECT windowRect;
174     windowRect.left = 0;
175     windowRect.right = 8;
176     windowRect.top = 0;
177     windowRect.bottom = 8;
178 
179     WNDCLASS wc;
180 
181     wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
182     wc.lpfnWndProc = (WNDPROC) DefWindowProc;
183     wc.cbClsExtra = 0;
184     wc.cbWndExtra = 0;
185     wc.hInstance = module;
186     wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
187     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
188     wc.hbrBackground = NULL;
189     wc.lpszMenuName = NULL;
190     wc.lpszClassName = DUMMY_CLASS;
191 
192     if(!RegisterClass(&wc)) {
193         return 0;
194     }
195 
196     DWORD style, exStyle;
197     exStyle = WS_EX_CLIENTEDGE;
198     style = WS_SYSMENU;
199 
200     AdjustWindowRectEx(&windowRect, style, false, exStyle);
201     if(!(dummy = CreateWindowEx(exStyle,
202                                 DUMMY_CLASS,
203                                 STR_LIT("DummyWindow"),
204                                 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
205                                 0, 0,
206                                 windowRect.right-windowRect.left,
207                                 windowRect.bottom-windowRect.top,
208                                 NULL, NULL,
209                                 module,
210                                 NULL))) {
211         UnregisterClass(DUMMY_CLASS, module);
212         return NULL;
213     }
214     ShowWindow(dummy, SW_HIDE);
215 
216     return dummy;
217 }
218 
destroy_dummy_window(HWND dummy)219 void destroy_dummy_window(HWND dummy) {
220     DestroyWindow(dummy);
221     HMODULE module = GetModuleHandle(NULL);
222     UnregisterClass(DUMMY_CLASS, module);
223 }
224 }
225 
226 #define GET_PROC(NAME, SUFFIX) f##NAME = \
227                      (##NAME##Proc) wglGetProcAddress("wgl" #NAME #SUFFIX)
228 
SkWGLExtensions()229 SkWGLExtensions::SkWGLExtensions()
230     : fGetExtensionsString(NULL)
231     , fChoosePixelFormat(NULL)
232     , fGetPixelFormatAttribfv(NULL)
233     , fGetPixelFormatAttribiv(NULL)
234     , fCreateContextAttribs(NULL)
235     , fSwapInterval(NULL)
236     , fCreatePbuffer(NULL)
237     , fGetPbufferDC(NULL)
238     , fReleasePbufferDC(NULL)
239     , fDestroyPbuffer(NULL)
240  {
241     HDC prevDC = wglGetCurrentDC();
242     HGLRC prevGLRC = wglGetCurrentContext();
243 
244     PIXELFORMATDESCRIPTOR dummyPFD;
245 
246     ZeroMemory(&dummyPFD, sizeof(dummyPFD));
247     dummyPFD.nSize = sizeof(dummyPFD);
248     dummyPFD.nVersion = 1;
249     dummyPFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
250     dummyPFD.iPixelType = PFD_TYPE_RGBA;
251     dummyPFD.cColorBits  = 32;
252     dummyPFD.cDepthBits  = 0;
253     dummyPFD.cStencilBits = 8;
254     dummyPFD.iLayerType = PFD_MAIN_PLANE;
255     HWND dummyWND = create_dummy_window();
256     if (dummyWND) {
257         HDC dummyDC = GetDC(dummyWND);
258         int dummyFormat = ChoosePixelFormat(dummyDC, &dummyPFD);
259         SetPixelFormat(dummyDC, dummyFormat, &dummyPFD);
260         HGLRC dummyGLRC = wglCreateContext(dummyDC);
261         SkASSERT(dummyGLRC);
262         wglMakeCurrent(dummyDC, dummyGLRC);
263 
264         GET_PROC(GetExtensionsString, ARB);
265         GET_PROC(ChoosePixelFormat, ARB);
266         GET_PROC(GetPixelFormatAttribiv, ARB);
267         GET_PROC(GetPixelFormatAttribfv, ARB);
268         GET_PROC(CreateContextAttribs, ARB);
269         GET_PROC(SwapInterval, EXT);
270         GET_PROC(CreatePbuffer, ARB);
271         GET_PROC(GetPbufferDC, ARB);
272         GET_PROC(ReleasePbufferDC, ARB);
273         GET_PROC(DestroyPbuffer, ARB);
274 
275         wglMakeCurrent(dummyDC, NULL);
276         wglDeleteContext(dummyGLRC);
277         destroy_dummy_window(dummyWND);
278     }
279 
280     wglMakeCurrent(prevDC, prevGLRC);
281 }
282 
283 ///////////////////////////////////////////////////////////////////////////////
284 
get_pixel_formats_to_try(HDC dc,const SkWGLExtensions & extensions,bool doubleBuffered,int msaaSampleCount,int formatsToTry[2])285 static void get_pixel_formats_to_try(HDC dc, const SkWGLExtensions& extensions,
286                                      bool doubleBuffered, int msaaSampleCount,
287                                      int formatsToTry[2]) {
288     int iAttrs[] = {
289         SK_WGL_DRAW_TO_WINDOW, TRUE,
290         SK_WGL_DOUBLE_BUFFER, (doubleBuffered ? TRUE : FALSE),
291         SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION,
292         SK_WGL_SUPPORT_OPENGL, TRUE,
293         SK_WGL_COLOR_BITS, 24,
294         SK_WGL_ALPHA_BITS, 8,
295         SK_WGL_STENCIL_BITS, 8,
296         0, 0
297     };
298 
299     float fAttrs[] = {0, 0};
300 
301     // Get a MSAA format if requested and possible.
302     if (msaaSampleCount > 0 &&
303         extensions.hasExtension(dc, "WGL_ARB_multisample")) {
304         static const int kIAttrsCount = SK_ARRAY_COUNT(iAttrs);
305         int msaaIAttrs[kIAttrsCount + 4];
306         memcpy(msaaIAttrs, iAttrs, sizeof(int) * kIAttrsCount);
307         SkASSERT(0 == msaaIAttrs[kIAttrsCount - 2] &&
308                  0 == msaaIAttrs[kIAttrsCount - 1]);
309         msaaIAttrs[kIAttrsCount - 2] = SK_WGL_SAMPLE_BUFFERS;
310         msaaIAttrs[kIAttrsCount - 1] = TRUE;
311         msaaIAttrs[kIAttrsCount + 0] = SK_WGL_SAMPLES;
312         msaaIAttrs[kIAttrsCount + 1] = msaaSampleCount;
313         msaaIAttrs[kIAttrsCount + 2] = 0;
314         msaaIAttrs[kIAttrsCount + 3] = 0;
315         unsigned int num;
316         int formats[64];
317         extensions.choosePixelFormat(dc, msaaIAttrs, fAttrs, 64, formats, &num);
318         num = SkTMin(num, 64U);
319         formatsToTry[0] = extensions.selectFormat(formats, num, dc, msaaSampleCount);
320     }
321 
322     // Get a non-MSAA format
323     int* format = -1 == formatsToTry[0] ? &formatsToTry[0] : &formatsToTry[1];
324     unsigned int num;
325     extensions.choosePixelFormat(dc, iAttrs, fAttrs, 1, format, &num);
326 }
327 
create_gl_context(HDC dc,SkWGLExtensions extensions,SkWGLContextRequest contextType)328 static HGLRC create_gl_context(HDC dc, SkWGLExtensions extensions, SkWGLContextRequest contextType) {
329     HDC prevDC = wglGetCurrentDC();
330     HGLRC prevGLRC = wglGetCurrentContext();
331 
332     HGLRC glrc = NULL;
333     if (kGLES_SkWGLContextRequest == contextType) {
334         if (!extensions.hasExtension(dc, "WGL_EXT_create_context_es2_profile")) {
335             wglMakeCurrent(prevDC, prevGLRC);
336             return NULL;
337         }
338         static const int glesAttribs[] = {
339             SK_WGL_CONTEXT_MAJOR_VERSION, 3,
340             SK_WGL_CONTEXT_MINOR_VERSION, 0,
341             SK_WGL_CONTEXT_PROFILE_MASK,  SK_WGL_CONTEXT_ES2_PROFILE_BIT,
342             0,
343         };
344         glrc = extensions.createContextAttribs(dc, NULL, glesAttribs);
345         if (NULL == glrc) {
346             wglMakeCurrent(prevDC, prevGLRC);
347             return NULL;
348         }
349     } else {
350         if (kGLPreferCoreProfile_SkWGLContextRequest == contextType &&
351             extensions.hasExtension(dc, "WGL_ARB_create_context")) {
352             static const int kCoreGLVersions[] = {
353                 4, 3,
354                 4, 2,
355                 4, 1,
356                 4, 0,
357                 3, 3,
358                 3, 2,
359             };
360             int coreProfileAttribs[] = {
361                 SK_WGL_CONTEXT_MAJOR_VERSION, -1,
362                 SK_WGL_CONTEXT_MINOR_VERSION, -1,
363                 SK_WGL_CONTEXT_PROFILE_MASK,  SK_WGL_CONTEXT_CORE_PROFILE_BIT,
364                 0,
365             };
366             for (int v = 0; v < SK_ARRAY_COUNT(kCoreGLVersions) / 2; ++v) {
367                 coreProfileAttribs[1] = kCoreGLVersions[2 * v];
368                 coreProfileAttribs[3] = kCoreGLVersions[2 * v + 1];
369                 glrc = extensions.createContextAttribs(dc, NULL, coreProfileAttribs);
370                 if (glrc) {
371                     break;
372                 }
373             }
374         }
375     }
376 
377     if (NULL == glrc) {
378         glrc = wglCreateContext(dc);
379     }
380     SkASSERT(glrc);
381 
382     wglMakeCurrent(prevDC, prevGLRC);
383 
384     // This might help make the context non-vsynced.
385     if (extensions.hasExtension(dc, "WGL_EXT_swap_control")) {
386         extensions.swapInterval(-1);
387     }
388     return glrc;
389 }
390 
SkCreateWGLContext(HDC dc,int msaaSampleCount,SkWGLContextRequest contextType)391 HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, SkWGLContextRequest contextType) {
392     SkWGLExtensions extensions;
393     if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) {
394         return NULL;
395     }
396 
397     BOOL set = FALSE;
398 
399     int pixelFormatsToTry[] = { -1, -1 };
400     get_pixel_formats_to_try(dc, extensions, true, msaaSampleCount, pixelFormatsToTry);
401     for (int f = 0;
402          !set && -1 != pixelFormatsToTry[f] && f < SK_ARRAY_COUNT(pixelFormatsToTry);
403          ++f) {
404         PIXELFORMATDESCRIPTOR pfd;
405         DescribePixelFormat(dc, pixelFormatsToTry[f], sizeof(pfd), &pfd);
406         set = SetPixelFormat(dc, pixelFormatsToTry[f], &pfd);
407     }
408 
409     if (!set) {
410         return NULL;
411     }
412 
413     return create_gl_context(dc, extensions, contextType);}
414 
Create(HDC parentDC,int msaaSampleCount,SkWGLContextRequest contextType)415 SkWGLPbufferContext* SkWGLPbufferContext::Create(HDC parentDC, int msaaSampleCount,
416                                                  SkWGLContextRequest contextType) {
417     SkWGLExtensions extensions;
418     if (!extensions.hasExtension(parentDC, "WGL_ARB_pixel_format") ||
419         !extensions.hasExtension(parentDC, "WGL_ARB_pbuffer")) {
420         return NULL;
421     }
422 
423     // try for single buffer first
424     for (int dblBuffer = 0; dblBuffer < 2; ++dblBuffer) {
425         int pixelFormatsToTry[] = { -1, -1 };
426         get_pixel_formats_to_try(parentDC, extensions, (0 != dblBuffer), msaaSampleCount,
427                                  pixelFormatsToTry);
428         for (int f = 0; -1 != pixelFormatsToTry[f] && f < SK_ARRAY_COUNT(pixelFormatsToTry); ++f) {
429             HPBUFFER pbuf = extensions.createPbuffer(parentDC, pixelFormatsToTry[f], 1, 1, NULL);
430             if (0 != pbuf) {
431                 HDC dc = extensions.getPbufferDC(pbuf);
432                 if (dc) {
433                     HGLRC glrc = create_gl_context(dc, extensions, contextType);
434                     if (glrc) {
435                         return SkNEW_ARGS(SkWGLPbufferContext, (pbuf, dc, glrc));
436                     }
437                     extensions.releasePbufferDC(pbuf, dc);
438                 }
439                 extensions.destroyPbuffer(pbuf);
440             }
441         }
442     }
443     return NULL;
444 }
445 
~SkWGLPbufferContext()446 SkWGLPbufferContext::~SkWGLPbufferContext() {
447     SkASSERT(fExtensions.hasExtension(fDC, "WGL_ARB_pbuffer"));
448     wglDeleteContext(fGLRC);
449     fExtensions.releasePbufferDC(fPbuffer, fDC);
450     fExtensions.destroyPbuffer(fPbuffer);
451 }
452 
SkWGLPbufferContext(HPBUFFER pbuffer,HDC dc,HGLRC glrc)453 SkWGLPbufferContext::SkWGLPbufferContext(HPBUFFER pbuffer, HDC dc, HGLRC glrc)
454     : fPbuffer(pbuffer)
455     , fDC(dc)
456     , fGLRC(glrc) {
457 }
458