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