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