blob: dabe13637336f53f5b2c7ff59a2237ef75b651b2 [file] [log] [blame]
bsalomon@google.combd7c6412011-12-01 16:34:28 +00001
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 "SkWGL.h"
10
bsalomon@google.com8a189b02012-04-17 12:43:00 +000011#include "SkTDArray.h"
12#include "SkTSearch.h"
13
bsalomon@google.combd7c6412011-12-01 16:34:28 +000014bool SkWGLExtensions::hasExtension(HDC dc, const char* ext) const {
15 if (NULL == this->fGetExtensionsString) {
16 return false;
17 }
18 if (!strcmp("WGL_ARB_extensions_string", ext)) {
19 return true;
20 }
21 const char* extensionString = this->getExtensionsString(dc);
22 int extLength = strlen(ext);
23
24 while (true) {
25 int n = strcspn(extensionString, " ");
26 if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
27 return true;
28 }
29 if (0 == extensionString[n]) {
30 return false;
31 }
32 extensionString += n+1;
33 }
34
35 return false;
36}
37
38const char* SkWGLExtensions::getExtensionsString(HDC hdc) const {
39 return fGetExtensionsString(hdc);
40}
41
42BOOL SkWGLExtensions::choosePixelFormat(HDC hdc,
43 const int* piAttribIList,
44 const FLOAT* pfAttribFList,
45 UINT nMaxFormats,
46 int* piFormats,
47 UINT* nNumFormats) const {
48 return fChoosePixelFormat(hdc, piAttribIList, pfAttribFList,
49 nMaxFormats, piFormats, nNumFormats);
50}
51
52BOOL SkWGLExtensions::getPixelFormatAttribiv(HDC hdc,
53 int iPixelFormat,
54 int iLayerPlane,
55 UINT nAttributes,
56 const int *piAttributes,
57 int *piValues) const {
58 return fGetPixelFormatAttribiv(hdc, iPixelFormat, iLayerPlane,
59 nAttributes, piAttributes, piValues);
60}
61
62BOOL SkWGLExtensions::getPixelFormatAttribfv(HDC hdc,
63 int iPixelFormat,
64 int iLayerPlane,
65 UINT nAttributes,
66 const int *piAttributes,
67 float *pfValues) const {
68 return fGetPixelFormatAttribfv(hdc, iPixelFormat, iLayerPlane,
69 nAttributes, piAttributes, pfValues);
70}
71HGLRC SkWGLExtensions::createContextAttribs(HDC hDC,
72 HGLRC hShareContext,
73 const int *attribList) const {
74 return fCreateContextAttribs(hDC, hShareContext, attribList);
75}
76
77namespace {
78
bsalomon@google.com8a189b02012-04-17 12:43:00 +000079struct PixelFormat {
80 int fFormat;
81 int fCoverageSamples;
82 int fColorSamples;
83 int fChoosePixelFormatRank;
84};
85
86int compare_pf(const PixelFormat* a, const PixelFormat* b) {
87 if (a->fCoverageSamples < b->fCoverageSamples) {
88 return -1;
89 } else if (b->fCoverageSamples < a->fCoverageSamples) {
90 return 1;
91 } else if (a->fColorSamples < b->fColorSamples) {
92 return -1;
93 } else if (b->fColorSamples < a->fColorSamples) {
94 return 1;
95 } else if (a->fChoosePixelFormatRank < b->fChoosePixelFormatRank) {
96 return -1;
97 } else if (b->fChoosePixelFormatRank < a->fChoosePixelFormatRank) {
98 return 1;
99 }
100 return 0;
101}
102}
103
104int SkWGLExtensions::selectFormat(const int formats[],
105 int formatCount,
106 HDC dc,
107 int desiredSampleCount) {
108 PixelFormat desiredFormat = {
109 0,
110 desiredSampleCount,
111 0,
112 0,
113 };
114 SkTDArray<PixelFormat> rankedFormats;
115 rankedFormats.setCount(formatCount);
116 bool supportsCoverage = this->hasExtension(dc,
117 "WGL_NV_multisample_coverage");
118 for (int i = 0; i < formatCount; ++i) {
119 static const int queryAttrs[] = {
120 SK_WGL_COVERAGE_SAMPLES,
robertphillips@google.comf92cfcf2012-09-17 13:38:57 +0000121 // Keep COLOR_SAMPLES at the end so it can be skipped
bsalomon@google.com8a189b02012-04-17 12:43:00 +0000122 SK_WGL_COLOR_SAMPLES,
123 };
124 int answers[2];
skia.committer@gmail.com54339a82012-09-18 02:01:09 +0000125 int queryAttrCnt = supportsCoverage ?
126 SK_ARRAY_COUNT(queryAttrs) :
robertphillips@google.comf92cfcf2012-09-17 13:38:57 +0000127 SK_ARRAY_COUNT(queryAttrs) - 1;
bsalomon@google.com8a189b02012-04-17 12:43:00 +0000128 this->getPixelFormatAttribiv(dc,
129 formats[i],
130 0,
robertphillips@google.comf92cfcf2012-09-17 13:38:57 +0000131 queryAttrCnt,
bsalomon@google.com8a189b02012-04-17 12:43:00 +0000132 queryAttrs,
133 answers);
134 rankedFormats[i].fFormat = formats[i];
135 rankedFormats[i].fCoverageSamples = answers[0];
136 rankedFormats[i].fColorSamples = answers[supportsCoverage ? 1 : 0];
137 rankedFormats[i].fChoosePixelFormatRank = i;
138 }
reed@google.comaa99c9e2012-05-07 15:04:18 +0000139 qsort(rankedFormats.begin(),
bsalomon@google.com8a189b02012-04-17 12:43:00 +0000140 rankedFormats.count(),
141 sizeof(PixelFormat),
reed@google.comaa99c9e2012-05-07 15:04:18 +0000142 SkCastForQSort(compare_pf));
bsalomon@google.com8a189b02012-04-17 12:43:00 +0000143 int idx = SkTSearch<PixelFormat>(rankedFormats.begin(),
144 rankedFormats.count(),
145 desiredFormat,
146 sizeof(PixelFormat),
147 compare_pf);
148 if (idx < 0) {
149 idx = ~idx;
150 }
151 return rankedFormats[idx].fFormat;
152}
153
154
155namespace {
156
bsalomon@google.combd7c6412011-12-01 16:34:28 +0000157#if defined(UNICODE)
158 #define STR_LIT(X) L## #X
159#else
160 #define STR_LIT(X) #X
161#endif
162
163#define DUMMY_CLASS STR_LIT("DummyClass")
164
165HWND create_dummy_window() {
166 HMODULE module = GetModuleHandle(NULL);
167 HWND dummy;
168 RECT windowRect;
169 windowRect.left = 0;
170 windowRect.right = 8;
171 windowRect.top = 0;
172 windowRect.bottom = 8;
173
174 WNDCLASS wc;
175
176 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
177 wc.lpfnWndProc = (WNDPROC) DefWindowProc;
178 wc.cbClsExtra = 0;
179 wc.cbWndExtra = 0;
180 wc.hInstance = module;
181 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
182 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
183 wc.hbrBackground = NULL;
184 wc.lpszMenuName = NULL;
185 wc.lpszClassName = DUMMY_CLASS;
186
187 if(!RegisterClass(&wc)) {
188 return 0;
189 }
190
191 DWORD style, exStyle;
192 exStyle = WS_EX_CLIENTEDGE;
193 style = WS_SYSMENU;
194
195 AdjustWindowRectEx(&windowRect, style, false, exStyle);
196 if(!(dummy = CreateWindowEx(exStyle,
197 DUMMY_CLASS,
198 STR_LIT("DummyWindow"),
199 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
200 0, 0,
201 windowRect.right-windowRect.left,
202 windowRect.bottom-windowRect.top,
203 NULL, NULL,
204 module,
205 NULL))) {
206 UnregisterClass(DUMMY_CLASS, module);
207 return NULL;
208 }
209 ShowWindow(dummy, SW_HIDE);
210
211 return dummy;
212}
213
214void destroy_dummy_window(HWND dummy) {
215 DestroyWindow(dummy);
216 HMODULE module = GetModuleHandle(NULL);
217 UnregisterClass(DUMMY_CLASS, module);
218}
219}
220
221#define GET_PROC(NAME, SUFFIX) f##NAME = \
222 (##NAME##Proc) wglGetProcAddress("wgl" #NAME #SUFFIX)
223
224SkWGLExtensions::SkWGLExtensions()
225 : fGetExtensionsString(NULL)
226 , fChoosePixelFormat(NULL)
227 , fGetPixelFormatAttribfv(NULL)
228 , fGetPixelFormatAttribiv(NULL)
229 , fCreateContextAttribs(NULL) {
230 HDC prevDC = wglGetCurrentDC();
231 HGLRC prevGLRC = wglGetCurrentContext();
232
233 PIXELFORMATDESCRIPTOR dummyPFD;
234
235 ZeroMemory(&dummyPFD, sizeof(dummyPFD));
236 dummyPFD.nSize = sizeof(dummyPFD);
237 dummyPFD.nVersion = 1;
238 dummyPFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
239 dummyPFD.iPixelType = PFD_TYPE_RGBA;
240 dummyPFD.cColorBits = 32;
241 dummyPFD.cDepthBits = 0;
242 dummyPFD.cStencilBits = 8;
243 dummyPFD.iLayerType = PFD_MAIN_PLANE;
244 HWND dummyWND = create_dummy_window();
245 if (dummyWND) {
246 HDC dummyDC = GetDC(dummyWND);
247 int dummyFormat = ChoosePixelFormat(dummyDC, &dummyPFD);
248 SetPixelFormat(dummyDC, dummyFormat, &dummyPFD);
249 HGLRC dummyGLRC = wglCreateContext(dummyDC);
250 SkASSERT(dummyGLRC);
251 wglMakeCurrent(dummyDC, dummyGLRC);
252
253 GET_PROC(GetExtensionsString, ARB);
254 GET_PROC(ChoosePixelFormat, ARB);
255 GET_PROC(GetPixelFormatAttribiv, ARB);
256 GET_PROC(GetPixelFormatAttribfv, ARB);
257 GET_PROC(CreateContextAttribs, ARB);
258
259 wglMakeCurrent(dummyDC, NULL);
260 wglDeleteContext(dummyGLRC);
261 destroy_dummy_window(dummyWND);
262 }
263
264 wglMakeCurrent(prevDC, prevGLRC);
265}
bsalomon@google.comb7f20f22013-03-05 19:13:09 +0000266
267HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool preferCoreProfile) {
268 SkWGLExtensions extensions;
269 if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) {
270 return NULL;
271 }
272
273 HDC prevDC = wglGetCurrentDC();
274 HGLRC prevGLRC = wglGetCurrentContext();
275 PIXELFORMATDESCRIPTOR pfd;
276
277 int format = 0;
278
279 static const int iAttrs[] = {
280 SK_WGL_DRAW_TO_WINDOW, TRUE,
281 SK_WGL_DOUBLE_BUFFER, TRUE,
282 SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION,
283 SK_WGL_SUPPORT_OPENGL, TRUE,
284 SK_WGL_COLOR_BITS, 24,
285 SK_WGL_ALPHA_BITS, 8,
286 SK_WGL_STENCIL_BITS, 8,
287 0, 0
288 };
289
290 float fAttrs[] = {0, 0};
291
292 if (msaaSampleCount > 0 &&
293 extensions.hasExtension(dc, "WGL_ARB_multisample")) {
294 static const int kIAttrsCount = SK_ARRAY_COUNT(iAttrs);
295 int msaaIAttrs[kIAttrsCount + 6];
296 memcpy(msaaIAttrs, iAttrs, sizeof(int) * kIAttrsCount);
297 SkASSERT(0 == msaaIAttrs[kIAttrsCount - 2] &&
298 0 == msaaIAttrs[kIAttrsCount - 1]);
299 msaaIAttrs[kIAttrsCount - 2] = SK_WGL_SAMPLE_BUFFERS;
300 msaaIAttrs[kIAttrsCount - 1] = TRUE;
301 msaaIAttrs[kIAttrsCount + 0] = SK_WGL_SAMPLES;
302 msaaIAttrs[kIAttrsCount + 1] = msaaSampleCount;
303 if (extensions.hasExtension(dc, "WGL_NV_multisample_coverage")) {
304 msaaIAttrs[kIAttrsCount + 2] = SK_WGL_COLOR_SAMPLES;
305 // We want the fewest number of color samples possible.
306 // Passing 0 gives only the formats where all samples are color
307 // samples.
308 msaaIAttrs[kIAttrsCount + 3] = 1;
309 msaaIAttrs[kIAttrsCount + 4] = 0;
310 msaaIAttrs[kIAttrsCount + 5] = 0;
311 } else {
312 msaaIAttrs[kIAttrsCount + 2] = 0;
313 msaaIAttrs[kIAttrsCount + 3] = 0;
314 }
315 unsigned int num;
316 int formats[64];
317 extensions.choosePixelFormat(dc, msaaIAttrs, fAttrs, 64, formats, &num);
318 num = min(num,64);
319 int formatToTry = extensions.selectFormat(formats,
320 num,
321 dc,
322 msaaSampleCount);
323 DescribePixelFormat(dc, formatToTry, sizeof(pfd), &pfd);
324 if (SetPixelFormat(dc, formatToTry, &pfd)) {
325 format = formatToTry;
326 }
327 }
328
329 if (0 == format) {
330 // Either MSAA wasn't requested or creation failed
331 unsigned int num;
332 extensions.choosePixelFormat(dc, iAttrs, fAttrs, 1, &format, &num);
333 DescribePixelFormat(dc, format, sizeof(pfd), &pfd);
bsalomon@google.comb58a6392013-03-21 20:29:05 +0000334 SkDEBUGCODE(BOOL set =) SetPixelFormat(dc, format, &pfd);
bsalomon@google.comb7f20f22013-03-05 19:13:09 +0000335 SkASSERT(TRUE == set);
336 }
337
338 HGLRC glrc = NULL;
339 if (preferCoreProfile && extensions.hasExtension(dc, "WGL_ARB_create_context")) {
340 static const int kCoreGLVersions[] = {
341 4, 3,
342 4, 2,
343 4, 1,
344 4, 0,
345 3, 3,
346 3, 2,
347 };
348 int coreProfileAttribs[] = {
349 SK_WGL_CONTEXT_MAJOR_VERSION, -1,
350 SK_WGL_CONTEXT_MINOR_VERSION, -1,
351 SK_WGL_CONTEXT_PROFILE_MASK, SK_WGL_CONTEXT_CORE_PROFILE_BIT,
352 0,
353 };
354 for (int v = 0; v < SK_ARRAY_COUNT(kCoreGLVersions) / 2; ++v) {
355 coreProfileAttribs[1] = kCoreGLVersions[2 * v];
356 coreProfileAttribs[3] = kCoreGLVersions[2 * v + 1];
357 glrc = extensions.createContextAttribs(dc, NULL, coreProfileAttribs);
358 if (NULL != glrc) {
359 break;
360 }
361 }
362 }
363
364 if (NULL == glrc) {
365 glrc = wglCreateContext(dc);
366 }
367 SkASSERT(glrc);
368
369 wglMakeCurrent(prevDC, prevGLRC);
370 return glrc;
371}