blob: 56d55492719a36ddcf01e6625faa6ab14275fc9a [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
Mathias Agopian53238bd2009-04-22 18:24:18 -070017#define LOG_TAG "libEGL"
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080018
19#include <ctype.h>
20#include <string.h>
21#include <errno.h>
22#include <dlfcn.h>
23
24#include <sys/ioctl.h>
25
26#if HAVE_ANDROID_OS
27#include <linux/android_pmem.h>
28#endif
29
30#include <EGL/egl.h>
31#include <EGL/eglext.h>
32#include <GLES/gl.h>
33#include <GLES/glext.h>
34
35#include <cutils/log.h>
36#include <cutils/atomic.h>
37#include <cutils/properties.h>
38#include <cutils/memory.h>
39
40#include <utils/RefBase.h>
41
42#include "hooks.h"
43#include "egl_impl.h"
44
45
46#define MAKE_CONFIG(_impl, _index) ((EGLConfig)(((_impl)<<24) | (_index)))
47#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
48
49// ----------------------------------------------------------------------------
50namespace android {
51// ----------------------------------------------------------------------------
52
53#define VERSION_MAJOR 1
54#define VERSION_MINOR 4
55static char const * const gVendorString = "Android";
56static char const * const gVersionString = "1.31 Android META-EGL";
57static char const * const gClientApiString = "OpenGL ES";
58static char const * const gExtensionString = "";
59
60template <int MAGIC>
61struct egl_object_t
62{
63 egl_object_t() : magic(MAGIC) { }
64 ~egl_object_t() { magic = 0; }
65 bool isValid() const { return magic == MAGIC; }
66private:
67 uint32_t magic;
68};
69
70struct egl_display_t : public egl_object_t<'_dpy'>
71{
Mathias Agopian53238bd2009-04-22 18:24:18 -070072 EGLDisplay dpys[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
73 EGLConfig* configs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
74 EGLint numConfigs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080075 EGLint numTotalConfigs;
76 char const* extensionsString;
77 volatile int32_t refs;
78 struct strings_t {
79 char const * vendor;
80 char const * version;
81 char const * clientApi;
82 char const * extensions;
83 };
Mathias Agopian53238bd2009-04-22 18:24:18 -070084 strings_t queryString[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080085};
86
87struct egl_surface_t : public egl_object_t<'_srf'>
88{
89 egl_surface_t(EGLDisplay dpy, EGLSurface surface,
90 NativeWindowType window, int impl, egl_connection_t const* cnx)
91 : dpy(dpy), surface(surface), window(window), impl(impl), cnx(cnx)
92 {
93 // NOTE: window must be incRef'ed and connected already
94 }
95 ~egl_surface_t() {
96 if (window) {
97 if (window->disconnect)
98 window->disconnect(window);
99 window->decRef(window);
100 }
101 }
102 EGLDisplay dpy;
103 EGLSurface surface;
104 NativeWindowType window;
105 int impl;
106 egl_connection_t const* cnx;
107};
108
109struct egl_context_t : public egl_object_t<'_ctx'>
110{
111 egl_context_t(EGLDisplay dpy, EGLContext context,
112 int impl, egl_connection_t const* cnx)
113 : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
114 {
115 }
116 EGLDisplay dpy;
117 EGLContext context;
118 EGLSurface read;
119 EGLSurface draw;
120 int impl;
121 egl_connection_t const* cnx;
122};
123
124struct tls_t
125{
126 tls_t() : error(EGL_SUCCESS), ctx(0) { }
127 EGLint error;
128 EGLContext ctx;
129};
130
131static void gl_unimplemented() {
132 LOGE("called unimplemented OpenGL ES API");
133}
134
135// ----------------------------------------------------------------------------
136// GL / EGL hooks
137// ----------------------------------------------------------------------------
138
139#undef GL_ENTRY
140#undef EGL_ENTRY
141#define GL_ENTRY(_r, _api, ...) #_api,
142#define EGL_ENTRY(_r, _api, ...) #_api,
143
144static char const * const gl_names[] = {
145 #include "gl_entries.in"
146 NULL
147};
148
149static char const * const egl_names[] = {
150 #include "egl_entries.in"
151 NULL
152};
153
154#undef GL_ENTRY
155#undef EGL_ENTRY
156
157// ----------------------------------------------------------------------------
158
Mathias Agopian53238bd2009-04-22 18:24:18 -0700159egl_connection_t gEGLImpl[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800160static egl_display_t gDisplay[NUM_DISPLAYS];
161static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
162static pthread_key_t gEGLThreadLocalStorageKey = -1;
163
164// ----------------------------------------------------------------------------
165
166gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
167pthread_key_t gGLWrapperKey = -1;
168
169// ----------------------------------------------------------------------------
170
171static __attribute__((noinline))
172const char *egl_strerror(EGLint err)
173{
174 switch (err){
175 case EGL_SUCCESS: return "EGL_SUCCESS";
176 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
177 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
178 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
179 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
180 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
181 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
182 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
183 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
184 case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
185 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
186 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
187 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
188 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
189 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
190 default: return "UNKNOWN";
191 }
192}
193
194static __attribute__((noinline))
195void clearTLS() {
196 if (gEGLThreadLocalStorageKey != -1) {
197 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
198 if (tls) {
199 delete tls;
200 pthread_setspecific(gEGLThreadLocalStorageKey, 0);
201 }
202 }
203}
204
205static tls_t* getTLS()
206{
207 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
208 if (tls == 0) {
209 tls = new tls_t;
210 pthread_setspecific(gEGLThreadLocalStorageKey, tls);
211 }
212 return tls;
213}
214
215template<typename T>
216static __attribute__((noinline))
217T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
218 if (gEGLThreadLocalStorageKey == -1) {
219 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
220 if (gEGLThreadLocalStorageKey == -1)
221 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
222 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
223 }
224 tls_t* tls = getTLS();
225 if (tls->error != error) {
226 LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
227 tls->error = error;
228 }
229 return returnValue;
230}
231
232static __attribute__((noinline))
233GLint getError() {
234 if (gEGLThreadLocalStorageKey == -1)
235 return EGL_SUCCESS;
236 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
237 if (!tls) return EGL_SUCCESS;
238 GLint error = tls->error;
239 tls->error = EGL_SUCCESS;
240 return error;
241}
242
243static __attribute__((noinline))
244void setContext(EGLContext ctx) {
245 if (gEGLThreadLocalStorageKey == -1) {
246 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
247 if (gEGLThreadLocalStorageKey == -1)
248 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
249 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
250 }
251 tls_t* tls = getTLS();
252 tls->ctx = ctx;
253}
254
255static __attribute__((noinline))
256EGLContext getContext() {
257 if (gEGLThreadLocalStorageKey == -1)
258 return EGL_NO_CONTEXT;
259 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
260 if (!tls) return EGL_NO_CONTEXT;
261 return tls->ctx;
262}
263
264
265/*****************************************************************************/
266
267class ISurfaceComposer;
268const sp<ISurfaceComposer>& getSurfaceFlinger();
269request_gpu_t* gpu_acquire(void* user);
270int gpu_release(void*, request_gpu_t* gpu);
271
272static __attribute__((noinline))
273void *load_driver(const char* driver, gl_hooks_t* hooks)
274{
275 void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
276 LOGE_IF(!dso,
277 "couldn't load <%s> library (%s)",
278 driver, dlerror());
279
280 if (dso) {
Mathias Agopian53238bd2009-04-22 18:24:18 -0700281 // first find the symbol for eglGetProcAddress
282
283 typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
284 const char*);
285
286 getProcAddressType getProcAddress =
287 (getProcAddressType)dlsym(dso, "eglGetProcAddress");
288
289 LOGE_IF(!getProcAddress,
290 "can't find eglGetProcAddress() in %s", driver);
291
292 __eglMustCastToProperFunctionPointerType* curr;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800293 char const * const * api;
Mathias Agopian53238bd2009-04-22 18:24:18 -0700294
295 gl_hooks_t::egl_t* egl = &hooks->egl;
296 curr = (__eglMustCastToProperFunctionPointerType*)egl;
297 api = egl_names;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800298 while (*api) {
Mathias Agopian53238bd2009-04-22 18:24:18 -0700299 char const * name = *api;
300 __eglMustCastToProperFunctionPointerType f =
301 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800302 if (f == NULL) {
Mathias Agopian53238bd2009-04-22 18:24:18 -0700303 // couldn't find the entry-point, use eglGetProcAddress()
304 f = getProcAddress(name);
305 if (f == NULL) {
306 f = (__eglMustCastToProperFunctionPointerType)0;
307 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800308 }
309 *curr++ = f;
310 api++;
311 }
Mathias Agopian53238bd2009-04-22 18:24:18 -0700312
313 gl_hooks_t::gl_t* gl = &hooks->gl;
314 curr = (__eglMustCastToProperFunctionPointerType*)gl;
315 api = gl_names;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800316 while (*api) {
Mathias Agopian53238bd2009-04-22 18:24:18 -0700317 char const * name = *api;
318 // if the function starts with '__' it's a special case that
319 // uses a wrapper. skip the '__' when looking into the real lib.
320 if (name[0] == '_' && name[1] == '_') {
321 name += 2;
322 }
323 __eglMustCastToProperFunctionPointerType f =
324 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800325 if (f == NULL) {
Mathias Agopian53238bd2009-04-22 18:24:18 -0700326 // couldn't find the entry-point, use eglGetProcAddress()
327 f = getProcAddress(name);
328 if (f == NULL) {
329 f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
330 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800331 }
332 *curr++ = f;
333 api++;
334 }
335
336 // hook this driver up with surfaceflinger if needed
337 register_gpu_t register_gpu =
338 (register_gpu_t)dlsym(dso, "oem_register_gpu");
339
340 if (register_gpu != NULL) {
341 if (getSurfaceFlinger() != 0) {
342 register_gpu(dso, gpu_acquire, gpu_release);
343 }
344 }
345 }
346 return dso;
347}
348
349template<typename T>
350static __attribute__((noinline))
351int binarySearch(
352 T const sortedArray[], int first, int last, T key)
353{
354 while (first <= last) {
355 int mid = (first + last) / 2;
356 if (key > sortedArray[mid]) {
357 first = mid + 1;
358 } else if (key < sortedArray[mid]) {
359 last = mid - 1;
360 } else {
361 return mid;
362 }
363 }
364 return -1;
365}
366
367static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
368{
369 // NOTE: this mapping works only if we have no more than two EGLimpl
370 return (i>0 ? dp->numConfigs[0] : 0) + index;
371}
372
373static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
374 int& i, int& index)
375{
376 // NOTE: this mapping works only if we have no more than two EGLimpl
377 size_t numConfigs = dp->numConfigs[0];
378 i = configId / numConfigs;
379 index = configId % numConfigs;
380}
381
382static int cmp_configs(const void* a, const void *b)
383{
384 EGLConfig c0 = *(EGLConfig const *)a;
385 EGLConfig c1 = *(EGLConfig const *)b;
386 return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
387}
388
389struct extention_map_t {
390 const char* name;
391 __eglMustCastToProperFunctionPointerType address;
392};
393
394static const extention_map_t gExtentionMap[] = {
395};
396
397static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
398
399static void(*findProcAddress(const char* name,
400 const extention_map_t* map, size_t n))()
401{
402 for (uint32_t i=0 ; i<n ; i++) {
403 if (!strcmp(name, map[i].name)) {
404 return map[i].address;
405 }
406 }
407 return NULL;
408}
409
410// ----------------------------------------------------------------------------
411
412static int gl_context_lost() {
413 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
414 return 0;
415}
416static int egl_context_lost() {
417 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
418 return EGL_FALSE;
419}
420static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
421 usleep(100000); // don't use all the CPU
422 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
423 return EGL_FALSE;
424}
425static GLint egl_context_lost_get_error() {
426 return EGL_CONTEXT_LOST;
427}
428static int ext_context_lost() {
429 return 0;
430}
431
432static void gl_no_context() {
433 LOGE("call to OpenGL ES API with no current context");
434}
435static void early_egl_init(void)
436{
437#if !USE_FAST_TLS_KEY
438 pthread_key_create(&gGLWrapperKey, NULL);
439#endif
440 uint32_t addr = (uint32_t)((void*)gl_no_context);
441 android_memset32(
442 (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT],
443 addr,
444 sizeof(gHooks[IMPL_NO_CONTEXT]));
445 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
446}
447
448static pthread_once_t once_control = PTHREAD_ONCE_INIT;
449static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
450
451
452static inline
453egl_display_t* get_display(EGLDisplay dpy)
454{
455 uintptr_t index = uintptr_t(dpy)-1U;
456 return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
457}
458
Mathias Agopian53238bd2009-04-22 18:24:18 -0700459template<typename NATIVE, typename EGL>
460static inline NATIVE* egl_to_native_cast(EGL arg) {
461 return reinterpret_cast<NATIVE*>(arg);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800462}
463
464static inline
Mathias Agopian53238bd2009-04-22 18:24:18 -0700465egl_surface_t* get_surface(EGLSurface surface) {
466 return egl_to_native_cast<egl_surface_t>(surface);
467}
468
469static inline
470egl_context_t* get_context(EGLContext context) {
471 return egl_to_native_cast<egl_context_t>(context);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800472}
473
474static egl_connection_t* validate_display_config(
475 EGLDisplay dpy, EGLConfig config,
476 egl_display_t const*& dp, int& impl, int& index)
477{
478 dp = get_display(dpy);
479 if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
480
481 impl = uintptr_t(config)>>24;
Mathias Agopian53238bd2009-04-22 18:24:18 -0700482 if (uint32_t(impl) >= IMPL_NUM_DRIVERS_IMPLEMENTATIONS) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800483 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
484 }
485 index = uintptr_t(config) & 0xFFFFFF;
486 if (index >= dp->numConfigs[impl]) {
487 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
488 }
489 egl_connection_t* const cnx = &gEGLImpl[impl];
490 if (cnx->dso == 0) {
491 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
492 }
493 return cnx;
494}
495
496static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
497{
498 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
499 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
500 if (!get_display(dpy)->isValid())
501 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
502 if (!ctx) // TODO: make sure context is a valid object
503 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
504 if (!get_context(ctx)->isValid())
505 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
506 return EGL_TRUE;
507}
508
509static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
510{
511 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
512 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
513 if (!get_display(dpy)->isValid())
514 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
515 if (!surface) // TODO: make sure surface is a valid object
516 return setError(EGL_BAD_SURFACE, EGL_FALSE);
517 if (!get_surface(surface)->isValid())
518 return setError(EGL_BAD_SURFACE, EGL_FALSE);
519 return EGL_TRUE;
520}
521
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800522
Mathias Agopian53238bd2009-04-22 18:24:18 -0700523EGLDisplay egl_init_displays(NativeDisplayType display)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800524{
525 if (sEarlyInitState) {
526 return EGL_NO_DISPLAY;
527 }
528
529 uint32_t index = uint32_t(display);
530 if (index >= NUM_DISPLAYS) {
531 return EGL_NO_DISPLAY;
532 }
533
534 EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
535 egl_display_t* d = &gDisplay[index];
Mathias Agopian53238bd2009-04-22 18:24:18 -0700536
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800537 // dynamically load all our EGL implementations for that display
538 // and call into the real eglGetGisplay()
539 egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
540 if (cnx->dso == 0) {
541 cnx->hooks = &gHooks[IMPL_SOFTWARE];
542 cnx->dso = load_driver("libagl.so", cnx->hooks);
543 }
544 if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
545 d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
546 LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
547 "No EGLDisplay for software EGL!");
548 }
549
550 cnx = &gEGLImpl[IMPL_HARDWARE];
551 if (cnx->dso == 0 && cnx->unavailable == 0) {
552 char value[PROPERTY_VALUE_MAX];
553 property_get("debug.egl.hw", value, "1");
554 if (atoi(value) != 0) {
555 cnx->hooks = &gHooks[IMPL_HARDWARE];
556 cnx->dso = load_driver("libhgl.so", cnx->hooks);
557 } else {
558 LOGD("3D hardware acceleration is disabled");
559 }
560 }
561 if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
562 android_memset32(
563 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
564 (uint32_t)((void*)gl_context_lost),
565 sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
566 android_memset32(
567 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
568 (uint32_t)((void*)egl_context_lost),
569 sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
570 android_memset32(
571 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
572 (uint32_t)((void*)ext_context_lost),
573 sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
574
575 gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
576 egl_context_lost_swap_buffers;
577
578 gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
579 egl_context_lost_get_error;
580
581 gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
582 gHooks[IMPL_HARDWARE].egl.eglTerminate;
583
584 d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
585 if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
586 LOGE("h/w accelerated eglGetDisplay() failed (%s)",
587 egl_strerror(cnx->hooks->egl.eglGetError()));
588 dlclose((void*)cnx->dso);
589 cnx->dso = 0;
590 // in case of failure, we want to make sure we don't try again
591 // as it's expensive.
592 cnx->unavailable = 1;
593 }
594 }
595
596 return dpy;
597}
598
Mathias Agopian53238bd2009-04-22 18:24:18 -0700599
600// ----------------------------------------------------------------------------
601}; // namespace android
602// ----------------------------------------------------------------------------
603
604using namespace android;
605
606EGLDisplay eglGetDisplay(NativeDisplayType display)
607{
608 return egl_init_displays(display);
609}
610
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800611// ----------------------------------------------------------------------------
612// Initialization
613// ----------------------------------------------------------------------------
614
615EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
616{
617 egl_display_t * const dp = get_display(dpy);
618 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
619
620 if (android_atomic_inc(&dp->refs) > 0) {
621 if (major != NULL) *major = VERSION_MAJOR;
622 if (minor != NULL) *minor = VERSION_MINOR;
623 return EGL_TRUE;
624 }
625
626 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
627
628 // initialize each EGL and
629 // build our own extension string first, based on the extension we know
630 // and the extension supported by our client implementation
631 dp->extensionsString = strdup(gExtensionString);
Mathias Agopian53238bd2009-04-22 18:24:18 -0700632 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800633 egl_connection_t* const cnx = &gEGLImpl[i];
634 cnx->major = -1;
635 cnx->minor = -1;
636 if (!cnx->dso)
637 continue;
638
639 if (cnx->hooks->egl.eglInitialize(
640 dp->dpys[i], &cnx->major, &cnx->minor)) {
641
642 //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
643 // i, dp->dpys[i], cnx->major, cnx->minor, cnx);
644
645 // get the query-strings for this display for each implementation
646 dp->queryString[i].vendor =
647 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
648 dp->queryString[i].version =
649 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
650 dp->queryString[i].extensions = strdup(
651 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
652 dp->queryString[i].clientApi =
653 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
654
655 } else {
656 LOGD("%d: eglInitialize() failed (%s)",
657 i, egl_strerror(cnx->hooks->egl.eglGetError()));
658 }
659 }
660
661 EGLBoolean res = EGL_FALSE;
Mathias Agopian53238bd2009-04-22 18:24:18 -0700662 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800663 egl_connection_t* const cnx = &gEGLImpl[i];
664 if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
665 EGLint n;
666 if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
667 dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
668 if (dp->configs[i]) {
669 if (cnx->hooks->egl.eglGetConfigs(
670 dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
671 {
672 // sort the configurations so we can do binary searches
673 qsort( dp->configs[i],
674 dp->numConfigs[i],
675 sizeof(EGLConfig), cmp_configs);
676
677 dp->numTotalConfigs += n;
678 res = EGL_TRUE;
679 }
680 }
681 }
682 }
683 }
684
685 if (res == EGL_TRUE) {
686 if (major != NULL) *major = VERSION_MAJOR;
687 if (minor != NULL) *minor = VERSION_MINOR;
688 return EGL_TRUE;
689 }
690 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
691}
692
693EGLBoolean eglTerminate(EGLDisplay dpy)
694{
695 egl_display_t* const dp = get_display(dpy);
696 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
697 if (android_atomic_dec(&dp->refs) != 1)
698 return EGL_TRUE;
699
700 EGLBoolean res = EGL_FALSE;
Mathias Agopian53238bd2009-04-22 18:24:18 -0700701 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800702 egl_connection_t* const cnx = &gEGLImpl[i];
703 if (cnx->dso) {
704 cnx->hooks->egl.eglTerminate(dp->dpys[i]);
705
706 /* REVISIT: it's unclear what to do if eglTerminate() fails,
707 * on one end we shouldn't care, on the other end if it fails
708 * it might not be safe to call dlclose() (there could be some
709 * threads around). */
710
711 free(dp->configs[i]);
712 free((void*)dp->queryString[i].extensions);
713 dp->numConfigs[i] = 0;
714 dp->dpys[i] = EGL_NO_DISPLAY;
715 dlclose((void*)cnx->dso);
716 cnx->dso = 0;
717 res = EGL_TRUE;
718 }
719 }
720 free((void*)dp->extensionsString);
721 dp->extensionsString = 0;
722 dp->numTotalConfigs = 0;
723 clearTLS();
724 return res;
725}
726
727// ----------------------------------------------------------------------------
728// configuration
729// ----------------------------------------------------------------------------
730
731EGLBoolean eglGetConfigs( EGLDisplay dpy,
732 EGLConfig *configs,
733 EGLint config_size, EGLint *num_config)
734{
735 egl_display_t const * const dp = get_display(dpy);
736 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
737
738 GLint numConfigs = dp->numTotalConfigs;
739 if (!configs) {
740 *num_config = numConfigs;
741 return EGL_TRUE;
742 }
743 GLint n = 0;
Mathias Agopian53238bd2009-04-22 18:24:18 -0700744 for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800745 for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
746 *configs++ = MAKE_CONFIG(j, i);
747 config_size--;
748 n++;
749 }
750 }
751
752 *num_config = n;
753 return EGL_TRUE;
754}
755
756EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
757 EGLConfig *configs, EGLint config_size,
758 EGLint *num_config)
759{
760 egl_display_t const * const dp = get_display(dpy);
761 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
762
Jack Palevich87d80222009-03-24 22:48:26 -0700763 if (num_config==0) {
764 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800765 }
766
767 EGLint n;
768 EGLBoolean res = EGL_FALSE;
769 *num_config = 0;
770
771
772 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
773 // to do this, we have to go through the attrib_list array once
774 // to figure out both its size and if it contains an EGL_CONFIG_ID
775 // key. If so, the full array is copied and patched.
776 // NOTE: we assume that there can be only one occurrence
777 // of EGL_CONFIG_ID.
778
779 EGLint patch_index = -1;
780 GLint attr;
781 size_t size = 0;
782 while ((attr=attrib_list[size])) {
783 if (attr == EGL_CONFIG_ID)
784 patch_index = size;
785 size += 2;
786 }
787 if (patch_index >= 0) {
788 size += 2; // we need copy the sentinel as well
789 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
790 if (new_list == 0)
791 return setError(EGL_BAD_ALLOC, EGL_FALSE);
792 memcpy(new_list, attrib_list, size*sizeof(EGLint));
793
794 // patch the requested EGL_CONFIG_ID
795 int i, index;
796 EGLint& configId(new_list[patch_index+1]);
797 uniqueIdToConfig(dp, configId, i, index);
798
799 egl_connection_t* const cnx = &gEGLImpl[i];
800 if (cnx->dso) {
801 cnx->hooks->egl.eglGetConfigAttrib(
802 dp->dpys[i], dp->configs[i][index],
803 EGL_CONFIG_ID, &configId);
804
805 // and switch to the new list
806 attrib_list = const_cast<const EGLint *>(new_list);
807
808 // At this point, the only configuration that can match is
809 // dp->configs[i][index], however, we don't know if it would be
810 // rejected because of the other attributes, so we do have to call
811 // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
812 // through all the EGLimpl[].
813 // We also know we can only get a single config back, and we know
814 // which one.
815
816 res = cnx->hooks->egl.eglChooseConfig(
817 dp->dpys[i], attrib_list, configs, config_size, &n);
818 if (res && n>0) {
819 // n has to be 0 or 1, by construction, and we already know
820 // which config it will return (since there can be only one).
Jack Palevich87d80222009-03-24 22:48:26 -0700821 if (configs) {
822 configs[0] = MAKE_CONFIG(i, index);
823 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800824 *num_config = 1;
825 }
826 }
827
828 free(const_cast<EGLint *>(attrib_list));
829 return res;
830 }
831
Mathias Agopian53238bd2009-04-22 18:24:18 -0700832 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800833 egl_connection_t* const cnx = &gEGLImpl[i];
834 if (cnx->dso) {
835 if (cnx->hooks->egl.eglChooseConfig(
836 dp->dpys[i], attrib_list, configs, config_size, &n)) {
Jack Palevich87d80222009-03-24 22:48:26 -0700837 if (configs) {
838 // now we need to convert these client EGLConfig to our
839 // internal EGLConfig format. This is done in O(n log n).
840 for (int j=0 ; j<n ; j++) {
841 int index = binarySearch<EGLConfig>(
842 dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
843 if (index >= 0) {
844 if (configs) {
845 configs[j] = MAKE_CONFIG(i, index);
846 }
847 } else {
848 return setError(EGL_BAD_CONFIG, EGL_FALSE);
849 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800850 }
Jack Palevich87d80222009-03-24 22:48:26 -0700851 configs += n;
852 config_size -= n;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800853 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800854 *num_config += n;
855 res = EGL_TRUE;
856 }
857 }
858 }
859 return res;
860}
861
862EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
863 EGLint attribute, EGLint *value)
864{
865 egl_display_t const* dp = 0;
866 int i=0, index=0;
867 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
868 if (!cnx) return EGL_FALSE;
869
870 if (attribute == EGL_CONFIG_ID) {
871 // EGL_CONFIG_IDs must be unique, just use the order of the selected
872 // EGLConfig.
873 *value = configToUniqueId(dp, i, index);
874 return EGL_TRUE;
875 }
876 return cnx->hooks->egl.eglGetConfigAttrib(
877 dp->dpys[i], dp->configs[i][index], attribute, value);
878}
879
880// ----------------------------------------------------------------------------
881// surfaces
882// ----------------------------------------------------------------------------
883
884EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
885 NativeWindowType window,
886 const EGLint *attrib_list)
887{
888 egl_display_t const* dp = 0;
889 int i=0, index=0;
890 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
891 if (cnx) {
892 // window must be connected upon calling underlying
893 // eglCreateWindowSurface
894 if (window) {
895 window->incRef(window);
896 if (window->connect)
897 window->connect(window);
898 }
899
900 EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
901 dp->dpys[i], dp->configs[i][index], window, attrib_list);
902 if (surface != EGL_NO_SURFACE) {
903 egl_surface_t* s = new egl_surface_t(dpy, surface, window, i, cnx);
904 return s;
905 }
906
907 // something went wrong, disconnect and free window
908 // (will disconnect() automatically)
909 if (window) {
910 window->decRef(window);
911 }
912 }
913 return EGL_NO_SURFACE;
914}
915
916EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
917 NativePixmapType pixmap,
918 const EGLint *attrib_list)
919{
920 egl_display_t const* dp = 0;
921 int i=0, index=0;
922 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
923 if (cnx) {
924 EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
925 dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
926 if (surface != EGL_NO_SURFACE) {
927 egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
928 return s;
929 }
930 }
931 return EGL_NO_SURFACE;
932}
933
934EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
935 const EGLint *attrib_list)
936{
937 egl_display_t const* dp = 0;
938 int i=0, index=0;
939 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
940 if (cnx) {
941 EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
942 dp->dpys[i], dp->configs[i][index], attrib_list);
943 if (surface != EGL_NO_SURFACE) {
944 egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
945 return s;
946 }
947 }
948 return EGL_NO_SURFACE;
949}
950
951EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
952{
953 if (!validate_display_surface(dpy, surface))
954 return EGL_FALSE;
955 egl_display_t const * const dp = get_display(dpy);
956 egl_surface_t const * const s = get_surface(surface);
957
958 EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
959 dp->dpys[s->impl], s->surface);
960
961 delete s;
962 return result;
963}
964
965EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
966 EGLint attribute, EGLint *value)
967{
968 if (!validate_display_surface(dpy, surface))
969 return EGL_FALSE;
970 egl_display_t const * const dp = get_display(dpy);
971 egl_surface_t const * const s = get_surface(surface);
972
973 return s->cnx->hooks->egl.eglQuerySurface(
974 dp->dpys[s->impl], s->surface, attribute, value);
975}
976
977// ----------------------------------------------------------------------------
978// contextes
979// ----------------------------------------------------------------------------
980
981EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
982 EGLContext share_list, const EGLint *attrib_list)
983{
984 egl_display_t const* dp = 0;
985 int i=0, index=0;
986 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
987 if (cnx) {
988 EGLContext context = cnx->hooks->egl.eglCreateContext(
989 dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
990 if (context != EGL_NO_CONTEXT) {
991 egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
992 return c;
993 }
994 }
995 return EGL_NO_CONTEXT;
996}
997
998EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
999{
1000 if (!validate_display_context(dpy, ctx))
1001 return EGL_FALSE;
1002 egl_display_t const * const dp = get_display(dpy);
1003 egl_context_t * const c = get_context(ctx);
1004 EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
1005 dp->dpys[c->impl], c->context);
1006 delete c;
1007 return result;
1008}
1009
1010EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
1011 EGLSurface read, EGLContext ctx)
1012{
1013 egl_display_t const * const dp = get_display(dpy);
1014 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1015
1016 if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
1017 ctx == EGL_NO_CONTEXT)
1018 {
1019 EGLBoolean result = EGL_TRUE;
1020 ctx = getContext();
1021 if (ctx) {
1022 egl_context_t * const c = get_context(ctx);
1023 result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
1024 if (result == EGL_TRUE) {
1025 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
1026 setContext(EGL_NO_CONTEXT);
1027 }
1028 }
1029 return result;
1030 }
1031
1032 if (!validate_display_context(dpy, ctx))
1033 return EGL_FALSE;
1034
1035 egl_context_t * const c = get_context(ctx);
1036 if (draw != EGL_NO_SURFACE) {
1037 egl_surface_t const * d = get_surface(draw);
1038 if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1039 if (d->impl != c->impl)
1040 return setError(EGL_BAD_MATCH, EGL_FALSE);
1041 draw = d->surface;
1042 }
1043 if (read != EGL_NO_SURFACE) {
1044 egl_surface_t const * r = get_surface(read);
1045 if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1046 if (r->impl != c->impl)
1047 return setError(EGL_BAD_MATCH, EGL_FALSE);
1048 read = r->surface;
1049 }
1050 EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
1051 dp->dpys[c->impl], draw, read, c->context);
1052
1053 if (result == EGL_TRUE) {
1054 setGlThreadSpecific(c->cnx->hooks);
1055 setContext(ctx);
1056 c->read = read;
1057 c->draw = draw;
1058 }
1059 return result;
1060}
1061
1062
1063EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1064 EGLint attribute, EGLint *value)
1065{
1066 if (!validate_display_context(dpy, ctx))
1067 return EGL_FALSE;
1068
1069 egl_display_t const * const dp = get_display(dpy);
1070 egl_context_t * const c = get_context(ctx);
1071
1072 return c->cnx->hooks->egl.eglQueryContext(
1073 dp->dpys[c->impl], c->context, attribute, value);
1074}
1075
1076EGLContext eglGetCurrentContext(void)
1077{
1078 EGLContext ctx = getContext();
1079 return ctx;
1080}
1081
1082EGLSurface eglGetCurrentSurface(EGLint readdraw)
1083{
1084 EGLContext ctx = getContext();
1085 if (ctx) {
1086 egl_context_t const * const c = get_context(ctx);
1087 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1088 switch (readdraw) {
1089 case EGL_READ: return c->read;
1090 case EGL_DRAW: return c->draw;
1091 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1092 }
1093 }
1094 return EGL_NO_SURFACE;
1095}
1096
1097EGLDisplay eglGetCurrentDisplay(void)
1098{
1099 EGLContext ctx = getContext();
1100 if (ctx) {
1101 egl_context_t const * const c = get_context(ctx);
1102 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1103 return c->dpy;
1104 }
1105 return EGL_NO_DISPLAY;
1106}
1107
1108EGLBoolean eglWaitGL(void)
1109{
1110 EGLBoolean res = EGL_TRUE;
1111 EGLContext ctx = getContext();
1112 if (ctx) {
1113 egl_context_t const * const c = get_context(ctx);
1114 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1115 if (uint32_t(c->impl)>=2)
1116 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1117 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1118 if (!cnx->dso)
1119 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1120 res = cnx->hooks->egl.eglWaitGL();
1121 }
1122 return res;
1123}
1124
1125EGLBoolean eglWaitNative(EGLint engine)
1126{
1127 EGLBoolean res = EGL_TRUE;
1128 EGLContext ctx = getContext();
1129 if (ctx) {
1130 egl_context_t const * const c = get_context(ctx);
1131 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1132 if (uint32_t(c->impl)>=2)
1133 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1134 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1135 if (!cnx->dso)
1136 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1137 res = cnx->hooks->egl.eglWaitNative(engine);
1138 }
1139 return res;
1140}
1141
1142EGLint eglGetError(void)
1143{
1144 EGLint result = EGL_SUCCESS;
Mathias Agopian53238bd2009-04-22 18:24:18 -07001145 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001146 EGLint err = EGL_SUCCESS;
1147 egl_connection_t* const cnx = &gEGLImpl[i];
1148 if (cnx->dso)
1149 err = cnx->hooks->egl.eglGetError();
1150 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1151 result = err;
1152 }
1153 if (result == EGL_SUCCESS)
1154 result = getError();
1155 return result;
1156}
1157
Mathias Agopian53238bd2009-04-22 18:24:18 -07001158__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001159{
Mathias Agopian53238bd2009-04-22 18:24:18 -07001160 // eglGetProcAddress() could be the very first function called
1161 // in which case we must make sure we've initialized ourselves, this
1162 // happens the first time egl_get_display() is called.
1163
1164 if (egl_init_displays(EGL_DEFAULT_DISPLAY) == EGL_NO_DISPLAY)
1165 return NULL;
1166
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001167 __eglMustCastToProperFunctionPointerType addr;
1168 addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1169 if (addr) return addr;
1170
1171 return NULL; // TODO: finish implementation below
1172
1173 addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1174 if (addr) return addr;
1175
1176 addr = 0;
1177 int slot = -1;
Mathias Agopian53238bd2009-04-22 18:24:18 -07001178 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001179 egl_connection_t* const cnx = &gEGLImpl[i];
1180 if (cnx->dso) {
1181 if (cnx->hooks->egl.eglGetProcAddress) {
1182 addr = cnx->hooks->egl.eglGetProcAddress(procname);
1183 if (addr) {
1184 if (slot == -1) {
1185 slot = 0; // XXX: find free slot
1186 if (slot == -1) {
1187 addr = 0;
1188 break;
1189 }
1190 }
1191 cnx->hooks->ext.extensions[slot] = addr;
1192 }
1193 }
1194 }
1195 }
1196
1197 if (slot >= 0) {
1198 addr = 0; // XXX: address of stub 'slot'
1199 gGLExtentionMap[slot].name = strdup(procname);
1200 gGLExtentionMap[slot].address = addr;
1201 }
1202
1203 return addr;
1204
1205
1206 /*
1207 * TODO: For OpenGL ES extensions, we must generate a stub
1208 * that looks like
1209 * mov r12, #0xFFFF0FFF
1210 * ldr r12, [r12, #-15]
1211 * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
1212 * mov r12, [r12, #api_offset]
1213 * ldrne pc, r12
1214 * mov pc, #unsupported_extension
1215 *
1216 * and write the address of the extension in *all*
1217 * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1218 *
1219 */
1220}
1221
1222EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1223{
1224 if (!validate_display_surface(dpy, draw))
1225 return EGL_FALSE;
1226 egl_display_t const * const dp = get_display(dpy);
1227 egl_surface_t const * const s = get_surface(draw);
1228 return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1229}
1230
1231EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1232 NativePixmapType target)
1233{
1234 if (!validate_display_surface(dpy, surface))
1235 return EGL_FALSE;
1236 egl_display_t const * const dp = get_display(dpy);
1237 egl_surface_t const * const s = get_surface(surface);
1238 return s->cnx->hooks->egl.eglCopyBuffers(
1239 dp->dpys[s->impl], s->surface, target);
1240}
1241
1242const char* eglQueryString(EGLDisplay dpy, EGLint name)
1243{
1244 egl_display_t const * const dp = get_display(dpy);
1245 switch (name) {
1246 case EGL_VENDOR:
1247 return gVendorString;
1248 case EGL_VERSION:
1249 return gVersionString;
1250 case EGL_EXTENSIONS:
1251 return gExtensionString;
1252 case EGL_CLIENT_APIS:
1253 return gClientApiString;
1254 }
1255 return setError(EGL_BAD_PARAMETER, (const char *)0);
1256}
1257
1258
1259// ----------------------------------------------------------------------------
1260// EGL 1.1
1261// ----------------------------------------------------------------------------
1262
1263EGLBoolean eglSurfaceAttrib(
1264 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1265{
1266 if (!validate_display_surface(dpy, surface))
1267 return EGL_FALSE;
1268 egl_display_t const * const dp = get_display(dpy);
1269 egl_surface_t const * const s = get_surface(surface);
1270 if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1271 return s->cnx->hooks->egl.eglSurfaceAttrib(
1272 dp->dpys[s->impl], s->surface, attribute, value);
1273 }
1274 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1275}
1276
1277EGLBoolean eglBindTexImage(
1278 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1279{
1280 if (!validate_display_surface(dpy, surface))
1281 return EGL_FALSE;
1282 egl_display_t const * const dp = get_display(dpy);
1283 egl_surface_t const * const s = get_surface(surface);
1284 if (s->cnx->hooks->egl.eglBindTexImage) {
1285 return s->cnx->hooks->egl.eglBindTexImage(
1286 dp->dpys[s->impl], s->surface, buffer);
1287 }
1288 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1289}
1290
1291EGLBoolean eglReleaseTexImage(
1292 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1293{
1294 if (!validate_display_surface(dpy, surface))
1295 return EGL_FALSE;
1296 egl_display_t const * const dp = get_display(dpy);
1297 egl_surface_t const * const s = get_surface(surface);
1298 if (s->cnx->hooks->egl.eglReleaseTexImage) {
1299 return s->cnx->hooks->egl.eglReleaseTexImage(
1300 dp->dpys[s->impl], s->surface, buffer);
1301 }
1302 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1303}
1304
1305EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1306{
1307 egl_display_t * const dp = get_display(dpy);
1308 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1309
1310 EGLBoolean res = EGL_TRUE;
Mathias Agopian53238bd2009-04-22 18:24:18 -07001311 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001312 egl_connection_t* const cnx = &gEGLImpl[i];
1313 if (cnx->dso) {
1314 if (cnx->hooks->egl.eglSwapInterval) {
1315 if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1316 res = EGL_FALSE;
1317 }
1318 }
1319 }
1320 }
1321 return res;
1322}
1323
1324
1325// ----------------------------------------------------------------------------
1326// EGL 1.2
1327// ----------------------------------------------------------------------------
1328
1329EGLBoolean eglWaitClient(void)
1330{
1331 EGLBoolean res = EGL_TRUE;
1332 EGLContext ctx = getContext();
1333 if (ctx) {
1334 egl_context_t const * const c = get_context(ctx);
1335 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1336 if (uint32_t(c->impl)>=2)
1337 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1338 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1339 if (!cnx->dso)
1340 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1341 if (cnx->hooks->egl.eglWaitClient) {
1342 res = cnx->hooks->egl.eglWaitClient();
1343 } else {
1344 res = cnx->hooks->egl.eglWaitGL();
1345 }
1346 }
1347 return res;
1348}
1349
1350EGLBoolean eglBindAPI(EGLenum api)
1351{
1352 // bind this API on all EGLs
1353 EGLBoolean res = EGL_TRUE;
Mathias Agopian53238bd2009-04-22 18:24:18 -07001354 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001355 egl_connection_t* const cnx = &gEGLImpl[i];
1356 if (cnx->dso) {
1357 if (cnx->hooks->egl.eglBindAPI) {
1358 if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1359 res = EGL_FALSE;
1360 }
1361 }
1362 }
1363 }
1364 return res;
1365}
1366
1367EGLenum eglQueryAPI(void)
1368{
Mathias Agopian53238bd2009-04-22 18:24:18 -07001369 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001370 egl_connection_t* const cnx = &gEGLImpl[i];
1371 if (cnx->dso) {
1372 if (cnx->hooks->egl.eglQueryAPI) {
1373 // the first one we find is okay, because they all
1374 // should be the same
1375 return cnx->hooks->egl.eglQueryAPI();
1376 }
1377 }
1378 }
1379 // or, it can only be OpenGL ES
1380 return EGL_OPENGL_ES_API;
1381}
1382
1383EGLBoolean eglReleaseThread(void)
1384{
Mathias Agopian53238bd2009-04-22 18:24:18 -07001385 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001386 egl_connection_t* const cnx = &gEGLImpl[i];
1387 if (cnx->dso) {
1388 if (cnx->hooks->egl.eglReleaseThread) {
1389 cnx->hooks->egl.eglReleaseThread();
1390 }
1391 }
1392 }
1393 clearTLS();
1394 return EGL_TRUE;
1395}
1396
1397EGLSurface eglCreatePbufferFromClientBuffer(
1398 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1399 EGLConfig config, const EGLint *attrib_list)
1400{
1401 egl_display_t const* dp = 0;
1402 int i=0, index=0;
1403 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1404 if (!cnx) return EGL_FALSE;
1405 if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1406 return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1407 dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1408 }
1409 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1410}