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