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 } 343