blob: 319753570d1a2469742332d5b8a75f19aed8caa7 [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
30#include <GLES/egl.h>
31
32#include <cutils/log.h>
33#include <cutils/atomic.h>
34#include <cutils/properties.h>
35#include <cutils/memory.h>
36
37#include <utils/IMemory.h>
38#include <utils/KeyedVector.h>
39#include <utils/threads.h>
40#include <utils/IServiceManager.h>
41#include <utils/IPCThreadState.h>
42#include <utils/Parcel.h>
43
44#include <ui/EGLDisplaySurface.h>
45#include <ui/ISurfaceComposer.h>
46
47#include "gl_logger.h"
48
49#undef NELEM
50
51#define GL_LOGGER 0
52#define USE_SLOW_BINDING 0
53#define NELEM(x) (sizeof(x)/sizeof(*(x)))
54#define MAX_NUMBER_OF_GL_EXTENSIONS 32
55#define MAKE_CONFIG(_impl, _index) ((EGLConfig)(((_impl)<<24) | (_index)))
56#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
57
58// ----------------------------------------------------------------------------
59namespace android {
60// ----------------------------------------------------------------------------
61
62// EGLDisplay are global, not attached to a given thread
63static const unsigned int NUM_DISPLAYS = 1;
64static const unsigned int IMPL_HARDWARE = 0;
65static const unsigned int IMPL_SOFTWARE = 1;
66static const unsigned int IMPL_HARDWARE_CONTEXT_LOST = 2;
67static const unsigned int IMPL_SOFTWARE_CONTEXT_LOST = 3;
68static const unsigned int IMPL_NO_CONTEXT = 4;
69
70// ----------------------------------------------------------------------------
71
72struct gl_hooks_t;
73
74struct egl_connection_t
75{
76 void volatile * dso;
77 gl_hooks_t * hooks;
78 EGLint major;
79 EGLint minor;
80 int unavailable;
81};
82
83template <int MAGIC>
84struct egl_object_t
85{
86 egl_object_t() : magic(MAGIC) { }
87 ~egl_object_t() { magic = 0; }
88 bool isValid() const { return magic == MAGIC; }
89private:
90 uint32_t magic;
91};
92
93struct egl_display_t : public egl_object_t<'_dpy'>
94{
95 EGLDisplay dpys[2];
96 EGLConfig* configs[2];
97 EGLint numConfigs[2];
98 EGLint numTotalConfigs;
99 char const* extensionsString;
100 volatile int32_t refs;
101 struct strings_t {
102 char const * vendor;
103 char const * version;
104 char const * clientApi;
105 char const * extensions;
106 char const * extensions_config;
107 };
108 strings_t queryString[2];
109};
110
111struct egl_surface_t : public egl_object_t<'_srf'>
112{
113 egl_surface_t(EGLDisplay dpy, EGLSurface surface,
114 NativeWindowType window, int impl, egl_connection_t const* cnx)
115 : dpy(dpy), surface(surface), window(window), impl(impl), cnx(cnx)
116 {
117 // NOTE: window must be incRef'ed and connected already
118 }
119 ~egl_surface_t() {
120 if (window) {
121 if (window->disconnect)
122 window->disconnect(window);
123 window->decRef(window);
124 }
125 }
126 EGLDisplay dpy;
127 EGLSurface surface;
128 NativeWindowType window;
129 int impl;
130 egl_connection_t const* cnx;
131};
132
133struct egl_context_t : public egl_object_t<'_ctx'>
134{
135 egl_context_t(EGLDisplay dpy, EGLContext context,
136 int impl, egl_connection_t const* cnx)
137 : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
138 {
139 }
140 EGLDisplay dpy;
141 EGLContext context;
142 EGLSurface read;
143 EGLSurface draw;
144 int impl;
145 egl_connection_t const* cnx;
146};
147
148struct tls_t
149{
150 tls_t() : error(EGL_SUCCESS), ctx(0) { }
151 EGLint error;
152 EGLContext ctx;
153};
154
155
156// GL / EGL hooks
157
158typedef void(*proc_t)();
159
160struct gl_hooks_t {
161 struct gl_t {
162 #define GL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
163 #include "gl_entries.cpp"
164 #undef GL_ENTRY
165 } gl;
166 struct egl_t {
167 #define EGL_ENTRY(_r, _api, ...) _r (*_api)(__VA_ARGS__);
168 #include "egl_entries.cpp"
169 #undef EGL_ENTRY
170 } egl;
171 struct gl_ext_t {
172 void (*extensions[MAX_NUMBER_OF_GL_EXTENSIONS])(void);
173 } ext;
174};
175
176static char const * const gl_names[] = {
177 #define GL_ENTRY(_r, _api, ...) #_api,
178 #include "gl_entries.cpp"
179 #undef GL_ENTRY
180 NULL
181};
182
183static char const * const egl_names[] = {
184 #define EGL_ENTRY(_r, _api, ...) #_api,
185 #include "egl_entries.cpp"
186 #undef EGL_ENTRY
187 NULL
188};
189
190static void gl_unimplemented() {
191 LOGE("called unimplemented OpenGL ES API");
192}
193
194// ----------------------------------------------------------------------------
195
196static egl_connection_t gEGLImpl[2];
197static egl_display_t gDisplay[NUM_DISPLAYS];
198static gl_hooks_t gHooks[5];
199static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
200static pthread_key_t gEGLThreadLocalStorageKey = -1;
201
202// ----------------------------------------------------------------------------
203
204#if defined(HAVE_ANDROID_OS) && !USE_SLOW_BINDING && !GL_LOGGER
205
The Android Open Source Project8a7a6752009-01-15 16:12:10 -0800206/* special private C library header */
207#include <bionic_tls.h>
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700208// We have a dedicated TLS slot in bionic
209static inline void setGlThreadSpecific(gl_hooks_t const *value) {
210 ((uint32_t *)__get_tls())[TLS_SLOT_OPENGL_API] = (uint32_t)value;
211}
212static gl_hooks_t const* getGlThreadSpecific() {
213 gl_hooks_t const* hooks = (gl_hooks_t const *)(((unsigned const *)__get_tls())[TLS_SLOT_OPENGL_API]);
214 if (hooks) return hooks;
215 return &gHooks[IMPL_NO_CONTEXT];
216}
217
218#else
219
220static pthread_key_t gGLWrapperKey = -1;
221static inline void setGlThreadSpecific(gl_hooks_t const *value) {
222 pthread_setspecific(gGLWrapperKey, value);
223}
224static gl_hooks_t const* getGlThreadSpecific() {
225 gl_hooks_t const* hooks = static_cast<gl_hooks_t*>(pthread_getspecific(gGLWrapperKey));
226 if (hooks) return hooks;
227 return &gHooks[IMPL_NO_CONTEXT];
228}
229
230#endif
231
232static __attribute__((noinline))
233const char *egl_strerror(EGLint err)
234{
235 switch (err){
236 case EGL_SUCCESS: return "EGL_SUCCESS";
237 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
238 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
239 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
240 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
241 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
242 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
243 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
244 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
245 case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
246 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
247 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
248 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
249 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
250 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
251 default: return "UNKNOWN";
252 }
253}
254
255static __attribute__((noinline))
256void clearTLS() {
257 if (gEGLThreadLocalStorageKey != -1) {
258 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
259 if (tls) {
260 delete tls;
261 pthread_setspecific(gEGLThreadLocalStorageKey, 0);
262 }
263 }
264}
265
266static tls_t* getTLS()
267{
268 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
269 if (tls == 0) {
270 tls = new tls_t;
271 pthread_setspecific(gEGLThreadLocalStorageKey, tls);
272 }
273 return tls;
274}
275
276template<typename T>
277static __attribute__((noinline))
278T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
279 if (gEGLThreadLocalStorageKey == -1) {
280 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
281 if (gEGLThreadLocalStorageKey == -1)
282 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
283 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
284 }
285 tls_t* tls = getTLS();
286 if (tls->error != error) {
287 LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
288 tls->error = error;
289 }
290 return returnValue;
291}
292
293static __attribute__((noinline))
294GLint getError() {
295 if (gEGLThreadLocalStorageKey == -1)
296 return EGL_SUCCESS;
297 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
298 if (!tls) return EGL_SUCCESS;
299 GLint error = tls->error;
300 tls->error = EGL_SUCCESS;
301 return error;
302}
303
304static __attribute__((noinline))
305void setContext(EGLContext ctx) {
306 if (gEGLThreadLocalStorageKey == -1) {
307 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
308 if (gEGLThreadLocalStorageKey == -1)
309 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
310 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
311 }
312 tls_t* tls = getTLS();
313 tls->ctx = ctx;
314}
315
316static __attribute__((noinline))
317EGLContext getContext() {
318 if (gEGLThreadLocalStorageKey == -1)
319 return EGL_NO_CONTEXT;
320 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
321 if (!tls) return EGL_NO_CONTEXT;
322 return tls->ctx;
323}
324
325/*****************************************************************************/
326
327/*
328 * we provide our own allocators for the GPU regions, these
329 * allocators go through surfaceflinger
330 */
331
332static Mutex gRegionsLock;
333static request_gpu_t gRegions;
334static sp<ISurfaceComposer> gSurfaceManager;
335ISurfaceComposer* GLES_localSurfaceManager = 0;
336
337const sp<ISurfaceComposer>& getSurfaceFlinger()
338{
339 Mutex::Autolock _l(gRegionsLock);
340
341 /*
342 * There is a little bit of voodoo magic here. We want to access
343 * surfaceflinger for allocating GPU regions, however, when we are
344 * running as part of surfaceflinger, we want to bypass the
345 * service manager because surfaceflinger might not be registered yet.
346 * SurfaceFlinger will populate "GLES_localSurfaceManager" with its
347 * own address, so we can just use that.
348 */
349 if (gSurfaceManager == 0) {
350 if (GLES_localSurfaceManager) {
351 // we're running in SurfaceFlinger's context
352 gSurfaceManager = GLES_localSurfaceManager;
353 } else {
354 // we're a remote process or not part of surfaceflinger,
355 // go through the service manager
356 sp<IServiceManager> sm = defaultServiceManager();
357 if (sm != NULL) {
358 sp<IBinder> binder = sm->getService(String16("SurfaceFlinger"));
359 gSurfaceManager = interface_cast<ISurfaceComposer>(binder);
360 }
361 }
362 }
363 return gSurfaceManager;
364}
365
366class GPURevokeRequester : public BnGPUCallback
367{
368public:
369 virtual void gpuLost() {
370 LOGD("CONTEXT_LOST: Releasing GPU upon request from SurfaceFlinger.");
371 gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_HARDWARE_CONTEXT_LOST];
372 }
373};
374
375static sp<GPURevokeRequester> gRevokerCallback;
376
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800377
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700378static request_gpu_t* gpu_acquire(void* user)
379{
380 sp<ISurfaceComposer> server( getSurfaceFlinger() );
381
382 Mutex::Autolock _l(gRegionsLock);
383 if (server == NULL) {
384 return 0;
385 }
386
387 ISurfaceComposer::gpu_info_t info;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800388
389 if (gRevokerCallback == 0)
390 gRevokerCallback = new GPURevokeRequester();
391
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700392 status_t err = server->requestGPU(gRevokerCallback, &info);
393 if (err != NO_ERROR) {
394 LOGD("requestGPU returned %d", err);
395 return 0;
396 }
397
398 bool failed = false;
399 request_gpu_t* gpu = &gRegions;
400 memset(gpu, 0, sizeof(*gpu));
401
402 if (info.regs != 0) {
403 sp<IMemoryHeap> heap(info.regs->getMemory());
404 if (heap != 0) {
405 int fd = heap->heapID();
406 gpu->regs.fd = fd;
407 gpu->regs.base = info.regs->pointer();
408 gpu->regs.size = info.regs->size();
409 gpu->regs.user = info.regs.get();
410#if HAVE_ANDROID_OS
411 struct pmem_region region;
412 if (ioctl(fd, PMEM_GET_PHYS, &region) >= 0)
413 gpu->regs.phys = (void*)region.offset;
414#endif
415 info.regs->incStrong(gpu);
416 } else {
417 LOGE("GPU register handle %p is invalid!", info.regs.get());
418 failed = true;
419 }
420 }
421
422 for (size_t i=0 ; i<info.count && !failed ; i++) {
423 sp<IMemory>& region(info.regions[i].region);
424 if (region != 0) {
425 sp<IMemoryHeap> heap(region->getMemory());
426 if (heap != 0) {
427 const int fd = heap->heapID();
428 gpu->gpu[i].fd = fd;
429 gpu->gpu[i].base = region->pointer();
430 gpu->gpu[i].size = region->size();
431 gpu->gpu[i].user = region.get();
432 gpu->gpu[i].offset = info.regions[i].reserved;
433#if HAVE_ANDROID_OS
434 struct pmem_region reg;
435 if (ioctl(fd, PMEM_GET_PHYS, &reg) >= 0)
436 gpu->gpu[i].phys = (void*)reg.offset;
437#endif
438 region->incStrong(gpu);
439 } else {
440 LOGE("GPU region handle [%d, %p] is invalid!", i, region.get());
441 failed = true;
442 }
443 }
444 }
445
446 if (failed) {
447 // something went wrong, clean up everything!
448 if (gpu->regs.user) {
449 static_cast<IMemory*>(gpu->regs.user)->decStrong(gpu);
450 for (size_t i=0 ; i<info.count ; i++) {
451 if (gpu->gpu[i].user) {
452 static_cast<IMemory*>(gpu->gpu[i].user)->decStrong(gpu);
453 }
454 }
455 }
456 }
457
458 gpu->count = info.count;
459 return gpu;
460}
461
462static int gpu_release(void*, request_gpu_t* gpu)
463{
464 sp<IMemory> regs;
465
466 { // scope for lock
467 Mutex::Autolock _l(gRegionsLock);
468 regs = static_cast<IMemory*>(gpu->regs.user);
469 gpu->regs.user = 0;
470 if (regs != 0) regs->decStrong(gpu);
471
472 for (int i=0 ; i<gpu->count ; i++) {
473 sp<IMemory> r(static_cast<IMemory*>(gpu->gpu[i].user));
474 gpu->gpu[i].user = 0;
475 if (r != 0) r->decStrong(gpu);
476 }
477 }
478
479 // there is a special transaction to relinquish the GPU
480 // (it will happen automatically anyway if we don't do this)
481 Parcel data, reply;
482 // NOTE: this transaction does not require an interface token
483 regs->asBinder()->transact(1000, data, &reply);
484 return 1;
485}
486
487/*****************************************************************************/
488
489static __attribute__((noinline))
490void *load_driver(const char* driver, gl_hooks_t* hooks)
491{
492 void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
493 LOGE_IF(!dso,
494 "couldn't load <%s> library (%s)",
495 driver, dlerror());
496
497 if (dso) {
498 void** curr;
499 char const * const * api;
500 gl_hooks_t::gl_t* gl = &hooks->gl;
501 curr = (void**)gl;
502 api = gl_names;
503 while (*api) {
504 void* f = dlsym(dso, *api);
505 //LOGD("<%s> @ 0x%p", *api, f);
506 if (f == NULL) {
507 //LOGW("<%s> not found in %s", *api, driver);
508 f = (void*)gl_unimplemented;
509 }
510 *curr++ = f;
511 api++;
512 }
513 gl_hooks_t::egl_t* egl = &hooks->egl;
514 curr = (void**)egl;
515 api = egl_names;
516 while (*api) {
517 void* f = dlsym(dso, *api);
518 if (f == NULL) {
519 //LOGW("<%s> not found in %s", *api, driver);
520 f = (void*)0;
521 }
522 *curr++ = f;
523 api++;
524 }
525
526 // hook this driver up with surfaceflinger if needed
527 register_gpu_t register_gpu =
528 (register_gpu_t)dlsym(dso, "oem_register_gpu");
529
530 if (register_gpu != NULL) {
531 if (getSurfaceFlinger() != 0) {
532 register_gpu(dso, gpu_acquire, gpu_release);
533 }
534 }
535 }
536 return dso;
537}
538
539template<typename T>
540static __attribute__((noinline))
541int binarySearch(
542 T const sortedArray[], int first, int last, T key)
543{
544 while (first <= last) {
545 int mid = (first + last) / 2;
546 if (key > sortedArray[mid]) {
547 first = mid + 1;
548 } else if (key < sortedArray[mid]) {
549 last = mid - 1;
550 } else {
551 return mid;
552 }
553 }
554 return -1;
555}
556
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800557static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
558{
559 // NOTE: this mapping works only if we have no more than two EGLimpl
560 return (i>0 ? dp->numConfigs[0] : 0) + index;
561}
562
563static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
564 int& i, int& index)
565{
566 // NOTE: this mapping works only if we have no more than two EGLimpl
567 size_t numConfigs = dp->numConfigs[0];
568 i = configId / numConfigs;
569 index = configId % numConfigs;
570}
571
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700572static int cmp_configs(const void* a, const void *b)
573{
574 EGLConfig c0 = *(EGLConfig const *)a;
575 EGLConfig c1 = *(EGLConfig const *)b;
576 return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
577}
578
579static char const * const gVendorString = "Android";
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800580static char const * const gVersionString = "1.3 Android META-EGL";
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700581static char const * const gClientApiString = "OpenGL ES";
582
583struct extention_map_t {
584 const char* name;
585 void (*address)(void);
586};
587
588static const extention_map_t gExtentionMap[] = {
589 { "eglSwapRectangleANDROID", (void(*)())&eglSwapRectangleANDROID },
590 { "eglQueryStringConfigANDROID", (void(*)())&eglQueryStringConfigANDROID },
591};
592
593static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
594
595static void(*findProcAddress(const char* name,
596 const extention_map_t* map, size_t n))()
597{
598 for (uint32_t i=0 ; i<n ; i++) {
599 if (!strcmp(name, map[i].name)) {
600 return map[i].address;
601 }
602 }
603 return NULL;
604}
605
606// ----------------------------------------------------------------------------
607}; // namespace android
608// ----------------------------------------------------------------------------
609
610using namespace android;
611
612
613// ----------------------------------------------------------------------------
614// extensions for the framework
615// ----------------------------------------------------------------------------
616
617void glColorPointerBounds(GLint size, GLenum type, GLsizei stride,
618 const GLvoid *ptr, GLsizei count) {
619 glColorPointer(size, type, stride, ptr);
620}
621void glNormalPointerBounds(GLenum type, GLsizei stride,
622 const GLvoid *pointer, GLsizei count) {
623 glNormalPointer(type, stride, pointer);
624}
625void glTexCoordPointerBounds(GLint size, GLenum type,
626 GLsizei stride, const GLvoid *pointer, GLsizei count) {
627 glTexCoordPointer(size, type, stride, pointer);
628}
629void glVertexPointerBounds(GLint size, GLenum type,
630 GLsizei stride, const GLvoid *pointer, GLsizei count) {
631 glVertexPointer(size, type, stride, pointer);
632}
633
634
635// ----------------------------------------------------------------------------
636// Actual GL wrappers
637// ----------------------------------------------------------------------------
638
639#if __OPTIMIZE__ && defined(__arm__) && !defined(__thumb__) && !USE_SLOW_BINDING && !GL_LOGGER
640
641 #define API_ENTRY(_api) __attribute__((naked)) _api
642 #define CALL_GL_API(_api, ...) \
643 asm volatile( \
644 "mov r12, #0xFFFF0FFF \n" \
645 "ldr r12, [r12, #-15] \n" \
646 "ldr r12, [r12, %[tls]] \n" \
647 "cmp r12, #0 \n" \
648 "ldrne pc, [r12, %[api]] \n" \
649 "bx lr \n" \
650 : \
651 : [tls] "J"(TLS_SLOT_OPENGL_API*4), \
652 [api] "J"(__builtin_offsetof(gl_hooks_t, gl._api)) \
653 : \
654 );
655
656 #define CALL_GL_API_RETURN(_api, ...) \
657 CALL_GL_API(_api, __VA_ARGS__) \
658 return 0; // placate gcc's warnings. never reached.
659
660#else
661
662 #define API_ENTRY(_api) _api
663 #if GL_LOGGER
664
665 #define CALL_GL_API(_api, ...) \
666 gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
667 log_##_api(__VA_ARGS__); \
668 _c->_api(__VA_ARGS__);
669
670 #define CALL_GL_API_RETURN(_api, ...) \
671 gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
672 log_##_api(__VA_ARGS__); \
673 return _c->_api(__VA_ARGS__)
674
675 #else
676
677 #define CALL_GL_API(_api, ...) \
678 gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
679 _c->_api(__VA_ARGS__);
680
681 #define CALL_GL_API_RETURN(_api, ...) \
682 gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl; \
683 return _c->_api(__VA_ARGS__)
684
685 #endif
686
687#endif
688
689#include "gl_api.cpp"
690
691#undef API_ENTRY
692#undef CALL_GL_API
693#undef CALL_GL_API_RETURN
694
695// ----------------------------------------------------------------------------
696namespace android {
697// ----------------------------------------------------------------------------
698
699static int gl_context_lost() {
700 setGlThreadSpecific(&gHooks[IMPL_HARDWARE_CONTEXT_LOST]);
701 return 0;
702}
703static int egl_context_lost() {
704 setGlThreadSpecific(&gHooks[IMPL_HARDWARE_CONTEXT_LOST]);
705 return EGL_FALSE;
706}
707static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
708 usleep(100000); // don't use all the CPU
709 setGlThreadSpecific(&gHooks[IMPL_HARDWARE_CONTEXT_LOST]);
710 return EGL_FALSE;
711}
712static GLint egl_context_lost_get_error() {
713 return EGL_CONTEXT_LOST;
714}
715static int ext_context_lost() {
716 return 0;
717}
718
719static void gl_no_context() {
720 LOGE("call to OpenGL ES API with no current context");
721}
722static void early_egl_init(void)
723{
724#if !defined(HAVE_ANDROID_OS) || USE_SLOW_BINDING || GL_LOGGER
725 pthread_key_create(&gGLWrapperKey, NULL);
726#endif
727 uint32_t addr = (uint32_t)((void*)gl_no_context);
728 android_memset32((uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT], addr, sizeof(gHooks[IMPL_NO_CONTEXT]));
729 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
730}
731
732static pthread_once_t once_control = PTHREAD_ONCE_INIT;
733static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
734
735
736static inline
737egl_display_t* get_display(EGLDisplay dpy)
738{
739 uintptr_t index = uintptr_t(dpy)-1U;
740 return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
741}
742
743static inline
744egl_surface_t* get_surface(EGLSurface surface)
745{
746 egl_surface_t* s = (egl_surface_t *)surface;
747 return s;
748}
749
750static inline
751egl_context_t* get_context(EGLContext context)
752{
753 egl_context_t* c = (egl_context_t *)context;
754 return c;
755}
756
757static egl_connection_t* validate_display_config(
758 EGLDisplay dpy, EGLConfig config,
759 egl_display_t const*& dp, int& impl, int& index)
760{
761 dp = get_display(dpy);
762 if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
763
764 impl = uintptr_t(config)>>24;
765 if (uint32_t(impl) >= 2) {
766 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
767 }
768 index = uintptr_t(config) & 0xFFFFFF;
769 if (index >= dp->numConfigs[impl]) {
770 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
771 }
772 egl_connection_t* const cnx = &gEGLImpl[impl];
773 if (cnx->dso == 0) {
774 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
775 }
776 return cnx;
777}
778
779static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
780{
781 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
782 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
783 if (!get_display(dpy)->isValid())
784 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
785 if (!ctx) // TODO: make sure context is a valid object
786 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
787 if (!get_context(ctx)->isValid())
788 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
789 return EGL_TRUE;
790}
791
792static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
793{
794 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
795 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
796 if (!get_display(dpy)->isValid())
797 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
798 if (!surface) // TODO: make sure surface is a valid object
799 return setError(EGL_BAD_SURFACE, EGL_FALSE);
800 if (!get_surface(surface)->isValid())
801 return setError(EGL_BAD_SURFACE, EGL_FALSE);
802 return EGL_TRUE;
803}
804
805static void add_extension(egl_display_t* dp, char const*& p, const char* ext)
806{
807 if (!strstr(p, ext)) {
808 p = (char const*)realloc((void*)p, strlen(p) + 1 + strlen(ext) + 1);
809 strcat((char*)p, " ");
810 strcat((char*)p, ext);
811 }
812 if (!strstr(dp->extensionsString, ext)) {
813 char const*& es = dp->extensionsString;
814 es = (char const*)realloc((void*)es, strlen(es) + 1 + strlen(ext) + 1);
815 strcat((char*)es, " ");
816 strcat((char*)es, ext);
817 }
818}
819
820// ----------------------------------------------------------------------------
821}; // namespace android
822// ----------------------------------------------------------------------------
823
824EGLDisplay eglGetDisplay(NativeDisplayType display)
825{
826 if (sEarlyInitState) {
827 return EGL_NO_DISPLAY;
828 }
829
830 uint32_t index = uint32_t(display);
831 if (index >= NUM_DISPLAYS) {
832 return EGL_NO_DISPLAY;
833 }
834
835 EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
836 egl_display_t* d = &gDisplay[index];
837
838 // dynamically load all our EGL implementations for that display
839 // and call into the real eglGetGisplay()
840 egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
841 if (cnx->dso == 0) {
842 cnx->hooks = &gHooks[IMPL_SOFTWARE];
843 cnx->dso = load_driver("libagl.so", cnx->hooks);
844 }
845 if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
846 d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
847 LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
848 "No EGLDisplay for software EGL!");
849 }
850
851 cnx = &gEGLImpl[IMPL_HARDWARE];
852 if (cnx->dso == 0 && cnx->unavailable == 0) {
853 char value[PROPERTY_VALUE_MAX];
854 property_get("debug.egl.hw", value, "1");
855 if (atoi(value) != 0) {
856 cnx->hooks = &gHooks[IMPL_HARDWARE];
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800857 property_get("debug.egl.profiler", value, "0");
858 if (atoi(value) == 0) {
859 cnx->dso = load_driver("libhgl.so", cnx->hooks);
860 } else {
861 LOGW("Using instrumented h/w OpenGL ES library");
862 cnx->dso = load_driver("libhgld.so", cnx->hooks);
863 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700864 } else {
865 LOGD("3D hardware acceleration is disabled");
866 }
867 }
868 if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
869 android_memset32(
870 (uint32_t*)(void*)&gHooks[IMPL_HARDWARE_CONTEXT_LOST].gl,
871 (uint32_t)((void*)gl_context_lost),
872 sizeof(gHooks[IMPL_HARDWARE_CONTEXT_LOST].gl));
873 android_memset32(
874 (uint32_t*)(void*)&gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl,
875 (uint32_t)((void*)egl_context_lost),
876 sizeof(gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl));
877 android_memset32(
878 (uint32_t*)(void*)&gHooks[IMPL_HARDWARE_CONTEXT_LOST].ext,
879 (uint32_t)((void*)ext_context_lost),
880 sizeof(gHooks[IMPL_HARDWARE_CONTEXT_LOST].ext));
881
882 gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl.eglSwapBuffers =
883 egl_context_lost_swap_buffers;
884
885 gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl.eglGetError =
886 egl_context_lost_get_error;
887
888 gHooks[IMPL_HARDWARE_CONTEXT_LOST].egl.eglTerminate =
889 gHooks[IMPL_HARDWARE].egl.eglTerminate;
890
891 d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
892 if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800893 LOGE("h/w accelerated eglGetDisplay() failed (%s)",
894 egl_strerror(cnx->hooks->egl.eglGetError()));
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700895 dlclose((void*)cnx->dso);
896 cnx->dso = 0;
897 // in case of failure, we want to make sure we don't try again
898 // as it's expensive.
899 cnx->unavailable = 1;
900 }
901 }
902
903 return dpy;
904}
905
906// ----------------------------------------------------------------------------
907// Initialization
908// ----------------------------------------------------------------------------
909
910EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
911{
912 egl_display_t * const dp = get_display(dpy);
913 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
914
915 if (android_atomic_inc(&dp->refs) > 0) {
916 if (major != NULL) *major = 1;
917 if (minor != NULL) *minor = 2;
918 return EGL_TRUE;
919 }
920
921 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
922
923 // initialize each EGL and
924 // build our own extension string first, based on the extension we know
925 // and the extension supported by our client implementation
926 dp->extensionsString = strdup("EGL_ANDROID_query_string_config");
927 for (int i=0 ; i<2 ; i++) {
928 egl_connection_t* const cnx = &gEGLImpl[i];
929 cnx->major = -1;
930 cnx->minor = -1;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800931 if (!cnx->dso)
932 continue;
933
934 if (cnx->hooks->egl.eglInitialize(
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700935 dp->dpys[i], &cnx->major, &cnx->minor)) {
936
937 //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
938 // i, dp->dpys[i], cnx->major, cnx->minor, cnx);
939
940 // get the query-strings for this display for each implementation
941 dp->queryString[i].vendor =
942 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
943 dp->queryString[i].version =
944 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
945 dp->queryString[i].extensions = strdup(
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800946 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700947 dp->queryString[i].clientApi =
948 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800949
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700950 // Dynamically insert extensions we know about
951 if (cnx->hooks->egl.eglSwapRectangleANDROID)
952 add_extension(dp, dp->queryString[i].extensions,
953 "EGL_ANDROID_swap_rectangle");
954
955 if (cnx->hooks->egl.eglQueryStringConfigANDROID)
956 add_extension(dp, dp->queryString[i].extensions,
957 "EGL_ANDROID_query_string_config");
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800958 } else {
959 LOGD("%d: eglInitialize() failed (%s)",
960 i, egl_strerror(cnx->hooks->egl.eglGetError()));
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700961 }
962 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800963
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700964 // Build the extension list that depends on the current config.
965 // It is the intersection of our extension list and the
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800966 // underlying EGL's extensions list
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700967 EGLBoolean res = EGL_FALSE;
968 for (int i=0 ; i<2 ; i++) {
969 egl_connection_t* const cnx = &gEGLImpl[i];
970 if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
971 char const* const their_extensions = dp->queryString[i].extensions;
972 char* our_extensions = strdup(dp->extensionsString);
973 char* const our_extensions_org = our_extensions;
974 char* extensions_config = (char*)calloc(strlen(our_extensions)+2, 1);
975 char* p;
976 do {
977 p = strchr(our_extensions, ' ');
978 if (p) *p++ = 0;
979 else p = strchr(our_extensions, 0);
980 if (strstr(their_extensions, our_extensions)) {
981 strcat(extensions_config, our_extensions);
982 strcat(extensions_config, " ");
983 }
984 our_extensions = p;
985 } while (*p);
986 free((void*)our_extensions_org);
987
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800988 // remove the trailing white space
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700989 if (extensions_config[0] != 0) {
990 size_t l = strlen(extensions_config) - 1; // new size
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800991 extensions_config[l] = 0; // remove the trailing white space
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700992 extensions_config = (char*)realloc(extensions_config, l+1);
993 } else {
994 extensions_config = (char*)realloc(extensions_config, 1);
995 }
996 dp->queryString[i].extensions_config = extensions_config;
997
998 EGLint n;
999 if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
1000 dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
1001 if (dp->configs[i]) {
1002 if (cnx->hooks->egl.eglGetConfigs(
1003 dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
1004 {
1005 // sort the configurations so we can do binary searches
1006 qsort( dp->configs[i],
1007 dp->numConfigs[i],
1008 sizeof(EGLConfig), cmp_configs);
1009
1010 dp->numTotalConfigs += n;
1011 res = EGL_TRUE;
1012 }
1013 }
1014 }
1015 }
1016 }
1017
1018 if (res == EGL_TRUE) {
1019 if (major != NULL) *major = 1;
1020 if (minor != NULL) *minor = 2;
1021 return EGL_TRUE;
1022 }
1023 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
1024}
1025
1026EGLBoolean eglTerminate(EGLDisplay dpy)
1027{
1028 egl_display_t* const dp = get_display(dpy);
1029 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1030 if (android_atomic_dec(&dp->refs) != 1)
1031 return EGL_TRUE;
1032
1033 EGLBoolean res = EGL_FALSE;
1034 for (int i=0 ; i<2 ; i++) {
1035 egl_connection_t* const cnx = &gEGLImpl[i];
1036 if (cnx->dso) {
1037 cnx->hooks->egl.eglTerminate(dp->dpys[i]);
1038
1039 /* REVISIT: it's unclear what to do if eglTerminate() fails,
1040 * on one end we shouldn't care, on the other end if it fails
1041 * it might not be safe to call dlclose() (there could be some
1042 * threads around). */
1043
1044 free(dp->configs[i]);
1045 free((void*)dp->queryString[i].extensions_config);
1046 free((void*)dp->queryString[i].extensions);
1047 dp->numConfigs[i] = 0;
1048 dp->dpys[i] = EGL_NO_DISPLAY;
1049 dlclose((void*)cnx->dso);
1050 cnx->dso = 0;
1051 res = EGL_TRUE;
1052 }
1053 }
1054 free((void*)dp->extensionsString);
1055 dp->extensionsString = 0;
1056 dp->numTotalConfigs = 0;
1057 clearTLS();
1058 return res;
1059}
1060
1061// ----------------------------------------------------------------------------
1062// configuration
1063// ----------------------------------------------------------------------------
1064
1065EGLBoolean eglGetConfigs( EGLDisplay dpy,
1066 EGLConfig *configs,
1067 EGLint config_size, EGLint *num_config)
1068{
1069 egl_display_t const * const dp = get_display(dpy);
1070 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1071
1072 GLint numConfigs = dp->numTotalConfigs;
1073 if (!configs) {
1074 *num_config = numConfigs;
1075 return EGL_TRUE;
1076 }
1077 GLint n = 0;
1078 for (int j=0 ; j<2 ; j++) {
1079 for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
1080 *configs++ = MAKE_CONFIG(j, i);
1081 config_size--;
1082 n++;
1083 }
1084 }
1085
1086 *num_config = n;
1087 return EGL_TRUE;
1088}
1089
1090EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
1091 EGLConfig *configs, EGLint config_size,
1092 EGLint *num_config)
1093{
1094 egl_display_t const * const dp = get_display(dpy);
1095 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1096
1097 if (configs == 0) {
1098 *num_config = 0;
1099 return EGL_TRUE;
1100 }
1101
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001102 EGLint n;
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001103 EGLBoolean res = EGL_FALSE;
1104 *num_config = 0;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001105
1106
1107 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
1108 // to do this, we have to go through the attrib_list array once
1109 // to figure out both its size and if it contains an EGL_CONFIG_ID
1110 // key. If so, the full array is copied and patched.
1111 // NOTE: we assume that there can be only one occurrence
1112 // of EGL_CONFIG_ID.
1113
1114 EGLint patch_index = -1;
1115 GLint attr;
1116 size_t size = 0;
1117 while ((attr=attrib_list[size])) {
1118 if (attr == EGL_CONFIG_ID)
1119 patch_index = size;
1120 size += 2;
1121 }
1122 if (patch_index >= 0) {
1123 size += 2; // we need copy the sentinel as well
1124 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
1125 if (new_list == 0)
1126 return setError(EGL_BAD_ALLOC, EGL_FALSE);
1127 memcpy(new_list, attrib_list, size*sizeof(EGLint));
1128
1129 // patch the requested EGL_CONFIG_ID
1130 int i, index;
1131 EGLint& configId(new_list[patch_index+1]);
1132 uniqueIdToConfig(dp, configId, i, index);
1133
1134 egl_connection_t* const cnx = &gEGLImpl[i];
1135 if (cnx->dso) {
1136 cnx->hooks->egl.eglGetConfigAttrib(
1137 dp->dpys[i], dp->configs[i][index],
1138 EGL_CONFIG_ID, &configId);
1139
1140 // and switch to the new list
1141 attrib_list = const_cast<const EGLint *>(new_list);
1142
1143 // At this point, the only configuration that can match is
1144 // dp->configs[i][index], however, we don't know if it would be
1145 // rejected because of the other attributes, so we do have to call
1146 // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
1147 // through all the EGLimpl[].
1148 // We also know we can only get a single config back, and we know
1149 // which one.
1150
1151 res = cnx->hooks->egl.eglChooseConfig(
1152 dp->dpys[i], attrib_list, configs, config_size, &n);
1153 if (res && n>0) {
1154 // n has to be 0 or 1, by construction, and we already know
1155 // which config it will return (since there can be only one).
1156 configs[0] = MAKE_CONFIG(i, index);
1157 *num_config = 1;
1158 }
1159 }
1160
1161 free(const_cast<EGLint *>(attrib_list));
1162 return res;
1163 }
1164
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001165 for (int i=0 ; i<2 ; i++) {
1166 egl_connection_t* const cnx = &gEGLImpl[i];
1167 if (cnx->dso) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001168 if (cnx->hooks->egl.eglChooseConfig(
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001169 dp->dpys[i], attrib_list, configs, config_size, &n)) {
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001170 // now we need to convert these client EGLConfig to our
1171 // internal EGLConfig format. This is done in O(n log n).
1172 for (int j=0 ; j<n ; j++) {
1173 int index = binarySearch<EGLConfig>(
1174 dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
1175 if (index >= 0) {
1176 configs[j] = MAKE_CONFIG(i, index);
1177 } else {
1178 return setError(EGL_BAD_CONFIG, EGL_FALSE);
1179 }
1180 }
1181 configs += n;
1182 config_size -= n;
1183 *num_config += n;
1184 res = EGL_TRUE;
1185 }
1186 }
1187 }
1188 return res;
1189}
1190
1191EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
1192 EGLint attribute, EGLint *value)
1193{
1194 egl_display_t const* dp = 0;
1195 int i=0, index=0;
1196 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1197 if (!cnx) return EGL_FALSE;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -08001198
1199 if (attribute == EGL_CONFIG_ID) {
1200 // EGL_CONFIG_IDs must be unique, just use the order of the selected
1201 // EGLConfig.
1202 *value = configToUniqueId(dp, i, index);
1203 return EGL_TRUE;
1204 }
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001205 return cnx->hooks->egl.eglGetConfigAttrib(
1206 dp->dpys[i], dp->configs[i][index], attribute, value);
1207}
1208
1209// ----------------------------------------------------------------------------
1210// surfaces
1211// ----------------------------------------------------------------------------
1212
1213EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
1214 NativeWindowType window,
1215 const EGLint *attrib_list)
1216{
1217 egl_display_t const* dp = 0;
1218 int i=0, index=0;
1219 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1220 if (cnx) {
1221 // window must be connected upon calling underlying
1222 // eglCreateWindowSurface
1223 if (window) {
1224 window->incRef(window);
1225 if (window->connect)
1226 window->connect(window);
1227 }
1228
1229 EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
1230 dp->dpys[i], dp->configs[i][index], window, attrib_list);
1231 if (surface != EGL_NO_SURFACE) {
1232 egl_surface_t* s = new egl_surface_t(dpy, surface, window, i, cnx);
1233 return s;
1234 }
1235
1236 // something went wrong, disconnect and free window
1237 // (will disconnect() automatically)
1238 if (window) {
1239 window->decRef(window);
1240 }
1241 }
1242 return EGL_NO_SURFACE;
1243}
1244
1245EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
1246 NativePixmapType pixmap,
1247 const EGLint *attrib_list)
1248{
1249 egl_display_t const* dp = 0;
1250 int i=0, index=0;
1251 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1252 if (cnx) {
1253 EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
1254 dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
1255 if (surface != EGL_NO_SURFACE) {
1256 egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
1257 return s;
1258 }
1259 }
1260 return EGL_NO_SURFACE;
1261}
1262
1263EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
1264 const EGLint *attrib_list)
1265{
1266 egl_display_t const* dp = 0;
1267 int i=0, index=0;
1268 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1269 if (cnx) {
1270 EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
1271 dp->dpys[i], dp->configs[i][index], attrib_list);
1272 if (surface != EGL_NO_SURFACE) {
1273 egl_surface_t* s = new egl_surface_t(dpy, surface, NULL, i, cnx);
1274 return s;
1275 }
1276 }
1277 return EGL_NO_SURFACE;
1278}
1279
1280EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
1281{
1282 if (!validate_display_surface(dpy, surface))
1283 return EGL_FALSE;
1284 egl_display_t const * const dp = get_display(dpy);
1285 egl_surface_t const * const s = get_surface(surface);
1286
1287 EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
1288 dp->dpys[s->impl], s->surface);
1289
1290 delete s;
1291 return result;
1292}
1293
1294EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
1295 EGLint attribute, EGLint *value)
1296{
1297 if (!validate_display_surface(dpy, surface))
1298 return EGL_FALSE;
1299 egl_display_t const * const dp = get_display(dpy);
1300 egl_surface_t const * const s = get_surface(surface);
1301
1302 return s->cnx->hooks->egl.eglQuerySurface(
1303 dp->dpys[s->impl], s->surface, attribute, value);
1304}
1305
1306// ----------------------------------------------------------------------------
1307// contextes
1308// ----------------------------------------------------------------------------
1309
1310EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1311 EGLContext share_list, const EGLint *attrib_list)
1312{
1313 egl_display_t const* dp = 0;
1314 int i=0, index=0;
1315 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1316 if (cnx) {
1317 EGLContext context = cnx->hooks->egl.eglCreateContext(
1318 dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
1319 if (context != EGL_NO_CONTEXT) {
1320 egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
1321 return c;
1322 }
1323 }
1324 return EGL_NO_CONTEXT;
1325}
1326
1327EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1328{
1329 if (!validate_display_context(dpy, ctx))
1330 return EGL_FALSE;
1331 egl_display_t const * const dp = get_display(dpy);
1332 egl_context_t * const c = get_context(ctx);
1333 EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
1334 dp->dpys[c->impl], c->context);
1335 delete c;
1336 return result;
1337}
1338
1339EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
1340 EGLSurface read, EGLContext ctx)
1341{
1342 egl_display_t const * const dp = get_display(dpy);
1343 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1344
1345 if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
1346 ctx == EGL_NO_CONTEXT)
1347 {
1348 EGLBoolean result = EGL_TRUE;
1349 ctx = getContext();
1350 if (ctx) {
1351 egl_context_t * const c = get_context(ctx);
1352 result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
1353 if (result == EGL_TRUE) {
1354 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
1355 setContext(EGL_NO_CONTEXT);
1356 }
1357 }
1358 return result;
1359 }
1360
1361 if (!validate_display_context(dpy, ctx))
1362 return EGL_FALSE;
1363
1364 egl_context_t * const c = get_context(ctx);
1365 if (draw != EGL_NO_SURFACE) {
1366 egl_surface_t const * d = get_surface(draw);
1367 if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1368 if (d->impl != c->impl)
1369 return setError(EGL_BAD_MATCH, EGL_FALSE);
1370 draw = d->surface;
1371 }
1372 if (read != EGL_NO_SURFACE) {
1373 egl_surface_t const * r = get_surface(read);
1374 if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1375 if (r->impl != c->impl)
1376 return setError(EGL_BAD_MATCH, EGL_FALSE);
1377 read = r->surface;
1378 }
1379 EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
1380 dp->dpys[c->impl], draw, read, c->context);
1381
1382 if (result == EGL_TRUE) {
1383 setGlThreadSpecific(c->cnx->hooks);
1384 setContext(ctx);
1385 c->read = read;
1386 c->draw = draw;
1387 }
1388 return result;
1389}
1390
1391
1392EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1393 EGLint attribute, EGLint *value)
1394{
1395 if (!validate_display_context(dpy, ctx))
1396 return EGL_FALSE;
1397
1398 egl_display_t const * const dp = get_display(dpy);
1399 egl_context_t * const c = get_context(ctx);
1400
1401 return c->cnx->hooks->egl.eglQueryContext(
1402 dp->dpys[c->impl], c->context, attribute, value);
1403}
1404
1405EGLContext eglGetCurrentContext(void)
1406{
1407 EGLContext ctx = getContext();
1408 return ctx;
1409}
1410
1411EGLSurface eglGetCurrentSurface(EGLint readdraw)
1412{
1413 EGLContext ctx = getContext();
1414 if (ctx) {
1415 egl_context_t const * const c = get_context(ctx);
1416 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1417 switch (readdraw) {
1418 case EGL_READ: return c->read;
1419 case EGL_DRAW: return c->draw;
1420 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1421 }
1422 }
1423 return EGL_NO_SURFACE;
1424}
1425
1426EGLDisplay eglGetCurrentDisplay(void)
1427{
1428 EGLContext ctx = getContext();
1429 if (ctx) {
1430 egl_context_t const * const c = get_context(ctx);
1431 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1432 return c->dpy;
1433 }
1434 return EGL_NO_DISPLAY;
1435}
1436
1437EGLBoolean eglWaitGL(void)
1438{
1439 EGLBoolean res = EGL_TRUE;
1440 EGLContext ctx = getContext();
1441 if (ctx) {
1442 egl_context_t const * const c = get_context(ctx);
1443 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1444 if (uint32_t(c->impl)>=2)
1445 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1446 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1447 if (!cnx->dso)
1448 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1449 res = cnx->hooks->egl.eglWaitGL();
1450 }
1451 return res;
1452}
1453
1454EGLBoolean eglWaitNative(EGLint engine)
1455{
1456 EGLBoolean res = EGL_TRUE;
1457 EGLContext ctx = getContext();
1458 if (ctx) {
1459 egl_context_t const * const c = get_context(ctx);
1460 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1461 if (uint32_t(c->impl)>=2)
1462 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1463 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1464 if (!cnx->dso)
1465 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1466 res = cnx->hooks->egl.eglWaitNative(engine);
1467 }
1468 return res;
1469}
1470
1471EGLint eglGetError(void)
1472{
1473 EGLint result = EGL_SUCCESS;
1474 for (int i=0 ; i<2 ; i++) {
1475 EGLint err = EGL_SUCCESS;
1476 egl_connection_t* const cnx = &gEGLImpl[i];
1477 if (cnx->dso)
1478 err = cnx->hooks->egl.eglGetError();
1479 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1480 result = err;
1481 }
1482 if (result == EGL_SUCCESS)
1483 result = getError();
1484 return result;
1485}
1486
1487void (*eglGetProcAddress(const char *procname))()
1488{
1489 void (*addr)();
1490 addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1491 if (addr) return addr;
1492
1493 return NULL; // TODO: finish implementation below
1494
1495 addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1496 if (addr) return addr;
1497
1498 addr = 0;
1499 int slot = -1;
1500 for (int i=0 ; i<2 ; i++) {
1501 egl_connection_t* const cnx = &gEGLImpl[i];
1502 if (cnx->dso) {
1503 if (cnx->hooks->egl.eglGetProcAddress) {
1504 addr = cnx->hooks->egl.eglGetProcAddress(procname);
1505 if (addr) {
1506 if (slot == -1) {
1507 slot = 0; // XXX: find free slot
1508 if (slot == -1) {
1509 addr = 0;
1510 break;
1511 }
1512 }
1513 cnx->hooks->ext.extensions[slot] = addr;
1514 }
1515 }
1516 }
1517 }
1518
1519 if (slot >= 0) {
1520 addr = 0; // XXX: address of stub 'slot'
1521 gGLExtentionMap[slot].name = strdup(procname);
1522 gGLExtentionMap[slot].address = addr;
1523 }
1524
1525 return addr;
1526
1527
1528 /*
1529 * TODO: For OpenGL ES extensions, we must generate a stub
1530 * that looks like
1531 * mov r12, #0xFFFF0FFF
1532 * ldr r12, [r12, #-15]
1533 * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
1534 * mov r12, [r12, #api_offset]
1535 * ldrne pc, r12
1536 * mov pc, #unsupported_extension
1537 *
1538 * and write the address of the extension in *all*
1539 * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1540 *
1541 */
1542}
1543
1544EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1545{
1546 if (!validate_display_surface(dpy, draw))
1547 return EGL_FALSE;
1548 egl_display_t const * const dp = get_display(dpy);
1549 egl_surface_t const * const s = get_surface(draw);
1550 return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1551}
1552
1553EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1554 NativePixmapType target)
1555{
1556 if (!validate_display_surface(dpy, surface))
1557 return EGL_FALSE;
1558 egl_display_t const * const dp = get_display(dpy);
1559 egl_surface_t const * const s = get_surface(surface);
1560 return s->cnx->hooks->egl.eglCopyBuffers(
1561 dp->dpys[s->impl], s->surface, target);
1562}
1563
1564const char* eglQueryString(EGLDisplay dpy, EGLint name)
1565{
1566 egl_display_t const * const dp = get_display(dpy);
1567 switch (name) {
1568 case EGL_VENDOR:
1569 return gVendorString;
1570 case EGL_VERSION:
1571 return gVersionString;
1572 case EGL_EXTENSIONS:
1573 return dp->extensionsString;
1574 case EGL_CLIENT_APIS:
1575 return gClientApiString;
1576 }
1577 return setError(EGL_BAD_PARAMETER, (const char *)0);
1578}
1579
1580
1581// ----------------------------------------------------------------------------
1582// EGL 1.1
1583// ----------------------------------------------------------------------------
1584
1585EGLBoolean eglSurfaceAttrib(
1586 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1587{
1588 if (!validate_display_surface(dpy, surface))
1589 return EGL_FALSE;
1590 egl_display_t const * const dp = get_display(dpy);
1591 egl_surface_t const * const s = get_surface(surface);
1592 if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1593 return s->cnx->hooks->egl.eglSurfaceAttrib(
1594 dp->dpys[s->impl], s->surface, attribute, value);
1595 }
1596 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1597}
1598
1599EGLBoolean eglBindTexImage(
1600 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1601{
1602 if (!validate_display_surface(dpy, surface))
1603 return EGL_FALSE;
1604 egl_display_t const * const dp = get_display(dpy);
1605 egl_surface_t const * const s = get_surface(surface);
1606 if (s->cnx->hooks->egl.eglBindTexImage) {
1607 return s->cnx->hooks->egl.eglBindTexImage(
1608 dp->dpys[s->impl], s->surface, buffer);
1609 }
1610 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1611}
1612
1613EGLBoolean eglReleaseTexImage(
1614 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1615{
1616 if (!validate_display_surface(dpy, surface))
1617 return EGL_FALSE;
1618 egl_display_t const * const dp = get_display(dpy);
1619 egl_surface_t const * const s = get_surface(surface);
1620 if (s->cnx->hooks->egl.eglReleaseTexImage) {
1621 return s->cnx->hooks->egl.eglReleaseTexImage(
1622 dp->dpys[s->impl], s->surface, buffer);
1623 }
1624 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1625}
1626
1627EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1628{
1629 egl_display_t * const dp = get_display(dpy);
1630 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1631
1632 EGLBoolean res = EGL_TRUE;
1633 for (int i=0 ; i<2 ; i++) {
1634 egl_connection_t* const cnx = &gEGLImpl[i];
1635 if (cnx->dso) {
1636 if (cnx->hooks->egl.eglSwapInterval) {
1637 if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1638 res = EGL_FALSE;
1639 }
1640 }
1641 }
1642 }
1643 return res;
1644}
1645
1646
1647// ----------------------------------------------------------------------------
1648// EGL 1.2
1649// ----------------------------------------------------------------------------
1650
1651EGLBoolean eglWaitClient(void)
1652{
1653 EGLBoolean res = EGL_TRUE;
1654 EGLContext ctx = getContext();
1655 if (ctx) {
1656 egl_context_t const * const c = get_context(ctx);
1657 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1658 if (uint32_t(c->impl)>=2)
1659 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1660 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1661 if (!cnx->dso)
1662 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1663 if (cnx->hooks->egl.eglWaitClient) {
1664 res = cnx->hooks->egl.eglWaitClient();
1665 } else {
1666 res = cnx->hooks->egl.eglWaitGL();
1667 }
1668 }
1669 return res;
1670}
1671
1672EGLBoolean eglBindAPI(EGLenum api)
1673{
1674 // bind this API on all EGLs
1675 EGLBoolean res = EGL_TRUE;
1676 for (int i=0 ; i<2 ; i++) {
1677 egl_connection_t* const cnx = &gEGLImpl[i];
1678 if (cnx->dso) {
1679 if (cnx->hooks->egl.eglBindAPI) {
1680 if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1681 res = EGL_FALSE;
1682 }
1683 }
1684 }
1685 }
1686 return res;
1687}
1688
1689EGLenum eglQueryAPI(void)
1690{
1691 for (int i=0 ; i<2 ; i++) {
1692 egl_connection_t* const cnx = &gEGLImpl[i];
1693 if (cnx->dso) {
1694 if (cnx->hooks->egl.eglQueryAPI) {
1695 // the first one we find is okay, because they all
1696 // should be the same
1697 return cnx->hooks->egl.eglQueryAPI();
1698 }
1699 }
1700 }
1701 // or, it can only be OpenGL ES
1702 return EGL_OPENGL_ES_API;
1703}
1704
1705EGLBoolean eglReleaseThread(void)
1706{
1707 for (int i=0 ; i<2 ; i++) {
1708 egl_connection_t* const cnx = &gEGLImpl[i];
1709 if (cnx->dso) {
1710 if (cnx->hooks->egl.eglReleaseThread) {
1711 cnx->hooks->egl.eglReleaseThread();
1712 }
1713 }
1714 }
1715 clearTLS();
1716 return EGL_TRUE;
1717}
1718
1719EGLSurface eglCreatePbufferFromClientBuffer(
1720 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1721 EGLConfig config, const EGLint *attrib_list)
1722{
1723 egl_display_t const* dp = 0;
1724 int i=0, index=0;
1725 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1726 if (!cnx) return EGL_FALSE;
1727 if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1728 return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1729 dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1730 }
1731 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1732}
1733
1734// ----------------------------------------------------------------------------
1735// Android extentions
1736// ----------------------------------------------------------------------------
1737
1738EGLBoolean eglSwapRectangleANDROID(
1739 EGLDisplay dpy, EGLSurface draw,
1740 EGLint l, EGLint t, EGLint w, EGLint h)
1741{
1742 if (!validate_display_surface(dpy, draw))
1743 return EGL_FALSE;
1744 egl_display_t const * const dp = get_display(dpy);
1745 egl_surface_t const * const s = get_surface(draw);
1746 if (s->cnx->hooks->egl.eglSwapRectangleANDROID) {
1747 return s->cnx->hooks->egl.eglSwapRectangleANDROID(
1748 dp->dpys[s->impl], s->surface, l, t, w, h);
1749 }
1750 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1751}
1752
1753const char* eglQueryStringConfigANDROID(
1754 EGLDisplay dpy, EGLConfig config, EGLint name)
1755{
1756 egl_display_t const* dp = 0;
1757 int i=0, index=0;
1758 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1759 if (cnx) {
1760 return dp->queryString[i].extensions_config;
1761 }
1762 return setError(EGL_BAD_PARAMETER, (const char *)0);
1763}