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 BOOL SkWGLExtensions::swapInterval(int interval) const { 79 return fSwapInterval(interval); 80 } 81 82 HPBUFFER SkWGLExtensions::createPbuffer(HDC hDC, 83 int iPixelFormat, 84 int iWidth, 85 int iHeight, 86 const int *piAttribList) const { 87 return fCreatePbuffer(hDC, iPixelFormat, iWidth, iHeight, piAttribList); 88 } 89 90 HDC SkWGLExtensions::getPbufferDC(HPBUFFER hPbuffer) const { 91 return fGetPbufferDC(hPbuffer); 92 } 93 94 int SkWGLExtensions::releasePbufferDC(HPBUFFER hPbuffer, HDC hDC) const { 95 return fReleasePbufferDC(hPbuffer, hDC); 96 } 97 98 BOOL SkWGLExtensions::destroyPbuffer(HPBUFFER hPbuffer) const { 99 return fDestroyPbuffer(hPbuffer); 100 } 101 102 namespace { 103 104 struct PixelFormat { 105 int fFormat; 106 int fSampleCnt; 107 int fChoosePixelFormatRank; 108 }; 109 110 bool pf_less(const PixelFormat& a, const PixelFormat& b) { 111 if (a.fSampleCnt < b.fSampleCnt) { 112 return true; 113 } else if (b.fSampleCnt < a.fSampleCnt) { 114 return false; 115 } else if (a.fChoosePixelFormatRank < b.fChoosePixelFormatRank) { 116 return true; 117 } 118 return false; 119 } 120 } 121 122 int SkWGLExtensions::selectFormat(const int formats[], 123 int formatCount, 124 HDC dc, 125 int desiredSampleCount) const { 126 PixelFormat desiredFormat = { 127 0, 128 desiredSampleCount, 129 0, 130 }; 131 SkTDArray<PixelFormat> rankedFormats; 132 rankedFormats.setCount(formatCount); 133 for (int i = 0; i < formatCount; ++i) { 134 static const int kQueryAttr = SK_WGL_SAMPLES; 135 int numSamples; 136 this->getPixelFormatAttribiv(dc, 137 formats[i], 138 0, 139 1, 140 &kQueryAttr, 141 &numSamples); 142 rankedFormats[i].fFormat = formats[i]; 143 rankedFormats[i].fSampleCnt = numSamples; 144 rankedFormats[i].fChoosePixelFormatRank = i; 145 } 146 SkTQSort(rankedFormats.begin(), 147 rankedFormats.begin() + rankedFormats.count() - 1, 148 SkTLessFunctionToFunctorAdaptor<PixelFormat, pf_less>()); 149 int idx = SkTSearch<PixelFormat, pf_less>(rankedFormats.begin(), 150 rankedFormats.count(), 151 desiredFormat, 152 sizeof(PixelFormat)); 153 if (idx < 0) { 154 idx = ~idx; 155 } 156 return rankedFormats[idx].fFormat; 157 } 158 159 160 namespace { 161 162 #if defined(UNICODE) 163 #define STR_LIT(X) L## #X 164 #else 165 #define STR_LIT(X) #X 166 #endif 167 168 #define DUMMY_CLASS STR_LIT("DummyClass") 169 170 HWND create_dummy_window() { 171 HMODULE module = GetModuleHandle(NULL); 172 HWND dummy; 173 RECT windowRect; 174 windowRect.left = 0; 175 windowRect.right = 8; 176 windowRect.top = 0; 177 windowRect.bottom = 8; 178 179 WNDCLASS wc; 180 181 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; 182 wc.lpfnWndProc = (WNDPROC) DefWindowProc; 183 wc.cbClsExtra = 0; 184 wc.cbWndExtra = 0; 185 wc.hInstance = module; 186 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); 187 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 188 wc.hbrBackground = NULL; 189 wc.lpszMenuName = NULL; 190 wc.lpszClassName = DUMMY_CLASS; 191 192 if(!RegisterClass(&wc)) { 193 return 0; 194 } 195 196 DWORD style, exStyle; 197 exStyle = WS_EX_CLIENTEDGE; 198 style = WS_SYSMENU; 199 200 AdjustWindowRectEx(&windowRect, style, false, exStyle); 201 if(!(dummy = CreateWindowEx(exStyle, 202 DUMMY_CLASS, 203 STR_LIT("DummyWindow"), 204 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style, 205 0, 0, 206 windowRect.right-windowRect.left, 207 windowRect.bottom-windowRect.top, 208 NULL, NULL, 209 module, 210 NULL))) { 211 UnregisterClass(DUMMY_CLASS, module); 212 return NULL; 213 } 214 ShowWindow(dummy, SW_HIDE); 215 216 return dummy; 217 } 218 219 void destroy_dummy_window(HWND dummy) { 220 DestroyWindow(dummy); 221 HMODULE module = GetModuleHandle(NULL); 222 UnregisterClass(DUMMY_CLASS, module); 223 } 224 } 225 226 #define GET_PROC(NAME, SUFFIX) f##NAME = \ 227 (##NAME##Proc) wglGetProcAddress("wgl" #NAME #SUFFIX) 228 229 SkWGLExtensions::SkWGLExtensions() 230 : fGetExtensionsString(NULL) 231 , fChoosePixelFormat(NULL) 232 , fGetPixelFormatAttribfv(NULL) 233 , fGetPixelFormatAttribiv(NULL) 234 , fCreateContextAttribs(NULL) 235 , fSwapInterval(NULL) 236 , fCreatePbuffer(NULL) 237 , fGetPbufferDC(NULL) 238 , fReleasePbufferDC(NULL) 239 , fDestroyPbuffer(NULL) 240 { 241 HDC prevDC = wglGetCurrentDC(); 242 HGLRC prevGLRC = wglGetCurrentContext(); 243 244 PIXELFORMATDESCRIPTOR dummyPFD; 245 246 ZeroMemory(&dummyPFD, sizeof(dummyPFD)); 247 dummyPFD.nSize = sizeof(dummyPFD); 248 dummyPFD.nVersion = 1; 249 dummyPFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; 250 dummyPFD.iPixelType = PFD_TYPE_RGBA; 251 dummyPFD.cColorBits = 32; 252 dummyPFD.cDepthBits = 0; 253 dummyPFD.cStencilBits = 8; 254 dummyPFD.iLayerType = PFD_MAIN_PLANE; 255 HWND dummyWND = create_dummy_window(); 256 if (dummyWND) { 257 HDC dummyDC = GetDC(dummyWND); 258 int dummyFormat = ChoosePixelFormat(dummyDC, &dummyPFD); 259 SetPixelFormat(dummyDC, dummyFormat, &dummyPFD); 260 HGLRC dummyGLRC = wglCreateContext(dummyDC); 261 SkASSERT(dummyGLRC); 262 wglMakeCurrent(dummyDC, dummyGLRC); 263 264 GET_PROC(GetExtensionsString, ARB); 265 GET_PROC(ChoosePixelFormat, ARB); 266 GET_PROC(GetPixelFormatAttribiv, ARB); 267 GET_PROC(GetPixelFormatAttribfv, ARB); 268 GET_PROC(CreateContextAttribs, ARB); 269 GET_PROC(SwapInterval, EXT); 270 GET_PROC(CreatePbuffer, ARB); 271 GET_PROC(GetPbufferDC, ARB); 272 GET_PROC(ReleasePbufferDC, ARB); 273 GET_PROC(DestroyPbuffer, ARB); 274 275 wglMakeCurrent(dummyDC, NULL); 276 wglDeleteContext(dummyGLRC); 277 destroy_dummy_window(dummyWND); 278 } 279 280 wglMakeCurrent(prevDC, prevGLRC); 281 } 282 283 /////////////////////////////////////////////////////////////////////////////// 284 285 static void get_pixel_formats_to_try(HDC dc, const SkWGLExtensions& extensions, 286 bool doubleBuffered, int msaaSampleCount, 287 int formatsToTry[2]) { 288 int iAttrs[] = { 289 SK_WGL_DRAW_TO_WINDOW, TRUE, 290 SK_WGL_DOUBLE_BUFFER, (doubleBuffered ? TRUE : FALSE), 291 SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION, 292 SK_WGL_SUPPORT_OPENGL, TRUE, 293 SK_WGL_COLOR_BITS, 24, 294 SK_WGL_ALPHA_BITS, 8, 295 SK_WGL_STENCIL_BITS, 8, 296 0, 0 297 }; 298 299 float fAttrs[] = {0, 0}; 300 301 // Get a MSAA format if requested and possible. 302 if (msaaSampleCount > 0 && 303 extensions.hasExtension(dc, "WGL_ARB_multisample")) { 304 static const int kIAttrsCount = SK_ARRAY_COUNT(iAttrs); 305 int msaaIAttrs[kIAttrsCount + 4]; 306 memcpy(msaaIAttrs, iAttrs, sizeof(int) * kIAttrsCount); 307 SkASSERT(0 == msaaIAttrs[kIAttrsCount - 2] && 308 0 == msaaIAttrs[kIAttrsCount - 1]); 309 msaaIAttrs[kIAttrsCount - 2] = SK_WGL_SAMPLE_BUFFERS; 310 msaaIAttrs[kIAttrsCount - 1] = TRUE; 311 msaaIAttrs[kIAttrsCount + 0] = SK_WGL_SAMPLES; 312 msaaIAttrs[kIAttrsCount + 1] = msaaSampleCount; 313 msaaIAttrs[kIAttrsCount + 2] = 0; 314 msaaIAttrs[kIAttrsCount + 3] = 0; 315 unsigned int num; 316 int formats[64]; 317 extensions.choosePixelFormat(dc, msaaIAttrs, fAttrs, 64, formats, &num); 318 num = SkTMin(num, 64U); 319 formatsToTry[0] = extensions.selectFormat(formats, num, dc, msaaSampleCount); 320 } 321 322 // Get a non-MSAA format 323 int* format = -1 == formatsToTry[0] ? &formatsToTry[0] : &formatsToTry[1]; 324 unsigned int num; 325 extensions.choosePixelFormat(dc, iAttrs, fAttrs, 1, format, &num); 326 } 327 328 static HGLRC create_gl_context(HDC dc, SkWGLExtensions extensions, SkWGLContextRequest contextType) { 329 HDC prevDC = wglGetCurrentDC(); 330 HGLRC prevGLRC = wglGetCurrentContext(); 331 332 HGLRC glrc = NULL; 333 if (kGLES_SkWGLContextRequest == contextType) { 334 if (!extensions.hasExtension(dc, "WGL_EXT_create_context_es2_profile")) { 335 wglMakeCurrent(prevDC, prevGLRC); 336 return NULL; 337 } 338 static const int glesAttribs[] = { 339 SK_WGL_CONTEXT_MAJOR_VERSION, 3, 340 SK_WGL_CONTEXT_MINOR_VERSION, 0, 341 SK_WGL_CONTEXT_PROFILE_MASK, SK_WGL_CONTEXT_ES2_PROFILE_BIT, 342 0, 343 }; 344 glrc = extensions.createContextAttribs(dc, NULL, glesAttribs); 345 if (NULL == glrc) { 346 wglMakeCurrent(prevDC, prevGLRC); 347 return NULL; 348 } 349 } else { 350 if (kGLPreferCoreProfile_SkWGLContextRequest == contextType && 351 extensions.hasExtension(dc, "WGL_ARB_create_context")) { 352 static const int kCoreGLVersions[] = { 353 4, 3, 354 4, 2, 355 4, 1, 356 4, 0, 357 3, 3, 358 3, 2, 359 }; 360 int coreProfileAttribs[] = { 361 SK_WGL_CONTEXT_MAJOR_VERSION, -1, 362 SK_WGL_CONTEXT_MINOR_VERSION, -1, 363 SK_WGL_CONTEXT_PROFILE_MASK, SK_WGL_CONTEXT_CORE_PROFILE_BIT, 364 0, 365 }; 366 for (int v = 0; v < SK_ARRAY_COUNT(kCoreGLVersions) / 2; ++v) { 367 coreProfileAttribs[1] = kCoreGLVersions[2 * v]; 368 coreProfileAttribs[3] = kCoreGLVersions[2 * v + 1]; 369 glrc = extensions.createContextAttribs(dc, NULL, coreProfileAttribs); 370 if (glrc) { 371 break; 372 } 373 } 374 } 375 } 376 377 if (NULL == glrc) { 378 glrc = wglCreateContext(dc); 379 } 380 SkASSERT(glrc); 381 382 wglMakeCurrent(prevDC, prevGLRC); 383 384 // This might help make the context non-vsynced. 385 if (extensions.hasExtension(dc, "WGL_EXT_swap_control")) { 386 extensions.swapInterval(-1); 387 } 388 return glrc; 389 } 390 391 HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, SkWGLContextRequest contextType) { 392 SkWGLExtensions extensions; 393 if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) { 394 return NULL; 395 } 396 397 BOOL set = FALSE; 398 399 int pixelFormatsToTry[] = { -1, -1 }; 400 get_pixel_formats_to_try(dc, extensions, true, msaaSampleCount, pixelFormatsToTry); 401 for (int f = 0; 402 !set && -1 != pixelFormatsToTry[f] && f < SK_ARRAY_COUNT(pixelFormatsToTry); 403 ++f) { 404 PIXELFORMATDESCRIPTOR pfd; 405 DescribePixelFormat(dc, pixelFormatsToTry[f], sizeof(pfd), &pfd); 406 set = SetPixelFormat(dc, pixelFormatsToTry[f], &pfd); 407 } 408 409 if (!set) { 410 return NULL; 411 } 412 413 return create_gl_context(dc, extensions, contextType);} 414 415 SkWGLPbufferContext* SkWGLPbufferContext::Create(HDC parentDC, int msaaSampleCount, 416 SkWGLContextRequest contextType) { 417 SkWGLExtensions extensions; 418 if (!extensions.hasExtension(parentDC, "WGL_ARB_pixel_format") || 419 !extensions.hasExtension(parentDC, "WGL_ARB_pbuffer")) { 420 return NULL; 421 } 422 423 // try for single buffer first 424 for (int dblBuffer = 0; dblBuffer < 2; ++dblBuffer) { 425 int pixelFormatsToTry[] = { -1, -1 }; 426 get_pixel_formats_to_try(parentDC, extensions, (0 != dblBuffer), msaaSampleCount, 427 pixelFormatsToTry); 428 for (int f = 0; -1 != pixelFormatsToTry[f] && f < SK_ARRAY_COUNT(pixelFormatsToTry); ++f) { 429 HPBUFFER pbuf = extensions.createPbuffer(parentDC, pixelFormatsToTry[f], 1, 1, NULL); 430 if (0 != pbuf) { 431 HDC dc = extensions.getPbufferDC(pbuf); 432 if (dc) { 433 HGLRC glrc = create_gl_context(dc, extensions, contextType); 434 if (glrc) { 435 return SkNEW_ARGS(SkWGLPbufferContext, (pbuf, dc, glrc)); 436 } 437 extensions.releasePbufferDC(pbuf, dc); 438 } 439 extensions.destroyPbuffer(pbuf); 440 } 441 } 442 } 443 return NULL; 444 } 445 446 SkWGLPbufferContext::~SkWGLPbufferContext() { 447 SkASSERT(fExtensions.hasExtension(fDC, "WGL_ARB_pbuffer")); 448 wglDeleteContext(fGLRC); 449 fExtensions.releasePbufferDC(fPbuffer, fDC); 450 fExtensions.destroyPbuffer(fPbuffer); 451 } 452 453 SkWGLPbufferContext::SkWGLPbufferContext(HPBUFFER pbuffer, HDC dc, HGLRC glrc) 454 : fPbuffer(pbuffer) 455 , fDC(dc) 456 , fGLRC(glrc) { 457 } 458