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 #include "SkTypes.h" 9 10 #if defined(SK_BUILD_FOR_WIN) 11 12 #include <GL/gl.h> 13 #include <WindowsX.h> 14 #include "SkWGL.h" 15 #include "SkWindow.h" 16 #include "SkCanvas.h" 17 #include "SkOSMenu.h" 18 #include "SkTime.h" 19 #include "SkUtils.h" 20 21 #include "SkGraphics.h" 22 23 #if SK_ANGLE 24 #include "gl/GrGLInterface.h" 25 26 #include "GLES2/gl2.h" 27 28 #define ANGLE_GL_CALL(IFACE, X) \ 29 do { \ 30 (IFACE)->f##X; \ 31 } while (false) 32 33 #endif 34 35 #define INVALIDATE_DELAY_MS 200 36 37 static SkOSWindow* gCurrOSWin; 38 static HWND gEventTarget; 39 40 #define WM_EVENT_CALLBACK (WM_USER+0) 41 42 void post_skwinevent() 43 { 44 PostMessage(gEventTarget, WM_EVENT_CALLBACK, 0, 0); 45 } 46 47 SkOSWindow::SkOSWindow(void* hWnd) { 48 fHWND = hWnd; 49 #if SK_SUPPORT_GPU 50 #if SK_ANGLE 51 fDisplay = EGL_NO_DISPLAY; 52 fContext = EGL_NO_CONTEXT; 53 fSurface = EGL_NO_SURFACE; 54 #endif 55 fHGLRC = NULL; 56 #endif 57 fAttached = kNone_BackEndType; 58 gEventTarget = (HWND)hWnd; 59 } 60 61 SkOSWindow::~SkOSWindow() { 62 #if SK_SUPPORT_GPU 63 if (NULL != fHGLRC) { 64 wglDeleteContext((HGLRC)fHGLRC); 65 } 66 #if SK_ANGLE 67 if (EGL_NO_CONTEXT != fContext) { 68 eglDestroyContext(fDisplay, fContext); 69 fContext = EGL_NO_CONTEXT; 70 } 71 72 if (EGL_NO_SURFACE != fSurface) { 73 eglDestroySurface(fDisplay, fSurface); 74 fSurface = EGL_NO_SURFACE; 75 } 76 77 if (EGL_NO_DISPLAY != fDisplay) { 78 eglTerminate(fDisplay); 79 fDisplay = EGL_NO_DISPLAY; 80 } 81 #endif // SK_ANGLE 82 #endif // SK_SUPPORT_GPU 83 } 84 85 static SkKey winToskKey(WPARAM vk) { 86 static const struct { 87 WPARAM fVK; 88 SkKey fKey; 89 } gPair[] = { 90 { VK_BACK, kBack_SkKey }, 91 { VK_CLEAR, kBack_SkKey }, 92 { VK_RETURN, kOK_SkKey }, 93 { VK_UP, kUp_SkKey }, 94 { VK_DOWN, kDown_SkKey }, 95 { VK_LEFT, kLeft_SkKey }, 96 { VK_RIGHT, kRight_SkKey } 97 }; 98 for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) { 99 if (gPair[i].fVK == vk) { 100 return gPair[i].fKey; 101 } 102 } 103 return kNONE_SkKey; 104 } 105 106 static unsigned getModifiers(UINT message) { 107 return 0; // TODO 108 } 109 110 bool SkOSWindow::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { 111 switch (message) { 112 case WM_KEYDOWN: { 113 SkKey key = winToskKey(wParam); 114 if (kNONE_SkKey != key) { 115 this->handleKey(key); 116 return true; 117 } 118 } break; 119 case WM_KEYUP: { 120 SkKey key = winToskKey(wParam); 121 if (kNONE_SkKey != key) { 122 this->handleKeyUp(key); 123 return true; 124 } 125 } break; 126 case WM_UNICHAR: 127 this->handleChar(wParam); 128 return true; 129 case WM_CHAR: { 130 this->handleChar(SkUTF8_ToUnichar((char*)&wParam)); 131 return true; 132 } break; 133 case WM_SIZE: 134 this->resize(lParam & 0xFFFF, lParam >> 16); 135 break; 136 case WM_PAINT: { 137 PAINTSTRUCT ps; 138 HDC hdc = BeginPaint(hWnd, &ps); 139 this->doPaint(hdc); 140 EndPaint(hWnd, &ps); 141 return true; 142 } break; 143 144 case WM_TIMER: { 145 RECT* rect = (RECT*)wParam; 146 InvalidateRect(hWnd, rect, FALSE); 147 KillTimer(hWnd, (UINT_PTR)rect); 148 delete rect; 149 return true; 150 } break; 151 152 case WM_LBUTTONDOWN: 153 this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 154 Click::kDown_State, NULL, getModifiers(message)); 155 return true; 156 157 case WM_MOUSEMOVE: 158 this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 159 Click::kMoved_State, NULL, getModifiers(message)); 160 return true; 161 162 case WM_LBUTTONUP: 163 this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 164 Click::kUp_State, NULL, getModifiers(message)); 165 return true; 166 167 case WM_EVENT_CALLBACK: 168 if (SkEvent::ProcessEvent()) { 169 post_skwinevent(); 170 } 171 return true; 172 } 173 return false; 174 } 175 176 void SkOSWindow::doPaint(void* ctx) { 177 this->update(NULL); 178 179 if (kNone_BackEndType == fAttached) 180 { 181 HDC hdc = (HDC)ctx; 182 const SkBitmap& bitmap = this->getBitmap(); 183 184 BITMAPINFO bmi; 185 memset(&bmi, 0, sizeof(bmi)); 186 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 187 bmi.bmiHeader.biWidth = bitmap.width(); 188 bmi.bmiHeader.biHeight = -bitmap.height(); // top-down image 189 bmi.bmiHeader.biPlanes = 1; 190 bmi.bmiHeader.biBitCount = 32; 191 bmi.bmiHeader.biCompression = BI_RGB; 192 bmi.bmiHeader.biSizeImage = 0; 193 194 // 195 // Do the SetDIBitsToDevice. 196 // 197 // TODO(wjmaclean): 198 // Fix this call to handle SkBitmaps that have rowBytes != width, 199 // i.e. may have padding at the end of lines. The SkASSERT below 200 // may be ignored by builds, and the only obviously safe option 201 // seems to be to copy the bitmap to a temporary (contiguous) 202 // buffer before passing to SetDIBitsToDevice(). 203 SkASSERT(bitmap.width() * bitmap.bytesPerPixel() == bitmap.rowBytes()); 204 bitmap.lockPixels(); 205 int ret = SetDIBitsToDevice(hdc, 206 0, 0, 207 bitmap.width(), bitmap.height(), 208 0, 0, 209 0, bitmap.height(), 210 bitmap.getPixels(), 211 &bmi, 212 DIB_RGB_COLORS); 213 (void)ret; // we're ignoring potential failures for now. 214 bitmap.unlockPixels(); 215 } 216 } 217 218 #if 0 219 void SkOSWindow::updateSize() 220 { 221 RECT r; 222 GetWindowRect((HWND)this->getHWND(), &r); 223 this->resize(r.right - r.left, r.bottom - r.top); 224 } 225 #endif 226 227 void SkOSWindow::onHandleInval(const SkIRect& r) { 228 RECT* rect = new RECT; 229 rect->left = r.fLeft; 230 rect->top = r.fTop; 231 rect->right = r.fRight; 232 rect->bottom = r.fBottom; 233 SetTimer((HWND)fHWND, (UINT_PTR)rect, INVALIDATE_DELAY_MS, NULL); 234 } 235 236 void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu) 237 { 238 } 239 240 void SkOSWindow::onSetTitle(const char title[]){ 241 SetWindowTextA((HWND)fHWND, title); 242 } 243 244 enum { 245 SK_MacReturnKey = 36, 246 SK_MacDeleteKey = 51, 247 SK_MacEndKey = 119, 248 SK_MacLeftKey = 123, 249 SK_MacRightKey = 124, 250 SK_MacDownKey = 125, 251 SK_MacUpKey = 126, 252 253 SK_Mac0Key = 0x52, 254 SK_Mac1Key = 0x53, 255 SK_Mac2Key = 0x54, 256 SK_Mac3Key = 0x55, 257 SK_Mac4Key = 0x56, 258 SK_Mac5Key = 0x57, 259 SK_Mac6Key = 0x58, 260 SK_Mac7Key = 0x59, 261 SK_Mac8Key = 0x5b, 262 SK_Mac9Key = 0x5c 263 }; 264 265 static SkKey raw2key(uint32_t raw) 266 { 267 static const struct { 268 uint32_t fRaw; 269 SkKey fKey; 270 } gKeys[] = { 271 { SK_MacUpKey, kUp_SkKey }, 272 { SK_MacDownKey, kDown_SkKey }, 273 { SK_MacLeftKey, kLeft_SkKey }, 274 { SK_MacRightKey, kRight_SkKey }, 275 { SK_MacReturnKey, kOK_SkKey }, 276 { SK_MacDeleteKey, kBack_SkKey }, 277 { SK_MacEndKey, kEnd_SkKey }, 278 { SK_Mac0Key, k0_SkKey }, 279 { SK_Mac1Key, k1_SkKey }, 280 { SK_Mac2Key, k2_SkKey }, 281 { SK_Mac3Key, k3_SkKey }, 282 { SK_Mac4Key, k4_SkKey }, 283 { SK_Mac5Key, k5_SkKey }, 284 { SK_Mac6Key, k6_SkKey }, 285 { SK_Mac7Key, k7_SkKey }, 286 { SK_Mac8Key, k8_SkKey }, 287 { SK_Mac9Key, k9_SkKey } 288 }; 289 290 for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++) 291 if (gKeys[i].fRaw == raw) 292 return gKeys[i].fKey; 293 return kNONE_SkKey; 294 } 295 296 /////////////////////////////////////////////////////////////////////////////////////// 297 298 void SkEvent::SignalNonEmptyQueue() 299 { 300 post_skwinevent(); 301 //SkDebugf("signal nonempty\n"); 302 } 303 304 static UINT_PTR gTimer; 305 306 VOID CALLBACK sk_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) 307 { 308 SkEvent::ServiceQueueTimer(); 309 //SkDebugf("timer task fired\n"); 310 } 311 312 void SkEvent::SignalQueueTimer(SkMSec delay) 313 { 314 if (gTimer) 315 { 316 KillTimer(NULL, gTimer); 317 gTimer = NULL; 318 } 319 if (delay) 320 { 321 gTimer = SetTimer(NULL, 0, delay, sk_timer_proc); 322 //SkDebugf("SetTimer of %d returned %d\n", delay, gTimer); 323 } 324 } 325 326 #if SK_SUPPORT_GPU 327 328 bool SkOSWindow::attachGL(int msaaSampleCount, AttachmentInfo* info) { 329 HDC dc = GetDC((HWND)fHWND); 330 if (NULL == fHGLRC) { 331 fHGLRC = SkCreateWGLContext(dc, msaaSampleCount, false); 332 if (NULL == fHGLRC) { 333 return false; 334 } 335 glClearStencil(0); 336 glClearColor(0, 0, 0, 0); 337 glStencilMask(0xffffffff); 338 glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 339 } 340 if (wglMakeCurrent(dc, (HGLRC)fHGLRC)) { 341 // use DescribePixelFormat to get the stencil bit depth. 342 int pixelFormat = GetPixelFormat(dc); 343 PIXELFORMATDESCRIPTOR pfd; 344 DescribePixelFormat(dc, pixelFormat, sizeof(pfd), &pfd); 345 info->fStencilBits = pfd.cStencilBits; 346 347 // Get sample count if the MSAA WGL extension is present 348 SkWGLExtensions extensions; 349 if (extensions.hasExtension(dc, "WGL_ARB_multisample")) { 350 static const int kSampleCountAttr = SK_WGL_SAMPLES; 351 extensions.getPixelFormatAttribiv(dc, 352 pixelFormat, 353 0, 354 1, 355 &kSampleCountAttr, 356 &info->fSampleCount); 357 } else { 358 info->fSampleCount = 0; 359 } 360 361 glViewport(0, 0, SkScalarRound(this->width()), SkScalarRound(this->height())); 362 return true; 363 } 364 return false; 365 } 366 367 void SkOSWindow::detachGL() { 368 wglMakeCurrent(GetDC((HWND)fHWND), 0); 369 wglDeleteContext((HGLRC)fHGLRC); 370 fHGLRC = NULL; 371 } 372 373 void SkOSWindow::presentGL() { 374 glFlush(); 375 HDC dc = GetDC((HWND)fHWND); 376 SwapBuffers(dc); 377 ReleaseDC((HWND)fHWND, dc); 378 } 379 380 #if SK_ANGLE 381 bool create_ANGLE(EGLNativeWindowType hWnd, 382 int msaaSampleCount, 383 EGLDisplay* eglDisplay, 384 EGLContext* eglContext, 385 EGLSurface* eglSurface, 386 EGLConfig* eglConfig) { 387 static const EGLint contextAttribs[] = { 388 EGL_CONTEXT_CLIENT_VERSION, 2, 389 EGL_NONE, EGL_NONE 390 }; 391 static const EGLint configAttribList[] = { 392 EGL_RED_SIZE, 8, 393 EGL_GREEN_SIZE, 8, 394 EGL_BLUE_SIZE, 8, 395 EGL_ALPHA_SIZE, 8, 396 EGL_DEPTH_SIZE, 8, 397 EGL_STENCIL_SIZE, 8, 398 EGL_NONE 399 }; 400 static const EGLint surfaceAttribList[] = { 401 EGL_NONE, EGL_NONE 402 }; 403 404 EGLDisplay display = eglGetDisplay(GetDC(hWnd)); 405 if (display == EGL_NO_DISPLAY ) { 406 return false; 407 } 408 409 // Initialize EGL 410 EGLint majorVersion, minorVersion; 411 if (!eglInitialize(display, &majorVersion, &minorVersion)) { 412 return false; 413 } 414 415 EGLint numConfigs; 416 if (!eglGetConfigs(display, NULL, 0, &numConfigs)) { 417 return false; 418 } 419 420 // Choose config 421 bool foundConfig = false; 422 if (msaaSampleCount) { 423 static const int kConfigAttribListCnt = 424 SK_ARRAY_COUNT(configAttribList); 425 EGLint msaaConfigAttribList[kConfigAttribListCnt + 4]; 426 memcpy(msaaConfigAttribList, 427 configAttribList, 428 sizeof(configAttribList)); 429 SkASSERT(EGL_NONE == msaaConfigAttribList[kConfigAttribListCnt - 1]); 430 msaaConfigAttribList[kConfigAttribListCnt - 1] = EGL_SAMPLE_BUFFERS; 431 msaaConfigAttribList[kConfigAttribListCnt + 0] = 1; 432 msaaConfigAttribList[kConfigAttribListCnt + 1] = EGL_SAMPLES; 433 msaaConfigAttribList[kConfigAttribListCnt + 2] = msaaSampleCount; 434 msaaConfigAttribList[kConfigAttribListCnt + 3] = EGL_NONE; 435 if (eglChooseConfig(display, configAttribList, eglConfig, 1, &numConfigs)) { 436 SkASSERT(numConfigs > 0); 437 foundConfig = true; 438 } 439 } 440 if (!foundConfig) { 441 if (!eglChooseConfig(display, configAttribList, eglConfig, 1, &numConfigs)) { 442 return false; 443 } 444 } 445 446 // Create a surface 447 EGLSurface surface = eglCreateWindowSurface(display, *eglConfig, 448 (EGLNativeWindowType)hWnd, 449 surfaceAttribList); 450 if (surface == EGL_NO_SURFACE) { 451 return false; 452 } 453 454 // Create a GL context 455 EGLContext context = eglCreateContext(display, *eglConfig, 456 EGL_NO_CONTEXT, 457 contextAttribs ); 458 if (context == EGL_NO_CONTEXT ) { 459 return false; 460 } 461 462 // Make the context current 463 if (!eglMakeCurrent(display, surface, surface, context)) { 464 return false; 465 } 466 467 *eglDisplay = display; 468 *eglContext = context; 469 *eglSurface = surface; 470 return true; 471 } 472 473 bool SkOSWindow::attachANGLE(int msaaSampleCount, AttachmentInfo* info) { 474 if (EGL_NO_DISPLAY == fDisplay) { 475 bool bResult = create_ANGLE((HWND)fHWND, 476 msaaSampleCount, 477 &fDisplay, 478 &fContext, 479 &fSurface, 480 &fConfig); 481 if (false == bResult) { 482 return false; 483 } 484 SkAutoTUnref<const GrGLInterface> intf(GrGLCreateANGLEInterface()); 485 486 if (intf) { 487 ANGLE_GL_CALL(intf, ClearStencil(0)); 488 ANGLE_GL_CALL(intf, ClearColor(0, 0, 0, 0)); 489 ANGLE_GL_CALL(intf, StencilMask(0xffffffff)); 490 ANGLE_GL_CALL(intf, Clear(GL_STENCIL_BUFFER_BIT |GL_COLOR_BUFFER_BIT)); 491 } 492 } 493 if (eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) { 494 eglGetConfigAttrib(fDisplay, fConfig, EGL_STENCIL_SIZE, &info->fStencilBits); 495 eglGetConfigAttrib(fDisplay, fConfig, EGL_SAMPLES, &info->fSampleCount); 496 497 SkAutoTUnref<const GrGLInterface> intf(GrGLCreateANGLEInterface()); 498 499 if (intf ) { 500 ANGLE_GL_CALL(intf, Viewport(0, 0, SkScalarRound(this->width()), 501 SkScalarRound(this->height()))); 502 } 503 return true; 504 } 505 return false; 506 } 507 508 void SkOSWindow::detachANGLE() { 509 eglMakeCurrent(fDisplay, EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT); 510 511 eglDestroyContext(fDisplay, fContext); 512 fContext = EGL_NO_CONTEXT; 513 514 eglDestroySurface(fDisplay, fSurface); 515 fSurface = EGL_NO_SURFACE; 516 517 eglTerminate(fDisplay); 518 fDisplay = EGL_NO_DISPLAY; 519 } 520 521 void SkOSWindow::presentANGLE() { 522 SkAutoTUnref<const GrGLInterface> intf(GrGLCreateANGLEInterface()); 523 524 if (intf) { 525 ANGLE_GL_CALL(intf, Flush()); 526 } 527 528 eglSwapBuffers(fDisplay, fSurface); 529 } 530 #endif // SK_ANGLE 531 #endif // SK_SUPPORT_GPU 532 533 // return true on success 534 bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo* info) { 535 536 // attach doubles as "windowResize" so we need to allo 537 // already bound states to pass through again 538 // TODO: split out the resize functionality 539 // SkASSERT(kNone_BackEndType == fAttached); 540 bool result = true; 541 542 switch (attachType) { 543 case kNone_BackEndType: 544 // nothing to do 545 break; 546 #if SK_SUPPORT_GPU 547 case kNativeGL_BackEndType: 548 result = attachGL(msaaSampleCount, info); 549 break; 550 #if SK_ANGLE 551 case kANGLE_BackEndType: 552 result = attachANGLE(msaaSampleCount, info); 553 break; 554 #endif // SK_ANGLE 555 #endif // SK_SUPPORT_GPU 556 default: 557 SkASSERT(false); 558 result = false; 559 break; 560 } 561 562 if (result) { 563 fAttached = attachType; 564 } 565 566 return result; 567 } 568 569 void SkOSWindow::detach() { 570 switch (fAttached) { 571 case kNone_BackEndType: 572 // nothing to do 573 break; 574 #if SK_SUPPORT_GPU 575 case kNativeGL_BackEndType: 576 detachGL(); 577 break; 578 #if SK_ANGLE 579 case kANGLE_BackEndType: 580 detachANGLE(); 581 break; 582 #endif // SK_ANGLE 583 #endif // SK_SUPPORT_GPU 584 default: 585 SkASSERT(false); 586 break; 587 } 588 fAttached = kNone_BackEndType; 589 } 590 591 void SkOSWindow::present() { 592 switch (fAttached) { 593 case kNone_BackEndType: 594 // nothing to do 595 return; 596 #if SK_SUPPORT_GPU 597 case kNativeGL_BackEndType: 598 presentGL(); 599 break; 600 #if SK_ANGLE 601 case kANGLE_BackEndType: 602 presentANGLE(); 603 break; 604 #endif // SK_ANGLE 605 #endif // SK_SUPPORT_GPU 606 default: 607 SkASSERT(false); 608 break; 609 } 610 } 611 612 #endif 613