1 /*
2 ** Copyright 2007, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17 #define __STDC_LIMIT_MACROS 1
18 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
19
20 #include "egl_display.h"
21
22 #include "../egl_impl.h"
23
24 #include <private/EGL/display.h>
25
26 #include "egl_cache.h"
27 #include "egl_object.h"
28 #include "egl_tls.h"
29 #include "egl_trace.h"
30 #include "Loader.h"
31 #include <cutils/properties.h>
32
33 // ----------------------------------------------------------------------------
34 namespace android {
35 // ----------------------------------------------------------------------------
36
37 static char const * const sVendorString = "Android";
38 static char const * const sVersionString = "1.4 Android META-EGL";
39 static char const * const sClientApiString = "OpenGL_ES";
40
41 extern char const * const gBuiltinExtensionString;
42 extern char const * const gExtensionString;
43
44 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
45
46 // ----------------------------------------------------------------------------
47
findExtension(const char * exts,const char * name,size_t nameLen)48 static bool findExtension(const char* exts, const char* name, size_t nameLen) {
49 if (exts) {
50 for (const char* match = strstr(exts, name); match; match = strstr(match + nameLen, name)) {
51 if (match[nameLen] == '\0' || match[nameLen] == ' ') {
52 return true;
53 }
54 }
55 }
56 return false;
57 }
58
egl_get_init_count(EGLDisplay dpy)59 int egl_get_init_count(EGLDisplay dpy) {
60 egl_display_t* eglDisplay = egl_display_t::get(dpy);
61 return eglDisplay ? eglDisplay->getRefsCount() : 0;
62 }
63
64 egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
65
egl_display_t()66 egl_display_t::egl_display_t() :
67 magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0), eglIsInitialized(false) {
68 }
69
~egl_display_t()70 egl_display_t::~egl_display_t() {
71 magic = 0;
72 egl_cache_t::get()->terminate();
73 }
74
get(EGLDisplay dpy)75 egl_display_t* egl_display_t::get(EGLDisplay dpy) {
76 uintptr_t index = uintptr_t(dpy)-1U;
77 if (index >= NUM_DISPLAYS || !sDisplay[index].isValid()) {
78 return nullptr;
79 }
80 return &sDisplay[index];
81 }
82
addObject(egl_object_t * object)83 void egl_display_t::addObject(egl_object_t* object) {
84 std::lock_guard<std::mutex> _l(lock);
85 objects.insert(object);
86 }
87
removeObject(egl_object_t * object)88 void egl_display_t::removeObject(egl_object_t* object) {
89 std::lock_guard<std::mutex> _l(lock);
90 objects.erase(object);
91 }
92
getObject(egl_object_t * object) const93 bool egl_display_t::getObject(egl_object_t* object) const {
94 std::lock_guard<std::mutex> _l(lock);
95 if (objects.find(object) != objects.end()) {
96 if (object->getDisplay() == this) {
97 object->incRef();
98 return true;
99 }
100 }
101 return false;
102 }
103
getFromNativeDisplay(EGLNativeDisplayType disp)104 EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
105 if (uintptr_t(disp) >= NUM_DISPLAYS)
106 return NULL;
107
108 return sDisplay[uintptr_t(disp)].getDisplay(disp);
109 }
110
getDisplay(EGLNativeDisplayType display)111 EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
112
113 std::lock_guard<std::mutex> _l(lock);
114 ATRACE_CALL();
115
116 // get our driver loader
117 Loader& loader(Loader::getInstance());
118
119 egl_connection_t* const cnx = &gEGLImpl;
120 if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) {
121 EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
122 disp.dpy = dpy;
123 if (dpy == EGL_NO_DISPLAY) {
124 loader.close(cnx->dso);
125 cnx->dso = NULL;
126 }
127 }
128
129 return EGLDisplay(uintptr_t(display) + 1U);
130 }
131
initialize(EGLint * major,EGLint * minor)132 EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {
133
134 { // scope for refLock
135 std::unique_lock<std::mutex> _l(refLock);
136 refs++;
137 if (refs > 1) {
138 if (major != NULL)
139 *major = VERSION_MAJOR;
140 if (minor != NULL)
141 *minor = VERSION_MINOR;
142 while(!eglIsInitialized) {
143 refCond.wait(_l);
144 }
145 return EGL_TRUE;
146 }
147 while(eglIsInitialized) {
148 refCond.wait(_l);
149 }
150 }
151
152 { // scope for lock
153 std::lock_guard<std::mutex> _l(lock);
154
155 setGLHooksThreadSpecific(&gHooksNoContext);
156
157 // initialize each EGL and
158 // build our own extension string first, based on the extension we know
159 // and the extension supported by our client implementation
160
161 egl_connection_t* const cnx = &gEGLImpl;
162 cnx->major = -1;
163 cnx->minor = -1;
164 if (cnx->dso) {
165 EGLDisplay idpy = disp.dpy;
166 if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
167 //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p",
168 // idpy, cnx->major, cnx->minor, cnx);
169
170 // display is now initialized
171 disp.state = egl_display_t::INITIALIZED;
172
173 // get the query-strings for this display for each implementation
174 disp.queryString.vendor = cnx->egl.eglQueryString(idpy,
175 EGL_VENDOR);
176 disp.queryString.version = cnx->egl.eglQueryString(idpy,
177 EGL_VERSION);
178 disp.queryString.extensions = cnx->egl.eglQueryString(idpy,
179 EGL_EXTENSIONS);
180 disp.queryString.clientApi = cnx->egl.eglQueryString(idpy,
181 EGL_CLIENT_APIS);
182
183 } else {
184 ALOGW("eglInitialize(%p) failed (%s)", idpy,
185 egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
186 }
187 }
188
189 // the query strings are per-display
190 mVendorString = sVendorString;
191 mVersionString = sVersionString;
192 mClientApiString = sClientApiString;
193
194 mExtensionString = gBuiltinExtensionString;
195 char const* start = gExtensionString;
196 do {
197 // length of the extension name
198 size_t len = strcspn(start, " ");
199 if (len) {
200 // NOTE: we could avoid the copy if we had strnstr.
201 const std::string ext(start, len);
202 if (findExtension(disp.queryString.extensions, ext.c_str(), len)) {
203 mExtensionString.append(ext + " ");
204 }
205 // advance to the next extension name, skipping the space.
206 start += len;
207 start += (*start == ' ') ? 1 : 0;
208 }
209 } while (*start != '\0');
210
211 egl_cache_t::get()->initialize(this);
212
213 char value[PROPERTY_VALUE_MAX];
214 property_get("debug.egl.finish", value, "0");
215 if (atoi(value)) {
216 finishOnSwap = true;
217 }
218
219 property_get("debug.egl.traceGpuCompletion", value, "0");
220 if (atoi(value)) {
221 traceGpuCompletion = true;
222 }
223
224 if (major != NULL)
225 *major = VERSION_MAJOR;
226 if (minor != NULL)
227 *minor = VERSION_MINOR;
228 }
229
230 { // scope for refLock
231 std::unique_lock<std::mutex> _l(refLock);
232 eglIsInitialized = true;
233 refCond.notify_all();
234 }
235
236 return EGL_TRUE;
237 }
238
terminate()239 EGLBoolean egl_display_t::terminate() {
240
241 { // scope for refLock
242 std::unique_lock<std::mutex> _rl(refLock);
243 if (refs == 0) {
244 /*
245 * From the EGL spec (3.2):
246 * "Termination of a display that has already been terminated,
247 * (...), is allowed, but the only effect of such a call is
248 * to return EGL_TRUE (...)
249 */
250 return EGL_TRUE;
251 }
252
253 // this is specific to Android, display termination is ref-counted.
254 refs--;
255 if (refs > 0) {
256 return EGL_TRUE;
257 }
258 }
259
260 EGLBoolean res = EGL_FALSE;
261
262 { // scope for lock
263 std::lock_guard<std::mutex> _l(lock);
264
265 egl_connection_t* const cnx = &gEGLImpl;
266 if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
267 if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) {
268 ALOGW("eglTerminate(%p) failed (%s)", disp.dpy,
269 egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
270 }
271 // REVISIT: it's unclear what to do if eglTerminate() fails
272 disp.state = egl_display_t::TERMINATED;
273 res = EGL_TRUE;
274 }
275
276 // Reset the extension string since it will be regenerated if we get
277 // reinitialized.
278 mExtensionString.clear();
279
280 // Mark all objects remaining in the list as terminated, unless
281 // there are no reference to them, it which case, we're free to
282 // delete them.
283 size_t count = objects.size();
284 ALOGW_IF(count, "eglTerminate() called w/ %zu objects remaining", count);
285 for (auto o : objects) {
286 o->destroy();
287 }
288
289 // this marks all object handles are "terminated"
290 objects.clear();
291 }
292
293 { // scope for refLock
294 std::unique_lock<std::mutex> _rl(refLock);
295 eglIsInitialized = false;
296 refCond.notify_all();
297 }
298
299 return res;
300 }
301
loseCurrent(egl_context_t * cur_c)302 void egl_display_t::loseCurrent(egl_context_t * cur_c)
303 {
304 if (cur_c) {
305 egl_display_t* display = cur_c->getDisplay();
306 if (display) {
307 display->loseCurrentImpl(cur_c);
308 }
309 }
310 }
311
loseCurrentImpl(egl_context_t * cur_c)312 void egl_display_t::loseCurrentImpl(egl_context_t * cur_c)
313 {
314 // by construction, these are either 0 or valid (possibly terminated)
315 // it should be impossible for these to be invalid
316 ContextRef _cur_c(cur_c);
317 SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
318 SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
319
320 { // scope for the lock
321 std::lock_guard<std::mutex> _l(lock);
322 cur_c->onLooseCurrent();
323
324 }
325
326 // This cannot be called with the lock held because it might end-up
327 // calling back into EGL (in particular when a surface is destroyed
328 // it calls ANativeWindow::disconnect
329 _cur_c.release();
330 _cur_r.release();
331 _cur_d.release();
332 }
333
makeCurrent(egl_context_t * c,egl_context_t * cur_c,EGLSurface draw,EGLSurface read,EGLContext,EGLSurface impl_draw,EGLSurface impl_read,EGLContext impl_ctx)334 EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
335 EGLSurface draw, EGLSurface read, EGLContext /*ctx*/,
336 EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx)
337 {
338 EGLBoolean result;
339
340 // by construction, these are either 0 or valid (possibly terminated)
341 // it should be impossible for these to be invalid
342 ContextRef _cur_c(cur_c);
343 SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
344 SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
345
346 { // scope for the lock
347 std::lock_guard<std::mutex> _l(lock);
348 if (c) {
349 result = c->cnx->egl.eglMakeCurrent(
350 disp.dpy, impl_draw, impl_read, impl_ctx);
351 if (result == EGL_TRUE) {
352 c->onMakeCurrent(draw, read);
353 }
354 } else {
355 result = cur_c->cnx->egl.eglMakeCurrent(
356 disp.dpy, impl_draw, impl_read, impl_ctx);
357 if (result == EGL_TRUE) {
358 cur_c->onLooseCurrent();
359 }
360 }
361 }
362
363 if (result == EGL_TRUE) {
364 // This cannot be called with the lock held because it might end-up
365 // calling back into EGL (in particular when a surface is destroyed
366 // it calls ANativeWindow::disconnect
367 _cur_c.release();
368 _cur_r.release();
369 _cur_d.release();
370 }
371
372 return result;
373 }
374
haveExtension(const char * name,size_t nameLen) const375 bool egl_display_t::haveExtension(const char* name, size_t nameLen) const {
376 if (!nameLen) {
377 nameLen = strlen(name);
378 }
379 return findExtension(mExtensionString.c_str(), name, nameLen);
380 }
381
382 // ----------------------------------------------------------------------------
383 }; // namespace android
384 // ----------------------------------------------------------------------------
385