blob: 3b1966dae8fbcd352229440c6d5c2582cb234046 [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);
robertphillips@google.comadacc702013-10-14 21:53:24 +000023 size_t extLength = strlen(ext);
bsalomon@google.combd7c6412011-12-01 16:34:28 +000024
25 while (true) {
robertphillips@google.comadacc702013-10-14 21:53:24 +000026 size_t n = strcspn(extensionString, " ");
bsalomon@google.combd7c6412011-12-01 16:34:28 +000027 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;
commit-bot@chromium.org040fd8f2013-09-06 20:00:41 +000082 int fSampleCnt;
bsalomon@google.com8a189b02012-04-17 12:43:00 +000083 int fChoosePixelFormatRank;
84};
85
bsalomon@google.com20f7f172013-05-17 19:05:03 +000086bool pf_less(const PixelFormat& a, const PixelFormat& b) {
commit-bot@chromium.org040fd8f2013-09-06 20:00:41 +000087 if (a.fSampleCnt < b.fSampleCnt) {
bsalomon@google.com20f7f172013-05-17 19:05:03 +000088 return true;
commit-bot@chromium.org040fd8f2013-09-06 20:00:41 +000089 } else if (b.fSampleCnt < a.fSampleCnt) {
bsalomon@google.com20f7f172013-05-17 19:05:03 +000090 return false;
91 } else if (a.fChoosePixelFormatRank < b.fChoosePixelFormatRank) {
92 return true;
bsalomon@google.com8a189b02012-04-17 12:43:00 +000093 }
bsalomon@google.com20f7f172013-05-17 19:05:03 +000094 return false;
bsalomon@google.com8a189b02012-04-17 12:43:00 +000095}
96}
97
98int SkWGLExtensions::selectFormat(const int formats[],
99 int formatCount,
100 HDC dc,
101 int desiredSampleCount) {
102 PixelFormat desiredFormat = {
103 0,
104 desiredSampleCount,
105 0,
bsalomon@google.com8a189b02012-04-17 12:43:00 +0000106 };
107 SkTDArray<PixelFormat> rankedFormats;
108 rankedFormats.setCount(formatCount);
bsalomon@google.com8a189b02012-04-17 12:43:00 +0000109 for (int i = 0; i < formatCount; ++i) {
commit-bot@chromium.org040fd8f2013-09-06 20:00:41 +0000110 static const int kQueryAttr = SK_WGL_SAMPLES;
111 int numSamples;
bsalomon@google.com8a189b02012-04-17 12:43:00 +0000112 this->getPixelFormatAttribiv(dc,
113 formats[i],
114 0,
commit-bot@chromium.org040fd8f2013-09-06 20:00:41 +0000115 1,
116 &kQueryAttr,
117 &numSamples);
bsalomon@google.com8a189b02012-04-17 12:43:00 +0000118 rankedFormats[i].fFormat = formats[i];
commit-bot@chromium.org040fd8f2013-09-06 20:00:41 +0000119 rankedFormats[i].fSampleCnt = numSamples;
bsalomon@google.com8a189b02012-04-17 12:43:00 +0000120 rankedFormats[i].fChoosePixelFormatRank = i;
121 }
bsalomon@google.com20f7f172013-05-17 19:05:03 +0000122 SkTQSort(rankedFormats.begin(),
123 rankedFormats.begin() + rankedFormats.count() - 1,
124 SkTLessFunctionToFunctorAdaptor<PixelFormat, pf_less>());
125 int idx = SkTSearch<PixelFormat, pf_less>(rankedFormats.begin(),
126 rankedFormats.count(),
127 desiredFormat,
128 sizeof(PixelFormat));
bsalomon@google.com8a189b02012-04-17 12:43:00 +0000129 if (idx < 0) {
130 idx = ~idx;
131 }
132 return rankedFormats[idx].fFormat;
133}
134
135
136namespace {
137
bsalomon@google.combd7c6412011-12-01 16:34:28 +0000138#if defined(UNICODE)
139 #define STR_LIT(X) L## #X
140#else
141 #define STR_LIT(X) #X
142#endif
143
144#define DUMMY_CLASS STR_LIT("DummyClass")
145
146HWND create_dummy_window() {
147 HMODULE module = GetModuleHandle(NULL);
148 HWND dummy;
149 RECT windowRect;
150 windowRect.left = 0;
151 windowRect.right = 8;
152 windowRect.top = 0;
153 windowRect.bottom = 8;
154
155 WNDCLASS wc;
156
157 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
158 wc.lpfnWndProc = (WNDPROC) DefWindowProc;
159 wc.cbClsExtra = 0;
160 wc.cbWndExtra = 0;
161 wc.hInstance = module;
162 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
163 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
164 wc.hbrBackground = NULL;
165 wc.lpszMenuName = NULL;
166 wc.lpszClassName = DUMMY_CLASS;
167
168 if(!RegisterClass(&wc)) {
169 return 0;
170 }
171
172 DWORD style, exStyle;
173 exStyle = WS_EX_CLIENTEDGE;
174 style = WS_SYSMENU;
175
176 AdjustWindowRectEx(&windowRect, style, false, exStyle);
177 if(!(dummy = CreateWindowEx(exStyle,
178 DUMMY_CLASS,
179 STR_LIT("DummyWindow"),
180 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
181 0, 0,
182 windowRect.right-windowRect.left,
183 windowRect.bottom-windowRect.top,
184 NULL, NULL,
185 module,
186 NULL))) {
187 UnregisterClass(DUMMY_CLASS, module);
188 return NULL;
189 }
190 ShowWindow(dummy, SW_HIDE);
191
192 return dummy;
193}
194
195void destroy_dummy_window(HWND dummy) {
196 DestroyWindow(dummy);
197 HMODULE module = GetModuleHandle(NULL);
198 UnregisterClass(DUMMY_CLASS, module);
199}
200}
201
202#define GET_PROC(NAME, SUFFIX) f##NAME = \
203 (##NAME##Proc) wglGetProcAddress("wgl" #NAME #SUFFIX)
204
205SkWGLExtensions::SkWGLExtensions()
206 : fGetExtensionsString(NULL)
207 , fChoosePixelFormat(NULL)
208 , fGetPixelFormatAttribfv(NULL)
209 , fGetPixelFormatAttribiv(NULL)
210 , fCreateContextAttribs(NULL) {
211 HDC prevDC = wglGetCurrentDC();
212 HGLRC prevGLRC = wglGetCurrentContext();
213
214 PIXELFORMATDESCRIPTOR dummyPFD;
215
216 ZeroMemory(&dummyPFD, sizeof(dummyPFD));
217 dummyPFD.nSize = sizeof(dummyPFD);
218 dummyPFD.nVersion = 1;
219 dummyPFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
220 dummyPFD.iPixelType = PFD_TYPE_RGBA;
221 dummyPFD.cColorBits = 32;
222 dummyPFD.cDepthBits = 0;
223 dummyPFD.cStencilBits = 8;
224 dummyPFD.iLayerType = PFD_MAIN_PLANE;
225 HWND dummyWND = create_dummy_window();
226 if (dummyWND) {
227 HDC dummyDC = GetDC(dummyWND);
228 int dummyFormat = ChoosePixelFormat(dummyDC, &dummyPFD);
229 SetPixelFormat(dummyDC, dummyFormat, &dummyPFD);
230 HGLRC dummyGLRC = wglCreateContext(dummyDC);
231 SkASSERT(dummyGLRC);
232 wglMakeCurrent(dummyDC, dummyGLRC);
233
234 GET_PROC(GetExtensionsString, ARB);
235 GET_PROC(ChoosePixelFormat, ARB);
236 GET_PROC(GetPixelFormatAttribiv, ARB);
237 GET_PROC(GetPixelFormatAttribfv, ARB);
238 GET_PROC(CreateContextAttribs, ARB);
239
240 wglMakeCurrent(dummyDC, NULL);
241 wglDeleteContext(dummyGLRC);
242 destroy_dummy_window(dummyWND);
243 }
244
245 wglMakeCurrent(prevDC, prevGLRC);
246}
bsalomon@google.comb7f20f22013-03-05 19:13:09 +0000247
248HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool preferCoreProfile) {
249 SkWGLExtensions extensions;
250 if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) {
251 return NULL;
252 }
253
254 HDC prevDC = wglGetCurrentDC();
255 HGLRC prevGLRC = wglGetCurrentContext();
256 PIXELFORMATDESCRIPTOR pfd;
257
258 int format = 0;
259
260 static const int iAttrs[] = {
261 SK_WGL_DRAW_TO_WINDOW, TRUE,
262 SK_WGL_DOUBLE_BUFFER, TRUE,
263 SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION,
264 SK_WGL_SUPPORT_OPENGL, TRUE,
265 SK_WGL_COLOR_BITS, 24,
266 SK_WGL_ALPHA_BITS, 8,
267 SK_WGL_STENCIL_BITS, 8,
268 0, 0
269 };
270
271 float fAttrs[] = {0, 0};
272
273 if (msaaSampleCount > 0 &&
274 extensions.hasExtension(dc, "WGL_ARB_multisample")) {
275 static const int kIAttrsCount = SK_ARRAY_COUNT(iAttrs);
commit-bot@chromium.org040fd8f2013-09-06 20:00:41 +0000276 int msaaIAttrs[kIAttrsCount + 4];
bsalomon@google.comb7f20f22013-03-05 19:13:09 +0000277 memcpy(msaaIAttrs, iAttrs, sizeof(int) * kIAttrsCount);
278 SkASSERT(0 == msaaIAttrs[kIAttrsCount - 2] &&
279 0 == msaaIAttrs[kIAttrsCount - 1]);
280 msaaIAttrs[kIAttrsCount - 2] = SK_WGL_SAMPLE_BUFFERS;
281 msaaIAttrs[kIAttrsCount - 1] = TRUE;
282 msaaIAttrs[kIAttrsCount + 0] = SK_WGL_SAMPLES;
283 msaaIAttrs[kIAttrsCount + 1] = msaaSampleCount;
commit-bot@chromium.org040fd8f2013-09-06 20:00:41 +0000284 msaaIAttrs[kIAttrsCount + 2] = 0;
285 msaaIAttrs[kIAttrsCount + 3] = 0;
bsalomon@google.comb7f20f22013-03-05 19:13:09 +0000286 unsigned int num;
287 int formats[64];
288 extensions.choosePixelFormat(dc, msaaIAttrs, fAttrs, 64, formats, &num);
bsalomon@google.comf3f2d162013-07-31 18:52:31 +0000289 num = SkTMin(num, 64U);
bsalomon@google.comb7f20f22013-03-05 19:13:09 +0000290 int formatToTry = extensions.selectFormat(formats,
291 num,
292 dc,
293 msaaSampleCount);
294 DescribePixelFormat(dc, formatToTry, sizeof(pfd), &pfd);
295 if (SetPixelFormat(dc, formatToTry, &pfd)) {
296 format = formatToTry;
297 }
298 }
299
300 if (0 == format) {
301 // Either MSAA wasn't requested or creation failed
302 unsigned int num;
303 extensions.choosePixelFormat(dc, iAttrs, fAttrs, 1, &format, &num);
304 DescribePixelFormat(dc, format, sizeof(pfd), &pfd);
bsalomon@google.comb58a6392013-03-21 20:29:05 +0000305 SkDEBUGCODE(BOOL set =) SetPixelFormat(dc, format, &pfd);
bsalomon@google.comb7f20f22013-03-05 19:13:09 +0000306 SkASSERT(TRUE == set);
307 }
308
309 HGLRC glrc = NULL;
310 if (preferCoreProfile && extensions.hasExtension(dc, "WGL_ARB_create_context")) {
311 static const int kCoreGLVersions[] = {
312 4, 3,
313 4, 2,
314 4, 1,
315 4, 0,
316 3, 3,
317 3, 2,
318 };
319 int coreProfileAttribs[] = {
320 SK_WGL_CONTEXT_MAJOR_VERSION, -1,
321 SK_WGL_CONTEXT_MINOR_VERSION, -1,
322 SK_WGL_CONTEXT_PROFILE_MASK, SK_WGL_CONTEXT_CORE_PROFILE_BIT,
323 0,
324 };
325 for (int v = 0; v < SK_ARRAY_COUNT(kCoreGLVersions) / 2; ++v) {
326 coreProfileAttribs[1] = kCoreGLVersions[2 * v];
327 coreProfileAttribs[3] = kCoreGLVersions[2 * v + 1];
328 glrc = extensions.createContextAttribs(dc, NULL, coreProfileAttribs);
329 if (NULL != glrc) {
330 break;
331 }
332 }
333 }
334
335 if (NULL == glrc) {
336 glrc = wglCreateContext(dc);
337 }
338 SkASSERT(glrc);
339
340 wglMakeCurrent(prevDC, prevGLRC);
341 return glrc;
342}