blob: fec4e5d3a3d3f369be7e3811f9793712e7f4f11c [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001/*
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
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080017#include <ctype.h>
Mathias Agopiand8fb7b52009-05-17 18:50:16 -070018#include <stdlib.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080019#include <string.h>
20#include <errno.h>
21#include <dlfcn.h>
22
23#include <sys/ioctl.h>
24
25#if HAVE_ANDROID_OS
26#include <linux/android_pmem.h>
27#endif
28
29#include <EGL/egl.h>
30#include <EGL/eglext.h>
31#include <GLES/gl.h>
32#include <GLES/glext.h>
33
34#include <cutils/log.h>
35#include <cutils/atomic.h>
36#include <cutils/properties.h>
37#include <cutils/memory.h>
38
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080039#include "hooks.h"
40#include "egl_impl.h"
Mathias Agopiande586972009-05-28 17:39:03 -070041#include "Loader.h"
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080042
43#define MAKE_CONFIG(_impl, _index) ((EGLConfig)(((_impl)<<24) | (_index)))
44#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
45
46// ----------------------------------------------------------------------------
47namespace android {
48// ----------------------------------------------------------------------------
49
50#define VERSION_MAJOR 1
51#define VERSION_MINOR 4
52static char const * const gVendorString = "Android";
53static char const * const gVersionString = "1.31 Android META-EGL";
54static char const * const gClientApiString = "OpenGL ES";
Mathias Agopian076b1cc2009-04-10 14:24:30 -070055static char const * const gExtensionString =
56 "EGL_KHR_image "
Mathias Agopiane6bf8b32009-05-06 23:47:08 -070057 "EGL_KHR_image_base "
58 "EGL_KHR_image_pixmap "
Mathias Agopian076b1cc2009-04-10 14:24:30 -070059 "EGL_ANDROID_image_native_buffer "
Mathias Agopiandf3ca302009-05-04 19:29:25 -070060 "EGL_ANDROID_swap_rectangle "
Mathias Agopian076b1cc2009-04-10 14:24:30 -070061 ;
62
63// ----------------------------------------------------------------------------
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080064
65template <int MAGIC>
66struct egl_object_t
67{
68 egl_object_t() : magic(MAGIC) { }
69 ~egl_object_t() { magic = 0; }
70 bool isValid() const { return magic == MAGIC; }
71private:
72 uint32_t magic;
73};
74
75struct egl_display_t : public egl_object_t<'_dpy'>
76{
Mathias Agopian076b1cc2009-04-10 14:24:30 -070077 EGLDisplay dpys[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
78 EGLConfig* configs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
79 EGLint numConfigs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080080 EGLint numTotalConfigs;
81 char const* extensionsString;
82 volatile int32_t refs;
83 struct strings_t {
84 char const * vendor;
85 char const * version;
86 char const * clientApi;
87 char const * extensions;
88 };
Mathias Agopian076b1cc2009-04-10 14:24:30 -070089 strings_t queryString[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080090};
91
92struct egl_surface_t : public egl_object_t<'_srf'>
93{
94 egl_surface_t(EGLDisplay dpy, EGLSurface surface,
Mathias Agopian076b1cc2009-04-10 14:24:30 -070095 int impl, egl_connection_t const* cnx)
96 : dpy(dpy), surface(surface), impl(impl), cnx(cnx)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080097 {
98 // NOTE: window must be incRef'ed and connected already
99 }
100 ~egl_surface_t() {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800101 }
102 EGLDisplay dpy;
103 EGLSurface surface;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800104 int impl;
105 egl_connection_t const* cnx;
106};
107
108struct egl_context_t : public egl_object_t<'_ctx'>
109{
110 egl_context_t(EGLDisplay dpy, EGLContext context,
111 int impl, egl_connection_t const* cnx)
112 : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
113 {
114 }
115 EGLDisplay dpy;
116 EGLContext context;
117 EGLSurface read;
118 EGLSurface draw;
119 int impl;
120 egl_connection_t const* cnx;
121};
122
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700123struct egl_image_t : public egl_object_t<'_img'>
124{
125 egl_image_t(EGLDisplay dpy, EGLContext context)
126 : dpy(dpy), context(context)
127 {
128 memset(images, 0, sizeof(images));
129 }
130 EGLDisplay dpy;
131 EGLConfig context;
132 EGLImageKHR images[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
133};
134
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800135struct tls_t
136{
137 tls_t() : error(EGL_SUCCESS), ctx(0) { }
138 EGLint error;
139 EGLContext ctx;
140};
141
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800142
143// ----------------------------------------------------------------------------
144
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700145egl_connection_t gEGLImpl[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800146static egl_display_t gDisplay[NUM_DISPLAYS];
147static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
148static pthread_key_t gEGLThreadLocalStorageKey = -1;
149
150// ----------------------------------------------------------------------------
151
Mathias Agopianeccc8cf2009-05-13 00:19:22 -0700152EGLAPI gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
153EGLAPI pthread_key_t gGLWrapperKey = -1;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800154
155// ----------------------------------------------------------------------------
156
157static __attribute__((noinline))
158const char *egl_strerror(EGLint err)
159{
160 switch (err){
161 case EGL_SUCCESS: return "EGL_SUCCESS";
162 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
163 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
164 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
165 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
166 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
167 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
168 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
169 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
170 case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
171 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
172 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
173 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
174 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
175 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
176 default: return "UNKNOWN";
177 }
178}
179
180static __attribute__((noinline))
181void clearTLS() {
182 if (gEGLThreadLocalStorageKey != -1) {
183 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
184 if (tls) {
185 delete tls;
186 pthread_setspecific(gEGLThreadLocalStorageKey, 0);
187 }
188 }
189}
190
191static tls_t* getTLS()
192{
193 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
194 if (tls == 0) {
195 tls = new tls_t;
196 pthread_setspecific(gEGLThreadLocalStorageKey, tls);
197 }
198 return tls;
199}
200
201template<typename T>
202static __attribute__((noinline))
203T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
204 if (gEGLThreadLocalStorageKey == -1) {
205 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
206 if (gEGLThreadLocalStorageKey == -1)
207 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
208 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
209 }
210 tls_t* tls = getTLS();
211 if (tls->error != error) {
212 LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
213 tls->error = error;
214 }
215 return returnValue;
216}
217
218static __attribute__((noinline))
219GLint getError() {
220 if (gEGLThreadLocalStorageKey == -1)
221 return EGL_SUCCESS;
222 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
223 if (!tls) return EGL_SUCCESS;
224 GLint error = tls->error;
225 tls->error = EGL_SUCCESS;
226 return error;
227}
228
229static __attribute__((noinline))
230void setContext(EGLContext ctx) {
231 if (gEGLThreadLocalStorageKey == -1) {
232 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
233 if (gEGLThreadLocalStorageKey == -1)
234 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
235 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
236 }
237 tls_t* tls = getTLS();
238 tls->ctx = ctx;
239}
240
241static __attribute__((noinline))
242EGLContext getContext() {
243 if (gEGLThreadLocalStorageKey == -1)
244 return EGL_NO_CONTEXT;
245 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
246 if (!tls) return EGL_NO_CONTEXT;
247 return tls->ctx;
248}
249
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800250/*****************************************************************************/
251
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800252template<typename T>
253static __attribute__((noinline))
254int binarySearch(
255 T const sortedArray[], int first, int last, T key)
256{
257 while (first <= last) {
258 int mid = (first + last) / 2;
259 if (key > sortedArray[mid]) {
260 first = mid + 1;
261 } else if (key < sortedArray[mid]) {
262 last = mid - 1;
263 } else {
264 return mid;
265 }
266 }
267 return -1;
268}
269
270static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
271{
272 // NOTE: this mapping works only if we have no more than two EGLimpl
273 return (i>0 ? dp->numConfigs[0] : 0) + index;
274}
275
276static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
277 int& i, int& index)
278{
279 // NOTE: this mapping works only if we have no more than two EGLimpl
280 size_t numConfigs = dp->numConfigs[0];
281 i = configId / numConfigs;
282 index = configId % numConfigs;
283}
284
285static int cmp_configs(const void* a, const void *b)
286{
287 EGLConfig c0 = *(EGLConfig const *)a;
288 EGLConfig c1 = *(EGLConfig const *)b;
289 return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
290}
291
292struct extention_map_t {
293 const char* name;
294 __eglMustCastToProperFunctionPointerType address;
295};
296
297static const extention_map_t gExtentionMap[] = {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700298 { "eglLockSurfaceKHR",
299 (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
300 { "eglUnlockSurfaceKHR",
301 (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
302 { "eglCreateImageKHR",
303 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
304 { "eglDestroyImageKHR",
305 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800306};
307
308static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
309
310static void(*findProcAddress(const char* name,
311 const extention_map_t* map, size_t n))()
312{
313 for (uint32_t i=0 ; i<n ; i++) {
314 if (!strcmp(name, map[i].name)) {
315 return map[i].address;
316 }
317 }
318 return NULL;
319}
320
321// ----------------------------------------------------------------------------
322
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700323/*
324 * To "loose" the GPU, use something like
325 * gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_CONTEXT_LOST];
326 *
327 */
328
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800329static int gl_context_lost() {
330 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
331 return 0;
332}
333static int egl_context_lost() {
334 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
335 return EGL_FALSE;
336}
337static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
338 usleep(100000); // don't use all the CPU
339 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
340 return EGL_FALSE;
341}
342static GLint egl_context_lost_get_error() {
343 return EGL_CONTEXT_LOST;
344}
345static int ext_context_lost() {
346 return 0;
347}
348
349static void gl_no_context() {
350 LOGE("call to OpenGL ES API with no current context");
351}
352static void early_egl_init(void)
353{
354#if !USE_FAST_TLS_KEY
355 pthread_key_create(&gGLWrapperKey, NULL);
356#endif
357 uint32_t addr = (uint32_t)((void*)gl_no_context);
358 android_memset32(
359 (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT],
360 addr,
361 sizeof(gHooks[IMPL_NO_CONTEXT]));
362 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
363}
364
365static pthread_once_t once_control = PTHREAD_ONCE_INIT;
366static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
367
368
369static inline
370egl_display_t* get_display(EGLDisplay dpy)
371{
372 uintptr_t index = uintptr_t(dpy)-1U;
373 return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
374}
375
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700376template<typename NATIVE, typename EGL>
377static inline NATIVE* egl_to_native_cast(EGL arg) {
378 return reinterpret_cast<NATIVE*>(arg);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800379}
380
381static inline
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700382egl_surface_t* get_surface(EGLSurface surface) {
383 return egl_to_native_cast<egl_surface_t>(surface);
384}
385
386static inline
387egl_context_t* get_context(EGLContext context) {
388 return egl_to_native_cast<egl_context_t>(context);
389}
390
391static inline
392egl_image_t* get_image(EGLImageKHR image) {
393 return egl_to_native_cast<egl_image_t>(image);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800394}
395
396static egl_connection_t* validate_display_config(
397 EGLDisplay dpy, EGLConfig config,
398 egl_display_t const*& dp, int& impl, int& index)
399{
400 dp = get_display(dpy);
401 if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
402
403 impl = uintptr_t(config)>>24;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700404 if (uint32_t(impl) >= IMPL_NUM_DRIVERS_IMPLEMENTATIONS) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800405 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
406 }
407 index = uintptr_t(config) & 0xFFFFFF;
408 if (index >= dp->numConfigs[impl]) {
409 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
410 }
411 egl_connection_t* const cnx = &gEGLImpl[impl];
412 if (cnx->dso == 0) {
413 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
414 }
415 return cnx;
416}
417
418static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
419{
420 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
421 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
422 if (!get_display(dpy)->isValid())
423 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
424 if (!ctx) // TODO: make sure context is a valid object
425 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
426 if (!get_context(ctx)->isValid())
427 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
428 return EGL_TRUE;
429}
430
431static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
432{
433 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
434 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
435 if (!get_display(dpy)->isValid())
436 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
437 if (!surface) // TODO: make sure surface is a valid object
438 return setError(EGL_BAD_SURFACE, EGL_FALSE);
439 if (!get_surface(surface)->isValid())
440 return setError(EGL_BAD_SURFACE, EGL_FALSE);
441 return EGL_TRUE;
442}
443
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800444
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700445EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
446{
447 EGLContext context = getContext();
448 if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
449 return EGL_NO_IMAGE_KHR;
450
451 egl_context_t const * const c = get_context(context);
452 if (!c->isValid())
453 return EGL_NO_IMAGE_KHR;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800454
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700455 egl_image_t const * const i = get_image(image);
456 if (!i->isValid())
457 return EGL_NO_IMAGE_KHR;
458
459 return i->images[c->impl];
460}
461
462
463EGLDisplay egl_init_displays(NativeDisplayType display)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800464{
465 if (sEarlyInitState) {
466 return EGL_NO_DISPLAY;
467 }
468
469 uint32_t index = uint32_t(display);
470 if (index >= NUM_DISPLAYS) {
471 return EGL_NO_DISPLAY;
472 }
473
474 EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
475 egl_display_t* d = &gDisplay[index];
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700476
Mathias Agopiande586972009-05-28 17:39:03 -0700477 // get our driver loader
478 Loader& loader(Loader::getInstance());
479
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800480 // dynamically load all our EGL implementations for that display
481 // and call into the real eglGetGisplay()
482 egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
483 if (cnx->dso == 0) {
484 cnx->hooks = &gHooks[IMPL_SOFTWARE];
Mathias Agopiande586972009-05-28 17:39:03 -0700485 cnx->dso = loader.open(display, 0, cnx->hooks);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800486 }
487 if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
488 d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
489 LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
490 "No EGLDisplay for software EGL!");
491 }
492
493 cnx = &gEGLImpl[IMPL_HARDWARE];
494 if (cnx->dso == 0 && cnx->unavailable == 0) {
495 char value[PROPERTY_VALUE_MAX];
496 property_get("debug.egl.hw", value, "1");
497 if (atoi(value) != 0) {
498 cnx->hooks = &gHooks[IMPL_HARDWARE];
Mathias Agopiande586972009-05-28 17:39:03 -0700499 cnx->dso = loader.open(display, 1, cnx->hooks);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800500 } else {
501 LOGD("3D hardware acceleration is disabled");
502 }
503 }
504 if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
505 android_memset32(
506 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
507 (uint32_t)((void*)gl_context_lost),
508 sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
509 android_memset32(
510 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
511 (uint32_t)((void*)egl_context_lost),
512 sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
513 android_memset32(
514 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
515 (uint32_t)((void*)ext_context_lost),
516 sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
517
518 gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
519 egl_context_lost_swap_buffers;
520
521 gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
522 egl_context_lost_get_error;
523
524 gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
525 gHooks[IMPL_HARDWARE].egl.eglTerminate;
526
527 d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
528 if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
529 LOGE("h/w accelerated eglGetDisplay() failed (%s)",
530 egl_strerror(cnx->hooks->egl.eglGetError()));
Mathias Agopiande586972009-05-28 17:39:03 -0700531
532 loader.close(cnx->dso);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800533 cnx->dso = 0;
534 // in case of failure, we want to make sure we don't try again
535 // as it's expensive.
536 cnx->unavailable = 1;
537 }
538 }
539
540 return dpy;
541}
542
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700543
544// ----------------------------------------------------------------------------
545}; // namespace android
546// ----------------------------------------------------------------------------
547
548using namespace android;
549
550EGLDisplay eglGetDisplay(NativeDisplayType display)
551{
552 return egl_init_displays(display);
553}
554
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800555// ----------------------------------------------------------------------------
556// Initialization
557// ----------------------------------------------------------------------------
558
559EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
560{
561 egl_display_t * const dp = get_display(dpy);
562 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
563
564 if (android_atomic_inc(&dp->refs) > 0) {
565 if (major != NULL) *major = VERSION_MAJOR;
566 if (minor != NULL) *minor = VERSION_MINOR;
567 return EGL_TRUE;
568 }
569
570 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
571
572 // initialize each EGL and
573 // build our own extension string first, based on the extension we know
574 // and the extension supported by our client implementation
575 dp->extensionsString = strdup(gExtensionString);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700576 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800577 egl_connection_t* const cnx = &gEGLImpl[i];
578 cnx->major = -1;
579 cnx->minor = -1;
580 if (!cnx->dso)
581 continue;
582
583 if (cnx->hooks->egl.eglInitialize(
584 dp->dpys[i], &cnx->major, &cnx->minor)) {
585
586 //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
587 // i, dp->dpys[i], cnx->major, cnx->minor, cnx);
588
589 // get the query-strings for this display for each implementation
590 dp->queryString[i].vendor =
591 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
592 dp->queryString[i].version =
593 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
594 dp->queryString[i].extensions = strdup(
595 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
596 dp->queryString[i].clientApi =
597 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
598
599 } else {
600 LOGD("%d: eglInitialize() failed (%s)",
601 i, egl_strerror(cnx->hooks->egl.eglGetError()));
602 }
603 }
604
605 EGLBoolean res = EGL_FALSE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700606 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800607 egl_connection_t* const cnx = &gEGLImpl[i];
608 if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
609 EGLint n;
610 if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
611 dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
612 if (dp->configs[i]) {
613 if (cnx->hooks->egl.eglGetConfigs(
614 dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
615 {
616 // sort the configurations so we can do binary searches
617 qsort( dp->configs[i],
618 dp->numConfigs[i],
619 sizeof(EGLConfig), cmp_configs);
620
621 dp->numTotalConfigs += n;
622 res = EGL_TRUE;
623 }
624 }
625 }
626 }
627 }
628
629 if (res == EGL_TRUE) {
630 if (major != NULL) *major = VERSION_MAJOR;
631 if (minor != NULL) *minor = VERSION_MINOR;
632 return EGL_TRUE;
633 }
634 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
635}
636
637EGLBoolean eglTerminate(EGLDisplay dpy)
638{
639 egl_display_t* const dp = get_display(dpy);
640 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
641 if (android_atomic_dec(&dp->refs) != 1)
642 return EGL_TRUE;
643
Mathias Agopiande586972009-05-28 17:39:03 -0700644 Loader& loader(Loader::getInstance());
645
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800646 EGLBoolean res = EGL_FALSE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700647 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800648 egl_connection_t* const cnx = &gEGLImpl[i];
649 if (cnx->dso) {
650 cnx->hooks->egl.eglTerminate(dp->dpys[i]);
651
652 /* REVISIT: it's unclear what to do if eglTerminate() fails,
653 * on one end we shouldn't care, on the other end if it fails
654 * it might not be safe to call dlclose() (there could be some
655 * threads around). */
656
657 free(dp->configs[i]);
658 free((void*)dp->queryString[i].extensions);
659 dp->numConfigs[i] = 0;
660 dp->dpys[i] = EGL_NO_DISPLAY;
Mathias Agopiande586972009-05-28 17:39:03 -0700661
662 loader.close(cnx->dso);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800663 cnx->dso = 0;
664 res = EGL_TRUE;
665 }
666 }
667 free((void*)dp->extensionsString);
668 dp->extensionsString = 0;
669 dp->numTotalConfigs = 0;
670 clearTLS();
671 return res;
672}
673
674// ----------------------------------------------------------------------------
675// configuration
676// ----------------------------------------------------------------------------
677
678EGLBoolean eglGetConfigs( EGLDisplay dpy,
679 EGLConfig *configs,
680 EGLint config_size, EGLint *num_config)
681{
682 egl_display_t const * const dp = get_display(dpy);
683 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
684
685 GLint numConfigs = dp->numTotalConfigs;
686 if (!configs) {
687 *num_config = numConfigs;
688 return EGL_TRUE;
689 }
690 GLint n = 0;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700691 for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800692 for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
693 *configs++ = MAKE_CONFIG(j, i);
694 config_size--;
695 n++;
696 }
697 }
698
699 *num_config = n;
700 return EGL_TRUE;
701}
702
703EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
704 EGLConfig *configs, EGLint config_size,
705 EGLint *num_config)
706{
707 egl_display_t const * const dp = get_display(dpy);
708 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
709
Jack Palevich749c63d2009-03-25 15:12:17 -0700710 if (num_config==0) {
711 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800712 }
713
714 EGLint n;
715 EGLBoolean res = EGL_FALSE;
716 *num_config = 0;
717
718
719 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
720 // to do this, we have to go through the attrib_list array once
721 // to figure out both its size and if it contains an EGL_CONFIG_ID
722 // key. If so, the full array is copied and patched.
723 // NOTE: we assume that there can be only one occurrence
724 // of EGL_CONFIG_ID.
725
726 EGLint patch_index = -1;
727 GLint attr;
728 size_t size = 0;
729 while ((attr=attrib_list[size])) {
730 if (attr == EGL_CONFIG_ID)
731 patch_index = size;
732 size += 2;
733 }
734 if (patch_index >= 0) {
735 size += 2; // we need copy the sentinel as well
736 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
737 if (new_list == 0)
738 return setError(EGL_BAD_ALLOC, EGL_FALSE);
739 memcpy(new_list, attrib_list, size*sizeof(EGLint));
740
741 // patch the requested EGL_CONFIG_ID
742 int i, index;
743 EGLint& configId(new_list[patch_index+1]);
744 uniqueIdToConfig(dp, configId, i, index);
745
746 egl_connection_t* const cnx = &gEGLImpl[i];
747 if (cnx->dso) {
748 cnx->hooks->egl.eglGetConfigAttrib(
749 dp->dpys[i], dp->configs[i][index],
750 EGL_CONFIG_ID, &configId);
751
752 // and switch to the new list
753 attrib_list = const_cast<const EGLint *>(new_list);
754
755 // At this point, the only configuration that can match is
756 // dp->configs[i][index], however, we don't know if it would be
757 // rejected because of the other attributes, so we do have to call
758 // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
759 // through all the EGLimpl[].
760 // We also know we can only get a single config back, and we know
761 // which one.
762
763 res = cnx->hooks->egl.eglChooseConfig(
764 dp->dpys[i], attrib_list, configs, config_size, &n);
765 if (res && n>0) {
766 // n has to be 0 or 1, by construction, and we already know
767 // which config it will return (since there can be only one).
Jack Palevich749c63d2009-03-25 15:12:17 -0700768 if (configs) {
769 configs[0] = MAKE_CONFIG(i, index);
770 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800771 *num_config = 1;
772 }
773 }
774
775 free(const_cast<EGLint *>(attrib_list));
776 return res;
777 }
778
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700779 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800780 egl_connection_t* const cnx = &gEGLImpl[i];
781 if (cnx->dso) {
782 if (cnx->hooks->egl.eglChooseConfig(
783 dp->dpys[i], attrib_list, configs, config_size, &n)) {
Jack Palevich749c63d2009-03-25 15:12:17 -0700784 if (configs) {
785 // now we need to convert these client EGLConfig to our
786 // internal EGLConfig format. This is done in O(n log n).
787 for (int j=0 ; j<n ; j++) {
788 int index = binarySearch<EGLConfig>(
789 dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
790 if (index >= 0) {
791 if (configs) {
792 configs[j] = MAKE_CONFIG(i, index);
793 }
794 } else {
795 return setError(EGL_BAD_CONFIG, EGL_FALSE);
796 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800797 }
Jack Palevich749c63d2009-03-25 15:12:17 -0700798 configs += n;
799 config_size -= n;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800800 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800801 *num_config += n;
802 res = EGL_TRUE;
803 }
804 }
805 }
806 return res;
807}
808
809EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
810 EGLint attribute, EGLint *value)
811{
812 egl_display_t const* dp = 0;
813 int i=0, index=0;
814 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
815 if (!cnx) return EGL_FALSE;
816
817 if (attribute == EGL_CONFIG_ID) {
818 // EGL_CONFIG_IDs must be unique, just use the order of the selected
819 // EGLConfig.
820 *value = configToUniqueId(dp, i, index);
821 return EGL_TRUE;
822 }
823 return cnx->hooks->egl.eglGetConfigAttrib(
824 dp->dpys[i], dp->configs[i][index], attribute, value);
825}
826
827// ----------------------------------------------------------------------------
828// surfaces
829// ----------------------------------------------------------------------------
830
831EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
832 NativeWindowType window,
833 const EGLint *attrib_list)
834{
835 egl_display_t const* dp = 0;
836 int i=0, index=0;
837 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
838 if (cnx) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800839 EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
840 dp->dpys[i], dp->configs[i][index], window, attrib_list);
841 if (surface != EGL_NO_SURFACE) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700842 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800843 return s;
844 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800845 }
846 return EGL_NO_SURFACE;
847}
848
849EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
850 NativePixmapType pixmap,
851 const EGLint *attrib_list)
852{
853 egl_display_t const* dp = 0;
854 int i=0, index=0;
855 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
856 if (cnx) {
857 EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
858 dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
859 if (surface != EGL_NO_SURFACE) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700860 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800861 return s;
862 }
863 }
864 return EGL_NO_SURFACE;
865}
866
867EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
868 const EGLint *attrib_list)
869{
870 egl_display_t const* dp = 0;
871 int i=0, index=0;
872 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
873 if (cnx) {
874 EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
875 dp->dpys[i], dp->configs[i][index], attrib_list);
876 if (surface != EGL_NO_SURFACE) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700877 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800878 return s;
879 }
880 }
881 return EGL_NO_SURFACE;
882}
883
884EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
885{
886 if (!validate_display_surface(dpy, surface))
887 return EGL_FALSE;
888 egl_display_t const * const dp = get_display(dpy);
889 egl_surface_t const * const s = get_surface(surface);
890
891 EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
892 dp->dpys[s->impl], s->surface);
893
894 delete s;
895 return result;
896}
897
898EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
899 EGLint attribute, EGLint *value)
900{
901 if (!validate_display_surface(dpy, surface))
902 return EGL_FALSE;
903 egl_display_t const * const dp = get_display(dpy);
904 egl_surface_t const * const s = get_surface(surface);
905
906 return s->cnx->hooks->egl.eglQuerySurface(
907 dp->dpys[s->impl], s->surface, attribute, value);
908}
909
910// ----------------------------------------------------------------------------
911// contextes
912// ----------------------------------------------------------------------------
913
914EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
915 EGLContext share_list, const EGLint *attrib_list)
916{
917 egl_display_t const* dp = 0;
918 int i=0, index=0;
919 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
920 if (cnx) {
921 EGLContext context = cnx->hooks->egl.eglCreateContext(
922 dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
923 if (context != EGL_NO_CONTEXT) {
924 egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
925 return c;
926 }
927 }
928 return EGL_NO_CONTEXT;
929}
930
931EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
932{
933 if (!validate_display_context(dpy, ctx))
934 return EGL_FALSE;
935 egl_display_t const * const dp = get_display(dpy);
936 egl_context_t * const c = get_context(ctx);
937 EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
938 dp->dpys[c->impl], c->context);
939 delete c;
940 return result;
941}
942
943EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
944 EGLSurface read, EGLContext ctx)
945{
946 egl_display_t const * const dp = get_display(dpy);
947 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
948
949 if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
950 ctx == EGL_NO_CONTEXT)
951 {
952 EGLBoolean result = EGL_TRUE;
953 ctx = getContext();
954 if (ctx) {
955 egl_context_t * const c = get_context(ctx);
956 result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
957 if (result == EGL_TRUE) {
958 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
959 setContext(EGL_NO_CONTEXT);
960 }
961 }
962 return result;
963 }
964
965 if (!validate_display_context(dpy, ctx))
966 return EGL_FALSE;
967
Mathias Agopianaf742132009-06-25 00:01:11 -0700968 EGLSurface impl_draw = EGL_NO_SURFACE;
969 EGLSurface impl_read = EGL_NO_SURFACE;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800970 egl_context_t * const c = get_context(ctx);
971 if (draw != EGL_NO_SURFACE) {
972 egl_surface_t const * d = get_surface(draw);
973 if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
974 if (d->impl != c->impl)
975 return setError(EGL_BAD_MATCH, EGL_FALSE);
Mathias Agopianaf742132009-06-25 00:01:11 -0700976 impl_draw = d->surface;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800977 }
978 if (read != EGL_NO_SURFACE) {
979 egl_surface_t const * r = get_surface(read);
980 if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
981 if (r->impl != c->impl)
982 return setError(EGL_BAD_MATCH, EGL_FALSE);
Mathias Agopianaf742132009-06-25 00:01:11 -0700983 impl_read = r->surface;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800984 }
985 EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
Mathias Agopianaf742132009-06-25 00:01:11 -0700986 dp->dpys[c->impl], impl_draw, impl_read, c->context);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800987
988 if (result == EGL_TRUE) {
989 setGlThreadSpecific(c->cnx->hooks);
990 setContext(ctx);
991 c->read = read;
992 c->draw = draw;
993 }
994 return result;
995}
996
997
998EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
999 EGLint attribute, EGLint *value)
1000{
1001 if (!validate_display_context(dpy, ctx))
1002 return EGL_FALSE;
1003
1004 egl_display_t const * const dp = get_display(dpy);
1005 egl_context_t * const c = get_context(ctx);
1006
1007 return c->cnx->hooks->egl.eglQueryContext(
1008 dp->dpys[c->impl], c->context, attribute, value);
1009}
1010
1011EGLContext eglGetCurrentContext(void)
1012{
1013 EGLContext ctx = getContext();
1014 return ctx;
1015}
1016
1017EGLSurface eglGetCurrentSurface(EGLint readdraw)
1018{
1019 EGLContext ctx = getContext();
1020 if (ctx) {
1021 egl_context_t const * const c = get_context(ctx);
1022 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1023 switch (readdraw) {
1024 case EGL_READ: return c->read;
1025 case EGL_DRAW: return c->draw;
1026 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1027 }
1028 }
1029 return EGL_NO_SURFACE;
1030}
1031
1032EGLDisplay eglGetCurrentDisplay(void)
1033{
1034 EGLContext ctx = getContext();
1035 if (ctx) {
1036 egl_context_t const * const c = get_context(ctx);
1037 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1038 return c->dpy;
1039 }
1040 return EGL_NO_DISPLAY;
1041}
1042
1043EGLBoolean eglWaitGL(void)
1044{
1045 EGLBoolean res = EGL_TRUE;
1046 EGLContext ctx = getContext();
1047 if (ctx) {
1048 egl_context_t const * const c = get_context(ctx);
1049 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1050 if (uint32_t(c->impl)>=2)
1051 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1052 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1053 if (!cnx->dso)
1054 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1055 res = cnx->hooks->egl.eglWaitGL();
1056 }
1057 return res;
1058}
1059
1060EGLBoolean eglWaitNative(EGLint engine)
1061{
1062 EGLBoolean res = EGL_TRUE;
1063 EGLContext ctx = getContext();
1064 if (ctx) {
1065 egl_context_t const * const c = get_context(ctx);
1066 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1067 if (uint32_t(c->impl)>=2)
1068 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1069 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1070 if (!cnx->dso)
1071 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1072 res = cnx->hooks->egl.eglWaitNative(engine);
1073 }
1074 return res;
1075}
1076
1077EGLint eglGetError(void)
1078{
1079 EGLint result = EGL_SUCCESS;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001080 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001081 EGLint err = EGL_SUCCESS;
1082 egl_connection_t* const cnx = &gEGLImpl[i];
1083 if (cnx->dso)
1084 err = cnx->hooks->egl.eglGetError();
1085 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1086 result = err;
1087 }
1088 if (result == EGL_SUCCESS)
1089 result = getError();
1090 return result;
1091}
1092
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001093__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001094{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001095 // eglGetProcAddress() could be the very first function called
1096 // in which case we must make sure we've initialized ourselves, this
1097 // happens the first time egl_get_display() is called.
1098
1099 if (egl_init_displays(EGL_DEFAULT_DISPLAY) == EGL_NO_DISPLAY)
1100 return NULL;
1101
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001102 __eglMustCastToProperFunctionPointerType addr;
1103 addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1104 if (addr) return addr;
1105
1106 return NULL; // TODO: finish implementation below
1107
1108 addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1109 if (addr) return addr;
1110
1111 addr = 0;
1112 int slot = -1;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001113 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001114 egl_connection_t* const cnx = &gEGLImpl[i];
1115 if (cnx->dso) {
1116 if (cnx->hooks->egl.eglGetProcAddress) {
1117 addr = cnx->hooks->egl.eglGetProcAddress(procname);
1118 if (addr) {
1119 if (slot == -1) {
1120 slot = 0; // XXX: find free slot
1121 if (slot == -1) {
1122 addr = 0;
1123 break;
1124 }
1125 }
1126 cnx->hooks->ext.extensions[slot] = addr;
1127 }
1128 }
1129 }
1130 }
1131
1132 if (slot >= 0) {
1133 addr = 0; // XXX: address of stub 'slot'
1134 gGLExtentionMap[slot].name = strdup(procname);
1135 gGLExtentionMap[slot].address = addr;
1136 }
1137
1138 return addr;
1139
1140
1141 /*
1142 * TODO: For OpenGL ES extensions, we must generate a stub
1143 * that looks like
1144 * mov r12, #0xFFFF0FFF
1145 * ldr r12, [r12, #-15]
1146 * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
1147 * mov r12, [r12, #api_offset]
1148 * ldrne pc, r12
1149 * mov pc, #unsupported_extension
1150 *
1151 * and write the address of the extension in *all*
1152 * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1153 *
1154 */
1155}
1156
1157EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1158{
1159 if (!validate_display_surface(dpy, draw))
1160 return EGL_FALSE;
1161 egl_display_t const * const dp = get_display(dpy);
1162 egl_surface_t const * const s = get_surface(draw);
1163 return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1164}
1165
1166EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1167 NativePixmapType target)
1168{
1169 if (!validate_display_surface(dpy, surface))
1170 return EGL_FALSE;
1171 egl_display_t const * const dp = get_display(dpy);
1172 egl_surface_t const * const s = get_surface(surface);
1173 return s->cnx->hooks->egl.eglCopyBuffers(
1174 dp->dpys[s->impl], s->surface, target);
1175}
1176
1177const char* eglQueryString(EGLDisplay dpy, EGLint name)
1178{
1179 egl_display_t const * const dp = get_display(dpy);
1180 switch (name) {
1181 case EGL_VENDOR:
1182 return gVendorString;
1183 case EGL_VERSION:
1184 return gVersionString;
1185 case EGL_EXTENSIONS:
1186 return gExtensionString;
1187 case EGL_CLIENT_APIS:
1188 return gClientApiString;
1189 }
1190 return setError(EGL_BAD_PARAMETER, (const char *)0);
1191}
1192
1193
1194// ----------------------------------------------------------------------------
1195// EGL 1.1
1196// ----------------------------------------------------------------------------
1197
1198EGLBoolean eglSurfaceAttrib(
1199 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1200{
1201 if (!validate_display_surface(dpy, surface))
1202 return EGL_FALSE;
1203 egl_display_t const * const dp = get_display(dpy);
1204 egl_surface_t const * const s = get_surface(surface);
1205 if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1206 return s->cnx->hooks->egl.eglSurfaceAttrib(
1207 dp->dpys[s->impl], s->surface, attribute, value);
1208 }
1209 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1210}
1211
1212EGLBoolean eglBindTexImage(
1213 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1214{
1215 if (!validate_display_surface(dpy, surface))
1216 return EGL_FALSE;
1217 egl_display_t const * const dp = get_display(dpy);
1218 egl_surface_t const * const s = get_surface(surface);
1219 if (s->cnx->hooks->egl.eglBindTexImage) {
1220 return s->cnx->hooks->egl.eglBindTexImage(
1221 dp->dpys[s->impl], s->surface, buffer);
1222 }
1223 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1224}
1225
1226EGLBoolean eglReleaseTexImage(
1227 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1228{
1229 if (!validate_display_surface(dpy, surface))
1230 return EGL_FALSE;
1231 egl_display_t const * const dp = get_display(dpy);
1232 egl_surface_t const * const s = get_surface(surface);
1233 if (s->cnx->hooks->egl.eglReleaseTexImage) {
1234 return s->cnx->hooks->egl.eglReleaseTexImage(
1235 dp->dpys[s->impl], s->surface, buffer);
1236 }
1237 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1238}
1239
1240EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1241{
1242 egl_display_t * const dp = get_display(dpy);
1243 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1244
1245 EGLBoolean res = EGL_TRUE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001246 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001247 egl_connection_t* const cnx = &gEGLImpl[i];
1248 if (cnx->dso) {
1249 if (cnx->hooks->egl.eglSwapInterval) {
1250 if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1251 res = EGL_FALSE;
1252 }
1253 }
1254 }
1255 }
1256 return res;
1257}
1258
1259
1260// ----------------------------------------------------------------------------
1261// EGL 1.2
1262// ----------------------------------------------------------------------------
1263
1264EGLBoolean eglWaitClient(void)
1265{
1266 EGLBoolean res = EGL_TRUE;
1267 EGLContext ctx = getContext();
1268 if (ctx) {
1269 egl_context_t const * const c = get_context(ctx);
1270 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1271 if (uint32_t(c->impl)>=2)
1272 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1273 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1274 if (!cnx->dso)
1275 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1276 if (cnx->hooks->egl.eglWaitClient) {
1277 res = cnx->hooks->egl.eglWaitClient();
1278 } else {
1279 res = cnx->hooks->egl.eglWaitGL();
1280 }
1281 }
1282 return res;
1283}
1284
1285EGLBoolean eglBindAPI(EGLenum api)
1286{
1287 // bind this API on all EGLs
1288 EGLBoolean res = EGL_TRUE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001289 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001290 egl_connection_t* const cnx = &gEGLImpl[i];
1291 if (cnx->dso) {
1292 if (cnx->hooks->egl.eglBindAPI) {
1293 if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1294 res = EGL_FALSE;
1295 }
1296 }
1297 }
1298 }
1299 return res;
1300}
1301
1302EGLenum eglQueryAPI(void)
1303{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001304 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001305 egl_connection_t* const cnx = &gEGLImpl[i];
1306 if (cnx->dso) {
1307 if (cnx->hooks->egl.eglQueryAPI) {
1308 // the first one we find is okay, because they all
1309 // should be the same
1310 return cnx->hooks->egl.eglQueryAPI();
1311 }
1312 }
1313 }
1314 // or, it can only be OpenGL ES
1315 return EGL_OPENGL_ES_API;
1316}
1317
1318EGLBoolean eglReleaseThread(void)
1319{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001320 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001321 egl_connection_t* const cnx = &gEGLImpl[i];
1322 if (cnx->dso) {
1323 if (cnx->hooks->egl.eglReleaseThread) {
1324 cnx->hooks->egl.eglReleaseThread();
1325 }
1326 }
1327 }
1328 clearTLS();
1329 return EGL_TRUE;
1330}
1331
1332EGLSurface eglCreatePbufferFromClientBuffer(
1333 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1334 EGLConfig config, const EGLint *attrib_list)
1335{
1336 egl_display_t const* dp = 0;
1337 int i=0, index=0;
1338 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1339 if (!cnx) return EGL_FALSE;
1340 if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1341 return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1342 dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1343 }
1344 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1345}
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001346
1347// ----------------------------------------------------------------------------
1348// EGL_EGLEXT_VERSION 3
1349// ----------------------------------------------------------------------------
1350
1351EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1352 const EGLint *attrib_list)
1353{
1354 EGLBoolean result = EGL_FALSE;
1355 if (!validate_display_surface(dpy, surface))
1356 return result;
1357
1358 egl_display_t const * const dp = get_display(dpy);
1359 egl_surface_t const * const s = get_surface(surface);
1360
1361 if (s->cnx->hooks->egl.eglLockSurfaceKHR) {
1362 result = s->cnx->hooks->egl.eglLockSurfaceKHR(
1363 dp->dpys[s->impl], s->surface, attrib_list);
1364 }
1365 return result;
1366}
1367
1368EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1369{
1370 EGLBoolean result = EGL_FALSE;
1371 if (!validate_display_surface(dpy, surface))
1372 return result;
1373
1374 egl_display_t const * const dp = get_display(dpy);
1375 egl_surface_t const * const s = get_surface(surface);
1376
1377 if (s->cnx->hooks->egl.eglUnlockSurfaceKHR) {
1378 result = s->cnx->hooks->egl.eglUnlockSurfaceKHR(
1379 dp->dpys[s->impl], s->surface);
1380 }
1381 return result;
1382}
1383
1384EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1385 EGLClientBuffer buffer, const EGLint *attrib_list)
1386{
1387 if (ctx != EGL_NO_CONTEXT) {
1388 if (!validate_display_context(dpy, ctx))
1389 return EGL_NO_IMAGE_KHR;
1390 egl_display_t const * const dp = get_display(dpy);
1391 egl_context_t * const c = get_context(ctx);
1392 // since we have an EGLContext, we know which implementation to use
1393 EGLImageKHR image = c->cnx->hooks->egl.eglCreateImageKHR(
1394 dp->dpys[c->impl], c->context, target, buffer, attrib_list);
1395 if (image == EGL_NO_IMAGE_KHR)
1396 return image;
1397
1398 egl_image_t* result = new egl_image_t(dpy, ctx);
1399 result->images[c->impl] = image;
1400 return (EGLImageKHR)result;
1401 } else {
1402 // EGL_NO_CONTEXT is a valid parameter
1403 egl_display_t const * const dp = get_display(dpy);
1404 if (dp == 0) {
1405 return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1406 }
1407 // since we don't have a way to know which implementation to call,
1408 // we're calling all of them
1409
1410 EGLImageKHR implImages[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
1411 bool success = false;
1412 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1413 egl_connection_t* const cnx = &gEGLImpl[i];
1414 implImages[i] = EGL_NO_IMAGE_KHR;
1415 if (cnx->dso) {
1416 if (cnx->hooks->egl.eglCreateImageKHR) {
1417 implImages[i] = cnx->hooks->egl.eglCreateImageKHR(
1418 dp->dpys[i], ctx, target, buffer, attrib_list);
1419 if (implImages[i] != EGL_NO_IMAGE_KHR) {
1420 success = true;
1421 }
1422 }
1423 }
1424 }
1425 if (!success)
1426 return EGL_NO_IMAGE_KHR;
1427
1428 egl_image_t* result = new egl_image_t(dpy, ctx);
1429 memcpy(result->images, implImages, sizeof(implImages));
1430 return (EGLImageKHR)result;
1431 }
1432}
1433
1434EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1435{
1436 egl_display_t const * const dp = get_display(dpy);
1437 if (dp == 0) {
1438 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1439 }
1440
1441 egl_image_t* image = get_image(img);
1442 if (!image->isValid()) {
1443 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1444 }
1445
1446 bool success = false;
1447 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1448 egl_connection_t* const cnx = &gEGLImpl[i];
1449 if (image->images[i] != EGL_NO_IMAGE_KHR) {
1450 if (cnx->dso) {
1451 if (cnx->hooks->egl.eglCreateImageKHR) {
1452 if (cnx->hooks->egl.eglDestroyImageKHR(
1453 dp->dpys[i], image->images[i])) {
1454 success = true;
1455 }
1456 }
1457 }
1458 }
1459 }
1460 if (!success)
1461 return EGL_FALSE;
1462
1463 delete image;
1464
1465 return EGL_FALSE;
1466}
Mathias Agopiandf3ca302009-05-04 19:29:25 -07001467
1468
1469// ----------------------------------------------------------------------------
1470// ANDROID extensions
1471// ----------------------------------------------------------------------------
1472
1473EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1474 EGLint left, EGLint top, EGLint width, EGLint height)
1475{
1476 if (!validate_display_surface(dpy, draw))
1477 return EGL_FALSE;
1478 egl_display_t const * const dp = get_display(dpy);
1479 egl_surface_t const * const s = get_surface(draw);
1480 if (s->cnx->hooks->egl.eglSetSwapRectangleANDROID) {
1481 return s->cnx->hooks->egl.eglSetSwapRectangleANDROID(dp->dpys[s->impl],
1482 s->surface, left, top, width, height);
1483 }
1484 return EGL_FALSE;
1485}
1486