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