michael@0: michael@0: /* michael@0: * Copyright 2011 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "SkWGL.h" michael@0: michael@0: #include "SkTDArray.h" michael@0: #include "SkTSearch.h" michael@0: #include "SkTSort.h" michael@0: michael@0: bool SkWGLExtensions::hasExtension(HDC dc, const char* ext) const { michael@0: if (NULL == this->fGetExtensionsString) { michael@0: return false; michael@0: } michael@0: if (!strcmp("WGL_ARB_extensions_string", ext)) { michael@0: return true; michael@0: } michael@0: const char* extensionString = this->getExtensionsString(dc); michael@0: size_t extLength = strlen(ext); michael@0: michael@0: while (true) { michael@0: size_t n = strcspn(extensionString, " "); michael@0: if (n == extLength && 0 == strncmp(ext, extensionString, n)) { michael@0: return true; michael@0: } michael@0: if (0 == extensionString[n]) { michael@0: return false; michael@0: } michael@0: extensionString += n+1; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: const char* SkWGLExtensions::getExtensionsString(HDC hdc) const { michael@0: return fGetExtensionsString(hdc); michael@0: } michael@0: michael@0: BOOL SkWGLExtensions::choosePixelFormat(HDC hdc, michael@0: const int* piAttribIList, michael@0: const FLOAT* pfAttribFList, michael@0: UINT nMaxFormats, michael@0: int* piFormats, michael@0: UINT* nNumFormats) const { michael@0: return fChoosePixelFormat(hdc, piAttribIList, pfAttribFList, michael@0: nMaxFormats, piFormats, nNumFormats); michael@0: } michael@0: michael@0: BOOL SkWGLExtensions::getPixelFormatAttribiv(HDC hdc, michael@0: int iPixelFormat, michael@0: int iLayerPlane, michael@0: UINT nAttributes, michael@0: const int *piAttributes, michael@0: int *piValues) const { michael@0: return fGetPixelFormatAttribiv(hdc, iPixelFormat, iLayerPlane, michael@0: nAttributes, piAttributes, piValues); michael@0: } michael@0: michael@0: BOOL SkWGLExtensions::getPixelFormatAttribfv(HDC hdc, michael@0: int iPixelFormat, michael@0: int iLayerPlane, michael@0: UINT nAttributes, michael@0: const int *piAttributes, michael@0: float *pfValues) const { michael@0: return fGetPixelFormatAttribfv(hdc, iPixelFormat, iLayerPlane, michael@0: nAttributes, piAttributes, pfValues); michael@0: } michael@0: HGLRC SkWGLExtensions::createContextAttribs(HDC hDC, michael@0: HGLRC hShareContext, michael@0: const int *attribList) const { michael@0: return fCreateContextAttribs(hDC, hShareContext, attribList); michael@0: } michael@0: michael@0: namespace { michael@0: michael@0: struct PixelFormat { michael@0: int fFormat; michael@0: int fSampleCnt; michael@0: int fChoosePixelFormatRank; michael@0: }; michael@0: michael@0: bool pf_less(const PixelFormat& a, const PixelFormat& b) { michael@0: if (a.fSampleCnt < b.fSampleCnt) { michael@0: return true; michael@0: } else if (b.fSampleCnt < a.fSampleCnt) { michael@0: return false; michael@0: } else if (a.fChoosePixelFormatRank < b.fChoosePixelFormatRank) { michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: int SkWGLExtensions::selectFormat(const int formats[], michael@0: int formatCount, michael@0: HDC dc, michael@0: int desiredSampleCount) { michael@0: PixelFormat desiredFormat = { michael@0: 0, michael@0: desiredSampleCount, michael@0: 0, michael@0: }; michael@0: SkTDArray rankedFormats; michael@0: rankedFormats.setCount(formatCount); michael@0: for (int i = 0; i < formatCount; ++i) { michael@0: static const int kQueryAttr = SK_WGL_SAMPLES; michael@0: int numSamples; michael@0: this->getPixelFormatAttribiv(dc, michael@0: formats[i], michael@0: 0, michael@0: 1, michael@0: &kQueryAttr, michael@0: &numSamples); michael@0: rankedFormats[i].fFormat = formats[i]; michael@0: rankedFormats[i].fSampleCnt = numSamples; michael@0: rankedFormats[i].fChoosePixelFormatRank = i; michael@0: } michael@0: SkTQSort(rankedFormats.begin(), michael@0: rankedFormats.begin() + rankedFormats.count() - 1, michael@0: SkTLessFunctionToFunctorAdaptor()); michael@0: int idx = SkTSearch(rankedFormats.begin(), michael@0: rankedFormats.count(), michael@0: desiredFormat, michael@0: sizeof(PixelFormat)); michael@0: if (idx < 0) { michael@0: idx = ~idx; michael@0: } michael@0: return rankedFormats[idx].fFormat; michael@0: } michael@0: michael@0: michael@0: namespace { michael@0: michael@0: #if defined(UNICODE) michael@0: #define STR_LIT(X) L## #X michael@0: #else michael@0: #define STR_LIT(X) #X michael@0: #endif michael@0: michael@0: #define DUMMY_CLASS STR_LIT("DummyClass") michael@0: michael@0: HWND create_dummy_window() { michael@0: HMODULE module = GetModuleHandle(NULL); michael@0: HWND dummy; michael@0: RECT windowRect; michael@0: windowRect.left = 0; michael@0: windowRect.right = 8; michael@0: windowRect.top = 0; michael@0: windowRect.bottom = 8; michael@0: michael@0: WNDCLASS wc; michael@0: michael@0: wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; michael@0: wc.lpfnWndProc = (WNDPROC) DefWindowProc; michael@0: wc.cbClsExtra = 0; michael@0: wc.cbWndExtra = 0; michael@0: wc.hInstance = module; michael@0: wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); michael@0: wc.hCursor = LoadCursor(NULL, IDC_ARROW); michael@0: wc.hbrBackground = NULL; michael@0: wc.lpszMenuName = NULL; michael@0: wc.lpszClassName = DUMMY_CLASS; michael@0: michael@0: if(!RegisterClass(&wc)) { michael@0: return 0; michael@0: } michael@0: michael@0: DWORD style, exStyle; michael@0: exStyle = WS_EX_CLIENTEDGE; michael@0: style = WS_SYSMENU; michael@0: michael@0: AdjustWindowRectEx(&windowRect, style, false, exStyle); michael@0: if(!(dummy = CreateWindowEx(exStyle, michael@0: DUMMY_CLASS, michael@0: STR_LIT("DummyWindow"), michael@0: WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style, michael@0: 0, 0, michael@0: windowRect.right-windowRect.left, michael@0: windowRect.bottom-windowRect.top, michael@0: NULL, NULL, michael@0: module, michael@0: NULL))) { michael@0: UnregisterClass(DUMMY_CLASS, module); michael@0: return NULL; michael@0: } michael@0: ShowWindow(dummy, SW_HIDE); michael@0: michael@0: return dummy; michael@0: } michael@0: michael@0: void destroy_dummy_window(HWND dummy) { michael@0: DestroyWindow(dummy); michael@0: HMODULE module = GetModuleHandle(NULL); michael@0: UnregisterClass(DUMMY_CLASS, module); michael@0: } michael@0: } michael@0: michael@0: #define GET_PROC(NAME, SUFFIX) f##NAME = \ michael@0: (##NAME##Proc) wglGetProcAddress("wgl" #NAME #SUFFIX) michael@0: michael@0: SkWGLExtensions::SkWGLExtensions() michael@0: : fGetExtensionsString(NULL) michael@0: , fChoosePixelFormat(NULL) michael@0: , fGetPixelFormatAttribfv(NULL) michael@0: , fGetPixelFormatAttribiv(NULL) michael@0: , fCreateContextAttribs(NULL) { michael@0: HDC prevDC = wglGetCurrentDC(); michael@0: HGLRC prevGLRC = wglGetCurrentContext(); michael@0: michael@0: PIXELFORMATDESCRIPTOR dummyPFD; michael@0: michael@0: ZeroMemory(&dummyPFD, sizeof(dummyPFD)); michael@0: dummyPFD.nSize = sizeof(dummyPFD); michael@0: dummyPFD.nVersion = 1; michael@0: dummyPFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; michael@0: dummyPFD.iPixelType = PFD_TYPE_RGBA; michael@0: dummyPFD.cColorBits = 32; michael@0: dummyPFD.cDepthBits = 0; michael@0: dummyPFD.cStencilBits = 8; michael@0: dummyPFD.iLayerType = PFD_MAIN_PLANE; michael@0: HWND dummyWND = create_dummy_window(); michael@0: if (dummyWND) { michael@0: HDC dummyDC = GetDC(dummyWND); michael@0: int dummyFormat = ChoosePixelFormat(dummyDC, &dummyPFD); michael@0: SetPixelFormat(dummyDC, dummyFormat, &dummyPFD); michael@0: HGLRC dummyGLRC = wglCreateContext(dummyDC); michael@0: SkASSERT(dummyGLRC); michael@0: wglMakeCurrent(dummyDC, dummyGLRC); michael@0: michael@0: GET_PROC(GetExtensionsString, ARB); michael@0: GET_PROC(ChoosePixelFormat, ARB); michael@0: GET_PROC(GetPixelFormatAttribiv, ARB); michael@0: GET_PROC(GetPixelFormatAttribfv, ARB); michael@0: GET_PROC(CreateContextAttribs, ARB); michael@0: michael@0: wglMakeCurrent(dummyDC, NULL); michael@0: wglDeleteContext(dummyGLRC); michael@0: destroy_dummy_window(dummyWND); michael@0: } michael@0: michael@0: wglMakeCurrent(prevDC, prevGLRC); michael@0: } michael@0: michael@0: HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool preferCoreProfile) { michael@0: SkWGLExtensions extensions; michael@0: if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) { michael@0: return NULL; michael@0: } michael@0: michael@0: HDC prevDC = wglGetCurrentDC(); michael@0: HGLRC prevGLRC = wglGetCurrentContext(); michael@0: PIXELFORMATDESCRIPTOR pfd; michael@0: michael@0: int format = 0; michael@0: michael@0: static const int iAttrs[] = { michael@0: SK_WGL_DRAW_TO_WINDOW, TRUE, michael@0: SK_WGL_DOUBLE_BUFFER, TRUE, michael@0: SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION, michael@0: SK_WGL_SUPPORT_OPENGL, TRUE, michael@0: SK_WGL_COLOR_BITS, 24, michael@0: SK_WGL_ALPHA_BITS, 8, michael@0: SK_WGL_STENCIL_BITS, 8, michael@0: 0, 0 michael@0: }; michael@0: michael@0: float fAttrs[] = {0, 0}; michael@0: michael@0: if (msaaSampleCount > 0 && michael@0: extensions.hasExtension(dc, "WGL_ARB_multisample")) { michael@0: static const int kIAttrsCount = SK_ARRAY_COUNT(iAttrs); michael@0: int msaaIAttrs[kIAttrsCount + 4]; michael@0: memcpy(msaaIAttrs, iAttrs, sizeof(int) * kIAttrsCount); michael@0: SkASSERT(0 == msaaIAttrs[kIAttrsCount - 2] && michael@0: 0 == msaaIAttrs[kIAttrsCount - 1]); michael@0: msaaIAttrs[kIAttrsCount - 2] = SK_WGL_SAMPLE_BUFFERS; michael@0: msaaIAttrs[kIAttrsCount - 1] = TRUE; michael@0: msaaIAttrs[kIAttrsCount + 0] = SK_WGL_SAMPLES; michael@0: msaaIAttrs[kIAttrsCount + 1] = msaaSampleCount; michael@0: msaaIAttrs[kIAttrsCount + 2] = 0; michael@0: msaaIAttrs[kIAttrsCount + 3] = 0; michael@0: unsigned int num; michael@0: int formats[64]; michael@0: extensions.choosePixelFormat(dc, msaaIAttrs, fAttrs, 64, formats, &num); michael@0: num = SkTMin(num, 64U); michael@0: int formatToTry = extensions.selectFormat(formats, michael@0: num, michael@0: dc, michael@0: msaaSampleCount); michael@0: DescribePixelFormat(dc, formatToTry, sizeof(pfd), &pfd); michael@0: if (SetPixelFormat(dc, formatToTry, &pfd)) { michael@0: format = formatToTry; michael@0: } michael@0: } michael@0: michael@0: if (0 == format) { michael@0: // Either MSAA wasn't requested or creation failed michael@0: unsigned int num; michael@0: extensions.choosePixelFormat(dc, iAttrs, fAttrs, 1, &format, &num); michael@0: DescribePixelFormat(dc, format, sizeof(pfd), &pfd); michael@0: SkDEBUGCODE(BOOL set =) SetPixelFormat(dc, format, &pfd); michael@0: SkASSERT(TRUE == set); michael@0: } michael@0: michael@0: HGLRC glrc = NULL; michael@0: if (preferCoreProfile && extensions.hasExtension(dc, "WGL_ARB_create_context")) { michael@0: static const int kCoreGLVersions[] = { michael@0: 4, 3, michael@0: 4, 2, michael@0: 4, 1, michael@0: 4, 0, michael@0: 3, 3, michael@0: 3, 2, michael@0: }; michael@0: int coreProfileAttribs[] = { michael@0: SK_WGL_CONTEXT_MAJOR_VERSION, -1, michael@0: SK_WGL_CONTEXT_MINOR_VERSION, -1, michael@0: SK_WGL_CONTEXT_PROFILE_MASK, SK_WGL_CONTEXT_CORE_PROFILE_BIT, michael@0: 0, michael@0: }; michael@0: for (int v = 0; v < SK_ARRAY_COUNT(kCoreGLVersions) / 2; ++v) { michael@0: coreProfileAttribs[1] = kCoreGLVersions[2 * v]; michael@0: coreProfileAttribs[3] = kCoreGLVersions[2 * v + 1]; michael@0: glrc = extensions.createContextAttribs(dc, NULL, coreProfileAttribs); michael@0: if (NULL != glrc) { michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (NULL == glrc) { michael@0: glrc = wglCreateContext(dc); michael@0: } michael@0: SkASSERT(glrc); michael@0: michael@0: wglMakeCurrent(prevDC, prevGLRC); michael@0: return glrc; michael@0: }