• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
hasExtension(HDC dc,const char * ext) const15 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 
getExtensionsString(HDC hdc) const39 const char* SkWGLExtensions::getExtensionsString(HDC hdc) const {
40     return fGetExtensionsString(hdc);
41 }
42 
choosePixelFormat(HDC hdc,const int * piAttribIList,const FLOAT * pfAttribFList,UINT nMaxFormats,int * piFormats,UINT * nNumFormats) const43 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 
getPixelFormatAttribiv(HDC hdc,int iPixelFormat,int iLayerPlane,UINT nAttributes,const int * piAttributes,int * piValues) const53 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 
getPixelFormatAttribfv(HDC hdc,int iPixelFormat,int iLayerPlane,UINT nAttributes,const int * piAttributes,float * pfValues) const63 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 }
createContextAttribs(HDC hDC,HGLRC hShareContext,const int * attribList) const72 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 
pf_less(const PixelFormat & a,const PixelFormat & b)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 
selectFormat(const int formats[],int formatCount,HDC dc,int desiredSampleCount)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 
create_dummy_window()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 
destroy_dummy_window(HWND dummy)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 
SkWGLExtensions()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 
SkCreateWGLContext(HDC dc,int msaaSampleCount,bool preferCoreProfile)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 }
343