Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkTypes.h"
      9 #if defined(SK_BUILD_FOR_WIN32)
     10 
     11 #include "SkWGL.h"
     12 
     13 #include "SkTDArray.h"
     14 #include "SkTSearch.h"
     15 #include "SkTSort.h"
     16 
     17 bool SkWGLExtensions::hasExtension(HDC dc, const char* ext) const {
     18     if (nullptr == this->fGetExtensionsString) {
     19         return false;
     20     }
     21     if (!strcmp("WGL_ARB_extensions_string", ext)) {
     22         return true;
     23     }
     24     const char* extensionString = this->getExtensionsString(dc);
     25     size_t extLength = strlen(ext);
     26 
     27     while (true) {
     28         size_t n = strcspn(extensionString, " ");
     29         if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
     30             return true;
     31         }
     32         if (0 == extensionString[n]) {
     33             return false;
     34         }
     35         extensionString += n+1;
     36     }
     37 
     38     return false;
     39 }
     40 
     41 const char* SkWGLExtensions::getExtensionsString(HDC hdc) const {
     42     return fGetExtensionsString(hdc);
     43 }
     44 
     45 BOOL SkWGLExtensions::choosePixelFormat(HDC hdc,
     46                                         const int* piAttribIList,
     47                                         const FLOAT* pfAttribFList,
     48                                         UINT nMaxFormats,
     49                                         int* piFormats,
     50                                         UINT* nNumFormats) const {
     51     return fChoosePixelFormat(hdc, piAttribIList, pfAttribFList,
     52                               nMaxFormats, piFormats, nNumFormats);
     53 }
     54 
     55 BOOL SkWGLExtensions::getPixelFormatAttribiv(HDC hdc,
     56                                              int iPixelFormat,
     57                                              int iLayerPlane,
     58                                              UINT nAttributes,
     59                                              const int *piAttributes,
     60                                              int *piValues) const {
     61     return fGetPixelFormatAttribiv(hdc, iPixelFormat, iLayerPlane,
     62                                    nAttributes, piAttributes, piValues);
     63 }
     64 
     65 BOOL SkWGLExtensions::getPixelFormatAttribfv(HDC hdc,
     66                                              int iPixelFormat,
     67                                              int iLayerPlane,
     68                                              UINT nAttributes,
     69                                              const int *piAttributes,
     70                                              float *pfValues) const {
     71     return fGetPixelFormatAttribfv(hdc, iPixelFormat, iLayerPlane,
     72                                    nAttributes, piAttributes, pfValues);
     73 }
     74 HGLRC SkWGLExtensions::createContextAttribs(HDC hDC,
     75                                             HGLRC hShareContext,
     76                                             const int *attribList) const {
     77     return fCreateContextAttribs(hDC, hShareContext, attribList);
     78 }
     79 
     80 BOOL SkWGLExtensions::swapInterval(int interval) const {
     81     return fSwapInterval(interval);
     82 }
     83 
     84 HPBUFFER SkWGLExtensions::createPbuffer(HDC hDC,
     85                                         int iPixelFormat,
     86                                         int iWidth,
     87                                         int iHeight,
     88                                         const int *piAttribList) const {
     89     return fCreatePbuffer(hDC, iPixelFormat, iWidth, iHeight, piAttribList);
     90 }
     91 
     92 HDC SkWGLExtensions::getPbufferDC(HPBUFFER hPbuffer) const {
     93     return fGetPbufferDC(hPbuffer);
     94 }
     95 
     96 int SkWGLExtensions::releasePbufferDC(HPBUFFER hPbuffer, HDC hDC) const {
     97     return fReleasePbufferDC(hPbuffer, hDC);
     98 }
     99 
    100 BOOL SkWGLExtensions::destroyPbuffer(HPBUFFER hPbuffer) const {
    101     return fDestroyPbuffer(hPbuffer);
    102 }
    103 
    104 namespace {
    105 
    106 struct PixelFormat {
    107     int fFormat;
    108     int fSampleCnt;
    109     int fChoosePixelFormatRank;
    110 };
    111 
    112 bool pf_less(const PixelFormat& a, const PixelFormat& b) {
    113     if (a.fSampleCnt < b.fSampleCnt) {
    114         return true;
    115     } else if (b.fSampleCnt < a.fSampleCnt) {
    116         return false;
    117     } else if (a.fChoosePixelFormatRank < b.fChoosePixelFormatRank) {
    118         return true;
    119     }
    120     return false;
    121 }
    122 }
    123 
    124 int SkWGLExtensions::selectFormat(const int formats[],
    125                                   int formatCount,
    126                                   HDC dc,
    127                                   int desiredSampleCount) const {
    128     if (formatCount <= 0) {
    129         return -1;
    130     }
    131     PixelFormat desiredFormat = {
    132         0,
    133         desiredSampleCount,
    134         0,
    135     };
    136     SkTDArray<PixelFormat> rankedFormats;
    137     rankedFormats.setCount(formatCount);
    138     for (int i = 0; i < formatCount; ++i) {
    139         static const int kQueryAttr = SK_WGL_SAMPLES;
    140         int numSamples;
    141         this->getPixelFormatAttribiv(dc,
    142                                      formats[i],
    143                                      0,
    144                                      1,
    145                                      &kQueryAttr,
    146                                      &numSamples);
    147         rankedFormats[i].fFormat =  formats[i];
    148         rankedFormats[i].fSampleCnt = numSamples;
    149         rankedFormats[i].fChoosePixelFormatRank = i;
    150     }
    151     SkTQSort(rankedFormats.begin(),
    152              rankedFormats.begin() + rankedFormats.count() - 1,
    153              SkTLessFunctionToFunctorAdaptor<PixelFormat, pf_less>());
    154     int idx = SkTSearch<PixelFormat, pf_less>(rankedFormats.begin(),
    155                                               rankedFormats.count(),
    156                                               desiredFormat,
    157                                               sizeof(PixelFormat));
    158     if (idx < 0) {
    159         idx = ~idx;
    160     }
    161     return rankedFormats[idx].fFormat;
    162 }
    163 
    164 
    165 namespace {
    166 
    167 #if defined(UNICODE)
    168     #define STR_LIT(X) L## #X
    169 #else
    170     #define STR_LIT(X) #X
    171 #endif
    172 
    173 #define DUMMY_CLASS STR_LIT("DummyClass")
    174 
    175 HWND create_dummy_window() {
    176     HMODULE module = GetModuleHandle(nullptr);
    177     HWND dummy;
    178     RECT windowRect;
    179     windowRect.left = 0;
    180     windowRect.right = 8;
    181     windowRect.top = 0;
    182     windowRect.bottom = 8;
    183 
    184     WNDCLASS wc;
    185 
    186     wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    187     wc.lpfnWndProc = (WNDPROC) DefWindowProc;
    188     wc.cbClsExtra = 0;
    189     wc.cbWndExtra = 0;
    190     wc.hInstance = module;
    191     wc.hIcon = LoadIcon(nullptr, IDI_WINLOGO);
    192     wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
    193     wc.hbrBackground = nullptr;
    194     wc.lpszMenuName = nullptr;
    195     wc.lpszClassName = DUMMY_CLASS;
    196 
    197     if(!RegisterClass(&wc)) {
    198         return 0;
    199     }
    200 
    201     DWORD style, exStyle;
    202     exStyle = WS_EX_CLIENTEDGE;
    203     style = WS_SYSMENU;
    204 
    205     AdjustWindowRectEx(&windowRect, style, false, exStyle);
    206     if(!(dummy = CreateWindowEx(exStyle,
    207                                 DUMMY_CLASS,
    208                                 STR_LIT("DummyWindow"),
    209                                 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
    210                                 0, 0,
    211                                 windowRect.right-windowRect.left,
    212                                 windowRect.bottom-windowRect.top,
    213                                 nullptr, nullptr,
    214                                 module,
    215                                 nullptr))) {
    216         UnregisterClass(DUMMY_CLASS, module);
    217         return nullptr;
    218     }
    219     ShowWindow(dummy, SW_HIDE);
    220 
    221     return dummy;
    222 }
    223 
    224 void destroy_dummy_window(HWND dummy) {
    225     DestroyWindow(dummy);
    226     HMODULE module = GetModuleHandle(nullptr);
    227     UnregisterClass(DUMMY_CLASS, module);
    228 }
    229 }
    230 
    231 #define GET_PROC(NAME, SUFFIX) f##NAME = \
    232                      (##NAME##Proc) wglGetProcAddress("wgl" #NAME #SUFFIX)
    233 
    234 SkWGLExtensions::SkWGLExtensions()
    235     : fGetExtensionsString(nullptr)
    236     , fChoosePixelFormat(nullptr)
    237     , fGetPixelFormatAttribfv(nullptr)
    238     , fGetPixelFormatAttribiv(nullptr)
    239     , fCreateContextAttribs(nullptr)
    240     , fSwapInterval(nullptr)
    241     , fCreatePbuffer(nullptr)
    242     , fGetPbufferDC(nullptr)
    243     , fReleasePbufferDC(nullptr)
    244     , fDestroyPbuffer(nullptr)
    245  {
    246     HDC prevDC = wglGetCurrentDC();
    247     HGLRC prevGLRC = wglGetCurrentContext();
    248 
    249     PIXELFORMATDESCRIPTOR dummyPFD;
    250 
    251     ZeroMemory(&dummyPFD, sizeof(dummyPFD));
    252     dummyPFD.nSize = sizeof(dummyPFD);
    253     dummyPFD.nVersion = 1;
    254     dummyPFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
    255     dummyPFD.iPixelType = PFD_TYPE_RGBA;
    256     dummyPFD.cColorBits  = 32;
    257     dummyPFD.cDepthBits  = 0;
    258     dummyPFD.cStencilBits = 8;
    259     dummyPFD.iLayerType = PFD_MAIN_PLANE;
    260     HWND dummyWND = create_dummy_window();
    261     if (dummyWND) {
    262         HDC dummyDC = GetDC(dummyWND);
    263         int dummyFormat = ChoosePixelFormat(dummyDC, &dummyPFD);
    264         SetPixelFormat(dummyDC, dummyFormat, &dummyPFD);
    265         HGLRC dummyGLRC = wglCreateContext(dummyDC);
    266         SkASSERT(dummyGLRC);
    267         wglMakeCurrent(dummyDC, dummyGLRC);
    268 
    269         GET_PROC(GetExtensionsString, ARB);
    270         GET_PROC(ChoosePixelFormat, ARB);
    271         GET_PROC(GetPixelFormatAttribiv, ARB);
    272         GET_PROC(GetPixelFormatAttribfv, ARB);
    273         GET_PROC(CreateContextAttribs, ARB);
    274         GET_PROC(SwapInterval, EXT);
    275         GET_PROC(CreatePbuffer, ARB);
    276         GET_PROC(GetPbufferDC, ARB);
    277         GET_PROC(ReleasePbufferDC, ARB);
    278         GET_PROC(DestroyPbuffer, ARB);
    279 
    280         wglMakeCurrent(dummyDC, nullptr);
    281         wglDeleteContext(dummyGLRC);
    282         destroy_dummy_window(dummyWND);
    283     }
    284 
    285     wglMakeCurrent(prevDC, prevGLRC);
    286 }
    287 
    288 ///////////////////////////////////////////////////////////////////////////////
    289 
    290 static void get_pixel_formats_to_try(HDC dc, const SkWGLExtensions& extensions,
    291                                      bool doubleBuffered, int msaaSampleCount, bool deepColor,
    292                                      int formatsToTry[2]) {
    293     auto appendAttr = [](SkTDArray<int>& attrs, int attr, int value) {
    294         attrs.push(attr);
    295         attrs.push(value);
    296     };
    297 
    298     SkTDArray<int> iAttrs;
    299     appendAttr(iAttrs, SK_WGL_DRAW_TO_WINDOW, TRUE);
    300     appendAttr(iAttrs, SK_WGL_DOUBLE_BUFFER, (doubleBuffered ? TRUE : FALSE));
    301     appendAttr(iAttrs, SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION);
    302     appendAttr(iAttrs, SK_WGL_SUPPORT_OPENGL, TRUE);
    303     if (deepColor) {
    304         appendAttr(iAttrs, SK_WGL_RED_BITS, 10);
    305         appendAttr(iAttrs, SK_WGL_GREEN_BITS, 10);
    306         appendAttr(iAttrs, SK_WGL_BLUE_BITS, 10);
    307         appendAttr(iAttrs, SK_WGL_ALPHA_BITS, 2);
    308     } else {
    309         appendAttr(iAttrs, SK_WGL_COLOR_BITS, 24);
    310         appendAttr(iAttrs, SK_WGL_ALPHA_BITS, 8);
    311     }
    312     appendAttr(iAttrs, SK_WGL_STENCIL_BITS, 8);
    313 
    314     float fAttrs[] = {0, 0};
    315 
    316     // Get a MSAA format if requested and possible.
    317     if (msaaSampleCount > 0 &&
    318         extensions.hasExtension(dc, "WGL_ARB_multisample")) {
    319         SkTDArray<int> msaaIAttrs = iAttrs;
    320         appendAttr(msaaIAttrs, SK_WGL_SAMPLE_BUFFERS, TRUE);
    321         appendAttr(msaaIAttrs, SK_WGL_SAMPLES, msaaSampleCount);
    322         appendAttr(msaaIAttrs, 0, 0);
    323         unsigned int num;
    324         int formats[64];
    325         extensions.choosePixelFormat(dc, msaaIAttrs.begin(), fAttrs, 64, formats, &num);
    326         num = SkTMin(num, 64U);
    327         formatsToTry[0] = extensions.selectFormat(formats, num, dc, msaaSampleCount);
    328     }
    329 
    330     // Get a non-MSAA format
    331     int* format = -1 == formatsToTry[0] ? &formatsToTry[0] : &formatsToTry[1];
    332     unsigned int num;
    333     appendAttr(iAttrs, 0, 0);
    334     extensions.choosePixelFormat(dc, iAttrs.begin(), fAttrs, 1, format, &num);
    335 }
    336 
    337 static HGLRC create_gl_context(HDC dc, SkWGLExtensions extensions, SkWGLContextRequest contextType,
    338                                HGLRC shareContext) {
    339     HDC prevDC = wglGetCurrentDC();
    340     HGLRC prevGLRC = wglGetCurrentContext();
    341 
    342     HGLRC glrc = nullptr;
    343     if (kGLES_SkWGLContextRequest == contextType) {
    344         if (!extensions.hasExtension(dc, "WGL_EXT_create_context_es2_profile")) {
    345             wglMakeCurrent(prevDC, prevGLRC);
    346             return nullptr;
    347         }
    348         static const int glesAttribs[] = {
    349             SK_WGL_CONTEXT_MAJOR_VERSION, 3,
    350             SK_WGL_CONTEXT_MINOR_VERSION, 0,
    351             SK_WGL_CONTEXT_PROFILE_MASK,  SK_WGL_CONTEXT_ES2_PROFILE_BIT,
    352             0,
    353         };
    354         glrc = extensions.createContextAttribs(dc, shareContext, glesAttribs);
    355         if (nullptr == glrc) {
    356             wglMakeCurrent(prevDC, prevGLRC);
    357             return nullptr;
    358         }
    359     } else {
    360         if (kGLPreferCoreProfile_SkWGLContextRequest == contextType &&
    361             extensions.hasExtension(dc, "WGL_ARB_create_context")) {
    362             static const int kCoreGLVersions[] = {
    363                 4, 3,
    364                 4, 2,
    365                 4, 1,
    366                 4, 0,
    367                 3, 3,
    368                 3, 2,
    369             };
    370             int coreProfileAttribs[] = {
    371                 SK_WGL_CONTEXT_MAJOR_VERSION, -1,
    372                 SK_WGL_CONTEXT_MINOR_VERSION, -1,
    373                 SK_WGL_CONTEXT_PROFILE_MASK,  SK_WGL_CONTEXT_CORE_PROFILE_BIT,
    374                 0,
    375             };
    376             for (int v = 0; v < SK_ARRAY_COUNT(kCoreGLVersions) / 2; ++v) {
    377                 coreProfileAttribs[1] = kCoreGLVersions[2 * v];
    378                 coreProfileAttribs[3] = kCoreGLVersions[2 * v + 1];
    379                 glrc = extensions.createContextAttribs(dc, shareContext, coreProfileAttribs);
    380                 if (glrc) {
    381                     break;
    382                 }
    383             }
    384         }
    385     }
    386 
    387     if (nullptr == glrc) {
    388         glrc = wglCreateContext(dc);
    389         if (shareContext) {
    390             if (!wglShareLists(shareContext, glrc)) {
    391                 wglDeleteContext(glrc);
    392                 return nullptr;
    393             }
    394         }
    395     }
    396     SkASSERT(glrc);
    397 
    398     wglMakeCurrent(prevDC, prevGLRC);
    399 
    400     // This might help make the context non-vsynced.
    401     if (extensions.hasExtension(dc, "WGL_EXT_swap_control")) {
    402         extensions.swapInterval(-1);
    403     }
    404     return glrc;
    405 }
    406 
    407 HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor,
    408                          SkWGLContextRequest contextType, HGLRC shareContext) {
    409     SkWGLExtensions extensions;
    410     if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) {
    411         return nullptr;
    412     }
    413 
    414     BOOL set = FALSE;
    415 
    416     int pixelFormatsToTry[] = { -1, -1 };
    417     get_pixel_formats_to_try(dc, extensions, true, msaaSampleCount, deepColor, pixelFormatsToTry);
    418     for (int f = 0;
    419          !set && -1 != pixelFormatsToTry[f] && f < SK_ARRAY_COUNT(pixelFormatsToTry);
    420          ++f) {
    421         PIXELFORMATDESCRIPTOR pfd;
    422         DescribePixelFormat(dc, pixelFormatsToTry[f], sizeof(pfd), &pfd);
    423         set = SetPixelFormat(dc, pixelFormatsToTry[f], &pfd);
    424     }
    425 
    426     if (!set) {
    427         return nullptr;
    428     }
    429 
    430     return create_gl_context(dc, extensions, contextType, shareContext);
    431 }
    432 
    433 SkWGLPbufferContext* SkWGLPbufferContext::Create(HDC parentDC, int msaaSampleCount,
    434                                                  SkWGLContextRequest contextType,
    435                                                  HGLRC shareContext) {
    436     SkWGLExtensions extensions;
    437     if (!extensions.hasExtension(parentDC, "WGL_ARB_pixel_format") ||
    438         !extensions.hasExtension(parentDC, "WGL_ARB_pbuffer")) {
    439         return nullptr;
    440     }
    441 
    442     // try for single buffer first
    443     for (int dblBuffer = 0; dblBuffer < 2; ++dblBuffer) {
    444         int pixelFormatsToTry[] = { -1, -1 };
    445         get_pixel_formats_to_try(parentDC, extensions, (0 != dblBuffer), msaaSampleCount,
    446                                  false, pixelFormatsToTry);
    447         for (int f = 0; -1 != pixelFormatsToTry[f] && f < SK_ARRAY_COUNT(pixelFormatsToTry); ++f) {
    448             HPBUFFER pbuf = extensions.createPbuffer(parentDC, pixelFormatsToTry[f], 1, 1, nullptr);
    449             if (0 != pbuf) {
    450                 HDC dc = extensions.getPbufferDC(pbuf);
    451                 if (dc) {
    452                     HGLRC glrc = create_gl_context(dc, extensions, contextType, shareContext);
    453                     if (glrc) {
    454                         return new SkWGLPbufferContext(pbuf, dc, glrc);
    455                     }
    456                     extensions.releasePbufferDC(pbuf, dc);
    457                 }
    458                 extensions.destroyPbuffer(pbuf);
    459             }
    460         }
    461     }
    462     return nullptr;
    463 }
    464 
    465 SkWGLPbufferContext::~SkWGLPbufferContext() {
    466     SkASSERT(fExtensions.hasExtension(fDC, "WGL_ARB_pbuffer"));
    467     wglDeleteContext(fGLRC);
    468     fExtensions.releasePbufferDC(fPbuffer, fDC);
    469     fExtensions.destroyPbuffer(fPbuffer);
    470 }
    471 
    472 SkWGLPbufferContext::SkWGLPbufferContext(HPBUFFER pbuffer, HDC dc, HGLRC glrc)
    473     : fPbuffer(pbuffer)
    474     , fDC(dc)
    475     , fGLRC(glrc) {
    476 }
    477 
    478 #endif//defined(SK_BUILD_FOR_WIN32)
    479