blob: 7d5d01084fc57ff2c4ae1a17053266431d9ce9b9 [file] [log] [blame]
Mathias Agopian518ec112011-05-13 16:21:08 -07001/*
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
17#include <ctype.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include <hardware/gralloc.h>
22#include <system/window.h>
23
24#include <EGL/egl.h>
25#include <EGL/eglext.h>
26#include <GLES/gl.h>
27#include <GLES/glext.h>
28
29#include <cutils/log.h>
30#include <cutils/atomic.h>
31#include <cutils/properties.h>
32#include <cutils/memory.h>
33
34#include <utils/KeyedVector.h>
35#include <utils/SortedVector.h>
36#include <utils/String8.h>
37
38#include "egl_impl.h"
39#include "egl_tls.h"
40#include "glesv2dbg.h"
41#include "hooks.h"
42
43#include "egl_display.h"
44#include "egl_impl.h"
45#include "egl_object.h"
46#include "egl_tls.h"
47
48using namespace android;
49
50// ----------------------------------------------------------------------------
51
52static char const * const sVendorString = "Android";
53static char const * const sVersionString = "1.4 Android META-EGL";
54static char const * const sClientApiString = "OpenGL ES";
55static char const * const sExtensionString =
56 "EGL_KHR_image "
57 "EGL_KHR_image_base "
58 "EGL_KHR_image_pixmap "
59 "EGL_KHR_gl_texture_2D_image "
60 "EGL_KHR_gl_texture_cubemap_image "
61 "EGL_KHR_gl_renderbuffer_image "
62 "EGL_KHR_fence_sync "
63 "EGL_ANDROID_image_native_buffer "
64 "EGL_ANDROID_swap_rectangle "
65 ;
66
67struct extention_map_t {
68 const char* name;
69 __eglMustCastToProperFunctionPointerType address;
70};
71
72static const extention_map_t sExtentionMap[] = {
73 { "eglLockSurfaceKHR",
74 (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
75 { "eglUnlockSurfaceKHR",
76 (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
77 { "eglCreateImageKHR",
78 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
79 { "eglDestroyImageKHR",
80 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
81 { "eglSetSwapRectangleANDROID",
82 (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
83};
84
85// accesses protected by sExtensionMapMutex
86static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
87static int sGLExtentionSlot = 0;
88static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER;
89
90static void(*findProcAddress(const char* name,
91 const extention_map_t* map, size_t n))() {
92 for (uint32_t i=0 ; i<n ; i++) {
93 if (!strcmp(name, map[i].name)) {
94 return map[i].address;
95 }
96 }
97 return NULL;
98}
99
100// ----------------------------------------------------------------------------
101
102template<typename T>
103static __attribute__((noinline))
104int binarySearch(T const sortedArray[], int first, int last, T key) {
105 while (first <= last) {
106 int mid = (first + last) / 2;
107 if (sortedArray[mid] < key) {
108 first = mid + 1;
109 } else if (key < sortedArray[mid]) {
110 last = mid - 1;
111 } else {
112 return mid;
113 }
114 }
115 return -1;
116}
117
118// ----------------------------------------------------------------------------
119
120namespace android {
121extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
122extern EGLBoolean egl_init_drivers();
123extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
124extern int gEGLDebugLevel;
125extern gl_hooks_t gHooksTrace;
126extern gl_hooks_t gHooksDebug;
127} // namespace android;
128
129// ----------------------------------------------------------------------------
130
131static inline void clearError() { egl_tls_t::clearError(); }
132static inline EGLContext getContext() { return egl_tls_t::getContext(); }
133
134// ----------------------------------------------------------------------------
135
136EGLDisplay eglGetDisplay(EGLNativeDisplayType display)
137{
138 clearError();
139
140 uint32_t index = uint32_t(display);
141 if (index >= NUM_DISPLAYS) {
142 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
143 }
144
145 if (egl_init_drivers() == EGL_FALSE) {
146 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
147 }
148
149 EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);
150 return dpy;
151}
152
153// ----------------------------------------------------------------------------
154// Initialization
155// ----------------------------------------------------------------------------
156
157EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
158{
159 clearError();
160
161 egl_display_t * const dp = get_display(dpy);
162 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
163
164 EGLBoolean res = dp->initialize(major, minor);
165
166 return res;
167}
168
169EGLBoolean eglTerminate(EGLDisplay dpy)
170{
171 // NOTE: don't unload the drivers b/c some APIs can be called
172 // after eglTerminate() has been called. eglTerminate() only
173 // terminates an EGLDisplay, not a EGL itself.
174
175 clearError();
176
177 egl_display_t* const dp = get_display(dpy);
178 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
179
180 EGLBoolean res = dp->terminate();
181
182 return res;
183}
184
185// ----------------------------------------------------------------------------
186// configuration
187// ----------------------------------------------------------------------------
188
189EGLBoolean eglGetConfigs( EGLDisplay dpy,
190 EGLConfig *configs,
191 EGLint config_size, EGLint *num_config)
192{
193 clearError();
194
195 egl_display_t const * const dp = validate_display(dpy);
196 if (!dp) return EGL_FALSE;
197
198 GLint numConfigs = dp->numTotalConfigs;
199 if (!configs) {
200 *num_config = numConfigs;
201 return EGL_TRUE;
202 }
203
204 GLint n = 0;
205 for (intptr_t i=0 ; i<dp->numTotalConfigs && config_size ; i++) {
206 *configs++ = EGLConfig(i);
207 config_size--;
208 n++;
209 }
210
211 *num_config = n;
212 return EGL_TRUE;
213}
214
215EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
216 EGLConfig *configs, EGLint config_size,
217 EGLint *num_config)
218{
219 clearError();
220
221 egl_display_t const * const dp = validate_display(dpy);
222 if (!dp) return EGL_FALSE;
223
224 if (num_config==0) {
225 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
226 }
227
228 EGLint n;
229 EGLBoolean res = EGL_FALSE;
230 *num_config = 0;
231
232
233 // It is unfortunate, but we need to remap the EGL_CONFIG_IDs,
234 // to do this, we have to go through the attrib_list array once
235 // to figure out both its size and if it contains an EGL_CONFIG_ID
236 // key. If so, the full array is copied and patched.
237 // NOTE: we assume that there can be only one occurrence
238 // of EGL_CONFIG_ID.
239
240 EGLint patch_index = -1;
241 GLint attr;
242 size_t size = 0;
243 if (attrib_list) {
244 while ((attr=attrib_list[size]) != EGL_NONE) {
245 if (attr == EGL_CONFIG_ID)
246 patch_index = size;
247 size += 2;
248 }
249 }
250 if (patch_index >= 0) {
251 size += 2; // we need copy the sentinel as well
252 EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint));
253 if (new_list == 0)
254 return setError(EGL_BAD_ALLOC, EGL_FALSE);
255 memcpy(new_list, attrib_list, size*sizeof(EGLint));
256
257 // patch the requested EGL_CONFIG_ID
258 bool found = false;
259 EGLConfig ourConfig(0);
260 EGLint& configId(new_list[patch_index+1]);
261 for (intptr_t i=0 ; i<dp->numTotalConfigs ; i++) {
262 if (dp->configs[i].configId == configId) {
263 ourConfig = EGLConfig(i);
264 configId = dp->configs[i].implConfigId;
265 found = true;
266 break;
267 }
268 }
269
270 egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(ourConfig)].impl];
271 if (found && cnx->dso) {
272 // and switch to the new list
273 attrib_list = const_cast<const EGLint *>(new_list);
274
275 // At this point, the only configuration that can match is
276 // dp->configs[i][index], however, we don't know if it would be
277 // rejected because of the other attributes, so we do have to call
278 // cnx->egl.eglChooseConfig() -- but we don't have to loop
279 // through all the EGLimpl[].
280 // We also know we can only get a single config back, and we know
281 // which one.
282
283 res = cnx->egl.eglChooseConfig(
284 dp->disp[ dp->configs[intptr_t(ourConfig)].impl ].dpy,
285 attrib_list, configs, config_size, &n);
286 if (res && n>0) {
287 // n has to be 0 or 1, by construction, and we already know
288 // which config it will return (since there can be only one).
289 if (configs) {
290 configs[0] = ourConfig;
291 }
292 *num_config = 1;
293 }
294 }
295
296 free(const_cast<EGLint *>(attrib_list));
297 return res;
298 }
299
300
301 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
302 egl_connection_t* const cnx = &gEGLImpl[i];
303 if (cnx->dso) {
304 if (cnx->egl.eglChooseConfig(
305 dp->disp[i].dpy, attrib_list, configs, config_size, &n)) {
306 if (configs) {
307 // now we need to convert these client EGLConfig to our
308 // internal EGLConfig format.
309 // This is done in O(n Log(n)) time.
310 for (int j=0 ; j<n ; j++) {
311 egl_config_t key(i, configs[j]);
312 intptr_t index = binarySearch<egl_config_t>(
313 dp->configs, 0, dp->numTotalConfigs, key);
314 if (index >= 0) {
315 configs[j] = EGLConfig(index);
316 } else {
317 return setError(EGL_BAD_CONFIG, EGL_FALSE);
318 }
319 }
320 configs += n;
321 config_size -= n;
322 }
323 *num_config += n;
324 res = EGL_TRUE;
325 }
326 }
327 }
328 return res;
329}
330
331EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
332 EGLint attribute, EGLint *value)
333{
334 clearError();
335
336 egl_display_t const* dp = 0;
337 egl_connection_t* cnx = validate_display_config(dpy, config, dp);
338 if (!cnx) return EGL_FALSE;
339
340 if (attribute == EGL_CONFIG_ID) {
341 *value = dp->configs[intptr_t(config)].configId;
342 return EGL_TRUE;
343 }
344 return cnx->egl.eglGetConfigAttrib(
345 dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
346 dp->configs[intptr_t(config)].config, attribute, value);
347}
348
349// ----------------------------------------------------------------------------
350// surfaces
351// ----------------------------------------------------------------------------
352
353EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
354 NativeWindowType window,
355 const EGLint *attrib_list)
356{
357 clearError();
358
359 egl_display_t const* dp = 0;
360 egl_connection_t* cnx = validate_display_config(dpy, config, dp);
361 if (cnx) {
362 EGLDisplay iDpy = dp->disp[ dp->configs[intptr_t(config)].impl ].dpy;
363 EGLConfig iConfig = dp->configs[intptr_t(config)].config;
364 EGLint format;
365
366 // set the native window's buffers format to match this config
367 if (cnx->egl.eglGetConfigAttrib(iDpy,
368 iConfig, EGL_NATIVE_VISUAL_ID, &format)) {
369 if (format != 0) {
370 native_window_set_buffers_geometry(window, 0, 0, format);
371 }
372 }
373
374 EGLSurface surface = cnx->egl.eglCreateWindowSurface(
375 iDpy, iConfig, window, attrib_list);
376 if (surface != EGL_NO_SURFACE) {
377 egl_surface_t* s = new egl_surface_t(dpy, config, window, surface,
378 dp->configs[intptr_t(config)].impl, cnx);
379 return s;
380 }
381 }
382 return EGL_NO_SURFACE;
383}
384
385EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
386 NativePixmapType pixmap,
387 const EGLint *attrib_list)
388{
389 clearError();
390
391 egl_display_t const* dp = 0;
392 egl_connection_t* cnx = validate_display_config(dpy, config, dp);
393 if (cnx) {
394 EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
395 dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
396 dp->configs[intptr_t(config)].config, pixmap, attrib_list);
397 if (surface != EGL_NO_SURFACE) {
398 egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
399 dp->configs[intptr_t(config)].impl, cnx);
400 return s;
401 }
402 }
403 return EGL_NO_SURFACE;
404}
405
406EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
407 const EGLint *attrib_list)
408{
409 clearError();
410
411 egl_display_t const* dp = 0;
412 egl_connection_t* cnx = validate_display_config(dpy, config, dp);
413 if (cnx) {
414 EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
415 dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
416 dp->configs[intptr_t(config)].config, attrib_list);
417 if (surface != EGL_NO_SURFACE) {
418 egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface,
419 dp->configs[intptr_t(config)].impl, cnx);
420 return s;
421 }
422 }
423 return EGL_NO_SURFACE;
424}
425
426EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
427{
428 clearError();
429
430 egl_display_t const * const dp = validate_display(dpy);
431 if (!dp) return EGL_FALSE;
432
433 SurfaceRef _s(surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700434 if (!_s.get())
435 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -0700436
437 egl_surface_t * const s = get_surface(surface);
438 EGLBoolean result = s->cnx->egl.eglDestroySurface(
439 dp->disp[s->impl].dpy, s->surface);
440 if (result == EGL_TRUE) {
441 if (s->win != NULL) {
442 native_window_set_buffers_geometry(s->win.get(), 0, 0, 0);
443 }
444 _s.terminate();
445 }
446 return result;
447}
448
449EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
450 EGLint attribute, EGLint *value)
451{
452 clearError();
453
454 egl_display_t const * const dp = validate_display(dpy);
455 if (!dp) return EGL_FALSE;
456
457 SurfaceRef _s(surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700458 if (!_s.get())
459 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -0700460
Mathias Agopian518ec112011-05-13 16:21:08 -0700461 egl_surface_t const * const s = get_surface(surface);
Mathias Agopian518ec112011-05-13 16:21:08 -0700462 EGLBoolean result(EGL_TRUE);
463 if (attribute == EGL_CONFIG_ID) {
464 // We need to remap EGL_CONFIG_IDs
465 *value = dp->configs[intptr_t(s->config)].configId;
466 } else {
467 result = s->cnx->egl.eglQuerySurface(
468 dp->disp[s->impl].dpy, s->surface, attribute, value);
469 }
470
471 return result;
472}
473
474// ----------------------------------------------------------------------------
475// Contexts
476// ----------------------------------------------------------------------------
477
478EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
479 EGLContext share_list, const EGLint *attrib_list)
480{
481 clearError();
482
483 egl_display_t const* dp = 0;
484 egl_connection_t* cnx = validate_display_config(dpy, config, dp);
485 if (cnx) {
486 if (share_list != EGL_NO_CONTEXT) {
487 egl_context_t* const c = get_context(share_list);
488 share_list = c->context;
489 }
490 EGLContext context = cnx->egl.eglCreateContext(
491 dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
492 dp->configs[intptr_t(config)].config,
493 share_list, attrib_list);
494 if (context != EGL_NO_CONTEXT) {
495 // figure out if it's a GLESv1 or GLESv2
496 int version = 0;
497 if (attrib_list) {
498 while (*attrib_list != EGL_NONE) {
499 GLint attr = *attrib_list++;
500 GLint value = *attrib_list++;
501 if (attr == EGL_CONTEXT_CLIENT_VERSION) {
502 if (value == 1) {
503 version = GLESv1_INDEX;
504 } else if (value == 2) {
505 version = GLESv2_INDEX;
506 }
507 }
508 };
509 }
510 egl_context_t* c = new egl_context_t(dpy, context, config,
511 dp->configs[intptr_t(config)].impl, cnx, version);
512 return c;
513 }
514 }
515 return EGL_NO_CONTEXT;
516}
517
518EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
519{
520 clearError();
521
522 egl_display_t const * const dp = validate_display(dpy);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700523 if (!dp)
524 return EGL_FALSE;
Mathias Agopian518ec112011-05-13 16:21:08 -0700525
526 ContextRef _c(ctx);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700527 if (!_c.get())
528 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -0700529
Mathias Agopian518ec112011-05-13 16:21:08 -0700530 egl_context_t * const c = get_context(ctx);
531 EGLBoolean result = c->cnx->egl.eglDestroyContext(
532 dp->disp[c->impl].dpy, c->context);
533 if (result == EGL_TRUE) {
534 _c.terminate();
535 }
536 return result;
537}
538
539static void loseCurrent(egl_context_t * cur_c)
540{
541 if (cur_c) {
542 egl_surface_t * cur_r = get_surface(cur_c->read);
543 egl_surface_t * cur_d = get_surface(cur_c->draw);
544
545 // by construction, these are either 0 or valid (possibly terminated)
546 // it should be impossible for these to be invalid
547 ContextRef _cur_c(cur_c);
548 SurfaceRef _cur_r(cur_r);
549 SurfaceRef _cur_d(cur_d);
550
551 cur_c->read = NULL;
552 cur_c->draw = NULL;
553
554 _cur_c.release();
555 _cur_r.release();
556 _cur_d.release();
557 }
558}
559
560EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
561 EGLSurface read, EGLContext ctx)
562{
563 clearError();
564
565 egl_display_t const * const dp = get_display(dpy);
566 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
567
Mathias Agopian5b287a62011-05-16 18:58:55 -0700568 // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
569 // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
570 // a valid but uninitialized display.
Mathias Agopian518ec112011-05-13 16:21:08 -0700571 if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
572 (draw != EGL_NO_SURFACE) ) {
573 if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
574 }
575
576 // get a reference to the object passed in
577 ContextRef _c(ctx);
578 SurfaceRef _d(draw);
579 SurfaceRef _r(read);
580
581 // validate the context (if not EGL_NO_CONTEXT)
Mathias Agopian5b287a62011-05-16 18:58:55 -0700582 if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
Mathias Agopian518ec112011-05-13 16:21:08 -0700583 // EGL_NO_CONTEXT is valid
584 return EGL_FALSE;
585 }
586
587 // these are the underlying implementation's object
588 EGLContext impl_ctx = EGL_NO_CONTEXT;
589 EGLSurface impl_draw = EGL_NO_SURFACE;
590 EGLSurface impl_read = EGL_NO_SURFACE;
591
592 // these are our objects structs passed in
593 egl_context_t * c = NULL;
594 egl_surface_t const * d = NULL;
595 egl_surface_t const * r = NULL;
596
597 // these are the current objects structs
598 egl_context_t * cur_c = get_context(getContext());
599
600 if (ctx != EGL_NO_CONTEXT) {
601 c = get_context(ctx);
602 impl_ctx = c->context;
603 } else {
604 // no context given, use the implementation of the current context
605 if (cur_c == NULL) {
606 // no current context
607 if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
608 // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
609 return setError(EGL_BAD_MATCH, EGL_FALSE);
610 }
611 // not an error, there is just no current context.
612 return EGL_TRUE;
613 }
614 }
615
616 // retrieve the underlying implementation's draw EGLSurface
617 if (draw != EGL_NO_SURFACE) {
618 d = get_surface(draw);
619 // make sure the EGLContext and EGLSurface passed in are for
620 // the same driver
621 if (c && d->impl != c->impl)
622 return setError(EGL_BAD_MATCH, EGL_FALSE);
623 impl_draw = d->surface;
624 }
625
626 // retrieve the underlying implementation's read EGLSurface
627 if (read != EGL_NO_SURFACE) {
628 r = get_surface(read);
629 // make sure the EGLContext and EGLSurface passed in are for
630 // the same driver
631 if (c && r->impl != c->impl)
632 return setError(EGL_BAD_MATCH, EGL_FALSE);
633 impl_read = r->surface;
634 }
635
636 EGLBoolean result;
637
638 if (c) {
639 result = c->cnx->egl.eglMakeCurrent(
640 dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
641 } else {
642 result = cur_c->cnx->egl.eglMakeCurrent(
643 dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
644 }
645
646 if (result == EGL_TRUE) {
647
648 loseCurrent(cur_c);
649
650 if (ctx != EGL_NO_CONTEXT) {
651 setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
652 egl_tls_t::setContext(ctx);
653 if (gEGLDebugLevel > 0) {
654 CreateDbgContext(c->version, c->cnx->hooks[c->version]);
655 }
656 _c.acquire();
657 _r.acquire();
658 _d.acquire();
659 c->read = read;
660 c->draw = draw;
661 } else {
662 setGLHooksThreadSpecific(&gHooksNoContext);
663 egl_tls_t::setContext(EGL_NO_CONTEXT);
664 }
665 }
666 return result;
667}
668
669
670EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
671 EGLint attribute, EGLint *value)
672{
673 clearError();
674
675 egl_display_t const * const dp = validate_display(dpy);
676 if (!dp) return EGL_FALSE;
677
678 ContextRef _c(ctx);
679 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
680
Mathias Agopian518ec112011-05-13 16:21:08 -0700681 egl_context_t * const c = get_context(ctx);
682
683 EGLBoolean result(EGL_TRUE);
684 if (attribute == EGL_CONFIG_ID) {
685 *value = dp->configs[intptr_t(c->config)].configId;
686 } else {
687 // We need to remap EGL_CONFIG_IDs
688 result = c->cnx->egl.eglQueryContext(
689 dp->disp[c->impl].dpy, c->context, attribute, value);
690 }
691
692 return result;
693}
694
695EGLContext eglGetCurrentContext(void)
696{
697 // could be called before eglInitialize(), but we wouldn't have a context
698 // then, and this function would correctly return EGL_NO_CONTEXT.
699
700 clearError();
701
702 EGLContext ctx = getContext();
703 return ctx;
704}
705
706EGLSurface eglGetCurrentSurface(EGLint readdraw)
707{
708 // could be called before eglInitialize(), but we wouldn't have a context
709 // then, and this function would correctly return EGL_NO_SURFACE.
710
711 clearError();
712
713 EGLContext ctx = getContext();
714 if (ctx) {
715 egl_context_t const * const c = get_context(ctx);
716 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
717 switch (readdraw) {
718 case EGL_READ: return c->read;
719 case EGL_DRAW: return c->draw;
720 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
721 }
722 }
723 return EGL_NO_SURFACE;
724}
725
726EGLDisplay eglGetCurrentDisplay(void)
727{
728 // could be called before eglInitialize(), but we wouldn't have a context
729 // then, and this function would correctly return EGL_NO_DISPLAY.
730
731 clearError();
732
733 EGLContext ctx = getContext();
734 if (ctx) {
735 egl_context_t const * const c = get_context(ctx);
736 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
737 return c->dpy;
738 }
739 return EGL_NO_DISPLAY;
740}
741
742EGLBoolean eglWaitGL(void)
743{
744 // could be called before eglInitialize(), but we wouldn't have a context
745 // then, and this function would return GL_TRUE, which isn't wrong.
746
747 clearError();
748
749 EGLBoolean res = EGL_TRUE;
750 EGLContext ctx = getContext();
751 if (ctx) {
752 egl_context_t const * const c = get_context(ctx);
753 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
754 if (uint32_t(c->impl)>=2)
755 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
756 egl_connection_t* const cnx = &gEGLImpl[c->impl];
757 if (!cnx->dso)
758 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
759 res = cnx->egl.eglWaitGL();
760 }
761 return res;
762}
763
764EGLBoolean eglWaitNative(EGLint engine)
765{
766 // could be called before eglInitialize(), but we wouldn't have a context
767 // then, and this function would return GL_TRUE, which isn't wrong.
768
769 clearError();
770
771 EGLBoolean res = EGL_TRUE;
772 EGLContext ctx = getContext();
773 if (ctx) {
774 egl_context_t const * const c = get_context(ctx);
775 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
776 if (uint32_t(c->impl)>=2)
777 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
778 egl_connection_t* const cnx = &gEGLImpl[c->impl];
779 if (!cnx->dso)
780 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
781 res = cnx->egl.eglWaitNative(engine);
782 }
783 return res;
784}
785
786EGLint eglGetError(void)
787{
788 EGLint result = EGL_SUCCESS;
789 EGLint err;
790 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
791 err = EGL_SUCCESS;
792 egl_connection_t* const cnx = &gEGLImpl[i];
793 if (cnx->dso)
794 err = cnx->egl.eglGetError();
795 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
796 result = err;
797 }
798 err = egl_tls_t::getError();
799 if (result == EGL_SUCCESS)
800 result = err;
801 return result;
802}
803
804// Note: Similar implementations of these functions also exist in
805// gl2.cpp and gl.cpp, and are used by applications that call the
806// exported entry points directly.
807typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
808typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
809
810static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL;
811static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL;
812
813static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image)
814{
815 GLeglImageOES implImage =
816 (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
817 glEGLImageTargetTexture2DOES_impl(target, implImage);
818}
819
820static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image)
821{
822 GLeglImageOES implImage =
823 (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
824 glEGLImageTargetRenderbufferStorageOES_impl(target, implImage);
825}
826
827__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
828{
829 // eglGetProcAddress() could be the very first function called
830 // in which case we must make sure we've initialized ourselves, this
831 // happens the first time egl_get_display() is called.
832
833 clearError();
834
835 if (egl_init_drivers() == EGL_FALSE) {
836 setError(EGL_BAD_PARAMETER, NULL);
837 return NULL;
838 }
839
840 __eglMustCastToProperFunctionPointerType addr;
841 addr = findProcAddress(procname, sExtentionMap, NELEM(sExtentionMap));
842 if (addr) return addr;
843
844 // this protects accesses to sGLExtentionMap and sGLExtentionSlot
845 pthread_mutex_lock(&sExtensionMapMutex);
846
847 /*
848 * Since eglGetProcAddress() is not associated to anything, it needs
849 * to return a function pointer that "works" regardless of what
850 * the current context is.
851 *
852 * For this reason, we return a "forwarder", a small stub that takes
853 * care of calling the function associated with the context
854 * currently bound.
855 *
856 * We first look for extensions we've already resolved, if we're seeing
857 * this extension for the first time, we go through all our
858 * implementations and call eglGetProcAddress() and record the
859 * result in the appropriate implementation hooks and return the
860 * address of the forwarder corresponding to that hook set.
861 *
862 */
863
864 const String8 name(procname);
865 addr = sGLExtentionMap.valueFor(name);
866 const int slot = sGLExtentionSlot;
867
868 LOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
869 "no more slots for eglGetProcAddress(\"%s\")",
870 procname);
871
872 if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
873 bool found = false;
874 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
875 egl_connection_t* const cnx = &gEGLImpl[i];
876 if (cnx->dso && cnx->egl.eglGetProcAddress) {
877 found = true;
878 // Extensions are independent of the bound context
879 cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
880 cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
881#if EGL_TRACE
882 gHooksDebug.ext.extensions[slot] = gHooksTrace.ext.extensions[slot] =
883#endif
884 cnx->egl.eglGetProcAddress(procname);
885 }
886 }
887 if (found) {
888 addr = gExtensionForwarders[slot];
889
890 if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) {
891 glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr;
892 addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper;
893 }
894 if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) {
895 glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr;
896 addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper;
897 }
898
899 sGLExtentionMap.add(name, addr);
900 sGLExtentionSlot++;
901 }
902 }
903
904 pthread_mutex_unlock(&sExtensionMapMutex);
905 return addr;
906}
907
908EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
909{
910 EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw);
911 if (gEGLDebugLevel > 0)
912 Debug_eglSwapBuffers(dpy, draw);
913
914 clearError();
915
916 egl_display_t const * const dp = validate_display(dpy);
917 if (!dp) return EGL_FALSE;
918
919 SurfaceRef _s(draw);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700920 if (!_s.get())
921 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -0700922
Mathias Agopian518ec112011-05-13 16:21:08 -0700923 egl_surface_t const * const s = get_surface(draw);
924 return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
925}
926
927EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
928 NativePixmapType target)
929{
930 clearError();
931
932 egl_display_t const * const dp = validate_display(dpy);
933 if (!dp) return EGL_FALSE;
934
935 SurfaceRef _s(surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700936 if (!_s.get())
937 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -0700938
Mathias Agopian518ec112011-05-13 16:21:08 -0700939 egl_surface_t const * const s = get_surface(surface);
940 return s->cnx->egl.eglCopyBuffers(
941 dp->disp[s->impl].dpy, s->surface, target);
942}
943
944const char* eglQueryString(EGLDisplay dpy, EGLint name)
945{
946 clearError();
947
948 egl_display_t const * const dp = validate_display(dpy);
949 if (!dp) return (const char *) NULL;
950
951 switch (name) {
952 case EGL_VENDOR:
953 return sVendorString;
954 case EGL_VERSION:
955 return sVersionString;
956 case EGL_EXTENSIONS:
957 return sExtensionString;
958 case EGL_CLIENT_APIS:
959 return sClientApiString;
960 }
961 return setError(EGL_BAD_PARAMETER, (const char *)0);
962}
963
964
965// ----------------------------------------------------------------------------
966// EGL 1.1
967// ----------------------------------------------------------------------------
968
969EGLBoolean eglSurfaceAttrib(
970 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
971{
972 clearError();
973
974 egl_display_t const * const dp = validate_display(dpy);
975 if (!dp) return EGL_FALSE;
976
977 SurfaceRef _s(surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700978 if (!_s.get())
979 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -0700980
Mathias Agopian518ec112011-05-13 16:21:08 -0700981 egl_surface_t const * const s = get_surface(surface);
982 if (s->cnx->egl.eglSurfaceAttrib) {
983 return s->cnx->egl.eglSurfaceAttrib(
984 dp->disp[s->impl].dpy, s->surface, attribute, value);
985 }
986 return setError(EGL_BAD_SURFACE, EGL_FALSE);
987}
988
989EGLBoolean eglBindTexImage(
990 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
991{
992 clearError();
993
994 egl_display_t const * const dp = validate_display(dpy);
995 if (!dp) return EGL_FALSE;
996
997 SurfaceRef _s(surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700998 if (!_s.get())
999 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -07001000
Mathias Agopian518ec112011-05-13 16:21:08 -07001001 egl_surface_t const * const s = get_surface(surface);
1002 if (s->cnx->egl.eglBindTexImage) {
1003 return s->cnx->egl.eglBindTexImage(
1004 dp->disp[s->impl].dpy, s->surface, buffer);
1005 }
1006 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1007}
1008
1009EGLBoolean eglReleaseTexImage(
1010 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1011{
1012 clearError();
1013
1014 egl_display_t const * const dp = validate_display(dpy);
1015 if (!dp) return EGL_FALSE;
1016
1017 SurfaceRef _s(surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -07001018 if (!_s.get())
1019 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -07001020
Mathias Agopian518ec112011-05-13 16:21:08 -07001021 egl_surface_t const * const s = get_surface(surface);
1022 if (s->cnx->egl.eglReleaseTexImage) {
1023 return s->cnx->egl.eglReleaseTexImage(
1024 dp->disp[s->impl].dpy, s->surface, buffer);
1025 }
1026 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1027}
1028
1029EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1030{
1031 clearError();
1032
1033 egl_display_t const * const dp = validate_display(dpy);
1034 if (!dp) return EGL_FALSE;
1035
1036 EGLBoolean res = EGL_TRUE;
1037 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1038 egl_connection_t* const cnx = &gEGLImpl[i];
1039 if (cnx->dso) {
1040 if (cnx->egl.eglSwapInterval) {
1041 if (cnx->egl.eglSwapInterval(
1042 dp->disp[i].dpy, interval) == EGL_FALSE) {
1043 res = EGL_FALSE;
1044 }
1045 }
1046 }
1047 }
1048 return res;
1049}
1050
1051
1052// ----------------------------------------------------------------------------
1053// EGL 1.2
1054// ----------------------------------------------------------------------------
1055
1056EGLBoolean eglWaitClient(void)
1057{
1058 clearError();
1059
1060 // could be called before eglInitialize(), but we wouldn't have a context
1061 // then, and this function would return GL_TRUE, which isn't wrong.
1062 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 if (cnx->egl.eglWaitClient) {
1073 res = cnx->egl.eglWaitClient();
1074 } else {
1075 res = cnx->egl.eglWaitGL();
1076 }
1077 }
1078 return res;
1079}
1080
1081EGLBoolean eglBindAPI(EGLenum api)
1082{
1083 clearError();
1084
1085 if (egl_init_drivers() == EGL_FALSE) {
1086 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1087 }
1088
1089 // bind this API on all EGLs
1090 EGLBoolean res = EGL_TRUE;
1091 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1092 egl_connection_t* const cnx = &gEGLImpl[i];
1093 if (cnx->dso) {
1094 if (cnx->egl.eglBindAPI) {
1095 if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
1096 res = EGL_FALSE;
1097 }
1098 }
1099 }
1100 }
1101 return res;
1102}
1103
1104EGLenum eglQueryAPI(void)
1105{
1106 clearError();
1107
1108 if (egl_init_drivers() == EGL_FALSE) {
1109 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1110 }
1111
1112 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1113 egl_connection_t* const cnx = &gEGLImpl[i];
1114 if (cnx->dso) {
1115 if (cnx->egl.eglQueryAPI) {
1116 // the first one we find is okay, because they all
1117 // should be the same
1118 return cnx->egl.eglQueryAPI();
1119 }
1120 }
1121 }
1122 // or, it can only be OpenGL ES
1123 return EGL_OPENGL_ES_API;
1124}
1125
1126EGLBoolean eglReleaseThread(void)
1127{
1128 clearError();
1129
1130 // If there is context bound to the thread, release it
1131 loseCurrent(get_context(getContext()));
1132
1133 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1134 egl_connection_t* const cnx = &gEGLImpl[i];
1135 if (cnx->dso) {
1136 if (cnx->egl.eglReleaseThread) {
1137 cnx->egl.eglReleaseThread();
1138 }
1139 }
1140 }
1141 egl_tls_t::clearTLS();
1142 dbgReleaseThread();
1143 return EGL_TRUE;
1144}
1145
1146EGLSurface eglCreatePbufferFromClientBuffer(
1147 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1148 EGLConfig config, const EGLint *attrib_list)
1149{
1150 clearError();
1151
1152 egl_display_t const* dp = 0;
1153 egl_connection_t* cnx = validate_display_config(dpy, config, dp);
1154 if (!cnx) return EGL_FALSE;
1155 if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1156 return cnx->egl.eglCreatePbufferFromClientBuffer(
1157 dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
1158 buftype, buffer,
1159 dp->configs[intptr_t(config)].config, attrib_list);
1160 }
1161 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1162}
1163
1164// ----------------------------------------------------------------------------
1165// EGL_EGLEXT_VERSION 3
1166// ----------------------------------------------------------------------------
1167
1168EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1169 const EGLint *attrib_list)
1170{
1171 clearError();
1172
1173 egl_display_t const * const dp = validate_display(dpy);
1174 if (!dp) return EGL_FALSE;
1175
1176 SurfaceRef _s(surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -07001177 if (!_s.get())
1178 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -07001179
1180 egl_surface_t const * const s = get_surface(surface);
Mathias Agopian518ec112011-05-13 16:21:08 -07001181 if (s->cnx->egl.eglLockSurfaceKHR) {
1182 return s->cnx->egl.eglLockSurfaceKHR(
1183 dp->disp[s->impl].dpy, s->surface, attrib_list);
1184 }
1185 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1186}
1187
1188EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1189{
1190 clearError();
1191
1192 egl_display_t const * const dp = validate_display(dpy);
1193 if (!dp) return EGL_FALSE;
1194
1195 SurfaceRef _s(surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -07001196 if (!_s.get())
1197 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -07001198
1199 egl_surface_t const * const s = get_surface(surface);
Mathias Agopian518ec112011-05-13 16:21:08 -07001200 if (s->cnx->egl.eglUnlockSurfaceKHR) {
1201 return s->cnx->egl.eglUnlockSurfaceKHR(
1202 dp->disp[s->impl].dpy, s->surface);
1203 }
1204 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1205}
1206
1207EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1208 EGLClientBuffer buffer, const EGLint *attrib_list)
1209{
1210 clearError();
1211
1212 egl_display_t const * const dp = validate_display(dpy);
1213 if (!dp) return EGL_NO_IMAGE_KHR;
1214
1215 if (ctx != EGL_NO_CONTEXT) {
1216 ContextRef _c(ctx);
Mathias Agopian5b287a62011-05-16 18:58:55 -07001217 if (!_c.get())
1218 return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
Mathias Agopian518ec112011-05-13 16:21:08 -07001219 egl_context_t * const c = get_context(ctx);
1220 // since we have an EGLContext, we know which implementation to use
1221 EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
1222 dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
1223 if (image == EGL_NO_IMAGE_KHR)
1224 return image;
1225
1226 egl_image_t* result = new egl_image_t(dpy, ctx);
1227 result->images[c->impl] = image;
1228 return (EGLImageKHR)result;
1229 } else {
1230 // EGL_NO_CONTEXT is a valid parameter
1231
1232 /* Since we don't have a way to know which implementation to call,
1233 * we're calling all of them. If at least one of the implementation
1234 * succeeded, this is a success.
1235 */
1236
1237 EGLint currentError = eglGetError();
1238
1239 EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
1240 bool success = false;
1241 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1242 egl_connection_t* const cnx = &gEGLImpl[i];
1243 implImages[i] = EGL_NO_IMAGE_KHR;
1244 if (cnx->dso) {
1245 if (cnx->egl.eglCreateImageKHR) {
1246 implImages[i] = cnx->egl.eglCreateImageKHR(
1247 dp->disp[i].dpy, ctx, target, buffer, attrib_list);
1248 if (implImages[i] != EGL_NO_IMAGE_KHR) {
1249 success = true;
1250 }
1251 }
1252 }
1253 }
1254
1255 if (!success) {
1256 // failure, if there was an error when we entered this function,
1257 // the error flag must not be updated.
1258 // Otherwise, the error is whatever happened in the implementation
1259 // that faulted.
1260 if (currentError != EGL_SUCCESS) {
1261 setError(currentError, EGL_NO_IMAGE_KHR);
1262 }
1263 return EGL_NO_IMAGE_KHR;
1264 } else {
1265 // In case of success, we need to clear all error flags
1266 // (especially those caused by the implementation that didn't
1267 // succeed). TODO: we could avoid this if we knew this was
1268 // a "full" success (all implementation succeeded).
1269 eglGetError();
1270 }
1271
1272 egl_image_t* result = new egl_image_t(dpy, ctx);
1273 memcpy(result->images, implImages, sizeof(implImages));
1274 return (EGLImageKHR)result;
1275 }
1276}
1277
1278EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1279{
1280 clearError();
1281
1282 egl_display_t const * const dp = validate_display(dpy);
1283 if (!dp) return EGL_FALSE;
1284
1285 ImageRef _i(img);
1286 if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1287
1288 egl_image_t* image = get_image(img);
1289 bool success = false;
1290 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1291 egl_connection_t* const cnx = &gEGLImpl[i];
1292 if (image->images[i] != EGL_NO_IMAGE_KHR) {
1293 if (cnx->dso) {
1294 if (cnx->egl.eglDestroyImageKHR) {
1295 if (cnx->egl.eglDestroyImageKHR(
1296 dp->disp[i].dpy, image->images[i])) {
1297 success = true;
1298 }
1299 }
1300 }
1301 }
1302 }
1303 if (!success)
1304 return EGL_FALSE;
1305
1306 _i.terminate();
1307
1308 return EGL_TRUE;
1309}
1310
1311// ----------------------------------------------------------------------------
1312// EGL_EGLEXT_VERSION 5
1313// ----------------------------------------------------------------------------
1314
1315
1316EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1317{
1318 clearError();
1319
1320 egl_display_t const * const dp = validate_display(dpy);
1321 if (!dp) return EGL_NO_SYNC_KHR;
1322
1323 EGLContext ctx = eglGetCurrentContext();
1324 ContextRef _c(ctx);
Mathias Agopian5b287a62011-05-16 18:58:55 -07001325 if (!_c.get())
1326 return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
1327
Mathias Agopian518ec112011-05-13 16:21:08 -07001328 egl_context_t * const c = get_context(ctx);
1329 EGLSyncKHR result = EGL_NO_SYNC_KHR;
1330 if (c->cnx->egl.eglCreateSyncKHR) {
1331 EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR(
1332 dp->disp[c->impl].dpy, type, attrib_list);
1333 if (sync == EGL_NO_SYNC_KHR)
1334 return sync;
1335 result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync);
1336 }
1337 return (EGLSyncKHR)result;
1338}
1339
1340EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1341{
1342 clearError();
1343
1344 egl_display_t const * const dp = validate_display(dpy);
1345 if (!dp) return EGL_FALSE;
1346
1347 SyncRef _s(sync);
1348 if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1349 egl_sync_t* syncObject = get_sync(sync);
1350
1351 EGLContext ctx = syncObject->context;
1352 ContextRef _c(ctx);
Mathias Agopian5b287a62011-05-16 18:58:55 -07001353 if (!_c.get())
1354 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -07001355
1356 EGLBoolean result = EGL_FALSE;
1357 egl_context_t * const c = get_context(ctx);
1358 if (c->cnx->egl.eglDestroySyncKHR) {
1359 result = c->cnx->egl.eglDestroySyncKHR(
1360 dp->disp[c->impl].dpy, syncObject->sync);
1361 if (result)
1362 _s.terminate();
1363 }
1364 return result;
1365}
1366
1367EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
1368{
1369 clearError();
1370
1371 egl_display_t const * const dp = validate_display(dpy);
1372 if (!dp) return EGL_FALSE;
1373
1374 SyncRef _s(sync);
1375 if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1376 egl_sync_t* syncObject = get_sync(sync);
1377
1378 EGLContext ctx = syncObject->context;
1379 ContextRef _c(ctx);
Mathias Agopian5b287a62011-05-16 18:58:55 -07001380 if (!_c.get())
1381 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -07001382
1383 egl_context_t * const c = get_context(ctx);
Mathias Agopian518ec112011-05-13 16:21:08 -07001384 if (c->cnx->egl.eglClientWaitSyncKHR) {
1385 return c->cnx->egl.eglClientWaitSyncKHR(
1386 dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
1387 }
1388
1389 return EGL_FALSE;
1390}
1391
1392EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
1393{
1394 clearError();
1395
1396 egl_display_t const * const dp = validate_display(dpy);
1397 if (!dp) return EGL_FALSE;
1398
1399 SyncRef _s(sync);
Mathias Agopian5b287a62011-05-16 18:58:55 -07001400 if (!_s.get())
1401 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -07001402
Mathias Agopian5b287a62011-05-16 18:58:55 -07001403 egl_sync_t* syncObject = get_sync(sync);
Mathias Agopian518ec112011-05-13 16:21:08 -07001404 EGLContext ctx = syncObject->context;
1405 ContextRef _c(ctx);
Mathias Agopian5b287a62011-05-16 18:58:55 -07001406 if (!_c.get())
1407 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -07001408
1409 egl_context_t * const c = get_context(ctx);
Mathias Agopian518ec112011-05-13 16:21:08 -07001410 if (c->cnx->egl.eglGetSyncAttribKHR) {
1411 return c->cnx->egl.eglGetSyncAttribKHR(
1412 dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
1413 }
1414
1415 return EGL_FALSE;
1416}
1417
1418// ----------------------------------------------------------------------------
1419// ANDROID extensions
1420// ----------------------------------------------------------------------------
1421
1422EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1423 EGLint left, EGLint top, EGLint width, EGLint height)
1424{
1425 clearError();
1426
1427 egl_display_t const * const dp = validate_display(dpy);
1428 if (!dp) return EGL_FALSE;
1429
1430 SurfaceRef _s(draw);
Mathias Agopian5b287a62011-05-16 18:58:55 -07001431 if (!_s.get())
1432 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -07001433
Mathias Agopian518ec112011-05-13 16:21:08 -07001434 egl_surface_t const * const s = get_surface(draw);
1435 if (s->cnx->egl.eglSetSwapRectangleANDROID) {
1436 return s->cnx->egl.eglSetSwapRectangleANDROID(
1437 dp->disp[s->impl].dpy, s->surface, left, top, width, height);
1438 }
1439 return setError(EGL_BAD_DISPLAY, NULL);
1440}