blob: 5efecb064cb339472e653b9e07550208e2e35dd0 [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;
Mathias Agopian6fc56992009-10-14 02:06:37 -0700167 DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS];
Mathias Agopian94263d72009-08-24 21:47:13 -0700168 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,
Mathias Agopian6fc56992009-10-14 02:06:37 -0700198 int impl, egl_connection_t const* cnx, int version)
199 : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx),
200 version(version)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 {
202 }
203 EGLDisplay dpy;
204 EGLContext context;
205 EGLSurface read;
206 EGLSurface draw;
207 int impl;
208 egl_connection_t const* cnx;
Mathias Agopian6fc56992009-10-14 02:06:37 -0700209 int version;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210};
211
Mathias Agopian4a34e882009-08-21 02:18:25 -0700212struct egl_image_t : public egl_object_t
Mathias Agopian1473f462009-04-10 14:24:30 -0700213{
Mathias Agopian4a34e882009-08-21 02:18:25 -0700214 typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref;
215
Mathias Agopian1473f462009-04-10 14:24:30 -0700216 egl_image_t(EGLDisplay dpy, EGLContext context)
217 : dpy(dpy), context(context)
218 {
219 memset(images, 0, sizeof(images));
220 }
221 EGLDisplay dpy;
222 EGLConfig context;
Mathias Agopian6fc56992009-10-14 02:06:37 -0700223 EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS];
Mathias Agopian1473f462009-04-10 14:24:30 -0700224};
225
Mathias Agopian4a34e882009-08-21 02:18:25 -0700226typedef egl_surface_t::Ref SurfaceRef;
227typedef egl_context_t::Ref ContextRef;
228typedef egl_image_t::Ref ImageRef;
229
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230struct tls_t
231{
Mathias Agopian997d1072009-07-31 16:21:17 -0700232 tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 EGLint error;
234 EGLContext ctx;
Mathias Agopian997d1072009-07-31 16:21:17 -0700235 EGLBoolean logCallWithNoContext;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236};
237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238
239// ----------------------------------------------------------------------------
240
Mathias Agopian6fc56992009-10-14 02:06:37 -0700241egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242static egl_display_t gDisplay[NUM_DISPLAYS];
243static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
244static pthread_key_t gEGLThreadLocalStorageKey = -1;
245
246// ----------------------------------------------------------------------------
247
Mathias Agopian6fc56992009-10-14 02:06:37 -0700248EGLAPI gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS];
249EGLAPI gl_hooks_t gHooksNoContext;
Mathias Agopian3cc68d22009-05-13 00:19:22 -0700250EGLAPI pthread_key_t gGLWrapperKey = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251
252// ----------------------------------------------------------------------------
253
254static __attribute__((noinline))
255const char *egl_strerror(EGLint err)
256{
257 switch (err){
258 case EGL_SUCCESS: return "EGL_SUCCESS";
259 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
260 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
261 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
262 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
263 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
264 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
265 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
266 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
267 case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
268 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
269 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
270 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
271 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
272 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
273 default: return "UNKNOWN";
274 }
275}
276
277static __attribute__((noinline))
278void clearTLS() {
279 if (gEGLThreadLocalStorageKey != -1) {
280 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
281 if (tls) {
282 delete tls;
283 pthread_setspecific(gEGLThreadLocalStorageKey, 0);
284 }
285 }
286}
287
288static tls_t* getTLS()
289{
290 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
291 if (tls == 0) {
292 tls = new tls_t;
293 pthread_setspecific(gEGLThreadLocalStorageKey, tls);
294 }
295 return tls;
296}
297
298template<typename T>
299static __attribute__((noinline))
300T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
301 if (gEGLThreadLocalStorageKey == -1) {
302 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
303 if (gEGLThreadLocalStorageKey == -1)
304 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
305 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
306 }
307 tls_t* tls = getTLS();
308 if (tls->error != error) {
309 LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
310 tls->error = error;
311 }
312 return returnValue;
313}
314
315static __attribute__((noinline))
316GLint getError() {
317 if (gEGLThreadLocalStorageKey == -1)
318 return EGL_SUCCESS;
319 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
320 if (!tls) return EGL_SUCCESS;
321 GLint error = tls->error;
322 tls->error = EGL_SUCCESS;
323 return error;
324}
325
326static __attribute__((noinline))
327void setContext(EGLContext ctx) {
328 if (gEGLThreadLocalStorageKey == -1) {
329 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
330 if (gEGLThreadLocalStorageKey == -1)
331 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
332 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
333 }
334 tls_t* tls = getTLS();
335 tls->ctx = ctx;
336}
337
338static __attribute__((noinline))
339EGLContext getContext() {
340 if (gEGLThreadLocalStorageKey == -1)
341 return EGL_NO_CONTEXT;
342 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
343 if (!tls) return EGL_NO_CONTEXT;
344 return tls->ctx;
345}
346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347/*****************************************************************************/
348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349template<typename T>
350static __attribute__((noinline))
351int binarySearch(
352 T const sortedArray[], int first, int last, T key)
353{
354 while (first <= last) {
355 int mid = (first + last) / 2;
356 if (key > sortedArray[mid]) {
357 first = mid + 1;
358 } else if (key < sortedArray[mid]) {
359 last = mid - 1;
360 } else {
361 return mid;
362 }
363 }
364 return -1;
365}
366
367static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
368{
369 // NOTE: this mapping works only if we have no more than two EGLimpl
Mathias Agopian94263d72009-08-24 21:47:13 -0700370 return (i>0 ? dp->disp[0].numConfigs : 0) + index;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371}
372
373static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
374 int& i, int& index)
375{
376 // NOTE: this mapping works only if we have no more than two EGLimpl
Mathias Agopian94263d72009-08-24 21:47:13 -0700377 size_t numConfigs = dp->disp[0].numConfigs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 i = configId / numConfigs;
379 index = configId % numConfigs;
380}
381
382static int cmp_configs(const void* a, const void *b)
383{
384 EGLConfig c0 = *(EGLConfig const *)a;
385 EGLConfig c1 = *(EGLConfig const *)b;
386 return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
387}
388
389struct extention_map_t {
390 const char* name;
391 __eglMustCastToProperFunctionPointerType address;
392};
393
394static const extention_map_t gExtentionMap[] = {
Mathias Agopian1473f462009-04-10 14:24:30 -0700395 { "eglLockSurfaceKHR",
396 (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
397 { "eglUnlockSurfaceKHR",
398 (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
399 { "eglCreateImageKHR",
400 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
401 { "eglDestroyImageKHR",
402 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
Mathias Agopianc1e3ec52009-06-24 22:37:39 -0700403 { "eglSetSwapRectangleANDROID",
404 (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
405 { "eglGetRenderBufferANDROID",
406 (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407};
408
409static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
410
411static void(*findProcAddress(const char* name,
412 const extention_map_t* map, size_t n))()
413{
414 for (uint32_t i=0 ; i<n ; i++) {
415 if (!strcmp(name, map[i].name)) {
416 return map[i].address;
417 }
418 }
419 return NULL;
420}
421
422// ----------------------------------------------------------------------------
423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424static void gl_no_context() {
Mathias Agopian997d1072009-07-31 16:21:17 -0700425 tls_t* tls = getTLS();
426 if (tls->logCallWithNoContext == EGL_TRUE) {
427 tls->logCallWithNoContext = EGL_FALSE;
428 LOGE("call to OpenGL ES API with no current context "
429 "(logged once per thread)");
430 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431}
Mathias Agopian997d1072009-07-31 16:21:17 -0700432
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433static void early_egl_init(void)
434{
435#if !USE_FAST_TLS_KEY
436 pthread_key_create(&gGLWrapperKey, NULL);
437#endif
438 uint32_t addr = (uint32_t)((void*)gl_no_context);
439 android_memset32(
Mathias Agopian6fc56992009-10-14 02:06:37 -0700440 (uint32_t*)(void*)&gHooksNoContext,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 addr,
Mathias Agopian6fc56992009-10-14 02:06:37 -0700442 sizeof(gHooksNoContext));
443 setGlThreadSpecific(&gHooksNoContext);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444}
445
446static pthread_once_t once_control = PTHREAD_ONCE_INIT;
447static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
448
449
450static inline
451egl_display_t* get_display(EGLDisplay dpy)
452{
453 uintptr_t index = uintptr_t(dpy)-1U;
454 return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
455}
456
Mathias Agopian1473f462009-04-10 14:24:30 -0700457template<typename NATIVE, typename EGL>
458static inline NATIVE* egl_to_native_cast(EGL arg) {
459 return reinterpret_cast<NATIVE*>(arg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460}
461
462static inline
Mathias Agopian1473f462009-04-10 14:24:30 -0700463egl_surface_t* get_surface(EGLSurface surface) {
464 return egl_to_native_cast<egl_surface_t>(surface);
465}
466
467static inline
468egl_context_t* get_context(EGLContext context) {
469 return egl_to_native_cast<egl_context_t>(context);
470}
471
472static inline
473egl_image_t* get_image(EGLImageKHR image) {
474 return egl_to_native_cast<egl_image_t>(image);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475}
476
477static egl_connection_t* validate_display_config(
478 EGLDisplay dpy, EGLConfig config,
479 egl_display_t const*& dp, int& impl, int& index)
480{
481 dp = get_display(dpy);
482 if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
483
484 impl = uintptr_t(config)>>24;
Mathias Agopian6fc56992009-10-14 02:06:37 -0700485 if (uint32_t(impl) >= IMPL_NUM_IMPLEMENTATIONS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
487 }
488 index = uintptr_t(config) & 0xFFFFFF;
Mathias Agopian94263d72009-08-24 21:47:13 -0700489 if (index >= dp->disp[impl].numConfigs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
491 }
492 egl_connection_t* const cnx = &gEGLImpl[impl];
493 if (cnx->dso == 0) {
494 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
495 }
496 return cnx;
497}
498
499static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
500{
501 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
502 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian4a34e882009-08-21 02:18:25 -0700503 if (!get_display(dpy)->isAlive())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian4a34e882009-08-21 02:18:25 -0700505 if (!get_context(ctx)->isAlive())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
507 return EGL_TRUE;
508}
509
510static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
511{
512 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
513 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian4a34e882009-08-21 02:18:25 -0700514 if (!get_display(dpy)->isAlive())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian4a34e882009-08-21 02:18:25 -0700516 if (!get_surface(surface)->isAlive())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 return setError(EGL_BAD_SURFACE, EGL_FALSE);
518 return EGL_TRUE;
519}
520
Mathias Agopian1473f462009-04-10 14:24:30 -0700521EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
522{
Mathias Agopian4a34e882009-08-21 02:18:25 -0700523 ImageRef _i(image);
524 if (!_i.get()) return EGL_NO_IMAGE_KHR;
525
Mathias Agopian1473f462009-04-10 14:24:30 -0700526 EGLContext context = getContext();
527 if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
528 return EGL_NO_IMAGE_KHR;
529
530 egl_context_t const * const c = get_context(context);
Mathias Agopian4a34e882009-08-21 02:18:25 -0700531 if (!c->isAlive())
Mathias Agopian1473f462009-04-10 14:24:30 -0700532 return EGL_NO_IMAGE_KHR;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533
Mathias Agopian1473f462009-04-10 14:24:30 -0700534 egl_image_t const * const i = get_image(image);
Mathias Agopian1473f462009-04-10 14:24:30 -0700535 return i->images[c->impl];
536}
537
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700538// ----------------------------------------------------------------------------
Mathias Agopian1473f462009-04-10 14:24:30 -0700539
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700540// this mutex protects:
Mathias Agopian94263d72009-08-24 21:47:13 -0700541// d->disp[]
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700542// egl_init_drivers_locked()
543//
544static pthread_mutex_t gInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
545
546EGLBoolean egl_init_drivers_locked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547{
548 if (sEarlyInitState) {
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700549 // initialized by static ctor. should be set here.
550 return EGL_FALSE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 }
552
Mathias Agopian9d17c052009-05-28 17:39:03 -0700553 // get our driver loader
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700554 Loader& loader(Loader::getInstance());
Mathias Agopian9d17c052009-05-28 17:39:03 -0700555
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700556 // dynamically load all our EGL implementations for all displays
557 // and retrieve the corresponding EGLDisplay
558 // if that fails, don't use this driver.
559 // TODO: currently we only deal with EGL_DEFAULT_DISPLAY
560 egl_connection_t* cnx;
561 egl_display_t* d = &gDisplay[0];
562
563 cnx = &gEGLImpl[IMPL_SOFTWARE];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 if (cnx->dso == 0) {
Mathias Agopian6fc56992009-10-14 02:06:37 -0700565 cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE];
566 cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE];
567 cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx);
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700568 if (cnx->dso) {
Mathias Agopian6fc56992009-10-14 02:06:37 -0700569 EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700570 LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
Mathias Agopian94263d72009-08-24 21:47:13 -0700571 d->disp[IMPL_SOFTWARE].dpy = dpy;
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700572 if (dpy == EGL_NO_DISPLAY) {
573 loader.close(cnx->dso);
574 cnx->dso = NULL;
575 }
576 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 }
578
579 cnx = &gEGLImpl[IMPL_HARDWARE];
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700580 if (cnx->dso == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 char value[PROPERTY_VALUE_MAX];
582 property_get("debug.egl.hw", value, "1");
583 if (atoi(value) != 0) {
Mathias Agopian6fc56992009-10-14 02:06:37 -0700584 cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_HARDWARE];
585 cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_HARDWARE];
586 cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx);
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700587 if (cnx->dso) {
Mathias Agopian6fc56992009-10-14 02:06:37 -0700588 EGLDisplay dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700589 LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!");
Mathias Agopian94263d72009-08-24 21:47:13 -0700590 d->disp[IMPL_HARDWARE].dpy = dpy;
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700591 if (dpy == EGL_NO_DISPLAY) {
592 loader.close(cnx->dso);
593 cnx->dso = NULL;
594 }
595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 } else {
597 LOGD("3D hardware acceleration is disabled");
598 }
599 }
Mathias Agopian94263d72009-08-24 21:47:13 -0700600
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700601 if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
602 return EGL_FALSE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 }
604
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700605 return EGL_TRUE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606}
607
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700608EGLBoolean egl_init_drivers()
609{
610 EGLBoolean res;
611 pthread_mutex_lock(&gInitDriverMutex);
612 res = egl_init_drivers_locked();
613 pthread_mutex_unlock(&gInitDriverMutex);
614 return res;
615}
Mathias Agopian1473f462009-04-10 14:24:30 -0700616
617// ----------------------------------------------------------------------------
618}; // namespace android
619// ----------------------------------------------------------------------------
620
621using namespace android;
622
623EGLDisplay eglGetDisplay(NativeDisplayType display)
624{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700625 uint32_t index = uint32_t(display);
626 if (index >= NUM_DISPLAYS) {
627 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
628 }
629
630 if (egl_init_drivers() == EGL_FALSE) {
631 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
632 }
633
634 EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
635 return dpy;
Mathias Agopian1473f462009-04-10 14:24:30 -0700636}
637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638// ----------------------------------------------------------------------------
639// Initialization
640// ----------------------------------------------------------------------------
641
642EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
643{
644 egl_display_t * const dp = get_display(dpy);
645 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
646
647 if (android_atomic_inc(&dp->refs) > 0) {
648 if (major != NULL) *major = VERSION_MAJOR;
649 if (minor != NULL) *minor = VERSION_MINOR;
650 return EGL_TRUE;
651 }
652
Mathias Agopian6fc56992009-10-14 02:06:37 -0700653 setGlThreadSpecific(&gHooksNoContext);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654
655 // initialize each EGL and
656 // build our own extension string first, based on the extension we know
657 // and the extension supported by our client implementation
Mathias Agopian6fc56992009-10-14 02:06:37 -0700658 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 egl_connection_t* const cnx = &gEGLImpl[i];
660 cnx->major = -1;
661 cnx->minor = -1;
662 if (!cnx->dso)
663 continue;
664
Mathias Agopian94263d72009-08-24 21:47:13 -0700665#if defined(ADRENO130)
666#warning "Adreno-130 eglInitialize() workaround"
667 /*
668 * The ADRENO 130 driver returns a different EGLDisplay each time
669 * eglGetDisplay() is called, but also makes the EGLDisplay invalid
670 * after eglTerminate() has been called, so that eglInitialize()
671 * cannot be called again. Therefore, we need to make sure to call
672 * eglGetDisplay() before calling eglInitialize();
673 */
674 if (i == IMPL_HARDWARE) {
675 dp->disp[i].dpy =
Mathias Agopian6fc56992009-10-14 02:06:37 -0700676 cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
Mathias Agopian94263d72009-08-24 21:47:13 -0700677 }
678#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679
Mathias Agopian94263d72009-08-24 21:47:13 -0700680
681 EGLDisplay idpy = dp->disp[i].dpy;
Mathias Agopian6fc56992009-10-14 02:06:37 -0700682 if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
Mathias Agopian94263d72009-08-24 21:47:13 -0700684 // i, idpy, cnx->major, cnx->minor, cnx);
685
686 // display is now initialized
687 dp->disp[i].state = egl_display_t::INITIALIZED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688
689 // get the query-strings for this display for each implementation
Mathias Agopian94263d72009-08-24 21:47:13 -0700690 dp->disp[i].queryString.vendor =
Mathias Agopian6fc56992009-10-14 02:06:37 -0700691 cnx->egl.eglQueryString(idpy, EGL_VENDOR);
Mathias Agopian94263d72009-08-24 21:47:13 -0700692 dp->disp[i].queryString.version =
Mathias Agopian6fc56992009-10-14 02:06:37 -0700693 cnx->egl.eglQueryString(idpy, EGL_VERSION);
Mathias Agopian94263d72009-08-24 21:47:13 -0700694 dp->disp[i].queryString.extensions =
Mathias Agopian6fc56992009-10-14 02:06:37 -0700695 cnx->egl.eglQueryString(idpy, EGL_EXTENSIONS);
Mathias Agopian94263d72009-08-24 21:47:13 -0700696 dp->disp[i].queryString.clientApi =
Mathias Agopian6fc56992009-10-14 02:06:37 -0700697 cnx->egl.eglQueryString(idpy, EGL_CLIENT_APIS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698
699 } else {
Mathias Agopian94263d72009-08-24 21:47:13 -0700700 LOGW("%d: eglInitialize(%p) failed (%s)", i, idpy,
Mathias Agopian6fc56992009-10-14 02:06:37 -0700701 egl_strerror(cnx->egl.eglGetError()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 }
703 }
704
705 EGLBoolean res = EGL_FALSE;
Mathias Agopian6fc56992009-10-14 02:06:37 -0700706 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 egl_connection_t* const cnx = &gEGLImpl[i];
708 if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
709 EGLint n;
Mathias Agopian6fc56992009-10-14 02:06:37 -0700710 if (cnx->egl.eglGetConfigs(dp->disp[i].dpy, 0, 0, &n)) {
Mathias Agopian94263d72009-08-24 21:47:13 -0700711 dp->disp[i].config = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
712 if (dp->disp[i].config) {
Mathias Agopian6fc56992009-10-14 02:06:37 -0700713 if (cnx->egl.eglGetConfigs(
Mathias Agopian94263d72009-08-24 21:47:13 -0700714 dp->disp[i].dpy, dp->disp[i].config, n,
715 &dp->disp[i].numConfigs))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800716 {
717 // sort the configurations so we can do binary searches
Mathias Agopian94263d72009-08-24 21:47:13 -0700718 qsort( dp->disp[i].config,
719 dp->disp[i].numConfigs,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 sizeof(EGLConfig), cmp_configs);
721
722 dp->numTotalConfigs += n;
723 res = EGL_TRUE;
724 }
725 }
726 }
727 }
728 }
729
730 if (res == EGL_TRUE) {
731 if (major != NULL) *major = VERSION_MAJOR;
732 if (minor != NULL) *minor = VERSION_MINOR;
733 return EGL_TRUE;
734 }
735 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
736}
737
738EGLBoolean eglTerminate(EGLDisplay dpy)
739{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700740 // NOTE: don't unload the drivers b/c some APIs can be called
741 // after eglTerminate() has been called. eglTerminate() only
742 // terminates an EGLDisplay, not a EGL itself.
743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 egl_display_t* const dp = get_display(dpy);
745 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
746 if (android_atomic_dec(&dp->refs) != 1)
747 return EGL_TRUE;
Mathias Agopian9d17c052009-05-28 17:39:03 -0700748
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 EGLBoolean res = EGL_FALSE;
Mathias Agopian6fc56992009-10-14 02:06:37 -0700750 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 egl_connection_t* const cnx = &gEGLImpl[i];
Mathias Agopian94263d72009-08-24 21:47:13 -0700752 if (cnx->dso && dp->disp[i].state == egl_display_t::INITIALIZED) {
Mathias Agopian6fc56992009-10-14 02:06:37 -0700753 if (cnx->egl.eglTerminate(dp->disp[i].dpy) == EGL_FALSE) {
Mathias Agopian94263d72009-08-24 21:47:13 -0700754 LOGW("%d: eglTerminate(%p) failed (%s)", i, dp->disp[i].dpy,
Mathias Agopian6fc56992009-10-14 02:06:37 -0700755 egl_strerror(cnx->egl.eglGetError()));
Mathias Agopian94263d72009-08-24 21:47:13 -0700756 }
Mathias Agopiandcebf6f2009-08-17 18:07:06 -0700757 // REVISIT: it's unclear what to do if eglTerminate() fails
Mathias Agopian94263d72009-08-24 21:47:13 -0700758 free(dp->disp[i].config);
759
760 dp->disp[i].numConfigs = 0;
761 dp->disp[i].config = 0;
762 dp->disp[i].state = egl_display_t::TERMINATED;
763
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 res = EGL_TRUE;
765 }
766 }
Mathias Agopian4a34e882009-08-21 02:18:25 -0700767
768 // TODO: all egl_object_t should be marked for termination
769
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 dp->numTotalConfigs = 0;
771 clearTLS();
772 return res;
773}
774
775// ----------------------------------------------------------------------------
776// configuration
777// ----------------------------------------------------------------------------
778
779EGLBoolean eglGetConfigs( EGLDisplay dpy,
780 EGLConfig *configs,
781 EGLint config_size, EGLint *num_config)
782{
783 egl_display_t const * const dp = get_display(dpy);
784 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
785
786 GLint numConfigs = dp->numTotalConfigs;
787 if (!configs) {
788 *num_config = numConfigs;
789 return EGL_TRUE;
790 }
791 GLint n = 0;
Mathias Agopian6fc56992009-10-14 02:06:37 -0700792 for (int j=0 ; j<IMPL_NUM_IMPLEMENTATIONS ; j++) {
Mathias Agopian94263d72009-08-24 21:47:13 -0700793 for (int i=0 ; i<dp->disp[j].numConfigs && config_size ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 *configs++ = MAKE_CONFIG(j, i);
795 config_size--;
796 n++;
797 }
798 }
799
800 *num_config = n;
801 return EGL_TRUE;
802}
803
804EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
805 EGLConfig *configs, EGLint config_size,
806 EGLint *num_config)
807{
808 egl_display_t const * const dp = get_display(dpy);
809 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
810
Jack Palevich1badb712009-03-25 15:12:17 -0700811 if (num_config==0) {
812 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 }
814
815 EGLint n;
816 EGLBoolean res = EGL_FALSE;
817 *num_config = 0;
818
819
820 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
821 // to do this, we have to go through the attrib_list array once
822 // to figure out both its size and if it contains an EGL_CONFIG_ID
823 // key. If so, the full array is copied and patched.
824 // NOTE: we assume that there can be only one occurrence
825 // of EGL_CONFIG_ID.
826
827 EGLint patch_index = -1;
828 GLint attr;
829 size_t size = 0;
Mathias Agopianab1cf3e2009-07-09 17:33:15 -0700830 while ((attr=attrib_list[size]) != EGL_NONE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 if (attr == EGL_CONFIG_ID)
832 patch_index = size;
833 size += 2;
834 }
835 if (patch_index >= 0) {
836 size += 2; // we need copy the sentinel as well
837 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
838 if (new_list == 0)
839 return setError(EGL_BAD_ALLOC, EGL_FALSE);
840 memcpy(new_list, attrib_list, size*sizeof(EGLint));
841
842 // patch the requested EGL_CONFIG_ID
843 int i, index;
844 EGLint& configId(new_list[patch_index+1]);
845 uniqueIdToConfig(dp, configId, i, index);
846
847 egl_connection_t* const cnx = &gEGLImpl[i];
848 if (cnx->dso) {
Mathias Agopian6fc56992009-10-14 02:06:37 -0700849 cnx->egl.eglGetConfigAttrib(
Mathias Agopian94263d72009-08-24 21:47:13 -0700850 dp->disp[i].dpy, dp->disp[i].config[index],
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 EGL_CONFIG_ID, &configId);
852
853 // and switch to the new list
854 attrib_list = const_cast<const EGLint *>(new_list);
855
856 // At this point, the only configuration that can match is
857 // dp->configs[i][index], however, we don't know if it would be
858 // rejected because of the other attributes, so we do have to call
Mathias Agopian6fc56992009-10-14 02:06:37 -0700859 // cnx->egl.eglChooseConfig() -- but we don't have to loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860 // through all the EGLimpl[].
861 // We also know we can only get a single config back, and we know
862 // which one.
863
Mathias Agopian6fc56992009-10-14 02:06:37 -0700864 res = cnx->egl.eglChooseConfig(
Mathias Agopian94263d72009-08-24 21:47:13 -0700865 dp->disp[i].dpy, attrib_list, configs, config_size, &n);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 if (res && n>0) {
867 // n has to be 0 or 1, by construction, and we already know
868 // which config it will return (since there can be only one).
Jack Palevich1badb712009-03-25 15:12:17 -0700869 if (configs) {
870 configs[0] = MAKE_CONFIG(i, index);
871 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872 *num_config = 1;
873 }
874 }
875
876 free(const_cast<EGLint *>(attrib_list));
877 return res;
878 }
879
Mathias Agopian6fc56992009-10-14 02:06:37 -0700880 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 egl_connection_t* const cnx = &gEGLImpl[i];
882 if (cnx->dso) {
Mathias Agopian6fc56992009-10-14 02:06:37 -0700883 if (cnx->egl.eglChooseConfig(
Mathias Agopian94263d72009-08-24 21:47:13 -0700884 dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
Jack Palevich1badb712009-03-25 15:12:17 -0700885 if (configs) {
886 // now we need to convert these client EGLConfig to our
887 // internal EGLConfig format. This is done in O(n log n).
888 for (int j=0 ; j<n ; j++) {
889 int index = binarySearch<EGLConfig>(
Mathias Agopian94263d72009-08-24 21:47:13 -0700890 dp->disp[i].config, 0,
891 dp->disp[i].numConfigs-1, configs[j]);
Jack Palevich1badb712009-03-25 15:12:17 -0700892 if (index >= 0) {
893 if (configs) {
894 configs[j] = MAKE_CONFIG(i, index);
895 }
896 } else {
897 return setError(EGL_BAD_CONFIG, EGL_FALSE);
898 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 }
Jack Palevich1badb712009-03-25 15:12:17 -0700900 configs += n;
901 config_size -= n;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 *num_config += n;
904 res = EGL_TRUE;
905 }
906 }
907 }
908 return res;
909}
910
911EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
912 EGLint attribute, EGLint *value)
913{
914 egl_display_t const* dp = 0;
915 int i=0, index=0;
916 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
917 if (!cnx) return EGL_FALSE;
918
919 if (attribute == EGL_CONFIG_ID) {
920 // EGL_CONFIG_IDs must be unique, just use the order of the selected
921 // EGLConfig.
922 *value = configToUniqueId(dp, i, index);
923 return EGL_TRUE;
924 }
Mathias Agopian6fc56992009-10-14 02:06:37 -0700925 return cnx->egl.eglGetConfigAttrib(
Mathias Agopian94263d72009-08-24 21:47:13 -0700926 dp->disp[i].dpy, dp->disp[i].config[index], attribute, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927}
928
929// ----------------------------------------------------------------------------
930// surfaces
931// ----------------------------------------------------------------------------
932
933EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
934 NativeWindowType window,
935 const EGLint *attrib_list)
936{
937 egl_display_t const* dp = 0;
938 int i=0, index=0;
939 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
940 if (cnx) {
Mathias Agopian6fc56992009-10-14 02:06:37 -0700941 EGLSurface surface = cnx->egl.eglCreateWindowSurface(
Mathias Agopian94263d72009-08-24 21:47:13 -0700942 dp->disp[i].dpy, dp->disp[i].config[index], window, attrib_list);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 if (surface != EGL_NO_SURFACE) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700944 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 return s;
946 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800947 }
948 return EGL_NO_SURFACE;
949}
950
951EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
952 NativePixmapType pixmap,
953 const EGLint *attrib_list)
954{
955 egl_display_t const* dp = 0;
956 int i=0, index=0;
957 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
958 if (cnx) {
Mathias Agopian6fc56992009-10-14 02:06:37 -0700959 EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
Mathias Agopian94263d72009-08-24 21:47:13 -0700960 dp->disp[i].dpy, dp->disp[i].config[index], pixmap, attrib_list);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 if (surface != EGL_NO_SURFACE) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700962 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 return s;
964 }
965 }
966 return EGL_NO_SURFACE;
967}
968
969EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
970 const EGLint *attrib_list)
971{
972 egl_display_t const* dp = 0;
973 int i=0, index=0;
974 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
975 if (cnx) {
Mathias Agopian6fc56992009-10-14 02:06:37 -0700976 EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
Mathias Agopian94263d72009-08-24 21:47:13 -0700977 dp->disp[i].dpy, dp->disp[i].config[index], attrib_list);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 if (surface != EGL_NO_SURFACE) {
Mathias Agopian1473f462009-04-10 14:24:30 -0700979 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 return s;
981 }
982 }
983 return EGL_NO_SURFACE;
984}
985
986EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
987{
Mathias Agopian4a34e882009-08-21 02:18:25 -0700988 SurfaceRef _s(surface);
989 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
990
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 if (!validate_display_surface(dpy, surface))
992 return EGL_FALSE;
993 egl_display_t const * const dp = get_display(dpy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994
Mathias Agopian4a34e882009-08-21 02:18:25 -0700995 egl_surface_t * const s = get_surface(surface);
Mathias Agopian6fc56992009-10-14 02:06:37 -0700996 EGLBoolean result = s->cnx->egl.eglDestroySurface(
Mathias Agopian94263d72009-08-24 21:47:13 -0700997 dp->disp[s->impl].dpy, s->surface);
Mathias Agopian4a34e882009-08-21 02:18:25 -0700998 if (result == EGL_TRUE) {
999 _s.terminate();
1000 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001001 return result;
1002}
1003
1004EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
1005 EGLint attribute, EGLint *value)
1006{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001007 SurfaceRef _s(surface);
1008 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1009
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 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
Mathias Agopian6fc56992009-10-14 02:06:37 -07001015 return s->cnx->egl.eglQuerySurface(
Mathias Agopian94263d72009-08-24 21:47:13 -07001016 dp->disp[s->impl].dpy, s->surface, attribute, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017}
1018
1019// ----------------------------------------------------------------------------
1020// contextes
1021// ----------------------------------------------------------------------------
1022
1023EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
1024 EGLContext share_list, const EGLint *attrib_list)
1025{
1026 egl_display_t const* dp = 0;
1027 int i=0, index=0;
1028 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1029 if (cnx) {
Mathias Agopian6fc56992009-10-14 02:06:37 -07001030 EGLContext context = cnx->egl.eglCreateContext(
Mathias Agopian94263d72009-08-24 21:47:13 -07001031 dp->disp[i].dpy, dp->disp[i].config[index],
1032 share_list, attrib_list);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 if (context != EGL_NO_CONTEXT) {
Mathias Agopian6fc56992009-10-14 02:06:37 -07001034 // figure out if it's a GLESv1 or GLESv2
1035 int version = 0;
1036 if (attrib_list) {
1037 while (*attrib_list != EGL_NONE) {
1038 GLint attr = *attrib_list++;
1039 GLint value = *attrib_list++;
1040 if (attr == EGL_CONTEXT_CLIENT_VERSION) {
1041 if (value == 1) {
1042 version = GLESv1_INDEX;
1043 } else if (value == 2) {
1044 version = GLESv2_INDEX;
1045 }
1046 }
1047 };
1048 }
1049 egl_context_t* c = new egl_context_t(dpy, context, i, cnx, version);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 return c;
1051 }
1052 }
1053 return EGL_NO_CONTEXT;
1054}
1055
1056EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1057{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001058 ContextRef _c(ctx);
1059 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 if (!validate_display_context(dpy, ctx))
1062 return EGL_FALSE;
1063 egl_display_t const * const dp = get_display(dpy);
1064 egl_context_t * const c = get_context(ctx);
Mathias Agopian6fc56992009-10-14 02:06:37 -07001065 EGLBoolean result = c->cnx->egl.eglDestroyContext(
Mathias Agopian94263d72009-08-24 21:47:13 -07001066 dp->disp[c->impl].dpy, c->context);
Mathias Agopian4a34e882009-08-21 02:18:25 -07001067 if (result == EGL_TRUE) {
1068 _c.terminate();
1069 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 return result;
1071}
1072
1073EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
1074 EGLSurface read, EGLContext ctx)
1075{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001076 // get a reference to the object passed in
1077 ContextRef _c(ctx);
1078 SurfaceRef _d(draw);
1079 SurfaceRef _r(read);
1080
1081 // validate the display and the context (if not EGL_NO_CONTEXT)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 egl_display_t const * const dp = get_display(dpy);
1083 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian4a34e882009-08-21 02:18:25 -07001084 if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
1085 // EGL_NO_CONTEXT is valid
1086 return EGL_FALSE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 }
1088
Mathias Agopian4a34e882009-08-21 02:18:25 -07001089 // these are the underlying implementation's object
1090 EGLContext impl_ctx = EGL_NO_CONTEXT;
Mathias Agopian3a7e1832009-06-25 00:01:11 -07001091 EGLSurface impl_draw = EGL_NO_SURFACE;
1092 EGLSurface impl_read = EGL_NO_SURFACE;
Mathias Agopian4a34e882009-08-21 02:18:25 -07001093
1094 // these are our objects structs passed in
1095 egl_context_t * c = NULL;
1096 egl_surface_t const * d = NULL;
1097 egl_surface_t const * r = NULL;
1098
1099 // these are the current objects structs
1100 egl_context_t * cur_c = get_context(getContext());
1101 egl_surface_t * cur_r = NULL;
1102 egl_surface_t * cur_d = NULL;
1103
1104 if (ctx != EGL_NO_CONTEXT) {
1105 c = get_context(ctx);
1106 cur_r = get_surface(c->read);
1107 cur_d = get_surface(c->draw);
1108 impl_ctx = c->context;
1109 } else {
1110 // no context given, use the implementation of the current context
1111 if (cur_c == NULL) {
1112 // no current context
1113 if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
1114 // calling eglMakeCurrent( ..., EGL_NO_CONTEXT, !=0, !=0);
1115 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1116 }
1117 // not an error, there is just not current context.
1118 return EGL_TRUE;
1119 }
1120 }
1121
1122 // retrieve the underlying implementation's draw EGLSurface
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 if (draw != EGL_NO_SURFACE) {
Mathias Agopian4a34e882009-08-21 02:18:25 -07001124 d = get_surface(draw);
Mathias Agopian94263d72009-08-24 21:47:13 -07001125 // make sure the EGLContext and EGLSurface passed in are for
1126 // the same driver
Mathias Agopian4a34e882009-08-21 02:18:25 -07001127 if (c && d->impl != c->impl)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 return setError(EGL_BAD_MATCH, EGL_FALSE);
Mathias Agopian3a7e1832009-06-25 00:01:11 -07001129 impl_draw = d->surface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130 }
Mathias Agopian4a34e882009-08-21 02:18:25 -07001131
1132 // retrieve the underlying implementation's read EGLSurface
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001133 if (read != EGL_NO_SURFACE) {
Mathias Agopian4a34e882009-08-21 02:18:25 -07001134 r = get_surface(read);
Mathias Agopian94263d72009-08-24 21:47:13 -07001135 // make sure the EGLContext and EGLSurface passed in are for
1136 // the same driver
Mathias Agopian4a34e882009-08-21 02:18:25 -07001137 if (c && r->impl != c->impl)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138 return setError(EGL_BAD_MATCH, EGL_FALSE);
Mathias Agopian3a7e1832009-06-25 00:01:11 -07001139 impl_read = r->surface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 }
Mathias Agopian4a34e882009-08-21 02:18:25 -07001141
1142 EGLBoolean result;
1143
1144 if (c) {
Mathias Agopian6fc56992009-10-14 02:06:37 -07001145 result = c->cnx->egl.eglMakeCurrent(
Mathias Agopian94263d72009-08-24 21:47:13 -07001146 dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
Mathias Agopian4a34e882009-08-21 02:18:25 -07001147 } else {
Mathias Agopian6fc56992009-10-14 02:06:37 -07001148 result = cur_c->cnx->egl.eglMakeCurrent(
Mathias Agopian94263d72009-08-24 21:47:13 -07001149 dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
Mathias Agopian4a34e882009-08-21 02:18:25 -07001150 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151
1152 if (result == EGL_TRUE) {
Mathias Agopian4a34e882009-08-21 02:18:25 -07001153 // by construction, these are either 0 or valid (possibly terminated)
1154 // it should be impossible for these to be invalid
1155 ContextRef _cur_c(cur_c);
1156 SurfaceRef _cur_r(cur_r);
1157 SurfaceRef _cur_d(cur_d);
1158
1159 // cur_c has to be valid here (but could be terminated)
1160 if (ctx != EGL_NO_CONTEXT) {
Mathias Agopian6fc56992009-10-14 02:06:37 -07001161 setGlThreadSpecific(c->cnx->hooks[c->version]);
Mathias Agopian4a34e882009-08-21 02:18:25 -07001162 setContext(ctx);
1163 _c.acquire();
1164 } else {
Mathias Agopian6fc56992009-10-14 02:06:37 -07001165 setGlThreadSpecific(&gHooksNoContext);
Mathias Agopian4a34e882009-08-21 02:18:25 -07001166 setContext(EGL_NO_CONTEXT);
1167 }
1168 _cur_c.release();
1169
1170 _r.acquire();
1171 _cur_r.release();
1172 if (c) c->read = read;
1173
1174 _d.acquire();
1175 _cur_d.release();
1176 if (c) c->draw = draw;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 }
1178 return result;
1179}
1180
1181
1182EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
1183 EGLint attribute, EGLint *value)
1184{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001185 ContextRef _c(ctx);
1186 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 if (!validate_display_context(dpy, ctx))
1189 return EGL_FALSE;
1190
1191 egl_display_t const * const dp = get_display(dpy);
1192 egl_context_t * const c = get_context(ctx);
1193
Mathias Agopian6fc56992009-10-14 02:06:37 -07001194 return c->cnx->egl.eglQueryContext(
Mathias Agopian94263d72009-08-24 21:47:13 -07001195 dp->disp[c->impl].dpy, c->context, attribute, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196}
1197
1198EGLContext eglGetCurrentContext(void)
1199{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001200 // could be called before eglInitialize(), but we wouldn't have a context
1201 // then, and this function would correctly return EGL_NO_CONTEXT.
1202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001203 EGLContext ctx = getContext();
1204 return ctx;
1205}
1206
1207EGLSurface eglGetCurrentSurface(EGLint readdraw)
1208{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001209 // could be called before eglInitialize(), but we wouldn't have a context
1210 // then, and this function would correctly return EGL_NO_SURFACE.
1211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 EGLContext ctx = getContext();
1213 if (ctx) {
1214 egl_context_t const * const c = get_context(ctx);
1215 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1216 switch (readdraw) {
1217 case EGL_READ: return c->read;
1218 case EGL_DRAW: return c->draw;
1219 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1220 }
1221 }
1222 return EGL_NO_SURFACE;
1223}
1224
1225EGLDisplay eglGetCurrentDisplay(void)
1226{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001227 // could be called before eglInitialize(), but we wouldn't have a context
1228 // then, and this function would correctly return EGL_NO_DISPLAY.
1229
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 EGLContext ctx = getContext();
1231 if (ctx) {
1232 egl_context_t const * const c = get_context(ctx);
1233 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1234 return c->dpy;
1235 }
1236 return EGL_NO_DISPLAY;
1237}
1238
1239EGLBoolean eglWaitGL(void)
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);
Mathias Agopian6fc56992009-10-14 02:06:37 -07001254 res = cnx->egl.eglWaitGL();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255 }
1256 return res;
1257}
1258
1259EGLBoolean eglWaitNative(EGLint engine)
1260{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001261 // could be called before eglInitialize(), but we wouldn't have a context
1262 // then, and this function would return GL_TRUE, which isn't wrong.
1263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 EGLBoolean res = EGL_TRUE;
1265 EGLContext ctx = getContext();
1266 if (ctx) {
1267 egl_context_t const * const c = get_context(ctx);
1268 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1269 if (uint32_t(c->impl)>=2)
1270 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1271 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1272 if (!cnx->dso)
1273 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
Mathias Agopian6fc56992009-10-14 02:06:37 -07001274 res = cnx->egl.eglWaitNative(engine);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001275 }
1276 return res;
1277}
1278
1279EGLint eglGetError(void)
1280{
1281 EGLint result = EGL_SUCCESS;
Mathias Agopian6fc56992009-10-14 02:06:37 -07001282 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 EGLint err = EGL_SUCCESS;
1284 egl_connection_t* const cnx = &gEGLImpl[i];
1285 if (cnx->dso)
Mathias Agopian6fc56992009-10-14 02:06:37 -07001286 err = cnx->egl.eglGetError();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1288 result = err;
1289 }
1290 if (result == EGL_SUCCESS)
1291 result = getError();
1292 return result;
1293}
1294
Mathias Agopian1473f462009-04-10 14:24:30 -07001295__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296{
Mathias Agopian1473f462009-04-10 14:24:30 -07001297 // eglGetProcAddress() could be the very first function called
1298 // in which case we must make sure we've initialized ourselves, this
1299 // happens the first time egl_get_display() is called.
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001300
1301 if (egl_init_drivers() == EGL_FALSE) {
1302 setError(EGL_BAD_PARAMETER, NULL);
1303 return NULL;
1304 }
Mathias Agopian1473f462009-04-10 14:24:30 -07001305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 __eglMustCastToProperFunctionPointerType addr;
1307 addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1308 if (addr) return addr;
1309
1310 return NULL; // TODO: finish implementation below
1311
1312 addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1313 if (addr) return addr;
1314
1315 addr = 0;
1316 int slot = -1;
Mathias Agopian6fc56992009-10-14 02:06:37 -07001317 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 egl_connection_t* const cnx = &gEGLImpl[i];
1319 if (cnx->dso) {
Mathias Agopian6fc56992009-10-14 02:06:37 -07001320 if (cnx->egl.eglGetProcAddress) {
1321 addr = cnx->egl.eglGetProcAddress(procname);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 if (addr) {
1323 if (slot == -1) {
1324 slot = 0; // XXX: find free slot
1325 if (slot == -1) {
1326 addr = 0;
1327 break;
1328 }
1329 }
Mathias Agopian6fc56992009-10-14 02:06:37 -07001330 //cnx->hooks->ext.extensions[slot] = addr;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001331 }
1332 }
1333 }
1334 }
1335
1336 if (slot >= 0) {
1337 addr = 0; // XXX: address of stub 'slot'
1338 gGLExtentionMap[slot].name = strdup(procname);
1339 gGLExtentionMap[slot].address = addr;
1340 }
1341
1342 return addr;
1343
1344
1345 /*
1346 * TODO: For OpenGL ES extensions, we must generate a stub
1347 * that looks like
1348 * mov r12, #0xFFFF0FFF
1349 * ldr r12, [r12, #-15]
1350 * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
1351 * mov r12, [r12, #api_offset]
1352 * ldrne pc, r12
1353 * mov pc, #unsupported_extension
1354 *
1355 * and write the address of the extension in *all*
1356 * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1357 *
1358 */
1359}
1360
1361EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1362{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001363 SurfaceRef _s(draw);
1364 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 if (!validate_display_surface(dpy, draw))
1367 return EGL_FALSE;
1368 egl_display_t const * const dp = get_display(dpy);
1369 egl_surface_t const * const s = get_surface(draw);
Mathias Agopian6fc56992009-10-14 02:06:37 -07001370 return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371}
1372
1373EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1374 NativePixmapType target)
1375{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001376 SurfaceRef _s(surface);
1377 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 if (!validate_display_surface(dpy, surface))
1380 return EGL_FALSE;
1381 egl_display_t const * const dp = get_display(dpy);
1382 egl_surface_t const * const s = get_surface(surface);
Mathias Agopian6fc56992009-10-14 02:06:37 -07001383 return s->cnx->egl.eglCopyBuffers(
Mathias Agopian94263d72009-08-24 21:47:13 -07001384 dp->disp[s->impl].dpy, s->surface, target);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385}
1386
1387const char* eglQueryString(EGLDisplay dpy, EGLint name)
1388{
1389 egl_display_t const * const dp = get_display(dpy);
1390 switch (name) {
1391 case EGL_VENDOR:
1392 return gVendorString;
1393 case EGL_VERSION:
1394 return gVersionString;
1395 case EGL_EXTENSIONS:
1396 return gExtensionString;
1397 case EGL_CLIENT_APIS:
1398 return gClientApiString;
1399 }
1400 return setError(EGL_BAD_PARAMETER, (const char *)0);
1401}
1402
1403
1404// ----------------------------------------------------------------------------
1405// EGL 1.1
1406// ----------------------------------------------------------------------------
1407
1408EGLBoolean eglSurfaceAttrib(
1409 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1410{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001411 SurfaceRef _s(surface);
1412 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 if (!validate_display_surface(dpy, surface))
1415 return EGL_FALSE;
1416 egl_display_t const * const dp = get_display(dpy);
1417 egl_surface_t const * const s = get_surface(surface);
Mathias Agopian6fc56992009-10-14 02:06:37 -07001418 if (s->cnx->egl.eglSurfaceAttrib) {
1419 return s->cnx->egl.eglSurfaceAttrib(
Mathias Agopian94263d72009-08-24 21:47:13 -07001420 dp->disp[s->impl].dpy, s->surface, attribute, value);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421 }
1422 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1423}
1424
1425EGLBoolean eglBindTexImage(
1426 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1427{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001428 SurfaceRef _s(surface);
1429 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1430
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 if (!validate_display_surface(dpy, surface))
1432 return EGL_FALSE;
1433 egl_display_t const * const dp = get_display(dpy);
1434 egl_surface_t const * const s = get_surface(surface);
Mathias Agopian6fc56992009-10-14 02:06:37 -07001435 if (s->cnx->egl.eglBindTexImage) {
1436 return s->cnx->egl.eglBindTexImage(
Mathias Agopian94263d72009-08-24 21:47:13 -07001437 dp->disp[s->impl].dpy, s->surface, buffer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001438 }
1439 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1440}
1441
1442EGLBoolean eglReleaseTexImage(
1443 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1444{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001445 SurfaceRef _s(surface);
1446 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 if (!validate_display_surface(dpy, surface))
1449 return EGL_FALSE;
1450 egl_display_t const * const dp = get_display(dpy);
1451 egl_surface_t const * const s = get_surface(surface);
Mathias Agopian6fc56992009-10-14 02:06:37 -07001452 if (s->cnx->egl.eglReleaseTexImage) {
1453 return s->cnx->egl.eglReleaseTexImage(
Mathias Agopian94263d72009-08-24 21:47:13 -07001454 dp->disp[s->impl].dpy, s->surface, buffer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455 }
1456 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1457}
1458
1459EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1460{
1461 egl_display_t * const dp = get_display(dpy);
1462 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1463
1464 EGLBoolean res = EGL_TRUE;
Mathias Agopian6fc56992009-10-14 02:06:37 -07001465 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001466 egl_connection_t* const cnx = &gEGLImpl[i];
1467 if (cnx->dso) {
Mathias Agopian6fc56992009-10-14 02:06:37 -07001468 if (cnx->egl.eglSwapInterval) {
1469 if (cnx->egl.eglSwapInterval(
Mathias Agopian94263d72009-08-24 21:47:13 -07001470 dp->disp[i].dpy, interval) == EGL_FALSE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001471 res = EGL_FALSE;
1472 }
1473 }
1474 }
1475 }
1476 return res;
1477}
1478
1479
1480// ----------------------------------------------------------------------------
1481// EGL 1.2
1482// ----------------------------------------------------------------------------
1483
1484EGLBoolean eglWaitClient(void)
1485{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001486 // could be called before eglInitialize(), but we wouldn't have a context
1487 // then, and this function would return GL_TRUE, which isn't wrong.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 EGLBoolean res = EGL_TRUE;
1489 EGLContext ctx = getContext();
1490 if (ctx) {
1491 egl_context_t const * const c = get_context(ctx);
1492 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1493 if (uint32_t(c->impl)>=2)
1494 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1495 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1496 if (!cnx->dso)
1497 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
Mathias Agopian6fc56992009-10-14 02:06:37 -07001498 if (cnx->egl.eglWaitClient) {
1499 res = cnx->egl.eglWaitClient();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 } else {
Mathias Agopian6fc56992009-10-14 02:06:37 -07001501 res = cnx->egl.eglWaitGL();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001502 }
1503 }
1504 return res;
1505}
1506
1507EGLBoolean eglBindAPI(EGLenum api)
1508{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001509 if (egl_init_drivers() == EGL_FALSE) {
1510 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1511 }
1512
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 // bind this API on all EGLs
1514 EGLBoolean res = EGL_TRUE;
Mathias Agopian6fc56992009-10-14 02:06:37 -07001515 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 egl_connection_t* const cnx = &gEGLImpl[i];
1517 if (cnx->dso) {
Mathias Agopian6fc56992009-10-14 02:06:37 -07001518 if (cnx->egl.eglBindAPI) {
1519 if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001520 res = EGL_FALSE;
1521 }
1522 }
1523 }
1524 }
1525 return res;
1526}
1527
1528EGLenum eglQueryAPI(void)
1529{
Mathias Agopiandcebf6f2009-08-17 18:07:06 -07001530 if (egl_init_drivers() == EGL_FALSE) {
1531 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1532 }
1533
Mathias Agopian6fc56992009-10-14 02:06:37 -07001534 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001535 egl_connection_t* const cnx = &gEGLImpl[i];
1536 if (cnx->dso) {
Mathias Agopian6fc56992009-10-14 02:06:37 -07001537 if (cnx->egl.eglQueryAPI) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 // the first one we find is okay, because they all
1539 // should be the same
Mathias Agopian6fc56992009-10-14 02:06:37 -07001540 return cnx->egl.eglQueryAPI();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001541 }
1542 }
1543 }
1544 // or, it can only be OpenGL ES
1545 return EGL_OPENGL_ES_API;
1546}
1547
1548EGLBoolean eglReleaseThread(void)
1549{
Mathias Agopian6fc56992009-10-14 02:06:37 -07001550 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 egl_connection_t* const cnx = &gEGLImpl[i];
1552 if (cnx->dso) {
Mathias Agopian6fc56992009-10-14 02:06:37 -07001553 if (cnx->egl.eglReleaseThread) {
1554 cnx->egl.eglReleaseThread();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 }
1556 }
1557 }
1558 clearTLS();
1559 return EGL_TRUE;
1560}
1561
1562EGLSurface eglCreatePbufferFromClientBuffer(
1563 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1564 EGLConfig config, const EGLint *attrib_list)
1565{
1566 egl_display_t const* dp = 0;
1567 int i=0, index=0;
1568 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1569 if (!cnx) return EGL_FALSE;
Mathias Agopian6fc56992009-10-14 02:06:37 -07001570 if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1571 return cnx->egl.eglCreatePbufferFromClientBuffer(
Mathias Agopian94263d72009-08-24 21:47:13 -07001572 dp->disp[i].dpy, buftype, buffer,
1573 dp->disp[i].config[index], attrib_list);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 }
1575 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1576}
Mathias Agopian1473f462009-04-10 14:24:30 -07001577
1578// ----------------------------------------------------------------------------
1579// EGL_EGLEXT_VERSION 3
1580// ----------------------------------------------------------------------------
1581
1582EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1583 const EGLint *attrib_list)
1584{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001585 SurfaceRef _s(surface);
1586 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1587
Mathias Agopian1473f462009-04-10 14:24:30 -07001588 if (!validate_display_surface(dpy, surface))
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001589 return EGL_FALSE;
Mathias Agopian1473f462009-04-10 14:24:30 -07001590
1591 egl_display_t const * const dp = get_display(dpy);
1592 egl_surface_t const * const s = get_surface(surface);
1593
Mathias Agopian6fc56992009-10-14 02:06:37 -07001594 if (s->cnx->egl.eglLockSurfaceKHR) {
1595 return s->cnx->egl.eglLockSurfaceKHR(
Mathias Agopian94263d72009-08-24 21:47:13 -07001596 dp->disp[s->impl].dpy, s->surface, attrib_list);
Mathias Agopian1473f462009-04-10 14:24:30 -07001597 }
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001598 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001599}
1600
1601EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1602{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001603 SurfaceRef _s(surface);
1604 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1605
Mathias Agopian1473f462009-04-10 14:24:30 -07001606 if (!validate_display_surface(dpy, surface))
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001607 return EGL_FALSE;
Mathias Agopian1473f462009-04-10 14:24:30 -07001608
1609 egl_display_t const * const dp = get_display(dpy);
1610 egl_surface_t const * const s = get_surface(surface);
1611
Mathias Agopian6fc56992009-10-14 02:06:37 -07001612 if (s->cnx->egl.eglUnlockSurfaceKHR) {
1613 return s->cnx->egl.eglUnlockSurfaceKHR(
Mathias Agopian94263d72009-08-24 21:47:13 -07001614 dp->disp[s->impl].dpy, s->surface);
Mathias Agopian1473f462009-04-10 14:24:30 -07001615 }
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001616 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001617}
1618
1619EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1620 EGLClientBuffer buffer, const EGLint *attrib_list)
1621{
1622 if (ctx != EGL_NO_CONTEXT) {
Mathias Agopian4a34e882009-08-21 02:18:25 -07001623 ContextRef _c(ctx);
1624 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
Mathias Agopian1473f462009-04-10 14:24:30 -07001625 if (!validate_display_context(dpy, ctx))
1626 return EGL_NO_IMAGE_KHR;
1627 egl_display_t const * const dp = get_display(dpy);
1628 egl_context_t * const c = get_context(ctx);
1629 // since we have an EGLContext, we know which implementation to use
Mathias Agopian6fc56992009-10-14 02:06:37 -07001630 EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
Mathias Agopian94263d72009-08-24 21:47:13 -07001631 dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
Mathias Agopian1473f462009-04-10 14:24:30 -07001632 if (image == EGL_NO_IMAGE_KHR)
1633 return image;
1634
1635 egl_image_t* result = new egl_image_t(dpy, ctx);
1636 result->images[c->impl] = image;
1637 return (EGLImageKHR)result;
1638 } else {
1639 // EGL_NO_CONTEXT is a valid parameter
1640 egl_display_t const * const dp = get_display(dpy);
1641 if (dp == 0) {
1642 return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1643 }
Mathias Agopianf007a2f2009-10-28 21:00:29 -07001644
1645 /* Since we don't have a way to know which implementation to call,
1646 * we're calling all of them. If at least one of the implementation
1647 * succeeded, this is a success.
1648 */
1649
1650 EGLint currentError = eglGetError();
Mathias Agopian1473f462009-04-10 14:24:30 -07001651
Mathias Agopian6fc56992009-10-14 02:06:37 -07001652 EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
Mathias Agopian1473f462009-04-10 14:24:30 -07001653 bool success = false;
Mathias Agopian6fc56992009-10-14 02:06:37 -07001654 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001655 egl_connection_t* const cnx = &gEGLImpl[i];
1656 implImages[i] = EGL_NO_IMAGE_KHR;
1657 if (cnx->dso) {
Mathias Agopian6fc56992009-10-14 02:06:37 -07001658 if (cnx->egl.eglCreateImageKHR) {
1659 implImages[i] = cnx->egl.eglCreateImageKHR(
Mathias Agopian94263d72009-08-24 21:47:13 -07001660 dp->disp[i].dpy, ctx, target, buffer, attrib_list);
Mathias Agopian1473f462009-04-10 14:24:30 -07001661 if (implImages[i] != EGL_NO_IMAGE_KHR) {
1662 success = true;
1663 }
1664 }
1665 }
1666 }
Mathias Agopianf007a2f2009-10-28 21:00:29 -07001667
1668 if (!success) {
1669 // failure, if there was an error when we entered this function,
1670 // the error flag must not be updated.
1671 // Otherwise, the error is whatever happened in the implementation
1672 // that faulted.
1673 if (currentError != EGL_SUCCESS) {
1674 setError(currentError, EGL_NO_IMAGE_KHR);
1675 }
Mathias Agopian1473f462009-04-10 14:24:30 -07001676 return EGL_NO_IMAGE_KHR;
Mathias Agopianf007a2f2009-10-28 21:00:29 -07001677 } else {
1678 // In case of success, we need to clear all error flags
1679 // (especially those caused by the implementation that didn't
1680 // succeed). TODO: we could about this if we knew this was
1681 // a "full" success (all implementation succeeded).
1682 eglGetError();
1683 }
1684
Mathias Agopian1473f462009-04-10 14:24:30 -07001685 egl_image_t* result = new egl_image_t(dpy, ctx);
1686 memcpy(result->images, implImages, sizeof(implImages));
1687 return (EGLImageKHR)result;
1688 }
1689}
1690
1691EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1692{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001693 egl_display_t const * const dp = get_display(dpy);
Mathias Agopian1473f462009-04-10 14:24:30 -07001694 if (dp == 0) {
1695 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1696 }
1697
Mathias Agopian4a34e882009-08-21 02:18:25 -07001698 ImageRef _i(img);
1699 if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
Mathias Agopian1473f462009-04-10 14:24:30 -07001700
Mathias Agopian4a34e882009-08-21 02:18:25 -07001701 egl_image_t* image = get_image(img);
Mathias Agopian1473f462009-04-10 14:24:30 -07001702 bool success = false;
Mathias Agopian6fc56992009-10-14 02:06:37 -07001703 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001704 egl_connection_t* const cnx = &gEGLImpl[i];
1705 if (image->images[i] != EGL_NO_IMAGE_KHR) {
1706 if (cnx->dso) {
Mathias Agopian6fc56992009-10-14 02:06:37 -07001707 if (cnx->egl.eglCreateImageKHR) {
1708 if (cnx->egl.eglDestroyImageKHR(
Mathias Agopian94263d72009-08-24 21:47:13 -07001709 dp->disp[i].dpy, image->images[i])) {
Mathias Agopian1473f462009-04-10 14:24:30 -07001710 success = true;
1711 }
1712 }
1713 }
1714 }
1715 }
1716 if (!success)
1717 return EGL_FALSE;
1718
Mathias Agopian4a34e882009-08-21 02:18:25 -07001719 _i.terminate();
Mathias Agopian1473f462009-04-10 14:24:30 -07001720
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001721 return EGL_TRUE;
Mathias Agopian1473f462009-04-10 14:24:30 -07001722}
Mathias Agopian2e20bff2009-05-04 19:29:25 -07001723
1724
1725// ----------------------------------------------------------------------------
1726// ANDROID extensions
1727// ----------------------------------------------------------------------------
1728
1729EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1730 EGLint left, EGLint top, EGLint width, EGLint height)
1731{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001732 SurfaceRef _s(draw);
1733 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1734
Mathias Agopian2e20bff2009-05-04 19:29:25 -07001735 if (!validate_display_surface(dpy, draw))
1736 return EGL_FALSE;
1737 egl_display_t const * const dp = get_display(dpy);
1738 egl_surface_t const * const s = get_surface(draw);
Mathias Agopian6fc56992009-10-14 02:06:37 -07001739 if (s->cnx->egl.eglSetSwapRectangleANDROID) {
1740 return s->cnx->egl.eglSetSwapRectangleANDROID(
Mathias Agopian94263d72009-08-24 21:47:13 -07001741 dp->disp[s->impl].dpy, s->surface, left, top, width, height);
Mathias Agopian2e20bff2009-05-04 19:29:25 -07001742 }
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001743 return setError(EGL_BAD_DISPLAY, NULL);
Mathias Agopian2e20bff2009-05-04 19:29:25 -07001744}
1745
Mathias Agopianc1e3ec52009-06-24 22:37:39 -07001746EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
1747{
Mathias Agopian4a34e882009-08-21 02:18:25 -07001748 SurfaceRef _s(draw);
1749 if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLClientBuffer*)0);
1750
Mathias Agopianc1e3ec52009-06-24 22:37:39 -07001751 if (!validate_display_surface(dpy, draw))
1752 return 0;
1753 egl_display_t const * const dp = get_display(dpy);
1754 egl_surface_t const * const s = get_surface(draw);
Mathias Agopian6fc56992009-10-14 02:06:37 -07001755 if (s->cnx->egl.eglGetRenderBufferANDROID) {
1756 return s->cnx->egl.eglGetRenderBufferANDROID(
Mathias Agopian94263d72009-08-24 21:47:13 -07001757 dp->disp[s->impl].dpy, s->surface);
Mathias Agopianc1e3ec52009-06-24 22:37:39 -07001758 }
Mathias Agopian88e3e6b2009-08-12 21:18:15 -07001759 return setError(EGL_BAD_DISPLAY, (EGLClientBuffer*)0);
Mathias Agopianc1e3ec52009-06-24 22:37:39 -07001760}