|
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 "SkWGL.h" |
|
10 |
|
11 #include "SkTDArray.h" |
|
12 #include "SkTSearch.h" |
|
13 #include "SkTSort.h" |
|
14 |
|
15 bool 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 size_t extLength = strlen(ext); |
|
24 |
|
25 while (true) { |
|
26 size_t 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 |
|
39 const char* SkWGLExtensions::getExtensionsString(HDC hdc) const { |
|
40 return fGetExtensionsString(hdc); |
|
41 } |
|
42 |
|
43 BOOL 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 |
|
53 BOOL 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 |
|
63 BOOL 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 } |
|
72 HGLRC SkWGLExtensions::createContextAttribs(HDC hDC, |
|
73 HGLRC hShareContext, |
|
74 const int *attribList) const { |
|
75 return fCreateContextAttribs(hDC, hShareContext, attribList); |
|
76 } |
|
77 |
|
78 namespace { |
|
79 |
|
80 struct PixelFormat { |
|
81 int fFormat; |
|
82 int fSampleCnt; |
|
83 int fChoosePixelFormatRank; |
|
84 }; |
|
85 |
|
86 bool pf_less(const PixelFormat& a, const PixelFormat& b) { |
|
87 if (a.fSampleCnt < b.fSampleCnt) { |
|
88 return true; |
|
89 } else if (b.fSampleCnt < a.fSampleCnt) { |
|
90 return false; |
|
91 } else if (a.fChoosePixelFormatRank < b.fChoosePixelFormatRank) { |
|
92 return true; |
|
93 } |
|
94 return false; |
|
95 } |
|
96 } |
|
97 |
|
98 int SkWGLExtensions::selectFormat(const int formats[], |
|
99 int formatCount, |
|
100 HDC dc, |
|
101 int desiredSampleCount) { |
|
102 PixelFormat desiredFormat = { |
|
103 0, |
|
104 desiredSampleCount, |
|
105 0, |
|
106 }; |
|
107 SkTDArray<PixelFormat> rankedFormats; |
|
108 rankedFormats.setCount(formatCount); |
|
109 for (int i = 0; i < formatCount; ++i) { |
|
110 static const int kQueryAttr = SK_WGL_SAMPLES; |
|
111 int numSamples; |
|
112 this->getPixelFormatAttribiv(dc, |
|
113 formats[i], |
|
114 0, |
|
115 1, |
|
116 &kQueryAttr, |
|
117 &numSamples); |
|
118 rankedFormats[i].fFormat = formats[i]; |
|
119 rankedFormats[i].fSampleCnt = numSamples; |
|
120 rankedFormats[i].fChoosePixelFormatRank = i; |
|
121 } |
|
122 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)); |
|
129 if (idx < 0) { |
|
130 idx = ~idx; |
|
131 } |
|
132 return rankedFormats[idx].fFormat; |
|
133 } |
|
134 |
|
135 |
|
136 namespace { |
|
137 |
|
138 #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 |
|
146 HWND 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 |
|
195 void 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 |
|
205 SkWGLExtensions::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 } |
|
247 |
|
248 HGLRC 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); |
|
276 int msaaIAttrs[kIAttrsCount + 4]; |
|
277 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; |
|
284 msaaIAttrs[kIAttrsCount + 2] = 0; |
|
285 msaaIAttrs[kIAttrsCount + 3] = 0; |
|
286 unsigned int num; |
|
287 int formats[64]; |
|
288 extensions.choosePixelFormat(dc, msaaIAttrs, fAttrs, 64, formats, &num); |
|
289 num = SkTMin(num, 64U); |
|
290 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); |
|
305 SkDEBUGCODE(BOOL set =) SetPixelFormat(dc, format, &pfd); |
|
306 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 } |