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