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