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 14 bool SkWGLExtensions::hasExtension(HDC dc, const char* ext) const { 15 if (NULL == this->fGetExtensionsString) { 16 return false; 17 } 18 if (!strcmp("WGL_ARB_extensions_string", ext)) { 19 return true; 20 } 21 const char* extensionString = this->getExtensionsString(dc); 22 int extLength = strlen(ext); 23 24 while (true) { 25 int n = strcspn(extensionString, " "); 26 if (n == extLength && 0 == strncmp(ext, extensionString, n)) { 27 return true; 28 } 29 if (0 == extensionString[n]) { 30 return false; 31 } 32 extensionString += n+1; 33 } 34 35 return false; 36 } 37 38 const char* SkWGLExtensions::getExtensionsString(HDC hdc) const { 39 return fGetExtensionsString(hdc); 40 } 41 42 BOOL SkWGLExtensions::choosePixelFormat(HDC hdc, 43 const int* piAttribIList, 44 const FLOAT* pfAttribFList, 45 UINT nMaxFormats, 46 int* piFormats, 47 UINT* nNumFormats) const { 48 return fChoosePixelFormat(hdc, piAttribIList, pfAttribFList, 49 nMaxFormats, piFormats, nNumFormats); 50 } 51 52 BOOL SkWGLExtensions::getPixelFormatAttribiv(HDC hdc, 53 int iPixelFormat, 54 int iLayerPlane, 55 UINT nAttributes, 56 const int *piAttributes, 57 int *piValues) const { 58 return fGetPixelFormatAttribiv(hdc, iPixelFormat, iLayerPlane, 59 nAttributes, piAttributes, piValues); 60 } 61 62 BOOL SkWGLExtensions::getPixelFormatAttribfv(HDC hdc, 63 int iPixelFormat, 64 int iLayerPlane, 65 UINT nAttributes, 66 const int *piAttributes, 67 float *pfValues) const { 68 return fGetPixelFormatAttribfv(hdc, iPixelFormat, iLayerPlane, 69 nAttributes, piAttributes, pfValues); 70 } 71 HGLRC SkWGLExtensions::createContextAttribs(HDC hDC, 72 HGLRC hShareContext, 73 const int *attribList) const { 74 return fCreateContextAttribs(hDC, hShareContext, attribList); 75 } 76 77 namespace { 78 79 struct PixelFormat { 80 int fFormat; 81 int fCoverageSamples; 82 int fColorSamples; 83 int fChoosePixelFormatRank; 84 }; 85 86 int compare_pf(const PixelFormat* a, const PixelFormat* b) { 87 if (a->fCoverageSamples < b->fCoverageSamples) { 88 return -1; 89 } else if (b->fCoverageSamples < a->fCoverageSamples) { 90 return 1; 91 } else if (a->fColorSamples < b->fColorSamples) { 92 return -1; 93 } else if (b->fColorSamples < a->fColorSamples) { 94 return 1; 95 } else if (a->fChoosePixelFormatRank < b->fChoosePixelFormatRank) { 96 return -1; 97 } else if (b->fChoosePixelFormatRank < a->fChoosePixelFormatRank) { 98 return 1; 99 } 100 return 0; 101 } 102 } 103 104 int SkWGLExtensions::selectFormat(const int formats[], 105 int formatCount, 106 HDC dc, 107 int desiredSampleCount) { 108 PixelFormat desiredFormat = { 109 0, 110 desiredSampleCount, 111 0, 112 0, 113 }; 114 SkTDArray<PixelFormat> rankedFormats; 115 rankedFormats.setCount(formatCount); 116 bool supportsCoverage = this->hasExtension(dc, 117 "WGL_NV_multisample_coverage"); 118 for (int i = 0; i < formatCount; ++i) { 119 static const int queryAttrs[] = { 120 SK_WGL_COVERAGE_SAMPLES, 121 // Keep COLOR_SAMPLES at the end so it can be skipped 122 SK_WGL_COLOR_SAMPLES, 123 }; 124 int answers[2]; 125 int queryAttrCnt = supportsCoverage ? 126 SK_ARRAY_COUNT(queryAttrs) : 127 SK_ARRAY_COUNT(queryAttrs) - 1; 128 this->getPixelFormatAttribiv(dc, 129 formats[i], 130 0, 131 queryAttrCnt, 132 queryAttrs, 133 answers); 134 rankedFormats[i].fFormat = formats[i]; 135 rankedFormats[i].fCoverageSamples = answers[0]; 136 rankedFormats[i].fColorSamples = answers[supportsCoverage ? 1 : 0]; 137 rankedFormats[i].fChoosePixelFormatRank = i; 138 } 139 qsort(rankedFormats.begin(), 140 rankedFormats.count(), 141 sizeof(PixelFormat), 142 SkCastForQSort(compare_pf)); 143 int idx = SkTSearch<PixelFormat>(rankedFormats.begin(), 144 rankedFormats.count(), 145 desiredFormat, 146 sizeof(PixelFormat), 147 compare_pf); 148 if (idx < 0) { 149 idx = ~idx; 150 } 151 return rankedFormats[idx].fFormat; 152 } 153 154 155 namespace { 156 157 #if defined(UNICODE) 158 #define STR_LIT(X) L## #X 159 #else 160 #define STR_LIT(X) #X 161 #endif 162 163 #define DUMMY_CLASS STR_LIT("DummyClass") 164 165 HWND create_dummy_window() { 166 HMODULE module = GetModuleHandle(NULL); 167 HWND dummy; 168 RECT windowRect; 169 windowRect.left = 0; 170 windowRect.right = 8; 171 windowRect.top = 0; 172 windowRect.bottom = 8; 173 174 WNDCLASS wc; 175 176 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; 177 wc.lpfnWndProc = (WNDPROC) DefWindowProc; 178 wc.cbClsExtra = 0; 179 wc.cbWndExtra = 0; 180 wc.hInstance = module; 181 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); 182 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 183 wc.hbrBackground = NULL; 184 wc.lpszMenuName = NULL; 185 wc.lpszClassName = DUMMY_CLASS; 186 187 if(!RegisterClass(&wc)) { 188 return 0; 189 } 190 191 DWORD style, exStyle; 192 exStyle = WS_EX_CLIENTEDGE; 193 style = WS_SYSMENU; 194 195 AdjustWindowRectEx(&windowRect, style, false, exStyle); 196 if(!(dummy = CreateWindowEx(exStyle, 197 DUMMY_CLASS, 198 STR_LIT("DummyWindow"), 199 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style, 200 0, 0, 201 windowRect.right-windowRect.left, 202 windowRect.bottom-windowRect.top, 203 NULL, NULL, 204 module, 205 NULL))) { 206 UnregisterClass(DUMMY_CLASS, module); 207 return NULL; 208 } 209 ShowWindow(dummy, SW_HIDE); 210 211 return dummy; 212 } 213 214 void destroy_dummy_window(HWND dummy) { 215 DestroyWindow(dummy); 216 HMODULE module = GetModuleHandle(NULL); 217 UnregisterClass(DUMMY_CLASS, module); 218 } 219 } 220 221 #define GET_PROC(NAME, SUFFIX) f##NAME = \ 222 (##NAME##Proc) wglGetProcAddress("wgl" #NAME #SUFFIX) 223 224 SkWGLExtensions::SkWGLExtensions() 225 : fGetExtensionsString(NULL) 226 , fChoosePixelFormat(NULL) 227 , fGetPixelFormatAttribfv(NULL) 228 , fGetPixelFormatAttribiv(NULL) 229 , fCreateContextAttribs(NULL) { 230 HDC prevDC = wglGetCurrentDC(); 231 HGLRC prevGLRC = wglGetCurrentContext(); 232 233 PIXELFORMATDESCRIPTOR dummyPFD; 234 235 ZeroMemory(&dummyPFD, sizeof(dummyPFD)); 236 dummyPFD.nSize = sizeof(dummyPFD); 237 dummyPFD.nVersion = 1; 238 dummyPFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; 239 dummyPFD.iPixelType = PFD_TYPE_RGBA; 240 dummyPFD.cColorBits = 32; 241 dummyPFD.cDepthBits = 0; 242 dummyPFD.cStencilBits = 8; 243 dummyPFD.iLayerType = PFD_MAIN_PLANE; 244 HWND dummyWND = create_dummy_window(); 245 if (dummyWND) { 246 HDC dummyDC = GetDC(dummyWND); 247 int dummyFormat = ChoosePixelFormat(dummyDC, &dummyPFD); 248 SetPixelFormat(dummyDC, dummyFormat, &dummyPFD); 249 HGLRC dummyGLRC = wglCreateContext(dummyDC); 250 SkASSERT(dummyGLRC); 251 wglMakeCurrent(dummyDC, dummyGLRC); 252 253 GET_PROC(GetExtensionsString, ARB); 254 GET_PROC(ChoosePixelFormat, ARB); 255 GET_PROC(GetPixelFormatAttribiv, ARB); 256 GET_PROC(GetPixelFormatAttribfv, ARB); 257 GET_PROC(CreateContextAttribs, ARB); 258 259 wglMakeCurrent(dummyDC, NULL); 260 wglDeleteContext(dummyGLRC); 261 destroy_dummy_window(dummyWND); 262 } 263 264 wglMakeCurrent(prevDC, prevGLRC); 265 } 266