/* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkWGL.h" #include "SkTDArray.h" #include "SkTSearch.h" bool SkWGLExtensions::hasExtension(HDC dc, const char* ext) const { if (NULL == this->fGetExtensionsString) { return false; } if (!strcmp("WGL_ARB_extensions_string", ext)) { return true; } const char* extensionString = this->getExtensionsString(dc); int extLength = strlen(ext); while (true) { int n = strcspn(extensionString, " "); if (n == extLength && 0 == strncmp(ext, extensionString, n)) { return true; } if (0 == extensionString[n]) { return false; } extensionString += n+1; } return false; } const char* SkWGLExtensions::getExtensionsString(HDC hdc) const { return fGetExtensionsString(hdc); } BOOL SkWGLExtensions::choosePixelFormat(HDC hdc, const int* piAttribIList, const FLOAT* pfAttribFList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats) const { return fChoosePixelFormat(hdc, piAttribIList, pfAttribFList, nMaxFormats, piFormats, nNumFormats); } BOOL SkWGLExtensions::getPixelFormatAttribiv(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues) const { return fGetPixelFormatAttribiv(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, piValues); } BOOL SkWGLExtensions::getPixelFormatAttribfv(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, float *pfValues) const { return fGetPixelFormatAttribfv(hdc, iPixelFormat, iLayerPlane, nAttributes, piAttributes, pfValues); } HGLRC SkWGLExtensions::createContextAttribs(HDC hDC, HGLRC hShareContext, const int *attribList) const { return fCreateContextAttribs(hDC, hShareContext, attribList); } namespace { struct PixelFormat { int fFormat; int fCoverageSamples; int fColorSamples; int fChoosePixelFormatRank; }; int compare_pf(const PixelFormat* a, const PixelFormat* b) { if (a->fCoverageSamples < b->fCoverageSamples) { return -1; } else if (b->fCoverageSamples < a->fCoverageSamples) { return 1; } else if (a->fColorSamples < b->fColorSamples) { return -1; } else if (b->fColorSamples < a->fColorSamples) { return 1; } else if (a->fChoosePixelFormatRank < b->fChoosePixelFormatRank) { return -1; } else if (b->fChoosePixelFormatRank < a->fChoosePixelFormatRank) { return 1; } return 0; } } int SkWGLExtensions::selectFormat(const int formats[], int formatCount, HDC dc, int desiredSampleCount) { PixelFormat desiredFormat = { 0, desiredSampleCount, 0, 0, }; SkTDArray<PixelFormat> rankedFormats; rankedFormats.setCount(formatCount); bool supportsCoverage = this->hasExtension(dc, "WGL_NV_multisample_coverage"); for (int i = 0; i < formatCount; ++i) { static const int queryAttrs[] = { SK_WGL_COVERAGE_SAMPLES, // Keep COLOR_SAMPLES at the end so it can be skipped SK_WGL_COLOR_SAMPLES, }; int answers[2]; int queryAttrCnt = supportsCoverage ? SK_ARRAY_COUNT(queryAttrs) : SK_ARRAY_COUNT(queryAttrs) - 1; this->getPixelFormatAttribiv(dc, formats[i], 0, queryAttrCnt, queryAttrs, answers); rankedFormats[i].fFormat = formats[i]; rankedFormats[i].fCoverageSamples = answers[0]; rankedFormats[i].fColorSamples = answers[supportsCoverage ? 1 : 0]; rankedFormats[i].fChoosePixelFormatRank = i; } qsort(rankedFormats.begin(), rankedFormats.count(), sizeof(PixelFormat), SkCastForQSort(compare_pf)); int idx = SkTSearch<PixelFormat>(rankedFormats.begin(), rankedFormats.count(), desiredFormat, sizeof(PixelFormat), compare_pf); if (idx < 0) { idx = ~idx; } return rankedFormats[idx].fFormat; } namespace { #if defined(UNICODE) #define STR_LIT(X) L## #X #else #define STR_LIT(X) #X #endif #define DUMMY_CLASS STR_LIT("DummyClass") HWND create_dummy_window() { HMODULE module = GetModuleHandle(NULL); HWND dummy; RECT windowRect; windowRect.left = 0; windowRect.right = 8; windowRect.top = 0; windowRect.bottom = 8; WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = (WNDPROC) DefWindowProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = module; wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = DUMMY_CLASS; if(!RegisterClass(&wc)) { return 0; } DWORD style, exStyle; exStyle = WS_EX_CLIENTEDGE; style = WS_SYSMENU; AdjustWindowRectEx(&windowRect, style, false, exStyle); if(!(dummy = CreateWindowEx(exStyle, DUMMY_CLASS, STR_LIT("DummyWindow"), WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style, 0, 0, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, NULL, NULL, module, NULL))) { UnregisterClass(DUMMY_CLASS, module); return NULL; } ShowWindow(dummy, SW_HIDE); return dummy; } void destroy_dummy_window(HWND dummy) { DestroyWindow(dummy); HMODULE module = GetModuleHandle(NULL); UnregisterClass(DUMMY_CLASS, module); } } #define GET_PROC(NAME, SUFFIX) f##NAME = \ (##NAME##Proc) wglGetProcAddress("wgl" #NAME #SUFFIX) SkWGLExtensions::SkWGLExtensions() : fGetExtensionsString(NULL) , fChoosePixelFormat(NULL) , fGetPixelFormatAttribfv(NULL) , fGetPixelFormatAttribiv(NULL) , fCreateContextAttribs(NULL) { HDC prevDC = wglGetCurrentDC(); HGLRC prevGLRC = wglGetCurrentContext(); PIXELFORMATDESCRIPTOR dummyPFD; ZeroMemory(&dummyPFD, sizeof(dummyPFD)); dummyPFD.nSize = sizeof(dummyPFD); dummyPFD.nVersion = 1; dummyPFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; dummyPFD.iPixelType = PFD_TYPE_RGBA; dummyPFD.cColorBits = 32; dummyPFD.cDepthBits = 0; dummyPFD.cStencilBits = 8; dummyPFD.iLayerType = PFD_MAIN_PLANE; HWND dummyWND = create_dummy_window(); if (dummyWND) { HDC dummyDC = GetDC(dummyWND); int dummyFormat = ChoosePixelFormat(dummyDC, &dummyPFD); SetPixelFormat(dummyDC, dummyFormat, &dummyPFD); HGLRC dummyGLRC = wglCreateContext(dummyDC); SkASSERT(dummyGLRC); wglMakeCurrent(dummyDC, dummyGLRC); GET_PROC(GetExtensionsString, ARB); GET_PROC(ChoosePixelFormat, ARB); GET_PROC(GetPixelFormatAttribiv, ARB); GET_PROC(GetPixelFormatAttribfv, ARB); GET_PROC(CreateContextAttribs, ARB); wglMakeCurrent(dummyDC, NULL); wglDeleteContext(dummyGLRC); destroy_dummy_window(dummyWND); } wglMakeCurrent(prevDC, prevGLRC); }