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 #include "SkTypes.h"
      8 
      9 #if defined(SK_BUILD_FOR_WIN)
     10 
     11 #include "SkLeanWindows.h"
     12 
     13 #include <GL/gl.h>
     14 #include <WindowsX.h>
     15 #include "win/SkWGL.h"
     16 #include "SkWindow.h"
     17 #include "SkCanvas.h"
     18 #include "SkOSMenu.h"
     19 #include "SkTime.h"
     20 #include "SkUtils.h"
     21 
     22 #include "SkGraphics.h"
     23 
     24 #if SK_ANGLE
     25 #include "gl/GrGLAssembleInterface.h"
     26 #include "gl/GrGLInterface.h"
     27 #include "GLES2/gl2.h"
     28 #include <EGL/egl.h>
     29 #include <EGL/eglext.h>
     30 #endif // SK_ANGLE
     31 
     32 const int kDefaultWindowWidth = 500;
     33 const int kDefaultWindowHeight = 500;
     34 
     35 #define GL_CALL(IFACE, X)                                 \
     36     SkASSERT(IFACE);                                      \
     37     do {                                                  \
     38         (IFACE)->fFunctions.f##X;                         \
     39     } while (false)
     40 
     41 #define WM_EVENT_CALLBACK (WM_USER+0)
     42 
     43 void post_skwinevent(HWND hwnd)
     44 {
     45     PostMessage(hwnd, WM_EVENT_CALLBACK, 0, 0);
     46 }
     47 
     48 SkTHashMap<void*, SkOSWindow*> SkOSWindow::gHwndToOSWindowMap;
     49 
     50 SkOSWindow::SkOSWindow(const void* winInit) {
     51     fWinInit = *(const WindowInit*)winInit;
     52 
     53     fHWND = CreateWindow(fWinInit.fClass, NULL, WS_OVERLAPPEDWINDOW,
     54                          CW_USEDEFAULT, 0, kDefaultWindowWidth, kDefaultWindowHeight, NULL, NULL,
     55                          fWinInit.fInstance, NULL);
     56     gHwndToOSWindowMap.set(fHWND, this);
     57 #if SK_SUPPORT_GPU
     58 #if SK_ANGLE
     59     fDisplay = EGL_NO_DISPLAY;
     60     fContext = EGL_NO_CONTEXT;
     61     fSurface = EGL_NO_SURFACE;
     62 #endif
     63 
     64     fHGLRC = NULL;
     65 #endif
     66     fAttached = kNone_BackEndType;
     67     fFullscreen = false;
     68 }
     69 
     70 SkOSWindow::~SkOSWindow() {
     71 #if SK_SUPPORT_GPU
     72     if (fHGLRC) {
     73         wglDeleteContext((HGLRC)fHGLRC);
     74     }
     75 #if SK_ANGLE
     76     if (EGL_NO_CONTEXT != fContext) {
     77         eglDestroyContext(fDisplay, fContext);
     78         fContext = EGL_NO_CONTEXT;
     79     }
     80 
     81     if (EGL_NO_SURFACE != fSurface) {
     82         eglDestroySurface(fDisplay, fSurface);
     83         fSurface = EGL_NO_SURFACE;
     84     }
     85 
     86     if (EGL_NO_DISPLAY != fDisplay) {
     87         eglTerminate(fDisplay);
     88         fDisplay = EGL_NO_DISPLAY;
     89     }
     90 #endif // SK_ANGLE
     91 #endif // SK_SUPPORT_GPU
     92     this->closeWindow();
     93 }
     94 
     95 static SkKey winToskKey(WPARAM vk) {
     96     static const struct {
     97         WPARAM    fVK;
     98         SkKey    fKey;
     99     } gPair[] = {
    100         { VK_BACK,    kBack_SkKey },
    101         { VK_CLEAR,    kBack_SkKey },
    102         { VK_RETURN, kOK_SkKey },
    103         { VK_UP,     kUp_SkKey },
    104         { VK_DOWN,     kDown_SkKey },
    105         { VK_LEFT,     kLeft_SkKey },
    106         { VK_RIGHT,     kRight_SkKey }
    107     };
    108     for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
    109         if (gPair[i].fVK == vk) {
    110             return gPair[i].fKey;
    111         }
    112     }
    113     return kNONE_SkKey;
    114 }
    115 
    116 static unsigned getModifiers(UINT message) {
    117     return 0;   // TODO
    118 }
    119 
    120 bool SkOSWindow::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    121     switch (message) {
    122         case WM_KEYDOWN: {
    123             SkKey key = winToskKey(wParam);
    124             if (kNONE_SkKey != key) {
    125                 this->handleKey(key);
    126                 return true;
    127             }
    128         } break;
    129         case WM_KEYUP: {
    130             SkKey key = winToskKey(wParam);
    131             if (kNONE_SkKey != key) {
    132                 this->handleKeyUp(key);
    133                 return true;
    134             }
    135         } break;
    136         case WM_UNICHAR:
    137             this->handleChar((SkUnichar) wParam);
    138             return true;
    139         case WM_CHAR: {
    140             const uint16_t* c = reinterpret_cast<uint16_t*>(&wParam);
    141             this->handleChar(SkUTF16_NextUnichar(&c));
    142             return true;
    143         } break;
    144         case WM_SIZE: {
    145             INT width = LOWORD(lParam);
    146             INT height = HIWORD(lParam);
    147             this->resize(width, height);
    148             break;
    149         }
    150         case WM_PAINT: {
    151             PAINTSTRUCT ps;
    152             HDC hdc = BeginPaint(hWnd, &ps);
    153             this->doPaint(hdc);
    154             EndPaint(hWnd, &ps);
    155             return true;
    156             } break;
    157 
    158         case WM_LBUTTONDOWN:
    159             this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
    160                               Click::kDown_State, NULL, getModifiers(message));
    161             return true;
    162 
    163         case WM_MOUSEMOVE:
    164             this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
    165                               Click::kMoved_State, NULL, getModifiers(message));
    166             return true;
    167 
    168         case WM_LBUTTONUP:
    169             this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
    170                               Click::kUp_State, NULL, getModifiers(message));
    171             return true;
    172 
    173         case WM_EVENT_CALLBACK:
    174             if (SkEvent::ProcessEvent()) {
    175                 post_skwinevent(hWnd);
    176             }
    177             return true;
    178     }
    179     return false;
    180 }
    181 
    182 void SkOSWindow::doPaint(void* ctx) {
    183     this->update(NULL);
    184 
    185     if (kNone_BackEndType == fAttached)
    186     {
    187         HDC hdc = (HDC)ctx;
    188         const SkBitmap& bitmap = this->getBitmap();
    189 
    190         BITMAPINFO bmi;
    191         memset(&bmi, 0, sizeof(bmi));
    192         bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
    193         bmi.bmiHeader.biWidth       = bitmap.width();
    194         bmi.bmiHeader.biHeight      = -bitmap.height(); // top-down image
    195         bmi.bmiHeader.biPlanes      = 1;
    196         bmi.bmiHeader.biBitCount    = 32;
    197         bmi.bmiHeader.biCompression = BI_RGB;
    198         bmi.bmiHeader.biSizeImage   = 0;
    199 
    200         //
    201         // Do the SetDIBitsToDevice.
    202         //
    203         // TODO(wjmaclean):
    204         //       Fix this call to handle SkBitmaps that have rowBytes != width,
    205         //       i.e. may have padding at the end of lines. The SkASSERT below
    206         //       may be ignored by builds, and the only obviously safe option
    207         //       seems to be to copy the bitmap to a temporary (contiguous)
    208         //       buffer before passing to SetDIBitsToDevice().
    209         SkASSERT(bitmap.width() * bitmap.bytesPerPixel() == bitmap.rowBytes());
    210         bitmap.lockPixels();
    211         int ret = SetDIBitsToDevice(hdc,
    212             0, 0,
    213             bitmap.width(), bitmap.height(),
    214             0, 0,
    215             0, bitmap.height(),
    216             bitmap.getPixels(),
    217             &bmi,
    218             DIB_RGB_COLORS);
    219         (void)ret; // we're ignoring potential failures for now.
    220         bitmap.unlockPixels();
    221     }
    222 }
    223 
    224 void SkOSWindow::updateSize()
    225 {
    226     RECT    r;
    227     GetWindowRect((HWND)fHWND, &r);
    228     this->resize(r.right - r.left, r.bottom - r.top);
    229 }
    230 
    231 void SkOSWindow::onHandleInval(const SkIRect& r) {
    232     RECT rect;
    233     rect.left    = r.fLeft;
    234     rect.top     = r.fTop;
    235     rect.right   = r.fRight;
    236     rect.bottom  = r.fBottom;
    237     InvalidateRect((HWND)fHWND, &rect, FALSE);
    238 }
    239 
    240 void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
    241 {
    242 }
    243 
    244 void SkOSWindow::onSetTitle(const char title[]){
    245     SetWindowTextA((HWND)fHWND, title);
    246 }
    247 
    248 enum {
    249     SK_MacReturnKey     = 36,
    250     SK_MacDeleteKey     = 51,
    251     SK_MacEndKey        = 119,
    252     SK_MacLeftKey       = 123,
    253     SK_MacRightKey      = 124,
    254     SK_MacDownKey       = 125,
    255     SK_MacUpKey         = 126,
    256 
    257     SK_Mac0Key          = 0x52,
    258     SK_Mac1Key          = 0x53,
    259     SK_Mac2Key          = 0x54,
    260     SK_Mac3Key          = 0x55,
    261     SK_Mac4Key          = 0x56,
    262     SK_Mac5Key          = 0x57,
    263     SK_Mac6Key          = 0x58,
    264     SK_Mac7Key          = 0x59,
    265     SK_Mac8Key          = 0x5b,
    266     SK_Mac9Key          = 0x5c
    267 };
    268 
    269 static SkKey raw2key(uint32_t raw)
    270 {
    271     static const struct {
    272         uint32_t  fRaw;
    273         SkKey   fKey;
    274     } gKeys[] = {
    275         { SK_MacUpKey,      kUp_SkKey       },
    276         { SK_MacDownKey,    kDown_SkKey     },
    277         { SK_MacLeftKey,    kLeft_SkKey     },
    278         { SK_MacRightKey,   kRight_SkKey    },
    279         { SK_MacReturnKey,  kOK_SkKey       },
    280         { SK_MacDeleteKey,  kBack_SkKey     },
    281         { SK_MacEndKey,     kEnd_SkKey      },
    282         { SK_Mac0Key,       k0_SkKey        },
    283         { SK_Mac1Key,       k1_SkKey        },
    284         { SK_Mac2Key,       k2_SkKey        },
    285         { SK_Mac3Key,       k3_SkKey        },
    286         { SK_Mac4Key,       k4_SkKey        },
    287         { SK_Mac5Key,       k5_SkKey        },
    288         { SK_Mac6Key,       k6_SkKey        },
    289         { SK_Mac7Key,       k7_SkKey        },
    290         { SK_Mac8Key,       k8_SkKey        },
    291         { SK_Mac9Key,       k9_SkKey        }
    292     };
    293 
    294     for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
    295         if (gKeys[i].fRaw == raw)
    296             return gKeys[i].fKey;
    297     return kNONE_SkKey;
    298 }
    299 
    300 ///////////////////////////////////////////////////////////////////////////////////////
    301 
    302 void SkEvent::SignalNonEmptyQueue()
    303 {
    304     SkOSWindow::ForAllWindows([](void* hWND, SkOSWindow**) {
    305         post_skwinevent((HWND)hWND);
    306     });
    307 }
    308 
    309 static UINT_PTR gTimer;
    310 
    311 VOID CALLBACK sk_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
    312 {
    313     SkEvent::ServiceQueueTimer();
    314     //SkDebugf("timer task fired\n");
    315 }
    316 
    317 void SkEvent::SignalQueueTimer(SkMSec delay)
    318 {
    319     if (gTimer)
    320     {
    321         KillTimer(NULL, gTimer);
    322         gTimer = NULL;
    323     }
    324     if (delay)
    325     {
    326         gTimer = SetTimer(NULL, 0, delay, sk_timer_proc);
    327         //SkDebugf("SetTimer of %d returned %d\n", delay, gTimer);
    328     }
    329 }
    330 
    331 #if SK_SUPPORT_GPU
    332 
    333 bool SkOSWindow::attachGL(int msaaSampleCount, bool deepColor, AttachmentInfo* info) {
    334     HDC dc = GetDC((HWND)fHWND);
    335     if (NULL == fHGLRC) {
    336         fHGLRC = SkCreateWGLContext(dc, msaaSampleCount, deepColor,
    337                 kGLPreferCompatibilityProfile_SkWGLContextRequest);
    338         if (NULL == fHGLRC) {
    339             return false;
    340         }
    341         glClearStencil(0);
    342         glClearColor(0, 0, 0, 0);
    343         glStencilMask(0xffffffff);
    344         glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    345     }
    346     if (wglMakeCurrent(dc, (HGLRC)fHGLRC)) {
    347         // use DescribePixelFormat to get the stencil and color bit depth.
    348         int pixelFormat = GetPixelFormat(dc);
    349         PIXELFORMATDESCRIPTOR pfd;
    350         DescribePixelFormat(dc, pixelFormat, sizeof(pfd), &pfd);
    351         info->fStencilBits = pfd.cStencilBits;
    352         // pfd.cColorBits includes alpha, so it will be 32 in 8/8/8/8 and 10/10/10/2
    353         info->fColorBits = pfd.cRedBits + pfd.cGreenBits + pfd.cBlueBits;
    354 
    355         // Get sample count if the MSAA WGL extension is present
    356         SkWGLExtensions extensions;
    357         if (extensions.hasExtension(dc, "WGL_ARB_multisample")) {
    358             static const int kSampleCountAttr = SK_WGL_SAMPLES;
    359             extensions.getPixelFormatAttribiv(dc,
    360                                               pixelFormat,
    361                                               0,
    362                                               1,
    363                                               &kSampleCountAttr,
    364                                               &info->fSampleCount);
    365         } else {
    366             info->fSampleCount = 0;
    367         }
    368 
    369         glViewport(0, 0,
    370                    SkScalarRoundToInt(this->width()),
    371                    SkScalarRoundToInt(this->height()));
    372         return true;
    373     }
    374     return false;
    375 }
    376 
    377 void SkOSWindow::detachGL() {
    378     wglMakeCurrent(GetDC((HWND)fHWND), 0);
    379     wglDeleteContext((HGLRC)fHGLRC);
    380     fHGLRC = NULL;
    381 }
    382 
    383 void SkOSWindow::presentGL() {
    384     HDC dc = GetDC((HWND)fHWND);
    385     SwapBuffers(dc);
    386     ReleaseDC((HWND)fHWND, dc);
    387 }
    388 
    389 #if SK_ANGLE
    390 
    391 static void* get_angle_egl_display(void* nativeDisplay) {
    392     PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
    393     eglGetPlatformDisplayEXT =
    394         (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
    395 
    396     // We expect ANGLE to support this extension
    397     if (!eglGetPlatformDisplayEXT) {
    398         return EGL_NO_DISPLAY;
    399     }
    400 
    401     EGLDisplay display = EGL_NO_DISPLAY;
    402     // Try for an ANGLE D3D11 context, fall back to D3D9, and finally GL.
    403     EGLint attribs[3][3] = {
    404         {
    405             EGL_PLATFORM_ANGLE_TYPE_ANGLE,
    406             EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
    407             EGL_NONE
    408         },
    409         {
    410             EGL_PLATFORM_ANGLE_TYPE_ANGLE,
    411             EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE,
    412             EGL_NONE
    413         },
    414     };
    415     for (int i = 0; i < 3 && display == EGL_NO_DISPLAY; ++i) {
    416         display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,nativeDisplay, attribs[i]);
    417     }
    418     return display;
    419 }
    420 
    421 struct ANGLEAssembleContext {
    422     ANGLEAssembleContext() {
    423         fEGL = GetModuleHandle("libEGL.dll");
    424         fGL = GetModuleHandle("libGLESv2.dll");
    425     }
    426 
    427     bool isValid() const { return SkToBool(fEGL) && SkToBool(fGL); }
    428 
    429     HMODULE fEGL;
    430     HMODULE fGL;
    431 };
    432 
    433 static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) {
    434     const ANGLEAssembleContext& context = *reinterpret_cast<const ANGLEAssembleContext*>(ctx);
    435     GrGLFuncPtr proc = (GrGLFuncPtr) GetProcAddress(context.fGL, name);
    436     if (proc) {
    437         return proc;
    438     }
    439     proc = (GrGLFuncPtr) GetProcAddress(context.fEGL, name);
    440     if (proc) {
    441         return proc;
    442     }
    443     return eglGetProcAddress(name);
    444 }
    445 
    446 static const GrGLInterface* get_angle_gl_interface() {
    447     ANGLEAssembleContext context;
    448     if (!context.isValid()) {
    449         return nullptr;
    450     }
    451     return GrGLAssembleGLESInterface(&context, angle_get_gl_proc);
    452 }
    453 
    454 bool create_ANGLE(EGLNativeWindowType hWnd,
    455                   int msaaSampleCount,
    456                   EGLDisplay* eglDisplay,
    457                   EGLContext* eglContext,
    458                   EGLSurface* eglSurface,
    459                   EGLConfig* eglConfig) {
    460     static const EGLint contextAttribs[] = {
    461         EGL_CONTEXT_CLIENT_VERSION, 2,
    462         EGL_NONE, EGL_NONE
    463     };
    464     static const EGLint configAttribList[] = {
    465         EGL_RED_SIZE,       8,
    466         EGL_GREEN_SIZE,     8,
    467         EGL_BLUE_SIZE,      8,
    468         EGL_ALPHA_SIZE,     8,
    469         EGL_DEPTH_SIZE,     8,
    470         EGL_STENCIL_SIZE,   8,
    471         EGL_NONE
    472     };
    473     static const EGLint surfaceAttribList[] = {
    474         EGL_NONE, EGL_NONE
    475     };
    476 
    477     EGLDisplay display = get_angle_egl_display(GetDC(hWnd));
    478 
    479     if (EGL_NO_DISPLAY == display) {
    480         SkDebugf("Could not create ANGLE egl display!\n");
    481         return false;
    482     }
    483 
    484     // Initialize EGL
    485     EGLint majorVersion, minorVersion;
    486     if (!eglInitialize(display, &majorVersion, &minorVersion)) {
    487        return false;
    488     }
    489 
    490     EGLint numConfigs;
    491     if (!eglGetConfigs(display, NULL, 0, &numConfigs)) {
    492        return false;
    493     }
    494 
    495     // Choose config
    496     bool foundConfig = false;
    497     if (msaaSampleCount) {
    498         static const int kConfigAttribListCnt =
    499                                 SK_ARRAY_COUNT(configAttribList);
    500         EGLint msaaConfigAttribList[kConfigAttribListCnt + 4];
    501         memcpy(msaaConfigAttribList,
    502                configAttribList,
    503                sizeof(configAttribList));
    504         SkASSERT(EGL_NONE == msaaConfigAttribList[kConfigAttribListCnt - 1]);
    505         msaaConfigAttribList[kConfigAttribListCnt - 1] = EGL_SAMPLE_BUFFERS;
    506         msaaConfigAttribList[kConfigAttribListCnt + 0] = 1;
    507         msaaConfigAttribList[kConfigAttribListCnt + 1] = EGL_SAMPLES;
    508         msaaConfigAttribList[kConfigAttribListCnt + 2] = msaaSampleCount;
    509         msaaConfigAttribList[kConfigAttribListCnt + 3] = EGL_NONE;
    510         if (eglChooseConfig(display, msaaConfigAttribList, eglConfig, 1, &numConfigs)) {
    511             SkASSERT(numConfigs > 0);
    512             foundConfig = true;
    513         }
    514     }
    515     if (!foundConfig) {
    516         if (!eglChooseConfig(display, configAttribList, eglConfig, 1, &numConfigs)) {
    517            return false;
    518         }
    519     }
    520 
    521     // Create a surface
    522     EGLSurface surface = eglCreateWindowSurface(display, *eglConfig,
    523                                                 (EGLNativeWindowType)hWnd,
    524                                                 surfaceAttribList);
    525     if (surface == EGL_NO_SURFACE) {
    526        return false;
    527     }
    528 
    529     // Create a GL context
    530     EGLContext context = eglCreateContext(display, *eglConfig,
    531                                           EGL_NO_CONTEXT,
    532                                           contextAttribs );
    533     if (context == EGL_NO_CONTEXT ) {
    534        return false;
    535     }
    536 
    537     // Make the context current
    538     if (!eglMakeCurrent(display, surface, surface, context)) {
    539        return false;
    540     }
    541 
    542     *eglDisplay = display;
    543     *eglContext = context;
    544     *eglSurface = surface;
    545     return true;
    546 }
    547 
    548 bool SkOSWindow::attachANGLE(int msaaSampleCount, AttachmentInfo* info) {
    549     if (EGL_NO_DISPLAY == fDisplay) {
    550         bool bResult = create_ANGLE((HWND)fHWND,
    551                                     msaaSampleCount,
    552                                     &fDisplay,
    553                                     &fContext,
    554                                     &fSurface,
    555                                     &fConfig);
    556         if (false == bResult) {
    557             return false;
    558         }
    559         fANGLEInterface.reset(get_angle_gl_interface());
    560         if (!fANGLEInterface) {
    561             this->detachANGLE();
    562             return false;
    563         }
    564         GL_CALL(fANGLEInterface, ClearStencil(0));
    565         GL_CALL(fANGLEInterface, ClearColor(0, 0, 0, 0));
    566         GL_CALL(fANGLEInterface, StencilMask(0xffffffff));
    567         GL_CALL(fANGLEInterface, Clear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT));
    568     }
    569     if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
    570         this->detachANGLE();
    571         return false;
    572     }
    573     eglGetConfigAttrib(fDisplay, fConfig, EGL_STENCIL_SIZE, &info->fStencilBits);
    574     eglGetConfigAttrib(fDisplay, fConfig, EGL_SAMPLES, &info->fSampleCount);
    575 
    576     GL_CALL(fANGLEInterface, Viewport(0, 0, SkScalarRoundToInt(this->width()),
    577                                       SkScalarRoundToInt(this->height())));
    578     return true;
    579 }
    580 
    581 void SkOSWindow::detachANGLE() {
    582     fANGLEInterface.reset(nullptr);
    583     eglMakeCurrent(fDisplay, EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT);
    584 
    585     eglDestroyContext(fDisplay, fContext);
    586     fContext = EGL_NO_CONTEXT;
    587 
    588     eglDestroySurface(fDisplay, fSurface);
    589     fSurface = EGL_NO_SURFACE;
    590 
    591     eglTerminate(fDisplay);
    592     fDisplay = EGL_NO_DISPLAY;
    593 }
    594 
    595 void SkOSWindow::presentANGLE() {
    596     GL_CALL(fANGLEInterface, Flush());
    597 
    598     eglSwapBuffers(fDisplay, fSurface);
    599 }
    600 #endif // SK_ANGLE
    601 
    602 #endif // SK_SUPPORT_GPU
    603 
    604 // return true on success
    605 bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor,
    606                         AttachmentInfo* info) {
    607 
    608     // attach doubles as "windowResize" so we need to allo
    609     // already bound states to pass through again
    610     // TODO: split out the resize functionality
    611 //    SkASSERT(kNone_BackEndType == fAttached);
    612     bool result = true;
    613 
    614     switch (attachType) {
    615     case kNone_BackEndType:
    616         // nothing to do
    617         break;
    618 #if SK_SUPPORT_GPU
    619     case kNativeGL_BackEndType:
    620         result = attachGL(msaaSampleCount, deepColor, info);
    621         break;
    622 #if SK_ANGLE
    623     case kANGLE_BackEndType:
    624         result = attachANGLE(msaaSampleCount, info);
    625         break;
    626 #endif // SK_ANGLE
    627 #endif // SK_SUPPORT_GPU
    628     default:
    629         SkASSERT(false);
    630         result = false;
    631         break;
    632     }
    633 
    634     if (result) {
    635         fAttached = attachType;
    636     }
    637 
    638     return result;
    639 }
    640 
    641 void SkOSWindow::release() {
    642     switch (fAttached) {
    643     case kNone_BackEndType:
    644         // nothing to do
    645         break;
    646 #if SK_SUPPORT_GPU
    647     case kNativeGL_BackEndType:
    648         detachGL();
    649         break;
    650 #if SK_ANGLE
    651     case kANGLE_BackEndType:
    652         detachANGLE();
    653         break;
    654 #endif // SK_ANGLE
    655 #endif // SK_SUPPORT_GPU
    656     default:
    657         SkASSERT(false);
    658         break;
    659     }
    660     fAttached = kNone_BackEndType;
    661 }
    662 
    663 void SkOSWindow::present() {
    664     switch (fAttached) {
    665     case kNone_BackEndType:
    666         // nothing to do
    667         return;
    668 #if SK_SUPPORT_GPU
    669     case kNativeGL_BackEndType:
    670         presentGL();
    671         break;
    672 #if SK_ANGLE
    673     case kANGLE_BackEndType:
    674         presentANGLE();
    675         break;
    676 #endif // SK_ANGLE
    677 #endif // SK_SUPPORT_GPU
    678     default:
    679         SkASSERT(false);
    680         break;
    681     }
    682 }
    683 
    684 bool SkOSWindow::makeFullscreen() {
    685     if (fFullscreen) {
    686         return true;
    687     }
    688 #if SK_SUPPORT_GPU
    689     if (fHGLRC) {
    690         this->detachGL();
    691     }
    692 #endif // SK_SUPPORT_GPU
    693     // This is hacked together from various sources on the web. It can certainly be improved and be
    694     // made more robust.
    695 
    696     // Save current window/resolution information. We do this in case we ever implement switching
    697     // back to windowed mode.
    698     fSavedWindowState.fZoomed = SkToBool(IsZoomed((HWND)fHWND));
    699     if (fSavedWindowState.fZoomed) {
    700         SendMessage((HWND)fHWND, WM_SYSCOMMAND, SC_RESTORE, 0);
    701     }
    702     fSavedWindowState.fStyle = GetWindowLong((HWND)fHWND, GWL_STYLE);
    703     fSavedWindowState.fExStyle = GetWindowLong((HWND)fHWND, GWL_EXSTYLE);
    704     GetWindowRect((HWND)fHWND, &fSavedWindowState.fRect);
    705     DEVMODE currScreenSettings;
    706     memset(&currScreenSettings,0,sizeof(currScreenSettings));
    707     currScreenSettings.dmSize = sizeof(currScreenSettings);
    708     EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &currScreenSettings);
    709     fSavedWindowState.fScreenWidth = currScreenSettings.dmPelsWidth;
    710     fSavedWindowState.fScreenHeight = currScreenSettings.dmPelsHeight;
    711     fSavedWindowState.fScreenBits = currScreenSettings.dmBitsPerPel;
    712     fSavedWindowState.fHWND = fHWND;
    713 
    714     // Try different sizes to find an allowed setting? Use ChangeDisplaySettingsEx?
    715     static const int kWidth = 1280;
    716     static const int kHeight = 1024;
    717     DEVMODE newScreenSettings;
    718     memset(&newScreenSettings, 0, sizeof(newScreenSettings));
    719     newScreenSettings.dmSize = sizeof(newScreenSettings);
    720     newScreenSettings.dmPelsWidth    = kWidth;
    721     newScreenSettings.dmPelsHeight   = kHeight;
    722     newScreenSettings.dmBitsPerPel   = 32;
    723     newScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
    724     if (ChangeDisplaySettings(&newScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
    725         return false;
    726     }
    727     RECT WindowRect;
    728     WindowRect.left = 0;
    729     WindowRect.right = kWidth;
    730     WindowRect.top = 0;
    731     WindowRect.bottom = kHeight;
    732     ShowCursor(FALSE);
    733     AdjustWindowRectEx(&WindowRect, WS_POPUP, FALSE, WS_EX_APPWINDOW);
    734     HWND fsHWND = CreateWindowEx(
    735         WS_EX_APPWINDOW,
    736         fWinInit.fClass,
    737         NULL,
    738         WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
    739         0, 0, WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top,
    740         NULL,
    741         NULL,
    742         fWinInit.fInstance,
    743         NULL
    744     );
    745     if (!fsHWND) {
    746         return false;
    747     }
    748     // Hide the old window and set the entry in the global mapping for this SkOSWindow to the
    749     // new HWND.
    750     ShowWindow((HWND)fHWND, SW_HIDE);
    751     gHwndToOSWindowMap.remove(fHWND);
    752     fHWND = fsHWND;
    753     gHwndToOSWindowMap.set(fHWND, this);
    754     this->updateSize();
    755 
    756     fFullscreen = true;
    757     return true;
    758 }
    759 
    760 void SkOSWindow::setVsync(bool enable) {
    761     SkWGLExtensions wgl;
    762     wgl.swapInterval(enable ? 1 : 0);
    763 }
    764 
    765 void SkOSWindow::closeWindow() {
    766     DestroyWindow((HWND)fHWND);
    767     if (fFullscreen) {
    768         DestroyWindow((HWND)fSavedWindowState.fHWND);
    769     }
    770     gHwndToOSWindowMap.remove(fHWND);
    771 }
    772 #endif
    773