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