robertphillips@google.com | 53e96a1 | 2012-03-30 14:47:53 +0000 | [diff] [blame^] | 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 <d3d9.h>
|
| 14 | #include <WindowsX.h>
|
| 15 | #include "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 "GLES2/gl2.h"
|
| 26 | #endif
|
| 27 |
|
| 28 | #define INVALIDATE_DELAY_MS 200
|
| 29 |
|
| 30 | static SkOSWindow* gCurrOSWin;
|
| 31 | static HWND gEventTarget;
|
| 32 |
|
| 33 | #define WM_EVENT_CALLBACK (WM_USER+0)
|
| 34 |
|
| 35 | void post_skwinevent()
|
| 36 | {
|
| 37 | PostMessage(gEventTarget, WM_EVENT_CALLBACK, 0, 0);
|
| 38 | }
|
| 39 |
|
| 40 | SkOSWindow::SkOSWindow(void* hWnd)
|
| 41 | : fHWND(hWnd)
|
| 42 | #if SK_ANGLE
|
| 43 | , fDisplay(EGL_NO_DISPLAY)
|
| 44 | , fContext(EGL_NO_CONTEXT)
|
| 45 | , fSurface(EGL_NO_SURFACE)
|
| 46 | #endif
|
| 47 | , fHGLRC(NULL)
|
| 48 | , fD3D9Device(NULL)
|
| 49 | , fAttached(kNone_BackEndType) {
|
| 50 | gEventTarget = (HWND)hWnd;
|
| 51 | }
|
| 52 |
|
| 53 | SkOSWindow::~SkOSWindow() {
|
| 54 | if (NULL != fD3D9Device) {
|
| 55 | ((IDirect3DDevice9*)fD3D9Device)->Release();
|
| 56 | }
|
| 57 | if (NULL != fHGLRC) {
|
| 58 | wglDeleteContext((HGLRC)fHGLRC);
|
| 59 | }
|
| 60 | #if SK_ANGLE
|
| 61 | if (EGL_NO_CONTEXT != fContext) {
|
| 62 | angle::eglDestroyContext(fDisplay, fContext);
|
| 63 | fContext = EGL_NO_CONTEXT;
|
| 64 | }
|
| 65 |
|
| 66 | if (EGL_NO_SURFACE != fSurface) {
|
| 67 | angle::eglDestroySurface(fDisplay, fSurface);
|
| 68 | fSurface = EGL_NO_SURFACE;
|
| 69 | }
|
| 70 |
|
| 71 | if (EGL_NO_DISPLAY != fDisplay) {
|
| 72 | angle::eglTerminate(fDisplay);
|
| 73 | fDisplay = EGL_NO_DISPLAY;
|
| 74 | }
|
| 75 | #endif
|
| 76 | }
|
| 77 |
|
| 78 | static SkKey winToskKey(WPARAM vk) {
|
| 79 | static const struct {
|
| 80 | WPARAM fVK;
|
| 81 | SkKey fKey;
|
| 82 | } gPair[] = {
|
| 83 | { VK_BACK, kBack_SkKey },
|
| 84 | { VK_CLEAR, kBack_SkKey },
|
| 85 | { VK_RETURN, kOK_SkKey },
|
| 86 | { VK_UP, kUp_SkKey },
|
| 87 | { VK_DOWN, kDown_SkKey },
|
| 88 | { VK_LEFT, kLeft_SkKey },
|
| 89 | { VK_RIGHT, kRight_SkKey }
|
| 90 | };
|
| 91 | for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
|
| 92 | if (gPair[i].fVK == vk) {
|
| 93 | return gPair[i].fKey;
|
| 94 | }
|
| 95 | }
|
| 96 | return kNONE_SkKey;
|
| 97 | }
|
| 98 |
|
| 99 | bool SkOSWindow::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
| 100 | switch (message) {
|
| 101 | case WM_KEYDOWN: {
|
| 102 | SkKey key = winToskKey(wParam);
|
| 103 | if (kNONE_SkKey != key) {
|
| 104 | this->handleKey(key);
|
| 105 | return true;
|
| 106 | }
|
| 107 | } break;
|
| 108 | case WM_KEYUP: {
|
| 109 | SkKey key = winToskKey(wParam);
|
| 110 | if (kNONE_SkKey != key) {
|
| 111 | this->handleKeyUp(key);
|
| 112 | return true;
|
| 113 | }
|
| 114 | } break;
|
| 115 | case WM_UNICHAR:
|
| 116 | this->handleChar(wParam);
|
| 117 | return true;
|
| 118 | case WM_CHAR: {
|
| 119 | this->handleChar(SkUTF8_ToUnichar((char*)&wParam));
|
| 120 | return true;
|
| 121 | } break;
|
| 122 | case WM_SIZE:
|
| 123 | this->resize(lParam & 0xFFFF, lParam >> 16);
|
| 124 | break;
|
| 125 | case WM_PAINT: {
|
| 126 | PAINTSTRUCT ps;
|
| 127 | HDC hdc = BeginPaint(hWnd, &ps);
|
| 128 | this->doPaint(hdc);
|
| 129 | EndPaint(hWnd, &ps);
|
| 130 | return true;
|
| 131 | } break;
|
| 132 |
|
| 133 | case WM_TIMER: {
|
| 134 | RECT* rect = (RECT*)wParam;
|
| 135 | InvalidateRect(hWnd, rect, FALSE);
|
| 136 | KillTimer(hWnd, (UINT_PTR)rect);
|
| 137 | delete rect;
|
| 138 | return true;
|
| 139 | } break;
|
| 140 |
|
| 141 | case WM_LBUTTONDOWN:
|
| 142 | this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), Click::kDown_State);
|
| 143 | return true;
|
| 144 |
|
| 145 | case WM_MOUSEMOVE:
|
| 146 | this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), Click::kMoved_State);
|
| 147 | return true;
|
| 148 |
|
| 149 | case WM_LBUTTONUP:
|
| 150 | this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), Click::kUp_State);
|
| 151 | return true;
|
| 152 |
|
| 153 | case WM_EVENT_CALLBACK:
|
| 154 | if (SkEvent::ProcessEvent()) {
|
| 155 | post_skwinevent();
|
| 156 | }
|
| 157 | return true;
|
| 158 | }
|
| 159 | return false;
|
| 160 | }
|
| 161 |
|
| 162 | void SkOSWindow::doPaint(void* ctx) {
|
| 163 | this->update(NULL);
|
| 164 |
|
| 165 | if (kNone_BackEndType == fAttached)
|
| 166 | {
|
| 167 | HDC hdc = (HDC)ctx;
|
| 168 | const SkBitmap& bitmap = this->getBitmap();
|
| 169 |
|
| 170 | BITMAPINFO bmi;
|
| 171 | memset(&bmi, 0, sizeof(bmi));
|
| 172 | bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
| 173 | bmi.bmiHeader.biWidth = bitmap.width();
|
| 174 | bmi.bmiHeader.biHeight = -bitmap.height(); // top-down image
|
| 175 | bmi.bmiHeader.biPlanes = 1;
|
| 176 | bmi.bmiHeader.biBitCount = 32;
|
| 177 | bmi.bmiHeader.biCompression = BI_RGB;
|
| 178 | bmi.bmiHeader.biSizeImage = 0;
|
| 179 |
|
| 180 | //
|
| 181 | // Do the SetDIBitsToDevice.
|
| 182 | //
|
| 183 | // TODO(wjmaclean):
|
| 184 | // Fix this call to handle SkBitmaps that have rowBytes != width,
|
| 185 | // i.e. may have padding at the end of lines. The SkASSERT below
|
| 186 | // may be ignored by builds, and the only obviously safe option
|
| 187 | // seems to be to copy the bitmap to a temporary (contiguous)
|
| 188 | // buffer before passing to SetDIBitsToDevice().
|
| 189 | SkASSERT(bitmap.width() * bitmap.bytesPerPixel() == bitmap.rowBytes());
|
| 190 | bitmap.lockPixels();
|
| 191 | int iRet = SetDIBitsToDevice(hdc,
|
| 192 | 0, 0,
|
| 193 | bitmap.width(), bitmap.height(),
|
| 194 | 0, 0,
|
| 195 | 0, bitmap.height(),
|
| 196 | bitmap.getPixels(),
|
| 197 | &bmi,
|
| 198 | DIB_RGB_COLORS);
|
| 199 | bitmap.unlockPixels();
|
| 200 | }
|
| 201 | }
|
| 202 |
|
| 203 | #if 0
|
| 204 | void SkOSWindow::updateSize()
|
| 205 | {
|
| 206 | RECT r;
|
| 207 | GetWindowRect((HWND)this->getHWND(), &r);
|
| 208 | this->resize(r.right - r.left, r.bottom - r.top);
|
| 209 | }
|
| 210 | #endif
|
| 211 |
|
| 212 | void SkOSWindow::onHandleInval(const SkIRect& r) {
|
| 213 | RECT* rect = new RECT;
|
| 214 | rect->left = r.fLeft;
|
| 215 | rect->top = r.fTop;
|
| 216 | rect->right = r.fRight;
|
| 217 | rect->bottom = r.fBottom;
|
| 218 | SetTimer((HWND)fHWND, (UINT_PTR)rect, INVALIDATE_DELAY_MS, NULL);
|
| 219 | }
|
| 220 |
|
| 221 | void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
|
| 222 | {
|
| 223 | }
|
| 224 |
|
| 225 | void SkOSWindow::onSetTitle(const char title[]){
|
| 226 | SetWindowTextA((HWND)fHWND, title);
|
| 227 | }
|
| 228 |
|
| 229 | enum {
|
| 230 | SK_MacReturnKey = 36,
|
| 231 | SK_MacDeleteKey = 51,
|
| 232 | SK_MacEndKey = 119,
|
| 233 | SK_MacLeftKey = 123,
|
| 234 | SK_MacRightKey = 124,
|
| 235 | SK_MacDownKey = 125,
|
| 236 | SK_MacUpKey = 126,
|
| 237 |
|
| 238 | SK_Mac0Key = 0x52,
|
| 239 | SK_Mac1Key = 0x53,
|
| 240 | SK_Mac2Key = 0x54,
|
| 241 | SK_Mac3Key = 0x55,
|
| 242 | SK_Mac4Key = 0x56,
|
| 243 | SK_Mac5Key = 0x57,
|
| 244 | SK_Mac6Key = 0x58,
|
| 245 | SK_Mac7Key = 0x59,
|
| 246 | SK_Mac8Key = 0x5b,
|
| 247 | SK_Mac9Key = 0x5c
|
| 248 | };
|
| 249 |
|
| 250 | static SkKey raw2key(uint32_t raw)
|
| 251 | {
|
| 252 | static const struct {
|
| 253 | uint32_t fRaw;
|
| 254 | SkKey fKey;
|
| 255 | } gKeys[] = {
|
| 256 | { SK_MacUpKey, kUp_SkKey },
|
| 257 | { SK_MacDownKey, kDown_SkKey },
|
| 258 | { SK_MacLeftKey, kLeft_SkKey },
|
| 259 | { SK_MacRightKey, kRight_SkKey },
|
| 260 | { SK_MacReturnKey, kOK_SkKey },
|
| 261 | { SK_MacDeleteKey, kBack_SkKey },
|
| 262 | { SK_MacEndKey, kEnd_SkKey },
|
| 263 | { SK_Mac0Key, k0_SkKey },
|
| 264 | { SK_Mac1Key, k1_SkKey },
|
| 265 | { SK_Mac2Key, k2_SkKey },
|
| 266 | { SK_Mac3Key, k3_SkKey },
|
| 267 | { SK_Mac4Key, k4_SkKey },
|
| 268 | { SK_Mac5Key, k5_SkKey },
|
| 269 | { SK_Mac6Key, k6_SkKey },
|
| 270 | { SK_Mac7Key, k7_SkKey },
|
| 271 | { SK_Mac8Key, k8_SkKey },
|
| 272 | { SK_Mac9Key, k9_SkKey }
|
| 273 | };
|
| 274 |
|
| 275 | for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
|
| 276 | if (gKeys[i].fRaw == raw)
|
| 277 | return gKeys[i].fKey;
|
| 278 | return kNONE_SkKey;
|
| 279 | }
|
| 280 |
|
| 281 | ///////////////////////////////////////////////////////////////////////////////////////
|
| 282 |
|
| 283 | void SkEvent::SignalNonEmptyQueue()
|
| 284 | {
|
| 285 | post_skwinevent();
|
| 286 | //SkDebugf("signal nonempty\n");
|
| 287 | }
|
| 288 |
|
| 289 | static UINT_PTR gTimer;
|
| 290 |
|
| 291 | VOID CALLBACK sk_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
|
| 292 | {
|
| 293 | SkEvent::ServiceQueueTimer();
|
| 294 | //SkDebugf("timer task fired\n");
|
| 295 | }
|
| 296 |
|
| 297 | void SkEvent::SignalQueueTimer(SkMSec delay)
|
| 298 | {
|
| 299 | if (gTimer)
|
| 300 | {
|
| 301 | KillTimer(NULL, gTimer);
|
| 302 | gTimer = NULL;
|
| 303 | }
|
| 304 | if (delay)
|
| 305 | {
|
| 306 | gTimer = SetTimer(NULL, 0, delay, sk_timer_proc);
|
| 307 | //SkDebugf("SetTimer of %d returned %d\n", delay, gTimer);
|
| 308 | }
|
| 309 | }
|
| 310 |
|
| 311 |
|
| 312 | #define USE_MSAA 0
|
| 313 |
|
| 314 | HGLRC create_gl(HWND hwnd) {
|
| 315 |
|
| 316 | HDC dc = GetDC(hwnd);
|
| 317 |
|
| 318 | SkWGLExtensions extensions;
|
| 319 | if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) {
|
| 320 | return NULL;
|
| 321 | }
|
| 322 |
|
| 323 | HDC prevDC = wglGetCurrentDC();
|
| 324 | HGLRC prevGLRC = wglGetCurrentContext();
|
| 325 | PIXELFORMATDESCRIPTOR pfd;
|
| 326 |
|
| 327 | int format = 0;
|
| 328 |
|
| 329 | GLint iattrs[] = {
|
| 330 | SK_WGL_DRAW_TO_WINDOW, TRUE,
|
| 331 | SK_WGL_DOUBLE_BUFFER, TRUE,
|
| 332 | SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION,
|
| 333 | SK_WGL_SUPPORT_OPENGL, TRUE,
|
| 334 | SK_WGL_COLOR_BITS, 24,
|
| 335 | SK_WGL_ALPHA_BITS, 8,
|
| 336 | SK_WGL_STENCIL_BITS, 8,
|
| 337 |
|
| 338 | // these must be kept last
|
| 339 | SK_WGL_SAMPLE_BUFFERS, TRUE,
|
| 340 | SK_WGL_SAMPLES, 0,
|
| 341 | 0,0
|
| 342 | };
|
| 343 |
|
| 344 | static const int kSampleBuffersValueIdx = SK_ARRAY_COUNT(iattrs) - 5;
|
| 345 | static const int kSamplesValueIdx = SK_ARRAY_COUNT(iattrs) - 3;
|
| 346 | if (USE_MSAA && extensions.hasExtension(dc, "WGL_ARB_multisample")) {
|
| 347 | for (int samples = 16; samples > 1; --samples) {
|
| 348 |
|
| 349 | iattrs[kSamplesValueIdx] = samples;
|
| 350 | GLfloat fattrs[] = {0,0};
|
| 351 | GLuint num;
|
| 352 | int formats[64];
|
| 353 | extensions.choosePixelFormat(dc, iattrs, fattrs, 64, formats, &num);
|
| 354 | num = min(num,64);
|
| 355 | for (GLuint i = 0; i < num; ++i) {
|
| 356 | DescribePixelFormat(dc, formats[i], sizeof(pfd), &pfd);
|
| 357 | if (SetPixelFormat(dc, formats[i], &pfd)) {
|
| 358 | format = formats[i];
|
| 359 | break;
|
| 360 | }
|
| 361 | }
|
| 362 | }
|
| 363 | }
|
| 364 |
|
| 365 | if (0 == format) {
|
| 366 | iattrs[kSampleBuffersValueIdx-1] = iattrs[kSampleBuffersValueIdx] = 0;
|
| 367 | iattrs[kSamplesValueIdx-1] = iattrs[kSamplesValueIdx] = 0;
|
| 368 | GLfloat fattrs[] = {0,0};
|
| 369 | GLuint num;
|
| 370 | extensions.choosePixelFormat(dc, iattrs, fattrs, 1, &format, &num);
|
| 371 | DescribePixelFormat(dc, format, sizeof(pfd), &pfd);
|
| 372 | BOOL set = SetPixelFormat(dc, format, &pfd);
|
| 373 | SkASSERT(TRUE == set);
|
| 374 | }
|
| 375 |
|
| 376 | HGLRC glrc = wglCreateContext(dc);
|
| 377 | SkASSERT(glrc);
|
| 378 |
|
| 379 | wglMakeCurrent(prevDC, prevGLRC);
|
| 380 | return glrc;
|
| 381 | }
|
| 382 |
|
| 383 | bool SkOSWindow::attachGL() {
|
| 384 | if (NULL == fHGLRC) {
|
| 385 | fHGLRC = create_gl((HWND)fHWND);
|
| 386 | if (NULL == fHGLRC) {
|
| 387 | return false;
|
| 388 | }
|
| 389 | glClearStencil(0);
|
| 390 | glClearColor(0, 0, 0, 0);
|
| 391 | glStencilMask(0xffffffff);
|
| 392 | glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
| 393 | }
|
| 394 | if (wglMakeCurrent(GetDC((HWND)fHWND), (HGLRC)fHGLRC)) {
|
| 395 | glViewport(0, 0, SkScalarRound(this->width()),
|
| 396 | SkScalarRound(this->height()));
|
| 397 | return true;
|
| 398 | }
|
| 399 | return false;
|
| 400 | }
|
| 401 |
|
| 402 | void SkOSWindow::detachGL() {
|
| 403 | wglMakeCurrent(GetDC((HWND)fHWND), 0);
|
| 404 | wglDeleteContext((HGLRC)fHGLRC);
|
| 405 | fHGLRC = NULL;
|
| 406 | }
|
| 407 |
|
| 408 | void SkOSWindow::presentGL() {
|
| 409 | glFlush();
|
| 410 | SwapBuffers(GetDC((HWND)fHWND));
|
| 411 | }
|
| 412 |
|
| 413 | #if SK_ANGLE
|
| 414 | bool create_ANGLE(EGLNativeWindowType hWnd, angle::EGLDisplay* eglDisplay,
|
| 415 | angle::EGLContext* eglContext, angle::EGLSurface* eglSurface) {
|
| 416 | EGLint contextAttribs[] = {
|
| 417 | EGL_CONTEXT_CLIENT_VERSION, 2,
|
| 418 | EGL_NONE, EGL_NONE
|
| 419 | };
|
| 420 | EGLint configAttribList[] = {
|
| 421 | EGL_RED_SIZE, 8,
|
| 422 | EGL_GREEN_SIZE, 8,
|
| 423 | EGL_BLUE_SIZE, 8,
|
| 424 | EGL_ALPHA_SIZE, 8,
|
| 425 | EGL_DEPTH_SIZE, 8,
|
| 426 | EGL_STENCIL_SIZE, 8,
|
| 427 | EGL_NONE
|
| 428 | };
|
| 429 | EGLint surfaceAttribList[] = {
|
| 430 | EGL_NONE, EGL_NONE
|
| 431 | };
|
| 432 |
|
| 433 | angle::EGLDisplay display = angle::eglGetDisplay(GetDC(hWnd));
|
| 434 | if (display == EGL_NO_DISPLAY ) {
|
| 435 | return false;
|
| 436 | }
|
| 437 |
|
| 438 | // Initialize EGL
|
| 439 | EGLint majorVersion, minorVersion;
|
| 440 | if (!angle::eglInitialize(display, &majorVersion, &minorVersion)) {
|
| 441 | return false;
|
| 442 | }
|
| 443 |
|
| 444 | EGLint numConfigs;
|
| 445 | if (!angle::eglGetConfigs(display, NULL, 0, &numConfigs)) {
|
| 446 | return false;
|
| 447 | }
|
| 448 |
|
| 449 | // Choose config
|
| 450 | angle::EGLConfig config;
|
| 451 | if (!angle::eglChooseConfig(display, configAttribList,
|
| 452 | &config, 1, &numConfigs)) {
|
| 453 | return false;
|
| 454 | }
|
| 455 |
|
| 456 | // Create a surface
|
| 457 | angle::EGLSurface surface = angle::eglCreateWindowSurface(display, config,
|
| 458 | (EGLNativeWindowType)hWnd,
|
| 459 | surfaceAttribList);
|
| 460 | if (surface == EGL_NO_SURFACE) {
|
| 461 | return false;
|
| 462 | }
|
| 463 |
|
| 464 | // Create a GL context
|
| 465 | angle::EGLContext context = angle::eglCreateContext(display, config,
|
| 466 | EGL_NO_CONTEXT,
|
| 467 | contextAttribs );
|
| 468 | if (context == EGL_NO_CONTEXT ) {
|
| 469 | return false;
|
| 470 | }
|
| 471 |
|
| 472 | // Make the context current
|
| 473 | if (!angle::eglMakeCurrent(display, surface, surface, context)) {
|
| 474 | return false;
|
| 475 | }
|
| 476 |
|
| 477 | *eglDisplay = display;
|
| 478 | *eglContext = context;
|
| 479 | *eglSurface = surface;
|
| 480 | return true;
|
| 481 | }
|
| 482 |
|
| 483 | bool SkOSWindow::attachANGLE() {
|
| 484 | if (EGL_NO_DISPLAY == fDisplay) {
|
| 485 | bool bResult = create_ANGLE((HWND)fHWND, &fDisplay, &fContext, &fSurface);
|
| 486 | if (false == bResult) {
|
| 487 | return false;
|
| 488 | }
|
| 489 | angle::glClearStencil(0);
|
| 490 | angle::glClearColor(0, 0, 0, 0);
|
| 491 | angle::glStencilMask(0xffffffff);
|
| 492 | angle::glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
| 493 | }
|
| 494 | if (angle::eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
|
| 495 | angle::glViewport(0, 0, SkScalarRound(this->width()),
|
| 496 | SkScalarRound(this->height()));
|
| 497 | return true;
|
| 498 | }
|
| 499 | return false;
|
| 500 | }
|
| 501 |
|
| 502 | void SkOSWindow::detachANGLE() {
|
| 503 | angle::eglMakeCurrent(fDisplay, EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT);
|
| 504 |
|
| 505 | angle::eglDestroyContext(fDisplay, fContext);
|
| 506 | fContext = EGL_NO_CONTEXT;
|
| 507 |
|
| 508 | angle::eglDestroySurface(fDisplay, fSurface);
|
| 509 | fSurface = EGL_NO_SURFACE;
|
| 510 |
|
| 511 | angle::eglTerminate(fDisplay);
|
| 512 | fDisplay = EGL_NO_DISPLAY;
|
| 513 | }
|
| 514 |
|
| 515 | void SkOSWindow::presentANGLE() {
|
| 516 | angle::glFlush();
|
| 517 | angle::eglSwapBuffers(fDisplay, fSurface);
|
| 518 | }
|
| 519 | #endif
|
| 520 |
|
| 521 | IDirect3DDevice9* create_d3d9_device(HWND hwnd) {
|
| 522 | HRESULT hr;
|
| 523 |
|
| 524 | IDirect3D9* d3d9;
|
| 525 | d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
|
| 526 | if (NULL == d3d9) {
|
| 527 | return NULL;
|
| 528 | }
|
| 529 | D3DDEVTYPE devType = D3DDEVTYPE_HAL;
|
| 530 | //D3DDEVTYPE devType = D3DDEVTYPE_REF;
|
| 531 | DWORD qLevels;
|
| 532 | DWORD qLevelsDepth;
|
| 533 | D3DMULTISAMPLE_TYPE type;
|
| 534 | for (type = D3DMULTISAMPLE_16_SAMPLES;
|
| 535 | type >= D3DMULTISAMPLE_NONMASKABLE; --(*(DWORD*)&type)) {
|
| 536 | hr = d3d9->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
|
| 537 | devType, D3DFMT_D24S8, TRUE,
|
| 538 | type, &qLevels);
|
| 539 | qLevels = (hr == D3D_OK) ? qLevels : 0;
|
| 540 | hr = d3d9->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
|
| 541 | devType, D3DFMT_A8R8G8B8, TRUE,
|
| 542 | type, &qLevelsDepth);
|
| 543 | qLevelsDepth = (hr == D3D_OK) ? qLevelsDepth : 0;
|
| 544 | qLevels = min(qLevels,qLevelsDepth);
|
| 545 | if (qLevels > 0) {
|
| 546 | break;
|
| 547 | }
|
| 548 | }
|
| 549 | qLevels = 0;
|
| 550 | IDirect3DDevice9* d3d9Device;
|
| 551 | D3DPRESENT_PARAMETERS pres;
|
| 552 | memset(&pres, 0, sizeof(pres));
|
| 553 | pres.EnableAutoDepthStencil = TRUE;
|
| 554 | pres.AutoDepthStencilFormat = D3DFMT_D24S8;
|
| 555 | pres.BackBufferCount = 2;
|
| 556 | pres.BackBufferFormat = D3DFMT_A8R8G8B8;
|
| 557 | pres.BackBufferHeight = 0;
|
| 558 | pres.BackBufferWidth = 0;
|
| 559 | if (qLevels > 0) {
|
| 560 | pres.MultiSampleType = type;
|
| 561 | pres.MultiSampleQuality = qLevels-1;
|
| 562 | } else {
|
| 563 | pres.MultiSampleType = D3DMULTISAMPLE_NONE;
|
| 564 | pres.MultiSampleQuality = 0;
|
| 565 | }
|
| 566 | pres.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
| 567 | pres.Windowed = TRUE;
|
| 568 | pres.hDeviceWindow = hwnd;
|
| 569 | pres.PresentationInterval = 1;
|
| 570 | pres.Flags = 0;
|
| 571 | hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT,
|
| 572 | devType,
|
| 573 | hwnd,
|
| 574 | D3DCREATE_HARDWARE_VERTEXPROCESSING,
|
| 575 | &pres,
|
| 576 | &d3d9Device);
|
| 577 | D3DERR_INVALIDCALL;
|
| 578 | if (SUCCEEDED(hr)) {
|
| 579 | d3d9Device->Clear(0, NULL, D3DCLEAR_TARGET, 0xFFFFFFFF, 0, 0);
|
| 580 | return d3d9Device;
|
| 581 | }
|
| 582 | return NULL;
|
| 583 | }
|
| 584 |
|
| 585 | // This needs some improvement. D3D doesn't have the same notion of attach/detach
|
| 586 | // as GL. However, just allowing GDI to write to the window after creating the
|
| 587 | // D3D device seems to work.
|
| 588 | // We need to handle resizing. On XP and earlier Reset() will trash all our textures
|
| 589 | // so we would need to inform the SkGpu/caches or just recreate them. On Vista+ we
|
| 590 | // could use an IDirect3DDevice9Ex and call ResetEx() to resize without trashing
|
| 591 | // everything. Currently we do nothing and the D3D9 image gets stretched/compressed
|
| 592 | // when resized.
|
| 593 |
|
| 594 | bool SkOSWindow::attachD3D9() {
|
| 595 | if (NULL == fD3D9Device) {
|
| 596 | fD3D9Device = (void*) create_d3d9_device((HWND)fHWND);
|
| 597 | }
|
| 598 | if (NULL != fD3D9Device) {
|
| 599 | ((IDirect3DDevice9*)fD3D9Device)->BeginScene();
|
| 600 | return true;
|
| 601 | }
|
| 602 | return false;
|
| 603 | }
|
| 604 |
|
| 605 | void SkOSWindow::detachD3D9() {
|
| 606 | if (NULL != fD3D9Device) {
|
| 607 | ((IDirect3DDevice9*)fD3D9Device)->EndScene();
|
| 608 | }
|
| 609 | }
|
| 610 |
|
| 611 | void SkOSWindow::presentD3D9() {
|
| 612 | if (NULL != fD3D9Device) {
|
| 613 | HRESULT hr;
|
| 614 | hr = ((IDirect3DDevice9*)fD3D9Device)->EndScene();
|
| 615 | SkASSERT(SUCCEEDED(hr));
|
| 616 | hr = ((IDirect3DDevice9*)d3d9Device())->Present(NULL, NULL, NULL, NULL);
|
| 617 | SkASSERT(SUCCEEDED(hr));
|
| 618 | hr = ((IDirect3DDevice9*)fD3D9Device)->Clear(0,NULL,D3DCLEAR_TARGET |
|
| 619 | D3DCLEAR_STENCIL, 0x0, 0,
|
| 620 | 0);
|
| 621 | SkASSERT(SUCCEEDED(hr));
|
| 622 | hr = ((IDirect3DDevice9*)fD3D9Device)->BeginScene();
|
| 623 | SkASSERT(SUCCEEDED(hr));
|
| 624 | }
|
| 625 | }
|
| 626 |
|
| 627 | // return true on success
|
| 628 | bool SkOSWindow::attach(SkBackEndTypes attachType) {
|
| 629 |
|
| 630 | // attach doubles as "windowResize" so we need to allo
|
| 631 | // already bound states to pass through again
|
| 632 | // TODO: split out the resize functionality
|
| 633 | // SkASSERT(kNone_BackEndType == fAttached);
|
| 634 | bool result = true;
|
| 635 |
|
| 636 | switch (attachType) {
|
| 637 | case kNone_BackEndType:
|
| 638 | // nothing to do
|
| 639 | break;
|
| 640 | case kNativeGL_BackEndType:
|
| 641 | result = attachGL();
|
| 642 | break;
|
| 643 | #if SK_ANGLE
|
| 644 | case kANGLE_BackEndType:
|
| 645 | result = attachANGLE();
|
| 646 | break;
|
| 647 | #endif
|
| 648 | case kD3D9_BackEndType:
|
| 649 | result = attachD3D9();
|
| 650 | break;
|
| 651 | default:
|
| 652 | SkASSERT(false);
|
| 653 | result = false;
|
| 654 | break;
|
| 655 | }
|
| 656 |
|
| 657 | if (result) {
|
| 658 | fAttached = attachType;
|
| 659 | }
|
| 660 |
|
| 661 | return result;
|
| 662 | }
|
| 663 |
|
| 664 | void SkOSWindow::detach() {
|
| 665 | switch (fAttached) {
|
| 666 | case kNone_BackEndType:
|
| 667 | // nothing to do
|
| 668 | break;
|
| 669 | case kNativeGL_BackEndType:
|
| 670 | detachGL();
|
| 671 | break;
|
| 672 | #if SK_ANGLE
|
| 673 | case kANGLE_BackEndType:
|
| 674 | detachANGLE();
|
| 675 | break;
|
| 676 | #endif
|
| 677 | case kD3D9_BackEndType:
|
| 678 | detachD3D9();
|
| 679 | break;
|
| 680 | default:
|
| 681 | SkASSERT(false);
|
| 682 | break;
|
| 683 | }
|
| 684 | fAttached = kNone_BackEndType;
|
| 685 | }
|
| 686 |
|
| 687 | void SkOSWindow::present() {
|
| 688 | switch (fAttached) {
|
| 689 | case kNone_BackEndType:
|
| 690 | // nothing to do
|
| 691 | return;
|
| 692 | case kNativeGL_BackEndType:
|
| 693 | presentGL();
|
| 694 | break;
|
| 695 | #if SK_ANGLE
|
| 696 | case kANGLE_BackEndType:
|
| 697 | presentANGLE();
|
| 698 | break;
|
| 699 | #endif
|
| 700 | case kD3D9_BackEndType:
|
| 701 | presentD3D9();
|
| 702 | break;
|
| 703 | default:
|
| 704 | SkASSERT(false);
|
| 705 | break;
|
| 706 | }
|
| 707 | }
|
| 708 |
|
| 709 | #endif
|
| 710 |
|