blob: aba5a6f4ae89d6f9ddb3331fcf584e1456ca28d1 [file] [log] [blame]
bsalomon@google.com2858b312012-04-02 20:44:38 +00001
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>
bsalomon@google.com2858b312012-04-02 20:44:38 +000013#include <WindowsX.h>
djsollen082a4622014-11-14 07:21:29 -080014#include "win/SkWGL.h"
bsalomon@google.com2858b312012-04-02 20:44:38 +000015#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
bsalomon42380172015-02-23 08:57:23 -080024#include "gl/angle/SkANGLEGLContext.h"
bsalomon@google.com2858b312012-04-02 20:44:38 +000025#include "gl/GrGLInterface.h"
bsalomon@google.com2858b312012-04-02 20:44:38 +000026#include "GLES2/gl2.h"
borenet@google.com0dd5ceb2012-08-28 15:15:49 +000027
28#define ANGLE_GL_CALL(IFACE, X) \
29 do { \
commit-bot@chromium.orgc72425a2014-01-21 16:09:18 +000030 (IFACE)->fFunctions.f##X; \
borenet@google.com0dd5ceb2012-08-28 15:15:49 +000031 } while (false)
32
hendrikw885bf092015-08-27 10:38:39 -070033#endif // SK_ANGLE
34
35#if SK_COMMAND_BUFFER
36#include "gl/command_buffer/SkCommandBufferGLContext.h"
37
38#define COMMAND_BUFFER_GL_CALL(IFACE, X) \
39 do { \
40 (IFACE)->fFunctions.f##X; \
41 } while (false)
42
43#endif // SK_COMMAND_BUFFER
bsalomon@google.com2858b312012-04-02 20:44:38 +000044
bsalomon@google.com2858b312012-04-02 20:44:38 +000045#define WM_EVENT_CALLBACK (WM_USER+0)
46
bsalomon1e7951f2015-06-16 07:04:43 -070047void post_skwinevent(HWND hwnd)
bsalomon@google.com2858b312012-04-02 20:44:38 +000048{
bsalomon1e7951f2015-06-16 07:04:43 -070049 PostMessage(hwnd, WM_EVENT_CALLBACK, 0, 0);
bsalomon@google.com2858b312012-04-02 20:44:38 +000050}
51
bsalomon1e7951f2015-06-16 07:04:43 -070052SkTHashMap<void*, SkOSWindow*> SkOSWindow::gHwndToOSWindowMap;
53
54SkOSWindow::SkOSWindow(const void* winInit) {
55 fWinInit = *(const WindowInit*)winInit;
56
57 fHWND = CreateWindow(fWinInit.fClass, NULL, WS_OVERLAPPEDWINDOW,
58 CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, fWinInit.fInstance, NULL);
59 gHwndToOSWindowMap.set(fHWND, this);
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000060#if SK_SUPPORT_GPU
bsalomon@google.com2858b312012-04-02 20:44:38 +000061#if SK_ANGLE
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000062 fDisplay = EGL_NO_DISPLAY;
63 fContext = EGL_NO_CONTEXT;
64 fSurface = EGL_NO_SURFACE;
bsalomon@google.com2858b312012-04-02 20:44:38 +000065#endif
hendrikw885bf092015-08-27 10:38:39 -070066#if SK_COMMAND_BUFFER
67 fCommandBuffer = nullptr;
68#endif // SK_COMMAND_BUFFER
69
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000070 fHGLRC = NULL;
71#endif
72 fAttached = kNone_BackEndType;
bsalomon1e7951f2015-06-16 07:04:43 -070073 fFullscreen = false;
bsalomon@google.com2858b312012-04-02 20:44:38 +000074}
75
76SkOSWindow::~SkOSWindow() {
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000077#if SK_SUPPORT_GPU
bsalomon49f085d2014-09-05 13:34:00 -070078 if (fHGLRC) {
bsalomon@google.com2858b312012-04-02 20:44:38 +000079 wglDeleteContext((HGLRC)fHGLRC);
80 }
81#if SK_ANGLE
82 if (EGL_NO_CONTEXT != fContext) {
83 eglDestroyContext(fDisplay, fContext);
84 fContext = EGL_NO_CONTEXT;
85 }
86
87 if (EGL_NO_SURFACE != fSurface) {
88 eglDestroySurface(fDisplay, fSurface);
89 fSurface = EGL_NO_SURFACE;
90 }
91
92 if (EGL_NO_DISPLAY != fDisplay) {
93 eglTerminate(fDisplay);
94 fDisplay = EGL_NO_DISPLAY;
95 }
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +000096#endif // SK_ANGLE
hendrikw885bf092015-08-27 10:38:39 -070097#if SK_COMMAND_BUFFER
98 delete fCommandBuffer;
99#endif // SK_COMMAND_BUFFER
100
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000101#endif // SK_SUPPORT_GPU
bsalomon85ab5512015-06-16 12:47:25 -0700102 this->closeWindow();
bsalomon@google.com2858b312012-04-02 20:44:38 +0000103}
104
105static SkKey winToskKey(WPARAM vk) {
106 static const struct {
107 WPARAM fVK;
108 SkKey fKey;
109 } gPair[] = {
110 { VK_BACK, kBack_SkKey },
111 { VK_CLEAR, kBack_SkKey },
112 { VK_RETURN, kOK_SkKey },
113 { VK_UP, kUp_SkKey },
114 { VK_DOWN, kDown_SkKey },
115 { VK_LEFT, kLeft_SkKey },
116 { VK_RIGHT, kRight_SkKey }
117 };
118 for (size_t i = 0; i < SK_ARRAY_COUNT(gPair); i++) {
119 if (gPair[i].fVK == vk) {
120 return gPair[i].fKey;
121 }
122 }
123 return kNONE_SkKey;
124}
125
reed@google.com4d5c26d2013-01-08 16:17:50 +0000126static unsigned getModifiers(UINT message) {
127 return 0; // TODO
128}
129
bsalomon@google.com2858b312012-04-02 20:44:38 +0000130bool SkOSWindow::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
131 switch (message) {
132 case WM_KEYDOWN: {
133 SkKey key = winToskKey(wParam);
134 if (kNONE_SkKey != key) {
135 this->handleKey(key);
136 return true;
137 }
138 } break;
139 case WM_KEYUP: {
140 SkKey key = winToskKey(wParam);
141 if (kNONE_SkKey != key) {
142 this->handleKeyUp(key);
143 return true;
144 }
145 } break;
146 case WM_UNICHAR:
robertphillips@google.com8b169312013-10-15 17:47:36 +0000147 this->handleChar((SkUnichar) wParam);
rmistry@google.comd6176b02012-08-23 18:14:13 +0000148 return true;
bsalomon@google.com2858b312012-04-02 20:44:38 +0000149 case WM_CHAR: {
150 this->handleChar(SkUTF8_ToUnichar((char*)&wParam));
151 return true;
152 } break;
robertphillips@google.coma4662862013-11-21 14:24:16 +0000153 case WM_SIZE: {
154 INT width = LOWORD(lParam);
155 INT height = HIWORD(lParam);
156 this->resize(width, height);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000157 break;
robertphillips@google.coma4662862013-11-21 14:24:16 +0000158 }
bsalomon@google.com2858b312012-04-02 20:44:38 +0000159 case WM_PAINT: {
160 PAINTSTRUCT ps;
161 HDC hdc = BeginPaint(hWnd, &ps);
162 this->doPaint(hdc);
163 EndPaint(hWnd, &ps);
164 return true;
165 } break;
166
rmistry@google.comd6176b02012-08-23 18:14:13 +0000167 case WM_LBUTTONDOWN:
reed@google.com4d5c26d2013-01-08 16:17:50 +0000168 this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
reed@google.com72708fa2013-01-08 16:22:44 +0000169 Click::kDown_State, NULL, getModifiers(message));
bsalomon@google.com2858b312012-04-02 20:44:38 +0000170 return true;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000171
bsalomon@google.com2858b312012-04-02 20:44:38 +0000172 case WM_MOUSEMOVE:
reed@google.com4d5c26d2013-01-08 16:17:50 +0000173 this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
reed@google.com72708fa2013-01-08 16:22:44 +0000174 Click::kMoved_State, NULL, getModifiers(message));
bsalomon@google.com2858b312012-04-02 20:44:38 +0000175 return true;
176
177 case WM_LBUTTONUP:
reed@google.com4d5c26d2013-01-08 16:17:50 +0000178 this->handleClick(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam),
reed@google.com72708fa2013-01-08 16:22:44 +0000179 Click::kUp_State, NULL, getModifiers(message));
bsalomon@google.com2858b312012-04-02 20:44:38 +0000180 return true;
181
182 case WM_EVENT_CALLBACK:
183 if (SkEvent::ProcessEvent()) {
bsalomon1e7951f2015-06-16 07:04:43 -0700184 post_skwinevent(hWnd);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000185 }
186 return true;
187 }
188 return false;
189}
190
191void SkOSWindow::doPaint(void* ctx) {
192 this->update(NULL);
193
194 if (kNone_BackEndType == fAttached)
195 {
196 HDC hdc = (HDC)ctx;
197 const SkBitmap& bitmap = this->getBitmap();
198
199 BITMAPINFO bmi;
200 memset(&bmi, 0, sizeof(bmi));
201 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
202 bmi.bmiHeader.biWidth = bitmap.width();
rmistry@google.comd6176b02012-08-23 18:14:13 +0000203 bmi.bmiHeader.biHeight = -bitmap.height(); // top-down image
bsalomon@google.com2858b312012-04-02 20:44:38 +0000204 bmi.bmiHeader.biPlanes = 1;
205 bmi.bmiHeader.biBitCount = 32;
206 bmi.bmiHeader.biCompression = BI_RGB;
207 bmi.bmiHeader.biSizeImage = 0;
208
rmistry@google.comd6176b02012-08-23 18:14:13 +0000209 //
210 // Do the SetDIBitsToDevice.
211 //
bsalomon@google.com2858b312012-04-02 20:44:38 +0000212 // TODO(wjmaclean):
213 // Fix this call to handle SkBitmaps that have rowBytes != width,
214 // i.e. may have padding at the end of lines. The SkASSERT below
215 // may be ignored by builds, and the only obviously safe option
216 // seems to be to copy the bitmap to a temporary (contiguous)
217 // buffer before passing to SetDIBitsToDevice().
218 SkASSERT(bitmap.width() * bitmap.bytesPerPixel() == bitmap.rowBytes());
219 bitmap.lockPixels();
bsalomon@google.comb58a6392013-03-21 20:29:05 +0000220 int ret = SetDIBitsToDevice(hdc,
bsalomon@google.com2858b312012-04-02 20:44:38 +0000221 0, 0,
222 bitmap.width(), bitmap.height(),
223 0, 0,
224 0, bitmap.height(),
225 bitmap.getPixels(),
226 &bmi,
227 DIB_RGB_COLORS);
bsalomon@google.comb58a6392013-03-21 20:29:05 +0000228 (void)ret; // we're ignoring potential failures for now.
bsalomon@google.com2858b312012-04-02 20:44:38 +0000229 bitmap.unlockPixels();
230 }
231}
232
bsalomon@google.com2858b312012-04-02 20:44:38 +0000233void SkOSWindow::updateSize()
234{
235 RECT r;
bsalomon1e7951f2015-06-16 07:04:43 -0700236 GetWindowRect((HWND)fHWND, &r);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000237 this->resize(r.right - r.left, r.bottom - r.top);
238}
bsalomon@google.com2858b312012-04-02 20:44:38 +0000239
240void SkOSWindow::onHandleInval(const SkIRect& r) {
bsalomone0ef4a72015-06-15 12:49:55 -0700241 RECT rect;
242 rect.left = r.fLeft;
243 rect.top = r.fTop;
244 rect.right = r.fRight;
245 rect.bottom = r.fBottom;
246 InvalidateRect((HWND)fHWND, &rect, FALSE);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000247}
248
249void SkOSWindow::onAddMenu(const SkOSMenu* sk_menu)
250{
251}
252
253void SkOSWindow::onSetTitle(const char title[]){
254 SetWindowTextA((HWND)fHWND, title);
255}
256
257enum {
258 SK_MacReturnKey = 36,
259 SK_MacDeleteKey = 51,
260 SK_MacEndKey = 119,
261 SK_MacLeftKey = 123,
262 SK_MacRightKey = 124,
263 SK_MacDownKey = 125,
264 SK_MacUpKey = 126,
rmistry@google.comd6176b02012-08-23 18:14:13 +0000265
bsalomon@google.com2858b312012-04-02 20:44:38 +0000266 SK_Mac0Key = 0x52,
267 SK_Mac1Key = 0x53,
268 SK_Mac2Key = 0x54,
269 SK_Mac3Key = 0x55,
270 SK_Mac4Key = 0x56,
271 SK_Mac5Key = 0x57,
272 SK_Mac6Key = 0x58,
273 SK_Mac7Key = 0x59,
274 SK_Mac8Key = 0x5b,
275 SK_Mac9Key = 0x5c
276};
rmistry@google.comd6176b02012-08-23 18:14:13 +0000277
bsalomon@google.com2858b312012-04-02 20:44:38 +0000278static SkKey raw2key(uint32_t raw)
279{
280 static const struct {
281 uint32_t fRaw;
282 SkKey fKey;
283 } gKeys[] = {
284 { SK_MacUpKey, kUp_SkKey },
285 { SK_MacDownKey, kDown_SkKey },
286 { SK_MacLeftKey, kLeft_SkKey },
287 { SK_MacRightKey, kRight_SkKey },
288 { SK_MacReturnKey, kOK_SkKey },
289 { SK_MacDeleteKey, kBack_SkKey },
290 { SK_MacEndKey, kEnd_SkKey },
291 { SK_Mac0Key, k0_SkKey },
292 { SK_Mac1Key, k1_SkKey },
293 { SK_Mac2Key, k2_SkKey },
294 { SK_Mac3Key, k3_SkKey },
295 { SK_Mac4Key, k4_SkKey },
296 { SK_Mac5Key, k5_SkKey },
297 { SK_Mac6Key, k6_SkKey },
298 { SK_Mac7Key, k7_SkKey },
299 { SK_Mac8Key, k8_SkKey },
300 { SK_Mac9Key, k9_SkKey }
301 };
rmistry@google.comd6176b02012-08-23 18:14:13 +0000302
bsalomon@google.com2858b312012-04-02 20:44:38 +0000303 for (unsigned i = 0; i < SK_ARRAY_COUNT(gKeys); i++)
304 if (gKeys[i].fRaw == raw)
305 return gKeys[i].fKey;
306 return kNONE_SkKey;
307}
308
309///////////////////////////////////////////////////////////////////////////////////////
310
311void SkEvent::SignalNonEmptyQueue()
312{
bsalomon1e7951f2015-06-16 07:04:43 -0700313 SkOSWindow::ForAllWindows([](void* hWND, SkOSWindow**) {
314 post_skwinevent((HWND)hWND);
315 });
bsalomon@google.com2858b312012-04-02 20:44:38 +0000316}
317
318static UINT_PTR gTimer;
319
320VOID CALLBACK sk_timer_proc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
321{
322 SkEvent::ServiceQueueTimer();
323 //SkDebugf("timer task fired\n");
324}
325
326void SkEvent::SignalQueueTimer(SkMSec delay)
327{
328 if (gTimer)
329 {
330 KillTimer(NULL, gTimer);
331 gTimer = NULL;
332 }
333 if (delay)
rmistry@google.comd6176b02012-08-23 18:14:13 +0000334 {
bsalomon@google.com2858b312012-04-02 20:44:38 +0000335 gTimer = SetTimer(NULL, 0, delay, sk_timer_proc);
336 //SkDebugf("SetTimer of %d returned %d\n", delay, gTimer);
337 }
338}
339
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000340#if SK_SUPPORT_GPU
bsalomon@google.com2858b312012-04-02 20:44:38 +0000341
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000342bool SkOSWindow::attachGL(int msaaSampleCount, AttachmentInfo* info) {
bsalomon@google.comb7f20f22013-03-05 19:13:09 +0000343 HDC dc = GetDC((HWND)fHWND);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000344 if (NULL == fHGLRC) {
kkinnunen80549fc2014-06-30 06:36:31 -0700345 fHGLRC = SkCreateWGLContext(dc, msaaSampleCount,
346 kGLPreferCompatibilityProfile_SkWGLContextRequest);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000347 if (NULL == fHGLRC) {
348 return false;
349 }
350 glClearStencil(0);
351 glClearColor(0, 0, 0, 0);
352 glStencilMask(0xffffffff);
353 glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
354 }
bsalomon@google.comb7f20f22013-03-05 19:13:09 +0000355 if (wglMakeCurrent(dc, (HGLRC)fHGLRC)) {
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000356 // use DescribePixelFormat to get the stencil bit depth.
357 int pixelFormat = GetPixelFormat(dc);
358 PIXELFORMATDESCRIPTOR pfd;
359 DescribePixelFormat(dc, pixelFormat, sizeof(pfd), &pfd);
360 info->fStencilBits = pfd.cStencilBits;
361
362 // Get sample count if the MSAA WGL extension is present
363 SkWGLExtensions extensions;
364 if (extensions.hasExtension(dc, "WGL_ARB_multisample")) {
365 static const int kSampleCountAttr = SK_WGL_SAMPLES;
366 extensions.getPixelFormatAttribiv(dc,
367 pixelFormat,
368 0,
369 1,
370 &kSampleCountAttr,
371 &info->fSampleCount);
372 } else {
373 info->fSampleCount = 0;
374 }
375
reed@google.come1ca7052013-12-17 19:22:07 +0000376 glViewport(0, 0,
377 SkScalarRoundToInt(this->width()),
378 SkScalarRoundToInt(this->height()));
bsalomon@google.com2858b312012-04-02 20:44:38 +0000379 return true;
380 }
381 return false;
382}
383
384void SkOSWindow::detachGL() {
385 wglMakeCurrent(GetDC((HWND)fHWND), 0);
386 wglDeleteContext((HGLRC)fHGLRC);
387 fHGLRC = NULL;
388}
389
390void SkOSWindow::presentGL() {
bungeman@google.comf44957e2013-03-12 17:27:10 +0000391 HDC dc = GetDC((HWND)fHWND);
392 SwapBuffers(dc);
393 ReleaseDC((HWND)fHWND, dc);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000394}
395
396#if SK_ANGLE
bsalomon42380172015-02-23 08:57:23 -0800397
bsalomon@google.com11959252012-04-06 20:13:38 +0000398bool create_ANGLE(EGLNativeWindowType hWnd,
399 int msaaSampleCount,
400 EGLDisplay* eglDisplay,
401 EGLContext* eglContext,
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000402 EGLSurface* eglSurface,
403 EGLConfig* eglConfig) {
bsalomon@google.com11959252012-04-06 20:13:38 +0000404 static const EGLint contextAttribs[] = {
405 EGL_CONTEXT_CLIENT_VERSION, 2,
rmistry@google.comd6176b02012-08-23 18:14:13 +0000406 EGL_NONE, EGL_NONE
bsalomon@google.com2858b312012-04-02 20:44:38 +0000407 };
bsalomon@google.com11959252012-04-06 20:13:38 +0000408 static const EGLint configAttribList[] = {
bsalomon@google.com2858b312012-04-02 20:44:38 +0000409 EGL_RED_SIZE, 8,
410 EGL_GREEN_SIZE, 8,
411 EGL_BLUE_SIZE, 8,
412 EGL_ALPHA_SIZE, 8,
413 EGL_DEPTH_SIZE, 8,
414 EGL_STENCIL_SIZE, 8,
415 EGL_NONE
416 };
bsalomon@google.com11959252012-04-06 20:13:38 +0000417 static const EGLint surfaceAttribList[] = {
bsalomon@google.com2858b312012-04-02 20:44:38 +0000418 EGL_NONE, EGL_NONE
419 };
420
hendrikweddbefb2015-09-11 13:07:29 -0700421 EGLDisplay display = SkANGLEGLContext::GetD3DEGLDisplay(GetDC(hWnd), false);
bsalomon42380172015-02-23 08:57:23 -0800422
423 if (EGL_NO_DISPLAY == display) {
424 SkDebugf("Could not create ANGLE egl display!\n");
425 return false;
bsalomon@google.com2858b312012-04-02 20:44:38 +0000426 }
427
428 // Initialize EGL
429 EGLint majorVersion, minorVersion;
430 if (!eglInitialize(display, &majorVersion, &minorVersion)) {
431 return false;
432 }
433
434 EGLint numConfigs;
435 if (!eglGetConfigs(display, NULL, 0, &numConfigs)) {
436 return false;
437 }
438
439 // Choose config
bsalomon@google.com11959252012-04-06 20:13:38 +0000440 bool foundConfig = false;
441 if (msaaSampleCount) {
442 static const int kConfigAttribListCnt =
443 SK_ARRAY_COUNT(configAttribList);
444 EGLint msaaConfigAttribList[kConfigAttribListCnt + 4];
445 memcpy(msaaConfigAttribList,
446 configAttribList,
447 sizeof(configAttribList));
448 SkASSERT(EGL_NONE == msaaConfigAttribList[kConfigAttribListCnt - 1]);
449 msaaConfigAttribList[kConfigAttribListCnt - 1] = EGL_SAMPLE_BUFFERS;
450 msaaConfigAttribList[kConfigAttribListCnt + 0] = 1;
451 msaaConfigAttribList[kConfigAttribListCnt + 1] = EGL_SAMPLES;
452 msaaConfigAttribList[kConfigAttribListCnt + 2] = msaaSampleCount;
453 msaaConfigAttribList[kConfigAttribListCnt + 3] = EGL_NONE;
hendrikw15120292015-09-08 05:53:23 -0700454 if (eglChooseConfig(display, msaaConfigAttribList, eglConfig, 1, &numConfigs)) {
bsalomon@google.com11959252012-04-06 20:13:38 +0000455 SkASSERT(numConfigs > 0);
456 foundConfig = true;
457 }
458 }
459 if (!foundConfig) {
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000460 if (!eglChooseConfig(display, configAttribList, eglConfig, 1, &numConfigs)) {
bsalomon@google.com11959252012-04-06 20:13:38 +0000461 return false;
462 }
bsalomon@google.com2858b312012-04-02 20:44:38 +0000463 }
464
465 // Create a surface
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000466 EGLSurface surface = eglCreateWindowSurface(display, *eglConfig,
rmistry@google.comd6176b02012-08-23 18:14:13 +0000467 (EGLNativeWindowType)hWnd,
bsalomon@google.com2858b312012-04-02 20:44:38 +0000468 surfaceAttribList);
469 if (surface == EGL_NO_SURFACE) {
470 return false;
471 }
472
473 // Create a GL context
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000474 EGLContext context = eglCreateContext(display, *eglConfig,
bsalomon@google.com2858b312012-04-02 20:44:38 +0000475 EGL_NO_CONTEXT,
476 contextAttribs );
477 if (context == EGL_NO_CONTEXT ) {
478 return false;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000479 }
480
bsalomon@google.com2858b312012-04-02 20:44:38 +0000481 // Make the context current
482 if (!eglMakeCurrent(display, surface, surface, context)) {
483 return false;
484 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000485
bsalomon@google.com2858b312012-04-02 20:44:38 +0000486 *eglDisplay = display;
487 *eglContext = context;
488 *eglSurface = surface;
489 return true;
490}
491
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000492bool SkOSWindow::attachANGLE(int msaaSampleCount, AttachmentInfo* info) {
bsalomon@google.com2858b312012-04-02 20:44:38 +0000493 if (EGL_NO_DISPLAY == fDisplay) {
bsalomon@google.com11959252012-04-06 20:13:38 +0000494 bool bResult = create_ANGLE((HWND)fHWND,
495 msaaSampleCount,
496 &fDisplay,
497 &fContext,
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000498 &fSurface,
499 &fConfig);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000500 if (false == bResult) {
501 return false;
502 }
bsalomon@google.com82502e22013-01-24 20:47:18 +0000503 SkAutoTUnref<const GrGLInterface> intf(GrGLCreateANGLEInterface());
bsalomon@google.com2858b312012-04-02 20:44:38 +0000504
505 if (intf) {
borenet@google.com0dd5ceb2012-08-28 15:15:49 +0000506 ANGLE_GL_CALL(intf, ClearStencil(0));
507 ANGLE_GL_CALL(intf, ClearColor(0, 0, 0, 0));
508 ANGLE_GL_CALL(intf, StencilMask(0xffffffff));
509 ANGLE_GL_CALL(intf, Clear(GL_STENCIL_BUFFER_BIT |GL_COLOR_BUFFER_BIT));
bsalomon@google.com2858b312012-04-02 20:44:38 +0000510 }
511 }
512 if (eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000513 eglGetConfigAttrib(fDisplay, fConfig, EGL_STENCIL_SIZE, &info->fStencilBits);
514 eglGetConfigAttrib(fDisplay, fConfig, EGL_SAMPLES, &info->fSampleCount);
515
bsalomon@google.com82502e22013-01-24 20:47:18 +0000516 SkAutoTUnref<const GrGLInterface> intf(GrGLCreateANGLEInterface());
bsalomon@google.com2858b312012-04-02 20:44:38 +0000517
518 if (intf ) {
reed@google.come1ca7052013-12-17 19:22:07 +0000519 ANGLE_GL_CALL(intf, Viewport(0, 0,
520 SkScalarRoundToInt(this->width()),
521 SkScalarRoundToInt(this->height())));
bsalomon@google.com2858b312012-04-02 20:44:38 +0000522 }
523 return true;
524 }
525 return false;
526}
527
528void SkOSWindow::detachANGLE() {
529 eglMakeCurrent(fDisplay, EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT);
530
531 eglDestroyContext(fDisplay, fContext);
532 fContext = EGL_NO_CONTEXT;
533
534 eglDestroySurface(fDisplay, fSurface);
535 fSurface = EGL_NO_SURFACE;
536
537 eglTerminate(fDisplay);
538 fDisplay = EGL_NO_DISPLAY;
539}
540
541void SkOSWindow::presentANGLE() {
bsalomon@google.com82502e22013-01-24 20:47:18 +0000542 SkAutoTUnref<const GrGLInterface> intf(GrGLCreateANGLEInterface());
bsalomon@google.com2858b312012-04-02 20:44:38 +0000543
544 if (intf) {
borenet@google.com0dd5ceb2012-08-28 15:15:49 +0000545 ANGLE_GL_CALL(intf, Flush());
bsalomon@google.com2858b312012-04-02 20:44:38 +0000546 }
547
548 eglSwapBuffers(fDisplay, fSurface);
549}
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000550#endif // SK_ANGLE
hendrikw885bf092015-08-27 10:38:39 -0700551
552#if SK_COMMAND_BUFFER
553
554bool SkOSWindow::attachCommandBuffer(int msaaSampleCount, AttachmentInfo* info) {
555 if (!fCommandBuffer) {
556 fCommandBuffer = SkCommandBufferGLContext::Create((HWND)fHWND, msaaSampleCount);
557 if (!fCommandBuffer)
558 return false;
559
560 SkAutoTUnref<const GrGLInterface> intf(GrGLCreateCommandBufferInterface());
561 if (intf) {
562 COMMAND_BUFFER_GL_CALL(intf, ClearStencil(0));
563 COMMAND_BUFFER_GL_CALL(intf, ClearColor(0, 0, 0, 0));
564 COMMAND_BUFFER_GL_CALL(intf, StencilMask(0xffffffff));
565 COMMAND_BUFFER_GL_CALL(intf, Clear(GL_STENCIL_BUFFER_BIT |GL_COLOR_BUFFER_BIT));
566 }
567 }
568
569 if (fCommandBuffer->makeCurrent()) {
570 info->fStencilBits = fCommandBuffer->getStencilBits();
571 info->fSampleCount = fCommandBuffer->getSampleCount();
572
573 SkAutoTUnref<const GrGLInterface> intf(GrGLCreateCommandBufferInterface());
574
575 if (intf ) {
576 COMMAND_BUFFER_GL_CALL(intf, Viewport(0, 0,
577 SkScalarRoundToInt(this->width()),
578 SkScalarRoundToInt(this->height())));
579 }
580 return true;
581 }
582 return false;
583}
584
585void SkOSWindow::detachCommandBuffer() {
586 delete fCommandBuffer;
587 fCommandBuffer = nullptr;
588}
589
590void SkOSWindow::presentCommandBuffer() {
591 fCommandBuffer->presentCommandBuffer();
592}
593#endif // SK_COMMAND_BUFFER
594
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000595#endif // SK_SUPPORT_GPU
bsalomon@google.com2858b312012-04-02 20:44:38 +0000596
bsalomon@google.com2858b312012-04-02 20:44:38 +0000597// return true on success
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000598bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo* info) {
bsalomon@google.com2858b312012-04-02 20:44:38 +0000599
600 // attach doubles as "windowResize" so we need to allo
601 // already bound states to pass through again
602 // TODO: split out the resize functionality
603// SkASSERT(kNone_BackEndType == fAttached);
604 bool result = true;
605
606 switch (attachType) {
607 case kNone_BackEndType:
608 // nothing to do
rmistry@google.comd6176b02012-08-23 18:14:13 +0000609 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000610#if SK_SUPPORT_GPU
bsalomon@google.com2858b312012-04-02 20:44:38 +0000611 case kNativeGL_BackEndType:
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000612 result = attachGL(msaaSampleCount, info);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000613 break;
614#if SK_ANGLE
615 case kANGLE_BackEndType:
bsalomon@google.com64cc8102013-03-05 20:06:05 +0000616 result = attachANGLE(msaaSampleCount, info);
bsalomon@google.com2858b312012-04-02 20:44:38 +0000617 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000618#endif // SK_ANGLE
hendrikw885bf092015-08-27 10:38:39 -0700619#if SK_COMMAND_BUFFER
620 case kCommandBuffer_BackEndType:
621 result = attachCommandBuffer(msaaSampleCount, info);
622 break;
623#endif // SK_COMMAND_BUFFER
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000624#endif // SK_SUPPORT_GPU
bsalomon@google.com2858b312012-04-02 20:44:38 +0000625 default:
626 SkASSERT(false);
627 result = false;
628 break;
629 }
630
631 if (result) {
632 fAttached = attachType;
633 }
634
635 return result;
636}
637
638void SkOSWindow::detach() {
639 switch (fAttached) {
640 case kNone_BackEndType:
641 // nothing to do
rmistry@google.comd6176b02012-08-23 18:14:13 +0000642 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000643#if SK_SUPPORT_GPU
bsalomon@google.com2858b312012-04-02 20:44:38 +0000644 case kNativeGL_BackEndType:
645 detachGL();
646 break;
647#if SK_ANGLE
648 case kANGLE_BackEndType:
649 detachANGLE();
650 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000651#endif // SK_ANGLE
hendrikw885bf092015-08-27 10:38:39 -0700652#if SK_COMMAND_BUFFER
653 case kCommandBuffer_BackEndType:
654 detachCommandBuffer();
655 break;
656#endif // SK_COMMAND_BUFFER
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000657#endif // SK_SUPPORT_GPU
bsalomon@google.com2858b312012-04-02 20:44:38 +0000658 default:
659 SkASSERT(false);
660 break;
661 }
662 fAttached = kNone_BackEndType;
663}
664
665void SkOSWindow::present() {
666 switch (fAttached) {
667 case kNone_BackEndType:
668 // nothing to do
rmistry@google.comd6176b02012-08-23 18:14:13 +0000669 return;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000670#if SK_SUPPORT_GPU
bsalomon@google.com2858b312012-04-02 20:44:38 +0000671 case kNativeGL_BackEndType:
672 presentGL();
673 break;
674#if SK_ANGLE
675 case kANGLE_BackEndType:
676 presentANGLE();
677 break;
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000678#endif // SK_ANGLE
hendrikw885bf092015-08-27 10:38:39 -0700679#if SK_COMMAND_BUFFER
680 case kCommandBuffer_BackEndType:
681 presentCommandBuffer();
682 break;
683#endif // SK_COMMAND_BUFFER
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000684#endif // SK_SUPPORT_GPU
bsalomon@google.com2858b312012-04-02 20:44:38 +0000685 default:
686 SkASSERT(false);
687 break;
688 }
689}
690
bsalomon85ab5512015-06-16 12:47:25 -0700691bool SkOSWindow::makeFullscreen() {
692 if (fFullscreen) {
693 return true;
bsalomon1e7951f2015-06-16 07:04:43 -0700694 }
695 if (fHGLRC) {
696 this->detachGL();
697 }
698 // This is hacked together from various sources on the web. It can certainly be improved and be
699 // made more robust.
bsalomon1e7951f2015-06-16 07:04:43 -0700700
bsalomon85ab5512015-06-16 12:47:25 -0700701 // Save current window/resolution information. We do this in case we ever implement switching
702 // back to windowed mode.
703 fSavedWindowState.fZoomed = SkToBool(IsZoomed((HWND)fHWND));
704 if (fSavedWindowState.fZoomed) {
705 SendMessage((HWND)fHWND, WM_SYSCOMMAND, SC_RESTORE, 0);
bsalomon1e7951f2015-06-16 07:04:43 -0700706 }
bsalomon85ab5512015-06-16 12:47:25 -0700707 fSavedWindowState.fStyle = GetWindowLong((HWND)fHWND, GWL_STYLE);
708 fSavedWindowState.fExStyle = GetWindowLong((HWND)fHWND, GWL_EXSTYLE);
709 GetWindowRect((HWND)fHWND, &fSavedWindowState.fRect);
710 DEVMODE currScreenSettings;
711 memset(&currScreenSettings,0,sizeof(currScreenSettings));
712 currScreenSettings.dmSize = sizeof(currScreenSettings);
713 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &currScreenSettings);
714 fSavedWindowState.fScreenWidth = currScreenSettings.dmPelsWidth;
715 fSavedWindowState.fScreenHeight = currScreenSettings.dmPelsHeight;
716 fSavedWindowState.fScreenBits = currScreenSettings.dmBitsPerPel;
717 fSavedWindowState.fHWND = fHWND;
718
719 // Try different sizes to find an allowed setting? Use ChangeDisplaySettingsEx?
720 static const int kWidth = 1280;
721 static const int kHeight = 1024;
722 DEVMODE newScreenSettings;
723 memset(&newScreenSettings, 0, sizeof(newScreenSettings));
724 newScreenSettings.dmSize = sizeof(newScreenSettings);
725 newScreenSettings.dmPelsWidth = kWidth;
726 newScreenSettings.dmPelsHeight = kHeight;
727 newScreenSettings.dmBitsPerPel = 32;
728 newScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
729 if (ChangeDisplaySettings(&newScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
730 return false;
731 }
732 RECT WindowRect;
733 WindowRect.left = 0;
734 WindowRect.right = kWidth;
735 WindowRect.top = 0;
736 WindowRect.bottom = kHeight;
737 ShowCursor(FALSE);
738 AdjustWindowRectEx(&WindowRect, WS_POPUP, FALSE, WS_EX_APPWINDOW);
739 HWND fsHWND = CreateWindowEx(
740 WS_EX_APPWINDOW,
741 fWinInit.fClass,
742 NULL,
743 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
744 0, 0, WindowRect.right-WindowRect.left, WindowRect.bottom-WindowRect.top,
745 NULL,
746 NULL,
747 fWinInit.fInstance,
748 NULL
749 );
750 if (!fsHWND) {
751 return false;
752 }
753 // Hide the old window and set the entry in the global mapping for this SkOSWindow to the
754 // new HWND.
755 ShowWindow((HWND)fHWND, SW_HIDE);
756 gHwndToOSWindowMap.remove(fHWND);
757 fHWND = fsHWND;
758 gHwndToOSWindowMap.set(fHWND, this);
759 this->updateSize();
760
761 fFullscreen = true;
762 return true;
bsalomon1e7951f2015-06-16 07:04:43 -0700763}
764
765void SkOSWindow::setVsync(bool enable) {
766 SkWGLExtensions wgl;
767 wgl.swapInterval(enable ? 1 : 0);
768}
769
770void SkOSWindow::closeWindow() {
bsalomon1e7951f2015-06-16 07:04:43 -0700771 DestroyWindow((HWND)fHWND);
bsalomon85ab5512015-06-16 12:47:25 -0700772 if (fFullscreen) {
773 DestroyWindow((HWND)fSavedWindowState.fHWND);
774 }
775 gHwndToOSWindowMap.remove(fHWND);
bsalomon1e7951f2015-06-16 07:04:43 -0700776}
bsalomon@google.com2858b312012-04-02 20:44:38 +0000777#endif