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 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 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 fCoverageSamples; 83 int fColorSamples; 84 int fChoosePixelFormatRank; 85 }; 86 87 bool 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; 98 } 99 return false; 100 } 101 } 102 103 int 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, 120 // Keep COLOR_SAMPLES at the end so it can be skipped 121 SK_WGL_COLOR_SAMPLES, 122 }; 123 int answers[2]; 124 int queryAttrCnt = supportsCoverage ? 125 SK_ARRAY_COUNT(queryAttrs) : 126 SK_ARRAY_COUNT(queryAttrs) - 1; 127 this->getPixelFormatAttribiv(dc, 128 formats[i], 129 0, 130 queryAttrCnt, 131 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 } 138 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)); 145 if (idx < 0) { 146 idx = ~idx; 147 } 148 return rankedFormats[idx].fFormat; 149 } 150 151 152 namespace { 153 154 #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 162 HWND 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 211 void 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 221 SkWGLExtensions::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 } 263 264 HGLRC 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); 315 num = SkTMin(num, 64U); 316 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); 331 SkDEBUGCODE(BOOL set =) SetPixelFormat(dc, format, &pfd); 332 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 } 369