blob: 4eae98eee5d5a96d990259275a1e401b034be9b7 [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[] = {
Mathias Agopianb1a39d62009-05-27 20:38:06 -0700156 #include "GLES_CM/gl_entries.in"
157 #include "GLES_CM/glext_entries.in"
158 NULL
159};
160
161static char const * const gl2_names[] = {
162 #include "GLES2/gl2_entries.in"
163 #include "GLES2/gl2ext_entries.in"
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800164 NULL
165};
166
167static char const * const egl_names[] = {
168 #include "egl_entries.in"
169 NULL
170};
171
172#undef GL_ENTRY
173#undef EGL_ENTRY
174
175// ----------------------------------------------------------------------------
176
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700177egl_connection_t gEGLImpl[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800178static egl_display_t gDisplay[NUM_DISPLAYS];
179static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
180static pthread_key_t gEGLThreadLocalStorageKey = -1;
181
182// ----------------------------------------------------------------------------
183
Mathias Agopianeccc8cf2009-05-13 00:19:22 -0700184EGLAPI gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
185EGLAPI pthread_key_t gGLWrapperKey = -1;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800186
187// ----------------------------------------------------------------------------
188
189static __attribute__((noinline))
190const char *egl_strerror(EGLint err)
191{
192 switch (err){
193 case EGL_SUCCESS: return "EGL_SUCCESS";
194 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
195 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
196 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
197 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
198 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
199 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
200 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
201 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
202 case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
203 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
204 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
205 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
206 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
207 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
208 default: return "UNKNOWN";
209 }
210}
211
212static __attribute__((noinline))
213void clearTLS() {
214 if (gEGLThreadLocalStorageKey != -1) {
215 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
216 if (tls) {
217 delete tls;
218 pthread_setspecific(gEGLThreadLocalStorageKey, 0);
219 }
220 }
221}
222
223static tls_t* getTLS()
224{
225 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
226 if (tls == 0) {
227 tls = new tls_t;
228 pthread_setspecific(gEGLThreadLocalStorageKey, tls);
229 }
230 return tls;
231}
232
233template<typename T>
234static __attribute__((noinline))
235T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
236 if (gEGLThreadLocalStorageKey == -1) {
237 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
238 if (gEGLThreadLocalStorageKey == -1)
239 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
240 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
241 }
242 tls_t* tls = getTLS();
243 if (tls->error != error) {
244 LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
245 tls->error = error;
246 }
247 return returnValue;
248}
249
250static __attribute__((noinline))
251GLint getError() {
252 if (gEGLThreadLocalStorageKey == -1)
253 return EGL_SUCCESS;
254 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
255 if (!tls) return EGL_SUCCESS;
256 GLint error = tls->error;
257 tls->error = EGL_SUCCESS;
258 return error;
259}
260
261static __attribute__((noinline))
262void setContext(EGLContext ctx) {
263 if (gEGLThreadLocalStorageKey == -1) {
264 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
265 if (gEGLThreadLocalStorageKey == -1)
266 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
267 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
268 }
269 tls_t* tls = getTLS();
270 tls->ctx = ctx;
271}
272
273static __attribute__((noinline))
274EGLContext getContext() {
275 if (gEGLThreadLocalStorageKey == -1)
276 return EGL_NO_CONTEXT;
277 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
278 if (!tls) return EGL_NO_CONTEXT;
279 return tls->ctx;
280}
281
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800282/*****************************************************************************/
283
Mathias Agopianb1a39d62009-05-27 20:38:06 -0700284typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
285 const char*);
286
287static __attribute__((noinline))
288void init_api(void* dso,
289 char const * const * api,
290 __eglMustCastToProperFunctionPointerType* curr,
291 getProcAddressType getProcAddress)
292{
293 char scrap[256];
294 while (*api) {
295 char const * name = *api;
296 __eglMustCastToProperFunctionPointerType f =
297 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
298 if (f == NULL) {
299 // couldn't find the entry-point, use eglGetProcAddress()
300 f = getProcAddress(name);
301 }
302 if (f == NULL) {
303 // Try without the OES postfix
304 ssize_t index = ssize_t(strlen(name)) - 3;
305 if ((index>0 && (index<255)) && (!strcmp(name+index, "OES"))) {
306 strncpy(scrap, name, index);
307 scrap[index] = 0;
308 f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
309 //LOGD_IF(f, "found <%s> instead", scrap);
310 }
311 }
312 if (f == NULL) {
313 // Try with the OES postfix
314 ssize_t index = ssize_t(strlen(name)) - 3;
315 if ((index>0 && (index<252)) && (strcmp(name+index, "OES"))) {
316 strncpy(scrap, name, index);
317 scrap[index] = 0;
318 strcat(scrap, "OES");
319 f = (__eglMustCastToProperFunctionPointerType)dlsym(dso, scrap);
320 //LOGD_IF(f, "found <%s> instead", scrap);
321 }
322 }
323 if (f == NULL) {
324 //LOGD("%s", name);
325 f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
326 }
327 *curr++ = f;
328 api++;
329 }
330}
331
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800332static __attribute__((noinline))
333void *load_driver(const char* driver, gl_hooks_t* hooks)
334{
Mathias Agopian1c2be6a2009-04-23 19:57:10 -0700335 //LOGD("%s", driver);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800336 void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
337 LOGE_IF(!dso,
338 "couldn't load <%s> library (%s)",
339 driver, dlerror());
340
341 if (dso) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700342 // first find the symbol for eglGetProcAddress
343
344 typedef __eglMustCastToProperFunctionPointerType (*getProcAddressType)(
345 const char*);
346
347 getProcAddressType getProcAddress =
348 (getProcAddressType)dlsym(dso, "eglGetProcAddress");
349
350 LOGE_IF(!getProcAddress,
351 "can't find eglGetProcAddress() in %s", driver);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700352
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800353 gl_hooks_t::egl_t* egl = &hooks->egl;
Mathias Agopianb1a39d62009-05-27 20:38:06 -0700354 __eglMustCastToProperFunctionPointerType* curr =
355 (__eglMustCastToProperFunctionPointerType*)egl;
356 char const * const * api = egl_names;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800357 while (*api) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700358 char const * name = *api;
359 __eglMustCastToProperFunctionPointerType f =
360 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800361 if (f == NULL) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700362 // couldn't find the entry-point, use eglGetProcAddress()
363 f = getProcAddress(name);
364 if (f == NULL) {
365 f = (__eglMustCastToProperFunctionPointerType)0;
366 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800367 }
368 *curr++ = f;
369 api++;
370 }
Mathias Agopianb1a39d62009-05-27 20:38:06 -0700371
372 init_api(dso, gl_names,
373 (__eglMustCastToProperFunctionPointerType*)&hooks->gl,
374 getProcAddress);
375
376 init_api(dso, gl2_names,
377 (__eglMustCastToProperFunctionPointerType*)&hooks->gl2,
378 getProcAddress);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800379 }
380 return dso;
381}
382
383template<typename T>
384static __attribute__((noinline))
385int binarySearch(
386 T const sortedArray[], int first, int last, T key)
387{
388 while (first <= last) {
389 int mid = (first + last) / 2;
390 if (key > sortedArray[mid]) {
391 first = mid + 1;
392 } else if (key < sortedArray[mid]) {
393 last = mid - 1;
394 } else {
395 return mid;
396 }
397 }
398 return -1;
399}
400
401static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
402{
403 // NOTE: this mapping works only if we have no more than two EGLimpl
404 return (i>0 ? dp->numConfigs[0] : 0) + index;
405}
406
407static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
408 int& i, int& index)
409{
410 // NOTE: this mapping works only if we have no more than two EGLimpl
411 size_t numConfigs = dp->numConfigs[0];
412 i = configId / numConfigs;
413 index = configId % numConfigs;
414}
415
416static int cmp_configs(const void* a, const void *b)
417{
418 EGLConfig c0 = *(EGLConfig const *)a;
419 EGLConfig c1 = *(EGLConfig const *)b;
420 return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
421}
422
423struct extention_map_t {
424 const char* name;
425 __eglMustCastToProperFunctionPointerType address;
426};
427
428static const extention_map_t gExtentionMap[] = {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700429 { "eglLockSurfaceKHR",
430 (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
431 { "eglUnlockSurfaceKHR",
432 (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
433 { "eglCreateImageKHR",
434 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
435 { "eglDestroyImageKHR",
436 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800437};
438
439static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
440
441static void(*findProcAddress(const char* name,
442 const extention_map_t* map, size_t n))()
443{
444 for (uint32_t i=0 ; i<n ; i++) {
445 if (!strcmp(name, map[i].name)) {
446 return map[i].address;
447 }
448 }
449 return NULL;
450}
451
452// ----------------------------------------------------------------------------
453
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700454/*
455 * To "loose" the GPU, use something like
456 * gEGLImpl[IMPL_HARDWARE].hooks = &gHooks[IMPL_CONTEXT_LOST];
457 *
458 */
459
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800460static int gl_context_lost() {
461 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
462 return 0;
463}
464static int egl_context_lost() {
465 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
466 return EGL_FALSE;
467}
468static EGLBoolean egl_context_lost_swap_buffers(void*, void*) {
469 usleep(100000); // don't use all the CPU
470 setGlThreadSpecific(&gHooks[IMPL_CONTEXT_LOST]);
471 return EGL_FALSE;
472}
473static GLint egl_context_lost_get_error() {
474 return EGL_CONTEXT_LOST;
475}
476static int ext_context_lost() {
477 return 0;
478}
479
480static void gl_no_context() {
481 LOGE("call to OpenGL ES API with no current context");
482}
483static void early_egl_init(void)
484{
485#if !USE_FAST_TLS_KEY
486 pthread_key_create(&gGLWrapperKey, NULL);
487#endif
488 uint32_t addr = (uint32_t)((void*)gl_no_context);
489 android_memset32(
490 (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT],
491 addr,
492 sizeof(gHooks[IMPL_NO_CONTEXT]));
493 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
494}
495
496static pthread_once_t once_control = PTHREAD_ONCE_INIT;
497static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
498
499
500static inline
501egl_display_t* get_display(EGLDisplay dpy)
502{
503 uintptr_t index = uintptr_t(dpy)-1U;
504 return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
505}
506
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700507template<typename NATIVE, typename EGL>
508static inline NATIVE* egl_to_native_cast(EGL arg) {
509 return reinterpret_cast<NATIVE*>(arg);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800510}
511
512static inline
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700513egl_surface_t* get_surface(EGLSurface surface) {
514 return egl_to_native_cast<egl_surface_t>(surface);
515}
516
517static inline
518egl_context_t* get_context(EGLContext context) {
519 return egl_to_native_cast<egl_context_t>(context);
520}
521
522static inline
523egl_image_t* get_image(EGLImageKHR image) {
524 return egl_to_native_cast<egl_image_t>(image);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800525}
526
527static egl_connection_t* validate_display_config(
528 EGLDisplay dpy, EGLConfig config,
529 egl_display_t const*& dp, int& impl, int& index)
530{
531 dp = get_display(dpy);
532 if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
533
534 impl = uintptr_t(config)>>24;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700535 if (uint32_t(impl) >= IMPL_NUM_DRIVERS_IMPLEMENTATIONS) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800536 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
537 }
538 index = uintptr_t(config) & 0xFFFFFF;
539 if (index >= dp->numConfigs[impl]) {
540 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
541 }
542 egl_connection_t* const cnx = &gEGLImpl[impl];
543 if (cnx->dso == 0) {
544 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
545 }
546 return cnx;
547}
548
549static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
550{
551 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
552 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
553 if (!get_display(dpy)->isValid())
554 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
555 if (!ctx) // TODO: make sure context is a valid object
556 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
557 if (!get_context(ctx)->isValid())
558 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
559 return EGL_TRUE;
560}
561
562static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
563{
564 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
565 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
566 if (!get_display(dpy)->isValid())
567 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
568 if (!surface) // TODO: make sure surface is a valid object
569 return setError(EGL_BAD_SURFACE, EGL_FALSE);
570 if (!get_surface(surface)->isValid())
571 return setError(EGL_BAD_SURFACE, EGL_FALSE);
572 return EGL_TRUE;
573}
574
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800575
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700576EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
577{
578 EGLContext context = getContext();
579 if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
580 return EGL_NO_IMAGE_KHR;
581
582 egl_context_t const * const c = get_context(context);
583 if (!c->isValid())
584 return EGL_NO_IMAGE_KHR;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800585
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700586 egl_image_t const * const i = get_image(image);
587 if (!i->isValid())
588 return EGL_NO_IMAGE_KHR;
589
590 return i->images[c->impl];
591}
592
593
594EGLDisplay egl_init_displays(NativeDisplayType display)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800595{
596 if (sEarlyInitState) {
597 return EGL_NO_DISPLAY;
598 }
599
600 uint32_t index = uint32_t(display);
601 if (index >= NUM_DISPLAYS) {
602 return EGL_NO_DISPLAY;
603 }
604
605 EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
606 egl_display_t* d = &gDisplay[index];
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700607
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800608 // dynamically load all our EGL implementations for that display
609 // and call into the real eglGetGisplay()
610 egl_connection_t* cnx = &gEGLImpl[IMPL_SOFTWARE];
611 if (cnx->dso == 0) {
612 cnx->hooks = &gHooks[IMPL_SOFTWARE];
613 cnx->dso = load_driver("libagl.so", cnx->hooks);
614 }
615 if (cnx->dso && d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY) {
616 d->dpys[IMPL_SOFTWARE] = cnx->hooks->egl.eglGetDisplay(display);
617 LOGE_IF(d->dpys[IMPL_SOFTWARE]==EGL_NO_DISPLAY,
618 "No EGLDisplay for software EGL!");
619 }
620
621 cnx = &gEGLImpl[IMPL_HARDWARE];
622 if (cnx->dso == 0 && cnx->unavailable == 0) {
623 char value[PROPERTY_VALUE_MAX];
624 property_get("debug.egl.hw", value, "1");
625 if (atoi(value) != 0) {
626 cnx->hooks = &gHooks[IMPL_HARDWARE];
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700627 cnx->dso = load_driver("libhgl2.so", cnx->hooks);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800628 } else {
629 LOGD("3D hardware acceleration is disabled");
630 }
631 }
632 if (cnx->dso && d->dpys[IMPL_HARDWARE]==EGL_NO_DISPLAY) {
633 android_memset32(
634 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].gl,
635 (uint32_t)((void*)gl_context_lost),
636 sizeof(gHooks[IMPL_CONTEXT_LOST].gl));
637 android_memset32(
638 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].egl,
639 (uint32_t)((void*)egl_context_lost),
640 sizeof(gHooks[IMPL_CONTEXT_LOST].egl));
641 android_memset32(
642 (uint32_t*)(void*)&gHooks[IMPL_CONTEXT_LOST].ext,
643 (uint32_t)((void*)ext_context_lost),
644 sizeof(gHooks[IMPL_CONTEXT_LOST].ext));
645
646 gHooks[IMPL_CONTEXT_LOST].egl.eglSwapBuffers =
647 egl_context_lost_swap_buffers;
648
649 gHooks[IMPL_CONTEXT_LOST].egl.eglGetError =
650 egl_context_lost_get_error;
651
652 gHooks[IMPL_CONTEXT_LOST].egl.eglTerminate =
653 gHooks[IMPL_HARDWARE].egl.eglTerminate;
654
655 d->dpys[IMPL_HARDWARE] = cnx->hooks->egl.eglGetDisplay(display);
656 if (d->dpys[IMPL_HARDWARE] == EGL_NO_DISPLAY) {
657 LOGE("h/w accelerated eglGetDisplay() failed (%s)",
658 egl_strerror(cnx->hooks->egl.eglGetError()));
659 dlclose((void*)cnx->dso);
660 cnx->dso = 0;
661 // in case of failure, we want to make sure we don't try again
662 // as it's expensive.
663 cnx->unavailable = 1;
664 }
665 }
666
667 return dpy;
668}
669
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700670
671// ----------------------------------------------------------------------------
672}; // namespace android
673// ----------------------------------------------------------------------------
674
675using namespace android;
676
677EGLDisplay eglGetDisplay(NativeDisplayType display)
678{
679 return egl_init_displays(display);
680}
681
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800682// ----------------------------------------------------------------------------
683// Initialization
684// ----------------------------------------------------------------------------
685
686EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
687{
688 egl_display_t * const dp = get_display(dpy);
689 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
690
691 if (android_atomic_inc(&dp->refs) > 0) {
692 if (major != NULL) *major = VERSION_MAJOR;
693 if (minor != NULL) *minor = VERSION_MINOR;
694 return EGL_TRUE;
695 }
696
697 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
698
699 // initialize each EGL and
700 // build our own extension string first, based on the extension we know
701 // and the extension supported by our client implementation
702 dp->extensionsString = strdup(gExtensionString);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700703 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800704 egl_connection_t* const cnx = &gEGLImpl[i];
705 cnx->major = -1;
706 cnx->minor = -1;
707 if (!cnx->dso)
708 continue;
709
710 if (cnx->hooks->egl.eglInitialize(
711 dp->dpys[i], &cnx->major, &cnx->minor)) {
712
713 //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
714 // i, dp->dpys[i], cnx->major, cnx->minor, cnx);
715
716 // get the query-strings for this display for each implementation
717 dp->queryString[i].vendor =
718 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
719 dp->queryString[i].version =
720 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
721 dp->queryString[i].extensions = strdup(
722 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
723 dp->queryString[i].clientApi =
724 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
725
726 } else {
727 LOGD("%d: eglInitialize() failed (%s)",
728 i, egl_strerror(cnx->hooks->egl.eglGetError()));
729 }
730 }
731
732 EGLBoolean res = EGL_FALSE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700733 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800734 egl_connection_t* const cnx = &gEGLImpl[i];
735 if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
736 EGLint n;
737 if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
738 dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
739 if (dp->configs[i]) {
740 if (cnx->hooks->egl.eglGetConfigs(
741 dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
742 {
743 // sort the configurations so we can do binary searches
744 qsort( dp->configs[i],
745 dp->numConfigs[i],
746 sizeof(EGLConfig), cmp_configs);
747
748 dp->numTotalConfigs += n;
749 res = EGL_TRUE;
750 }
751 }
752 }
753 }
754 }
755
756 if (res == EGL_TRUE) {
757 if (major != NULL) *major = VERSION_MAJOR;
758 if (minor != NULL) *minor = VERSION_MINOR;
759 return EGL_TRUE;
760 }
761 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
762}
763
764EGLBoolean eglTerminate(EGLDisplay dpy)
765{
766 egl_display_t* const dp = get_display(dpy);
767 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
768 if (android_atomic_dec(&dp->refs) != 1)
769 return EGL_TRUE;
770
771 EGLBoolean res = EGL_FALSE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700772 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800773 egl_connection_t* const cnx = &gEGLImpl[i];
774 if (cnx->dso) {
775 cnx->hooks->egl.eglTerminate(dp->dpys[i]);
776
777 /* REVISIT: it's unclear what to do if eglTerminate() fails,
778 * on one end we shouldn't care, on the other end if it fails
779 * it might not be safe to call dlclose() (there could be some
780 * threads around). */
781
782 free(dp->configs[i]);
783 free((void*)dp->queryString[i].extensions);
784 dp->numConfigs[i] = 0;
785 dp->dpys[i] = EGL_NO_DISPLAY;
786 dlclose((void*)cnx->dso);
787 cnx->dso = 0;
788 res = EGL_TRUE;
789 }
790 }
791 free((void*)dp->extensionsString);
792 dp->extensionsString = 0;
793 dp->numTotalConfigs = 0;
794 clearTLS();
795 return res;
796}
797
798// ----------------------------------------------------------------------------
799// configuration
800// ----------------------------------------------------------------------------
801
802EGLBoolean eglGetConfigs( EGLDisplay dpy,
803 EGLConfig *configs,
804 EGLint config_size, EGLint *num_config)
805{
806 egl_display_t const * const dp = get_display(dpy);
807 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
808
809 GLint numConfigs = dp->numTotalConfigs;
810 if (!configs) {
811 *num_config = numConfigs;
812 return EGL_TRUE;
813 }
814 GLint n = 0;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700815 for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800816 for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
817 *configs++ = MAKE_CONFIG(j, i);
818 config_size--;
819 n++;
820 }
821 }
822
823 *num_config = n;
824 return EGL_TRUE;
825}
826
827EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
828 EGLConfig *configs, EGLint config_size,
829 EGLint *num_config)
830{
831 egl_display_t const * const dp = get_display(dpy);
832 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
833
Jack Palevich749c63d2009-03-25 15:12:17 -0700834 if (num_config==0) {
835 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800836 }
837
838 EGLint n;
839 EGLBoolean res = EGL_FALSE;
840 *num_config = 0;
841
842
843 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
844 // to do this, we have to go through the attrib_list array once
845 // to figure out both its size and if it contains an EGL_CONFIG_ID
846 // key. If so, the full array is copied and patched.
847 // NOTE: we assume that there can be only one occurrence
848 // of EGL_CONFIG_ID.
849
850 EGLint patch_index = -1;
851 GLint attr;
852 size_t size = 0;
853 while ((attr=attrib_list[size])) {
854 if (attr == EGL_CONFIG_ID)
855 patch_index = size;
856 size += 2;
857 }
858 if (patch_index >= 0) {
859 size += 2; // we need copy the sentinel as well
860 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
861 if (new_list == 0)
862 return setError(EGL_BAD_ALLOC, EGL_FALSE);
863 memcpy(new_list, attrib_list, size*sizeof(EGLint));
864
865 // patch the requested EGL_CONFIG_ID
866 int i, index;
867 EGLint& configId(new_list[patch_index+1]);
868 uniqueIdToConfig(dp, configId, i, index);
869
870 egl_connection_t* const cnx = &gEGLImpl[i];
871 if (cnx->dso) {
872 cnx->hooks->egl.eglGetConfigAttrib(
873 dp->dpys[i], dp->configs[i][index],
874 EGL_CONFIG_ID, &configId);
875
876 // and switch to the new list
877 attrib_list = const_cast<const EGLint *>(new_list);
878
879 // At this point, the only configuration that can match is
880 // dp->configs[i][index], however, we don't know if it would be
881 // rejected because of the other attributes, so we do have to call
882 // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
883 // through all the EGLimpl[].
884 // We also know we can only get a single config back, and we know
885 // which one.
886
887 res = cnx->hooks->egl.eglChooseConfig(
888 dp->dpys[i], attrib_list, configs, config_size, &n);
889 if (res && n>0) {
890 // n has to be 0 or 1, by construction, and we already know
891 // which config it will return (since there can be only one).
Jack Palevich749c63d2009-03-25 15:12:17 -0700892 if (configs) {
893 configs[0] = MAKE_CONFIG(i, index);
894 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800895 *num_config = 1;
896 }
897 }
898
899 free(const_cast<EGLint *>(attrib_list));
900 return res;
901 }
902
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700903 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800904 egl_connection_t* const cnx = &gEGLImpl[i];
905 if (cnx->dso) {
906 if (cnx->hooks->egl.eglChooseConfig(
907 dp->dpys[i], attrib_list, configs, config_size, &n)) {
Jack Palevich749c63d2009-03-25 15:12:17 -0700908 if (configs) {
909 // now we need to convert these client EGLConfig to our
910 // internal EGLConfig format. This is done in O(n log n).
911 for (int j=0 ; j<n ; j++) {
912 int index = binarySearch<EGLConfig>(
913 dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
914 if (index >= 0) {
915 if (configs) {
916 configs[j] = MAKE_CONFIG(i, index);
917 }
918 } else {
919 return setError(EGL_BAD_CONFIG, EGL_FALSE);
920 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800921 }
Jack Palevich749c63d2009-03-25 15:12:17 -0700922 configs += n;
923 config_size -= n;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800924 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800925 *num_config += n;
926 res = EGL_TRUE;
927 }
928 }
929 }
930 return res;
931}
932
933EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
934 EGLint attribute, EGLint *value)
935{
936 egl_display_t const* dp = 0;
937 int i=0, index=0;
938 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
939 if (!cnx) return EGL_FALSE;
940
941 if (attribute == EGL_CONFIG_ID) {
942 // EGL_CONFIG_IDs must be unique, just use the order of the selected
943 // EGLConfig.
944 *value = configToUniqueId(dp, i, index);
945 return EGL_TRUE;
946 }
947 return cnx->hooks->egl.eglGetConfigAttrib(
948 dp->dpys[i], dp->configs[i][index], attribute, value);
949}
950
951// ----------------------------------------------------------------------------
952// surfaces
953// ----------------------------------------------------------------------------
954
955EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
956 NativeWindowType window,
957 const EGLint *attrib_list)
958{
959 egl_display_t const* dp = 0;
960 int i=0, index=0;
961 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
962 if (cnx) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800963 EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
964 dp->dpys[i], dp->configs[i][index], window, attrib_list);
965 if (surface != EGL_NO_SURFACE) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700966 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800967 return s;
968 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800969 }
970 return EGL_NO_SURFACE;
971}
972
973EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
974 NativePixmapType pixmap,
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.eglCreatePixmapSurface(
982 dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
983 if (surface != EGL_NO_SURFACE) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700984 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800985 return s;
986 }
987 }
988 return EGL_NO_SURFACE;
989}
990
991EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
992 const EGLint *attrib_list)
993{
994 egl_display_t const* dp = 0;
995 int i=0, index=0;
996 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
997 if (cnx) {
998 EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
999 dp->dpys[i], dp->configs[i][index], attrib_list);
1000 if (surface != EGL_NO_SURFACE) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001001 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001002 return s;
1003 }
1004 }
1005 return EGL_NO_SURFACE;
1006}
1007
1008EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
1009{
1010 if (!validate_display_surface(dpy, surface))
1011 return EGL_FALSE;
1012 egl_display_t const * const dp = get_display(dpy);
1013 egl_surface_t const * const s = get_surface(surface);
1014
1015 EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
1016 dp->dpys[s->impl], s->surface);
1017
1018 delete s;
1019 return result;
1020}
1021
1022EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
1023 EGLint attribute, EGLint *value)
1024{
1025 if (!validate_display_surface(dpy, surface))
1026 return EGL_FALSE;
1027 egl_display_t const * const dp = get_display(dpy);
1028 egl_surface_t const * const s = get_surface(surface);
1029
1030 return s->cnx->hooks->egl.eglQuerySurface(
1031 dp->dpys[s->impl], s->surface, attribute, value);
1032}
1033
1034// ----------------------------------------------------------------------------
1035// contextes
1036// ----------------------------------------------------------------------------
1037
1038EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1039 EGLContext share_list, const EGLint *attrib_list)
1040{
1041 egl_display_t const* dp = 0;
1042 int i=0, index=0;
1043 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1044 if (cnx) {
1045 EGLContext context = cnx->hooks->egl.eglCreateContext(
1046 dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
1047 if (context != EGL_NO_CONTEXT) {
1048 egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
1049 return c;
1050 }
1051 }
1052 return EGL_NO_CONTEXT;
1053}
1054
1055EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1056{
1057 if (!validate_display_context(dpy, ctx))
1058 return EGL_FALSE;
1059 egl_display_t const * const dp = get_display(dpy);
1060 egl_context_t * const c = get_context(ctx);
1061 EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
1062 dp->dpys[c->impl], c->context);
1063 delete c;
1064 return result;
1065}
1066
1067EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
1068 EGLSurface read, EGLContext ctx)
1069{
1070 egl_display_t const * const dp = get_display(dpy);
1071 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1072
1073 if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
1074 ctx == EGL_NO_CONTEXT)
1075 {
1076 EGLBoolean result = EGL_TRUE;
1077 ctx = getContext();
1078 if (ctx) {
1079 egl_context_t * const c = get_context(ctx);
1080 result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
1081 if (result == EGL_TRUE) {
1082 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
1083 setContext(EGL_NO_CONTEXT);
1084 }
1085 }
1086 return result;
1087 }
1088
1089 if (!validate_display_context(dpy, ctx))
1090 return EGL_FALSE;
1091
1092 egl_context_t * const c = get_context(ctx);
1093 if (draw != EGL_NO_SURFACE) {
1094 egl_surface_t const * d = get_surface(draw);
1095 if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1096 if (d->impl != c->impl)
1097 return setError(EGL_BAD_MATCH, EGL_FALSE);
1098 draw = d->surface;
1099 }
1100 if (read != EGL_NO_SURFACE) {
1101 egl_surface_t const * r = get_surface(read);
1102 if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1103 if (r->impl != c->impl)
1104 return setError(EGL_BAD_MATCH, EGL_FALSE);
1105 read = r->surface;
1106 }
1107 EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
1108 dp->dpys[c->impl], draw, read, c->context);
1109
1110 if (result == EGL_TRUE) {
1111 setGlThreadSpecific(c->cnx->hooks);
1112 setContext(ctx);
1113 c->read = read;
1114 c->draw = draw;
1115 }
1116 return result;
1117}
1118
1119
1120EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1121 EGLint attribute, EGLint *value)
1122{
1123 if (!validate_display_context(dpy, ctx))
1124 return EGL_FALSE;
1125
1126 egl_display_t const * const dp = get_display(dpy);
1127 egl_context_t * const c = get_context(ctx);
1128
1129 return c->cnx->hooks->egl.eglQueryContext(
1130 dp->dpys[c->impl], c->context, attribute, value);
1131}
1132
1133EGLContext eglGetCurrentContext(void)
1134{
1135 EGLContext ctx = getContext();
1136 return ctx;
1137}
1138
1139EGLSurface eglGetCurrentSurface(EGLint readdraw)
1140{
1141 EGLContext ctx = getContext();
1142 if (ctx) {
1143 egl_context_t const * const c = get_context(ctx);
1144 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1145 switch (readdraw) {
1146 case EGL_READ: return c->read;
1147 case EGL_DRAW: return c->draw;
1148 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1149 }
1150 }
1151 return EGL_NO_SURFACE;
1152}
1153
1154EGLDisplay eglGetCurrentDisplay(void)
1155{
1156 EGLContext ctx = getContext();
1157 if (ctx) {
1158 egl_context_t const * const c = get_context(ctx);
1159 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1160 return c->dpy;
1161 }
1162 return EGL_NO_DISPLAY;
1163}
1164
1165EGLBoolean eglWaitGL(void)
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.eglWaitGL();
1178 }
1179 return res;
1180}
1181
1182EGLBoolean eglWaitNative(EGLint engine)
1183{
1184 EGLBoolean res = EGL_TRUE;
1185 EGLContext ctx = getContext();
1186 if (ctx) {
1187 egl_context_t const * const c = get_context(ctx);
1188 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1189 if (uint32_t(c->impl)>=2)
1190 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1191 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1192 if (!cnx->dso)
1193 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1194 res = cnx->hooks->egl.eglWaitNative(engine);
1195 }
1196 return res;
1197}
1198
1199EGLint eglGetError(void)
1200{
1201 EGLint result = EGL_SUCCESS;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001202 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001203 EGLint err = EGL_SUCCESS;
1204 egl_connection_t* const cnx = &gEGLImpl[i];
1205 if (cnx->dso)
1206 err = cnx->hooks->egl.eglGetError();
1207 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1208 result = err;
1209 }
1210 if (result == EGL_SUCCESS)
1211 result = getError();
1212 return result;
1213}
1214
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001215__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001216{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001217 // eglGetProcAddress() could be the very first function called
1218 // in which case we must make sure we've initialized ourselves, this
1219 // happens the first time egl_get_display() is called.
1220
1221 if (egl_init_displays(EGL_DEFAULT_DISPLAY) == EGL_NO_DISPLAY)
1222 return NULL;
1223
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001224 __eglMustCastToProperFunctionPointerType addr;
1225 addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1226 if (addr) return addr;
1227
1228 return NULL; // TODO: finish implementation below
1229
1230 addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1231 if (addr) return addr;
1232
1233 addr = 0;
1234 int slot = -1;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001235 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001236 egl_connection_t* const cnx = &gEGLImpl[i];
1237 if (cnx->dso) {
1238 if (cnx->hooks->egl.eglGetProcAddress) {
1239 addr = cnx->hooks->egl.eglGetProcAddress(procname);
1240 if (addr) {
1241 if (slot == -1) {
1242 slot = 0; // XXX: find free slot
1243 if (slot == -1) {
1244 addr = 0;
1245 break;
1246 }
1247 }
1248 cnx->hooks->ext.extensions[slot] = addr;
1249 }
1250 }
1251 }
1252 }
1253
1254 if (slot >= 0) {
1255 addr = 0; // XXX: address of stub 'slot'
1256 gGLExtentionMap[slot].name = strdup(procname);
1257 gGLExtentionMap[slot].address = addr;
1258 }
1259
1260 return addr;
1261
1262
1263 /*
1264 * TODO: For OpenGL ES extensions, we must generate a stub
1265 * that looks like
1266 * mov r12, #0xFFFF0FFF
1267 * ldr r12, [r12, #-15]
1268 * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
1269 * mov r12, [r12, #api_offset]
1270 * ldrne pc, r12
1271 * mov pc, #unsupported_extension
1272 *
1273 * and write the address of the extension in *all*
1274 * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1275 *
1276 */
1277}
1278
1279EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1280{
1281 if (!validate_display_surface(dpy, draw))
1282 return EGL_FALSE;
1283 egl_display_t const * const dp = get_display(dpy);
1284 egl_surface_t const * const s = get_surface(draw);
1285 return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1286}
1287
1288EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1289 NativePixmapType target)
1290{
1291 if (!validate_display_surface(dpy, surface))
1292 return EGL_FALSE;
1293 egl_display_t const * const dp = get_display(dpy);
1294 egl_surface_t const * const s = get_surface(surface);
1295 return s->cnx->hooks->egl.eglCopyBuffers(
1296 dp->dpys[s->impl], s->surface, target);
1297}
1298
1299const char* eglQueryString(EGLDisplay dpy, EGLint name)
1300{
1301 egl_display_t const * const dp = get_display(dpy);
1302 switch (name) {
1303 case EGL_VENDOR:
1304 return gVendorString;
1305 case EGL_VERSION:
1306 return gVersionString;
1307 case EGL_EXTENSIONS:
1308 return gExtensionString;
1309 case EGL_CLIENT_APIS:
1310 return gClientApiString;
1311 }
1312 return setError(EGL_BAD_PARAMETER, (const char *)0);
1313}
1314
1315
1316// ----------------------------------------------------------------------------
1317// EGL 1.1
1318// ----------------------------------------------------------------------------
1319
1320EGLBoolean eglSurfaceAttrib(
1321 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1322{
1323 if (!validate_display_surface(dpy, surface))
1324 return EGL_FALSE;
1325 egl_display_t const * const dp = get_display(dpy);
1326 egl_surface_t const * const s = get_surface(surface);
1327 if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1328 return s->cnx->hooks->egl.eglSurfaceAttrib(
1329 dp->dpys[s->impl], s->surface, attribute, value);
1330 }
1331 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1332}
1333
1334EGLBoolean eglBindTexImage(
1335 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1336{
1337 if (!validate_display_surface(dpy, surface))
1338 return EGL_FALSE;
1339 egl_display_t const * const dp = get_display(dpy);
1340 egl_surface_t const * const s = get_surface(surface);
1341 if (s->cnx->hooks->egl.eglBindTexImage) {
1342 return s->cnx->hooks->egl.eglBindTexImage(
1343 dp->dpys[s->impl], s->surface, buffer);
1344 }
1345 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1346}
1347
1348EGLBoolean eglReleaseTexImage(
1349 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1350{
1351 if (!validate_display_surface(dpy, surface))
1352 return EGL_FALSE;
1353 egl_display_t const * const dp = get_display(dpy);
1354 egl_surface_t const * const s = get_surface(surface);
1355 if (s->cnx->hooks->egl.eglReleaseTexImage) {
1356 return s->cnx->hooks->egl.eglReleaseTexImage(
1357 dp->dpys[s->impl], s->surface, buffer);
1358 }
1359 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1360}
1361
1362EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1363{
1364 egl_display_t * const dp = get_display(dpy);
1365 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1366
1367 EGLBoolean res = EGL_TRUE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001368 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001369 egl_connection_t* const cnx = &gEGLImpl[i];
1370 if (cnx->dso) {
1371 if (cnx->hooks->egl.eglSwapInterval) {
1372 if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1373 res = EGL_FALSE;
1374 }
1375 }
1376 }
1377 }
1378 return res;
1379}
1380
1381
1382// ----------------------------------------------------------------------------
1383// EGL 1.2
1384// ----------------------------------------------------------------------------
1385
1386EGLBoolean eglWaitClient(void)
1387{
1388 EGLBoolean res = EGL_TRUE;
1389 EGLContext ctx = getContext();
1390 if (ctx) {
1391 egl_context_t const * const c = get_context(ctx);
1392 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1393 if (uint32_t(c->impl)>=2)
1394 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1395 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1396 if (!cnx->dso)
1397 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1398 if (cnx->hooks->egl.eglWaitClient) {
1399 res = cnx->hooks->egl.eglWaitClient();
1400 } else {
1401 res = cnx->hooks->egl.eglWaitGL();
1402 }
1403 }
1404 return res;
1405}
1406
1407EGLBoolean eglBindAPI(EGLenum api)
1408{
1409 // bind this API on all EGLs
1410 EGLBoolean res = EGL_TRUE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001411 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001412 egl_connection_t* const cnx = &gEGLImpl[i];
1413 if (cnx->dso) {
1414 if (cnx->hooks->egl.eglBindAPI) {
1415 if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1416 res = EGL_FALSE;
1417 }
1418 }
1419 }
1420 }
1421 return res;
1422}
1423
1424EGLenum eglQueryAPI(void)
1425{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001426 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001427 egl_connection_t* const cnx = &gEGLImpl[i];
1428 if (cnx->dso) {
1429 if (cnx->hooks->egl.eglQueryAPI) {
1430 // the first one we find is okay, because they all
1431 // should be the same
1432 return cnx->hooks->egl.eglQueryAPI();
1433 }
1434 }
1435 }
1436 // or, it can only be OpenGL ES
1437 return EGL_OPENGL_ES_API;
1438}
1439
1440EGLBoolean eglReleaseThread(void)
1441{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001442 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001443 egl_connection_t* const cnx = &gEGLImpl[i];
1444 if (cnx->dso) {
1445 if (cnx->hooks->egl.eglReleaseThread) {
1446 cnx->hooks->egl.eglReleaseThread();
1447 }
1448 }
1449 }
1450 clearTLS();
1451 return EGL_TRUE;
1452}
1453
1454EGLSurface eglCreatePbufferFromClientBuffer(
1455 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1456 EGLConfig config, const EGLint *attrib_list)
1457{
1458 egl_display_t const* dp = 0;
1459 int i=0, index=0;
1460 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1461 if (!cnx) return EGL_FALSE;
1462 if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1463 return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1464 dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1465 }
1466 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1467}
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001468
1469// ----------------------------------------------------------------------------
1470// EGL_EGLEXT_VERSION 3
1471// ----------------------------------------------------------------------------
1472
1473EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1474 const EGLint *attrib_list)
1475{
1476 EGLBoolean result = EGL_FALSE;
1477 if (!validate_display_surface(dpy, surface))
1478 return result;
1479
1480 egl_display_t const * const dp = get_display(dpy);
1481 egl_surface_t const * const s = get_surface(surface);
1482
1483 if (s->cnx->hooks->egl.eglLockSurfaceKHR) {
1484 result = s->cnx->hooks->egl.eglLockSurfaceKHR(
1485 dp->dpys[s->impl], s->surface, attrib_list);
1486 }
1487 return result;
1488}
1489
1490EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1491{
1492 EGLBoolean result = EGL_FALSE;
1493 if (!validate_display_surface(dpy, surface))
1494 return result;
1495
1496 egl_display_t const * const dp = get_display(dpy);
1497 egl_surface_t const * const s = get_surface(surface);
1498
1499 if (s->cnx->hooks->egl.eglUnlockSurfaceKHR) {
1500 result = s->cnx->hooks->egl.eglUnlockSurfaceKHR(
1501 dp->dpys[s->impl], s->surface);
1502 }
1503 return result;
1504}
1505
1506EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1507 EGLClientBuffer buffer, const EGLint *attrib_list)
1508{
1509 if (ctx != EGL_NO_CONTEXT) {
1510 if (!validate_display_context(dpy, ctx))
1511 return EGL_NO_IMAGE_KHR;
1512 egl_display_t const * const dp = get_display(dpy);
1513 egl_context_t * const c = get_context(ctx);
1514 // since we have an EGLContext, we know which implementation to use
1515 EGLImageKHR image = c->cnx->hooks->egl.eglCreateImageKHR(
1516 dp->dpys[c->impl], c->context, target, buffer, attrib_list);
1517 if (image == EGL_NO_IMAGE_KHR)
1518 return image;
1519
1520 egl_image_t* result = new egl_image_t(dpy, ctx);
1521 result->images[c->impl] = image;
1522 return (EGLImageKHR)result;
1523 } else {
1524 // EGL_NO_CONTEXT is a valid parameter
1525 egl_display_t const * const dp = get_display(dpy);
1526 if (dp == 0) {
1527 return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1528 }
1529 // since we don't have a way to know which implementation to call,
1530 // we're calling all of them
1531
1532 EGLImageKHR implImages[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
1533 bool success = false;
1534 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1535 egl_connection_t* const cnx = &gEGLImpl[i];
1536 implImages[i] = EGL_NO_IMAGE_KHR;
1537 if (cnx->dso) {
1538 if (cnx->hooks->egl.eglCreateImageKHR) {
1539 implImages[i] = cnx->hooks->egl.eglCreateImageKHR(
1540 dp->dpys[i], ctx, target, buffer, attrib_list);
1541 if (implImages[i] != EGL_NO_IMAGE_KHR) {
1542 success = true;
1543 }
1544 }
1545 }
1546 }
1547 if (!success)
1548 return EGL_NO_IMAGE_KHR;
1549
1550 egl_image_t* result = new egl_image_t(dpy, ctx);
1551 memcpy(result->images, implImages, sizeof(implImages));
1552 return (EGLImageKHR)result;
1553 }
1554}
1555
1556EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1557{
1558 egl_display_t const * const dp = get_display(dpy);
1559 if (dp == 0) {
1560 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1561 }
1562
1563 egl_image_t* image = get_image(img);
1564 if (!image->isValid()) {
1565 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1566 }
1567
1568 bool success = false;
1569 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1570 egl_connection_t* const cnx = &gEGLImpl[i];
1571 if (image->images[i] != EGL_NO_IMAGE_KHR) {
1572 if (cnx->dso) {
1573 if (cnx->hooks->egl.eglCreateImageKHR) {
1574 if (cnx->hooks->egl.eglDestroyImageKHR(
1575 dp->dpys[i], image->images[i])) {
1576 success = true;
1577 }
1578 }
1579 }
1580 }
1581 }
1582 if (!success)
1583 return EGL_FALSE;
1584
1585 delete image;
1586
1587 return EGL_FALSE;
1588}
Mathias Agopiandf3ca302009-05-04 19:29:25 -07001589
1590
1591// ----------------------------------------------------------------------------
1592// ANDROID extensions
1593// ----------------------------------------------------------------------------
1594
1595EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1596 EGLint left, EGLint top, EGLint width, EGLint height)
1597{
1598 if (!validate_display_surface(dpy, draw))
1599 return EGL_FALSE;
1600 egl_display_t const * const dp = get_display(dpy);
1601 egl_surface_t const * const s = get_surface(draw);
1602 if (s->cnx->hooks->egl.eglSetSwapRectangleANDROID) {
1603 return s->cnx->hooks->egl.eglSetSwapRectangleANDROID(dp->dpys[s->impl],
1604 s->surface, left, top, width, height);
1605 }
1606 return EGL_FALSE;
1607}
1608