blob: 2493fc67ee22663fc66ed723afd8b8669b407f1f [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>
Mathias Agopiand8fb7b52009-05-17 18:50:16 -070018#include <stdlib.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080019#include <string.h>
20#include <errno.h>
21#include <dlfcn.h>
22
23#include <sys/ioctl.h>
24
25#if HAVE_ANDROID_OS
26#include <linux/android_pmem.h>
27#endif
28
29#include <EGL/egl.h>
30#include <EGL/eglext.h>
31#include <GLES/gl.h>
32#include <GLES/glext.h>
33
34#include <cutils/log.h>
35#include <cutils/atomic.h>
36#include <cutils/properties.h>
37#include <cutils/memory.h>
38
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080039#include "hooks.h"
40#include "egl_impl.h"
41
42
43#define MAKE_CONFIG(_impl, _index) ((EGLConfig)(((_impl)<<24) | (_index)))
44#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
45
46// ----------------------------------------------------------------------------
47namespace android {
48// ----------------------------------------------------------------------------
49
50#define VERSION_MAJOR 1
51#define VERSION_MINOR 4
52static char const * const gVendorString = "Android";
53static char const * const gVersionString = "1.31 Android META-EGL";
54static char const * const gClientApiString = "OpenGL ES";
Mathias Agopian076b1cc2009-04-10 14:24:30 -070055static char const * const gExtensionString =
56 "EGL_KHR_image "
Mathias Agopiane6bf8b32009-05-06 23:47:08 -070057 "EGL_KHR_image_base "
58 "EGL_KHR_image_pixmap "
Mathias Agopian076b1cc2009-04-10 14:24:30 -070059 "EGL_ANDROID_image_native_buffer "
Mathias Agopiandf3ca302009-05-04 19:29:25 -070060 "EGL_ANDROID_swap_rectangle "
Mathias Agopian076b1cc2009-04-10 14:24:30 -070061 ;
62
63// ----------------------------------------------------------------------------
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080064
65template <int MAGIC>
66struct egl_object_t
67{
68 egl_object_t() : magic(MAGIC) { }
69 ~egl_object_t() { magic = 0; }
70 bool isValid() const { return magic == MAGIC; }
71private:
72 uint32_t magic;
73};
74
75struct egl_display_t : public egl_object_t<'_dpy'>
76{
Mathias Agopian076b1cc2009-04-10 14:24:30 -070077 EGLDisplay dpys[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
78 EGLConfig* configs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
79 EGLint numConfigs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080080 EGLint numTotalConfigs;
81 char const* extensionsString;
82 volatile int32_t refs;
83 struct strings_t {
84 char const * vendor;
85 char const * version;
86 char const * clientApi;
87 char const * extensions;
88 };
Mathias Agopian076b1cc2009-04-10 14:24:30 -070089 strings_t queryString[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080090};
91
92struct egl_surface_t : public egl_object_t<'_srf'>
93{
94 egl_surface_t(EGLDisplay dpy, EGLSurface surface,
Mathias Agopian076b1cc2009-04-10 14:24:30 -070095 int impl, egl_connection_t const* cnx)
96 : dpy(dpy), surface(surface), impl(impl), cnx(cnx)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080097 {
98 // NOTE: window must be incRef'ed and connected already
99 }
100 ~egl_surface_t() {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800101 }
102 EGLDisplay dpy;
103 EGLSurface surface;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800104 int impl;
105 egl_connection_t const* cnx;
106};
107
108struct egl_context_t : public egl_object_t<'_ctx'>
109{
110 egl_context_t(EGLDisplay dpy, EGLContext context,
111 int impl, egl_connection_t const* cnx)
112 : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
113 {
114 }
115 EGLDisplay dpy;
116 EGLContext context;
117 EGLSurface read;
118 EGLSurface draw;
119 int impl;
120 egl_connection_t const* cnx;
121};
122
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700123struct egl_image_t : public egl_object_t<'_img'>
124{
125 egl_image_t(EGLDisplay dpy, EGLContext context)
126 : dpy(dpy), context(context)
127 {
128 memset(images, 0, sizeof(images));
129 }
130 EGLDisplay dpy;
131 EGLConfig context;
132 EGLImageKHR images[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
133};
134
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800135struct tls_t
136{
137 tls_t() : error(EGL_SUCCESS), ctx(0) { }
138 EGLint error;
139 EGLContext ctx;
140};
141
142static void gl_unimplemented() {
143 LOGE("called unimplemented OpenGL ES API");
144}
145
146// ----------------------------------------------------------------------------
147// GL / EGL hooks
148// ----------------------------------------------------------------------------
149
150#undef GL_ENTRY
151#undef EGL_ENTRY
152#define GL_ENTRY(_r, _api, ...) #_api,
153#define EGL_ENTRY(_r, _api, ...) #_api,
154
155static char const * const gl_names[] = {
156 #include "gl_entries.in"
Mathias Agopianb519abb2009-04-23 18:05:44 -0700157 #include "glext_entries.in"
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800158 NULL
159};
160
161static char const * const egl_names[] = {
162 #include "egl_entries.in"
163 NULL
164};
165
166#undef GL_ENTRY
167#undef EGL_ENTRY
168
169// ----------------------------------------------------------------------------
170
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700171egl_connection_t gEGLImpl[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800172static egl_display_t gDisplay[NUM_DISPLAYS];
173static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
174static pthread_key_t gEGLThreadLocalStorageKey = -1;
175
176// ----------------------------------------------------------------------------
177
Mathias Agopianeccc8cf2009-05-13 00:19:22 -0700178EGLAPI gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
179EGLAPI pthread_key_t gGLWrapperKey = -1;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800180
181// ----------------------------------------------------------------------------
182
183static __attribute__((noinline))
184const char *egl_strerror(EGLint err)
185{
186 switch (err){
187 case EGL_SUCCESS: return "EGL_SUCCESS";
188 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
189 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
190 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
191 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
192 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
193 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
194 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
195 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
196 case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
197 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
198 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
199 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
200 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
201 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
202 default: return "UNKNOWN";
203 }
204}
205
206static __attribute__((noinline))
207void clearTLS() {
208 if (gEGLThreadLocalStorageKey != -1) {
209 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
210 if (tls) {
211 delete tls;
212 pthread_setspecific(gEGLThreadLocalStorageKey, 0);
213 }
214 }
215}
216
217static tls_t* getTLS()
218{
219 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
220 if (tls == 0) {
221 tls = new tls_t;
222 pthread_setspecific(gEGLThreadLocalStorageKey, tls);
223 }
224 return tls;
225}
226
227template<typename T>
228static __attribute__((noinline))
229T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
230 if (gEGLThreadLocalStorageKey == -1) {
231 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
232 if (gEGLThreadLocalStorageKey == -1)
233 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
234 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
235 }
236 tls_t* tls = getTLS();
237 if (tls->error != error) {
238 LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
239 tls->error = error;
240 }
241 return returnValue;
242}
243
244static __attribute__((noinline))
245GLint getError() {
246 if (gEGLThreadLocalStorageKey == -1)
247 return EGL_SUCCESS;
248 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
249 if (!tls) return EGL_SUCCESS;
250 GLint error = tls->error;
251 tls->error = EGL_SUCCESS;
252 return error;
253}
254
255static __attribute__((noinline))
256void setContext(EGLContext ctx) {
257 if (gEGLThreadLocalStorageKey == -1) {
258 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
259 if (gEGLThreadLocalStorageKey == -1)
260 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
261 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
262 }
263 tls_t* tls = getTLS();
264 tls->ctx = ctx;
265}
266
267static __attribute__((noinline))
268EGLContext getContext() {
269 if (gEGLThreadLocalStorageKey == -1)
270 return EGL_NO_CONTEXT;
271 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
272 if (!tls) return EGL_NO_CONTEXT;
273 return tls->ctx;
274}
275
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800276/*****************************************************************************/
277
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800278static __attribute__((noinline))
279void *load_driver(const char* driver, gl_hooks_t* hooks)
280{
Mathias Agopian1c2be6a2009-04-23 19:57:10 -0700281 //LOGD("%s", driver);
282 char scrap[256];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800283 void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
284 LOGE_IF(!dso,
285 "couldn't load <%s> library (%s)",
286 driver, dlerror());
287
288 if (dso) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700289 // first find the symbol for eglGetProcAddress
290
291 typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
292 const char*);
293
294 getProcAddressType getProcAddress =
295 (getProcAddressType)dlsym(dso, "eglGetProcAddress");
296
297 LOGE_IF(!getProcAddress,
298 "can't find eglGetProcAddress() in %s", driver);
299
300 __eglMustCastToProperFunctionPointerType* curr;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800301 char const * const * api;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700302
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800303 gl_hooks_t::egl_t* egl = &hooks->egl;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700304 curr = (__eglMustCastToProperFunctionPointerType*)egl;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800305 api = egl_names;
306 while (*api) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700307 char const * name = *api;
308 __eglMustCastToProperFunctionPointerType f =
309 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800310 if (f == NULL) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700311 // couldn't find the entry-point, use eglGetProcAddress()
312 f = getProcAddress(name);
313 if (f == NULL) {
314 f = (__eglMustCastToProperFunctionPointerType)0;
315 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800316 }
317 *curr++ = f;
318 api++;
319 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700320 gl_hooks_t::gl_t* gl = &hooks->gl;
321 curr = (__eglMustCastToProperFunctionPointerType*)gl;
322 api = gl_names;
323 while (*api) {
324 char const * name = *api;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700325 __eglMustCastToProperFunctionPointerType f =
326 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
327 if (f == NULL) {
328 // couldn't find the entry-point, use eglGetProcAddress()
329 f = getProcAddress(name);
Mathias Agopian1c2be6a2009-04-23 19:57:10 -0700330 }
331 if (f == NULL) {
332 // Try without the OES postfix
333 ssize_t index = ssize_t(strlen(name)) - 3;
334 if ((index>0 && (index<255)) && (!strcmp(name+index, "OES"))) {
335 strncpy(scrap, name, index);
336 scrap[index] = 0;
337 f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
338 //LOGD_IF(f, "found <%s> instead", scrap);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700339 }
340 }
Mathias Agopian1c2be6a2009-04-23 19:57:10 -0700341 if (f == NULL) {
342 // Try with the OES postfix
343 ssize_t index = ssize_t(strlen(name)) - 3;
344 if ((index>0 && (index<252)) && (strcmp(name+index, "OES"))) {
345 strncpy(scrap, name, index);
346 scrap[index] = 0;
347 strcat(scrap, "OES");
348 f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
349 //LOGD_IF(f, "found <%s> instead", scrap);
350 }
351 }
352 if (f == NULL) {
Mathias Agopian3d881792009-04-24 18:16:44 -0700353 //LOGD("%s", name);
Mathias Agopian1c2be6a2009-04-23 19:57:10 -0700354 f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
355 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700356 *curr++ = f;
357 api++;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800358 }
359 }
360 return dso;
361}
362
363template<typename T>
364static __attribute__((noinline))
365int binarySearch(
366 T const sortedArray[], int first, int last, T key)
367{
368 while (first <= last) {
369 int mid = (first + last) / 2;
370 if (key > sortedArray[mid]) {
371 first = mid + 1;
372 } else if (key < sortedArray[mid]) {
373 last = mid - 1;
374 } else {
375 return mid;
376 }
377 }
378 return -1;
379}
380
381static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
382{
383 // NOTE: this mapping works only if we have no more than two EGLimpl
384 return (i>0 ? dp->numConfigs[0] : 0) + index;
385}
386
387static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
388 int& i, int& index)
389{
390 // NOTE: this mapping works only if we have no more than two EGLimpl
391 size_t numConfigs = dp->numConfigs[0];
392 i = configId / numConfigs;
393 index = configId % numConfigs;
394}
395
396static int cmp_configs(const void* a, const void *b)
397{
398 EGLConfig c0 = *(EGLConfig const *)a;
399 EGLConfig c1 = *(EGLConfig const *)b;
400 return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
401}
402
403struct extention_map_t {
404 const char* name;
405 __eglMustCastToProperFunctionPointerType address;
406};
407
408static const extention_map_t gExtentionMap[] = {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700409 { "eglLockSurfaceKHR",
410 (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
411 { "eglUnlockSurfaceKHR",
412 (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
413 { "eglCreateImageKHR",
414 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
415 { "eglDestroyImageKHR",
416 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800417};
418
419static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
420
421static void(*findProcAddress(const char* name,
422 const extention_map_t* map, size_t n))()
423{
424 for (uint32_t i=0 ; i<n ; i++) {
425 if (!strcmp(name, map[i].name)) {
426 return map[i].address;
427 }
428 }
429 return NULL;
430}
431
432// ----------------------------------------------------------------------------
433
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700434/*
435 * To "loose" the GPU, use something like
436 * gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_CONTEXT_LOST];
437 *
438 */
439
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800440static int gl_context_lost() {
441 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
442 return 0;
443}
444static int egl_context_lost() {
445 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
446 return EGL_FALSE;
447}
448static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
449 usleep(100000); // don't use all the CPU
450 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
451 return EGL_FALSE;
452}
453static GLint egl_context_lost_get_error() {
454 return EGL_CONTEXT_LOST;
455}
456static int ext_context_lost() {
457 return 0;
458}
459
460static void gl_no_context() {
461 LOGE("call to OpenGL ES API with no current context");
462}
463static void early_egl_init(void)
464{
465#if !USE_FAST_TLS_KEY
466 pthread_key_create(&gGLWrapperKey, NULL);
467#endif
468 uint32_t addr = (uint32_t)((void*)gl_no_context);
469 android_memset32(
470 (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT],
471 addr,
472 sizeof(gHooks[IMPL_NO_CONTEXT]));
473 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
474}
475
476static pthread_once_t once_control = PTHREAD_ONCE_INIT;
477static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
478
479
480static inline
481egl_display_t* get_display(EGLDisplay dpy)
482{
483 uintptr_t index = uintptr_t(dpy)-1U;
484 return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
485}
486
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700487template<typename NATIVE, typename EGL>
488static inline NATIVE* egl_to_native_cast(EGL arg) {
489 return reinterpret_cast<NATIVE*>(arg);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800490}
491
492static inline
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700493egl_surface_t* get_surface(EGLSurface surface) {
494 return egl_to_native_cast<egl_surface_t>(surface);
495}
496
497static inline
498egl_context_t* get_context(EGLContext context) {
499 return egl_to_native_cast<egl_context_t>(context);
500}
501
502static inline
503egl_image_t* get_image(EGLImageKHR image) {
504 return egl_to_native_cast<egl_image_t>(image);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800505}
506
507static egl_connection_t* validate_display_config(
508 EGLDisplay dpy, EGLConfig config,
509 egl_display_t const*& dp, int& impl, int& index)
510{
511 dp = get_display(dpy);
512 if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
513
514 impl = uintptr_t(config)>>24;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700515 if (uint32_t(impl) >= IMPL_NUM_DRIVERS_IMPLEMENTATIONS) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800516 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
517 }
518 index = uintptr_t(config) & 0xFFFFFF;
519 if (index >= dp->numConfigs[impl]) {
520 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
521 }
522 egl_connection_t* const cnx = &gEGLImpl[impl];
523 if (cnx->dso == 0) {
524 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
525 }
526 return cnx;
527}
528
529static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
530{
531 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
532 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
533 if (!get_display(dpy)->isValid())
534 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
535 if (!ctx) // TODO: make sure context is a valid object
536 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
537 if (!get_context(ctx)->isValid())
538 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
539 return EGL_TRUE;
540}
541
542static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
543{
544 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
545 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
546 if (!get_display(dpy)->isValid())
547 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
548 if (!surface) // TODO: make sure surface is a valid object
549 return setError(EGL_BAD_SURFACE, EGL_FALSE);
550 if (!get_surface(surface)->isValid())
551 return setError(EGL_BAD_SURFACE, EGL_FALSE);
552 return EGL_TRUE;
553}
554
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800555
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700556EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
557{
558 EGLContext context = getContext();
559 if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
560 return EGL_NO_IMAGE_KHR;
561
562 egl_context_t const * const c = get_context(context);
563 if (!c->isValid())
564 return EGL_NO_IMAGE_KHR;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800565
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700566 egl_image_t const * const i = get_image(image);
567 if (!i->isValid())
568 return EGL_NO_IMAGE_KHR;
569
570 return i->images[c->impl];
571}
572
573
574EGLDisplay egl_init_displays(NativeDisplayType display)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800575{
576 if (sEarlyInitState) {
577 return EGL_NO_DISPLAY;
578 }
579
580 uint32_t index = uint32_t(display);
581 if (index >= NUM_DISPLAYS) {
582 return EGL_NO_DISPLAY;
583 }
584
585 EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
586 egl_display_t* d = &gDisplay[index];
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700587
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800588 // dynamically load all our EGL implementations for that display
589 // and call into the real eglGetGisplay()
590 egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
591 if (cnx->dso == 0) {
592 cnx->hooks = &gHooks[IMPL_SOFTWARE];
593 cnx->dso = load_driver("libagl.so", cnx->hooks);
594 }
595 if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
596 d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
597 LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
598 "No EGLDisplay for software EGL!");
599 }
600
601 cnx = &gEGLImpl[IMPL_HARDWARE];
602 if (cnx->dso == 0 && cnx->unavailable == 0) {
603 char value[PROPERTY_VALUE_MAX];
604 property_get("debug.egl.hw", value, "1");
605 if (atoi(value) != 0) {
606 cnx->hooks = &gHooks[IMPL_HARDWARE];
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700607 cnx->dso = load_driver("libhgl2.so", cnx->hooks);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800608 } else {
609 LOGD("3D hardware acceleration is disabled");
610 }
611 }
612 if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
613 android_memset32(
614 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
615 (uint32_t)((void*)gl_context_lost),
616 sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
617 android_memset32(
618 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
619 (uint32_t)((void*)egl_context_lost),
620 sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
621 android_memset32(
622 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
623 (uint32_t)((void*)ext_context_lost),
624 sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
625
626 gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
627 egl_context_lost_swap_buffers;
628
629 gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
630 egl_context_lost_get_error;
631
632 gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
633 gHooks[IMPL_HARDWARE].egl.eglTerminate;
634
635 d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
636 if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
637 LOGE("h/w accelerated eglGetDisplay() failed (%s)",
638 egl_strerror(cnx->hooks->egl.eglGetError()));
639 dlclose((void*)cnx->dso);
640 cnx->dso = 0;
641 // in case of failure, we want to make sure we don't try again
642 // as it's expensive.
643 cnx->unavailable = 1;
644 }
645 }
646
647 return dpy;
648}
649
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700650
651// ----------------------------------------------------------------------------
652}; // namespace android
653// ----------------------------------------------------------------------------
654
655using namespace android;
656
657EGLDisplay eglGetDisplay(NativeDisplayType display)
658{
659 return egl_init_displays(display);
660}
661
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800662// ----------------------------------------------------------------------------
663// Initialization
664// ----------------------------------------------------------------------------
665
666EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
667{
668 egl_display_t * const dp = get_display(dpy);
669 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
670
671 if (android_atomic_inc(&dp->refs) > 0) {
672 if (major != NULL) *major = VERSION_MAJOR;
673 if (minor != NULL) *minor = VERSION_MINOR;
674 return EGL_TRUE;
675 }
676
677 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
678
679 // initialize each EGL and
680 // build our own extension string first, based on the extension we know
681 // and the extension supported by our client implementation
682 dp->extensionsString = strdup(gExtensionString);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700683 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800684 egl_connection_t* const cnx = &gEGLImpl[i];
685 cnx->major = -1;
686 cnx->minor = -1;
687 if (!cnx->dso)
688 continue;
689
690 if (cnx->hooks->egl.eglInitialize(
691 dp->dpys[i], &cnx->major, &cnx->minor)) {
692
693 //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
694 // i, dp->dpys[i], cnx->major, cnx->minor, cnx);
695
696 // get the query-strings for this display for each implementation
697 dp->queryString[i].vendor =
698 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
699 dp->queryString[i].version =
700 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
701 dp->queryString[i].extensions = strdup(
702 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
703 dp->queryString[i].clientApi =
704 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
705
706 } else {
707 LOGD("%d: eglInitialize() failed (%s)",
708 i, egl_strerror(cnx->hooks->egl.eglGetError()));
709 }
710 }
711
712 EGLBoolean res = EGL_FALSE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700713 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800714 egl_connection_t* const cnx = &gEGLImpl[i];
715 if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
716 EGLint n;
717 if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
718 dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
719 if (dp->configs[i]) {
720 if (cnx->hooks->egl.eglGetConfigs(
721 dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
722 {
723 // sort the configurations so we can do binary searches
724 qsort( dp->configs[i],
725 dp->numConfigs[i],
726 sizeof(EGLConfig), cmp_configs);
727
728 dp->numTotalConfigs += n;
729 res = EGL_TRUE;
730 }
731 }
732 }
733 }
734 }
735
736 if (res == EGL_TRUE) {
737 if (major != NULL) *major = VERSION_MAJOR;
738 if (minor != NULL) *minor = VERSION_MINOR;
739 return EGL_TRUE;
740 }
741 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
742}
743
744EGLBoolean eglTerminate(EGLDisplay dpy)
745{
746 egl_display_t* const dp = get_display(dpy);
747 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
748 if (android_atomic_dec(&dp->refs) != 1)
749 return EGL_TRUE;
750
751 EGLBoolean res = EGL_FALSE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700752 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800753 egl_connection_t* const cnx = &gEGLImpl[i];
754 if (cnx->dso) {
755 cnx->hooks->egl.eglTerminate(dp->dpys[i]);
756
757 /* REVISIT: it's unclear what to do if eglTerminate() fails,
758 * on one end we shouldn't care, on the other end if it fails
759 * it might not be safe to call dlclose() (there could be some
760 * threads around). */
761
762 free(dp->configs[i]);
763 free((void*)dp->queryString[i].extensions);
764 dp->numConfigs[i] = 0;
765 dp->dpys[i] = EGL_NO_DISPLAY;
766 dlclose((void*)cnx->dso);
767 cnx->dso = 0;
768 res = EGL_TRUE;
769 }
770 }
771 free((void*)dp->extensionsString);
772 dp->extensionsString = 0;
773 dp->numTotalConfigs = 0;
774 clearTLS();
775 return res;
776}
777
778// ----------------------------------------------------------------------------
779// configuration
780// ----------------------------------------------------------------------------
781
782EGLBoolean eglGetConfigs( EGLDisplay dpy,
783 EGLConfig *configs,
784 EGLint config_size, EGLint *num_config)
785{
786 egl_display_t const * const dp = get_display(dpy);
787 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
788
789 GLint numConfigs = dp->numTotalConfigs;
790 if (!configs) {
791 *num_config = numConfigs;
792 return EGL_TRUE;
793 }
794 GLint n = 0;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700795 for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800796 for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
797 *configs++ = MAKE_CONFIG(j, i);
798 config_size--;
799 n++;
800 }
801 }
802
803 *num_config = n;
804 return EGL_TRUE;
805}
806
807EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
808 EGLConfig *configs, EGLint config_size,
809 EGLint *num_config)
810{
811 egl_display_t const * const dp = get_display(dpy);
812 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
813
Jack Palevich749c63d2009-03-25 15:12:17 -0700814 if (num_config==0) {
815 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800816 }
817
818 EGLint n;
819 EGLBoolean res = EGL_FALSE;
820 *num_config = 0;
821
822
823 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
824 // to do this, we have to go through the attrib_list array once
825 // to figure out both its size and if it contains an EGL_CONFIG_ID
826 // key. If so, the full array is copied and patched.
827 // NOTE: we assume that there can be only one occurrence
828 // of EGL_CONFIG_ID.
829
830 EGLint patch_index = -1;
831 GLint attr;
832 size_t size = 0;
833 while ((attr=attrib_list[size])) {
834 if (attr == EGL_CONFIG_ID)
835 patch_index = size;
836 size += 2;
837 }
838 if (patch_index >= 0) {
839 size += 2; // we need copy the sentinel as well
840 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
841 if (new_list == 0)
842 return setError(EGL_BAD_ALLOC, EGL_FALSE);
843 memcpy(new_list, attrib_list, size*sizeof(EGLint));
844
845 // patch the requested EGL_CONFIG_ID
846 int i, index;
847 EGLint& configId(new_list[patch_index+1]);
848 uniqueIdToConfig(dp, configId, i, index);
849
850 egl_connection_t* const cnx = &gEGLImpl[i];
851 if (cnx->dso) {
852 cnx->hooks->egl.eglGetConfigAttrib(
853 dp->dpys[i], dp->configs[i][index],
854 EGL_CONFIG_ID, &configId);
855
856 // and switch to the new list
857 attrib_list = const_cast<const EGLint *>(new_list);
858
859 // At this point, the only configuration that can match is
860 // dp->configs[i][index], however, we don't know if it would be
861 // rejected because of the other attributes, so we do have to call
862 // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
863 // through all the EGLimpl[].
864 // We also know we can only get a single config back, and we know
865 // which one.
866
867 res = cnx->hooks->egl.eglChooseConfig(
868 dp->dpys[i], attrib_list, configs, config_size, &n);
869 if (res && n>0) {
870 // n has to be 0 or 1, by construction, and we already know
871 // which config it will return (since there can be only one).
Jack Palevich749c63d2009-03-25 15:12:17 -0700872 if (configs) {
873 configs[0] = MAKE_CONFIG(i, index);
874 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800875 *num_config = 1;
876 }
877 }
878
879 free(const_cast<EGLint *>(attrib_list));
880 return res;
881 }
882
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700883 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800884 egl_connection_t* const cnx = &gEGLImpl[i];
885 if (cnx->dso) {
886 if (cnx->hooks->egl.eglChooseConfig(
887 dp->dpys[i], attrib_list, configs, config_size, &n)) {
Jack Palevich749c63d2009-03-25 15:12:17 -0700888 if (configs) {
889 // now we need to convert these client EGLConfig to our
890 // internal EGLConfig format. This is done in O(n log n).
891 for (int j=0 ; j<n ; j++) {
892 int index = binarySearch<EGLConfig>(
893 dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
894 if (index >= 0) {
895 if (configs) {
896 configs[j] = MAKE_CONFIG(i, index);
897 }
898 } else {
899 return setError(EGL_BAD_CONFIG, EGL_FALSE);
900 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800901 }
Jack Palevich749c63d2009-03-25 15:12:17 -0700902 configs += n;
903 config_size -= n;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800904 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800905 *num_config += n;
906 res = EGL_TRUE;
907 }
908 }
909 }
910 return res;
911}
912
913EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
914 EGLint attribute, EGLint *value)
915{
916 egl_display_t const* dp = 0;
917 int i=0, index=0;
918 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
919 if (!cnx) return EGL_FALSE;
920
921 if (attribute == EGL_CONFIG_ID) {
922 // EGL_CONFIG_IDs must be unique, just use the order of the selected
923 // EGLConfig.
924 *value = configToUniqueId(dp, i, index);
925 return EGL_TRUE;
926 }
927 return cnx->hooks->egl.eglGetConfigAttrib(
928 dp->dpys[i], dp->configs[i][index], attribute, value);
929}
930
931// ----------------------------------------------------------------------------
932// surfaces
933// ----------------------------------------------------------------------------
934
935EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
936 NativeWindowType window,
937 const EGLint *attrib_list)
938{
939 egl_display_t const* dp = 0;
940 int i=0, index=0;
941 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
942 if (cnx) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800943 EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
944 dp->dpys[i], dp->configs[i][index], window, attrib_list);
945 if (surface != EGL_NO_SURFACE) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700946 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800947 return s;
948 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800949 }
950 return EGL_NO_SURFACE;
951}
952
953EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
954 NativePixmapType pixmap,
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.eglCreatePixmapSurface(
962 dp->dpys[i], dp->configs[i][index], pixmap, 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
971EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
972 const EGLint *attrib_list)
973{
974 egl_display_t const* dp = 0;
975 int i=0, index=0;
976 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
977 if (cnx) {
978 EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
979 dp->dpys[i], dp->configs[i][index], attrib_list);
980 if (surface != EGL_NO_SURFACE) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700981 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800982 return s;
983 }
984 }
985 return EGL_NO_SURFACE;
986}
987
988EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
989{
990 if (!validate_display_surface(dpy, surface))
991 return EGL_FALSE;
992 egl_display_t const * const dp = get_display(dpy);
993 egl_surface_t const * const s = get_surface(surface);
994
995 EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
996 dp->dpys[s->impl], s->surface);
997
998 delete s;
999 return result;
1000}
1001
1002EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
1003 EGLint attribute, EGLint *value)
1004{
1005 if (!validate_display_surface(dpy, surface))
1006 return EGL_FALSE;
1007 egl_display_t const * const dp = get_display(dpy);
1008 egl_surface_t const * const s = get_surface(surface);
1009
1010 return s->cnx->hooks->egl.eglQuerySurface(
1011 dp->dpys[s->impl], s->surface, attribute, value);
1012}
1013
1014// ----------------------------------------------------------------------------
1015// contextes
1016// ----------------------------------------------------------------------------
1017
1018EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1019 EGLContext share_list, const EGLint *attrib_list)
1020{
1021 egl_display_t const* dp = 0;
1022 int i=0, index=0;
1023 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1024 if (cnx) {
1025 EGLContext context = cnx->hooks->egl.eglCreateContext(
1026 dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
1027 if (context != EGL_NO_CONTEXT) {
1028 egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
1029 return c;
1030 }
1031 }
1032 return EGL_NO_CONTEXT;
1033}
1034
1035EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1036{
1037 if (!validate_display_context(dpy, ctx))
1038 return EGL_FALSE;
1039 egl_display_t const * const dp = get_display(dpy);
1040 egl_context_t * const c = get_context(ctx);
1041 EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
1042 dp->dpys[c->impl], c->context);
1043 delete c;
1044 return result;
1045}
1046
1047EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
1048 EGLSurface read, EGLContext ctx)
1049{
1050 egl_display_t const * const dp = get_display(dpy);
1051 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1052
1053 if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
1054 ctx == EGL_NO_CONTEXT)
1055 {
1056 EGLBoolean result = EGL_TRUE;
1057 ctx = getContext();
1058 if (ctx) {
1059 egl_context_t * const c = get_context(ctx);
1060 result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
1061 if (result == EGL_TRUE) {
1062 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
1063 setContext(EGL_NO_CONTEXT);
1064 }
1065 }
1066 return result;
1067 }
1068
1069 if (!validate_display_context(dpy, ctx))
1070 return EGL_FALSE;
1071
1072 egl_context_t * const c = get_context(ctx);
1073 if (draw != EGL_NO_SURFACE) {
1074 egl_surface_t const * d = get_surface(draw);
1075 if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1076 if (d->impl != c->impl)
1077 return setError(EGL_BAD_MATCH, EGL_FALSE);
1078 draw = d->surface;
1079 }
1080 if (read != EGL_NO_SURFACE) {
1081 egl_surface_t const * r = get_surface(read);
1082 if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1083 if (r->impl != c->impl)
1084 return setError(EGL_BAD_MATCH, EGL_FALSE);
1085 read = r->surface;
1086 }
1087 EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
1088 dp->dpys[c->impl], draw, read, c->context);
1089
1090 if (result == EGL_TRUE) {
1091 setGlThreadSpecific(c->cnx->hooks);
1092 setContext(ctx);
1093 c->read = read;
1094 c->draw = draw;
1095 }
1096 return result;
1097}
1098
1099
1100EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1101 EGLint attribute, EGLint *value)
1102{
1103 if (!validate_display_context(dpy, ctx))
1104 return EGL_FALSE;
1105
1106 egl_display_t const * const dp = get_display(dpy);
1107 egl_context_t * const c = get_context(ctx);
1108
1109 return c->cnx->hooks->egl.eglQueryContext(
1110 dp->dpys[c->impl], c->context, attribute, value);
1111}
1112
1113EGLContext eglGetCurrentContext(void)
1114{
1115 EGLContext ctx = getContext();
1116 return ctx;
1117}
1118
1119EGLSurface eglGetCurrentSurface(EGLint readdraw)
1120{
1121 EGLContext ctx = getContext();
1122 if (ctx) {
1123 egl_context_t const * const c = get_context(ctx);
1124 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1125 switch (readdraw) {
1126 case EGL_READ: return c->read;
1127 case EGL_DRAW: return c->draw;
1128 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1129 }
1130 }
1131 return EGL_NO_SURFACE;
1132}
1133
1134EGLDisplay eglGetCurrentDisplay(void)
1135{
1136 EGLContext ctx = getContext();
1137 if (ctx) {
1138 egl_context_t const * const c = get_context(ctx);
1139 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1140 return c->dpy;
1141 }
1142 return EGL_NO_DISPLAY;
1143}
1144
1145EGLBoolean eglWaitGL(void)
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.eglWaitGL();
1158 }
1159 return res;
1160}
1161
1162EGLBoolean eglWaitNative(EGLint engine)
1163{
1164 EGLBoolean res = EGL_TRUE;
1165 EGLContext ctx = getContext();
1166 if (ctx) {
1167 egl_context_t const * const c = get_context(ctx);
1168 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1169 if (uint32_t(c->impl)>=2)
1170 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1171 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1172 if (!cnx->dso)
1173 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1174 res = cnx->hooks->egl.eglWaitNative(engine);
1175 }
1176 return res;
1177}
1178
1179EGLint eglGetError(void)
1180{
1181 EGLint result = EGL_SUCCESS;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001182 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001183 EGLint err = EGL_SUCCESS;
1184 egl_connection_t* const cnx = &gEGLImpl[i];
1185 if (cnx->dso)
1186 err = cnx->hooks->egl.eglGetError();
1187 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1188 result = err;
1189 }
1190 if (result == EGL_SUCCESS)
1191 result = getError();
1192 return result;
1193}
1194
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001195__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001196{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001197 // eglGetProcAddress() could be the very first function called
1198 // in which case we must make sure we've initialized ourselves, this
1199 // happens the first time egl_get_display() is called.
1200
1201 if (egl_init_displays(EGL_DEFAULT_DISPLAY) == EGL_NO_DISPLAY)
1202 return NULL;
1203
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001204 __eglMustCastToProperFunctionPointerType addr;
1205 addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1206 if (addr) return addr;
1207
1208 return NULL; // TODO: finish implementation below
1209
1210 addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1211 if (addr) return addr;
1212
1213 addr = 0;
1214 int slot = -1;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001215 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001216 egl_connection_t* const cnx = &gEGLImpl[i];
1217 if (cnx->dso) {
1218 if (cnx->hooks->egl.eglGetProcAddress) {
1219 addr = cnx->hooks->egl.eglGetProcAddress(procname);
1220 if (addr) {
1221 if (slot == -1) {
1222 slot = 0; // XXX: find free slot
1223 if (slot == -1) {
1224 addr = 0;
1225 break;
1226 }
1227 }
1228 cnx->hooks->ext.extensions[slot] = addr;
1229 }
1230 }
1231 }
1232 }
1233
1234 if (slot >= 0) {
1235 addr = 0; // XXX: address of stub 'slot'
1236 gGLExtentionMap[slot].name = strdup(procname);
1237 gGLExtentionMap[slot].address = addr;
1238 }
1239
1240 return addr;
1241
1242
1243 /*
1244 * TODO: For OpenGL ES extensions, we must generate a stub
1245 * that looks like
1246 * mov r12, #0xFFFF0FFF
1247 * ldr r12, [r12, #-15]
1248 * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
1249 * mov r12, [r12, #api_offset]
1250 * ldrne pc, r12
1251 * mov pc, #unsupported_extension
1252 *
1253 * and write the address of the extension in *all*
1254 * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1255 *
1256 */
1257}
1258
1259EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1260{
1261 if (!validate_display_surface(dpy, draw))
1262 return EGL_FALSE;
1263 egl_display_t const * const dp = get_display(dpy);
1264 egl_surface_t const * const s = get_surface(draw);
1265 return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1266}
1267
1268EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1269 NativePixmapType target)
1270{
1271 if (!validate_display_surface(dpy, surface))
1272 return EGL_FALSE;
1273 egl_display_t const * const dp = get_display(dpy);
1274 egl_surface_t const * const s = get_surface(surface);
1275 return s->cnx->hooks->egl.eglCopyBuffers(
1276 dp->dpys[s->impl], s->surface, target);
1277}
1278
1279const char* eglQueryString(EGLDisplay dpy, EGLint name)
1280{
1281 egl_display_t const * const dp = get_display(dpy);
1282 switch (name) {
1283 case EGL_VENDOR:
1284 return gVendorString;
1285 case EGL_VERSION:
1286 return gVersionString;
1287 case EGL_EXTENSIONS:
1288 return gExtensionString;
1289 case EGL_CLIENT_APIS:
1290 return gClientApiString;
1291 }
1292 return setError(EGL_BAD_PARAMETER, (const char *)0);
1293}
1294
1295
1296// ----------------------------------------------------------------------------
1297// EGL 1.1
1298// ----------------------------------------------------------------------------
1299
1300EGLBoolean eglSurfaceAttrib(
1301 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1302{
1303 if (!validate_display_surface(dpy, surface))
1304 return EGL_FALSE;
1305 egl_display_t const * const dp = get_display(dpy);
1306 egl_surface_t const * const s = get_surface(surface);
1307 if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1308 return s->cnx->hooks->egl.eglSurfaceAttrib(
1309 dp->dpys[s->impl], s->surface, attribute, value);
1310 }
1311 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1312}
1313
1314EGLBoolean eglBindTexImage(
1315 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1316{
1317 if (!validate_display_surface(dpy, surface))
1318 return EGL_FALSE;
1319 egl_display_t const * const dp = get_display(dpy);
1320 egl_surface_t const * const s = get_surface(surface);
1321 if (s->cnx->hooks->egl.eglBindTexImage) {
1322 return s->cnx->hooks->egl.eglBindTexImage(
1323 dp->dpys[s->impl], s->surface, buffer);
1324 }
1325 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1326}
1327
1328EGLBoolean eglReleaseTexImage(
1329 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1330{
1331 if (!validate_display_surface(dpy, surface))
1332 return EGL_FALSE;
1333 egl_display_t const * const dp = get_display(dpy);
1334 egl_surface_t const * const s = get_surface(surface);
1335 if (s->cnx->hooks->egl.eglReleaseTexImage) {
1336 return s->cnx->hooks->egl.eglReleaseTexImage(
1337 dp->dpys[s->impl], s->surface, buffer);
1338 }
1339 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1340}
1341
1342EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1343{
1344 egl_display_t * const dp = get_display(dpy);
1345 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1346
1347 EGLBoolean res = EGL_TRUE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001348 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001349 egl_connection_t* const cnx = &gEGLImpl[i];
1350 if (cnx->dso) {
1351 if (cnx->hooks->egl.eglSwapInterval) {
1352 if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1353 res = EGL_FALSE;
1354 }
1355 }
1356 }
1357 }
1358 return res;
1359}
1360
1361
1362// ----------------------------------------------------------------------------
1363// EGL 1.2
1364// ----------------------------------------------------------------------------
1365
1366EGLBoolean eglWaitClient(void)
1367{
1368 EGLBoolean res = EGL_TRUE;
1369 EGLContext ctx = getContext();
1370 if (ctx) {
1371 egl_context_t const * const c = get_context(ctx);
1372 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1373 if (uint32_t(c->impl)>=2)
1374 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1375 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1376 if (!cnx->dso)
1377 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1378 if (cnx->hooks->egl.eglWaitClient) {
1379 res = cnx->hooks->egl.eglWaitClient();
1380 } else {
1381 res = cnx->hooks->egl.eglWaitGL();
1382 }
1383 }
1384 return res;
1385}
1386
1387EGLBoolean eglBindAPI(EGLenum api)
1388{
1389 // bind this API on all EGLs
1390 EGLBoolean res = EGL_TRUE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001391 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001392 egl_connection_t* const cnx = &gEGLImpl[i];
1393 if (cnx->dso) {
1394 if (cnx->hooks->egl.eglBindAPI) {
1395 if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1396 res = EGL_FALSE;
1397 }
1398 }
1399 }
1400 }
1401 return res;
1402}
1403
1404EGLenum eglQueryAPI(void)
1405{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001406 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001407 egl_connection_t* const cnx = &gEGLImpl[i];
1408 if (cnx->dso) {
1409 if (cnx->hooks->egl.eglQueryAPI) {
1410 // the first one we find is okay, because they all
1411 // should be the same
1412 return cnx->hooks->egl.eglQueryAPI();
1413 }
1414 }
1415 }
1416 // or, it can only be OpenGL ES
1417 return EGL_OPENGL_ES_API;
1418}
1419
1420EGLBoolean eglReleaseThread(void)
1421{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001422 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001423 egl_connection_t* const cnx = &gEGLImpl[i];
1424 if (cnx->dso) {
1425 if (cnx->hooks->egl.eglReleaseThread) {
1426 cnx->hooks->egl.eglReleaseThread();
1427 }
1428 }
1429 }
1430 clearTLS();
1431 return EGL_TRUE;
1432}
1433
1434EGLSurface eglCreatePbufferFromClientBuffer(
1435 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1436 EGLConfig config, const EGLint *attrib_list)
1437{
1438 egl_display_t const* dp = 0;
1439 int i=0, index=0;
1440 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1441 if (!cnx) return EGL_FALSE;
1442 if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1443 return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1444 dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1445 }
1446 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1447}
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001448
1449// ----------------------------------------------------------------------------
1450// EGL_EGLEXT_VERSION 3
1451// ----------------------------------------------------------------------------
1452
1453EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1454 const EGLint *attrib_list)
1455{
1456 EGLBoolean result = EGL_FALSE;
1457 if (!validate_display_surface(dpy, surface))
1458 return result;
1459
1460 egl_display_t const * const dp = get_display(dpy);
1461 egl_surface_t const * const s = get_surface(surface);
1462
1463 if (s->cnx->hooks->egl.eglLockSurfaceKHR) {
1464 result = s->cnx->hooks->egl.eglLockSurfaceKHR(
1465 dp->dpys[s->impl], s->surface, attrib_list);
1466 }
1467 return result;
1468}
1469
1470EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1471{
1472 EGLBoolean result = EGL_FALSE;
1473 if (!validate_display_surface(dpy, surface))
1474 return result;
1475
1476 egl_display_t const * const dp = get_display(dpy);
1477 egl_surface_t const * const s = get_surface(surface);
1478
1479 if (s->cnx->hooks->egl.eglUnlockSurfaceKHR) {
1480 result = s->cnx->hooks->egl.eglUnlockSurfaceKHR(
1481 dp->dpys[s->impl], s->surface);
1482 }
1483 return result;
1484}
1485
1486EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1487 EGLClientBuffer buffer, const EGLint *attrib_list)
1488{
1489 if (ctx != EGL_NO_CONTEXT) {
1490 if (!validate_display_context(dpy, ctx))
1491 return EGL_NO_IMAGE_KHR;
1492 egl_display_t const * const dp = get_display(dpy);
1493 egl_context_t * const c = get_context(ctx);
1494 // since we have an EGLContext, we know which implementation to use
1495 EGLImageKHR image = c->cnx->hooks->egl.eglCreateImageKHR(
1496 dp->dpys[c->impl], c->context, target, buffer, attrib_list);
1497 if (image == EGL_NO_IMAGE_KHR)
1498 return image;
1499
1500 egl_image_t* result = new egl_image_t(dpy, ctx);
1501 result->images[c->impl] = image;
1502 return (EGLImageKHR)result;
1503 } else {
1504 // EGL_NO_CONTEXT is a valid parameter
1505 egl_display_t const * const dp = get_display(dpy);
1506 if (dp == 0) {
1507 return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1508 }
1509 // since we don't have a way to know which implementation to call,
1510 // we're calling all of them
1511
1512 EGLImageKHR implImages[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
1513 bool success = false;
1514 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1515 egl_connection_t* const cnx = &gEGLImpl[i];
1516 implImages[i] = EGL_NO_IMAGE_KHR;
1517 if (cnx->dso) {
1518 if (cnx->hooks->egl.eglCreateImageKHR) {
1519 implImages[i] = cnx->hooks->egl.eglCreateImageKHR(
1520 dp->dpys[i], ctx, target, buffer, attrib_list);
1521 if (implImages[i] != EGL_NO_IMAGE_KHR) {
1522 success = true;
1523 }
1524 }
1525 }
1526 }
1527 if (!success)
1528 return EGL_NO_IMAGE_KHR;
1529
1530 egl_image_t* result = new egl_image_t(dpy, ctx);
1531 memcpy(result->images, implImages, sizeof(implImages));
1532 return (EGLImageKHR)result;
1533 }
1534}
1535
1536EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1537{
1538 egl_display_t const * const dp = get_display(dpy);
1539 if (dp == 0) {
1540 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1541 }
1542
1543 egl_image_t* image = get_image(img);
1544 if (!image->isValid()) {
1545 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1546 }
1547
1548 bool success = false;
1549 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1550 egl_connection_t* const cnx = &gEGLImpl[i];
1551 if (image->images[i] != EGL_NO_IMAGE_KHR) {
1552 if (cnx->dso) {
1553 if (cnx->hooks->egl.eglCreateImageKHR) {
1554 if (cnx->hooks->egl.eglDestroyImageKHR(
1555 dp->dpys[i], image->images[i])) {
1556 success = true;
1557 }
1558 }
1559 }
1560 }
1561 }
1562 if (!success)
1563 return EGL_FALSE;
1564
1565 delete image;
1566
1567 return EGL_FALSE;
1568}
Mathias Agopiandf3ca302009-05-04 19:29:25 -07001569
1570
1571// ----------------------------------------------------------------------------
1572// ANDROID extensions
1573// ----------------------------------------------------------------------------
1574
1575EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1576 EGLint left, EGLint top, EGLint width, EGLint height)
1577{
1578 if (!validate_display_surface(dpy, draw))
1579 return EGL_FALSE;
1580 egl_display_t const * const dp = get_display(dpy);
1581 egl_surface_t const * const s = get_surface(draw);
1582 if (s->cnx->hooks->egl.eglSetSwapRectangleANDROID) {
1583 return s->cnx->hooks->egl.eglSetSwapRectangleANDROID(dp->dpys[s->impl],
1584 s->surface, left, top, width, height);
1585 }
1586 return EGL_FALSE;
1587}
1588