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
post_skwinevent(HWND hwnd)43 void post_skwinevent(HWND hwnd)
44 {
45 PostMessage(hwnd, WM_EVENT_CALLBACK, 0, 0);
46 }
47
48 SkTHashMap<void*, SkOSWindow*> SkOSWindow::gHwndToOSWindowMap;
49
SkOSWindow(const void * winInit)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
~SkOSWindow()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
winToskKey(WPARAM vk)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
getModifiers(UINT message)116 static unsigned getModifiers(UINT message) {
117 return 0; // TODO
118 }
119
wndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)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
doPaint(void * ctx)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
updateSize()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
onHandleInval(const SkIRect & r)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
onAddMenu(const SkOSMenu * sk_menu)240 void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
241 {
242 }
243
onSetTitle(const char title[])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
raw2key(uint32_t raw)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
SignalNonEmptyQueue()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
sk_timer_proc(HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime)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
SignalQueueTimer(SkMSec delay)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
attachGL(int msaaSampleCount,bool deepColor,AttachmentInfo * info)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
detachGL()377 void SkOSWindow::detachGL() {
378 wglMakeCurrent(GetDC((HWND)fHWND), 0);
379 wglDeleteContext((HGLRC)fHGLRC);
380 fHGLRC = NULL;
381 }
382
presentGL()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
get_angle_egl_display(void * nativeDisplay)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 {
ANGLEAssembleContextANGLEAssembleContext422 ANGLEAssembleContext() {
423 fEGL = GetModuleHandle("libEGL.dll");
424 fGL = GetModuleHandle("libGLESv2.dll");
425 }
426
isValidANGLEAssembleContext427 bool isValid() const { return SkToBool(fEGL) && SkToBool(fGL); }
428
429 HMODULE fEGL;
430 HMODULE fGL;
431 };
432
angle_get_gl_proc(void * ctx,const char name[])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
get_angle_gl_interface()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
create_ANGLE(EGLNativeWindowType hWnd,int msaaSampleCount,EGLDisplay * eglDisplay,EGLContext * eglContext,EGLSurface * eglSurface,EGLConfig * eglConfig)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
attachANGLE(int msaaSampleCount,AttachmentInfo * info)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
detachANGLE()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
presentANGLE()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
attach(SkBackEndTypes attachType,int msaaSampleCount,bool deepColor,AttachmentInfo * info)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
release()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
present()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
makeFullscreen()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
setVsync(bool enable)760 void SkOSWindow::setVsync(bool enable) {
761 SkWGLExtensions wgl;
762 wgl.swapInterval(enable ? 1 : 0);
763 }
764
closeWindow()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