• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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