blob: 6c805388ce8aa5d9504acd4a40dd955f364a7571 [file] [log] [blame]
The Android Open Source Project9066cfe2009-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 Project9066cfe2009-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 Agopian1473f462009-04-10 14:24:30 -070039#include <utils/threads.h>
40#include <utils/KeyedVector.h>
The Android Open Source Project9066cfe2009-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 Agopian1473f462009-04-10 14:24:30 -070058static char const * const gExtensionString =
59 "EGL_KHR_image "
Mathias Agopian927d37c2009-05-06 23:47:08 -070060 "EGL_KHR_image_base "
61 "EGL_KHR_image_pixmap "
Mathias Agopian1473f462009-04-10 14:24:30 -070062 "EGL_ANDROID_image_native_buffer "
Mathias Agopian2e20bff2009-05-04 19:29:25 -070063 "EGL_ANDROID_swap_rectangle "
Mathias Agopian1473f462009-04-10 14:24:30 -070064 ;
65
66// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067
68template <int MAGIC>
69struct egl_object_t
70{
71 egl_object_t() : magic(MAGIC) { }
72 ~egl_object_t() { magic = 0; }
73 bool isValid() const { return magic == MAGIC; }
74private:
75 uint32_t magic;
76};
77
78struct egl_display_t : public egl_object_t<'_dpy'>
79{
Mathias Agopian1473f462009-04-10 14:24:30 -070080 EGLDisplay dpys[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
81 EGLConfig* configs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
82 EGLint numConfigs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083 EGLint numTotalConfigs;
84 char const* extensionsString;
85 volatile int32_t refs;
86 struct strings_t {
87 char const * vendor;
88 char const * version;
89 char const * clientApi;
90 char const * extensions;
91 };
Mathias Agopian1473f462009-04-10 14:24:30 -070092 strings_t queryString[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093};
94
95struct egl_surface_t : public egl_object_t<'_srf'>
96{
97 egl_surface_t(EGLDisplay dpy, EGLSurface surface,
Mathias Agopian1473f462009-04-10 14:24:30 -070098 int impl, egl_connection_t const* cnx)
99 : dpy(dpy), surface(surface), impl(impl), cnx(cnx)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 {
101 // NOTE: window must be incRef'ed and connected already
102 }
103 ~egl_surface_t() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 }
105 EGLDisplay dpy;
106 EGLSurface surface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 int impl;
108 egl_connection_t const* cnx;
109};
110
111struct egl_context_t : public egl_object_t<'_ctx'>
112{
113 egl_context_t(EGLDisplay dpy, EGLContext context,
114 int impl, egl_connection_t const* cnx)
115 : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
116 {
117 }
118 EGLDisplay dpy;
119 EGLContext context;
120 EGLSurface read;
121 EGLSurface draw;
122 int impl;
123 egl_connection_t const* cnx;
124};
125
Mathias Agopian1473f462009-04-10 14:24:30 -0700126struct egl_image_t : public egl_object_t<'_img'>
127{
128 egl_image_t(EGLDisplay dpy, EGLContext context)
129 : dpy(dpy), context(context)
130 {
131 memset(images, 0, sizeof(images));
132 }
133 EGLDisplay dpy;
134 EGLConfig context;
135 EGLImageKHR images[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
136};
137
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138struct tls_t
139{
140 tls_t() : error(EGL_SUCCESS), ctx(0) { }
141 EGLint error;
142 EGLContext ctx;
143};
144
145static void gl_unimplemented() {
146 LOGE("called unimplemented OpenGL ES API");
147}
148
149// ----------------------------------------------------------------------------
150// GL / EGL hooks
151// ----------------------------------------------------------------------------
152
153#undef GL_ENTRY
154#undef EGL_ENTRY
155#define GL_ENTRY(_r, _api, ...) #_api,
156#define EGL_ENTRY(_r, _api, ...) #_api,
157
158static char const * const gl_names[] = {
159 #include "gl_entries.in"
Mathias Agopian1feecd82009-04-23 18:05:44 -0700160 #include "glext_entries.in"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 NULL
162};
163
164static char const * const egl_names[] = {
165 #include "egl_entries.in"
166 NULL
167};
168
169#undef GL_ENTRY
170#undef EGL_ENTRY
171
172// ----------------------------------------------------------------------------
173
Mathias Agopian1473f462009-04-10 14:24:30 -0700174egl_connection_t gEGLImpl[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175static egl_display_t gDisplay[NUM_DISPLAYS];
176static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
177static pthread_key_t gEGLThreadLocalStorageKey = -1;
178
179// ----------------------------------------------------------------------------
180
181gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
182pthread_key_t gGLWrapperKey = -1;
183
184// ----------------------------------------------------------------------------
185
186static __attribute__((noinline))
187const char *egl_strerror(EGLint err)
188{
189 switch (err){
190 case EGL_SUCCESS: return "EGL_SUCCESS";
191 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
192 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
193 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
194 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
195 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
196 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
197 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
198 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
199 case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
200 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
201 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
202 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
203 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
204 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
205 default: return "UNKNOWN";
206 }
207}
208
209static __attribute__((noinline))
210void clearTLS() {
211 if (gEGLThreadLocalStorageKey != -1) {
212 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
213 if (tls) {
214 delete tls;
215 pthread_setspecific(gEGLThreadLocalStorageKey, 0);
216 }
217 }
218}
219
220static tls_t* getTLS()
221{
222 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
223 if (tls == 0) {
224 tls = new tls_t;
225 pthread_setspecific(gEGLThreadLocalStorageKey, tls);
226 }
227 return tls;
228}
229
230template<typename T>
231static __attribute__((noinline))
232T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
233 if (gEGLThreadLocalStorageKey == -1) {
234 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
235 if (gEGLThreadLocalStorageKey == -1)
236 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
237 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
238 }
239 tls_t* tls = getTLS();
240 if (tls->error != error) {
241 LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
242 tls->error = error;
243 }
244 return returnValue;
245}
246
247static __attribute__((noinline))
248GLint getError() {
249 if (gEGLThreadLocalStorageKey == -1)
250 return EGL_SUCCESS;
251 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
252 if (!tls) return EGL_SUCCESS;
253 GLint error = tls->error;
254 tls->error = EGL_SUCCESS;
255 return error;
256}
257
258static __attribute__((noinline))
259void setContext(EGLContext ctx) {
260 if (gEGLThreadLocalStorageKey == -1) {
261 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
262 if (gEGLThreadLocalStorageKey == -1)
263 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
264 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
265 }
266 tls_t* tls = getTLS();
267 tls->ctx = ctx;
268}
269
270static __attribute__((noinline))
271EGLContext getContext() {
272 if (gEGLThreadLocalStorageKey == -1)
273 return EGL_NO_CONTEXT;
274 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
275 if (!tls) return EGL_NO_CONTEXT;
276 return tls->ctx;
277}
278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279/*****************************************************************************/
280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281static __attribute__((noinline))
282void *load_driver(const char* driver, gl_hooks_t* hooks)
283{
Mathias Agopian04ae6342009-04-23 19:57:10 -0700284 //LOGD("%s", driver);
285 char scrap[256];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
287 LOGE_IF(!dso,
288 "couldn't load <%s> library (%s)",
289 driver, dlerror());
290
291 if (dso) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700292 // first find the symbol for eglGetProcAddress
293
294 typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
295 const char*);
296
297 getProcAddressType getProcAddress =
298 (getProcAddressType)dlsym(dso, "eglGetProcAddress");
299
300 LOGE_IF(!getProcAddress,
301 "can't find eglGetProcAddress() in %s", driver);
302
303 __eglMustCastToProperFunctionPointerType* curr;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 char const * const * api;
Mathias Agopian1473f462009-04-10 14:24:30 -0700305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 gl_hooks_t::egl_t* egl = &hooks->egl;
Mathias Agopian1473f462009-04-10 14:24:30 -0700307 curr = (__eglMustCastToProperFunctionPointerType*)egl;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 api = egl_names;
309 while (*api) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700310 char const * name = *api;
311 __eglMustCastToProperFunctionPointerType f =
312 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 if (f == NULL) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700314 // couldn't find the entry-point, use eglGetProcAddress()
315 f = getProcAddress(name);
316 if (f == NULL) {
317 f = (__eglMustCastToProperFunctionPointerType)0;
318 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 }
320 *curr++ = f;
321 api++;
322 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700323 gl_hooks_t::gl_t* gl = &hooks->gl;
324 curr = (__eglMustCastToProperFunctionPointerType*)gl;
325 api = gl_names;
326 while (*api) {
327 char const * name = *api;
Mathias Agopian1473f462009-04-10 14:24:30 -0700328 __eglMustCastToProperFunctionPointerType f =
329 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
330 if (f == NULL) {
331 // couldn't find the entry-point, use eglGetProcAddress()
332 f = getProcAddress(name);
Mathias Agopian04ae6342009-04-23 19:57:10 -0700333 }
334 if (f == NULL) {
335 // Try without the OES postfix
336 ssize_t index = ssize_t(strlen(name)) - 3;
337 if ((index>0 && (index<255)) && (!strcmp(name+index, "OES"))) {
338 strncpy(scrap, name, index);
339 scrap[index] = 0;
340 f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
341 //LOGD_IF(f, "found <%s> instead", scrap);
Mathias Agopian1473f462009-04-10 14:24:30 -0700342 }
343 }
Mathias Agopian04ae6342009-04-23 19:57:10 -0700344 if (f == NULL) {
345 // Try with the OES postfix
346 ssize_t index = ssize_t(strlen(name)) - 3;
347 if ((index>0 && (index<252)) && (strcmp(name+index, "OES"))) {
348 strncpy(scrap, name, index);
349 scrap[index] = 0;
350 strcat(scrap, "OES");
351 f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
352 //LOGD_IF(f, "found <%s> instead", scrap);
353 }
354 }
355 if (f == NULL) {
Mathias Agopian799af8d2009-04-24 18:16:44 -0700356 //LOGD("%s", name);
Mathias Agopian04ae6342009-04-23 19:57:10 -0700357 f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
358 }
Mathias Agopian1473f462009-04-10 14:24:30 -0700359 *curr++ = f;
360 api++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 }
362 }
363 return dso;
364}
365
366template<typename T>
367static __attribute__((noinline))
368int binarySearch(
369 T const sortedArray[], int first, int last, T key)
370{
371 while (first <= last) {
372 int mid = (first + last) / 2;
373 if (key > sortedArray[mid]) {
374 first = mid + 1;
375 } else if (key < sortedArray[mid]) {
376 last = mid - 1;
377 } else {
378 return mid;
379 }
380 }
381 return -1;
382}
383
384static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
385{
386 // NOTE: this mapping works only if we have no more than two EGLimpl
387 return (i>0 ? dp->numConfigs[0] : 0) + index;
388}
389
390static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
391 int& i, int& index)
392{
393 // NOTE: this mapping works only if we have no more than two EGLimpl
394 size_t numConfigs = dp->numConfigs[0];
395 i = configId / numConfigs;
396 index = configId % numConfigs;
397}
398
399static int cmp_configs(const void* a, const void *b)
400{
401 EGLConfig c0 = *(EGLConfig const *)a;
402 EGLConfig c1 = *(EGLConfig const *)b;
403 return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
404}
405
406struct extention_map_t {
407 const char* name;
408 __eglMustCastToProperFunctionPointerType address;
409};
410
411static const extention_map_t gExtentionMap[] = {
Mathias Agopian1473f462009-04-10 14:24:30 -0700412 { "eglLockSurfaceKHR",
413 (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
414 { "eglUnlockSurfaceKHR",
415 (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
416 { "eglCreateImageKHR",
417 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
418 { "eglDestroyImageKHR",
419 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420};
421
422static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
423
424static void(*findProcAddress(const char* name,
425 const extention_map_t* map, size_t n))()
426{
427 for (uint32_t i=0 ; i<n ; i++) {
428 if (!strcmp(name, map[i].name)) {
429 return map[i].address;
430 }
431 }
432 return NULL;
433}
434
435// ----------------------------------------------------------------------------
436
Mathias Agopian1473f462009-04-10 14:24:30 -0700437/*
438 * To "loose" the GPU, use something like
439 * gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_CONTEXT_LOST];
440 *
441 */
442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443static int gl_context_lost() {
444 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
445 return 0;
446}
447static int egl_context_lost() {
448 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
449 return EGL_FALSE;
450}
451static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
452 usleep(100000); // don't use all the CPU
453 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
454 return EGL_FALSE;
455}
456static GLint egl_context_lost_get_error() {
457 return EGL_CONTEXT_LOST;
458}
459static int ext_context_lost() {
460 return 0;
461}
462
463static void gl_no_context() {
464 LOGE("call to OpenGL ES API with no current context");
465}
466static void early_egl_init(void)
467{
468#if !USE_FAST_TLS_KEY
469 pthread_key_create(&gGLWrapperKey, NULL);
470#endif
471 uint32_t addr = (uint32_t)((void*)gl_no_context);
472 android_memset32(
473 (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT],
474 addr,
475 sizeof(gHooks[IMPL_NO_CONTEXT]));
476 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
477}
478
479static pthread_once_t once_control = PTHREAD_ONCE_INIT;
480static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
481
482
483static inline
484egl_display_t* get_display(EGLDisplay dpy)
485{
486 uintptr_t index = uintptr_t(dpy)-1U;
487 return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
488}
489
Mathias Agopian1473f462009-04-10 14:24:30 -0700490template<typename NATIVE, typename EGL>
491static inline NATIVE* egl_to_native_cast(EGL arg) {
492 return reinterpret_cast<NATIVE*>(arg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493}
494
495static inline
Mathias Agopian1473f462009-04-10 14:24:30 -0700496egl_surface_t* get_surface(EGLSurface surface) {
497 return egl_to_native_cast<egl_surface_t>(surface);
498}
499
500static inline
501egl_context_t* get_context(EGLContext context) {
502 return egl_to_native_cast<egl_context_t>(context);
503}
504
505static inline
506egl_image_t* get_image(EGLImageKHR image) {
507 return egl_to_native_cast<egl_image_t>(image);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508}
509
510static egl_connection_t* validate_display_config(
511 EGLDisplay dpy, EGLConfig config,
512 egl_display_t const*& dp, int& impl, int& index)
513{
514 dp = get_display(dpy);
515 if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
516
517 impl = uintptr_t(config)>>24;
Mathias Agopian1473f462009-04-10 14:24:30 -0700518 if (uint32_t(impl) >= IMPL_NUM_DRIVERS_IMPLEMENTATIONS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
520 }
521 index = uintptr_t(config) & 0xFFFFFF;
522 if (index >= dp->numConfigs[impl]) {
523 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
524 }
525 egl_connection_t* const cnx = &gEGLImpl[impl];
526 if (cnx->dso == 0) {
527 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
528 }
529 return cnx;
530}
531
532static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
533{
534 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
535 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
536 if (!get_display(dpy)->isValid())
537 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
538 if (!ctx) // TODO: make sure context is a valid object
539 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
540 if (!get_context(ctx)->isValid())
541 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
542 return EGL_TRUE;
543}
544
545static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
546{
547 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
548 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
549 if (!get_display(dpy)->isValid())
550 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
551 if (!surface) // TODO: make sure surface is a valid object
552 return setError(EGL_BAD_SURFACE, EGL_FALSE);
553 if (!get_surface(surface)->isValid())
554 return setError(EGL_BAD_SURFACE, EGL_FALSE);
555 return EGL_TRUE;
556}
557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558
Mathias Agopian1473f462009-04-10 14:24:30 -0700559EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
560{
561 EGLContext context = getContext();
562 if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
563 return EGL_NO_IMAGE_KHR;
564
565 egl_context_t const * const c = get_context(context);
566 if (!c->isValid())
567 return EGL_NO_IMAGE_KHR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568
Mathias Agopian1473f462009-04-10 14:24:30 -0700569 egl_image_t const * const i = get_image(image);
570 if (!i->isValid())
571 return EGL_NO_IMAGE_KHR;
572
573 return i->images[c->impl];
574}
575
576
577EGLDisplay egl_init_displays(NativeDisplayType display)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578{
579 if (sEarlyInitState) {
580 return EGL_NO_DISPLAY;
581 }
582
583 uint32_t index = uint32_t(display);
584 if (index >= NUM_DISPLAYS) {
585 return EGL_NO_DISPLAY;
586 }
587
588 EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
589 egl_display_t* d = &gDisplay[index];
Mathias Agopian1473f462009-04-10 14:24:30 -0700590
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 // dynamically load all our EGL implementations for that display
592 // and call into the real eglGetGisplay()
593 egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
594 if (cnx->dso == 0) {
595 cnx->hooks = &gHooks[IMPL_SOFTWARE];
596 cnx->dso = load_driver("libagl.so", cnx->hooks);
597 }
598 if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
599 d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
600 LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
601 "No EGLDisplay for software EGL!");
602 }
603
604 cnx = &gEGLImpl[IMPL_HARDWARE];
605 if (cnx->dso == 0 && cnx->unavailable == 0) {
606 char value[PROPERTY_VALUE_MAX];
607 property_get("debug.egl.hw", value, "1");
608 if (atoi(value) != 0) {
609 cnx->hooks = &gHooks[IMPL_HARDWARE];
Mathias Agopian1473f462009-04-10 14:24:30 -0700610 cnx->dso = load_driver("libhgl2.so", cnx->hooks);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 } else {
612 LOGD("3D hardware acceleration is disabled");
613 }
614 }
615 if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
616 android_memset32(
617 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
618 (uint32_t)((void*)gl_context_lost),
619 sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
620 android_memset32(
621 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
622 (uint32_t)((void*)egl_context_lost),
623 sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
624 android_memset32(
625 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
626 (uint32_t)((void*)ext_context_lost),
627 sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
628
629 gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
630 egl_context_lost_swap_buffers;
631
632 gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
633 egl_context_lost_get_error;
634
635 gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
636 gHooks[IMPL_HARDWARE].egl.eglTerminate;
637
638 d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
639 if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
640 LOGE("h/w accelerated eglGetDisplay() failed (%s)",
641 egl_strerror(cnx->hooks->egl.eglGetError()));
642 dlclose((void*)cnx->dso);
643 cnx->dso = 0;
644 // in case of failure, we want to make sure we don't try again
645 // as it's expensive.
646 cnx->unavailable = 1;
647 }
648 }
649
650 return dpy;
651}
652
Mathias Agopian1473f462009-04-10 14:24:30 -0700653
654// ----------------------------------------------------------------------------
655}; // namespace android
656// ----------------------------------------------------------------------------
657
658using namespace android;
659
660EGLDisplay eglGetDisplay(NativeDisplayType display)
661{
662 return egl_init_displays(display);
663}
664
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665// ----------------------------------------------------------------------------
666// Initialization
667// ----------------------------------------------------------------------------
668
669EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
670{
671 egl_display_t * const dp = get_display(dpy);
672 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
673
674 if (android_atomic_inc(&dp->refs) > 0) {
675 if (major != NULL) *major = VERSION_MAJOR;
676 if (minor != NULL) *minor = VERSION_MINOR;
677 return EGL_TRUE;
678 }
679
680 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
681
682 // initialize each EGL and
683 // build our own extension string first, based on the extension we know
684 // and the extension supported by our client implementation
685 dp->extensionsString = strdup(gExtensionString);
Mathias Agopian1473f462009-04-10 14:24:30 -0700686 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 egl_connection_t* const cnx = &gEGLImpl[i];
688 cnx->major = -1;
689 cnx->minor = -1;
690 if (!cnx->dso)
691 continue;
692
693 if (cnx->hooks->egl.eglInitialize(
694 dp->dpys[i], &cnx->major, &cnx->minor)) {
695
696 //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
697 // i, dp->dpys[i], cnx->major, cnx->minor, cnx);
698
699 // get the query-strings for this display for each implementation
700 dp->queryString[i].vendor =
701 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
702 dp->queryString[i].version =
703 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
704 dp->queryString[i].extensions = strdup(
705 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
706 dp->queryString[i].clientApi =
707 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
708
709 } else {
710 LOGD("%d: eglInitialize() failed (%s)",
711 i, egl_strerror(cnx->hooks->egl.eglGetError()));
712 }
713 }
714
715 EGLBoolean res = EGL_FALSE;
Mathias Agopian1473f462009-04-10 14:24:30 -0700716 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 egl_connection_t* const cnx = &gEGLImpl[i];
718 if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
719 EGLint n;
720 if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
721 dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
722 if (dp->configs[i]) {
723 if (cnx->hooks->egl.eglGetConfigs(
724 dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
725 {
726 // sort the configurations so we can do binary searches
727 qsort( dp->configs[i],
728 dp->numConfigs[i],
729 sizeof(EGLConfig), cmp_configs);
730
731 dp->numTotalConfigs += n;
732 res = EGL_TRUE;
733 }
734 }
735 }
736 }
737 }
738
739 if (res == EGL_TRUE) {
740 if (major != NULL) *major = VERSION_MAJOR;
741 if (minor != NULL) *minor = VERSION_MINOR;
742 return EGL_TRUE;
743 }
744 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
745}
746
747EGLBoolean eglTerminate(EGLDisplay dpy)
748{
749 egl_display_t* const dp = get_display(dpy);
750 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
751 if (android_atomic_dec(&dp->refs) != 1)
752 return EGL_TRUE;
753
754 EGLBoolean res = EGL_FALSE;
Mathias Agopian1473f462009-04-10 14:24:30 -0700755 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 egl_connection_t* const cnx = &gEGLImpl[i];
757 if (cnx->dso) {
758 cnx->hooks->egl.eglTerminate(dp->dpys[i]);
759
760 /* REVISIT: it's unclear what to do if eglTerminate() fails,
761 * on one end we shouldn't care, on the other end if it fails
762 * it might not be safe to call dlclose() (there could be some
763 * threads around). */
764
765 free(dp->configs[i]);
766 free((void*)dp->queryString[i].extensions);
767 dp->numConfigs[i] = 0;
768 dp->dpys[i] = EGL_NO_DISPLAY;
769 dlclose((void*)cnx->dso);
770 cnx->dso = 0;
771 res = EGL_TRUE;
772 }
773 }
774 free((void*)dp->extensionsString);
775 dp->extensionsString = 0;
776 dp->numTotalConfigs = 0;
777 clearTLS();
778 return res;
779}
780
781// ----------------------------------------------------------------------------
782// configuration
783// ----------------------------------------------------------------------------
784
785EGLBoolean eglGetConfigs( EGLDisplay dpy,
786 EGLConfig *configs,
787 EGLint config_size, EGLint *num_config)
788{
789 egl_display_t const * const dp = get_display(dpy);
790 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
791
792 GLint numConfigs = dp->numTotalConfigs;
793 if (!configs) {
794 *num_config = numConfigs;
795 return EGL_TRUE;
796 }
797 GLint n = 0;
Mathias Agopian1473f462009-04-10 14:24:30 -0700798 for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
800 *configs++ = MAKE_CONFIG(j, i);
801 config_size--;
802 n++;
803 }
804 }
805
806 *num_config = n;
807 return EGL_TRUE;
808}
809
810EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
811 EGLConfig *configs, EGLint config_size,
812 EGLint *num_config)
813{
814 egl_display_t const * const dp = get_display(dpy);
815 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
816
Jack Palevich1badb712009-03-25 15:12:17 -0700817 if (num_config==0) {
818 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 }
820
821 EGLint n;
822 EGLBoolean res = EGL_FALSE;
823 *num_config = 0;
824
825
826 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
827 // to do this, we have to go through the attrib_list array once
828 // to figure out both its size and if it contains an EGL_CONFIG_ID
829 // key. If so, the full array is copied and patched.
830 // NOTE: we assume that there can be only one occurrence
831 // of EGL_CONFIG_ID.
832
833 EGLint patch_index = -1;
834 GLint attr;
835 size_t size = 0;
836 while ((attr=attrib_list[size])) {
837 if (attr == EGL_CONFIG_ID)
838 patch_index = size;
839 size += 2;
840 }
841 if (patch_index >= 0) {
842 size += 2; // we need copy the sentinel as well
843 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
844 if (new_list == 0)
845 return setError(EGL_BAD_ALLOC, EGL_FALSE);
846 memcpy(new_list, attrib_list, size*sizeof(EGLint));
847
848 // patch the requested EGL_CONFIG_ID
849 int i, index;
850 EGLint& configId(new_list[patch_index+1]);
851 uniqueIdToConfig(dp, configId, i, index);
852
853 egl_connection_t* const cnx = &gEGLImpl[i];
854 if (cnx->dso) {
855 cnx->hooks->egl.eglGetConfigAttrib(
856 dp->dpys[i], dp->configs[i][index],
857 EGL_CONFIG_ID, &configId);
858
859 // and switch to the new list
860 attrib_list = const_cast<const EGLint *>(new_list);
861
862 // At this point, the only configuration that can match is
863 // dp->configs[i][index], however, we don't know if it would be
864 // rejected because of the other attributes, so we do have to call
865 // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
866 // through all the EGLimpl[].
867 // We also know we can only get a single config back, and we know
868 // which one.
869
870 res = cnx->hooks->egl.eglChooseConfig(
871 dp->dpys[i], attrib_list, configs, config_size, &n);
872 if (res && n>0) {
873 // n has to be 0 or 1, by construction, and we already know
874 // which config it will return (since there can be only one).
Jack Palevich1badb712009-03-25 15:12:17 -0700875 if (configs) {
876 configs[0] = MAKE_CONFIG(i, index);
877 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800878 *num_config = 1;
879 }
880 }
881
882 free(const_cast<EGLint *>(attrib_list));
883 return res;
884 }
885
Mathias Agopian1473f462009-04-10 14:24:30 -0700886 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 egl_connection_t* const cnx = &gEGLImpl[i];
888 if (cnx->dso) {
889 if (cnx->hooks->egl.eglChooseConfig(
890 dp->dpys[i], attrib_list, configs, config_size, &n)) {
Jack Palevich1badb712009-03-25 15:12:17 -0700891 if (configs) {
892 // now we need to convert these client EGLConfig to our
893 // internal EGLConfig format. This is done in O(n log n).
894 for (int j=0 ; j<n ; j++) {
895 int index = binarySearch<EGLConfig>(
896 dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
897 if (index >= 0) {
898 if (configs) {
899 configs[j] = MAKE_CONFIG(i, index);
900 }
901 } else {
902 return setError(EGL_BAD_CONFIG, EGL_FALSE);
903 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 }
Jack Palevich1badb712009-03-25 15:12:17 -0700905 configs += n;
906 config_size -= n;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800907 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 *num_config += n;
909 res = EGL_TRUE;
910 }
911 }
912 }
913 return res;
914}
915
916EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
917 EGLint attribute, EGLint *value)
918{
919 egl_display_t const* dp = 0;
920 int i=0, index=0;
921 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
922 if (!cnx) return EGL_FALSE;
923
924 if (attribute == EGL_CONFIG_ID) {
925 // EGL_CONFIG_IDs must be unique, just use the order of the selected
926 // EGLConfig.
927 *value = configToUniqueId(dp, i, index);
928 return EGL_TRUE;
929 }
930 return cnx->hooks->egl.eglGetConfigAttrib(
931 dp->dpys[i], dp->configs[i][index], attribute, value);
932}
933
934// ----------------------------------------------------------------------------
935// surfaces
936// ----------------------------------------------------------------------------
937
938EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
939 NativeWindowType window,
940 const EGLint *attrib_list)
941{
942 egl_display_t const* dp = 0;
943 int i=0, index=0;
944 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
945 if (cnx) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
947 dp->dpys[i], dp->configs[i][index], window, attrib_list);
948 if (surface != EGL_NO_SURFACE) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700949 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 return s;
951 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 }
953 return EGL_NO_SURFACE;
954}
955
956EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
957 NativePixmapType pixmap,
958 const EGLint *attrib_list)
959{
960 egl_display_t const* dp = 0;
961 int i=0, index=0;
962 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
963 if (cnx) {
964 EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
965 dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
966 if (surface != EGL_NO_SURFACE) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700967 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 return s;
969 }
970 }
971 return EGL_NO_SURFACE;
972}
973
974EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
975 const EGLint *attrib_list)
976{
977 egl_display_t const* dp = 0;
978 int i=0, index=0;
979 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
980 if (cnx) {
981 EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
982 dp->dpys[i], dp->configs[i][index], attrib_list);
983 if (surface != EGL_NO_SURFACE) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700984 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 return s;
986 }
987 }
988 return EGL_NO_SURFACE;
989}
990
991EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
992{
993 if (!validate_display_surface(dpy, surface))
994 return EGL_FALSE;
995 egl_display_t const * const dp = get_display(dpy);
996 egl_surface_t const * const s = get_surface(surface);
997
998 EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
999 dp->dpys[s->impl], s->surface);
1000
1001 delete s;
1002 return result;
1003}
1004
1005EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
1006 EGLint attribute, EGLint *value)
1007{
1008 if (!validate_display_surface(dpy, surface))
1009 return EGL_FALSE;
1010 egl_display_t const * const dp = get_display(dpy);
1011 egl_surface_t const * const s = get_surface(surface);
1012
1013 return s->cnx->hooks->egl.eglQuerySurface(
1014 dp->dpys[s->impl], s->surface, attribute, value);
1015}
1016
1017// ----------------------------------------------------------------------------
1018// contextes
1019// ----------------------------------------------------------------------------
1020
1021EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1022 EGLContext share_list, const EGLint *attrib_list)
1023{
1024 egl_display_t const* dp = 0;
1025 int i=0, index=0;
1026 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1027 if (cnx) {
1028 EGLContext context = cnx->hooks->egl.eglCreateContext(
1029 dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
1030 if (context != EGL_NO_CONTEXT) {
1031 egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
1032 return c;
1033 }
1034 }
1035 return EGL_NO_CONTEXT;
1036}
1037
1038EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1039{
1040 if (!validate_display_context(dpy, ctx))
1041 return EGL_FALSE;
1042 egl_display_t const * const dp = get_display(dpy);
1043 egl_context_t * const c = get_context(ctx);
1044 EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
1045 dp->dpys[c->impl], c->context);
1046 delete c;
1047 return result;
1048}
1049
1050EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
1051 EGLSurface read, EGLContext ctx)
1052{
1053 egl_display_t const * const dp = get_display(dpy);
1054 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1055
1056 if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
1057 ctx == EGL_NO_CONTEXT)
1058 {
1059 EGLBoolean result = EGL_TRUE;
1060 ctx = getContext();
1061 if (ctx) {
1062 egl_context_t * const c = get_context(ctx);
1063 result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
1064 if (result == EGL_TRUE) {
1065 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
1066 setContext(EGL_NO_CONTEXT);
1067 }
1068 }
1069 return result;
1070 }
1071
1072 if (!validate_display_context(dpy, ctx))
1073 return EGL_FALSE;
1074
1075 egl_context_t * const c = get_context(ctx);
1076 if (draw != EGL_NO_SURFACE) {
1077 egl_surface_t const * d = get_surface(draw);
1078 if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1079 if (d->impl != c->impl)
1080 return setError(EGL_BAD_MATCH, EGL_FALSE);
1081 draw = d->surface;
1082 }
1083 if (read != EGL_NO_SURFACE) {
1084 egl_surface_t const * r = get_surface(read);
1085 if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1086 if (r->impl != c->impl)
1087 return setError(EGL_BAD_MATCH, EGL_FALSE);
1088 read = r->surface;
1089 }
1090 EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
1091 dp->dpys[c->impl], draw, read, c->context);
1092
1093 if (result == EGL_TRUE) {
1094 setGlThreadSpecific(c->cnx->hooks);
1095 setContext(ctx);
1096 c->read = read;
1097 c->draw = draw;
1098 }
1099 return result;
1100}
1101
1102
1103EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1104 EGLint attribute, EGLint *value)
1105{
1106 if (!validate_display_context(dpy, ctx))
1107 return EGL_FALSE;
1108
1109 egl_display_t const * const dp = get_display(dpy);
1110 egl_context_t * const c = get_context(ctx);
1111
1112 return c->cnx->hooks->egl.eglQueryContext(
1113 dp->dpys[c->impl], c->context, attribute, value);
1114}
1115
1116EGLContext eglGetCurrentContext(void)
1117{
1118 EGLContext ctx = getContext();
1119 return ctx;
1120}
1121
1122EGLSurface eglGetCurrentSurface(EGLint readdraw)
1123{
1124 EGLContext ctx = getContext();
1125 if (ctx) {
1126 egl_context_t const * const c = get_context(ctx);
1127 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1128 switch (readdraw) {
1129 case EGL_READ: return c->read;
1130 case EGL_DRAW: return c->draw;
1131 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1132 }
1133 }
1134 return EGL_NO_SURFACE;
1135}
1136
1137EGLDisplay eglGetCurrentDisplay(void)
1138{
1139 EGLContext ctx = getContext();
1140 if (ctx) {
1141 egl_context_t const * const c = get_context(ctx);
1142 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1143 return c->dpy;
1144 }
1145 return EGL_NO_DISPLAY;
1146}
1147
1148EGLBoolean eglWaitGL(void)
1149{
1150 EGLBoolean res = EGL_TRUE;
1151 EGLContext ctx = getContext();
1152 if (ctx) {
1153 egl_context_t const * const c = get_context(ctx);
1154 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1155 if (uint32_t(c->impl)>=2)
1156 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1157 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1158 if (!cnx->dso)
1159 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1160 res = cnx->hooks->egl.eglWaitGL();
1161 }
1162 return res;
1163}
1164
1165EGLBoolean eglWaitNative(EGLint engine)
1166{
1167 EGLBoolean res = EGL_TRUE;
1168 EGLContext ctx = getContext();
1169 if (ctx) {
1170 egl_context_t const * const c = get_context(ctx);
1171 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1172 if (uint32_t(c->impl)>=2)
1173 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1174 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1175 if (!cnx->dso)
1176 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1177 res = cnx->hooks->egl.eglWaitNative(engine);
1178 }
1179 return res;
1180}
1181
1182EGLint eglGetError(void)
1183{
1184 EGLint result = EGL_SUCCESS;
Mathias Agopian1473f462009-04-10 14:24:30 -07001185 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001186 EGLint err = EGL_SUCCESS;
1187 egl_connection_t* const cnx = &gEGLImpl[i];
1188 if (cnx->dso)
1189 err = cnx->hooks->egl.eglGetError();
1190 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1191 result = err;
1192 }
1193 if (result == EGL_SUCCESS)
1194 result = getError();
1195 return result;
1196}
1197
Mathias Agopian1473f462009-04-10 14:24:30 -07001198__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001199{
Mathias Agopian1473f462009-04-10 14:24:30 -07001200 // eglGetProcAddress() could be the very first function called
1201 // in which case we must make sure we've initialized ourselves, this
1202 // happens the first time egl_get_display() is called.
1203
1204 if (egl_init_displays(EGL_DEFAULT_DISPLAY) == EGL_NO_DISPLAY)
1205 return NULL;
1206
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001207 __eglMustCastToProperFunctionPointerType addr;
1208 addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1209 if (addr) return addr;
1210
1211 return NULL; // TODO: finish implementation below
1212
1213 addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1214 if (addr) return addr;
1215
1216 addr = 0;
1217 int slot = -1;
Mathias Agopian1473f462009-04-10 14:24:30 -07001218 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 egl_connection_t* const cnx = &gEGLImpl[i];
1220 if (cnx->dso) {
1221 if (cnx->hooks->egl.eglGetProcAddress) {
1222 addr = cnx->hooks->egl.eglGetProcAddress(procname);
1223 if (addr) {
1224 if (slot == -1) {
1225 slot = 0; // XXX: find free slot
1226 if (slot == -1) {
1227 addr = 0;
1228 break;
1229 }
1230 }
1231 cnx->hooks->ext.extensions[slot] = addr;
1232 }
1233 }
1234 }
1235 }
1236
1237 if (slot >= 0) {
1238 addr = 0; // XXX: address of stub 'slot'
1239 gGLExtentionMap[slot].name = strdup(procname);
1240 gGLExtentionMap[slot].address = addr;
1241 }
1242
1243 return addr;
1244
1245
1246 /*
1247 * TODO: For OpenGL ES extensions, we must generate a stub
1248 * that looks like
1249 * mov r12, #0xFFFF0FFF
1250 * ldr r12, [r12, #-15]
1251 * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
1252 * mov r12, [r12, #api_offset]
1253 * ldrne pc, r12
1254 * mov pc, #unsupported_extension
1255 *
1256 * and write the address of the extension in *all*
1257 * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1258 *
1259 */
1260}
1261
1262EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1263{
1264 if (!validate_display_surface(dpy, draw))
1265 return EGL_FALSE;
1266 egl_display_t const * const dp = get_display(dpy);
1267 egl_surface_t const * const s = get_surface(draw);
1268 return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1269}
1270
1271EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1272 NativePixmapType target)
1273{
1274 if (!validate_display_surface(dpy, surface))
1275 return EGL_FALSE;
1276 egl_display_t const * const dp = get_display(dpy);
1277 egl_surface_t const * const s = get_surface(surface);
1278 return s->cnx->hooks->egl.eglCopyBuffers(
1279 dp->dpys[s->impl], s->surface, target);
1280}
1281
1282const char* eglQueryString(EGLDisplay dpy, EGLint name)
1283{
1284 egl_display_t const * const dp = get_display(dpy);
1285 switch (name) {
1286 case EGL_VENDOR:
1287 return gVendorString;
1288 case EGL_VERSION:
1289 return gVersionString;
1290 case EGL_EXTENSIONS:
1291 return gExtensionString;
1292 case EGL_CLIENT_APIS:
1293 return gClientApiString;
1294 }
1295 return setError(EGL_BAD_PARAMETER, (const char *)0);
1296}
1297
1298
1299// ----------------------------------------------------------------------------
1300// EGL 1.1
1301// ----------------------------------------------------------------------------
1302
1303EGLBoolean eglSurfaceAttrib(
1304 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1305{
1306 if (!validate_display_surface(dpy, surface))
1307 return EGL_FALSE;
1308 egl_display_t const * const dp = get_display(dpy);
1309 egl_surface_t const * const s = get_surface(surface);
1310 if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1311 return s->cnx->hooks->egl.eglSurfaceAttrib(
1312 dp->dpys[s->impl], s->surface, attribute, value);
1313 }
1314 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1315}
1316
1317EGLBoolean eglBindTexImage(
1318 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1319{
1320 if (!validate_display_surface(dpy, surface))
1321 return EGL_FALSE;
1322 egl_display_t const * const dp = get_display(dpy);
1323 egl_surface_t const * const s = get_surface(surface);
1324 if (s->cnx->hooks->egl.eglBindTexImage) {
1325 return s->cnx->hooks->egl.eglBindTexImage(
1326 dp->dpys[s->impl], s->surface, buffer);
1327 }
1328 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1329}
1330
1331EGLBoolean eglReleaseTexImage(
1332 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1333{
1334 if (!validate_display_surface(dpy, surface))
1335 return EGL_FALSE;
1336 egl_display_t const * const dp = get_display(dpy);
1337 egl_surface_t const * const s = get_surface(surface);
1338 if (s->cnx->hooks->egl.eglReleaseTexImage) {
1339 return s->cnx->hooks->egl.eglReleaseTexImage(
1340 dp->dpys[s->impl], s->surface, buffer);
1341 }
1342 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1343}
1344
1345EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1346{
1347 egl_display_t * const dp = get_display(dpy);
1348 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1349
1350 EGLBoolean res = EGL_TRUE;
Mathias Agopian1473f462009-04-10 14:24:30 -07001351 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001352 egl_connection_t* const cnx = &gEGLImpl[i];
1353 if (cnx->dso) {
1354 if (cnx->hooks->egl.eglSwapInterval) {
1355 if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1356 res = EGL_FALSE;
1357 }
1358 }
1359 }
1360 }
1361 return res;
1362}
1363
1364
1365// ----------------------------------------------------------------------------
1366// EGL 1.2
1367// ----------------------------------------------------------------------------
1368
1369EGLBoolean eglWaitClient(void)
1370{
1371 EGLBoolean res = EGL_TRUE;
1372 EGLContext ctx = getContext();
1373 if (ctx) {
1374 egl_context_t const * const c = get_context(ctx);
1375 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1376 if (uint32_t(c->impl)>=2)
1377 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1378 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1379 if (!cnx->dso)
1380 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1381 if (cnx->hooks->egl.eglWaitClient) {
1382 res = cnx->hooks->egl.eglWaitClient();
1383 } else {
1384 res = cnx->hooks->egl.eglWaitGL();
1385 }
1386 }
1387 return res;
1388}
1389
1390EGLBoolean eglBindAPI(EGLenum api)
1391{
1392 // bind this API on all EGLs
1393 EGLBoolean res = EGL_TRUE;
Mathias Agopian1473f462009-04-10 14:24:30 -07001394 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 egl_connection_t* const cnx = &gEGLImpl[i];
1396 if (cnx->dso) {
1397 if (cnx->hooks->egl.eglBindAPI) {
1398 if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1399 res = EGL_FALSE;
1400 }
1401 }
1402 }
1403 }
1404 return res;
1405}
1406
1407EGLenum eglQueryAPI(void)
1408{
Mathias Agopian1473f462009-04-10 14:24:30 -07001409 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001410 egl_connection_t* const cnx = &gEGLImpl[i];
1411 if (cnx->dso) {
1412 if (cnx->hooks->egl.eglQueryAPI) {
1413 // the first one we find is okay, because they all
1414 // should be the same
1415 return cnx->hooks->egl.eglQueryAPI();
1416 }
1417 }
1418 }
1419 // or, it can only be OpenGL ES
1420 return EGL_OPENGL_ES_API;
1421}
1422
1423EGLBoolean eglReleaseThread(void)
1424{
Mathias Agopian1473f462009-04-10 14:24:30 -07001425 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426 egl_connection_t* const cnx = &gEGLImpl[i];
1427 if (cnx->dso) {
1428 if (cnx->hooks->egl.eglReleaseThread) {
1429 cnx->hooks->egl.eglReleaseThread();
1430 }
1431 }
1432 }
1433 clearTLS();
1434 return EGL_TRUE;
1435}
1436
1437EGLSurface eglCreatePbufferFromClientBuffer(
1438 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1439 EGLConfig config, const EGLint *attrib_list)
1440{
1441 egl_display_t const* dp = 0;
1442 int i=0, index=0;
1443 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1444 if (!cnx) return EGL_FALSE;
1445 if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1446 return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1447 dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1448 }
1449 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1450}
Mathias Agopian1473f462009-04-10 14:24:30 -07001451
1452// ----------------------------------------------------------------------------
1453// EGL_EGLEXT_VERSION 3
1454// ----------------------------------------------------------------------------
1455
1456EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1457 const EGLint *attrib_list)
1458{
1459 EGLBoolean result = EGL_FALSE;
1460 if (!validate_display_surface(dpy, surface))
1461 return result;
1462
1463 egl_display_t const * const dp = get_display(dpy);
1464 egl_surface_t const * const s = get_surface(surface);
1465
1466 if (s->cnx->hooks->egl.eglLockSurfaceKHR) {
1467 result = s->cnx->hooks->egl.eglLockSurfaceKHR(
1468 dp->dpys[s->impl], s->surface, attrib_list);
1469 }
1470 return result;
1471}
1472
1473EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1474{
1475 EGLBoolean result = EGL_FALSE;
1476 if (!validate_display_surface(dpy, surface))
1477 return result;
1478
1479 egl_display_t const * const dp = get_display(dpy);
1480 egl_surface_t const * const s = get_surface(surface);
1481
1482 if (s->cnx->hooks->egl.eglUnlockSurfaceKHR) {
1483 result = s->cnx->hooks->egl.eglUnlockSurfaceKHR(
1484 dp->dpys[s->impl], s->surface);
1485 }
1486 return result;
1487}
1488
1489EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1490 EGLClientBuffer buffer, const EGLint *attrib_list)
1491{
1492 if (ctx != EGL_NO_CONTEXT) {
1493 if (!validate_display_context(dpy, ctx))
1494 return EGL_NO_IMAGE_KHR;
1495 egl_display_t const * const dp = get_display(dpy);
1496 egl_context_t * const c = get_context(ctx);
1497 // since we have an EGLContext, we know which implementation to use
1498 EGLImageKHR image = c->cnx->hooks->egl.eglCreateImageKHR(
1499 dp->dpys[c->impl], c->context, target, buffer, attrib_list);
1500 if (image == EGL_NO_IMAGE_KHR)
1501 return image;
1502
1503 egl_image_t* result = new egl_image_t(dpy, ctx);
1504 result->images[c->impl] = image;
1505 return (EGLImageKHR)result;
1506 } else {
1507 // EGL_NO_CONTEXT is a valid parameter
1508 egl_display_t const * const dp = get_display(dpy);
1509 if (dp == 0) {
1510 return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1511 }
1512 // since we don't have a way to know which implementation to call,
1513 // we're calling all of them
1514
1515 EGLImageKHR implImages[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
1516 bool success = false;
1517 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1518 egl_connection_t* const cnx = &gEGLImpl[i];
1519 implImages[i] = EGL_NO_IMAGE_KHR;
1520 if (cnx->dso) {
1521 if (cnx->hooks->egl.eglCreateImageKHR) {
1522 implImages[i] = cnx->hooks->egl.eglCreateImageKHR(
1523 dp->dpys[i], ctx, target, buffer, attrib_list);
1524 if (implImages[i] != EGL_NO_IMAGE_KHR) {
1525 success = true;
1526 }
1527 }
1528 }
1529 }
1530 if (!success)
1531 return EGL_NO_IMAGE_KHR;
1532
1533 egl_image_t* result = new egl_image_t(dpy, ctx);
1534 memcpy(result->images, implImages, sizeof(implImages));
1535 return (EGLImageKHR)result;
1536 }
1537}
1538
1539EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1540{
1541 egl_display_t const * const dp = get_display(dpy);
1542 if (dp == 0) {
1543 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1544 }
1545
1546 egl_image_t* image = get_image(img);
1547 if (!image->isValid()) {
1548 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1549 }
1550
1551 bool success = false;
1552 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1553 egl_connection_t* const cnx = &gEGLImpl[i];
1554 if (image->images[i] != EGL_NO_IMAGE_KHR) {
1555 if (cnx->dso) {
1556 if (cnx->hooks->egl.eglCreateImageKHR) {
1557 if (cnx->hooks->egl.eglDestroyImageKHR(
1558 dp->dpys[i], image->images[i])) {
1559 success = true;
1560 }
1561 }
1562 }
1563 }
1564 }
1565 if (!success)
1566 return EGL_FALSE;
1567
1568 delete image;
1569
1570 return EGL_FALSE;
1571}
Mathias Agopian2e20bff2009-05-04 19:29:25 -07001572
1573
1574// ----------------------------------------------------------------------------
1575// ANDROID extensions
1576// ----------------------------------------------------------------------------
1577
1578EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1579 EGLint left, EGLint top, EGLint width, EGLint height)
1580{
1581 if (!validate_display_surface(dpy, draw))
1582 return EGL_FALSE;
1583 egl_display_t const * const dp = get_display(dpy);
1584 egl_surface_t const * const s = get_surface(draw);
1585 if (s->cnx->hooks->egl.eglSetSwapRectangleANDROID) {
1586 return s->cnx->hooks->egl.eglSetSwapRectangleANDROID(dp->dpys[s->impl],
1587 s->surface, left, top, width, height);
1588 }
1589 return EGL_FALSE;
1590}
1591