123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- /*
- * 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 "include/core/SkTypes.h"
- #if defined(SK_BUILD_FOR_WIN) && !defined(_M_ARM64)
- #include "src/utils/win/SkWGL.h"
- #include "include/private/SkOnce.h"
- #include "include/private/SkTDArray.h"
- #include "src/core/SkTSearch.h"
- #include "src/core/SkTSort.h"
- bool SkWGLExtensions::hasExtension(HDC dc, const char* ext) const {
- if (nullptr == this->fGetExtensionsString) {
- return false;
- }
- if (!strcmp("WGL_ARB_extensions_string", ext)) {
- return true;
- }
- const char* extensionString = this->getExtensionsString(dc);
- size_t extLength = strlen(ext);
- while (true) {
- size_t 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);
- }
- BOOL SkWGLExtensions::swapInterval(int interval) const {
- return fSwapInterval(interval);
- }
- HPBUFFER SkWGLExtensions::createPbuffer(HDC hDC,
- int iPixelFormat,
- int iWidth,
- int iHeight,
- const int *piAttribList) const {
- return fCreatePbuffer(hDC, iPixelFormat, iWidth, iHeight, piAttribList);
- }
- HDC SkWGLExtensions::getPbufferDC(HPBUFFER hPbuffer) const {
- return fGetPbufferDC(hPbuffer);
- }
- int SkWGLExtensions::releasePbufferDC(HPBUFFER hPbuffer, HDC hDC) const {
- return fReleasePbufferDC(hPbuffer, hDC);
- }
- BOOL SkWGLExtensions::destroyPbuffer(HPBUFFER hPbuffer) const {
- return fDestroyPbuffer(hPbuffer);
- }
- namespace {
- struct PixelFormat {
- int fFormat;
- int fSampleCnt;
- int fChoosePixelFormatRank;
- };
- bool pf_less(const PixelFormat& a, const PixelFormat& b) {
- if (a.fSampleCnt < b.fSampleCnt) {
- return true;
- } else if (b.fSampleCnt < a.fSampleCnt) {
- return false;
- } else if (a.fChoosePixelFormatRank < b.fChoosePixelFormatRank) {
- return true;
- }
- return false;
- }
- }
- int SkWGLExtensions::selectFormat(const int formats[],
- int formatCount,
- HDC dc,
- int desiredSampleCount) const {
- SkASSERT(desiredSampleCount >= 1);
- if (formatCount <= 0) {
- return -1;
- }
- PixelFormat desiredFormat = {
- 0,
- desiredSampleCount,
- 0,
- };
- SkTDArray<PixelFormat> rankedFormats;
- rankedFormats.setCount(formatCount);
- for (int i = 0; i < formatCount; ++i) {
- static const int kQueryAttr = SK_WGL_SAMPLES;
- int numSamples;
- this->getPixelFormatAttribiv(dc,
- formats[i],
- 0,
- 1,
- &kQueryAttr,
- &numSamples);
- rankedFormats[i].fFormat = formats[i];
- rankedFormats[i].fSampleCnt = SkTMax(1, numSamples);
- rankedFormats[i].fChoosePixelFormatRank = i;
- }
- SkTQSort(rankedFormats.begin(),
- rankedFormats.begin() + rankedFormats.count() - 1,
- SkTLessFunctionToFunctorAdaptor<PixelFormat, pf_less>());
- int idx = SkTSearch<PixelFormat, pf_less>(rankedFormats.begin(),
- rankedFormats.count(),
- desiredFormat,
- sizeof(PixelFormat));
- if (idx < 0) {
- idx = ~idx;
- }
- // If the caller asked for non-MSAA fail if the closest format has MSAA.
- if (desiredSampleCount == 1 && rankedFormats[idx].fSampleCnt != 1) {
- return -1;
- }
- 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(nullptr);
- 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(nullptr, IDI_WINLOGO);
- wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
- wc.hbrBackground = nullptr;
- wc.lpszMenuName = nullptr;
- 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,
- nullptr, nullptr,
- module,
- nullptr))) {
- UnregisterClass(DUMMY_CLASS, module);
- return nullptr;
- }
- ShowWindow(dummy, SW_HIDE);
- return dummy;
- }
- void destroy_dummy_window(HWND dummy) {
- DestroyWindow(dummy);
- HMODULE module = GetModuleHandle(nullptr);
- UnregisterClass(DUMMY_CLASS, module);
- }
- }
- #define GET_PROC(NAME, SUFFIX) f##NAME = \
- (NAME##Proc) wglGetProcAddress("wgl" #NAME #SUFFIX)
- SkWGLExtensions::GetExtensionsStringProc SkWGLExtensions::fGetExtensionsString = nullptr;
- SkWGLExtensions::ChoosePixelFormatProc SkWGLExtensions::fChoosePixelFormat = nullptr;
- SkWGLExtensions::GetPixelFormatAttribfvProc SkWGLExtensions::fGetPixelFormatAttribfv = nullptr;
- SkWGLExtensions::GetPixelFormatAttribivProc SkWGLExtensions::fGetPixelFormatAttribiv = nullptr;
- SkWGLExtensions::CreateContextAttribsProc SkWGLExtensions::fCreateContextAttribs = nullptr;
- SkWGLExtensions::SwapIntervalProc SkWGLExtensions::fSwapInterval = nullptr;
- SkWGLExtensions::CreatePbufferProc SkWGLExtensions::fCreatePbuffer = nullptr;
- SkWGLExtensions::GetPbufferDCProc SkWGLExtensions::fGetPbufferDC = nullptr;
- SkWGLExtensions::ReleasePbufferDCProc SkWGLExtensions::fReleasePbufferDC = nullptr;
- SkWGLExtensions::DestroyPbufferProc SkWGLExtensions::fDestroyPbuffer = nullptr;
- SkWGLExtensions::SkWGLExtensions() {
- // We cache these function pointers once, and then reuse them. That's possibly incorrect if
- // there are multiple GPUs, or if we intend to use these for rendering contexts of different
- // pixel formats (where wglGetProcAddress is not guaranteed to return the same pointer).
- static SkOnce once;
- once([] {
- 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);
- GET_PROC(SwapInterval, EXT);
- GET_PROC(CreatePbuffer, ARB);
- GET_PROC(GetPbufferDC, ARB);
- GET_PROC(ReleasePbufferDC, ARB);
- GET_PROC(DestroyPbuffer, ARB);
- wglMakeCurrent(dummyDC, nullptr);
- wglDeleteContext(dummyGLRC);
- destroy_dummy_window(dummyWND);
- }
- wglMakeCurrent(prevDC, prevGLRC);
- });
- }
- ///////////////////////////////////////////////////////////////////////////////
- static void get_pixel_formats_to_try(HDC dc, const SkWGLExtensions& extensions,
- bool doubleBuffered, int msaaSampleCount, bool deepColor,
- int formatsToTry[2]) {
- auto appendAttr = [](SkTDArray<int>& attrs, int attr, int value) {
- attrs.push_back(attr);
- attrs.push_back(value);
- };
- SkTDArray<int> iAttrs;
- appendAttr(iAttrs, SK_WGL_DRAW_TO_WINDOW, TRUE);
- appendAttr(iAttrs, SK_WGL_DOUBLE_BUFFER, (doubleBuffered ? TRUE : FALSE));
- appendAttr(iAttrs, SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION);
- appendAttr(iAttrs, SK_WGL_SUPPORT_OPENGL, TRUE);
- if (deepColor) {
- appendAttr(iAttrs, SK_WGL_RED_BITS, 10);
- appendAttr(iAttrs, SK_WGL_GREEN_BITS, 10);
- appendAttr(iAttrs, SK_WGL_BLUE_BITS, 10);
- appendAttr(iAttrs, SK_WGL_ALPHA_BITS, 2);
- } else {
- appendAttr(iAttrs, SK_WGL_COLOR_BITS, 24);
- appendAttr(iAttrs, SK_WGL_ALPHA_BITS, 8);
- }
- appendAttr(iAttrs, SK_WGL_STENCIL_BITS, 8);
- float fAttrs[] = {0, 0};
- // Get a MSAA format if requested and possible.
- if (msaaSampleCount > 0 &&
- extensions.hasExtension(dc, "WGL_ARB_multisample")) {
- SkTDArray<int> msaaIAttrs = iAttrs;
- appendAttr(msaaIAttrs, SK_WGL_SAMPLE_BUFFERS, TRUE);
- appendAttr(msaaIAttrs, SK_WGL_SAMPLES, msaaSampleCount);
- appendAttr(msaaIAttrs, 0, 0);
- unsigned int num;
- int formats[64];
- extensions.choosePixelFormat(dc, msaaIAttrs.begin(), fAttrs, 64, formats, &num);
- num = SkTMin(num, 64U);
- formatsToTry[0] = extensions.selectFormat(formats, num, dc, msaaSampleCount);
- }
- // Get a non-MSAA format
- int* format = -1 == formatsToTry[0] ? &formatsToTry[0] : &formatsToTry[1];
- unsigned int num;
- appendAttr(iAttrs, 0, 0);
- extensions.choosePixelFormat(dc, iAttrs.begin(), fAttrs, 1, format, &num);
- }
- static HGLRC create_gl_context(HDC dc, const SkWGLExtensions& extensions,
- SkWGLContextRequest contextType, HGLRC shareContext) {
- HDC prevDC = wglGetCurrentDC();
- HGLRC prevGLRC = wglGetCurrentContext();
- HGLRC glrc = nullptr;
- if (kGLES_SkWGLContextRequest == contextType) {
- if (!extensions.hasExtension(dc, "WGL_EXT_create_context_es2_profile")) {
- wglMakeCurrent(prevDC, prevGLRC);
- return nullptr;
- }
- static const int glesAttribs[] = {
- SK_WGL_CONTEXT_MAJOR_VERSION, 3,
- SK_WGL_CONTEXT_MINOR_VERSION, 0,
- SK_WGL_CONTEXT_PROFILE_MASK, SK_WGL_CONTEXT_ES2_PROFILE_BIT,
- 0,
- };
- glrc = extensions.createContextAttribs(dc, shareContext, glesAttribs);
- if (nullptr == glrc) {
- wglMakeCurrent(prevDC, prevGLRC);
- return nullptr;
- }
- } else {
- if (kGLPreferCoreProfile_SkWGLContextRequest == contextType &&
- extensions.hasExtension(dc, "WGL_ARB_create_context")) {
- static const int kCoreGLVersions[] = {
- 4, 3,
- 4, 2,
- 4, 1,
- 4, 0,
- 3, 3,
- 3, 2,
- };
- int coreProfileAttribs[] = {
- SK_WGL_CONTEXT_MAJOR_VERSION, -1,
- SK_WGL_CONTEXT_MINOR_VERSION, -1,
- SK_WGL_CONTEXT_PROFILE_MASK, SK_WGL_CONTEXT_CORE_PROFILE_BIT,
- 0,
- };
- for (size_t v = 0; v < SK_ARRAY_COUNT(kCoreGLVersions) / 2; ++v) {
- coreProfileAttribs[1] = kCoreGLVersions[2 * v];
- coreProfileAttribs[3] = kCoreGLVersions[2 * v + 1];
- glrc = extensions.createContextAttribs(dc, shareContext, coreProfileAttribs);
- if (glrc) {
- break;
- }
- }
- }
- }
- if (nullptr == glrc) {
- glrc = wglCreateContext(dc);
- if (shareContext) {
- if (!wglShareLists(shareContext, glrc)) {
- wglDeleteContext(glrc);
- return nullptr;
- }
- }
- }
- SkASSERT(glrc);
- wglMakeCurrent(prevDC, prevGLRC);
- return glrc;
- }
- HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor,
- SkWGLContextRequest contextType, HGLRC shareContext) {
- SkWGLExtensions extensions;
- if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) {
- return nullptr;
- }
- BOOL set = FALSE;
- int pixelFormatsToTry[] = { -1, -1 };
- get_pixel_formats_to_try(dc, extensions, true, msaaSampleCount, deepColor, pixelFormatsToTry);
- for (size_t f = 0;
- !set && -1 != pixelFormatsToTry[f] && f < SK_ARRAY_COUNT(pixelFormatsToTry);
- ++f) {
- PIXELFORMATDESCRIPTOR pfd;
- DescribePixelFormat(dc, pixelFormatsToTry[f], sizeof(pfd), &pfd);
- set = SetPixelFormat(dc, pixelFormatsToTry[f], &pfd);
- }
- if (!set) {
- return nullptr;
- }
- return create_gl_context(dc, extensions, contextType, shareContext);
- }
- sk_sp<SkWGLPbufferContext> SkWGLPbufferContext::Create(HDC parentDC,
- SkWGLContextRequest contextType,
- HGLRC shareContext) {
- SkWGLExtensions extensions;
- if (!extensions.hasExtension(parentDC, "WGL_ARB_pixel_format") ||
- !extensions.hasExtension(parentDC, "WGL_ARB_pbuffer")) {
- return nullptr;
- }
- // We cache the pixel formats once, and then reuse them. That's possibly incorrect if
- // there are multiple GPUs, but this function is always called with a freshly made,
- // identically constructed HDC (see WinGLTestContext).
- //
- // We only store two potential pixel formats, one for single buffer, one for double buffer.
- // We never ask for MSAA, so we don't need the second pixel format for each buffering state.
- static int gPixelFormats[2] = { -1, -1 };
- static SkOnce once;
- once([=] {
- {
- // Single buffer
- int pixelFormatsToTry[2] = { -1, -1 };
- get_pixel_formats_to_try(parentDC, extensions, false, 0, false, pixelFormatsToTry);
- gPixelFormats[0] = pixelFormatsToTry[0];
- }
- {
- // Double buffer
- int pixelFormatsToTry[2] = { -1, -1 };
- get_pixel_formats_to_try(parentDC, extensions, true, 0, false, pixelFormatsToTry);
- gPixelFormats[1] = pixelFormatsToTry[0];
- }
- });
- // try for single buffer first
- for (int pixelFormat : gPixelFormats) {
- if (-1 == pixelFormat) {
- continue;
- }
- HPBUFFER pbuf = extensions.createPbuffer(parentDC, pixelFormat, 1, 1, nullptr);
- if (0 != pbuf) {
- HDC dc = extensions.getPbufferDC(pbuf);
- if (dc) {
- HGLRC glrc = create_gl_context(dc, extensions, contextType, shareContext);
- if (glrc) {
- return sk_sp<SkWGLPbufferContext>(new SkWGLPbufferContext(pbuf, dc, glrc));
- }
- extensions.releasePbufferDC(pbuf, dc);
- }
- extensions.destroyPbuffer(pbuf);
- }
- }
- return nullptr;
- }
- SkWGLPbufferContext::~SkWGLPbufferContext() {
- SkASSERT(fExtensions.hasExtension(fDC, "WGL_ARB_pbuffer"));
- wglDeleteContext(fGLRC);
- fExtensions.releasePbufferDC(fPbuffer, fDC);
- fExtensions.destroyPbuffer(fPbuffer);
- }
- SkWGLPbufferContext::SkWGLPbufferContext(HPBUFFER pbuffer, HDC dc, HGLRC glrc)
- : fPbuffer(pbuffer)
- , fDC(dc)
- , fGLRC(glrc) {
- }
- #endif//defined(SK_BUILD_FOR_WIN)
|