blob: d1ddcd39a8be1923d5618ae84c8bb879aebe20ae [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 ** Copyright 2007, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080017#include <ctype.h>
Mathias Agopian11be99d2009-05-17 18:50:16 -070018#include <stdlib.h>
The Android Open Source Project9066cfe2009-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
Mathias Agopian4a34e882009-08-21 02:18:25 -070039#include <utils/SortedVector.h>
40
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041#include "hooks.h"
42#include "egl_impl.h"
Mathias Agopian9d17c052009-05-28 17:39:03 -070043#include "Loader.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044
45#define MAKE_CONFIG(_impl, _index) ((EGLConfig)(((_impl)<<24) | (_index)))
46#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
47
48// ----------------------------------------------------------------------------
49namespace android {
50// ----------------------------------------------------------------------------
51
52#define VERSION_MAJOR 1
53#define VERSION_MINOR 4
54static char const * const gVendorString = "Android";
Mathias Agopiandcebf6f2009-08-17 18:07:06 -070055static char const * const gVersionString = "1.4 Android META-EGL";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056static char const * const gClientApiString = "OpenGL ES";
Mathias Agopian1473f462009-04-10 14:24:30 -070057static char const * const gExtensionString =
58 "EGL_KHR_image "
Mathias Agopian927d37c2009-05-06 23:47:08 -070059 "EGL_KHR_image_base "
60 "EGL_KHR_image_pixmap "
Mathias Agopian1473f462009-04-10 14:24:30 -070061 "EGL_ANDROID_image_native_buffer "
Mathias Agopian2e20bff2009-05-04 19:29:25 -070062 "EGL_ANDROID_swap_rectangle "
Mathias Agopianc1e3ec52009-06-24 22:37:39 -070063 "EGL_ANDROID_get_render_buffer "
Mathias Agopian1473f462009-04-10 14:24:30 -070064 ;
65
66// ----------------------------------------------------------------------------
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067
Mathias Agopian4a34e882009-08-21 02:18:25 -070068class egl_object_t {
69 static SortedVector<egl_object_t*> sObjects;
70 static Mutex sLock;
71
72 volatile int32_t terminated;
73 mutable volatile int32_t count;
74
75public:
76 egl_object_t() : terminated(0), count(1) {
77 Mutex::Autolock _l(sLock);
78 sObjects.add(this);
79 }
80
81 inline bool isAlive() const { return !terminated; }
82
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083private:
Mathias Agopian4a34e882009-08-21 02:18:25 -070084 bool get() {
85 Mutex::Autolock _l(sLock);
86 if (egl_object_t::sObjects.indexOf(this) >= 0) {
87 android_atomic_inc(&count);
88 return true;
89 }
90 return false;
91 }
92
93 bool put() {
94 Mutex::Autolock _l(sLock);
95 if (android_atomic_dec(&count) == 1) {
96 sObjects.remove(this);
97 return true;
98 }
99 return false;
100 }
101
102public:
103 template <typename N, typename T>
104 struct LocalRef {
105 N* ref;
106 LocalRef(T o) : ref(0) {
107 N* native = reinterpret_cast<N*>(o);
108 if (o && native->get()) {
109 ref = native;
110 }
111 }
112 ~LocalRef() {
113 if (ref && ref->put()) {
114 delete ref;
115 }
116 }
117 inline N* get() {
118 return ref;
119 }
120 void acquire() const {
121 if (ref) {
122 android_atomic_inc(&ref->count);
123 }
124 }
125 void release() const {
126 if (ref) {
127 int32_t c = android_atomic_dec(&ref->count);
128 // ref->count cannot be 1 prior atomic_dec because we have
129 // a reference, and if we have one, it means there was
130 // already one before us.
131 LOGE_IF(c==1, "refcount is now 0 in release()");
132 }
133 }
134 void terminate() {
135 if (ref) {
136 ref->terminated = 1;
137 release();
138 }
139 }
140 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141};
142
Mathias Agopian4a34e882009-08-21 02:18:25 -0700143SortedVector<egl_object_t*> egl_object_t::sObjects;
144Mutex egl_object_t::sLock;
145
Mathias Agopian94263d72009-08-24 21:47:13 -0700146struct egl_display_t {
147 enum { NOT_INITIALIZED, INITIALIZED, TERMINATED };
148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 struct strings_t {
150 char const * vendor;
151 char const * version;
152 char const * clientApi;
153 char const * extensions;
154 };
Mathias Agopian94263d72009-08-24 21:47:13 -0700155
156 struct DisplayImpl {
157 DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0),
158 state(NOT_INITIALIZED), numConfigs(0) { }
159 EGLDisplay dpy;
160 EGLConfig* config;
161 EGLint state;
162 EGLint numConfigs;
163 strings_t queryString;
164 };
165
166 uint32_t magic;
167 DisplayImpl disp[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
168 EGLint numTotalConfigs;
169 volatile int32_t refs;
170
171 egl_display_t() : magic('_dpy'), numTotalConfigs(0) { }
Mathias Agopian4a34e882009-08-21 02:18:25 -0700172 ~egl_display_t() { magic = 0; }
173 inline bool isValid() const { return magic == '_dpy'; }
174 inline bool isAlive() const { return isValid(); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175};
176
Mathias Agopian4a34e882009-08-21 02:18:25 -0700177struct egl_surface_t : public egl_object_t
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178{
Mathias Agopian4a34e882009-08-21 02:18:25 -0700179 typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref;
180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 egl_surface_t(EGLDisplay dpy, EGLSurface surface,
Mathias Agopian1473f462009-04-10 14:24:30 -0700182 int impl, egl_connection_t const* cnx)
Mathias Agopian4a34e882009-08-21 02:18:25 -0700183 : dpy(dpy), surface(surface), impl(impl), cnx(cnx) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 }
185 ~egl_surface_t() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 }
187 EGLDisplay dpy;
188 EGLSurface surface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 int impl;
190 egl_connection_t const* cnx;
191};
192
Mathias Agopian4a34e882009-08-21 02:18:25 -0700193struct egl_context_t : public egl_object_t
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194{
Mathias Agopian4a34e882009-08-21 02:18:25 -0700195 typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 egl_context_t(EGLDisplay dpy, EGLContext context,
198 int impl, egl_connection_t const* cnx)
199 : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
200 {
201 }
202 EGLDisplay dpy;
203 EGLContext context;
204 EGLSurface read;
205 EGLSurface draw;
206 int impl;
207 egl_connection_t const* cnx;
208};
209
Mathias Agopian4a34e882009-08-21 02:18:25 -0700210struct egl_image_t : public egl_object_t
Mathias Agopian1473f462009-04-10 14:24:30 -0700211{
Mathias Agopian4a34e882009-08-21 02:18:25 -0700212 typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
213
Mathias Agopian1473f462009-04-10 14:24:30 -0700214 egl_image_t(EGLDisplay dpy, EGLContext context)
215 : dpy(dpy), context(context)
216 {
217 memset(images, 0, sizeof(images));
218 }
219 EGLDisplay dpy;
220 EGLConfig context;
221 EGLImageKHR images[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
222};
223
Mathias Agopian4a34e882009-08-21 02:18:25 -0700224typedef egl_surface_t::Ref SurfaceRef;
225typedef egl_context_t::Ref ContextRef;
226typedef egl_image_t::Ref ImageRef;
227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228struct tls_t
229{
Mathias Agopian997d10702009-07-31 16:21:17 -0700230 tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 EGLint error;
232 EGLContext ctx;
Mathias Agopian997d10702009-07-31 16:21:17 -0700233 EGLBoolean logCallWithNoContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234};
235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236
237// ----------------------------------------------------------------------------
238
Mathias Agopian1473f462009-04-10 14:24:30 -0700239egl_connection_t gEGLImpl[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240static egl_display_t gDisplay[NUM_DISPLAYS];
241static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
242static pthread_key_t gEGLThreadLocalStorageKey = -1;
243
244// ----------------------------------------------------------------------------
245
Mathias Agopian3cc68d22009-05-13 00:19:22 -0700246EGLAPI gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
247EGLAPI pthread_key_t gGLWrapperKey = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248
249// ----------------------------------------------------------------------------
250
251static __attribute__((noinline))
252const char *egl_strerror(EGLint err)
253{
254 switch (err){
255 case EGL_SUCCESS: return "EGL_SUCCESS";
256 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
257 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
258 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
259 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
260 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
261 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
262 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
263 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
264 case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
265 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
266 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
267 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
268 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
269 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
270 default: return "UNKNOWN";
271 }
272}
273
274static __attribute__((noinline))
275void clearTLS() {
276 if (gEGLThreadLocalStorageKey != -1) {
277 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
278 if (tls) {
279 delete tls;
280 pthread_setspecific(gEGLThreadLocalStorageKey, 0);
281 }
282 }
283}
284
285static tls_t* getTLS()
286{
287 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
288 if (tls == 0) {
289 tls = new tls_t;
290 pthread_setspecific(gEGLThreadLocalStorageKey, tls);
291 }
292 return tls;
293}
294
295template<typename T>
296static __attribute__((noinline))
297T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
298 if (gEGLThreadLocalStorageKey == -1) {
299 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
300 if (gEGLThreadLocalStorageKey == -1)
301 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
302 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
303 }
304 tls_t* tls = getTLS();
305 if (tls->error != error) {
306 LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
307 tls->error = error;
308 }
309 return returnValue;
310}
311
312static __attribute__((noinline))
313GLint getError() {
314 if (gEGLThreadLocalStorageKey == -1)
315 return EGL_SUCCESS;
316 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
317 if (!tls) return EGL_SUCCESS;
318 GLint error = tls->error;
319 tls->error = EGL_SUCCESS;
320 return error;
321}
322
323static __attribute__((noinline))
324void setContext(EGLContext ctx) {
325 if (gEGLThreadLocalStorageKey == -1) {
326 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
327 if (gEGLThreadLocalStorageKey == -1)
328 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
329 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
330 }
331 tls_t* tls = getTLS();
332 tls->ctx = ctx;
333}
334
335static __attribute__((noinline))
336EGLContext getContext() {
337 if (gEGLThreadLocalStorageKey == -1)
338 return EGL_NO_CONTEXT;
339 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
340 if (!tls) return EGL_NO_CONTEXT;
341 return tls->ctx;
342}
343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344/*****************************************************************************/
345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346template<typename T>
347static __attribute__((noinline))
348int binarySearch(
349 T const sortedArray[], int first, int last, T key)
350{
351 while (first <= last) {
352 int mid = (first + last) / 2;
353 if (key > sortedArray[mid]) {
354 first = mid + 1;
355 } else if (key < sortedArray[mid]) {
356 last = mid - 1;
357 } else {
358 return mid;
359 }
360 }
361 return -1;
362}
363
364static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
365{
366 // NOTE: this mapping works only if we have no more than two EGLimpl
Mathias Agopian94263d72009-08-24 21:47:13 -0700367 return (i>0 ? dp->disp[0].numConfigs : 0) + index;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368}
369
370static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
371 int& i, int& index)
372{
373 // NOTE: this mapping works only if we have no more than two EGLimpl
Mathias Agopian94263d72009-08-24 21:47:13 -0700374 size_t numConfigs = dp->disp[0].numConfigs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 i = configId / numConfigs;
376 index = configId % numConfigs;
377}
378
379static int cmp_configs(const void* a, const void *b)
380{
381 EGLConfig c0 = *(EGLConfig const *)a;
382 EGLConfig c1 = *(EGLConfig const *)b;
383 return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
384}
385
386struct extention_map_t {
387 const char* name;
388 __eglMustCastToProperFunctionPointerType address;
389};
390
391static const extention_map_t gExtentionMap[] = {
Mathias Agopian1473f462009-04-10 14:24:30 -0700392 { "eglLockSurfaceKHR",
393 (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
394 { "eglUnlockSurfaceKHR",
395 (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
396 { "eglCreateImageKHR",
397 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
398 { "eglDestroyImageKHR",
399 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700400 { "eglSetSwapRectangleANDROID",
401 (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
402 { "eglGetRenderBufferANDROID",
403 (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404};
405
406static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
407
408static void(*findProcAddress(const char* name,
409 const extention_map_t* map, size_t n))()
410{
411 for (uint32_t i=0 ; i<n ; i++) {
412 if (!strcmp(name, map[i].name)) {
413 return map[i].address;
414 }
415 }
416 return NULL;
417}
418
419// ----------------------------------------------------------------------------
420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421static void gl_no_context() {
Mathias Agopian997d10702009-07-31 16:21:17 -0700422 tls_t* tls = getTLS();
423 if (tls->logCallWithNoContext == EGL_TRUE) {
424 tls->logCallWithNoContext = EGL_FALSE;
425 LOGE("call to OpenGL ES API with no current context "
426 "(logged once per thread)");
427 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428}
Mathias Agopian997d10702009-07-31 16:21:17 -0700429
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430static void early_egl_init(void)
431{
432#if !USE_FAST_TLS_KEY
433 pthread_key_create(&gGLWrapperKey, NULL);
434#endif
435 uint32_t addr = (uint32_t)((void*)gl_no_context);
436 android_memset32(
437 (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT],
438 addr,
439 sizeof(gHooks[IMPL_NO_CONTEXT]));
440 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
441}
442
443static pthread_once_t once_control = PTHREAD_ONCE_INIT;
444static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
445
446
447static inline
448egl_display_t* get_display(EGLDisplay dpy)
449{
450 uintptr_t index = uintptr_t(dpy)-1U;
451 return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
452}
453
Mathias Agopian1473f462009-04-10 14:24:30 -0700454template<typename NATIVE, typename EGL>
455static inline NATIVE* egl_to_native_cast(EGL arg) {
456 return reinterpret_cast<NATIVE*>(arg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457}
458
459static inline
Mathias Agopian1473f462009-04-10 14:24:30 -0700460egl_surface_t* get_surface(EGLSurface surface) {
461 return egl_to_native_cast<egl_surface_t>(surface);
462}
463
464static inline
465egl_context_t* get_context(EGLContext context) {
466 return egl_to_native_cast<egl_context_t>(context);
467}
468
469static inline
470egl_image_t* get_image(EGLImageKHR image) {
471 return egl_to_native_cast<egl_image_t>(image);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472}
473
474static egl_connection_t* validate_display_config(
475 EGLDisplay dpy, EGLConfig config,
476 egl_display_t const*& dp, int& impl, int& index)
477{
478 dp = get_display(dpy);
479 if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
480
481 impl = uintptr_t(config)>>24;
Mathias Agopian1473f462009-04-10 14:24:30 -0700482 if (uint32_t(impl) >= IMPL_NUM_DRIVERS_IMPLEMENTATIONS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
484 }
485 index = uintptr_t(config) & 0xFFFFFF;
Mathias Agopian94263d72009-08-24 21:47:13 -0700486 if (index >= dp->disp[impl].numConfigs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
488 }
489 egl_connection_t* const cnx = &gEGLImpl[impl];
490 if (cnx->dso == 0) {
491 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
492 }
493 return cnx;
494}
495
496static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
497{
498 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
499 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian4a34e882009-08-21 02:18:25 -0700500 if (!get_display(dpy)->isAlive())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian4a34e882009-08-21 02:18:25 -0700502 if (!get_context(ctx)->isAlive())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
504 return EGL_TRUE;
505}
506
507static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
508{
509 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
510 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian4a34e882009-08-21 02:18:25 -0700511 if (!get_display(dpy)->isAlive())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian4a34e882009-08-21 02:18:25 -0700513 if (!get_surface(surface)->isAlive())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800514 return setError(EGL_BAD_SURFACE, EGL_FALSE);
515 return EGL_TRUE;
516}
517
Mathias Agopian1473f462009-04-10 14:24:30 -0700518EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
519{
Mathias Agopian4a34e882009-08-21 02:18:25 -0700520 ImageRef _i(image);
521 if (!_i.get()) return EGL_NO_IMAGE_KHR;
522
Mathias Agopian1473f462009-04-10 14:24:30 -0700523 EGLContext context = getContext();
524 if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
525 return EGL_NO_IMAGE_KHR;
526
527 egl_context_t const * const c = get_context(context);
Mathias Agopian4a34e882009-08-21 02:18:25 -0700528 if (!c->isAlive())
Mathias Agopian1473f462009-04-10 14:24:30 -0700529 return EGL_NO_IMAGE_KHR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530
Mathias Agopian1473f462009-04-10 14:24:30 -0700531 egl_image_t const * const i = get_image(image);
Mathias Agopian1473f462009-04-10 14:24:30 -0700532 return i->images[c->impl];
533}
534
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700535// ----------------------------------------------------------------------------
Mathias Agopian1473f462009-04-10 14:24:30 -0700536
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700537// this mutex protects:
Mathias Agopian94263d72009-08-24 21:47:13 -0700538// d->disp[]
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700539// egl_init_drivers_locked()
540//
541static pthread_mutex_t gInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
542
543EGLBoolean egl_init_drivers_locked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544{
545 if (sEarlyInitState) {
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700546 // initialized by static ctor. should be set here.
547 return EGL_FALSE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 }
549
Mathias Agopian9d17c052009-05-28 17:39:03 -0700550 // get our driver loader
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700551 Loader& loader(Loader::getInstance());
Mathias Agopian9d17c052009-05-28 17:39:03 -0700552
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700553 // dynamically load all our EGL implementations for all displays
554 // and retrieve the corresponding EGLDisplay
555 // if that fails, don't use this driver.
556 // TODO: currently we only deal with EGL_DEFAULT_DISPLAY
557 egl_connection_t* cnx;
558 egl_display_t* d = &gDisplay[0];
559
560 cnx = &gEGLImpl[IMPL_SOFTWARE];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 if (cnx->dso == 0) {
562 cnx->hooks = &gHooks[IMPL_SOFTWARE];
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700563 cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx->hooks);
564 if (cnx->dso) {
565 EGLDisplay dpy = cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
566 LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
Mathias Agopian94263d72009-08-24 21:47:13 -0700567 d->disp[IMPL_SOFTWARE].dpy = dpy;
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700568 if (dpy == EGL_NO_DISPLAY) {
569 loader.close(cnx->dso);
570 cnx->dso = NULL;
571 }
572 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 }
574
575 cnx = &gEGLImpl[IMPL_HARDWARE];
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700576 if (cnx->dso == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 char value[PROPERTY_VALUE_MAX];
578 property_get("debug.egl.hw", value, "1");
579 if (atoi(value) != 0) {
580 cnx->hooks = &gHooks[IMPL_HARDWARE];
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700581 cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx->hooks);
582 if (cnx->dso) {
583 EGLDisplay dpy = cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
584 LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!");
Mathias Agopian94263d72009-08-24 21:47:13 -0700585 d->disp[IMPL_HARDWARE].dpy = dpy;
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700586 if (dpy == EGL_NO_DISPLAY) {
587 loader.close(cnx->dso);
588 cnx->dso = NULL;
589 }
590 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 } else {
592 LOGD("3D hardware acceleration is disabled");
593 }
594 }
Mathias Agopian94263d72009-08-24 21:47:13 -0700595
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700596 if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
597 return EGL_FALSE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 }
599
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700600 return EGL_TRUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601}
602
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700603EGLBoolean egl_init_drivers()
604{
605 EGLBoolean res;
606 pthread_mutex_lock(&gInitDriverMutex);
607 res = egl_init_drivers_locked();
608 pthread_mutex_unlock(&gInitDriverMutex);
609 return res;
610}
Mathias Agopian1473f462009-04-10 14:24:30 -0700611
612// ----------------------------------------------------------------------------
613}; // namespace android
614// ----------------------------------------------------------------------------
615
616using namespace android;
617
618EGLDisplay eglGetDisplay(NativeDisplayType display)
619{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700620 uint32_t index = uint32_t(display);
621 if (index >= NUM_DISPLAYS) {
622 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
623 }
624
625 if (egl_init_drivers() == EGL_FALSE) {
626 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
627 }
628
629 EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
630 return dpy;
Mathias Agopian1473f462009-04-10 14:24:30 -0700631}
632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633// ----------------------------------------------------------------------------
634// Initialization
635// ----------------------------------------------------------------------------
636
637EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
638{
639 egl_display_t * const dp = get_display(dpy);
640 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
641
642 if (android_atomic_inc(&dp->refs) > 0) {
643 if (major != NULL) *major = VERSION_MAJOR;
644 if (minor != NULL) *minor = VERSION_MINOR;
645 return EGL_TRUE;
646 }
647
648 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
649
650 // initialize each EGL and
651 // build our own extension string first, based on the extension we know
652 // and the extension supported by our client implementation
Mathias Agopian1473f462009-04-10 14:24:30 -0700653 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 egl_connection_t* const cnx = &gEGLImpl[i];
655 cnx->major = -1;
656 cnx->minor = -1;
657 if (!cnx->dso)
658 continue;
659
Mathias Agopian94263d72009-08-24 21:47:13 -0700660#if defined(ADRENO130)
661#warning "Adreno-130 eglInitialize() workaround"
662 /*
663 * The ADRENO 130 driver returns a different EGLDisplay each time
664 * eglGetDisplay() is called, but also makes the EGLDisplay invalid
665 * after eglTerminate() has been called, so that eglInitialize()
666 * cannot be called again. Therefore, we need to make sure to call
667 * eglGetDisplay() before calling eglInitialize();
668 */
669 if (i == IMPL_HARDWARE) {
670 dp->disp[i].dpy =
671 cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
672 }
673#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674
Mathias Agopian94263d72009-08-24 21:47:13 -0700675
676 EGLDisplay idpy = dp->disp[i].dpy;
677 if (cnx->hooks->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
Mathias Agopian94263d72009-08-24 21:47:13 -0700679 // i, idpy, cnx->major, cnx->minor, cnx);
680
681 // display is now initialized
682 dp->disp[i].state = egl_display_t::INITIALIZED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683
684 // get the query-strings for this display for each implementation
Mathias Agopian94263d72009-08-24 21:47:13 -0700685 dp->disp[i].queryString.vendor =
686 cnx->hooks->egl.eglQueryString(idpy, EGL_VENDOR);
687 dp->disp[i].queryString.version =
688 cnx->hooks->egl.eglQueryString(idpy, EGL_VERSION);
689 dp->disp[i].queryString.extensions =
690 cnx->hooks->egl.eglQueryString(idpy, EGL_EXTENSIONS);
691 dp->disp[i].queryString.clientApi =
692 cnx->hooks->egl.eglQueryString(idpy, EGL_CLIENT_APIS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693
694 } else {
Mathias Agopian94263d72009-08-24 21:47:13 -0700695 LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
696 egl_strerror(cnx->hooks->egl.eglGetError()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 }
698 }
699
700 EGLBoolean res = EGL_FALSE;
Mathias Agopian1473f462009-04-10 14:24:30 -0700701 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 egl_connection_t* const cnx = &gEGLImpl[i];
703 if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
704 EGLint n;
Mathias Agopian94263d72009-08-24 21:47:13 -0700705 if (cnx->hooks->egl.eglGetConfigs(dp->disp[i].dpy, 0, 0, &n)) {
706 dp->disp[i].config = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
707 if (dp->disp[i].config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800708 if (cnx->hooks->egl.eglGetConfigs(
Mathias Agopian94263d72009-08-24 21:47:13 -0700709 dp->disp[i].dpy, dp->disp[i].config, n,
710 &dp->disp[i].numConfigs))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 {
712 // sort the configurations so we can do binary searches
Mathias Agopian94263d72009-08-24 21:47:13 -0700713 qsort( dp->disp[i].config,
714 dp->disp[i].numConfigs,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 sizeof(EGLConfig), cmp_configs);
716
717 dp->numTotalConfigs += n;
718 res = EGL_TRUE;
719 }
720 }
721 }
722 }
723 }
724
725 if (res == EGL_TRUE) {
726 if (major != NULL) *major = VERSION_MAJOR;
727 if (minor != NULL) *minor = VERSION_MINOR;
728 return EGL_TRUE;
729 }
730 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
731}
732
733EGLBoolean eglTerminate(EGLDisplay dpy)
734{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700735 // NOTE: don't unload the drivers b/c some APIs can be called
736 // after eglTerminate() has been called. eglTerminate() only
737 // terminates an EGLDisplay, not a EGL itself.
738
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 egl_display_t* const dp = get_display(dpy);
740 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
741 if (android_atomic_dec(&dp->refs) != 1)
742 return EGL_TRUE;
Mathias Agopian9d17c052009-05-28 17:39:03 -0700743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 EGLBoolean res = EGL_FALSE;
Mathias Agopian1473f462009-04-10 14:24:30 -0700745 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746 egl_connection_t* const cnx = &gEGLImpl[i];
Mathias Agopian94263d72009-08-24 21:47:13 -0700747 if (cnx->dso && dp->disp[i].state == egl_display_t::INITIALIZED) {
748 if (cnx->hooks->egl.eglTerminate(dp->disp[i].dpy) == EGL_FALSE) {
749 LOGW("%d: eglTerminate(%p) failed (%s)", i, dp->disp[i].dpy,
750 egl_strerror(cnx->hooks->egl.eglGetError()));
751 }
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700752 // REVISIT: it's unclear what to do if eglTerminate() fails
Mathias Agopian94263d72009-08-24 21:47:13 -0700753 free(dp->disp[i].config);
754
755 dp->disp[i].numConfigs = 0;
756 dp->disp[i].config = 0;
757 dp->disp[i].state = egl_display_t::TERMINATED;
758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 res = EGL_TRUE;
760 }
761 }
Mathias Agopian4a34e882009-08-21 02:18:25 -0700762
763 // TODO: all egl_object_t should be marked for termination
764
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 dp->numTotalConfigs = 0;
766 clearTLS();
767 return res;
768}
769
770// ----------------------------------------------------------------------------
771// configuration
772// ----------------------------------------------------------------------------
773
774EGLBoolean eglGetConfigs( EGLDisplay dpy,
775 EGLConfig *configs,
776 EGLint config_size, EGLint *num_config)
777{
778 egl_display_t const * const dp = get_display(dpy);
779 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
780
781 GLint numConfigs = dp->numTotalConfigs;
782 if (!configs) {
783 *num_config = numConfigs;
784 return EGL_TRUE;
785 }
786 GLint n = 0;
Mathias Agopian1473f462009-04-10 14:24:30 -0700787 for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) {
Mathias Agopian94263d72009-08-24 21:47:13 -0700788 for (int i=0 ; i<dp->disp[j].numConfigs && config_size ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 *configs++ = MAKE_CONFIG(j, i);
790 config_size--;
791 n++;
792 }
793 }
794
795 *num_config = n;
796 return EGL_TRUE;
797}
798
799EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
800 EGLConfig *configs, EGLint config_size,
801 EGLint *num_config)
802{
803 egl_display_t const * const dp = get_display(dpy);
804 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
805
Jack Palevich1badb712009-03-25 15:12:17 -0700806 if (num_config==0) {
807 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808 }
809
810 EGLint n;
811 EGLBoolean res = EGL_FALSE;
812 *num_config = 0;
813
814
815 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
816 // to do this, we have to go through the attrib_list array once
817 // to figure out both its size and if it contains an EGL_CONFIG_ID
818 // key. If so, the full array is copied and patched.
819 // NOTE: we assume that there can be only one occurrence
820 // of EGL_CONFIG_ID.
821
822 EGLint patch_index = -1;
823 GLint attr;
824 size_t size = 0;
Mathias Agopianab1cf3e2009-07-09 17:33:15 -0700825 while ((attr=attrib_list[size]) != EGL_NONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 if (attr == EGL_CONFIG_ID)
827 patch_index = size;
828 size += 2;
829 }
830 if (patch_index >= 0) {
831 size += 2; // we need copy the sentinel as well
832 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
833 if (new_list == 0)
834 return setError(EGL_BAD_ALLOC, EGL_FALSE);
835 memcpy(new_list, attrib_list, size*sizeof(EGLint));
836
837 // patch the requested EGL_CONFIG_ID
838 int i, index;
839 EGLint& configId(new_list[patch_index+1]);
840 uniqueIdToConfig(dp, configId, i, index);
841
842 egl_connection_t* const cnx = &gEGLImpl[i];
843 if (cnx->dso) {
844 cnx->hooks->egl.eglGetConfigAttrib(
Mathias Agopian94263d72009-08-24 21:47:13 -0700845 dp->disp[i].dpy, dp->disp[i].config[index],
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 EGL_CONFIG_ID, &configId);
847
848 // and switch to the new list
849 attrib_list = const_cast<const EGLint *>(new_list);
850
851 // At this point, the only configuration that can match is
852 // dp->configs[i][index], however, we don't know if it would be
853 // rejected because of the other attributes, so we do have to call
854 // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
855 // through all the EGLimpl[].
856 // We also know we can only get a single config back, and we know
857 // which one.
858
859 res = cnx->hooks->egl.eglChooseConfig(
Mathias Agopian94263d72009-08-24 21:47:13 -0700860 dp->disp[i].dpy, attrib_list, configs, config_size, &n);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 if (res && n>0) {
862 // n has to be 0 or 1, by construction, and we already know
863 // which config it will return (since there can be only one).
Jack Palevich1badb712009-03-25 15:12:17 -0700864 if (configs) {
865 configs[0] = MAKE_CONFIG(i, index);
866 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 *num_config = 1;
868 }
869 }
870
871 free(const_cast<EGLint *>(attrib_list));
872 return res;
873 }
874
Mathias Agopian1473f462009-04-10 14:24:30 -0700875 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 egl_connection_t* const cnx = &gEGLImpl[i];
877 if (cnx->dso) {
878 if (cnx->hooks->egl.eglChooseConfig(
Mathias Agopian94263d72009-08-24 21:47:13 -0700879 dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
Jack Palevich1badb712009-03-25 15:12:17 -0700880 if (configs) {
881 // now we need to convert these client EGLConfig to our
882 // internal EGLConfig format. This is done in O(n log n).
883 for (int j=0 ; j<n ; j++) {
884 int index = binarySearch<EGLConfig>(
Mathias Agopian94263d72009-08-24 21:47:13 -0700885 dp->disp[i].config, 0,
886 dp->disp[i].numConfigs-1, configs[j]);
Jack Palevich1badb712009-03-25 15:12:17 -0700887 if (index >= 0) {
888 if (configs) {
889 configs[j] = MAKE_CONFIG(i, index);
890 }
891 } else {
892 return setError(EGL_BAD_CONFIG, EGL_FALSE);
893 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 }
Jack Palevich1badb712009-03-25 15:12:17 -0700895 configs += n;
896 config_size -= n;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 *num_config += n;
899 res = EGL_TRUE;
900 }
901 }
902 }
903 return res;
904}
905
906EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
907 EGLint attribute, EGLint *value)
908{
909 egl_display_t const* dp = 0;
910 int i=0, index=0;
911 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
912 if (!cnx) return EGL_FALSE;
913
914 if (attribute == EGL_CONFIG_ID) {
915 // EGL_CONFIG_IDs must be unique, just use the order of the selected
916 // EGLConfig.
917 *value = configToUniqueId(dp, i, index);
918 return EGL_TRUE;
919 }
920 return cnx->hooks->egl.eglGetConfigAttrib(
Mathias Agopian94263d72009-08-24 21:47:13 -0700921 dp->disp[i].dpy, dp->disp[i].config[index], attribute, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922}
923
924// ----------------------------------------------------------------------------
925// surfaces
926// ----------------------------------------------------------------------------
927
928EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
929 NativeWindowType window,
930 const EGLint *attrib_list)
931{
932 egl_display_t const* dp = 0;
933 int i=0, index=0;
934 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
935 if (cnx) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
Mathias Agopian94263d72009-08-24 21:47:13 -0700937 dp->disp[i].dpy, dp->disp[i].config[index], window, attrib_list);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938 if (surface != EGL_NO_SURFACE) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700939 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 return s;
941 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 }
943 return EGL_NO_SURFACE;
944}
945
946EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
947 NativePixmapType pixmap,
948 const EGLint *attrib_list)
949{
950 egl_display_t const* dp = 0;
951 int i=0, index=0;
952 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
953 if (cnx) {
954 EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
Mathias Agopian94263d72009-08-24 21:47:13 -0700955 dp->disp[i].dpy, dp->disp[i].config[index], pixmap, attrib_list);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 if (surface != EGL_NO_SURFACE) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700957 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 return s;
959 }
960 }
961 return EGL_NO_SURFACE;
962}
963
964EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
965 const EGLint *attrib_list)
966{
967 egl_display_t const* dp = 0;
968 int i=0, index=0;
969 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
970 if (cnx) {
971 EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
Mathias Agopian94263d72009-08-24 21:47:13 -0700972 dp->disp[i].dpy, dp->disp[i].config[index], attrib_list);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 if (surface != EGL_NO_SURFACE) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700974 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 return s;
976 }
977 }
978 return EGL_NO_SURFACE;
979}
980
981EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
982{
Mathias Agopian4a34e882009-08-21 02:18:25 -0700983 SurfaceRef _s(surface);
984 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
985
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 if (!validate_display_surface(dpy, surface))
987 return EGL_FALSE;
988 egl_display_t const * const dp = get_display(dpy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989
Mathias Agopian4a34e882009-08-21 02:18:25 -0700990 egl_surface_t * const s = get_surface(surface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
Mathias Agopian94263d72009-08-24 21:47:13 -0700992 dp->disp[s->impl].dpy, s->surface);
Mathias Agopian4a34e882009-08-21 02:18:25 -0700993 if (result == EGL_TRUE) {
994 _s.terminate();
995 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 return result;
997}
998
999EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
1000 EGLint attribute, EGLint *value)
1001{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001002 SurfaceRef _s(surface);
1003 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1004
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 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(
Mathias Agopian94263d72009-08-24 21:47:13 -07001011 dp->disp[s->impl].dpy, s->surface, attribute, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012}
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(
Mathias Agopian94263d72009-08-24 21:47:13 -07001026 dp->disp[i].dpy, dp->disp[i].config[index],
1027 share_list, attrib_list);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 if (context != EGL_NO_CONTEXT) {
1029 egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
1030 return c;
1031 }
1032 }
1033 return EGL_NO_CONTEXT;
1034}
1035
1036EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1037{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001038 ContextRef _c(ctx);
1039 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 if (!validate_display_context(dpy, ctx))
1042 return EGL_FALSE;
1043 egl_display_t const * const dp = get_display(dpy);
1044 egl_context_t * const c = get_context(ctx);
1045 EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
Mathias Agopian94263d72009-08-24 21:47:13 -07001046 dp->disp[c->impl].dpy, c->context);
Mathias Agopian4a34e882009-08-21 02:18:25 -07001047 if (result == EGL_TRUE) {
1048 _c.terminate();
1049 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 return result;
1051}
1052
1053EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
1054 EGLSurface read, EGLContext ctx)
1055{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001056 // get a reference to the object passed in
1057 ContextRef _c(ctx);
1058 SurfaceRef _d(draw);
1059 SurfaceRef _r(read);
1060
1061 // validate the display and the context (if not EGL_NO_CONTEXT)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 egl_display_t const * const dp = get_display(dpy);
1063 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian4a34e882009-08-21 02:18:25 -07001064 if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
1065 // EGL_NO_CONTEXT is valid
1066 return EGL_FALSE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 }
1068
Mathias Agopian4a34e882009-08-21 02:18:25 -07001069 // these are the underlying implementation's object
1070 EGLContext impl_ctx = EGL_NO_CONTEXT;
Mathias Agopian3a7e1832009-06-25 00:01:11 -07001071 EGLSurface impl_draw = EGL_NO_SURFACE;
1072 EGLSurface impl_read = EGL_NO_SURFACE;
Mathias Agopian4a34e882009-08-21 02:18:25 -07001073
1074 // these are our objects structs passed in
1075 egl_context_t * c = NULL;
1076 egl_surface_t const * d = NULL;
1077 egl_surface_t const * r = NULL;
1078
1079 // these are the current objects structs
1080 egl_context_t * cur_c = get_context(getContext());
1081 egl_surface_t * cur_r = NULL;
1082 egl_surface_t * cur_d = NULL;
1083
1084 if (ctx != EGL_NO_CONTEXT) {
1085 c = get_context(ctx);
1086 cur_r = get_surface(c->read);
1087 cur_d = get_surface(c->draw);
1088 impl_ctx = c->context;
1089 } else {
1090 // no context given, use the implementation of the current context
1091 if (cur_c == NULL) {
1092 // no current context
1093 if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
1094 // calling eglMakeCurrent( ..., EGL_NO_CONTEXT, !=0, !=0);
1095 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1096 }
1097 // not an error, there is just not current context.
1098 return EGL_TRUE;
1099 }
1100 }
1101
1102 // retrieve the underlying implementation's draw EGLSurface
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 if (draw != EGL_NO_SURFACE) {
Mathias Agopian4a34e882009-08-21 02:18:25 -07001104 d = get_surface(draw);
Mathias Agopian94263d72009-08-24 21:47:13 -07001105 // make sure the EGLContext and EGLSurface passed in are for
1106 // the same driver
Mathias Agopian4a34e882009-08-21 02:18:25 -07001107 if (c && d->impl != c->impl)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 return setError(EGL_BAD_MATCH, EGL_FALSE);
Mathias Agopian3a7e1832009-06-25 00:01:11 -07001109 impl_draw = d->surface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 }
Mathias Agopian4a34e882009-08-21 02:18:25 -07001111
1112 // retrieve the underlying implementation's read EGLSurface
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 if (read != EGL_NO_SURFACE) {
Mathias Agopian4a34e882009-08-21 02:18:25 -07001114 r = get_surface(read);
Mathias Agopian94263d72009-08-24 21:47:13 -07001115 // make sure the EGLContext and EGLSurface passed in are for
1116 // the same driver
Mathias Agopian4a34e882009-08-21 02:18:25 -07001117 if (c && r->impl != c->impl)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118 return setError(EGL_BAD_MATCH, EGL_FALSE);
Mathias Agopian3a7e1832009-06-25 00:01:11 -07001119 impl_read = r->surface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 }
Mathias Agopian4a34e882009-08-21 02:18:25 -07001121
1122 EGLBoolean result;
1123
1124 if (c) {
1125 result = c->cnx->hooks->egl.eglMakeCurrent(
Mathias Agopian94263d72009-08-24 21:47:13 -07001126 dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
Mathias Agopian4a34e882009-08-21 02:18:25 -07001127 } else {
1128 result = cur_c->cnx->hooks->egl.eglMakeCurrent(
Mathias Agopian94263d72009-08-24 21:47:13 -07001129 dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
Mathias Agopian4a34e882009-08-21 02:18:25 -07001130 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001131
1132 if (result == EGL_TRUE) {
Mathias Agopian4a34e882009-08-21 02:18:25 -07001133 // by construction, these are either 0 or valid (possibly terminated)
1134 // it should be impossible for these to be invalid
1135 ContextRef _cur_c(cur_c);
1136 SurfaceRef _cur_r(cur_r);
1137 SurfaceRef _cur_d(cur_d);
1138
1139 // cur_c has to be valid here (but could be terminated)
1140 if (ctx != EGL_NO_CONTEXT) {
1141 setGlThreadSpecific(c->cnx->hooks);
1142 setContext(ctx);
1143 _c.acquire();
1144 } else {
1145 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
1146 setContext(EGL_NO_CONTEXT);
1147 }
1148 _cur_c.release();
1149
1150 _r.acquire();
1151 _cur_r.release();
1152 if (c) c->read = read;
1153
1154 _d.acquire();
1155 _cur_d.release();
1156 if (c) c->draw = draw;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 }
1158 return result;
1159}
1160
1161
1162EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1163 EGLint attribute, EGLint *value)
1164{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001165 ContextRef _c(ctx);
1166 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1167
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001168 if (!validate_display_context(dpy, ctx))
1169 return EGL_FALSE;
1170
1171 egl_display_t const * const dp = get_display(dpy);
1172 egl_context_t * const c = get_context(ctx);
1173
1174 return c->cnx->hooks->egl.eglQueryContext(
Mathias Agopian94263d72009-08-24 21:47:13 -07001175 dp->disp[c->impl].dpy, c->context, attribute, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176}
1177
1178EGLContext eglGetCurrentContext(void)
1179{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001180 // could be called before eglInitialize(), but we wouldn't have a context
1181 // then, and this function would correctly return EGL_NO_CONTEXT.
1182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001183 EGLContext ctx = getContext();
1184 return ctx;
1185}
1186
1187EGLSurface eglGetCurrentSurface(EGLint readdraw)
1188{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001189 // could be called before eglInitialize(), but we wouldn't have a context
1190 // then, and this function would correctly return EGL_NO_SURFACE.
1191
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192 EGLContext ctx = getContext();
1193 if (ctx) {
1194 egl_context_t const * const c = get_context(ctx);
1195 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1196 switch (readdraw) {
1197 case EGL_READ: return c->read;
1198 case EGL_DRAW: return c->draw;
1199 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1200 }
1201 }
1202 return EGL_NO_SURFACE;
1203}
1204
1205EGLDisplay eglGetCurrentDisplay(void)
1206{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001207 // could be called before eglInitialize(), but we wouldn't have a context
1208 // then, and this function would correctly return EGL_NO_DISPLAY.
1209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 EGLContext ctx = getContext();
1211 if (ctx) {
1212 egl_context_t const * const c = get_context(ctx);
1213 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1214 return c->dpy;
1215 }
1216 return EGL_NO_DISPLAY;
1217}
1218
1219EGLBoolean eglWaitGL(void)
1220{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001221 // could be called before eglInitialize(), but we wouldn't have a context
1222 // then, and this function would return GL_TRUE, which isn't wrong.
1223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001224 EGLBoolean res = EGL_TRUE;
1225 EGLContext ctx = getContext();
1226 if (ctx) {
1227 egl_context_t const * const c = get_context(ctx);
1228 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1229 if (uint32_t(c->impl)>=2)
1230 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1231 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1232 if (!cnx->dso)
1233 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1234 res = cnx->hooks->egl.eglWaitGL();
1235 }
1236 return res;
1237}
1238
1239EGLBoolean eglWaitNative(EGLint engine)
1240{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001241 // could be called before eglInitialize(), but we wouldn't have a context
1242 // then, and this function would return GL_TRUE, which isn't wrong.
1243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001244 EGLBoolean res = EGL_TRUE;
1245 EGLContext ctx = getContext();
1246 if (ctx) {
1247 egl_context_t const * const c = get_context(ctx);
1248 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1249 if (uint32_t(c->impl)>=2)
1250 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1251 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1252 if (!cnx->dso)
1253 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1254 res = cnx->hooks->egl.eglWaitNative(engine);
1255 }
1256 return res;
1257}
1258
1259EGLint eglGetError(void)
1260{
1261 EGLint result = EGL_SUCCESS;
Mathias Agopian1473f462009-04-10 14:24:30 -07001262 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 EGLint err = EGL_SUCCESS;
1264 egl_connection_t* const cnx = &gEGLImpl[i];
1265 if (cnx->dso)
1266 err = cnx->hooks->egl.eglGetError();
1267 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1268 result = err;
1269 }
1270 if (result == EGL_SUCCESS)
1271 result = getError();
1272 return result;
1273}
1274
Mathias Agopian1473f462009-04-10 14:24:30 -07001275__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276{
Mathias Agopian1473f462009-04-10 14:24:30 -07001277 // eglGetProcAddress() could be the very first function called
1278 // in which case we must make sure we've initialized ourselves, this
1279 // happens the first time egl_get_display() is called.
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001280
1281 if (egl_init_drivers() == EGL_FALSE) {
1282 setError(EGL_BAD_PARAMETER, NULL);
1283 return NULL;
1284 }
Mathias Agopian1473f462009-04-10 14:24:30 -07001285
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 __eglMustCastToProperFunctionPointerType addr;
1287 addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1288 if (addr) return addr;
1289
1290 return NULL; // TODO: finish implementation below
1291
1292 addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1293 if (addr) return addr;
1294
1295 addr = 0;
1296 int slot = -1;
Mathias Agopian1473f462009-04-10 14:24:30 -07001297 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298 egl_connection_t* const cnx = &gEGLImpl[i];
1299 if (cnx->dso) {
1300 if (cnx->hooks->egl.eglGetProcAddress) {
1301 addr = cnx->hooks->egl.eglGetProcAddress(procname);
1302 if (addr) {
1303 if (slot == -1) {
1304 slot = 0; // XXX: find free slot
1305 if (slot == -1) {
1306 addr = 0;
1307 break;
1308 }
1309 }
1310 cnx->hooks->ext.extensions[slot] = addr;
1311 }
1312 }
1313 }
1314 }
1315
1316 if (slot >= 0) {
1317 addr = 0; // XXX: address of stub 'slot'
1318 gGLExtentionMap[slot].name = strdup(procname);
1319 gGLExtentionMap[slot].address = addr;
1320 }
1321
1322 return addr;
1323
1324
1325 /*
1326 * TODO: For OpenGL ES extensions, we must generate a stub
1327 * that looks like
1328 * mov r12, #0xFFFF0FFF
1329 * ldr r12, [r12, #-15]
1330 * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
1331 * mov r12, [r12, #api_offset]
1332 * ldrne pc, r12
1333 * mov pc, #unsupported_extension
1334 *
1335 * and write the address of the extension in *all*
1336 * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1337 *
1338 */
1339}
1340
1341EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1342{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001343 SurfaceRef _s(draw);
1344 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001346 if (!validate_display_surface(dpy, draw))
1347 return EGL_FALSE;
1348 egl_display_t const * const dp = get_display(dpy);
1349 egl_surface_t const * const s = get_surface(draw);
Mathias Agopian94263d72009-08-24 21:47:13 -07001350 return s->cnx->hooks->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351}
1352
1353EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1354 NativePixmapType target)
1355{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001356 SurfaceRef _s(surface);
1357 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001359 if (!validate_display_surface(dpy, surface))
1360 return EGL_FALSE;
1361 egl_display_t const * const dp = get_display(dpy);
1362 egl_surface_t const * const s = get_surface(surface);
1363 return s->cnx->hooks->egl.eglCopyBuffers(
Mathias Agopian94263d72009-08-24 21:47:13 -07001364 dp->disp[s->impl].dpy, s->surface, target);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365}
1366
1367const char* eglQueryString(EGLDisplay dpy, EGLint name)
1368{
1369 egl_display_t const * const dp = get_display(dpy);
1370 switch (name) {
1371 case EGL_VENDOR:
1372 return gVendorString;
1373 case EGL_VERSION:
1374 return gVersionString;
1375 case EGL_EXTENSIONS:
1376 return gExtensionString;
1377 case EGL_CLIENT_APIS:
1378 return gClientApiString;
1379 }
1380 return setError(EGL_BAD_PARAMETER, (const char *)0);
1381}
1382
1383
1384// ----------------------------------------------------------------------------
1385// EGL 1.1
1386// ----------------------------------------------------------------------------
1387
1388EGLBoolean eglSurfaceAttrib(
1389 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1390{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001391 SurfaceRef _s(surface);
1392 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394 if (!validate_display_surface(dpy, surface))
1395 return EGL_FALSE;
1396 egl_display_t const * const dp = get_display(dpy);
1397 egl_surface_t const * const s = get_surface(surface);
1398 if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1399 return s->cnx->hooks->egl.eglSurfaceAttrib(
Mathias Agopian94263d72009-08-24 21:47:13 -07001400 dp->disp[s->impl].dpy, s->surface, attribute, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 }
1402 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1403}
1404
1405EGLBoolean eglBindTexImage(
1406 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1407{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001408 SurfaceRef _s(surface);
1409 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 if (!validate_display_surface(dpy, surface))
1412 return EGL_FALSE;
1413 egl_display_t const * const dp = get_display(dpy);
1414 egl_surface_t const * const s = get_surface(surface);
1415 if (s->cnx->hooks->egl.eglBindTexImage) {
1416 return s->cnx->hooks->egl.eglBindTexImage(
Mathias Agopian94263d72009-08-24 21:47:13 -07001417 dp->disp[s->impl].dpy, s->surface, buffer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 }
1419 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1420}
1421
1422EGLBoolean eglReleaseTexImage(
1423 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1424{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001425 SurfaceRef _s(surface);
1426 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 if (!validate_display_surface(dpy, surface))
1429 return EGL_FALSE;
1430 egl_display_t const * const dp = get_display(dpy);
1431 egl_surface_t const * const s = get_surface(surface);
1432 if (s->cnx->hooks->egl.eglReleaseTexImage) {
1433 return s->cnx->hooks->egl.eglReleaseTexImage(
Mathias Agopian94263d72009-08-24 21:47:13 -07001434 dp->disp[s->impl].dpy, s->surface, buffer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001435 }
1436 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1437}
1438
1439EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1440{
1441 egl_display_t * const dp = get_display(dpy);
1442 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1443
1444 EGLBoolean res = EGL_TRUE;
Mathias Agopian1473f462009-04-10 14:24:30 -07001445 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001446 egl_connection_t* const cnx = &gEGLImpl[i];
1447 if (cnx->dso) {
1448 if (cnx->hooks->egl.eglSwapInterval) {
Mathias Agopian94263d72009-08-24 21:47:13 -07001449 if (cnx->hooks->egl.eglSwapInterval(
1450 dp->disp[i].dpy, interval) == EGL_FALSE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 res = EGL_FALSE;
1452 }
1453 }
1454 }
1455 }
1456 return res;
1457}
1458
1459
1460// ----------------------------------------------------------------------------
1461// EGL 1.2
1462// ----------------------------------------------------------------------------
1463
1464EGLBoolean eglWaitClient(void)
1465{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001466 // could be called before eglInitialize(), but we wouldn't have a context
1467 // then, and this function would return GL_TRUE, which isn't wrong.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 EGLBoolean res = EGL_TRUE;
1469 EGLContext ctx = getContext();
1470 if (ctx) {
1471 egl_context_t const * const c = get_context(ctx);
1472 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1473 if (uint32_t(c->impl)>=2)
1474 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1475 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1476 if (!cnx->dso)
1477 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1478 if (cnx->hooks->egl.eglWaitClient) {
1479 res = cnx->hooks->egl.eglWaitClient();
1480 } else {
1481 res = cnx->hooks->egl.eglWaitGL();
1482 }
1483 }
1484 return res;
1485}
1486
1487EGLBoolean eglBindAPI(EGLenum api)
1488{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001489 if (egl_init_drivers() == EGL_FALSE) {
1490 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1491 }
1492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001493 // bind this API on all EGLs
1494 EGLBoolean res = EGL_TRUE;
Mathias Agopian1473f462009-04-10 14:24:30 -07001495 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001496 egl_connection_t* const cnx = &gEGLImpl[i];
1497 if (cnx->dso) {
1498 if (cnx->hooks->egl.eglBindAPI) {
1499 if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1500 res = EGL_FALSE;
1501 }
1502 }
1503 }
1504 }
1505 return res;
1506}
1507
1508EGLenum eglQueryAPI(void)
1509{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001510 if (egl_init_drivers() == EGL_FALSE) {
1511 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1512 }
1513
Mathias Agopian1473f462009-04-10 14:24:30 -07001514 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 egl_connection_t* const cnx = &gEGLImpl[i];
1516 if (cnx->dso) {
1517 if (cnx->hooks->egl.eglQueryAPI) {
1518 // the first one we find is okay, because they all
1519 // should be the same
1520 return cnx->hooks->egl.eglQueryAPI();
1521 }
1522 }
1523 }
1524 // or, it can only be OpenGL ES
1525 return EGL_OPENGL_ES_API;
1526}
1527
1528EGLBoolean eglReleaseThread(void)
1529{
Mathias Agopian1473f462009-04-10 14:24:30 -07001530 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001531 egl_connection_t* const cnx = &gEGLImpl[i];
1532 if (cnx->dso) {
1533 if (cnx->hooks->egl.eglReleaseThread) {
1534 cnx->hooks->egl.eglReleaseThread();
1535 }
1536 }
1537 }
1538 clearTLS();
1539 return EGL_TRUE;
1540}
1541
1542EGLSurface eglCreatePbufferFromClientBuffer(
1543 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1544 EGLConfig config, const EGLint *attrib_list)
1545{
1546 egl_display_t const* dp = 0;
1547 int i=0, index=0;
1548 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1549 if (!cnx) return EGL_FALSE;
1550 if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1551 return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
Mathias Agopian94263d72009-08-24 21:47:13 -07001552 dp->disp[i].dpy, buftype, buffer,
1553 dp->disp[i].config[index], attrib_list);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 }
1555 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1556}
Mathias Agopian1473f462009-04-10 14:24:30 -07001557
1558// ----------------------------------------------------------------------------
1559// EGL_EGLEXT_VERSION 3
1560// ----------------------------------------------------------------------------
1561
1562EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1563 const EGLint *attrib_list)
1564{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001565 SurfaceRef _s(surface);
1566 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1567
Mathias Agopian1473f462009-04-10 14:24:30 -07001568 if (!validate_display_surface(dpy, surface))
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001569 return EGL_FALSE;
Mathias Agopian1473f462009-04-10 14:24:30 -07001570
1571 egl_display_t const * const dp = get_display(dpy);
1572 egl_surface_t const * const s = get_surface(surface);
1573
1574 if (s->cnx->hooks->egl.eglLockSurfaceKHR) {
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001575 return s->cnx->hooks->egl.eglLockSurfaceKHR(
Mathias Agopian94263d72009-08-24 21:47:13 -07001576 dp->disp[s->impl].dpy, s->surface, attrib_list);
Mathias Agopian1473f462009-04-10 14:24:30 -07001577 }
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001578 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001579}
1580
1581EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1582{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001583 SurfaceRef _s(surface);
1584 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1585
Mathias Agopian1473f462009-04-10 14:24:30 -07001586 if (!validate_display_surface(dpy, surface))
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001587 return EGL_FALSE;
Mathias Agopian1473f462009-04-10 14:24:30 -07001588
1589 egl_display_t const * const dp = get_display(dpy);
1590 egl_surface_t const * const s = get_surface(surface);
1591
1592 if (s->cnx->hooks->egl.eglUnlockSurfaceKHR) {
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001593 return s->cnx->hooks->egl.eglUnlockSurfaceKHR(
Mathias Agopian94263d72009-08-24 21:47:13 -07001594 dp->disp[s->impl].dpy, s->surface);
Mathias Agopian1473f462009-04-10 14:24:30 -07001595 }
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001596 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001597}
1598
1599EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1600 EGLClientBuffer buffer, const EGLint *attrib_list)
1601{
1602 if (ctx != EGL_NO_CONTEXT) {
Mathias Agopian4a34e882009-08-21 02:18:25 -07001603 ContextRef _c(ctx);
1604 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
Mathias Agopian1473f462009-04-10 14:24:30 -07001605 if (!validate_display_context(dpy, ctx))
1606 return EGL_NO_IMAGE_KHR;
1607 egl_display_t const * const dp = get_display(dpy);
1608 egl_context_t * const c = get_context(ctx);
1609 // since we have an EGLContext, we know which implementation to use
1610 EGLImageKHR image = c->cnx->hooks->egl.eglCreateImageKHR(
Mathias Agopian94263d72009-08-24 21:47:13 -07001611 dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
Mathias Agopian1473f462009-04-10 14:24:30 -07001612 if (image == EGL_NO_IMAGE_KHR)
1613 return image;
1614
1615 egl_image_t* result = new egl_image_t(dpy, ctx);
1616 result->images[c->impl] = image;
1617 return (EGLImageKHR)result;
1618 } else {
1619 // EGL_NO_CONTEXT is a valid parameter
1620 egl_display_t const * const dp = get_display(dpy);
1621 if (dp == 0) {
1622 return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1623 }
1624 // since we don't have a way to know which implementation to call,
1625 // we're calling all of them
1626
1627 EGLImageKHR implImages[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
1628 bool success = false;
1629 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1630 egl_connection_t* const cnx = &gEGLImpl[i];
1631 implImages[i] = EGL_NO_IMAGE_KHR;
1632 if (cnx->dso) {
1633 if (cnx->hooks->egl.eglCreateImageKHR) {
1634 implImages[i] = cnx->hooks->egl.eglCreateImageKHR(
Mathias Agopian94263d72009-08-24 21:47:13 -07001635 dp->disp[i].dpy, ctx, target, buffer, attrib_list);
Mathias Agopian1473f462009-04-10 14:24:30 -07001636 if (implImages[i] != EGL_NO_IMAGE_KHR) {
1637 success = true;
1638 }
1639 }
1640 }
1641 }
1642 if (!success)
1643 return EGL_NO_IMAGE_KHR;
1644
1645 egl_image_t* result = new egl_image_t(dpy, ctx);
1646 memcpy(result->images, implImages, sizeof(implImages));
1647 return (EGLImageKHR)result;
1648 }
1649}
1650
1651EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1652{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001653 egl_display_t const * const dp = get_display(dpy);
Mathias Agopian1473f462009-04-10 14:24:30 -07001654 if (dp == 0) {
1655 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1656 }
1657
Mathias Agopian4a34e882009-08-21 02:18:25 -07001658 ImageRef _i(img);
1659 if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001660
Mathias Agopian4a34e882009-08-21 02:18:25 -07001661 egl_image_t* image = get_image(img);
Mathias Agopian1473f462009-04-10 14:24:30 -07001662 bool success = false;
1663 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1664 egl_connection_t* const cnx = &gEGLImpl[i];
1665 if (image->images[i] != EGL_NO_IMAGE_KHR) {
1666 if (cnx->dso) {
1667 if (cnx->hooks->egl.eglCreateImageKHR) {
1668 if (cnx->hooks->egl.eglDestroyImageKHR(
Mathias Agopian94263d72009-08-24 21:47:13 -07001669 dp->disp[i].dpy, image->images[i])) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001670 success = true;
1671 }
1672 }
1673 }
1674 }
1675 }
1676 if (!success)
1677 return EGL_FALSE;
1678
Mathias Agopian4a34e882009-08-21 02:18:25 -07001679 _i.terminate();
Mathias Agopian1473f462009-04-10 14:24:30 -07001680
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001681 return EGL_TRUE;
Mathias Agopian1473f462009-04-10 14:24:30 -07001682}
Mathias Agopian2e20bff2009-05-04 19:29:25 -07001683
1684
1685// ----------------------------------------------------------------------------
1686// ANDROID extensions
1687// ----------------------------------------------------------------------------
1688
1689EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1690 EGLint left, EGLint top, EGLint width, EGLint height)
1691{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001692 SurfaceRef _s(draw);
1693 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1694
Mathias Agopian2e20bff2009-05-04 19:29:25 -07001695 if (!validate_display_surface(dpy, draw))
1696 return EGL_FALSE;
1697 egl_display_t const * const dp = get_display(dpy);
1698 egl_surface_t const * const s = get_surface(draw);
1699 if (s->cnx->hooks->egl.eglSetSwapRectangleANDROID) {
Mathias Agopian94263d72009-08-24 21:47:13 -07001700 return s->cnx->hooks->egl.eglSetSwapRectangleANDROID(
1701 dp->disp[s->impl].dpy, s->surface, left, top, width, height);
Mathias Agopian2e20bff2009-05-04 19:29:25 -07001702 }
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001703 return setError(EGL_BAD_DISPLAY, NULL);
Mathias Agopian2e20bff2009-05-04 19:29:25 -07001704}
1705
Mathias Agopianc1e3ec52009-06-24 22:37:39 -07001706EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
1707{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001708 SurfaceRef _s(draw);
1709 if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLClientBuffer*)0);
1710
Mathias Agopianc1e3ec52009-06-24 22:37:39 -07001711 if (!validate_display_surface(dpy, draw))
1712 return 0;
1713 egl_display_t const * const dp = get_display(dpy);
1714 egl_surface_t const * const s = get_surface(draw);
1715 if (s->cnx->hooks->egl.eglGetRenderBufferANDROID) {
Mathias Agopian94263d72009-08-24 21:47:13 -07001716 return s->cnx->hooks->egl.eglGetRenderBufferANDROID(
1717 dp->disp[s->impl].dpy, s->surface);
Mathias Agopianc1e3ec52009-06-24 22:37:39 -07001718 }
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001719 return setError(EGL_BAD_DISPLAY, (EGLClientBuffer*)0);
Mathias Agopianc1e3ec52009-06-24 22:37:39 -07001720}