blob: 03e764cccf3e880c06e1e5b32cdf4172fa01b4f9 [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001/*
2 ** Copyright 2007, The Android Open Source Project
3 **
4 ** Licensed under the Apache License, Version 2.0 (the "License");
5 ** you may not use this file except in compliance with the License.
6 ** You may obtain a copy of the License at
7 **
8 ** http://www.apache.org/licenses/LICENSE-2.0
9 **
10 ** Unless required by applicable law or agreed to in writing, software
11 ** distributed under the License is distributed on an "AS IS" BASIS,
12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 ** See the License for the specific language governing permissions and
14 ** limitations under the License.
15 */
16
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080017#include <ctype.h>
Mathias Agopiand8fb7b52009-05-17 18:50:16 -070018#include <stdlib.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080019#include <string.h>
20#include <errno.h>
21#include <dlfcn.h>
22
23#include <sys/ioctl.h>
24
25#if HAVE_ANDROID_OS
26#include <linux/android_pmem.h>
27#endif
28
29#include <EGL/egl.h>
30#include <EGL/eglext.h>
31#include <GLES/gl.h>
32#include <GLES/glext.h>
33
34#include <cutils/log.h>
35#include <cutils/atomic.h>
36#include <cutils/properties.h>
37#include <cutils/memory.h>
38
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080039#include "hooks.h"
40#include "egl_impl.h"
Mathias Agopiande586972009-05-28 17:39:03 -070041#include "Loader.h"
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080042
43#define MAKE_CONFIG(_impl, _index) ((EGLConfig)(((_impl)<<24) | (_index)))
44#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
45
46// ----------------------------------------------------------------------------
47namespace android {
48// ----------------------------------------------------------------------------
49
50#define VERSION_MAJOR 1
51#define VERSION_MINOR 4
52static char const * const gVendorString = "Android";
Mathias Agopian923c6612009-08-17 18:07:06 -070053static char const * const gVersionString = "1.4 Android META-EGL";
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080054static char const * const gClientApiString = "OpenGL ES";
Mathias Agopian076b1cc2009-04-10 14:24:30 -070055static char const * const gExtensionString =
56 "EGL_KHR_image "
Mathias Agopiane6bf8b32009-05-06 23:47:08 -070057 "EGL_KHR_image_base "
58 "EGL_KHR_image_pixmap "
Mathias Agopian076b1cc2009-04-10 14:24:30 -070059 "EGL_ANDROID_image_native_buffer "
Mathias Agopiandf3ca302009-05-04 19:29:25 -070060 "EGL_ANDROID_swap_rectangle "
Mathias Agopian8d2e83b2009-06-24 22:37:39 -070061 "EGL_ANDROID_get_render_buffer "
Mathias Agopian076b1cc2009-04-10 14:24:30 -070062 ;
63
64// ----------------------------------------------------------------------------
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080065
66template <int MAGIC>
67struct egl_object_t
68{
69 egl_object_t() : magic(MAGIC) { }
70 ~egl_object_t() { magic = 0; }
71 bool isValid() const { return magic == MAGIC; }
72private:
73 uint32_t magic;
74};
75
76struct egl_display_t : public egl_object_t<'_dpy'>
77{
Mathias Agopian076b1cc2009-04-10 14:24:30 -070078 EGLDisplay dpys[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
79 EGLConfig* configs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
80 EGLint numConfigs[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080081 EGLint numTotalConfigs;
82 char const* extensionsString;
83 volatile int32_t refs;
84 struct strings_t {
85 char const * vendor;
86 char const * version;
87 char const * clientApi;
88 char const * extensions;
89 };
Mathias Agopian076b1cc2009-04-10 14:24:30 -070090 strings_t queryString[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080091};
92
93struct egl_surface_t : public egl_object_t<'_srf'>
94{
95 egl_surface_t(EGLDisplay dpy, EGLSurface surface,
Mathias Agopian076b1cc2009-04-10 14:24:30 -070096 int impl, egl_connection_t const* cnx)
97 : dpy(dpy), surface(surface), impl(impl), cnx(cnx)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080098 {
99 // NOTE: window must be incRef'ed and connected already
100 }
101 ~egl_surface_t() {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800102 }
103 EGLDisplay dpy;
104 EGLSurface surface;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800105 int impl;
106 egl_connection_t const* cnx;
107};
108
109struct egl_context_t : public egl_object_t<'_ctx'>
110{
111 egl_context_t(EGLDisplay dpy, EGLContext context,
112 int impl, egl_connection_t const* cnx)
113 : dpy(dpy), context(context), read(0), draw(0), impl(impl), cnx(cnx)
114 {
115 }
116 EGLDisplay dpy;
117 EGLContext context;
118 EGLSurface read;
119 EGLSurface draw;
120 int impl;
121 egl_connection_t const* cnx;
122};
123
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700124struct egl_image_t : public egl_object_t<'_img'>
125{
126 egl_image_t(EGLDisplay dpy, EGLContext context)
127 : dpy(dpy), context(context)
128 {
129 memset(images, 0, sizeof(images));
130 }
131 EGLDisplay dpy;
132 EGLConfig context;
133 EGLImageKHR images[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
134};
135
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800136struct tls_t
137{
Mathias Agopiand274eae2009-07-31 16:21:17 -0700138 tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800139 EGLint error;
140 EGLContext ctx;
Mathias Agopiand274eae2009-07-31 16:21:17 -0700141 EGLBoolean logCallWithNoContext;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800142};
143
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800144
145// ----------------------------------------------------------------------------
146
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700147egl_connection_t gEGLImpl[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800148static egl_display_t gDisplay[NUM_DISPLAYS];
149static pthread_mutex_t gThreadLocalStorageKeyMutex = PTHREAD_MUTEX_INITIALIZER;
150static pthread_key_t gEGLThreadLocalStorageKey = -1;
151
152// ----------------------------------------------------------------------------
153
Mathias Agopianeccc8cf2009-05-13 00:19:22 -0700154EGLAPI gl_hooks_t gHooks[IMPL_NUM_IMPLEMENTATIONS];
155EGLAPI pthread_key_t gGLWrapperKey = -1;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800156
157// ----------------------------------------------------------------------------
158
159static __attribute__((noinline))
160const char *egl_strerror(EGLint err)
161{
162 switch (err){
163 case EGL_SUCCESS: return "EGL_SUCCESS";
164 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED";
165 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS";
166 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC";
167 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE";
168 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG";
169 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT";
170 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
171 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY";
172 case EGL_BAD_MATCH: return "EGL_BAD_MATCH";
173 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
174 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
175 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER";
176 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE";
177 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST";
178 default: return "UNKNOWN";
179 }
180}
181
182static __attribute__((noinline))
183void clearTLS() {
184 if (gEGLThreadLocalStorageKey != -1) {
185 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
186 if (tls) {
187 delete tls;
188 pthread_setspecific(gEGLThreadLocalStorageKey, 0);
189 }
190 }
191}
192
193static tls_t* getTLS()
194{
195 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
196 if (tls == 0) {
197 tls = new tls_t;
198 pthread_setspecific(gEGLThreadLocalStorageKey, tls);
199 }
200 return tls;
201}
202
203template<typename T>
204static __attribute__((noinline))
205T setErrorEtc(const char* caller, int line, EGLint error, T returnValue) {
206 if (gEGLThreadLocalStorageKey == -1) {
207 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
208 if (gEGLThreadLocalStorageKey == -1)
209 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
210 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
211 }
212 tls_t* tls = getTLS();
213 if (tls->error != error) {
214 LOGE("%s:%d error %x (%s)", caller, line, error, egl_strerror(error));
215 tls->error = error;
216 }
217 return returnValue;
218}
219
220static __attribute__((noinline))
221GLint getError() {
222 if (gEGLThreadLocalStorageKey == -1)
223 return EGL_SUCCESS;
224 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
225 if (!tls) return EGL_SUCCESS;
226 GLint error = tls->error;
227 tls->error = EGL_SUCCESS;
228 return error;
229}
230
231static __attribute__((noinline))
232void setContext(EGLContext ctx) {
233 if (gEGLThreadLocalStorageKey == -1) {
234 pthread_mutex_lock(&gThreadLocalStorageKeyMutex);
235 if (gEGLThreadLocalStorageKey == -1)
236 pthread_key_create(&gEGLThreadLocalStorageKey, NULL);
237 pthread_mutex_unlock(&gThreadLocalStorageKeyMutex);
238 }
239 tls_t* tls = getTLS();
240 tls->ctx = ctx;
241}
242
243static __attribute__((noinline))
244EGLContext getContext() {
245 if (gEGLThreadLocalStorageKey == -1)
246 return EGL_NO_CONTEXT;
247 tls_t* tls = (tls_t*)pthread_getspecific(gEGLThreadLocalStorageKey);
248 if (!tls) return EGL_NO_CONTEXT;
249 return tls->ctx;
250}
251
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800252/*****************************************************************************/
253
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800254template<typename T>
255static __attribute__((noinline))
256int binarySearch(
257 T const sortedArray[], int first, int last, T key)
258{
259 while (first <= last) {
260 int mid = (first + last) / 2;
261 if (key > sortedArray[mid]) {
262 first = mid + 1;
263 } else if (key < sortedArray[mid]) {
264 last = mid - 1;
265 } else {
266 return mid;
267 }
268 }
269 return -1;
270}
271
272static EGLint configToUniqueId(egl_display_t const* dp, int i, int index)
273{
274 // NOTE: this mapping works only if we have no more than two EGLimpl
275 return (i>0 ? dp->numConfigs[0] : 0) + index;
276}
277
278static void uniqueIdToConfig(egl_display_t const* dp, EGLint configId,
279 int& i, int& index)
280{
281 // NOTE: this mapping works only if we have no more than two EGLimpl
282 size_t numConfigs = dp->numConfigs[0];
283 i = configId / numConfigs;
284 index = configId % numConfigs;
285}
286
287static int cmp_configs(const void* a, const void *b)
288{
289 EGLConfig c0 = *(EGLConfig const *)a;
290 EGLConfig c1 = *(EGLConfig const *)b;
291 return c0<c1 ? -1 : (c0>c1 ? 1 : 0);
292}
293
294struct extention_map_t {
295 const char* name;
296 __eglMustCastToProperFunctionPointerType address;
297};
298
299static const extention_map_t gExtentionMap[] = {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700300 { "eglLockSurfaceKHR",
301 (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
302 { "eglUnlockSurfaceKHR",
303 (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
304 { "eglCreateImageKHR",
305 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
306 { "eglDestroyImageKHR",
307 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
Mathias Agopian8d2e83b2009-06-24 22:37:39 -0700308 { "eglSetSwapRectangleANDROID",
309 (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
310 { "eglGetRenderBufferANDROID",
311 (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800312};
313
314static extention_map_t gGLExtentionMap[MAX_NUMBER_OF_GL_EXTENSIONS];
315
316static void(*findProcAddress(const char* name,
317 const extention_map_t* map, size_t n))()
318{
319 for (uint32_t i=0 ; i<n ; i++) {
320 if (!strcmp(name, map[i].name)) {
321 return map[i].address;
322 }
323 }
324 return NULL;
325}
326
327// ----------------------------------------------------------------------------
328
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800329static void gl_no_context() {
Mathias Agopiand274eae2009-07-31 16:21:17 -0700330 tls_t* tls = getTLS();
331 if (tls->logCallWithNoContext == EGL_TRUE) {
332 tls->logCallWithNoContext = EGL_FALSE;
333 LOGE("call to OpenGL ES API with no current context "
334 "(logged once per thread)");
335 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800336}
Mathias Agopiand274eae2009-07-31 16:21:17 -0700337
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800338static void early_egl_init(void)
339{
340#if !USE_FAST_TLS_KEY
341 pthread_key_create(&gGLWrapperKey, NULL);
342#endif
343 uint32_t addr = (uint32_t)((void*)gl_no_context);
344 android_memset32(
345 (uint32_t*)(void*)&gHooks[IMPL_NO_CONTEXT],
346 addr,
347 sizeof(gHooks[IMPL_NO_CONTEXT]));
348 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
349}
350
351static pthread_once_t once_control = PTHREAD_ONCE_INIT;
352static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);
353
354
355static inline
356egl_display_t* get_display(EGLDisplay dpy)
357{
358 uintptr_t index = uintptr_t(dpy)-1U;
359 return (index >= NUM_DISPLAYS) ? NULL : &gDisplay[index];
360}
361
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700362template<typename NATIVE, typename EGL>
363static inline NATIVE* egl_to_native_cast(EGL arg) {
364 return reinterpret_cast<NATIVE*>(arg);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800365}
366
367static inline
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700368egl_surface_t* get_surface(EGLSurface surface) {
369 return egl_to_native_cast<egl_surface_t>(surface);
370}
371
372static inline
373egl_context_t* get_context(EGLContext context) {
374 return egl_to_native_cast<egl_context_t>(context);
375}
376
377static inline
378egl_image_t* get_image(EGLImageKHR image) {
379 return egl_to_native_cast<egl_image_t>(image);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800380}
381
382static egl_connection_t* validate_display_config(
383 EGLDisplay dpy, EGLConfig config,
384 egl_display_t const*& dp, int& impl, int& index)
385{
386 dp = get_display(dpy);
387 if (!dp) return setError(EGL_BAD_DISPLAY, (egl_connection_t*)NULL);
388
389 impl = uintptr_t(config)>>24;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700390 if (uint32_t(impl) >= IMPL_NUM_DRIVERS_IMPLEMENTATIONS) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800391 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
392 }
393 index = uintptr_t(config) & 0xFFFFFF;
394 if (index >= dp->numConfigs[impl]) {
395 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
396 }
397 egl_connection_t* const cnx = &gEGLImpl[impl];
398 if (cnx->dso == 0) {
399 return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
400 }
401 return cnx;
402}
403
404static EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
405{
406 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
407 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
408 if (!get_display(dpy)->isValid())
409 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
410 if (!ctx) // TODO: make sure context is a valid object
411 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
412 if (!get_context(ctx)->isValid())
413 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
414 return EGL_TRUE;
415}
416
417static EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
418{
419 if ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS)
420 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
421 if (!get_display(dpy)->isValid())
422 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
423 if (!surface) // TODO: make sure surface is a valid object
424 return setError(EGL_BAD_SURFACE, EGL_FALSE);
425 if (!get_surface(surface)->isValid())
426 return setError(EGL_BAD_SURFACE, EGL_FALSE);
427 return EGL_TRUE;
428}
429
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800430
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700431EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
432{
433 EGLContext context = getContext();
434 if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
435 return EGL_NO_IMAGE_KHR;
436
437 egl_context_t const * const c = get_context(context);
438 if (!c->isValid())
439 return EGL_NO_IMAGE_KHR;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800440
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700441 egl_image_t const * const i = get_image(image);
442 if (!i->isValid())
443 return EGL_NO_IMAGE_KHR;
444
445 return i->images[c->impl];
446}
447
Mathias Agopian923c6612009-08-17 18:07:06 -0700448// ----------------------------------------------------------------------------
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700449
Mathias Agopian923c6612009-08-17 18:07:06 -0700450// this mutex protects:
451// d->dpys[]
452// egl_init_drivers_locked()
453//
454static pthread_mutex_t gInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
455
456EGLBoolean egl_init_drivers_locked()
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800457{
458 if (sEarlyInitState) {
Mathias Agopian923c6612009-08-17 18:07:06 -0700459 // initialized by static ctor. should be set here.
460 return EGL_FALSE;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800461 }
462
Mathias Agopiande586972009-05-28 17:39:03 -0700463 // get our driver loader
Mathias Agopian923c6612009-08-17 18:07:06 -0700464 Loader& loader(Loader::getInstance());
Mathias Agopiande586972009-05-28 17:39:03 -0700465
Mathias Agopian923c6612009-08-17 18:07:06 -0700466 // dynamically load all our EGL implementations for all displays
467 // and retrieve the corresponding EGLDisplay
468 // if that fails, don't use this driver.
469 // TODO: currently we only deal with EGL_DEFAULT_DISPLAY
470 egl_connection_t* cnx;
471 egl_display_t* d = &gDisplay[0];
472
473 cnx = &gEGLImpl[IMPL_SOFTWARE];
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800474 if (cnx->dso == 0) {
475 cnx->hooks = &gHooks[IMPL_SOFTWARE];
Mathias Agopian923c6612009-08-17 18:07:06 -0700476 cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx->hooks);
477 if (cnx->dso) {
478 EGLDisplay dpy = cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
479 LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for software EGL!");
480 d->dpys[IMPL_SOFTWARE] = dpy;
481 if (dpy == EGL_NO_DISPLAY) {
482 loader.close(cnx->dso);
483 cnx->dso = NULL;
484 }
485 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800486 }
487
488 cnx = &gEGLImpl[IMPL_HARDWARE];
Mathias Agopian923c6612009-08-17 18:07:06 -0700489 if (cnx->dso == 0) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800490 char value[PROPERTY_VALUE_MAX];
491 property_get("debug.egl.hw", value, "1");
492 if (atoi(value) != 0) {
493 cnx->hooks = &gHooks[IMPL_HARDWARE];
Mathias Agopian923c6612009-08-17 18:07:06 -0700494 cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx->hooks);
495 if (cnx->dso) {
496 EGLDisplay dpy = cnx->hooks->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY);
497 LOGE_IF(dpy==EGL_NO_DISPLAY, "No EGLDisplay for hardware EGL!");
498 d->dpys[IMPL_HARDWARE] = dpy;
499 if (dpy == EGL_NO_DISPLAY) {
500 loader.close(cnx->dso);
501 cnx->dso = NULL;
502 }
503 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800504 } else {
505 LOGD("3D hardware acceleration is disabled");
506 }
507 }
Mathias Agopian923c6612009-08-17 18:07:06 -0700508
509 if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) {
510 return EGL_FALSE;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800511 }
512
Mathias Agopian923c6612009-08-17 18:07:06 -0700513 return EGL_TRUE;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800514}
515
Mathias Agopian923c6612009-08-17 18:07:06 -0700516EGLBoolean egl_init_drivers()
517{
518 EGLBoolean res;
519 pthread_mutex_lock(&gInitDriverMutex);
520 res = egl_init_drivers_locked();
521 pthread_mutex_unlock(&gInitDriverMutex);
522 return res;
523}
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700524
525// ----------------------------------------------------------------------------
526}; // namespace android
527// ----------------------------------------------------------------------------
528
529using namespace android;
530
531EGLDisplay eglGetDisplay(NativeDisplayType display)
532{
Mathias Agopian923c6612009-08-17 18:07:06 -0700533 uint32_t index = uint32_t(display);
534 if (index >= NUM_DISPLAYS) {
535 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
536 }
537
538 if (egl_init_drivers() == EGL_FALSE) {
539 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
540 }
541
542 EGLDisplay dpy = EGLDisplay(uintptr_t(display) + 1LU);
543 return dpy;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700544}
545
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800546// ----------------------------------------------------------------------------
547// Initialization
548// ----------------------------------------------------------------------------
549
550EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
551{
552 egl_display_t * const dp = get_display(dpy);
553 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
554
555 if (android_atomic_inc(&dp->refs) > 0) {
556 if (major != NULL) *major = VERSION_MAJOR;
557 if (minor != NULL) *minor = VERSION_MINOR;
558 return EGL_TRUE;
559 }
560
561 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
562
563 // initialize each EGL and
564 // build our own extension string first, based on the extension we know
565 // and the extension supported by our client implementation
566 dp->extensionsString = strdup(gExtensionString);
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700567 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800568 egl_connection_t* const cnx = &gEGLImpl[i];
569 cnx->major = -1;
570 cnx->minor = -1;
571 if (!cnx->dso)
572 continue;
573
574 if (cnx->hooks->egl.eglInitialize(
575 dp->dpys[i], &cnx->major, &cnx->minor)) {
576
577 //LOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p",
578 // i, dp->dpys[i], cnx->major, cnx->minor, cnx);
579
580 // get the query-strings for this display for each implementation
581 dp->queryString[i].vendor =
582 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VENDOR);
583 dp->queryString[i].version =
584 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_VERSION);
585 dp->queryString[i].extensions = strdup(
586 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_EXTENSIONS));
587 dp->queryString[i].clientApi =
588 cnx->hooks->egl.eglQueryString(dp->dpys[i], EGL_CLIENT_APIS);
589
590 } else {
591 LOGD("%d: eglInitialize() failed (%s)",
592 i, egl_strerror(cnx->hooks->egl.eglGetError()));
593 }
594 }
595
596 EGLBoolean res = EGL_FALSE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700597 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800598 egl_connection_t* const cnx = &gEGLImpl[i];
599 if (cnx->dso && cnx->major>=0 && cnx->minor>=0) {
600 EGLint n;
601 if (cnx->hooks->egl.eglGetConfigs(dp->dpys[i], 0, 0, &n)) {
602 dp->configs[i] = (EGLConfig*)malloc(sizeof(EGLConfig)*n);
603 if (dp->configs[i]) {
604 if (cnx->hooks->egl.eglGetConfigs(
605 dp->dpys[i], dp->configs[i], n, &dp->numConfigs[i]))
606 {
607 // sort the configurations so we can do binary searches
608 qsort( dp->configs[i],
609 dp->numConfigs[i],
610 sizeof(EGLConfig), cmp_configs);
611
612 dp->numTotalConfigs += n;
613 res = EGL_TRUE;
614 }
615 }
616 }
617 }
618 }
619
620 if (res == EGL_TRUE) {
621 if (major != NULL) *major = VERSION_MAJOR;
622 if (minor != NULL) *minor = VERSION_MINOR;
623 return EGL_TRUE;
624 }
625 return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
626}
627
628EGLBoolean eglTerminate(EGLDisplay dpy)
629{
Mathias Agopian923c6612009-08-17 18:07:06 -0700630 // NOTE: don't unload the drivers b/c some APIs can be called
631 // after eglTerminate() has been called. eglTerminate() only
632 // terminates an EGLDisplay, not a EGL itself.
633
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800634 egl_display_t* const dp = get_display(dpy);
635 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
636 if (android_atomic_dec(&dp->refs) != 1)
637 return EGL_TRUE;
Mathias Agopiande586972009-05-28 17:39:03 -0700638
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800639 EGLBoolean res = EGL_FALSE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700640 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800641 egl_connection_t* const cnx = &gEGLImpl[i];
642 if (cnx->dso) {
643 cnx->hooks->egl.eglTerminate(dp->dpys[i]);
Mathias Agopian923c6612009-08-17 18:07:06 -0700644 // REVISIT: it's unclear what to do if eglTerminate() fails
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800645 free(dp->configs[i]);
646 free((void*)dp->queryString[i].extensions);
647 dp->numConfigs[i] = 0;
648 dp->dpys[i] = EGL_NO_DISPLAY;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800649 res = EGL_TRUE;
650 }
651 }
652 free((void*)dp->extensionsString);
653 dp->extensionsString = 0;
654 dp->numTotalConfigs = 0;
655 clearTLS();
656 return res;
657}
658
659// ----------------------------------------------------------------------------
660// configuration
661// ----------------------------------------------------------------------------
662
663EGLBoolean eglGetConfigs( EGLDisplay dpy,
664 EGLConfig *configs,
665 EGLint config_size, EGLint *num_config)
666{
667 egl_display_t const * const dp = get_display(dpy);
668 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
669
670 GLint numConfigs = dp->numTotalConfigs;
671 if (!configs) {
672 *num_config = numConfigs;
673 return EGL_TRUE;
674 }
675 GLint n = 0;
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700676 for (int j=0 ; j<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; j++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800677 for (int i=0 ; i<dp->numConfigs[j] && config_size ; i++) {
678 *configs++ = MAKE_CONFIG(j, i);
679 config_size--;
680 n++;
681 }
682 }
683
684 *num_config = n;
685 return EGL_TRUE;
686}
687
688EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
689 EGLConfig *configs, EGLint config_size,
690 EGLint *num_config)
691{
692 egl_display_t const * const dp = get_display(dpy);
693 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
694
Jack Palevich749c63d2009-03-25 15:12:17 -0700695 if (num_config==0) {
696 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800697 }
698
699 EGLint n;
700 EGLBoolean res = EGL_FALSE;
701 *num_config = 0;
702
703
704 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
705 // to do this, we have to go through the attrib_list array once
706 // to figure out both its size and if it contains an EGL_CONFIG_ID
707 // key. If so, the full array is copied and patched.
708 // NOTE: we assume that there can be only one occurrence
709 // of EGL_CONFIG_ID.
710
711 EGLint patch_index = -1;
712 GLint attr;
713 size_t size = 0;
Mathias Agopiandacd7a32009-07-09 17:33:15 -0700714 while ((attr=attrib_list[size]) != EGL_NONE) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800715 if (attr == EGL_CONFIG_ID)
716 patch_index = size;
717 size += 2;
718 }
719 if (patch_index >= 0) {
720 size += 2; // we need copy the sentinel as well
721 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
722 if (new_list == 0)
723 return setError(EGL_BAD_ALLOC, EGL_FALSE);
724 memcpy(new_list, attrib_list, size*sizeof(EGLint));
725
726 // patch the requested EGL_CONFIG_ID
727 int i, index;
728 EGLint& configId(new_list[patch_index+1]);
729 uniqueIdToConfig(dp, configId, i, index);
730
731 egl_connection_t* const cnx = &gEGLImpl[i];
732 if (cnx->dso) {
733 cnx->hooks->egl.eglGetConfigAttrib(
734 dp->dpys[i], dp->configs[i][index],
735 EGL_CONFIG_ID, &configId);
736
737 // and switch to the new list
738 attrib_list = const_cast<const EGLint *>(new_list);
739
740 // At this point, the only configuration that can match is
741 // dp->configs[i][index], however, we don't know if it would be
742 // rejected because of the other attributes, so we do have to call
743 // cnx->hooks->egl.eglChooseConfig() -- but we don't have to loop
744 // through all the EGLimpl[].
745 // We also know we can only get a single config back, and we know
746 // which one.
747
748 res = cnx->hooks->egl.eglChooseConfig(
749 dp->dpys[i], attrib_list, configs, config_size, &n);
750 if (res && n>0) {
751 // n has to be 0 or 1, by construction, and we already know
752 // which config it will return (since there can be only one).
Jack Palevich749c63d2009-03-25 15:12:17 -0700753 if (configs) {
754 configs[0] = MAKE_CONFIG(i, index);
755 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800756 *num_config = 1;
757 }
758 }
759
760 free(const_cast<EGLint *>(attrib_list));
761 return res;
762 }
763
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700764 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800765 egl_connection_t* const cnx = &gEGLImpl[i];
766 if (cnx->dso) {
767 if (cnx->hooks->egl.eglChooseConfig(
768 dp->dpys[i], attrib_list, configs, config_size, &n)) {
Jack Palevich749c63d2009-03-25 15:12:17 -0700769 if (configs) {
770 // now we need to convert these client EGLConfig to our
771 // internal EGLConfig format. This is done in O(n log n).
772 for (int j=0 ; j<n ; j++) {
773 int index = binarySearch<EGLConfig>(
774 dp->configs[i], 0, dp->numConfigs[i]-1, configs[j]);
775 if (index >= 0) {
776 if (configs) {
777 configs[j] = MAKE_CONFIG(i, index);
778 }
779 } else {
780 return setError(EGL_BAD_CONFIG, EGL_FALSE);
781 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800782 }
Jack Palevich749c63d2009-03-25 15:12:17 -0700783 configs += n;
784 config_size -= n;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800785 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800786 *num_config += n;
787 res = EGL_TRUE;
788 }
789 }
790 }
791 return res;
792}
793
794EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
795 EGLint attribute, EGLint *value)
796{
797 egl_display_t const* dp = 0;
798 int i=0, index=0;
799 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
800 if (!cnx) return EGL_FALSE;
801
802 if (attribute == EGL_CONFIG_ID) {
803 // EGL_CONFIG_IDs must be unique, just use the order of the selected
804 // EGLConfig.
805 *value = configToUniqueId(dp, i, index);
806 return EGL_TRUE;
807 }
808 return cnx->hooks->egl.eglGetConfigAttrib(
809 dp->dpys[i], dp->configs[i][index], attribute, value);
810}
811
812// ----------------------------------------------------------------------------
813// surfaces
814// ----------------------------------------------------------------------------
815
816EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
817 NativeWindowType window,
818 const EGLint *attrib_list)
819{
820 egl_display_t const* dp = 0;
821 int i=0, index=0;
822 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
823 if (cnx) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800824 EGLSurface surface = cnx->hooks->egl.eglCreateWindowSurface(
825 dp->dpys[i], dp->configs[i][index], window, attrib_list);
826 if (surface != EGL_NO_SURFACE) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700827 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800828 return s;
829 }
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800830 }
831 return EGL_NO_SURFACE;
832}
833
834EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
835 NativePixmapType pixmap,
836 const EGLint *attrib_list)
837{
838 egl_display_t const* dp = 0;
839 int i=0, index=0;
840 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
841 if (cnx) {
842 EGLSurface surface = cnx->hooks->egl.eglCreatePixmapSurface(
843 dp->dpys[i], dp->configs[i][index], pixmap, attrib_list);
844 if (surface != EGL_NO_SURFACE) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700845 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800846 return s;
847 }
848 }
849 return EGL_NO_SURFACE;
850}
851
852EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
853 const EGLint *attrib_list)
854{
855 egl_display_t const* dp = 0;
856 int i=0, index=0;
857 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
858 if (cnx) {
859 EGLSurface surface = cnx->hooks->egl.eglCreatePbufferSurface(
860 dp->dpys[i], dp->configs[i][index], attrib_list);
861 if (surface != EGL_NO_SURFACE) {
Mathias Agopian076b1cc2009-04-10 14:24:30 -0700862 egl_surface_t* s = new egl_surface_t(dpy, surface, i, cnx);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800863 return s;
864 }
865 }
866 return EGL_NO_SURFACE;
867}
868
869EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
870{
871 if (!validate_display_surface(dpy, surface))
872 return EGL_FALSE;
873 egl_display_t const * const dp = get_display(dpy);
874 egl_surface_t const * const s = get_surface(surface);
875
876 EGLBoolean result = s->cnx->hooks->egl.eglDestroySurface(
877 dp->dpys[s->impl], s->surface);
878
879 delete s;
880 return result;
881}
882
883EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
884 EGLint attribute, EGLint *value)
885{
886 if (!validate_display_surface(dpy, surface))
887 return EGL_FALSE;
888 egl_display_t const * const dp = get_display(dpy);
889 egl_surface_t const * const s = get_surface(surface);
890
891 return s->cnx->hooks->egl.eglQuerySurface(
892 dp->dpys[s->impl], s->surface, attribute, value);
893}
894
895// ----------------------------------------------------------------------------
896// contextes
897// ----------------------------------------------------------------------------
898
899EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
900 EGLContext share_list, const EGLint *attrib_list)
901{
902 egl_display_t const* dp = 0;
903 int i=0, index=0;
904 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
905 if (cnx) {
906 EGLContext context = cnx->hooks->egl.eglCreateContext(
907 dp->dpys[i], dp->configs[i][index], share_list, attrib_list);
908 if (context != EGL_NO_CONTEXT) {
909 egl_context_t* c = new egl_context_t(dpy, context, i, cnx);
910 return c;
911 }
912 }
913 return EGL_NO_CONTEXT;
914}
915
916EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
917{
918 if (!validate_display_context(dpy, ctx))
919 return EGL_FALSE;
920 egl_display_t const * const dp = get_display(dpy);
921 egl_context_t * const c = get_context(ctx);
922 EGLBoolean result = c->cnx->hooks->egl.eglDestroyContext(
923 dp->dpys[c->impl], c->context);
924 delete c;
925 return result;
926}
927
928EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
929 EGLSurface read, EGLContext ctx)
930{
931 egl_display_t const * const dp = get_display(dpy);
932 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
933
934 if (read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE &&
935 ctx == EGL_NO_CONTEXT)
936 {
937 EGLBoolean result = EGL_TRUE;
938 ctx = getContext();
939 if (ctx) {
940 egl_context_t * const c = get_context(ctx);
941 result = c->cnx->hooks->egl.eglMakeCurrent(dp->dpys[c->impl], 0, 0, 0);
942 if (result == EGL_TRUE) {
943 setGlThreadSpecific(&gHooks[IMPL_NO_CONTEXT]);
944 setContext(EGL_NO_CONTEXT);
945 }
946 }
947 return result;
948 }
949
950 if (!validate_display_context(dpy, ctx))
951 return EGL_FALSE;
952
Mathias Agopianaf742132009-06-25 00:01:11 -0700953 EGLSurface impl_draw = EGL_NO_SURFACE;
954 EGLSurface impl_read = EGL_NO_SURFACE;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800955 egl_context_t * const c = get_context(ctx);
956 if (draw != EGL_NO_SURFACE) {
957 egl_surface_t const * d = get_surface(draw);
958 if (!d) return setError(EGL_BAD_SURFACE, EGL_FALSE);
959 if (d->impl != c->impl)
960 return setError(EGL_BAD_MATCH, EGL_FALSE);
Mathias Agopianaf742132009-06-25 00:01:11 -0700961 impl_draw = d->surface;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800962 }
963 if (read != EGL_NO_SURFACE) {
964 egl_surface_t const * r = get_surface(read);
965 if (!r) return setError(EGL_BAD_SURFACE, EGL_FALSE);
966 if (r->impl != c->impl)
967 return setError(EGL_BAD_MATCH, EGL_FALSE);
Mathias Agopianaf742132009-06-25 00:01:11 -0700968 impl_read = r->surface;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800969 }
970 EGLBoolean result = c->cnx->hooks->egl.eglMakeCurrent(
Mathias Agopianaf742132009-06-25 00:01:11 -0700971 dp->dpys[c->impl], impl_draw, impl_read, c->context);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800972
973 if (result == EGL_TRUE) {
974 setGlThreadSpecific(c->cnx->hooks);
975 setContext(ctx);
976 c->read = read;
977 c->draw = draw;
978 }
979 return result;
980}
981
982
983EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
984 EGLint attribute, EGLint *value)
985{
986 if (!validate_display_context(dpy, ctx))
987 return EGL_FALSE;
988
989 egl_display_t const * const dp = get_display(dpy);
990 egl_context_t * const c = get_context(ctx);
991
992 return c->cnx->hooks->egl.eglQueryContext(
993 dp->dpys[c->impl], c->context, attribute, value);
994}
995
996EGLContext eglGetCurrentContext(void)
997{
Mathias Agopian923c6612009-08-17 18:07:06 -0700998 // could be called before eglInitialize(), but we wouldn't have a context
999 // then, and this function would correctly return EGL_NO_CONTEXT.
1000
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001001 EGLContext ctx = getContext();
1002 return ctx;
1003}
1004
1005EGLSurface eglGetCurrentSurface(EGLint readdraw)
1006{
Mathias Agopian923c6612009-08-17 18:07:06 -07001007 // could be called before eglInitialize(), but we wouldn't have a context
1008 // then, and this function would correctly return EGL_NO_SURFACE.
1009
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001010 EGLContext ctx = getContext();
1011 if (ctx) {
1012 egl_context_t const * const c = get_context(ctx);
1013 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1014 switch (readdraw) {
1015 case EGL_READ: return c->read;
1016 case EGL_DRAW: return c->draw;
1017 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1018 }
1019 }
1020 return EGL_NO_SURFACE;
1021}
1022
1023EGLDisplay eglGetCurrentDisplay(void)
1024{
Mathias Agopian923c6612009-08-17 18:07:06 -07001025 // could be called before eglInitialize(), but we wouldn't have a context
1026 // then, and this function would correctly return EGL_NO_DISPLAY.
1027
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001028 EGLContext ctx = getContext();
1029 if (ctx) {
1030 egl_context_t const * const c = get_context(ctx);
1031 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
1032 return c->dpy;
1033 }
1034 return EGL_NO_DISPLAY;
1035}
1036
1037EGLBoolean eglWaitGL(void)
1038{
Mathias Agopian923c6612009-08-17 18:07:06 -07001039 // could be called before eglInitialize(), but we wouldn't have a context
1040 // then, and this function would return GL_TRUE, which isn't wrong.
1041
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001042 EGLBoolean res = EGL_TRUE;
1043 EGLContext ctx = getContext();
1044 if (ctx) {
1045 egl_context_t const * const c = get_context(ctx);
1046 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1047 if (uint32_t(c->impl)>=2)
1048 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1049 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1050 if (!cnx->dso)
1051 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1052 res = cnx->hooks->egl.eglWaitGL();
1053 }
1054 return res;
1055}
1056
1057EGLBoolean eglWaitNative(EGLint engine)
1058{
Mathias Agopian923c6612009-08-17 18:07:06 -07001059 // could be called before eglInitialize(), but we wouldn't have a context
1060 // then, and this function would return GL_TRUE, which isn't wrong.
1061
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001062 EGLBoolean res = EGL_TRUE;
1063 EGLContext ctx = getContext();
1064 if (ctx) {
1065 egl_context_t const * const c = get_context(ctx);
1066 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1067 if (uint32_t(c->impl)>=2)
1068 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1069 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1070 if (!cnx->dso)
1071 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1072 res = cnx->hooks->egl.eglWaitNative(engine);
1073 }
1074 return res;
1075}
1076
1077EGLint eglGetError(void)
1078{
1079 EGLint result = EGL_SUCCESS;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001080 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001081 EGLint err = EGL_SUCCESS;
1082 egl_connection_t* const cnx = &gEGLImpl[i];
1083 if (cnx->dso)
1084 err = cnx->hooks->egl.eglGetError();
1085 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
1086 result = err;
1087 }
1088 if (result == EGL_SUCCESS)
1089 result = getError();
1090 return result;
1091}
1092
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001093__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001094{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001095 // eglGetProcAddress() could be the very first function called
1096 // in which case we must make sure we've initialized ourselves, this
1097 // happens the first time egl_get_display() is called.
Mathias Agopian923c6612009-08-17 18:07:06 -07001098
1099 if (egl_init_drivers() == EGL_FALSE) {
1100 setError(EGL_BAD_PARAMETER, NULL);
1101 return NULL;
1102 }
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001103
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001104 __eglMustCastToProperFunctionPointerType addr;
1105 addr = findProcAddress(procname, gExtentionMap, NELEM(gExtentionMap));
1106 if (addr) return addr;
1107
1108 return NULL; // TODO: finish implementation below
1109
1110 addr = findProcAddress(procname, gGLExtentionMap, NELEM(gGLExtentionMap));
1111 if (addr) return addr;
1112
1113 addr = 0;
1114 int slot = -1;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001115 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001116 egl_connection_t* const cnx = &gEGLImpl[i];
1117 if (cnx->dso) {
1118 if (cnx->hooks->egl.eglGetProcAddress) {
1119 addr = cnx->hooks->egl.eglGetProcAddress(procname);
1120 if (addr) {
1121 if (slot == -1) {
1122 slot = 0; // XXX: find free slot
1123 if (slot == -1) {
1124 addr = 0;
1125 break;
1126 }
1127 }
1128 cnx->hooks->ext.extensions[slot] = addr;
1129 }
1130 }
1131 }
1132 }
1133
1134 if (slot >= 0) {
1135 addr = 0; // XXX: address of stub 'slot'
1136 gGLExtentionMap[slot].name = strdup(procname);
1137 gGLExtentionMap[slot].address = addr;
1138 }
1139
1140 return addr;
1141
1142
1143 /*
1144 * TODO: For OpenGL ES extensions, we must generate a stub
1145 * that looks like
1146 * mov r12, #0xFFFF0FFF
1147 * ldr r12, [r12, #-15]
1148 * ldr r12, [r12, #TLS_SLOT_OPENGL_API*4]
1149 * mov r12, [r12, #api_offset]
1150 * ldrne pc, r12
1151 * mov pc, #unsupported_extension
1152 *
1153 * and write the address of the extension in *all*
1154 * gl_hooks_t::gl_ext_t at offset "api_offset" from gl_hooks_t
1155 *
1156 */
1157}
1158
1159EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
1160{
1161 if (!validate_display_surface(dpy, draw))
1162 return EGL_FALSE;
1163 egl_display_t const * const dp = get_display(dpy);
1164 egl_surface_t const * const s = get_surface(draw);
1165 return s->cnx->hooks->egl.eglSwapBuffers(dp->dpys[s->impl], s->surface);
1166}
1167
1168EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
1169 NativePixmapType target)
1170{
1171 if (!validate_display_surface(dpy, surface))
1172 return EGL_FALSE;
1173 egl_display_t const * const dp = get_display(dpy);
1174 egl_surface_t const * const s = get_surface(surface);
1175 return s->cnx->hooks->egl.eglCopyBuffers(
1176 dp->dpys[s->impl], s->surface, target);
1177}
1178
1179const char* eglQueryString(EGLDisplay dpy, EGLint name)
1180{
1181 egl_display_t const * const dp = get_display(dpy);
1182 switch (name) {
1183 case EGL_VENDOR:
1184 return gVendorString;
1185 case EGL_VERSION:
1186 return gVersionString;
1187 case EGL_EXTENSIONS:
1188 return gExtensionString;
1189 case EGL_CLIENT_APIS:
1190 return gClientApiString;
1191 }
1192 return setError(EGL_BAD_PARAMETER, (const char *)0);
1193}
1194
1195
1196// ----------------------------------------------------------------------------
1197// EGL 1.1
1198// ----------------------------------------------------------------------------
1199
1200EGLBoolean eglSurfaceAttrib(
1201 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1202{
1203 if (!validate_display_surface(dpy, surface))
1204 return EGL_FALSE;
1205 egl_display_t const * const dp = get_display(dpy);
1206 egl_surface_t const * const s = get_surface(surface);
1207 if (s->cnx->hooks->egl.eglSurfaceAttrib) {
1208 return s->cnx->hooks->egl.eglSurfaceAttrib(
1209 dp->dpys[s->impl], s->surface, attribute, value);
1210 }
1211 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1212}
1213
1214EGLBoolean eglBindTexImage(
1215 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1216{
1217 if (!validate_display_surface(dpy, surface))
1218 return EGL_FALSE;
1219 egl_display_t const * const dp = get_display(dpy);
1220 egl_surface_t const * const s = get_surface(surface);
1221 if (s->cnx->hooks->egl.eglBindTexImage) {
1222 return s->cnx->hooks->egl.eglBindTexImage(
1223 dp->dpys[s->impl], s->surface, buffer);
1224 }
1225 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1226}
1227
1228EGLBoolean eglReleaseTexImage(
1229 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1230{
1231 if (!validate_display_surface(dpy, surface))
1232 return EGL_FALSE;
1233 egl_display_t const * const dp = get_display(dpy);
1234 egl_surface_t const * const s = get_surface(surface);
1235 if (s->cnx->hooks->egl.eglReleaseTexImage) {
1236 return s->cnx->hooks->egl.eglReleaseTexImage(
1237 dp->dpys[s->impl], s->surface, buffer);
1238 }
1239 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1240}
1241
1242EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1243{
1244 egl_display_t * const dp = get_display(dpy);
1245 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1246
1247 EGLBoolean res = EGL_TRUE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001248 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001249 egl_connection_t* const cnx = &gEGLImpl[i];
1250 if (cnx->dso) {
1251 if (cnx->hooks->egl.eglSwapInterval) {
1252 if (cnx->hooks->egl.eglSwapInterval(dp->dpys[i], interval) == EGL_FALSE) {
1253 res = EGL_FALSE;
1254 }
1255 }
1256 }
1257 }
1258 return res;
1259}
1260
1261
1262// ----------------------------------------------------------------------------
1263// EGL 1.2
1264// ----------------------------------------------------------------------------
1265
1266EGLBoolean eglWaitClient(void)
1267{
Mathias Agopian923c6612009-08-17 18:07:06 -07001268 // could be called before eglInitialize(), but we wouldn't have a context
1269 // then, and this function would return GL_TRUE, which isn't wrong.
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001270 EGLBoolean res = EGL_TRUE;
1271 EGLContext ctx = getContext();
1272 if (ctx) {
1273 egl_context_t const * const c = get_context(ctx);
1274 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1275 if (uint32_t(c->impl)>=2)
1276 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1277 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1278 if (!cnx->dso)
1279 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1280 if (cnx->hooks->egl.eglWaitClient) {
1281 res = cnx->hooks->egl.eglWaitClient();
1282 } else {
1283 res = cnx->hooks->egl.eglWaitGL();
1284 }
1285 }
1286 return res;
1287}
1288
1289EGLBoolean eglBindAPI(EGLenum api)
1290{
Mathias Agopian923c6612009-08-17 18:07:06 -07001291 if (egl_init_drivers() == EGL_FALSE) {
1292 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1293 }
1294
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001295 // bind this API on all EGLs
1296 EGLBoolean res = EGL_TRUE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001297 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001298 egl_connection_t* const cnx = &gEGLImpl[i];
1299 if (cnx->dso) {
1300 if (cnx->hooks->egl.eglBindAPI) {
1301 if (cnx->hooks->egl.eglBindAPI(api) == EGL_FALSE) {
1302 res = EGL_FALSE;
1303 }
1304 }
1305 }
1306 }
1307 return res;
1308}
1309
1310EGLenum eglQueryAPI(void)
1311{
Mathias Agopian923c6612009-08-17 18:07:06 -07001312 if (egl_init_drivers() == EGL_FALSE) {
1313 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1314 }
1315
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001316 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001317 egl_connection_t* const cnx = &gEGLImpl[i];
1318 if (cnx->dso) {
1319 if (cnx->hooks->egl.eglQueryAPI) {
1320 // the first one we find is okay, because they all
1321 // should be the same
1322 return cnx->hooks->egl.eglQueryAPI();
1323 }
1324 }
1325 }
1326 // or, it can only be OpenGL ES
1327 return EGL_OPENGL_ES_API;
1328}
1329
1330EGLBoolean eglReleaseThread(void)
1331{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001332 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001333 egl_connection_t* const cnx = &gEGLImpl[i];
1334 if (cnx->dso) {
1335 if (cnx->hooks->egl.eglReleaseThread) {
1336 cnx->hooks->egl.eglReleaseThread();
1337 }
1338 }
1339 }
1340 clearTLS();
1341 return EGL_TRUE;
1342}
1343
1344EGLSurface eglCreatePbufferFromClientBuffer(
1345 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1346 EGLConfig config, const EGLint *attrib_list)
1347{
1348 egl_display_t const* dp = 0;
1349 int i=0, index=0;
1350 egl_connection_t* cnx = validate_display_config(dpy, config, dp, i, index);
1351 if (!cnx) return EGL_FALSE;
1352 if (cnx->hooks->egl.eglCreatePbufferFromClientBuffer) {
1353 return cnx->hooks->egl.eglCreatePbufferFromClientBuffer(
1354 dp->dpys[i], buftype, buffer, dp->configs[i][index], attrib_list);
1355 }
1356 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1357}
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001358
1359// ----------------------------------------------------------------------------
1360// EGL_EGLEXT_VERSION 3
1361// ----------------------------------------------------------------------------
1362
1363EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1364 const EGLint *attrib_list)
1365{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001366 if (!validate_display_surface(dpy, surface))
Mathias Agopian24e5f522009-08-12 21:18:15 -07001367 return EGL_FALSE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001368
1369 egl_display_t const * const dp = get_display(dpy);
1370 egl_surface_t const * const s = get_surface(surface);
1371
1372 if (s->cnx->hooks->egl.eglLockSurfaceKHR) {
Mathias Agopian24e5f522009-08-12 21:18:15 -07001373 return s->cnx->hooks->egl.eglLockSurfaceKHR(
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001374 dp->dpys[s->impl], s->surface, attrib_list);
1375 }
Mathias Agopian24e5f522009-08-12 21:18:15 -07001376 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001377}
1378
1379EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1380{
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001381 if (!validate_display_surface(dpy, surface))
Mathias Agopian24e5f522009-08-12 21:18:15 -07001382 return EGL_FALSE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001383
1384 egl_display_t const * const dp = get_display(dpy);
1385 egl_surface_t const * const s = get_surface(surface);
1386
1387 if (s->cnx->hooks->egl.eglUnlockSurfaceKHR) {
Mathias Agopian24e5f522009-08-12 21:18:15 -07001388 return s->cnx->hooks->egl.eglUnlockSurfaceKHR(
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001389 dp->dpys[s->impl], s->surface);
1390 }
Mathias Agopian24e5f522009-08-12 21:18:15 -07001391 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001392}
1393
1394EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1395 EGLClientBuffer buffer, const EGLint *attrib_list)
1396{
1397 if (ctx != EGL_NO_CONTEXT) {
1398 if (!validate_display_context(dpy, ctx))
1399 return EGL_NO_IMAGE_KHR;
1400 egl_display_t const * const dp = get_display(dpy);
1401 egl_context_t * const c = get_context(ctx);
1402 // since we have an EGLContext, we know which implementation to use
1403 EGLImageKHR image = c->cnx->hooks->egl.eglCreateImageKHR(
1404 dp->dpys[c->impl], c->context, target, buffer, attrib_list);
1405 if (image == EGL_NO_IMAGE_KHR)
1406 return image;
1407
1408 egl_image_t* result = new egl_image_t(dpy, ctx);
1409 result->images[c->impl] = image;
1410 return (EGLImageKHR)result;
1411 } else {
1412 // EGL_NO_CONTEXT is a valid parameter
1413 egl_display_t const * const dp = get_display(dpy);
1414 if (dp == 0) {
1415 return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
1416 }
1417 // since we don't have a way to know which implementation to call,
1418 // we're calling all of them
1419
1420 EGLImageKHR implImages[IMPL_NUM_DRIVERS_IMPLEMENTATIONS];
1421 bool success = false;
1422 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1423 egl_connection_t* const cnx = &gEGLImpl[i];
1424 implImages[i] = EGL_NO_IMAGE_KHR;
1425 if (cnx->dso) {
1426 if (cnx->hooks->egl.eglCreateImageKHR) {
1427 implImages[i] = cnx->hooks->egl.eglCreateImageKHR(
1428 dp->dpys[i], ctx, target, buffer, attrib_list);
1429 if (implImages[i] != EGL_NO_IMAGE_KHR) {
1430 success = true;
1431 }
1432 }
1433 }
1434 }
1435 if (!success)
1436 return EGL_NO_IMAGE_KHR;
1437
1438 egl_image_t* result = new egl_image_t(dpy, ctx);
1439 memcpy(result->images, implImages, sizeof(implImages));
1440 return (EGLImageKHR)result;
1441 }
1442}
1443
1444EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1445{
1446 egl_display_t const * const dp = get_display(dpy);
1447 if (dp == 0) {
1448 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1449 }
1450
1451 egl_image_t* image = get_image(img);
1452 if (!image->isValid()) {
1453 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1454 }
1455
1456 bool success = false;
1457 for (int i=0 ; i<IMPL_NUM_DRIVERS_IMPLEMENTATIONS ; i++) {
1458 egl_connection_t* const cnx = &gEGLImpl[i];
1459 if (image->images[i] != EGL_NO_IMAGE_KHR) {
1460 if (cnx->dso) {
1461 if (cnx->hooks->egl.eglCreateImageKHR) {
1462 if (cnx->hooks->egl.eglDestroyImageKHR(
1463 dp->dpys[i], image->images[i])) {
1464 success = true;
1465 }
1466 }
1467 }
1468 }
1469 }
1470 if (!success)
1471 return EGL_FALSE;
1472
1473 delete image;
1474
Mathias Agopian24e5f522009-08-12 21:18:15 -07001475 return EGL_TRUE;
Mathias Agopian076b1cc2009-04-10 14:24:30 -07001476}
Mathias Agopiandf3ca302009-05-04 19:29:25 -07001477
1478
1479// ----------------------------------------------------------------------------
1480// ANDROID extensions
1481// ----------------------------------------------------------------------------
1482
1483EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1484 EGLint left, EGLint top, EGLint width, EGLint height)
1485{
1486 if (!validate_display_surface(dpy, draw))
1487 return EGL_FALSE;
1488 egl_display_t const * const dp = get_display(dpy);
1489 egl_surface_t const * const s = get_surface(draw);
1490 if (s->cnx->hooks->egl.eglSetSwapRectangleANDROID) {
1491 return s->cnx->hooks->egl.eglSetSwapRectangleANDROID(dp->dpys[s->impl],
1492 s->surface, left, top, width, height);
1493 }
Mathias Agopian24e5f522009-08-12 21:18:15 -07001494 return setError(EGL_BAD_DISPLAY, NULL);
Mathias Agopiandf3ca302009-05-04 19:29:25 -07001495}
1496
Mathias Agopian8d2e83b2009-06-24 22:37:39 -07001497EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
1498{
1499 if (!validate_display_surface(dpy, draw))
1500 return 0;
1501 egl_display_t const * const dp = get_display(dpy);
1502 egl_surface_t const * const s = get_surface(draw);
1503 if (s->cnx->hooks->egl.eglGetRenderBufferANDROID) {
1504 return s->cnx->hooks->egl.eglGetRenderBufferANDROID(dp->dpys[s->impl],
1505 s->surface);
1506 }
Mathias Agopian24e5f522009-08-12 21:18:15 -07001507 return setError(EGL_BAD_DISPLAY, (EGLClientBuffer*)0);
Mathias Agopian8d2e83b2009-06-24 22:37:39 -07001508}