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     int extLength = strlen(ext);
     24 
     25     while (true) {
     26         int 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 namespace {
     79 
     80 struct PixelFormat {
     81     int fFormat;
     82     int fCoverageSamples;
     83     int fColorSamples;
     84     int fChoosePixelFormatRank;
     85 };
     86 
     87 bool pf_less(const PixelFormat& a, const PixelFormat& b) {
     88     if (a.fCoverageSamples < b.fCoverageSamples) {
     89         return true;
     90     } else if (b.fCoverageSamples < a.fCoverageSamples) {
     91         return false;
     92     } else if (a.fColorSamples < b.fColorSamples) {
     93         return true;
     94     } else if (b.fColorSamples < a.fColorSamples) {
     95         return false;
     96     } else if (a.fChoosePixelFormatRank < b.fChoosePixelFormatRank) {
     97         return true;
     98     }
     99     return false;
    100 }
    101 }
    102 
    103 int SkWGLExtensions::selectFormat(const int formats[],
    104                                   int formatCount,
    105                                   HDC dc,
    106                                   int desiredSampleCount) {
    107     PixelFormat desiredFormat = {
    108         0,
    109         desiredSampleCount,
    110         0,
    111         0,
    112     };
    113     SkTDArray<PixelFormat> rankedFormats;
    114     rankedFormats.setCount(formatCount);
    115     bool supportsCoverage = this->hasExtension(dc,
    116                                                "WGL_NV_multisample_coverage");
    117     for (int i = 0; i < formatCount; ++i) {
    118         static const int queryAttrs[] = {
    119             SK_WGL_COVERAGE_SAMPLES,
    120             // Keep COLOR_SAMPLES at the end so it can be skipped
    121             SK_WGL_COLOR_SAMPLES,
    122         };
    123         int answers[2];
    124         int queryAttrCnt = supportsCoverage ?
    125                                     SK_ARRAY_COUNT(queryAttrs) :
    126                                     SK_ARRAY_COUNT(queryAttrs) - 1;
    127         this->getPixelFormatAttribiv(dc,
    128                                      formats[i],
    129                                      0,
    130                                      queryAttrCnt,
    131                                      queryAttrs,
    132                                      answers);
    133         rankedFormats[i].fFormat =  formats[i];
    134         rankedFormats[i].fCoverageSamples = answers[0];
    135         rankedFormats[i].fColorSamples = answers[supportsCoverage ? 1 : 0];
    136         rankedFormats[i].fChoosePixelFormatRank = i;
    137     }
    138     SkTQSort(rankedFormats.begin(),
    139              rankedFormats.begin() + rankedFormats.count() - 1,
    140              SkTLessFunctionToFunctorAdaptor<PixelFormat, pf_less>());
    141     int idx = SkTSearch<PixelFormat, pf_less>(rankedFormats.begin(),
    142                                               rankedFormats.count(),
    143                                               desiredFormat,
    144                                               sizeof(PixelFormat));
    145     if (idx < 0) {
    146         idx = ~idx;
    147     }
    148     return rankedFormats[idx].fFormat;
    149 }
    150 
    151 
    152 namespace {
    153 
    154 #if defined(UNICODE)
    155     #define STR_LIT(X) L## #X
    156 #else
    157     #define STR_LIT(X) #X
    158 #endif
    159 
    160 #define DUMMY_CLASS STR_LIT("DummyClass")
    161 
    162 HWND create_dummy_window() {
    163     HMODULE module = GetModuleHandle(NULL);
    164     HWND dummy;
    165     RECT windowRect;
    166     windowRect.left = 0;
    167     windowRect.right = 8;
    168     windowRect.top = 0;
    169     windowRect.bottom = 8;
    170 
    171     WNDCLASS wc;
    172 
    173     wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    174     wc.lpfnWndProc = (WNDPROC) DefWindowProc;
    175     wc.cbClsExtra = 0;
    176     wc.cbWndExtra = 0;
    177     wc.hInstance = module;
    178     wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
    179     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    180     wc.hbrBackground = NULL;
    181     wc.lpszMenuName = NULL;
    182     wc.lpszClassName = DUMMY_CLASS;
    183 
    184     if(!RegisterClass(&wc)) {
    185         return 0;
    186     }
    187 
    188     DWORD style, exStyle;
    189     exStyle = WS_EX_CLIENTEDGE;
    190     style = WS_SYSMENU;
    191 
    192     AdjustWindowRectEx(&windowRect, style, false, exStyle);
    193     if(!(dummy = CreateWindowEx(exStyle,
    194                                 DUMMY_CLASS,
    195                                 STR_LIT("DummyWindow"),
    196                                 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
    197                                 0, 0,
    198                                 windowRect.right-windowRect.left,
    199                                 windowRect.bottom-windowRect.top,
    200                                 NULL, NULL,
    201                                 module,
    202                                 NULL))) {
    203         UnregisterClass(DUMMY_CLASS, module);
    204         return NULL;
    205     }
    206     ShowWindow(dummy, SW_HIDE);
    207 
    208     return dummy;
    209 }
    210 
    211 void destroy_dummy_window(HWND dummy) {
    212     DestroyWindow(dummy);
    213     HMODULE module = GetModuleHandle(NULL);
    214     UnregisterClass(DUMMY_CLASS, module);
    215 }
    216 }
    217 
    218 #define GET_PROC(NAME, SUFFIX) f##NAME = \
    219                      (##NAME##Proc) wglGetProcAddress("wgl" #NAME #SUFFIX)
    220 
    221 SkWGLExtensions::SkWGLExtensions()
    222     : fGetExtensionsString(NULL)
    223     , fChoosePixelFormat(NULL)
    224     , fGetPixelFormatAttribfv(NULL)
    225     , fGetPixelFormatAttribiv(NULL)
    226     , fCreateContextAttribs(NULL) {
    227     HDC prevDC = wglGetCurrentDC();
    228     HGLRC prevGLRC = wglGetCurrentContext();
    229 
    230     PIXELFORMATDESCRIPTOR dummyPFD;
    231 
    232     ZeroMemory(&dummyPFD, sizeof(dummyPFD));
    233     dummyPFD.nSize = sizeof(dummyPFD);
    234     dummyPFD.nVersion = 1;
    235     dummyPFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
    236     dummyPFD.iPixelType = PFD_TYPE_RGBA;
    237     dummyPFD.cColorBits  = 32;
    238     dummyPFD.cDepthBits  = 0;
    239     dummyPFD.cStencilBits = 8;
    240     dummyPFD.iLayerType = PFD_MAIN_PLANE;
    241     HWND dummyWND = create_dummy_window();
    242     if (dummyWND) {
    243         HDC dummyDC = GetDC(dummyWND);
    244         int dummyFormat = ChoosePixelFormat(dummyDC, &dummyPFD);
    245         SetPixelFormat(dummyDC, dummyFormat, &dummyPFD);
    246         HGLRC dummyGLRC = wglCreateContext(dummyDC);
    247         SkASSERT(dummyGLRC);
    248         wglMakeCurrent(dummyDC, dummyGLRC);
    249 
    250         GET_PROC(GetExtensionsString, ARB);
    251         GET_PROC(ChoosePixelFormat, ARB);
    252         GET_PROC(GetPixelFormatAttribiv, ARB);
    253         GET_PROC(GetPixelFormatAttribfv, ARB);
    254         GET_PROC(CreateContextAttribs, ARB);
    255 
    256         wglMakeCurrent(dummyDC, NULL);
    257         wglDeleteContext(dummyGLRC);
    258         destroy_dummy_window(dummyWND);
    259     }
    260 
    261     wglMakeCurrent(prevDC, prevGLRC);
    262 }
    263 
    264 HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool preferCoreProfile) {
    265     SkWGLExtensions extensions;
    266     if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) {
    267         return NULL;
    268     }
    269 
    270     HDC prevDC = wglGetCurrentDC();
    271     HGLRC prevGLRC = wglGetCurrentContext();
    272     PIXELFORMATDESCRIPTOR pfd;
    273 
    274     int format = 0;
    275 
    276     static const int iAttrs[] = {
    277         SK_WGL_DRAW_TO_WINDOW, TRUE,
    278         SK_WGL_DOUBLE_BUFFER, TRUE,
    279         SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION,
    280         SK_WGL_SUPPORT_OPENGL, TRUE,
    281         SK_WGL_COLOR_BITS, 24,
    282         SK_WGL_ALPHA_BITS, 8,
    283         SK_WGL_STENCIL_BITS, 8,
    284         0, 0
    285     };
    286 
    287     float fAttrs[] = {0, 0};
    288 
    289     if (msaaSampleCount > 0 &&
    290         extensions.hasExtension(dc, "WGL_ARB_multisample")) {
    291         static const int kIAttrsCount = SK_ARRAY_COUNT(iAttrs);
    292         int msaaIAttrs[kIAttrsCount + 6];
    293         memcpy(msaaIAttrs, iAttrs, sizeof(int) * kIAttrsCount);
    294         SkASSERT(0 == msaaIAttrs[kIAttrsCount - 2] &&
    295                  0 == msaaIAttrs[kIAttrsCount - 1]);
    296         msaaIAttrs[kIAttrsCount - 2] = SK_WGL_SAMPLE_BUFFERS;
    297         msaaIAttrs[kIAttrsCount - 1] = TRUE;
    298         msaaIAttrs[kIAttrsCount + 0] = SK_WGL_SAMPLES;
    299         msaaIAttrs[kIAttrsCount + 1] = msaaSampleCount;
    300         if (extensions.hasExtension(dc, "WGL_NV_multisample_coverage")) {
    301             msaaIAttrs[kIAttrsCount + 2] = SK_WGL_COLOR_SAMPLES;
    302             // We want the fewest number of color samples possible.
    303             // Passing 0 gives only the formats where all samples are color
    304             // samples.
    305             msaaIAttrs[kIAttrsCount + 3] = 1;
    306             msaaIAttrs[kIAttrsCount + 4] = 0;
    307             msaaIAttrs[kIAttrsCount + 5] = 0;
    308         } else {
    309             msaaIAttrs[kIAttrsCount + 2] = 0;
    310             msaaIAttrs[kIAttrsCount + 3] = 0;
    311         }
    312         unsigned int num;
    313         int formats[64];
    314         extensions.choosePixelFormat(dc, msaaIAttrs, fAttrs, 64, formats, &num);
    315         num = SkTMin(num, 64U);
    316         int formatToTry = extensions.selectFormat(formats,
    317                                                   num,
    318                                                   dc,
    319                                                   msaaSampleCount);
    320         DescribePixelFormat(dc, formatToTry, sizeof(pfd), &pfd);
    321         if (SetPixelFormat(dc, formatToTry, &pfd)) {
    322             format = formatToTry;
    323         }
    324     }
    325 
    326     if (0 == format) {
    327         // Either MSAA wasn't requested or creation failed
    328         unsigned int num;
    329         extensions.choosePixelFormat(dc, iAttrs, fAttrs, 1, &format, &num);
    330         DescribePixelFormat(dc, format, sizeof(pfd), &pfd);
    331         SkDEBUGCODE(BOOL set =) SetPixelFormat(dc, format, &pfd);
    332         SkASSERT(TRUE == set);
    333     }
    334 
    335     HGLRC glrc = NULL;
    336     if (preferCoreProfile && extensions.hasExtension(dc, "WGL_ARB_create_context")) {
    337         static const int kCoreGLVersions[] = {
    338             4, 3,
    339             4, 2,
    340             4, 1,
    341             4, 0,
    342             3, 3,
    343             3, 2,
    344         };
    345         int coreProfileAttribs[] = {
    346             SK_WGL_CONTEXT_MAJOR_VERSION, -1,
    347             SK_WGL_CONTEXT_MINOR_VERSION, -1,
    348             SK_WGL_CONTEXT_PROFILE_MASK,  SK_WGL_CONTEXT_CORE_PROFILE_BIT,
    349             0,
    350         };
    351         for (int v = 0; v < SK_ARRAY_COUNT(kCoreGLVersions) / 2; ++v) {
    352             coreProfileAttribs[1] = kCoreGLVersions[2 * v];
    353             coreProfileAttribs[3] = kCoreGLVersions[2 * v + 1];
    354             glrc = extensions.createContextAttribs(dc, NULL, coreProfileAttribs);
    355             if (NULL != glrc) {
    356                 break;
    357             }
    358         }
    359     }
    360 
    361     if (NULL == glrc) {
    362         glrc = wglCreateContext(dc);
    363     }
    364     SkASSERT(glrc);
    365 
    366     wglMakeCurrent(prevDC, prevGLRC);
    367     return glrc;
    368 }
    369