blob: 3f33b675a5f06de46e7a5136ed635046c584406c [file] [log] [blame]
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001/*
2 ** Copyright 2007, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
17#define LOG_TAG "GLLogger"
18
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
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -080030#include <EGL/egl.h>
31#include <EGL/eglext.h>
32#include <GLES/gl.h>
33#include <GLES/glext.h>
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070034
35#include <cutils/log.h>
36#include <cutils/atomic.h>
37#include <cutils/properties.h>
38#include <cutils/memory.h>
39
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -080040#include <utils/RefBase.h>
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070041
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -080042#include "hooks.h"
43#include "egl_impl.h"
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070044
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070045
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070046#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
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -080053#define VERSION_MINOR 1
54#define VERSION_MAJOR 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 = "";
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070059
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{
72 EGLDisplay dpys[2];
73 EGLConfig* configs[2];
74 EGLint numConfigs[2];
75 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;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070083 };
84 strings_t queryString[2];
85};
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
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700131static void gl_unimplemented() {
132 LOGE("called unimplemented OpenGL ES API");
133}
134
135// ----------------------------------------------------------------------------
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800136// GL / EGL hooks
137// ----------------------------------------------------------------------------
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700138
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800139#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
159egl_connection_t gEGLImpl[2];
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700160static egl_display_t gDisplay[NUM_DISPLAYS];
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700161static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
162static pthread_key_t gEGLThreadLocalStorageKey = -1;
163
164// ----------------------------------------------------------------------------
165
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800166gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
167pthread_key_t gGLWrapperKey = -1;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700168
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800169// ----------------------------------------------------------------------------
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700170
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
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700264
265/*****************************************************************************/
266
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800267class ISurfaceComposer;
268const sp<ISurfaceComposer>& getSurfaceFlinger();
269request_gpu_t* gpu_acquire(void* user);
270int gpu_release(void*, request_gpu_t* gpu);
271
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700272static __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) {
281 void** curr;
282 char const * const * api;
283 gl_hooks_t::gl_t* gl = &hooks->gl;
284 curr = (void**)gl;
285 api = gl_names;
286 while (*api) {
287 void* f = dlsym(dso, *api);
288 //LOGD("<%s> @ 0x%p", *api, f);
289 if (f == NULL) {
290 //LOGW("<%s> not found in %s", *api, driver);
291 f = (void*)gl_unimplemented;
292 }
293 *curr++ = f;
294 api++;
295 }
296 gl_hooks_t::egl_t* egl = &hooks->egl;
297 curr = (void**)egl;
298 api = egl_names;
299 while (*api) {
300 void* f = dlsym(dso, *api);
301 if (f == NULL) {
302 //LOGW("<%s> not found in %s", *api, driver);
303 f = (void*)0;
304 }
305 *curr++ = f;
306 api++;
307 }
308
309 // hook this driver up with surfaceflinger if needed
310 register_gpu_t register_gpu =
311 (register_gpu_t)dlsym(dso, "oem_register_gpu");
312
313 if (register_gpu != NULL) {
314 if (getSurfaceFlinger() != 0) {
315 register_gpu(dso, gpu_acquire, gpu_release);
316 }
317 }
318 }
319 return dso;
320}
321
322template<typename T>
323static __attribute__((noinline))
324int binarySearch(
325 T const sortedArray[], int first, int last, T key)
326{
327 while (first <= last) {
328 int mid = (first + last) / 2;
329 if (key > sortedArray[mid]) {
330 first = mid + 1;
331 } else if (key < sortedArray[mid]) {
332 last = mid - 1;
333 } else {
334 return mid;
335 }
336 }
337 return -1;
338}
339
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800340static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
341{
342 // NOTE: this mapping works only if we have no more than two EGLimpl
343 return (i>0 ? dp->numConfigs[0] : 0) + index;
344}
345
346static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
347 int& i, int& index)
348{
349 // NOTE: this mapping works only if we have no more than two EGLimpl
350 size_t numConfigs = dp->numConfigs[0];
351 i = configId / numConfigs;
352 index = configId % numConfigs;
353}
354
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700355static int cmp_configs(const void* a, const void *b)
356{
357 EGLConfig c0 = *(EGLConfig const *)a;
358 EGLConfig c1 = *(EGLConfig const *)b;
359 return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
360}
361
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700362struct extention_map_t {
363 const char* name;
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800364 __eglMustCastToProperFunctionPointerType address;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700365};
366
367static const extention_map_t gExtentionMap[] = {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700368};
369
370static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
371
372static void(*findProcAddress(const char* name,
373 const extention_map_t* map, size_t n))()
374{
375 for (uint32_t i=0 ; i<n ; i++) {
376 if (!strcmp(name, map[i].name)) {
377 return map[i].address;
378 }
379 }
380 return NULL;
381}
382
383// ----------------------------------------------------------------------------
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700384
385static int gl_context_lost() {
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800386 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700387 return 0;
388}
389static int egl_context_lost() {
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800390 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700391 return EGL_FALSE;
392}
393static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
394 usleep(100000); // don't use all the CPU
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800395 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700396 return EGL_FALSE;
397}
398static GLint egl_context_lost_get_error() {
399 return EGL_CONTEXT_LOST;
400}
401static int ext_context_lost() {
402 return 0;
403}
404
405static void gl_no_context() {
406 LOGE("call to OpenGL ES API with no current context");
407}
408static void early_egl_init(void)
409{
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800410#if !USE_FAST_TLS_KEY
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700411 pthread_key_create(&gGLWrapperKey, NULL);
412#endif
413 uint32_t addr = (uint32_t)((void*)gl_no_context);
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800414 android_memset32(
415 (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT],
416 addr,
417 sizeof(gHooks[IMPL_NO_CONTEXT]));
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700418 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
419}
420
421static pthread_once_t once_control = PTHREAD_ONCE_INIT;
422static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
423
424
425static inline
426egl_display_t* get_display(EGLDisplay dpy)
427{
428 uintptr_t index = uintptr_t(dpy)-1U;
429 return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
430}
431
432static inline
433egl_surface_t* get_surface(EGLSurface surface)
434{
435 egl_surface_t* s = (egl_surface_t *)surface;
436 return s;
437}
438
439static inline
440egl_context_t* get_context(EGLContext context)
441{
442 egl_context_t* c = (egl_context_t *)context;
443 return c;
444}
445
446static egl_connection_t* validate_display_config(
447 EGLDisplay dpy, EGLConfig config,
448 egl_display_t const*& dp, int& impl, int& index)
449{
450 dp = get_display(dpy);
451 if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
452
453 impl = uintptr_t(config)>>24;
454 if (uint32_t(impl) >= 2) {
455 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
456 }
457 index = uintptr_t(config) & 0xFFFFFF;
458 if (index >= dp->numConfigs[impl]) {
459 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
460 }
461 egl_connection_t* const cnx = &gEGLImpl[impl];
462 if (cnx->dso == 0) {
463 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
464 }
465 return cnx;
466}
467
468static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
469{
470 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
471 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
472 if (!get_display(dpy)->isValid())
473 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
474 if (!ctx) // TODO: make sure context is a valid object
475 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
476 if (!get_context(ctx)->isValid())
477 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
478 return EGL_TRUE;
479}
480
481static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
482{
483 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
484 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
485 if (!get_display(dpy)->isValid())
486 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
487 if (!surface) // TODO: make sure surface is a valid object
488 return setError(EGL_BAD_SURFACE, EGL_FALSE);
489 if (!get_surface(surface)->isValid())
490 return setError(EGL_BAD_SURFACE, EGL_FALSE);
491 return EGL_TRUE;
492}
493
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700494// ----------------------------------------------------------------------------
495}; // namespace android
496// ----------------------------------------------------------------------------
497
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800498using namespace android;
499
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700500EGLDisplay eglGetDisplay(NativeDisplayType display)
501{
502 if (sEarlyInitState) {
503 return EGL_NO_DISPLAY;
504 }
505
506 uint32_t index = uint32_t(display);
507 if (index >= NUM_DISPLAYS) {
508 return EGL_NO_DISPLAY;
509 }
510
511 EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
512 egl_display_t* d = &gDisplay[index];
513
514 // dynamically load all our EGL implementations for that display
515 // and call into the real eglGetGisplay()
516 egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
517 if (cnx->dso == 0) {
518 cnx->hooks = &gHooks[IMPL_SOFTWARE];
519 cnx->dso = load_driver("libagl.so", cnx->hooks);
520 }
521 if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
522 d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
523 LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
524 "No EGLDisplay for software EGL!");
525 }
526
527 cnx = &gEGLImpl[IMPL_HARDWARE];
528 if (cnx->dso == 0 && cnx->unavailable == 0) {
529 char value[PROPERTY_VALUE_MAX];
530 property_get("debug.egl.hw", value, "1");
531 if (atoi(value) != 0) {
532 cnx->hooks = &gHooks[IMPL_HARDWARE];
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800533 property_get("debug.egl.profiler", value, "0");
534 if (atoi(value) == 0) {
535 cnx->dso = load_driver("libhgl.so", cnx->hooks);
536 } else {
537 LOGW("Using instrumented h/w OpenGL ES library");
538 cnx->dso = load_driver("libhgld.so", cnx->hooks);
539 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700540 } else {
541 LOGD("3D hardware acceleration is disabled");
542 }
543 }
544 if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
545 android_memset32(
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800546 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700547 (uint32_t)((void*)gl_context_lost),
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800548 sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700549 android_memset32(
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800550 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700551 (uint32_t)((void*)egl_context_lost),
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800552 sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700553 android_memset32(
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800554 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700555 (uint32_t)((void*)ext_context_lost),
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800556 sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700557
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800558 gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700559 egl_context_lost_swap_buffers;
560
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800561 gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700562 egl_context_lost_get_error;
563
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800564 gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700565 gHooks[IMPL_HARDWARE].egl.eglTerminate;
566
567 d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
568 if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800569 LOGE("h/w accelerated eglGetDisplay() failed (%s)",
570 egl_strerror(cnx->hooks->egl.eglGetError()));
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700571 dlclose((void*)cnx->dso);
572 cnx->dso = 0;
573 // in case of failure, we want to make sure we don't try again
574 // as it's expensive.
575 cnx->unavailable = 1;
576 }
577 }
578
579 return dpy;
580}
581
582// ----------------------------------------------------------------------------
583// Initialization
584// ----------------------------------------------------------------------------
585
586EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
587{
588 egl_display_t * const dp = get_display(dpy);
589 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
590
591 if (android_atomic_inc(&dp->refs) > 0) {
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800592 if (major != NULL) *major = VERSION_MAJOR;
593 if (minor != NULL) *minor = VERSION_MINOR;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700594 return EGL_TRUE;
595 }
596
597 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
598
599 // initialize each EGL and
600 // build our own extension string first, based on the extension we know
601 // and the extension supported by our client implementation
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -0800602 dp->extensionsString = strdup(gExtensionString);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700603 for (int i=0 ; i<2 ; i++) {
604 egl_connection_t* const cnx = &gEGLImpl[i];
605 cnx->major = -1;
606 cnx->minor = -1;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800607 if (!cnx->dso)
608 continue;
609
610 if (cnx->hooks->egl.eglInitialize(
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700611 dp->dpys[i], &cnx->major, &cnx->minor)) {
612
613 //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
614 // i, dp->dpys[i], cnx->major, cnx->minor, cnx);
615
616 // get the query-strings for this display for each implementation
617 dp->queryString[i].vendor =
618 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
619 dp->queryString[i].version =
620 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
621 dp->queryString[i].extensions = strdup(
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800622 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700623 dp->queryString[i].clientApi =
624 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800625
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800626 } else {
627 LOGD("%d: eglInitialize() failed (%s)",
628 i, egl_strerror(cnx->hooks->egl.eglGetError()));
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700629 }
630 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800631
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700632 EGLBoolean res = EGL_FALSE;
633 for (int i=0 ; i<2 ; i++) {
634 egl_connection_t* const cnx = &gEGLImpl[i];
635 if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700636 EGLint n;
637 if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
638 dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
639 if (dp->configs[i]) {
640 if (cnx->hooks->egl.eglGetConfigs(
641 dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
642 {
643 // sort the configurations so we can do binary searches
644 qsort( dp->configs[i],
645 dp->numConfigs[i],
646 sizeof(EGLConfig), cmp_configs);
647
648 dp->numTotalConfigs += n;
649 res = EGL_TRUE;
650 }
651 }
652 }
653 }
654 }
655
656 if (res == EGL_TRUE) {
657 if (major != NULL) *major = 1;
658 if (minor != NULL) *minor = 2;
659 return EGL_TRUE;
660 }
661 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
662}
663
664EGLBoolean eglTerminate(EGLDisplay dpy)
665{
666 egl_display_t* const dp = get_display(dpy);
667 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
668 if (android_atomic_dec(&dp->refs) != 1)
669 return EGL_TRUE;
670
671 EGLBoolean res = EGL_FALSE;
672 for (int i=0 ; i<2 ; i++) {
673 egl_connection_t* const cnx = &gEGLImpl[i];
674 if (cnx->dso) {
675 cnx->hooks->egl.eglTerminate(dp->dpys[i]);
676
677 /* REVISIT: it's unclear what to do if eglTerminate() fails,
678 * on one end we shouldn't care, on the other end if it fails
679 * it might not be safe to call dlclose() (there could be some
680 * threads around). */
681
682 free(dp->configs[i]);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700683 free((void*)dp->queryString[i].extensions);
684 dp->numConfigs[i] = 0;
685 dp->dpys[i] = EGL_NO_DISPLAY;
686 dlclose((void*)cnx->dso);
687 cnx->dso = 0;
688 res = EGL_TRUE;
689 }
690 }
691 free((void*)dp->extensionsString);
692 dp->extensionsString = 0;
693 dp->numTotalConfigs = 0;
694 clearTLS();
695 return res;
696}
697
698// ----------------------------------------------------------------------------
699// configuration
700// ----------------------------------------------------------------------------
701
702EGLBoolean eglGetConfigs( EGLDisplay dpy,
703 EGLConfig *configs,
704 EGLint config_size, EGLint *num_config)
705{
706 egl_display_t const * const dp = get_display(dpy);
707 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
708
709 GLint numConfigs = dp->numTotalConfigs;
710 if (!configs) {
711 *num_config = numConfigs;
712 return EGL_TRUE;
713 }
714 GLint n = 0;
715 for (int j=0 ; j<2 ; j++) {
716 for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
717 *configs++ = MAKE_CONFIG(j, i);
718 config_size--;
719 n++;
720 }
721 }
722
723 *num_config = n;
724 return EGL_TRUE;
725}
726
727EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
728 EGLConfig *configs, EGLint config_size,
729 EGLint *num_config)
730{
731 egl_display_t const * const dp = get_display(dpy);
732 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
733
734 if (configs == 0) {
735 *num_config = 0;
736 return EGL_TRUE;
737 }
738
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800739 EGLint n;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700740 EGLBoolean res = EGL_FALSE;
741 *num_config = 0;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800742
743
744 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
745 // to do this, we have to go through the attrib_list array once
746 // to figure out both its size and if it contains an EGL_CONFIG_ID
747 // key. If so, the full array is copied and patched.
748 // NOTE: we assume that there can be only one occurrence
749 // of EGL_CONFIG_ID.
750
751 EGLint patch_index = -1;
752 GLint attr;
753 size_t size = 0;
754 while ((attr=attrib_list[size])) {
755 if (attr == EGL_CONFIG_ID)
756 patch_index = size;
757 size += 2;
758 }
759 if (patch_index >= 0) {
760 size += 2; // we need copy the sentinel as well
761 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
762 if (new_list == 0)
763 return setError(EGL_BAD_ALLOC, EGL_FALSE);
764 memcpy(new_list, attrib_list, size*sizeof(EGLint));
765
766 // patch the requested EGL_CONFIG_ID
767 int i, index;
768 EGLint& configId(new_list[patch_index+1]);
769 uniqueIdToConfig(dp, configId, i, index);
770
771 egl_connection_t* const cnx = &gEGLImpl[i];
772 if (cnx->dso) {
773 cnx->hooks->egl.eglGetConfigAttrib(
774 dp->dpys[i], dp->configs[i][index],
775 EGL_CONFIG_ID, &configId);
776
777 // and switch to the new list
778 attrib_list = const_cast<const EGLint *>(new_list);
779
780 // At this point, the only configuration that can match is
781 // dp->configs[i][index], however, we don't know if it would be
782 // rejected because of the other attributes, so we do have to call
783 // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
784 // through all the EGLimpl[].
785 // We also know we can only get a single config back, and we know
786 // which one.
787
788 res = cnx->hooks->egl.eglChooseConfig(
789 dp->dpys[i], attrib_list, configs, config_size, &n);
790 if (res && n>0) {
791 // n has to be 0 or 1, by construction, and we already know
792 // which config it will return (since there can be only one).
793 configs[0] = MAKE_CONFIG(i, index);
794 *num_config = 1;
795 }
796 }
797
798 free(const_cast<EGLint *>(attrib_list));
799 return res;
800 }
801
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700802 for (int i=0 ; i<2 ; i++) {
803 egl_connection_t* const cnx = &gEGLImpl[i];
804 if (cnx->dso) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700805 if (cnx->hooks->egl.eglChooseConfig(
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800806 dp->dpys[i], attrib_list, configs, config_size, &n)) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700807 // now we need to convert these client EGLConfig to our
808 // internal EGLConfig format. This is done in O(n log n).
809 for (int j=0 ; j<n ; j++) {
810 int index = binarySearch<EGLConfig>(
811 dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
812 if (index >= 0) {
813 configs[j] = MAKE_CONFIG(i, index);
814 } else {
815 return setError(EGL_BAD_CONFIG, EGL_FALSE);
816 }
817 }
818 configs += n;
819 config_size -= n;
820 *num_config += n;
821 res = EGL_TRUE;
822 }
823 }
824 }
825 return res;
826}
827
828EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
829 EGLint attribute, EGLint *value)
830{
831 egl_display_t const* dp = 0;
832 int i=0, index=0;
833 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
834 if (!cnx) return EGL_FALSE;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800835
836 if (attribute == EGL_CONFIG_ID) {
837 // EGL_CONFIG_IDs must be unique, just use the order of the selected
838 // EGLConfig.
839 *value = configToUniqueId(dp, i, index);
840 return EGL_TRUE;
841 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700842 return cnx->hooks->egl.eglGetConfigAttrib(
843 dp->dpys[i], dp->configs[i][index], attribute, value);
844}
845
846// ----------------------------------------------------------------------------
847// surfaces
848// ----------------------------------------------------------------------------
849
850EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
851 NativeWindowType window,
852 const EGLint *attrib_list)
853{
854 egl_display_t const* dp = 0;
855 int i=0, index=0;
856 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
857 if (cnx) {
858 // window must be connected upon calling underlying
859 // eglCreateWindowSurface
860 if (window) {
861 window->incRef(window);
862 if (window->connect)
863 window->connect(window);
864 }
865
866 EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
867 dp->dpys[i], dp->configs[i][index], window, attrib_list);
868 if (surface != EGL_NO_SURFACE) {
869 egl_surface_t* s = new egl_surface_t(dpy, surface, window, i, cnx);
870 return s;
871 }
872
873 // something went wrong, disconnect and free window
874 // (will disconnect() automatically)
875 if (window) {
876 window->decRef(window);
877 }
878 }
879 return EGL_NO_SURFACE;
880}
881
882EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
883 NativePixmapType pixmap,
884 const EGLint *attrib_list)
885{
886 egl_display_t const* dp = 0;
887 int i=0, index=0;
888 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
889 if (cnx) {
890 EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
891 dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
892 if (surface != EGL_NO_SURFACE) {
893 egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
894 return s;
895 }
896 }
897 return EGL_NO_SURFACE;
898}
899
900EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
901 const EGLint *attrib_list)
902{
903 egl_display_t const* dp = 0;
904 int i=0, index=0;
905 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
906 if (cnx) {
907 EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
908 dp->dpys[i], dp->configs[i][index], attrib_list);
909 if (surface != EGL_NO_SURFACE) {
910 egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
911 return s;
912 }
913 }
914 return EGL_NO_SURFACE;
915}
916
917EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
918{
919 if (!validate_display_surface(dpy, surface))
920 return EGL_FALSE;
921 egl_display_t const * const dp = get_display(dpy);
922 egl_surface_t const * const s = get_surface(surface);
923
924 EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
925 dp->dpys[s->impl], s->surface);
926
927 delete s;
928 return result;
929}
930
931EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
932 EGLint attribute, EGLint *value)
933{
934 if (!validate_display_surface(dpy, surface))
935 return EGL_FALSE;
936 egl_display_t const * const dp = get_display(dpy);
937 egl_surface_t const * const s = get_surface(surface);
938
939 return s->cnx->hooks->egl.eglQuerySurface(
940 dp->dpys[s->impl], s->surface, attribute, value);
941}
942
943// ----------------------------------------------------------------------------
944// contextes
945// ----------------------------------------------------------------------------
946
947EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
948 EGLContext share_list, const EGLint *attrib_list)
949{
950 egl_display_t const* dp = 0;
951 int i=0, index=0;
952 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
953 if (cnx) {
954 EGLContext context = cnx->hooks->egl.eglCreateContext(
955 dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
956 if (context != EGL_NO_CONTEXT) {
957 egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
958 return c;
959 }
960 }
961 return EGL_NO_CONTEXT;
962}
963
964EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
965{
966 if (!validate_display_context(dpy, ctx))
967 return EGL_FALSE;
968 egl_display_t const * const dp = get_display(dpy);
969 egl_context_t * const c = get_context(ctx);
970 EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
971 dp->dpys[c->impl], c->context);
972 delete c;
973 return result;
974}
975
976EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
977 EGLSurface read, EGLContext ctx)
978{
979 egl_display_t const * const dp = get_display(dpy);
980 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
981
982 if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
983 ctx == EGL_NO_CONTEXT)
984 {
985 EGLBoolean result = EGL_TRUE;
986 ctx = getContext();
987 if (ctx) {
988 egl_context_t * const c = get_context(ctx);
989 result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
990 if (result == EGL_TRUE) {
991 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
992 setContext(EGL_NO_CONTEXT);
993 }
994 }
995 return result;
996 }
997
998 if (!validate_display_context(dpy, ctx))
999 return EGL_FALSE;
1000
1001 egl_context_t * const c = get_context(ctx);
1002 if (draw != EGL_NO_SURFACE) {
1003 egl_surface_t const * d = get_surface(draw);
1004 if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1005 if (d->impl != c->impl)
1006 return setError(EGL_BAD_MATCH, EGL_FALSE);
1007 draw = d->surface;
1008 }
1009 if (read != EGL_NO_SURFACE) {
1010 egl_surface_t const * r = get_surface(read);
1011 if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1012 if (r->impl != c->impl)
1013 return setError(EGL_BAD_MATCH, EGL_FALSE);
1014 read = r->surface;
1015 }
1016 EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
1017 dp->dpys[c->impl], draw, read, c->context);
1018
1019 if (result == EGL_TRUE) {
1020 setGlThreadSpecific(c->cnx->hooks);
1021 setContext(ctx);
1022 c->read = read;
1023 c->draw = draw;
1024 }
1025 return result;
1026}
1027
1028
1029EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1030 EGLint attribute, EGLint *value)
1031{
1032 if (!validate_display_context(dpy, ctx))
1033 return EGL_FALSE;
1034
1035 egl_display_t const * const dp = get_display(dpy);
1036 egl_context_t * const c = get_context(ctx);
1037
1038 return c->cnx->hooks->egl.eglQueryContext(
1039 dp->dpys[c->impl], c->context, attribute, value);
1040}
1041
1042EGLContext eglGetCurrentContext(void)
1043{
1044 EGLContext ctx = getContext();
1045 return ctx;
1046}
1047
1048EGLSurface eglGetCurrentSurface(EGLint readdraw)
1049{
1050 EGLContext ctx = getContext();
1051 if (ctx) {
1052 egl_context_t const * const c = get_context(ctx);
1053 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1054 switch (readdraw) {
1055 case EGL_READ: return c->read;
1056 case EGL_DRAW: return c->draw;
1057 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1058 }
1059 }
1060 return EGL_NO_SURFACE;
1061}
1062
1063EGLDisplay eglGetCurrentDisplay(void)
1064{
1065 EGLContext ctx = getContext();
1066 if (ctx) {
1067 egl_context_t const * const c = get_context(ctx);
1068 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1069 return c->dpy;
1070 }
1071 return EGL_NO_DISPLAY;
1072}
1073
1074EGLBoolean eglWaitGL(void)
1075{
1076 EGLBoolean res = EGL_TRUE;
1077 EGLContext ctx = getContext();
1078 if (ctx) {
1079 egl_context_t const * const c = get_context(ctx);
1080 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1081 if (uint32_t(c->impl)>=2)
1082 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1083 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1084 if (!cnx->dso)
1085 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1086 res = cnx->hooks->egl.eglWaitGL();
1087 }
1088 return res;
1089}
1090
1091EGLBoolean eglWaitNative(EGLint engine)
1092{
1093 EGLBoolean res = EGL_TRUE;
1094 EGLContext ctx = getContext();
1095 if (ctx) {
1096 egl_context_t const * const c = get_context(ctx);
1097 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1098 if (uint32_t(c->impl)>=2)
1099 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1100 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1101 if (!cnx->dso)
1102 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1103 res = cnx->hooks->egl.eglWaitNative(engine);
1104 }
1105 return res;
1106}
1107
1108EGLint eglGetError(void)
1109{
1110 EGLint result = EGL_SUCCESS;
1111 for (int i=0 ; i<2 ; i++) {
1112 EGLint err = EGL_SUCCESS;
1113 egl_connection_t* const cnx = &gEGLImpl[i];
1114 if (cnx->dso)
1115 err = cnx->hooks->egl.eglGetError();
1116 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1117 result = err;
1118 }
1119 if (result == EGL_SUCCESS)
1120 result = getError();
1121 return result;
1122}
1123
1124void (*eglGetProcAddress(const char *procname))()
1125{
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -08001126 __eglMustCastToProperFunctionPointerType addr;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001127 addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1128 if (addr) return addr;
1129
1130 return NULL; // TODO: finish implementation below
1131
1132 addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1133 if (addr) return addr;
1134
1135 addr = 0;
1136 int slot = -1;
1137 for (int i=0 ; i<2 ; i++) {
1138 egl_connection_t* const cnx = &gEGLImpl[i];
1139 if (cnx->dso) {
1140 if (cnx->hooks->egl.eglGetProcAddress) {
1141 addr = cnx->hooks->egl.eglGetProcAddress(procname);
1142 if (addr) {
1143 if (slot == -1) {
1144 slot = 0; // XXX: find free slot
1145 if (slot == -1) {
1146 addr = 0;
1147 break;
1148 }
1149 }
1150 cnx->hooks->ext.extensions[slot] = addr;
1151 }
1152 }
1153 }
1154 }
1155
1156 if (slot >= 0) {
1157 addr = 0; // XXX: address of stub 'slot'
1158 gGLExtentionMap[slot].name = strdup(procname);
1159 gGLExtentionMap[slot].address = addr;
1160 }
1161
1162 return addr;
1163
1164
1165 /*
1166 * TODO: For OpenGL ES extensions, we must generate a stub
1167 * that looks like
1168 * mov r12, #0xFFFF0FFF
1169 * ldr r12, [r12, #-15]
1170 * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
1171 * mov r12, [r12, #api_offset]
1172 * ldrne pc, r12
1173 * mov pc, #unsupported_extension
1174 *
1175 * and write the address of the extension in *all*
1176 * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1177 *
1178 */
1179}
1180
1181EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1182{
1183 if (!validate_display_surface(dpy, draw))
1184 return EGL_FALSE;
1185 egl_display_t const * const dp = get_display(dpy);
1186 egl_surface_t const * const s = get_surface(draw);
1187 return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1188}
1189
1190EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1191 NativePixmapType target)
1192{
1193 if (!validate_display_surface(dpy, surface))
1194 return EGL_FALSE;
1195 egl_display_t const * const dp = get_display(dpy);
1196 egl_surface_t const * const s = get_surface(surface);
1197 return s->cnx->hooks->egl.eglCopyBuffers(
1198 dp->dpys[s->impl], s->surface, target);
1199}
1200
1201const char* eglQueryString(EGLDisplay dpy, EGLint name)
1202{
1203 egl_display_t const * const dp = get_display(dpy);
1204 switch (name) {
1205 case EGL_VENDOR:
1206 return gVendorString;
1207 case EGL_VERSION:
1208 return gVersionString;
1209 case EGL_EXTENSIONS:
The Android Open Source Projecta6938ba2009-02-10 15:44:00 -08001210 return gExtensionString;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001211 case EGL_CLIENT_APIS:
1212 return gClientApiString;
1213 }
1214 return setError(EGL_BAD_PARAMETER, (const char *)0);
1215}
1216
1217
1218// ----------------------------------------------------------------------------
1219// EGL 1.1
1220// ----------------------------------------------------------------------------
1221
1222EGLBoolean eglSurfaceAttrib(
1223 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1224{
1225 if (!validate_display_surface(dpy, surface))
1226 return EGL_FALSE;
1227 egl_display_t const * const dp = get_display(dpy);
1228 egl_surface_t const * const s = get_surface(surface);
1229 if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1230 return s->cnx->hooks->egl.eglSurfaceAttrib(
1231 dp->dpys[s->impl], s->surface, attribute, value);
1232 }
1233 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1234}
1235
1236EGLBoolean eglBindTexImage(
1237 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1238{
1239 if (!validate_display_surface(dpy, surface))
1240 return EGL_FALSE;
1241 egl_display_t const * const dp = get_display(dpy);
1242 egl_surface_t const * const s = get_surface(surface);
1243 if (s->cnx->hooks->egl.eglBindTexImage) {
1244 return s->cnx->hooks->egl.eglBindTexImage(
1245 dp->dpys[s->impl], s->surface, buffer);
1246 }
1247 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1248}
1249
1250EGLBoolean eglReleaseTexImage(
1251 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1252{
1253 if (!validate_display_surface(dpy, surface))
1254 return EGL_FALSE;
1255 egl_display_t const * const dp = get_display(dpy);
1256 egl_surface_t const * const s = get_surface(surface);
1257 if (s->cnx->hooks->egl.eglReleaseTexImage) {
1258 return s->cnx->hooks->egl.eglReleaseTexImage(
1259 dp->dpys[s->impl], s->surface, buffer);
1260 }
1261 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1262}
1263
1264EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1265{
1266 egl_display_t * const dp = get_display(dpy);
1267 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1268
1269 EGLBoolean res = EGL_TRUE;
1270 for (int i=0 ; i<2 ; i++) {
1271 egl_connection_t* const cnx = &gEGLImpl[i];
1272 if (cnx->dso) {
1273 if (cnx->hooks->egl.eglSwapInterval) {
1274 if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1275 res = EGL_FALSE;
1276 }
1277 }
1278 }
1279 }
1280 return res;
1281}
1282
1283
1284// ----------------------------------------------------------------------------
1285// EGL 1.2
1286// ----------------------------------------------------------------------------
1287
1288EGLBoolean eglWaitClient(void)
1289{
1290 EGLBoolean res = EGL_TRUE;
1291 EGLContext ctx = getContext();
1292 if (ctx) {
1293 egl_context_t const * const c = get_context(ctx);
1294 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1295 if (uint32_t(c->impl)>=2)
1296 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1297 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1298 if (!cnx->dso)
1299 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1300 if (cnx->hooks->egl.eglWaitClient) {
1301 res = cnx->hooks->egl.eglWaitClient();
1302 } else {
1303 res = cnx->hooks->egl.eglWaitGL();
1304 }
1305 }
1306 return res;
1307}
1308
1309EGLBoolean eglBindAPI(EGLenum api)
1310{
1311 // bind this API on all EGLs
1312 EGLBoolean res = EGL_TRUE;
1313 for (int i=0 ; i<2 ; i++) {
1314 egl_connection_t* const cnx = &gEGLImpl[i];
1315 if (cnx->dso) {
1316 if (cnx->hooks->egl.eglBindAPI) {
1317 if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1318 res = EGL_FALSE;
1319 }
1320 }
1321 }
1322 }
1323 return res;
1324}
1325
1326EGLenum eglQueryAPI(void)
1327{
1328 for (int i=0 ; i<2 ; i++) {
1329 egl_connection_t* const cnx = &gEGLImpl[i];
1330 if (cnx->dso) {
1331 if (cnx->hooks->egl.eglQueryAPI) {
1332 // the first one we find is okay, because they all
1333 // should be the same
1334 return cnx->hooks->egl.eglQueryAPI();
1335 }
1336 }
1337 }
1338 // or, it can only be OpenGL ES
1339 return EGL_OPENGL_ES_API;
1340}
1341
1342EGLBoolean eglReleaseThread(void)
1343{
1344 for (int i=0 ; i<2 ; i++) {
1345 egl_connection_t* const cnx = &gEGLImpl[i];
1346 if (cnx->dso) {
1347 if (cnx->hooks->egl.eglReleaseThread) {
1348 cnx->hooks->egl.eglReleaseThread();
1349 }
1350 }
1351 }
1352 clearTLS();
1353 return EGL_TRUE;
1354}
1355
1356EGLSurface eglCreatePbufferFromClientBuffer(
1357 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1358 EGLConfig config, const EGLint *attrib_list)
1359{
1360 egl_display_t const* dp = 0;
1361 int i=0, index=0;
1362 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1363 if (!cnx) return EGL_FALSE;
1364 if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1365 return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1366 dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1367 }
1368 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1369}