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