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