blob: c58fff8790b380aad1f4eed9d6f8b8f33942bc67 [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001/*
2 ** Copyright 2007, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080017#include <ctype.h>
18#include <string.h>
19#include <errno.h>
20#include <dlfcn.h>
21
22#include <sys/ioctl.h>
23
24#if HAVE_ANDROID_OS
25#include <linux/android_pmem.h>
26#endif
27
28#include <EGL/egl.h>
29#include <EGL/eglext.h>
30#include <GLES/gl.h>
31#include <GLES/glext.h>
32
33#include <cutils/log.h>
34#include <cutils/atomic.h>
35#include <cutils/properties.h>
36#include <cutils/memory.h>
37
38#include <utils/RefBase.h>
Mathias Agopian076b1cc2009-04-10 14:24:30 -070039#include <utils/threads.h>
40#include <utils/KeyedVector.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080041
42#include "hooks.h"
43#include "egl_impl.h"
44
45
46#define MAKE_CONFIG(_impl, _index) ((EGLConfig)(((_impl)<<24) | (_index)))
47#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
48
49// ----------------------------------------------------------------------------
50namespace android {
51// ----------------------------------------------------------------------------
52
53#define VERSION_MAJOR 1
54#define VERSION_MINOR 4
55static char const * const gVendorString = "Android";
56static char const * const gVersionString = "1.31 Android META-EGL";
57static char const * const gClientApiString = "OpenGL ES";
Mathias Agopian076b1cc2009-04-10 14:24:30 -070058static char const * const gExtensionString =
59 "EGL_KHR_image "
60 "KHR_image_base "
61 "KHR_image_pixmap "
62 "EGL_ANDROID_image_native_buffer "
63 ;
64
65// ----------------------------------------------------------------------------
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080066
67template <int MAGIC>
68struct egl_object_t
69{
70 egl_object_t() : magic(MAGIC) { }
71 ~egl_object_t() { magic = 0; }
72 bool isValid() const { return magic == MAGIC; }
73private:
74 uint32_t magic;
75};
76
77struct egl_display_t : public egl_object_t<'_dpy'>
78{
Mathias Agopian076b1cc2009-04-10 14:24:30 -070079 EGLDisplay dpys[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
80 EGLConfig* configs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
81 EGLint numConfigs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080082 EGLint numTotalConfigs;
83 char const* extensionsString;
84 volatile int32_t refs;
85 struct strings_t {
86 char const * vendor;
87 char const * version;
88 char const * clientApi;
89 char const * extensions;
90 };
Mathias Agopian076b1cc2009-04-10 14:24:30 -070091 strings_t queryString[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080092};
93
94struct egl_surface_t : public egl_object_t<'_srf'>
95{
96 egl_surface_t(EGLDisplay dpy, EGLSurface surface,
Mathias Agopian076b1cc2009-04-10 14:24:30 -070097 int impl, egl_connection_t const* cnx)
98 : dpy(dpy), surface(surface), impl(impl), cnx(cnx)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080099 {
100 // NOTE: window must be incRef'ed and connected already
101 }
102 ~egl_surface_t() {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800103 }
104 EGLDisplay dpy;
105 EGLSurface surface;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800106 int impl;
107 egl_connection_t const* cnx;
108};
109
110struct egl_context_t : public egl_object_t<'_ctx'>
111{
112 egl_context_t(EGLDisplay dpy, EGLContext context,
113 int impl, egl_connection_t const* cnx)
114 : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
115 {
116 }
117 EGLDisplay dpy;
118 EGLContext context;
119 EGLSurface read;
120 EGLSurface draw;
121 int impl;
122 egl_connection_t const* cnx;
123};
124
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700125struct egl_image_t : public egl_object_t<'_img'>
126{
127 egl_image_t(EGLDisplay dpy, EGLContext context)
128 : dpy(dpy), context(context)
129 {
130 memset(images, 0, sizeof(images));
131 }
132 EGLDisplay dpy;
133 EGLConfig context;
134 EGLImageKHR images[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
135};
136
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800137struct tls_t
138{
139 tls_t() : error(EGL_SUCCESS), ctx(0) { }
140 EGLint error;
141 EGLContext ctx;
142};
143
144static void gl_unimplemented() {
145 LOGE("called unimplemented OpenGL ES API");
146}
147
148// ----------------------------------------------------------------------------
149// GL / EGL hooks
150// ----------------------------------------------------------------------------
151
152#undef GL_ENTRY
153#undef EGL_ENTRY
154#define GL_ENTRY(_r, _api, ...) #_api,
155#define EGL_ENTRY(_r, _api, ...) #_api,
156
157static char const * const gl_names[] = {
158 #include "gl_entries.in"
159 NULL
160};
161
162static char const * const egl_names[] = {
163 #include "egl_entries.in"
164 NULL
165};
166
167#undef GL_ENTRY
168#undef EGL_ENTRY
169
170// ----------------------------------------------------------------------------
171
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700172egl_connection_t gEGLImpl[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800173static egl_display_t gDisplay[NUM_DISPLAYS];
174static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
175static pthread_key_t gEGLThreadLocalStorageKey = -1;
176
177// ----------------------------------------------------------------------------
178
179gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
180pthread_key_t gGLWrapperKey = -1;
181
182// ----------------------------------------------------------------------------
183
184static __attribute__((noinline))
185const char *egl_strerror(EGLint err)
186{
187 switch (err){
188 case EGL_SUCCESS: return "EGL_SUCCESS";
189 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
190 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
191 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
192 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
193 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
194 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
195 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
196 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
197 case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
198 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
199 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
200 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
201 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
202 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
203 default: return "UNKNOWN";
204 }
205}
206
207static __attribute__((noinline))
208void clearTLS() {
209 if (gEGLThreadLocalStorageKey != -1) {
210 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
211 if (tls) {
212 delete tls;
213 pthread_setspecific(gEGLThreadLocalStorageKey, 0);
214 }
215 }
216}
217
218static tls_t* getTLS()
219{
220 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
221 if (tls == 0) {
222 tls = new tls_t;
223 pthread_setspecific(gEGLThreadLocalStorageKey, tls);
224 }
225 return tls;
226}
227
228template<typename T>
229static __attribute__((noinline))
230T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
231 if (gEGLThreadLocalStorageKey == -1) {
232 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
233 if (gEGLThreadLocalStorageKey == -1)
234 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
235 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
236 }
237 tls_t* tls = getTLS();
238 if (tls->error != error) {
239 LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
240 tls->error = error;
241 }
242 return returnValue;
243}
244
245static __attribute__((noinline))
246GLint getError() {
247 if (gEGLThreadLocalStorageKey == -1)
248 return EGL_SUCCESS;
249 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
250 if (!tls) return EGL_SUCCESS;
251 GLint error = tls->error;
252 tls->error = EGL_SUCCESS;
253 return error;
254}
255
256static __attribute__((noinline))
257void setContext(EGLContext ctx) {
258 if (gEGLThreadLocalStorageKey == -1) {
259 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
260 if (gEGLThreadLocalStorageKey == -1)
261 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
262 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
263 }
264 tls_t* tls = getTLS();
265 tls->ctx = ctx;
266}
267
268static __attribute__((noinline))
269EGLContext getContext() {
270 if (gEGLThreadLocalStorageKey == -1)
271 return EGL_NO_CONTEXT;
272 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
273 if (!tls) return EGL_NO_CONTEXT;
274 return tls->ctx;
275}
276
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800277/*****************************************************************************/
278
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800279static __attribute__((noinline))
280void *load_driver(const char* driver, gl_hooks_t* hooks)
281{
282 void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
283 LOGE_IF(!dso,
284 "couldn't load <%s> library (%s)",
285 driver, dlerror());
286
287 if (dso) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700288 // first find the symbol for eglGetProcAddress
289
290 typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
291 const char*);
292
293 getProcAddressType getProcAddress =
294 (getProcAddressType)dlsym(dso, "eglGetProcAddress");
295
296 LOGE_IF(!getProcAddress,
297 "can't find eglGetProcAddress() in %s", driver);
298
299 __eglMustCastToProperFunctionPointerType* curr;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800300 char const * const * api;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700301
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800302 gl_hooks_t::egl_t* egl = &hooks->egl;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700303 curr = (__eglMustCastToProperFunctionPointerType*)egl;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800304 api = egl_names;
305 while (*api) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700306 char const * name = *api;
307 __eglMustCastToProperFunctionPointerType f =
308 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800309 if (f == NULL) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700310 // couldn't find the entry-point, use eglGetProcAddress()
311 f = getProcAddress(name);
312 if (f == NULL) {
313 f = (__eglMustCastToProperFunctionPointerType)0;
314 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800315 }
316 *curr++ = f;
317 api++;
318 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700319
320 gl_hooks_t::gl_t* gl = &hooks->gl;
321 curr = (__eglMustCastToProperFunctionPointerType*)gl;
322 api = gl_names;
323 while (*api) {
324 char const * name = *api;
325 // if the function starts with '__' it's a special case that
326 // uses a wrapper. skip the '__' when looking into the real lib.
327 if (name[0] == '_' && name[1] == '_') {
328 name += 2;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800329 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700330 __eglMustCastToProperFunctionPointerType f =
331 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
332 if (f == NULL) {
333 // couldn't find the entry-point, use eglGetProcAddress()
334 f = getProcAddress(name);
335 if (f == NULL) {
336 f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
337 }
338 }
339 *curr++ = f;
340 api++;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800341 }
342 }
343 return dso;
344}
345
346template<typename T>
347static __attribute__((noinline))
348int binarySearch(
349 T const sortedArray[], int first, int last, T key)
350{
351 while (first <= last) {
352 int mid = (first + last) / 2;
353 if (key > sortedArray[mid]) {
354 first = mid + 1;
355 } else if (key < sortedArray[mid]) {
356 last = mid - 1;
357 } else {
358 return mid;
359 }
360 }
361 return -1;
362}
363
364static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
365{
366 // NOTE: this mapping works only if we have no more than two EGLimpl
367 return (i>0 ? dp->numConfigs[0] : 0) + index;
368}
369
370static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
371 int& i, int& index)
372{
373 // NOTE: this mapping works only if we have no more than two EGLimpl
374 size_t numConfigs = dp->numConfigs[0];
375 i = configId / numConfigs;
376 index = configId % numConfigs;
377}
378
379static int cmp_configs(const void* a, const void *b)
380{
381 EGLConfig c0 = *(EGLConfig const *)a;
382 EGLConfig c1 = *(EGLConfig const *)b;
383 return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
384}
385
386struct extention_map_t {
387 const char* name;
388 __eglMustCastToProperFunctionPointerType address;
389};
390
391static const extention_map_t gExtentionMap[] = {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700392 { "eglLockSurfaceKHR",
393 (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
394 { "eglUnlockSurfaceKHR",
395 (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
396 { "eglCreateImageKHR",
397 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
398 { "eglDestroyImageKHR",
399 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800400};
401
402static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
403
404static void(*findProcAddress(const char* name,
405 const extention_map_t* map, size_t n))()
406{
407 for (uint32_t i=0 ; i<n ; i++) {
408 if (!strcmp(name, map[i].name)) {
409 return map[i].address;
410 }
411 }
412 return NULL;
413}
414
415// ----------------------------------------------------------------------------
416
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700417/*
418 * To "loose" the GPU, use something like
419 * gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_CONTEXT_LOST];
420 *
421 */
422
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800423static int gl_context_lost() {
424 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
425 return 0;
426}
427static int egl_context_lost() {
428 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
429 return EGL_FALSE;
430}
431static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
432 usleep(100000); // don't use all the CPU
433 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
434 return EGL_FALSE;
435}
436static GLint egl_context_lost_get_error() {
437 return EGL_CONTEXT_LOST;
438}
439static int ext_context_lost() {
440 return 0;
441}
442
443static void gl_no_context() {
444 LOGE("call to OpenGL ES API with no current context");
445}
446static void early_egl_init(void)
447{
448#if !USE_FAST_TLS_KEY
449 pthread_key_create(&gGLWrapperKey, NULL);
450#endif
451 uint32_t addr = (uint32_t)((void*)gl_no_context);
452 android_memset32(
453 (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT],
454 addr,
455 sizeof(gHooks[IMPL_NO_CONTEXT]));
456 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
457}
458
459static pthread_once_t once_control = PTHREAD_ONCE_INIT;
460static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
461
462
463static inline
464egl_display_t* get_display(EGLDisplay dpy)
465{
466 uintptr_t index = uintptr_t(dpy)-1U;
467 return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
468}
469
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700470template<typename NATIVE, typename EGL>
471static inline NATIVE* egl_to_native_cast(EGL arg) {
472 return reinterpret_cast<NATIVE*>(arg);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800473}
474
475static inline
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700476egl_surface_t* get_surface(EGLSurface surface) {
477 return egl_to_native_cast<egl_surface_t>(surface);
478}
479
480static inline
481egl_context_t* get_context(EGLContext context) {
482 return egl_to_native_cast<egl_context_t>(context);
483}
484
485static inline
486egl_image_t* get_image(EGLImageKHR image) {
487 return egl_to_native_cast<egl_image_t>(image);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800488}
489
490static egl_connection_t* validate_display_config(
491 EGLDisplay dpy, EGLConfig config,
492 egl_display_t const*& dp, int& impl, int& index)
493{
494 dp = get_display(dpy);
495 if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
496
497 impl = uintptr_t(config)>>24;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700498 if (uint32_t(impl) >= IMPL_NUM_DRIVERS_IMPLEMENTATIONS) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800499 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
500 }
501 index = uintptr_t(config) & 0xFFFFFF;
502 if (index >= dp->numConfigs[impl]) {
503 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
504 }
505 egl_connection_t* const cnx = &gEGLImpl[impl];
506 if (cnx->dso == 0) {
507 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
508 }
509 return cnx;
510}
511
512static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
513{
514 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
515 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
516 if (!get_display(dpy)->isValid())
517 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
518 if (!ctx) // TODO: make sure context is a valid object
519 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
520 if (!get_context(ctx)->isValid())
521 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
522 return EGL_TRUE;
523}
524
525static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
526{
527 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
528 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
529 if (!get_display(dpy)->isValid())
530 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
531 if (!surface) // TODO: make sure surface is a valid object
532 return setError(EGL_BAD_SURFACE, EGL_FALSE);
533 if (!get_surface(surface)->isValid())
534 return setError(EGL_BAD_SURFACE, EGL_FALSE);
535 return EGL_TRUE;
536}
537
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800538
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700539EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
540{
541 EGLContext context = getContext();
542 if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
543 return EGL_NO_IMAGE_KHR;
544
545 egl_context_t const * const c = get_context(context);
546 if (!c->isValid())
547 return EGL_NO_IMAGE_KHR;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800548
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700549 egl_image_t const * const i = get_image(image);
550 if (!i->isValid())
551 return EGL_NO_IMAGE_KHR;
552
553 return i->images[c->impl];
554}
555
556
557EGLDisplay egl_init_displays(NativeDisplayType display)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800558{
559 if (sEarlyInitState) {
560 return EGL_NO_DISPLAY;
561 }
562
563 uint32_t index = uint32_t(display);
564 if (index >= NUM_DISPLAYS) {
565 return EGL_NO_DISPLAY;
566 }
567
568 EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
569 egl_display_t* d = &gDisplay[index];
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700570
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800571 // dynamically load all our EGL implementations for that display
572 // and call into the real eglGetGisplay()
573 egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
574 if (cnx->dso == 0) {
575 cnx->hooks = &gHooks[IMPL_SOFTWARE];
576 cnx->dso = load_driver("libagl.so", cnx->hooks);
577 }
578 if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
579 d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
580 LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
581 "No EGLDisplay for software EGL!");
582 }
583
584 cnx = &gEGLImpl[IMPL_HARDWARE];
585 if (cnx->dso == 0 && cnx->unavailable == 0) {
586 char value[PROPERTY_VALUE_MAX];
587 property_get("debug.egl.hw", value, "1");
588 if (atoi(value) != 0) {
589 cnx->hooks = &gHooks[IMPL_HARDWARE];
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700590 cnx->dso = load_driver("libhgl2.so", cnx->hooks);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800591 } else {
592 LOGD("3D hardware acceleration is disabled");
593 }
594 }
595 if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
596 android_memset32(
597 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
598 (uint32_t)((void*)gl_context_lost),
599 sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
600 android_memset32(
601 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
602 (uint32_t)((void*)egl_context_lost),
603 sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
604 android_memset32(
605 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
606 (uint32_t)((void*)ext_context_lost),
607 sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
608
609 gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
610 egl_context_lost_swap_buffers;
611
612 gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
613 egl_context_lost_get_error;
614
615 gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
616 gHooks[IMPL_HARDWARE].egl.eglTerminate;
617
618 d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
619 if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
620 LOGE("h/w accelerated eglGetDisplay() failed (%s)",
621 egl_strerror(cnx->hooks->egl.eglGetError()));
622 dlclose((void*)cnx->dso);
623 cnx->dso = 0;
624 // in case of failure, we want to make sure we don't try again
625 // as it's expensive.
626 cnx->unavailable = 1;
627 }
628 }
629
630 return dpy;
631}
632
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700633
634// ----------------------------------------------------------------------------
635}; // namespace android
636// ----------------------------------------------------------------------------
637
638using namespace android;
639
640EGLDisplay eglGetDisplay(NativeDisplayType display)
641{
642 return egl_init_displays(display);
643}
644
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800645// ----------------------------------------------------------------------------
646// Initialization
647// ----------------------------------------------------------------------------
648
649EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
650{
651 egl_display_t * const dp = get_display(dpy);
652 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
653
654 if (android_atomic_inc(&dp->refs) > 0) {
655 if (major != NULL) *major = VERSION_MAJOR;
656 if (minor != NULL) *minor = VERSION_MINOR;
657 return EGL_TRUE;
658 }
659
660 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
661
662 // initialize each EGL and
663 // build our own extension string first, based on the extension we know
664 // and the extension supported by our client implementation
665 dp->extensionsString = strdup(gExtensionString);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700666 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800667 egl_connection_t* const cnx = &gEGLImpl[i];
668 cnx->major = -1;
669 cnx->minor = -1;
670 if (!cnx->dso)
671 continue;
672
673 if (cnx->hooks->egl.eglInitialize(
674 dp->dpys[i], &cnx->major, &cnx->minor)) {
675
676 //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
677 // i, dp->dpys[i], cnx->major, cnx->minor, cnx);
678
679 // get the query-strings for this display for each implementation
680 dp->queryString[i].vendor =
681 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
682 dp->queryString[i].version =
683 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
684 dp->queryString[i].extensions = strdup(
685 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
686 dp->queryString[i].clientApi =
687 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
688
689 } else {
690 LOGD("%d: eglInitialize() failed (%s)",
691 i, egl_strerror(cnx->hooks->egl.eglGetError()));
692 }
693 }
694
695 EGLBoolean res = EGL_FALSE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700696 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800697 egl_connection_t* const cnx = &gEGLImpl[i];
698 if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
699 EGLint n;
700 if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
701 dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
702 if (dp->configs[i]) {
703 if (cnx->hooks->egl.eglGetConfigs(
704 dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
705 {
706 // sort the configurations so we can do binary searches
707 qsort( dp->configs[i],
708 dp->numConfigs[i],
709 sizeof(EGLConfig), cmp_configs);
710
711 dp->numTotalConfigs += n;
712 res = EGL_TRUE;
713 }
714 }
715 }
716 }
717 }
718
719 if (res == EGL_TRUE) {
720 if (major != NULL) *major = VERSION_MAJOR;
721 if (minor != NULL) *minor = VERSION_MINOR;
722 return EGL_TRUE;
723 }
724 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
725}
726
727EGLBoolean eglTerminate(EGLDisplay dpy)
728{
729 egl_display_t* const dp = get_display(dpy);
730 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
731 if (android_atomic_dec(&dp->refs) != 1)
732 return EGL_TRUE;
733
734 EGLBoolean res = EGL_FALSE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700735 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800736 egl_connection_t* const cnx = &gEGLImpl[i];
737 if (cnx->dso) {
738 cnx->hooks->egl.eglTerminate(dp->dpys[i]);
739
740 /* REVISIT: it's unclear what to do if eglTerminate() fails,
741 * on one end we shouldn't care, on the other end if it fails
742 * it might not be safe to call dlclose() (there could be some
743 * threads around). */
744
745 free(dp->configs[i]);
746 free((void*)dp->queryString[i].extensions);
747 dp->numConfigs[i] = 0;
748 dp->dpys[i] = EGL_NO_DISPLAY;
749 dlclose((void*)cnx->dso);
750 cnx->dso = 0;
751 res = EGL_TRUE;
752 }
753 }
754 free((void*)dp->extensionsString);
755 dp->extensionsString = 0;
756 dp->numTotalConfigs = 0;
757 clearTLS();
758 return res;
759}
760
761// ----------------------------------------------------------------------------
762// configuration
763// ----------------------------------------------------------------------------
764
765EGLBoolean eglGetConfigs( EGLDisplay dpy,
766 EGLConfig *configs,
767 EGLint config_size, EGLint *num_config)
768{
769 egl_display_t const * const dp = get_display(dpy);
770 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
771
772 GLint numConfigs = dp->numTotalConfigs;
773 if (!configs) {
774 *num_config = numConfigs;
775 return EGL_TRUE;
776 }
777 GLint n = 0;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700778 for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800779 for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
780 *configs++ = MAKE_CONFIG(j, i);
781 config_size--;
782 n++;
783 }
784 }
785
786 *num_config = n;
787 return EGL_TRUE;
788}
789
790EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
791 EGLConfig *configs, EGLint config_size,
792 EGLint *num_config)
793{
794 egl_display_t const * const dp = get_display(dpy);
795 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
796
Jack Palevich749c63d2009-03-25 15:12:17 -0700797 if (num_config==0) {
798 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800799 }
800
801 EGLint n;
802 EGLBoolean res = EGL_FALSE;
803 *num_config = 0;
804
805
806 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
807 // to do this, we have to go through the attrib_list array once
808 // to figure out both its size and if it contains an EGL_CONFIG_ID
809 // key. If so, the full array is copied and patched.
810 // NOTE: we assume that there can be only one occurrence
811 // of EGL_CONFIG_ID.
812
813 EGLint patch_index = -1;
814 GLint attr;
815 size_t size = 0;
816 while ((attr=attrib_list[size])) {
817 if (attr == EGL_CONFIG_ID)
818 patch_index = size;
819 size += 2;
820 }
821 if (patch_index >= 0) {
822 size += 2; // we need copy the sentinel as well
823 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
824 if (new_list == 0)
825 return setError(EGL_BAD_ALLOC, EGL_FALSE);
826 memcpy(new_list, attrib_list, size*sizeof(EGLint));
827
828 // patch the requested EGL_CONFIG_ID
829 int i, index;
830 EGLint& configId(new_list[patch_index+1]);
831 uniqueIdToConfig(dp, configId, i, index);
832
833 egl_connection_t* const cnx = &gEGLImpl[i];
834 if (cnx->dso) {
835 cnx->hooks->egl.eglGetConfigAttrib(
836 dp->dpys[i], dp->configs[i][index],
837 EGL_CONFIG_ID, &configId);
838
839 // and switch to the new list
840 attrib_list = const_cast<const EGLint *>(new_list);
841
842 // At this point, the only configuration that can match is
843 // dp->configs[i][index], however, we don't know if it would be
844 // rejected because of the other attributes, so we do have to call
845 // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
846 // through all the EGLimpl[].
847 // We also know we can only get a single config back, and we know
848 // which one.
849
850 res = cnx->hooks->egl.eglChooseConfig(
851 dp->dpys[i], attrib_list, configs, config_size, &n);
852 if (res && n>0) {
853 // n has to be 0 or 1, by construction, and we already know
854 // which config it will return (since there can be only one).
Jack Palevich749c63d2009-03-25 15:12:17 -0700855 if (configs) {
856 configs[0] = MAKE_CONFIG(i, index);
857 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800858 *num_config = 1;
859 }
860 }
861
862 free(const_cast<EGLint *>(attrib_list));
863 return res;
864 }
865
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700866 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800867 egl_connection_t* const cnx = &gEGLImpl[i];
868 if (cnx->dso) {
869 if (cnx->hooks->egl.eglChooseConfig(
870 dp->dpys[i], attrib_list, configs, config_size, &n)) {
Jack Palevich749c63d2009-03-25 15:12:17 -0700871 if (configs) {
872 // now we need to convert these client EGLConfig to our
873 // internal EGLConfig format. This is done in O(n log n).
874 for (int j=0 ; j<n ; j++) {
875 int index = binarySearch<EGLConfig>(
876 dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
877 if (index >= 0) {
878 if (configs) {
879 configs[j] = MAKE_CONFIG(i, index);
880 }
881 } else {
882 return setError(EGL_BAD_CONFIG, EGL_FALSE);
883 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800884 }
Jack Palevich749c63d2009-03-25 15:12:17 -0700885 configs += n;
886 config_size -= n;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800887 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800888 *num_config += n;
889 res = EGL_TRUE;
890 }
891 }
892 }
893 return res;
894}
895
896EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
897 EGLint attribute, EGLint *value)
898{
899 egl_display_t const* dp = 0;
900 int i=0, index=0;
901 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
902 if (!cnx) return EGL_FALSE;
903
904 if (attribute == EGL_CONFIG_ID) {
905 // EGL_CONFIG_IDs must be unique, just use the order of the selected
906 // EGLConfig.
907 *value = configToUniqueId(dp, i, index);
908 return EGL_TRUE;
909 }
910 return cnx->hooks->egl.eglGetConfigAttrib(
911 dp->dpys[i], dp->configs[i][index], attribute, value);
912}
913
914// ----------------------------------------------------------------------------
915// surfaces
916// ----------------------------------------------------------------------------
917
918EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
919 NativeWindowType window,
920 const EGLint *attrib_list)
921{
922 egl_display_t const* dp = 0;
923 int i=0, index=0;
924 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
925 if (cnx) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800926 EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
927 dp->dpys[i], dp->configs[i][index], window, attrib_list);
928 if (surface != EGL_NO_SURFACE) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700929 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800930 return s;
931 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800932 }
933 return EGL_NO_SURFACE;
934}
935
936EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
937 NativePixmapType pixmap,
938 const EGLint *attrib_list)
939{
940 egl_display_t const* dp = 0;
941 int i=0, index=0;
942 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
943 if (cnx) {
944 EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
945 dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
946 if (surface != EGL_NO_SURFACE) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700947 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800948 return s;
949 }
950 }
951 return EGL_NO_SURFACE;
952}
953
954EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
955 const EGLint *attrib_list)
956{
957 egl_display_t const* dp = 0;
958 int i=0, index=0;
959 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
960 if (cnx) {
961 EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
962 dp->dpys[i], dp->configs[i][index], attrib_list);
963 if (surface != EGL_NO_SURFACE) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700964 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800965 return s;
966 }
967 }
968 return EGL_NO_SURFACE;
969}
970
971EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
972{
973 if (!validate_display_surface(dpy, surface))
974 return EGL_FALSE;
975 egl_display_t const * const dp = get_display(dpy);
976 egl_surface_t const * const s = get_surface(surface);
977
978 EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
979 dp->dpys[s->impl], s->surface);
980
981 delete s;
982 return result;
983}
984
985EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
986 EGLint attribute, EGLint *value)
987{
988 if (!validate_display_surface(dpy, surface))
989 return EGL_FALSE;
990 egl_display_t const * const dp = get_display(dpy);
991 egl_surface_t const * const s = get_surface(surface);
992
993 return s->cnx->hooks->egl.eglQuerySurface(
994 dp->dpys[s->impl], s->surface, attribute, value);
995}
996
997// ----------------------------------------------------------------------------
998// contextes
999// ----------------------------------------------------------------------------
1000
1001EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1002 EGLContext share_list, const EGLint *attrib_list)
1003{
1004 egl_display_t const* dp = 0;
1005 int i=0, index=0;
1006 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1007 if (cnx) {
1008 EGLContext context = cnx->hooks->egl.eglCreateContext(
1009 dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
1010 if (context != EGL_NO_CONTEXT) {
1011 egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
1012 return c;
1013 }
1014 }
1015 return EGL_NO_CONTEXT;
1016}
1017
1018EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1019{
1020 if (!validate_display_context(dpy, ctx))
1021 return EGL_FALSE;
1022 egl_display_t const * const dp = get_display(dpy);
1023 egl_context_t * const c = get_context(ctx);
1024 EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
1025 dp->dpys[c->impl], c->context);
1026 delete c;
1027 return result;
1028}
1029
1030EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
1031 EGLSurface read, EGLContext ctx)
1032{
1033 egl_display_t const * const dp = get_display(dpy);
1034 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1035
1036 if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
1037 ctx == EGL_NO_CONTEXT)
1038 {
1039 EGLBoolean result = EGL_TRUE;
1040 ctx = getContext();
1041 if (ctx) {
1042 egl_context_t * const c = get_context(ctx);
1043 result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
1044 if (result == EGL_TRUE) {
1045 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
1046 setContext(EGL_NO_CONTEXT);
1047 }
1048 }
1049 return result;
1050 }
1051
1052 if (!validate_display_context(dpy, ctx))
1053 return EGL_FALSE;
1054
1055 egl_context_t * const c = get_context(ctx);
1056 if (draw != EGL_NO_SURFACE) {
1057 egl_surface_t const * d = get_surface(draw);
1058 if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1059 if (d->impl != c->impl)
1060 return setError(EGL_BAD_MATCH, EGL_FALSE);
1061 draw = d->surface;
1062 }
1063 if (read != EGL_NO_SURFACE) {
1064 egl_surface_t const * r = get_surface(read);
1065 if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1066 if (r->impl != c->impl)
1067 return setError(EGL_BAD_MATCH, EGL_FALSE);
1068 read = r->surface;
1069 }
1070 EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
1071 dp->dpys[c->impl], draw, read, c->context);
1072
1073 if (result == EGL_TRUE) {
1074 setGlThreadSpecific(c->cnx->hooks);
1075 setContext(ctx);
1076 c->read = read;
1077 c->draw = draw;
1078 }
1079 return result;
1080}
1081
1082
1083EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1084 EGLint attribute, EGLint *value)
1085{
1086 if (!validate_display_context(dpy, ctx))
1087 return EGL_FALSE;
1088
1089 egl_display_t const * const dp = get_display(dpy);
1090 egl_context_t * const c = get_context(ctx);
1091
1092 return c->cnx->hooks->egl.eglQueryContext(
1093 dp->dpys[c->impl], c->context, attribute, value);
1094}
1095
1096EGLContext eglGetCurrentContext(void)
1097{
1098 EGLContext ctx = getContext();
1099 return ctx;
1100}
1101
1102EGLSurface eglGetCurrentSurface(EGLint readdraw)
1103{
1104 EGLContext ctx = getContext();
1105 if (ctx) {
1106 egl_context_t const * const c = get_context(ctx);
1107 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1108 switch (readdraw) {
1109 case EGL_READ: return c->read;
1110 case EGL_DRAW: return c->draw;
1111 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1112 }
1113 }
1114 return EGL_NO_SURFACE;
1115}
1116
1117EGLDisplay eglGetCurrentDisplay(void)
1118{
1119 EGLContext ctx = getContext();
1120 if (ctx) {
1121 egl_context_t const * const c = get_context(ctx);
1122 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1123 return c->dpy;
1124 }
1125 return EGL_NO_DISPLAY;
1126}
1127
1128EGLBoolean eglWaitGL(void)
1129{
1130 EGLBoolean res = EGL_TRUE;
1131 EGLContext ctx = getContext();
1132 if (ctx) {
1133 egl_context_t const * const c = get_context(ctx);
1134 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1135 if (uint32_t(c->impl)>=2)
1136 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1137 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1138 if (!cnx->dso)
1139 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1140 res = cnx->hooks->egl.eglWaitGL();
1141 }
1142 return res;
1143}
1144
1145EGLBoolean eglWaitNative(EGLint engine)
1146{
1147 EGLBoolean res = EGL_TRUE;
1148 EGLContext ctx = getContext();
1149 if (ctx) {
1150 egl_context_t const * const c = get_context(ctx);
1151 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1152 if (uint32_t(c->impl)>=2)
1153 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1154 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1155 if (!cnx->dso)
1156 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1157 res = cnx->hooks->egl.eglWaitNative(engine);
1158 }
1159 return res;
1160}
1161
1162EGLint eglGetError(void)
1163{
1164 EGLint result = EGL_SUCCESS;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001165 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001166 EGLint err = EGL_SUCCESS;
1167 egl_connection_t* const cnx = &gEGLImpl[i];
1168 if (cnx->dso)
1169 err = cnx->hooks->egl.eglGetError();
1170 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1171 result = err;
1172 }
1173 if (result == EGL_SUCCESS)
1174 result = getError();
1175 return result;
1176}
1177
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001178__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001179{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001180 // eglGetProcAddress() could be the very first function called
1181 // in which case we must make sure we've initialized ourselves, this
1182 // happens the first time egl_get_display() is called.
1183
1184 if (egl_init_displays(EGL_DEFAULT_DISPLAY) == EGL_NO_DISPLAY)
1185 return NULL;
1186
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001187 __eglMustCastToProperFunctionPointerType addr;
1188 addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1189 if (addr) return addr;
1190
1191 return NULL; // TODO: finish implementation below
1192
1193 addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1194 if (addr) return addr;
1195
1196 addr = 0;
1197 int slot = -1;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001198 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001199 egl_connection_t* const cnx = &gEGLImpl[i];
1200 if (cnx->dso) {
1201 if (cnx->hooks->egl.eglGetProcAddress) {
1202 addr = cnx->hooks->egl.eglGetProcAddress(procname);
1203 if (addr) {
1204 if (slot == -1) {
1205 slot = 0; // XXX: find free slot
1206 if (slot == -1) {
1207 addr = 0;
1208 break;
1209 }
1210 }
1211 cnx->hooks->ext.extensions[slot] = addr;
1212 }
1213 }
1214 }
1215 }
1216
1217 if (slot >= 0) {
1218 addr = 0; // XXX: address of stub 'slot'
1219 gGLExtentionMap[slot].name = strdup(procname);
1220 gGLExtentionMap[slot].address = addr;
1221 }
1222
1223 return addr;
1224
1225
1226 /*
1227 * TODO: For OpenGL ES extensions, we must generate a stub
1228 * that looks like
1229 * mov r12, #0xFFFF0FFF
1230 * ldr r12, [r12, #-15]
1231 * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
1232 * mov r12, [r12, #api_offset]
1233 * ldrne pc, r12
1234 * mov pc, #unsupported_extension
1235 *
1236 * and write the address of the extension in *all*
1237 * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1238 *
1239 */
1240}
1241
1242EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1243{
1244 if (!validate_display_surface(dpy, draw))
1245 return EGL_FALSE;
1246 egl_display_t const * const dp = get_display(dpy);
1247 egl_surface_t const * const s = get_surface(draw);
1248 return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1249}
1250
1251EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1252 NativePixmapType target)
1253{
1254 if (!validate_display_surface(dpy, surface))
1255 return EGL_FALSE;
1256 egl_display_t const * const dp = get_display(dpy);
1257 egl_surface_t const * const s = get_surface(surface);
1258 return s->cnx->hooks->egl.eglCopyBuffers(
1259 dp->dpys[s->impl], s->surface, target);
1260}
1261
1262const char* eglQueryString(EGLDisplay dpy, EGLint name)
1263{
1264 egl_display_t const * const dp = get_display(dpy);
1265 switch (name) {
1266 case EGL_VENDOR:
1267 return gVendorString;
1268 case EGL_VERSION:
1269 return gVersionString;
1270 case EGL_EXTENSIONS:
1271 return gExtensionString;
1272 case EGL_CLIENT_APIS:
1273 return gClientApiString;
1274 }
1275 return setError(EGL_BAD_PARAMETER, (const char *)0);
1276}
1277
1278
1279// ----------------------------------------------------------------------------
1280// EGL 1.1
1281// ----------------------------------------------------------------------------
1282
1283EGLBoolean eglSurfaceAttrib(
1284 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1285{
1286 if (!validate_display_surface(dpy, surface))
1287 return EGL_FALSE;
1288 egl_display_t const * const dp = get_display(dpy);
1289 egl_surface_t const * const s = get_surface(surface);
1290 if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1291 return s->cnx->hooks->egl.eglSurfaceAttrib(
1292 dp->dpys[s->impl], s->surface, attribute, value);
1293 }
1294 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1295}
1296
1297EGLBoolean eglBindTexImage(
1298 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1299{
1300 if (!validate_display_surface(dpy, surface))
1301 return EGL_FALSE;
1302 egl_display_t const * const dp = get_display(dpy);
1303 egl_surface_t const * const s = get_surface(surface);
1304 if (s->cnx->hooks->egl.eglBindTexImage) {
1305 return s->cnx->hooks->egl.eglBindTexImage(
1306 dp->dpys[s->impl], s->surface, buffer);
1307 }
1308 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1309}
1310
1311EGLBoolean eglReleaseTexImage(
1312 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1313{
1314 if (!validate_display_surface(dpy, surface))
1315 return EGL_FALSE;
1316 egl_display_t const * const dp = get_display(dpy);
1317 egl_surface_t const * const s = get_surface(surface);
1318 if (s->cnx->hooks->egl.eglReleaseTexImage) {
1319 return s->cnx->hooks->egl.eglReleaseTexImage(
1320 dp->dpys[s->impl], s->surface, buffer);
1321 }
1322 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1323}
1324
1325EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1326{
1327 egl_display_t * const dp = get_display(dpy);
1328 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1329
1330 EGLBoolean res = EGL_TRUE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001331 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001332 egl_connection_t* const cnx = &gEGLImpl[i];
1333 if (cnx->dso) {
1334 if (cnx->hooks->egl.eglSwapInterval) {
1335 if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1336 res = EGL_FALSE;
1337 }
1338 }
1339 }
1340 }
1341 return res;
1342}
1343
1344
1345// ----------------------------------------------------------------------------
1346// EGL 1.2
1347// ----------------------------------------------------------------------------
1348
1349EGLBoolean eglWaitClient(void)
1350{
1351 EGLBoolean res = EGL_TRUE;
1352 EGLContext ctx = getContext();
1353 if (ctx) {
1354 egl_context_t const * const c = get_context(ctx);
1355 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1356 if (uint32_t(c->impl)>=2)
1357 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1358 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1359 if (!cnx->dso)
1360 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1361 if (cnx->hooks->egl.eglWaitClient) {
1362 res = cnx->hooks->egl.eglWaitClient();
1363 } else {
1364 res = cnx->hooks->egl.eglWaitGL();
1365 }
1366 }
1367 return res;
1368}
1369
1370EGLBoolean eglBindAPI(EGLenum api)
1371{
1372 // bind this API on all EGLs
1373 EGLBoolean res = EGL_TRUE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001374 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001375 egl_connection_t* const cnx = &gEGLImpl[i];
1376 if (cnx->dso) {
1377 if (cnx->hooks->egl.eglBindAPI) {
1378 if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1379 res = EGL_FALSE;
1380 }
1381 }
1382 }
1383 }
1384 return res;
1385}
1386
1387EGLenum eglQueryAPI(void)
1388{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001389 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001390 egl_connection_t* const cnx = &gEGLImpl[i];
1391 if (cnx->dso) {
1392 if (cnx->hooks->egl.eglQueryAPI) {
1393 // the first one we find is okay, because they all
1394 // should be the same
1395 return cnx->hooks->egl.eglQueryAPI();
1396 }
1397 }
1398 }
1399 // or, it can only be OpenGL ES
1400 return EGL_OPENGL_ES_API;
1401}
1402
1403EGLBoolean eglReleaseThread(void)
1404{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001405 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001406 egl_connection_t* const cnx = &gEGLImpl[i];
1407 if (cnx->dso) {
1408 if (cnx->hooks->egl.eglReleaseThread) {
1409 cnx->hooks->egl.eglReleaseThread();
1410 }
1411 }
1412 }
1413 clearTLS();
1414 return EGL_TRUE;
1415}
1416
1417EGLSurface eglCreatePbufferFromClientBuffer(
1418 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1419 EGLConfig config, const EGLint *attrib_list)
1420{
1421 egl_display_t const* dp = 0;
1422 int i=0, index=0;
1423 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1424 if (!cnx) return EGL_FALSE;
1425 if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1426 return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1427 dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1428 }
1429 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1430}
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001431
1432// ----------------------------------------------------------------------------
1433// EGL_EGLEXT_VERSION 3
1434// ----------------------------------------------------------------------------
1435
1436EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1437 const EGLint *attrib_list)
1438{
1439 EGLBoolean result = EGL_FALSE;
1440 if (!validate_display_surface(dpy, surface))
1441 return result;
1442
1443 egl_display_t const * const dp = get_display(dpy);
1444 egl_surface_t const * const s = get_surface(surface);
1445
1446 if (s->cnx->hooks->egl.eglLockSurfaceKHR) {
1447 result = s->cnx->hooks->egl.eglLockSurfaceKHR(
1448 dp->dpys[s->impl], s->surface, attrib_list);
1449 }
1450 return result;
1451}
1452
1453EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1454{
1455 EGLBoolean result = EGL_FALSE;
1456 if (!validate_display_surface(dpy, surface))
1457 return result;
1458
1459 egl_display_t const * const dp = get_display(dpy);
1460 egl_surface_t const * const s = get_surface(surface);
1461
1462 if (s->cnx->hooks->egl.eglUnlockSurfaceKHR) {
1463 result = s->cnx->hooks->egl.eglUnlockSurfaceKHR(
1464 dp->dpys[s->impl], s->surface);
1465 }
1466 return result;
1467}
1468
1469EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1470 EGLClientBuffer buffer, const EGLint *attrib_list)
1471{
1472 if (ctx != EGL_NO_CONTEXT) {
1473 if (!validate_display_context(dpy, ctx))
1474 return EGL_NO_IMAGE_KHR;
1475 egl_display_t const * const dp = get_display(dpy);
1476 egl_context_t * const c = get_context(ctx);
1477 // since we have an EGLContext, we know which implementation to use
1478 EGLImageKHR image = c->cnx->hooks->egl.eglCreateImageKHR(
1479 dp->dpys[c->impl], c->context, target, buffer, attrib_list);
1480 if (image == EGL_NO_IMAGE_KHR)
1481 return image;
1482
1483 egl_image_t* result = new egl_image_t(dpy, ctx);
1484 result->images[c->impl] = image;
1485 return (EGLImageKHR)result;
1486 } else {
1487 // EGL_NO_CONTEXT is a valid parameter
1488 egl_display_t const * const dp = get_display(dpy);
1489 if (dp == 0) {
1490 return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1491 }
1492 // since we don't have a way to know which implementation to call,
1493 // we're calling all of them
1494
1495 EGLImageKHR implImages[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
1496 bool success = false;
1497 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1498 egl_connection_t* const cnx = &gEGLImpl[i];
1499 implImages[i] = EGL_NO_IMAGE_KHR;
1500 if (cnx->dso) {
1501 if (cnx->hooks->egl.eglCreateImageKHR) {
1502 implImages[i] = cnx->hooks->egl.eglCreateImageKHR(
1503 dp->dpys[i], ctx, target, buffer, attrib_list);
1504 if (implImages[i] != EGL_NO_IMAGE_KHR) {
1505 success = true;
1506 }
1507 }
1508 }
1509 }
1510 if (!success)
1511 return EGL_NO_IMAGE_KHR;
1512
1513 egl_image_t* result = new egl_image_t(dpy, ctx);
1514 memcpy(result->images, implImages, sizeof(implImages));
1515 return (EGLImageKHR)result;
1516 }
1517}
1518
1519EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1520{
1521 egl_display_t const * const dp = get_display(dpy);
1522 if (dp == 0) {
1523 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1524 }
1525
1526 egl_image_t* image = get_image(img);
1527 if (!image->isValid()) {
1528 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1529 }
1530
1531 bool success = false;
1532 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1533 egl_connection_t* const cnx = &gEGLImpl[i];
1534 if (image->images[i] != EGL_NO_IMAGE_KHR) {
1535 if (cnx->dso) {
1536 if (cnx->hooks->egl.eglCreateImageKHR) {
1537 if (cnx->hooks->egl.eglDestroyImageKHR(
1538 dp->dpys[i], image->images[i])) {
1539 success = true;
1540 }
1541 }
1542 }
1543 }
1544 }
1545 if (!success)
1546 return EGL_FALSE;
1547
1548 delete image;
1549
1550 return EGL_FALSE;
1551}