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