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 #include "egl_display.h"
18 #include "egl_object.h"
19 #include "egl_tls.h"
20 #include "egl_impl.h"
21 #include "Loader.h"
22
23 // ----------------------------------------------------------------------------
24 namespace android {
25 // ----------------------------------------------------------------------------
26
27 extern void initEglTraceLevel();
28 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
29
cmp_configs(const void * a,const void * b)30 static int cmp_configs(const void* a, const void *b) {
31 const egl_config_t& c0 = *(egl_config_t const *)a;
32 const egl_config_t& c1 = *(egl_config_t const *)b;
33 return c0<c1 ? -1 : (c1<c0 ? 1 : 0);
34 }
35
36 // ----------------------------------------------------------------------------
37
38 egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
39
egl_display_t()40 egl_display_t::egl_display_t() :
41 magic('_dpy'), numTotalConfigs(0), configs(0), refs(0) {
42 }
43
~egl_display_t()44 egl_display_t::~egl_display_t() {
45 magic = 0;
46 }
47
get(EGLDisplay dpy)48 egl_display_t* egl_display_t::get(EGLDisplay dpy) {
49 uintptr_t index = uintptr_t(dpy)-1U;
50 return (index >= NUM_DISPLAYS) ? NULL : &sDisplay[index];
51 }
52
addObject(egl_object_t * object)53 void egl_display_t::addObject(egl_object_t* object) {
54 Mutex::Autolock _l(lock);
55 objects.add(object);
56 }
57
removeObject(egl_object_t * object)58 void egl_display_t::removeObject(egl_object_t* object) {
59 Mutex::Autolock _l(lock);
60 objects.remove(object);
61 }
62
getObject(egl_object_t * object)63 bool egl_display_t::getObject(egl_object_t* object) {
64 Mutex::Autolock _l(lock);
65 if (objects.indexOf(object) >= 0) {
66 object->incRef();
67 return true;
68 }
69 return false;
70 }
71
getFromNativeDisplay(EGLNativeDisplayType disp)72 EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
73 if (uintptr_t(disp) >= NUM_DISPLAYS)
74 return NULL;
75
76 return sDisplay[uintptr_t(disp)].getDisplay(disp);
77 }
78
getDisplay(EGLNativeDisplayType display)79 EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) {
80
81 Mutex::Autolock _l(lock);
82
83 // get our driver loader
84 Loader& loader(Loader::getInstance());
85
86 for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
87 egl_connection_t* const cnx = &gEGLImpl[i];
88 if (cnx->dso && disp[i].dpy == EGL_NO_DISPLAY) {
89 EGLDisplay dpy = cnx->egl.eglGetDisplay(display);
90 disp[i].dpy = dpy;
91 if (dpy == EGL_NO_DISPLAY) {
92 loader.close(cnx->dso);
93 cnx->dso = NULL;
94 }
95 }
96 }
97
98 return EGLDisplay(uintptr_t(display) + 1U);
99 }
100
initialize(EGLint * major,EGLint * minor)101 EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {
102
103 Mutex::Autolock _l(lock);
104
105 if (refs > 0) {
106 if (major != NULL)
107 *major = VERSION_MAJOR;
108 if (minor != NULL)
109 *minor = VERSION_MINOR;
110 refs++;
111 return EGL_TRUE;
112 }
113
114 #if EGL_TRACE
115
116 // Called both at early_init time and at this time. (Early_init is pre-zygote, so
117 // the information from that call may be stale.)
118 initEglTraceLevel();
119
120 #endif
121
122 setGLHooksThreadSpecific(&gHooksNoContext);
123
124 // initialize each EGL and
125 // build our own extension string first, based on the extension we know
126 // and the extension supported by our client implementation
127 for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
128 egl_connection_t* const cnx = &gEGLImpl[i];
129 cnx->major = -1;
130 cnx->minor = -1;
131 if (!cnx->dso)
132 continue;
133
134 #if defined(ADRENO130)
135 #warning "Adreno-130 eglInitialize() workaround"
136 /*
137 * The ADRENO 130 driver returns a different EGLDisplay each time
138 * eglGetDisplay() is called, but also makes the EGLDisplay invalid
139 * after eglTerminate() has been called, so that eglInitialize()
140 * cannot be called again. Therefore, we need to make sure to call
141 * eglGetDisplay() before calling eglInitialize();
142 */
143 if (i == IMPL_HARDWARE) {
144 disp[i].dpy =
145 cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
146 }
147 #endif
148
149 EGLDisplay idpy = disp[i].dpy;
150 if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
151 //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
152 // i, idpy, cnx->major, cnx->minor, cnx);
153
154 // display is now initialized
155 disp[i].state = egl_display_t::INITIALIZED;
156
157 // get the query-strings for this display for each implementation
158 disp[i].queryString.vendor = cnx->egl.eglQueryString(idpy,
159 EGL_VENDOR);
160 disp[i].queryString.version = cnx->egl.eglQueryString(idpy,
161 EGL_VERSION);
162 disp[i].queryString.extensions = cnx->egl.eglQueryString(idpy,
163 EGL_EXTENSIONS);
164 disp[i].queryString.clientApi = cnx->egl.eglQueryString(idpy,
165 EGL_CLIENT_APIS);
166
167 } else {
168 LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
169 egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
170 }
171 }
172
173 EGLBoolean res = EGL_FALSE;
174 for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
175 egl_connection_t* const cnx = &gEGLImpl[i];
176 if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
177 EGLint n;
178 if (cnx->egl.eglGetConfigs(disp[i].dpy, 0, 0, &n)) {
179 disp[i].config = (EGLConfig*) malloc(sizeof(EGLConfig) * n);
180 if (disp[i].config) {
181 if (cnx->egl.eglGetConfigs(disp[i].dpy, disp[i].config, n,
182 &disp[i].numConfigs)) {
183 numTotalConfigs += n;
184 res = EGL_TRUE;
185 }
186 }
187 }
188 }
189 }
190
191 if (res == EGL_TRUE) {
192 configs = new egl_config_t[numTotalConfigs];
193 for (int i = 0, k = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
194 egl_connection_t* const cnx = &gEGLImpl[i];
195 if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
196 for (int j = 0; j < disp[i].numConfigs; j++) {
197 configs[k].impl = i;
198 configs[k].config = disp[i].config[j];
199 configs[k].configId = k + 1; // CONFIG_ID start at 1
200 // store the implementation's CONFIG_ID
201 cnx->egl.eglGetConfigAttrib(disp[i].dpy, disp[i].config[j],
202 EGL_CONFIG_ID, &configs[k].implConfigId);
203 k++;
204 }
205 }
206 }
207
208 // sort our configurations so we can do binary-searches
209 qsort(configs, numTotalConfigs, sizeof(egl_config_t), cmp_configs);
210
211 refs++;
212 if (major != NULL)
213 *major = VERSION_MAJOR;
214 if (minor != NULL)
215 *minor = VERSION_MINOR;
216 return EGL_TRUE;
217 }
218 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
219 }
220
terminate()221 EGLBoolean egl_display_t::terminate() {
222
223 Mutex::Autolock _l(lock);
224
225 if (refs == 0) {
226 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
227 }
228
229 // this is specific to Android, display termination is ref-counted.
230 if (refs > 1) {
231 refs--;
232 return EGL_TRUE;
233 }
234
235 EGLBoolean res = EGL_FALSE;
236 for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
237 egl_connection_t* const cnx = &gEGLImpl[i];
238 if (cnx->dso && disp[i].state == egl_display_t::INITIALIZED) {
239 if (cnx->egl.eglTerminate(disp[i].dpy) == EGL_FALSE) {
240 LOGW("%d: eglTerminate(%p) failed (%s)", i, disp[i].dpy,
241 egl_tls_t::egl_strerror(cnx->egl.eglGetError()));
242 }
243 // REVISIT: it's unclear what to do if eglTerminate() fails
244 free(disp[i].config);
245
246 disp[i].numConfigs = 0;
247 disp[i].config = 0;
248 disp[i].state = egl_display_t::TERMINATED;
249
250 res = EGL_TRUE;
251 }
252 }
253
254 // Mark all objects remaining in the list as terminated, unless
255 // there are no reference to them, it which case, we're free to
256 // delete them.
257 size_t count = objects.size();
258 LOGW_IF(count, "eglTerminate() called w/ %d objects remaining", count);
259 for (size_t i=0 ; i<count ; i++) {
260 egl_object_t* o = objects.itemAt(i);
261 o->destroy();
262 }
263
264 // this marks all object handles are "terminated"
265 objects.clear();
266
267 refs--;
268 numTotalConfigs = 0;
269 delete[] configs;
270 return res;
271 }
272
273
274 // ----------------------------------------------------------------------------
275 }; // namespace android
276 // ----------------------------------------------------------------------------
277