1 /*
2 * Copyright 2015 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
8 #include "SkOSWindow_Android.h"
9
10 #include <GLES/gl.h>
11
SkOSWindow(void * hwnd)12 SkOSWindow::SkOSWindow(void* hwnd) {
13 fWindow.fDisplay = EGL_NO_DISPLAY;
14 fWindow.fContext = EGL_NO_CONTEXT;
15 fWindow.fSurface = EGL_NO_SURFACE;
16 fNativeWindow = (ANativeWindow*)hwnd;
17 fDestroyRequested = false;
18 }
19
~SkOSWindow()20 SkOSWindow::~SkOSWindow() {
21 this->detach();
22 }
23
attach(SkBackEndTypes attachType,int,AttachmentInfo * info)24 bool SkOSWindow::attach(SkBackEndTypes attachType,
25 int /*msaaSampleCount*/,
26 AttachmentInfo* info) {
27 static const EGLint kEGLContextAttribsForOpenGL[] = {
28 EGL_NONE
29 };
30
31 static const EGLint kEGLContextAttribsForOpenGLES[] = {
32 EGL_CONTEXT_CLIENT_VERSION, 2,
33 EGL_NONE
34 };
35
36 static const struct {
37 const EGLint* fContextAttribs;
38 EGLenum fAPI;
39 EGLint fRenderableTypeBit;
40 } kAPIs[] = {
41 { // OpenGL
42 kEGLContextAttribsForOpenGL,
43 EGL_OPENGL_API,
44 EGL_OPENGL_BIT,
45 },
46 { // OpenGL ES. This seems to work for both ES2 and 3 (when available).
47 kEGLContextAttribsForOpenGLES,
48 EGL_OPENGL_ES_API,
49 EGL_OPENGL_ES2_BIT,
50 },
51 };
52
53 EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
54 if (EGL_NO_DISPLAY == display) {
55 return false;
56 }
57
58 EGLint majorVersion;
59 EGLint minorVersion;
60 if (!eglInitialize(display, &majorVersion, &minorVersion)) {
61 return false;
62 }
63
64 for (size_t api = 0; api < SK_ARRAY_COUNT(kAPIs); ++api) {
65 if (!eglBindAPI(kAPIs[api].fAPI)) {
66 continue;
67 }
68 #if 0
69 SkDebugf("VENDOR: %s\n", eglQueryString(fDisplay, EGL_VENDOR));
70 SkDebugf("APIS: %s\n", eglQueryString(fDisplay, EGL_CLIENT_APIS));
71 SkDebugf("VERSION: %s\n", eglQueryString(fDisplay, EGL_VERSION));
72 SkDebugf("EXTENSIONS %s\n", eglQueryString(fDisplay, EGL_EXTENSIONS));
73 #endif
74
75 const EGLint configAttribs[] = {
76 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
77 EGL_RENDERABLE_TYPE, kAPIs[api].fRenderableTypeBit,
78 EGL_RED_SIZE, 8,
79 EGL_GREEN_SIZE, 8,
80 EGL_BLUE_SIZE, 8,
81 EGL_ALPHA_SIZE, 8,
82 EGL_NONE
83 };
84
85 EGLint format;
86 EGLint numConfigs;
87 EGLConfig config;
88 EGLSurface surface;
89 EGLContext context;
90
91 /* Here, the application chooses the configuration it desires. In this
92 * sample, we have a very simplified selection process, where we pick
93 * the first EGLConfig that matches our criteria */
94 if (!eglChooseConfig(display, configAttribs, &config, 1, &numConfigs) ||
95 numConfigs != 1) {
96 continue;
97 }
98
99 /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
100 * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
101 * As soon as we picked a EGLConfig, we can safely reconfigure the
102 * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
103 if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) {
104 continue;
105 }
106
107 ANativeWindow_setBuffersGeometry(fNativeWindow, 0, 0, format);
108
109 surface = eglCreateWindowSurface(display, config, fNativeWindow, nullptr);
110 if (EGL_NO_SURFACE == surface) {
111 SkDebugf("eglCreateWindowSurface failed. EGL Error: 0x%08x\n", eglGetError());
112 continue;
113 }
114 context = eglCreateContext(display, config, nullptr, kAPIs[api].fContextAttribs);
115 if (EGL_NO_CONTEXT == context) {
116 SkDebugf("eglCreateContext failed. EGL Error: 0x%08x\n", eglGetError());
117 eglDestroySurface(display, surface);
118 continue;
119 }
120
121 if (!eglMakeCurrent(display, surface, surface, context)) {
122 SkDebugf("eglMakeCurrent failed. EGL Error: 0x%08x\n", eglGetError());
123 eglDestroyContext(display, context);
124 eglDestroySurface(display, surface);
125 continue;
126 }
127
128 fWindow.fDisplay = display;
129 fWindow.fContext = context;
130 fWindow.fSurface = surface;
131 break;
132 }
133
134 if (fWindow.fDisplay && fWindow.fContext && fWindow.fSurface) {
135 EGLint w, h;
136 eglQuerySurface(fWindow.fDisplay, fWindow.fSurface, EGL_WIDTH, &w);
137 eglQuerySurface(fWindow.fDisplay, fWindow.fSurface, EGL_HEIGHT, &h);
138
139 glViewport(0, 0, w, h);
140 glClearColor(0.0, 0, 0, 0.0);
141 glClearStencil(0);
142 glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
143
144 // We retrieve the fullscreen width and height
145 this->setSize((SkScalar)w, (SkScalar)h);
146 return true;
147 } else {
148 return false;
149 }
150 }
151
detach()152 void SkOSWindow::detach() {
153 if (fWindow.fDisplay != EGL_NO_DISPLAY) {
154 eglMakeCurrent(fWindow.fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
155 if (fWindow.fContext != EGL_NO_CONTEXT) {
156 eglDestroyContext(fWindow.fDisplay, fWindow.fContext);
157 }
158 if (fWindow.fSurface != EGL_NO_SURFACE) {
159 eglDestroySurface(fWindow.fDisplay, fWindow.fSurface);
160 }
161 eglTerminate(fWindow.fDisplay);
162 }
163 fWindow.fDisplay = EGL_NO_DISPLAY;
164 fWindow.fContext = EGL_NO_CONTEXT;
165 fWindow.fSurface = EGL_NO_SURFACE;
166 }
167
present()168 void SkOSWindow::present() {
169 if (fWindow.fDisplay != EGL_NO_DISPLAY && fWindow.fContext != EGL_NO_CONTEXT) {
170 eglSwapBuffers(fWindow.fDisplay, fWindow.fSurface);
171 }
172 }
173
closeWindow()174 void SkOSWindow::closeWindow() {
175 fDestroyRequested = true;
176 }
177
setVsync(bool vsync)178 void SkOSWindow::setVsync(bool vsync) {
179 if (fWindow.fDisplay != EGL_NO_DISPLAY) {
180 int swapInterval = vsync ? 1 : 0;
181 eglSwapInterval(fWindow.fDisplay, swapInterval);
182 }
183 }
184
onSetTitle(const char title[])185 void SkOSWindow::onSetTitle(const char title[]) {
186 }
187
onHandleInval(const SkIRect & rect)188 void SkOSWindow::onHandleInval(const SkIRect& rect) {
189 }
190
191 ///////////////////////////////////////////
192 /////////////// SkEvent impl //////////////
193 ///////////////////////////////////////////
194
SignalQueueTimer(SkMSec ms)195 void SkEvent::SignalQueueTimer(SkMSec ms) {
196 }
197
SignalNonEmptyQueue()198 void SkEvent::SignalNonEmptyQueue() {
199 }
200