Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkWGL_win.cpp
Go to the documentation of this file.
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
9#if defined(SK_BUILD_FOR_WIN) && !defined(_M_ARM64) && !defined(WINUWP)
10
12
15#include "src/base/SkTSearch.h"
16#include "src/base/SkTSort.h"
17
18bool 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
40const char* SkWGLExtensions::getExtensionsString(HDC hdc) const {
41 return fGetExtensionsString(hdc);
42}
43
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
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
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}
74 HGLRC hShareContext,
75 const int *attribList) const {
76 return fCreateContextAttribs(hDC, hShareContext, attribList);
77}
78
79BOOL SkWGLExtensions::swapInterval(int interval) const {
80 return fSwapInterval(interval);
81}
82
83HPBUFFER 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
91HDC SkWGLExtensions::getPbufferDC(HPBUFFER hPbuffer) const {
92 return fGetPbufferDC(hPbuffer);
93}
94
95int SkWGLExtensions::releasePbufferDC(HPBUFFER hPbuffer, HDC hDC) const {
96 return fReleasePbufferDC(hPbuffer, hDC);
97}
98
99BOOL SkWGLExtensions::destroyPbuffer(HPBUFFER hPbuffer) const {
100 return fDestroyPbuffer(hPbuffer);
101}
102
103namespace {
104
105struct PixelFormat {
106 int fFormat;
107 int fSampleCnt;
108 int fChoosePixelFormatRank;
109};
110
111bool 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
123int 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
167namespace {
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
177HWND 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
226void 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
237SkWGLExtensions::GetExtensionsStringProc SkWGLExtensions::fGetExtensionsString = nullptr;
238SkWGLExtensions::ChoosePixelFormatProc SkWGLExtensions::fChoosePixelFormat = nullptr;
239SkWGLExtensions::GetPixelFormatAttribfvProc SkWGLExtensions::fGetPixelFormatAttribfv = nullptr;
240SkWGLExtensions::GetPixelFormatAttribivProc SkWGLExtensions::fGetPixelFormatAttribiv = nullptr;
241SkWGLExtensions::CreateContextAttribsProc SkWGLExtensions::fCreateContextAttribs = nullptr;
242SkWGLExtensions::SwapIntervalProc SkWGLExtensions::fSwapInterval = nullptr;
243SkWGLExtensions::CreatePbufferProc SkWGLExtensions::fCreatePbuffer = nullptr;
244SkWGLExtensions::GetPbufferDCProc SkWGLExtensions::fGetPbufferDC = nullptr;
245SkWGLExtensions::ReleasePbufferDCProc SkWGLExtensions::fReleasePbufferDC = nullptr;
246SkWGLExtensions::DestroyPbufferProc SkWGLExtensions::fDestroyPbuffer = nullptr;
247
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
308static 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));
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
355static 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[] = {
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[] = {
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
421HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor,
422 SkWGLContextRequest contextType, HGLRC shareContext) {
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
448 SkWGLContextRequest contextType,
449 HGLRC shareContext) {
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
501 SkASSERT(fExtensions.hasExtension(fDC, "WGL_ARB_pbuffer"));
502 wglDeleteContext(fGLRC);
503 fExtensions.releasePbufferDC(fPbuffer, fDC);
504 fExtensions.destroyPbuffer(fPbuffer);
505}
506
507SkWGLPbufferContext::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)
#define SkASSERT(cond)
Definition SkAssert.h:116
void SkTQSort(T *begin, T *end, const C &lessThan)
Definition SkTSort.h:194
#define SK_WGL_DRAW_TO_WINDOW
Definition SkWGL.h:25
#define SK_WGL_ACCELERATION
Definition SkWGL.h:26
#define SK_WGL_RED_BITS
Definition SkWGL.h:30
#define SK_WGL_BLUE_BITS
Definition SkWGL.h:32
HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor, SkWGLContextRequest context, HGLRC shareContext=nullptr)
#define SK_WGL_COLOR_BITS
Definition SkWGL.h:29
#define SK_WGL_CONTEXT_CORE_PROFILE_BIT
Definition SkWGL.h:45
#define SK_WGL_SAMPLES
Definition SkWGL.h:37
#define SK_WGL_GREEN_BITS
Definition SkWGL.h:31
#define SK_WGL_STENCIL_BITS
Definition SkWGL.h:34
#define SK_WGL_SUPPORT_OPENGL
Definition SkWGL.h:27
#define SK_WGL_FULL_ACCELERATION
Definition SkWGL.h:35
SkWGLContextRequest
Definition SkWGL.h:119
@ kGLES_SkWGLContextRequest
Definition SkWGL.h:127
@ kGLPreferCoreProfile_SkWGLContextRequest
Definition SkWGL.h:122
#define SK_WGL_CONTEXT_MINOR_VERSION
Definition SkWGL.h:39
#define SK_WGL_SAMPLE_BUFFERS
Definition SkWGL.h:36
#define SK_WGL_CONTEXT_PROFILE_MASK
Definition SkWGL.h:42
#define SK_WGL_DOUBLE_BUFFER
Definition SkWGL.h:28
#define SK_WGL_ALPHA_BITS
Definition SkWGL.h:33
#define SK_WGL_CONTEXT_ES2_PROFILE_BIT
Definition SkWGL.h:47
#define SK_WGL_CONTEXT_MAJOR_VERSION
Definition SkWGL.h:38
#define ARB(name,...)
T * end()
Definition SkTDArray.h:152
int size() const
Definition SkTDArray.h:138
void push_back(const T &v)
Definition SkTDArray.h:219
T * begin()
Definition SkTDArray.h:150
void resize(int count)
Definition SkTDArray.h:183
int releasePbufferDC(HPBUFFER, HDC) const
HPBUFFER createPbuffer(HDC, int, int, int, const int *) const
BOOL swapInterval(int interval) const
BOOL choosePixelFormat(HDC hdc, const int *, const FLOAT *, UINT, int *, UINT *) const
int selectFormat(const int formats[], int formatCount, HDC dc, int desiredSampleCount) const
const char * getExtensionsString(HDC hdc) const
bool hasExtension(HDC dc, const char *ext) const
BOOL getPixelFormatAttribiv(HDC, int, int, UINT, const int *, int *) const
BOOL destroyPbuffer(HPBUFFER) const
HGLRC createContextAttribs(HDC, HGLRC, const int *) const
BOOL getPixelFormatAttribfv(HDC hdc, int, int, UINT, const int *, FLOAT *) const
HDC getPbufferDC(HPBUFFER) const
static sk_sp< SkWGLPbufferContext > Create(HDC parentDC, SkWGLContextRequest contextType, HGLRC shareContext)
~SkWGLPbufferContext() override
static bool b
struct MyStruct a[10]
uint8_t value
uint32_t uint32_t * format
return FALSE
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
Definition switches.h:76
int BOOL
unsigned int UINT
#define LoadIcon
unsigned long DWORD
HINSTANCE HMODULE