• 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 "include/core/SkTypes.h"
9 #if defined(SK_BUILD_FOR_WIN) && !defined(_M_ARM64)
10 
11 #include "src/utils/win/SkWGL.h"
12 
13 #include "include/private/SkOnce.h"
14 #include "include/private/SkTDArray.h"
15 #include "src/core/SkTSearch.h"
16 #include "src/core/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     SkASSERT(desiredSampleCount >= 1);
130     if (formatCount <= 0) {
131         return -1;
132     }
133     PixelFormat desiredFormat = {
134         0,
135         desiredSampleCount,
136         0,
137     };
138     SkTDArray<PixelFormat> rankedFormats;
139     rankedFormats.setCount(formatCount);
140     for (int i = 0; i < formatCount; ++i) {
141         static const int kQueryAttr = SK_WGL_SAMPLES;
142         int numSamples;
143         this->getPixelFormatAttribiv(dc,
144                                      formats[i],
145                                      0,
146                                      1,
147                                      &kQueryAttr,
148                                      &numSamples);
149         rankedFormats[i].fFormat =  formats[i];
150         rankedFormats[i].fSampleCnt = SkTMax(1, numSamples);
151         rankedFormats[i].fChoosePixelFormatRank = i;
152     }
153     SkTQSort(rankedFormats.begin(),
154              rankedFormats.begin() + rankedFormats.count() - 1,
155              SkTLessFunctionToFunctorAdaptor<PixelFormat, pf_less>());
156     int idx = SkTSearch<PixelFormat, pf_less>(rankedFormats.begin(),
157                                               rankedFormats.count(),
158                                               desiredFormat,
159                                               sizeof(PixelFormat));
160     if (idx < 0) {
161         idx = ~idx;
162     }
163     // If the caller asked for non-MSAA fail if the closest format has MSAA.
164     if (desiredSampleCount == 1 && rankedFormats[idx].fSampleCnt != 1) {
165         return -1;
166     }
167     return rankedFormats[idx].fFormat;
168 }
169 
170 
171 namespace {
172 
173 #if defined(UNICODE)
174     #define STR_LIT(X) L## #X
175 #else
176     #define STR_LIT(X) #X
177 #endif
178 
179 #define DUMMY_CLASS STR_LIT("DummyClass")
180 
create_dummy_window()181 HWND create_dummy_window() {
182     HMODULE module = GetModuleHandle(nullptr);
183     HWND dummy;
184     RECT windowRect;
185     windowRect.left = 0;
186     windowRect.right = 8;
187     windowRect.top = 0;
188     windowRect.bottom = 8;
189 
190     WNDCLASS wc;
191 
192     wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
193     wc.lpfnWndProc = (WNDPROC) DefWindowProc;
194     wc.cbClsExtra = 0;
195     wc.cbWndExtra = 0;
196     wc.hInstance = module;
197     wc.hIcon = LoadIcon(nullptr, IDI_WINLOGO);
198     wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
199     wc.hbrBackground = nullptr;
200     wc.lpszMenuName = nullptr;
201     wc.lpszClassName = DUMMY_CLASS;
202 
203     if(!RegisterClass(&wc)) {
204         return 0;
205     }
206 
207     DWORD style, exStyle;
208     exStyle = WS_EX_CLIENTEDGE;
209     style = WS_SYSMENU;
210 
211     AdjustWindowRectEx(&windowRect, style, false, exStyle);
212     if(!(dummy = CreateWindowEx(exStyle,
213                                 DUMMY_CLASS,
214                                 STR_LIT("DummyWindow"),
215                                 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
216                                 0, 0,
217                                 windowRect.right-windowRect.left,
218                                 windowRect.bottom-windowRect.top,
219                                 nullptr, nullptr,
220                                 module,
221                                 nullptr))) {
222         UnregisterClass(DUMMY_CLASS, module);
223         return nullptr;
224     }
225     ShowWindow(dummy, SW_HIDE);
226 
227     return dummy;
228 }
229 
destroy_dummy_window(HWND dummy)230 void destroy_dummy_window(HWND dummy) {
231     DestroyWindow(dummy);
232     HMODULE module = GetModuleHandle(nullptr);
233     UnregisterClass(DUMMY_CLASS, module);
234 }
235 }
236 
237 #define GET_PROC(NAME, SUFFIX) f##NAME = \
238                      (NAME##Proc) wglGetProcAddress("wgl" #NAME #SUFFIX)
239 
240 
241 SkWGLExtensions::GetExtensionsStringProc SkWGLExtensions::fGetExtensionsString = nullptr;
242 SkWGLExtensions::ChoosePixelFormatProc SkWGLExtensions::fChoosePixelFormat = nullptr;
243 SkWGLExtensions::GetPixelFormatAttribfvProc SkWGLExtensions::fGetPixelFormatAttribfv = nullptr;
244 SkWGLExtensions::GetPixelFormatAttribivProc SkWGLExtensions::fGetPixelFormatAttribiv = nullptr;
245 SkWGLExtensions::CreateContextAttribsProc SkWGLExtensions::fCreateContextAttribs = nullptr;
246 SkWGLExtensions::SwapIntervalProc SkWGLExtensions::fSwapInterval = nullptr;
247 SkWGLExtensions::CreatePbufferProc SkWGLExtensions::fCreatePbuffer = nullptr;
248 SkWGLExtensions::GetPbufferDCProc SkWGLExtensions::fGetPbufferDC = nullptr;
249 SkWGLExtensions::ReleasePbufferDCProc SkWGLExtensions::fReleasePbufferDC = nullptr;
250 SkWGLExtensions::DestroyPbufferProc SkWGLExtensions::fDestroyPbuffer = nullptr;
251 
SkWGLExtensions()252 SkWGLExtensions::SkWGLExtensions() {
253     // We cache these function pointers once, and then reuse them. That's possibly incorrect if
254     // there are multiple GPUs, or if we intend to use these for rendering contexts of different
255     // pixel formats (where wglGetProcAddress is not guaranteed to return the same pointer).
256     static SkOnce once;
257     once([] {
258         HDC prevDC = wglGetCurrentDC();
259         HGLRC prevGLRC = wglGetCurrentContext();
260 
261         PIXELFORMATDESCRIPTOR dummyPFD;
262 
263         ZeroMemory(&dummyPFD, sizeof(dummyPFD));
264         dummyPFD.nSize = sizeof(dummyPFD);
265         dummyPFD.nVersion = 1;
266         dummyPFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
267         dummyPFD.iPixelType = PFD_TYPE_RGBA;
268         dummyPFD.cColorBits  = 32;
269         dummyPFD.cDepthBits  = 0;
270         dummyPFD.cStencilBits = 8;
271         dummyPFD.iLayerType = PFD_MAIN_PLANE;
272         HWND dummyWND = create_dummy_window();
273         if (dummyWND) {
274             HDC dummyDC = GetDC(dummyWND);
275             int dummyFormat = ChoosePixelFormat(dummyDC, &dummyPFD);
276             SetPixelFormat(dummyDC, dummyFormat, &dummyPFD);
277             HGLRC dummyGLRC = wglCreateContext(dummyDC);
278             SkASSERT(dummyGLRC);
279             wglMakeCurrent(dummyDC, dummyGLRC);
280 
281             GET_PROC(GetExtensionsString, ARB);
282             GET_PROC(ChoosePixelFormat, ARB);
283             GET_PROC(GetPixelFormatAttribiv, ARB);
284             GET_PROC(GetPixelFormatAttribfv, ARB);
285             GET_PROC(CreateContextAttribs, ARB);
286             GET_PROC(SwapInterval, EXT);
287             GET_PROC(CreatePbuffer, ARB);
288             GET_PROC(GetPbufferDC, ARB);
289             GET_PROC(ReleasePbufferDC, ARB);
290             GET_PROC(DestroyPbuffer, ARB);
291 
292             wglMakeCurrent(dummyDC, nullptr);
293             wglDeleteContext(dummyGLRC);
294             destroy_dummy_window(dummyWND);
295         }
296 
297         wglMakeCurrent(prevDC, prevGLRC);
298     });
299 }
300 
301 ///////////////////////////////////////////////////////////////////////////////
302 
get_pixel_formats_to_try(HDC dc,const SkWGLExtensions & extensions,bool doubleBuffered,int msaaSampleCount,bool deepColor,int formatsToTry[2])303 static void get_pixel_formats_to_try(HDC dc, const SkWGLExtensions& extensions,
304                                      bool doubleBuffered, int msaaSampleCount, bool deepColor,
305                                      int formatsToTry[2]) {
306     auto appendAttr = [](SkTDArray<int>& attrs, int attr, int value) {
307         attrs.push_back(attr);
308         attrs.push_back(value);
309     };
310 
311     SkTDArray<int> iAttrs;
312     appendAttr(iAttrs, SK_WGL_DRAW_TO_WINDOW, TRUE);
313     appendAttr(iAttrs, SK_WGL_DOUBLE_BUFFER, (doubleBuffered ? TRUE : FALSE));
314     appendAttr(iAttrs, SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION);
315     appendAttr(iAttrs, SK_WGL_SUPPORT_OPENGL, TRUE);
316     if (deepColor) {
317         appendAttr(iAttrs, SK_WGL_RED_BITS, 10);
318         appendAttr(iAttrs, SK_WGL_GREEN_BITS, 10);
319         appendAttr(iAttrs, SK_WGL_BLUE_BITS, 10);
320         appendAttr(iAttrs, SK_WGL_ALPHA_BITS, 2);
321     } else {
322         appendAttr(iAttrs, SK_WGL_COLOR_BITS, 24);
323         appendAttr(iAttrs, SK_WGL_ALPHA_BITS, 8);
324     }
325     appendAttr(iAttrs, SK_WGL_STENCIL_BITS, 8);
326 
327     float fAttrs[] = {0, 0};
328 
329     // Get a MSAA format if requested and possible.
330     if (msaaSampleCount > 0 &&
331         extensions.hasExtension(dc, "WGL_ARB_multisample")) {
332         SkTDArray<int> msaaIAttrs = iAttrs;
333         appendAttr(msaaIAttrs, SK_WGL_SAMPLE_BUFFERS, TRUE);
334         appendAttr(msaaIAttrs, SK_WGL_SAMPLES, msaaSampleCount);
335         appendAttr(msaaIAttrs, 0, 0);
336         unsigned int num;
337         int formats[64];
338         extensions.choosePixelFormat(dc, msaaIAttrs.begin(), fAttrs, 64, formats, &num);
339         num = SkTMin(num, 64U);
340         formatsToTry[0] = extensions.selectFormat(formats, num, dc, msaaSampleCount);
341     }
342 
343     // Get a non-MSAA format
344     int* format = -1 == formatsToTry[0] ? &formatsToTry[0] : &formatsToTry[1];
345     unsigned int num;
346     appendAttr(iAttrs, 0, 0);
347     extensions.choosePixelFormat(dc, iAttrs.begin(), fAttrs, 1, format, &num);
348 }
349 
create_gl_context(HDC dc,const SkWGLExtensions & extensions,SkWGLContextRequest contextType,HGLRC shareContext)350 static HGLRC create_gl_context(HDC dc, const SkWGLExtensions& extensions,
351                                SkWGLContextRequest contextType, HGLRC shareContext) {
352     HDC prevDC = wglGetCurrentDC();
353     HGLRC prevGLRC = wglGetCurrentContext();
354 
355     HGLRC glrc = nullptr;
356     if (kGLES_SkWGLContextRequest == contextType) {
357         if (!extensions.hasExtension(dc, "WGL_EXT_create_context_es2_profile")) {
358             wglMakeCurrent(prevDC, prevGLRC);
359             return nullptr;
360         }
361         static const int glesAttribs[] = {
362             SK_WGL_CONTEXT_MAJOR_VERSION, 3,
363             SK_WGL_CONTEXT_MINOR_VERSION, 0,
364             SK_WGL_CONTEXT_PROFILE_MASK,  SK_WGL_CONTEXT_ES2_PROFILE_BIT,
365             0,
366         };
367         glrc = extensions.createContextAttribs(dc, shareContext, glesAttribs);
368         if (nullptr == glrc) {
369             wglMakeCurrent(prevDC, prevGLRC);
370             return nullptr;
371         }
372     } else {
373         if (kGLPreferCoreProfile_SkWGLContextRequest == contextType &&
374             extensions.hasExtension(dc, "WGL_ARB_create_context")) {
375             static const int kCoreGLVersions[] = {
376                 4, 3,
377                 4, 2,
378                 4, 1,
379                 4, 0,
380                 3, 3,
381                 3, 2,
382             };
383             int coreProfileAttribs[] = {
384                 SK_WGL_CONTEXT_MAJOR_VERSION, -1,
385                 SK_WGL_CONTEXT_MINOR_VERSION, -1,
386                 SK_WGL_CONTEXT_PROFILE_MASK,  SK_WGL_CONTEXT_CORE_PROFILE_BIT,
387                 0,
388             };
389             for (size_t v = 0; v < SK_ARRAY_COUNT(kCoreGLVersions) / 2; ++v) {
390                 coreProfileAttribs[1] = kCoreGLVersions[2 * v];
391                 coreProfileAttribs[3] = kCoreGLVersions[2 * v + 1];
392                 glrc = extensions.createContextAttribs(dc, shareContext, coreProfileAttribs);
393                 if (glrc) {
394                     break;
395                 }
396             }
397         }
398     }
399 
400     if (nullptr == glrc) {
401         glrc = wglCreateContext(dc);
402         if (shareContext) {
403             if (!wglShareLists(shareContext, glrc)) {
404                 wglDeleteContext(glrc);
405                 return nullptr;
406             }
407         }
408     }
409     SkASSERT(glrc);
410 
411     wglMakeCurrent(prevDC, prevGLRC);
412 
413     return glrc;
414 }
415 
SkCreateWGLContext(HDC dc,int msaaSampleCount,bool deepColor,SkWGLContextRequest contextType,HGLRC shareContext)416 HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor,
417                          SkWGLContextRequest contextType, HGLRC shareContext) {
418     SkWGLExtensions extensions;
419     if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) {
420         return nullptr;
421     }
422 
423     BOOL set = FALSE;
424 
425     int pixelFormatsToTry[] = { -1, -1 };
426     get_pixel_formats_to_try(dc, extensions, true, msaaSampleCount, deepColor, pixelFormatsToTry);
427     for (size_t f = 0;
428          !set && -1 != pixelFormatsToTry[f] && f < SK_ARRAY_COUNT(pixelFormatsToTry);
429          ++f) {
430         PIXELFORMATDESCRIPTOR pfd;
431         DescribePixelFormat(dc, pixelFormatsToTry[f], sizeof(pfd), &pfd);
432         set = SetPixelFormat(dc, pixelFormatsToTry[f], &pfd);
433     }
434 
435     if (!set) {
436         return nullptr;
437     }
438 
439     return create_gl_context(dc, extensions, contextType, shareContext);
440 }
441 
Create(HDC parentDC,SkWGLContextRequest contextType,HGLRC shareContext)442 sk_sp<SkWGLPbufferContext> SkWGLPbufferContext::Create(HDC parentDC,
443                                                        SkWGLContextRequest contextType,
444                                                        HGLRC shareContext) {
445     SkWGLExtensions extensions;
446     if (!extensions.hasExtension(parentDC, "WGL_ARB_pixel_format") ||
447         !extensions.hasExtension(parentDC, "WGL_ARB_pbuffer")) {
448         return nullptr;
449     }
450 
451     // We cache the pixel formats once, and then reuse them. That's possibly incorrect if
452     // there are multiple GPUs, but this function is always called with a freshly made,
453     // identically constructed HDC (see WinGLTestContext).
454     //
455     // We only store two potential pixel formats, one for single buffer, one for double buffer.
456     // We never ask for MSAA, so we don't need the second pixel format for each buffering state.
457     static int gPixelFormats[2] = { -1, -1 };
458     static SkOnce once;
459     once([=] {
460         {
461             // Single buffer
462             int pixelFormatsToTry[2] = { -1, -1 };
463             get_pixel_formats_to_try(parentDC, extensions, false, 0, false, pixelFormatsToTry);
464             gPixelFormats[0] = pixelFormatsToTry[0];
465         }
466         {
467             // Double buffer
468             int pixelFormatsToTry[2] = { -1, -1 };
469             get_pixel_formats_to_try(parentDC, extensions, true, 0, false, pixelFormatsToTry);
470             gPixelFormats[1] = pixelFormatsToTry[0];
471         }
472     });
473 
474     // try for single buffer first
475     for (int pixelFormat : gPixelFormats) {
476         if (-1 == pixelFormat) {
477             continue;
478         }
479         HPBUFFER pbuf = extensions.createPbuffer(parentDC, pixelFormat, 1, 1, nullptr);
480         if (0 != pbuf) {
481             HDC dc = extensions.getPbufferDC(pbuf);
482             if (dc) {
483                 HGLRC glrc = create_gl_context(dc, extensions, contextType, shareContext);
484                 if (glrc) {
485                     return sk_sp<SkWGLPbufferContext>(new SkWGLPbufferContext(pbuf, dc, glrc));
486                 }
487                 extensions.releasePbufferDC(pbuf, dc);
488             }
489             extensions.destroyPbuffer(pbuf);
490         }
491     }
492     return nullptr;
493 }
494 
~SkWGLPbufferContext()495 SkWGLPbufferContext::~SkWGLPbufferContext() {
496     SkASSERT(fExtensions.hasExtension(fDC, "WGL_ARB_pbuffer"));
497     wglDeleteContext(fGLRC);
498     fExtensions.releasePbufferDC(fPbuffer, fDC);
499     fExtensions.destroyPbuffer(fPbuffer);
500 }
501 
SkWGLPbufferContext(HPBUFFER pbuffer,HDC dc,HGLRC glrc)502 SkWGLPbufferContext::SkWGLPbufferContext(HPBUFFER pbuffer, HDC dc, HGLRC glrc)
503     : fPbuffer(pbuffer)
504     , fDC(dc)
505     , fGLRC(glrc) {
506 }
507 
508 #endif//defined(SK_BUILD_FOR_WIN)
509