blob: 210c24dd90d66363c62680a3c449d45073221871 [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);
434 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
435
436 if (!validate_display_surface(dpy, surface))
437 return EGL_FALSE;
438
439 egl_surface_t * const s = get_surface(surface);
440 EGLBoolean result = s->cnx->egl.eglDestroySurface(
441 dp->disp[s->impl].dpy, s->surface);
442 if (result == EGL_TRUE) {
443 if (s->win != NULL) {
444 native_window_set_buffers_geometry(s->win.get(), 0, 0, 0);
445 }
446 _s.terminate();
447 }
448 return result;
449}
450
451EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
452 EGLint attribute, EGLint *value)
453{
454 clearError();
455
456 egl_display_t const * const dp = validate_display(dpy);
457 if (!dp) return EGL_FALSE;
458
459 SurfaceRef _s(surface);
460 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
461
462 if (!validate_display_surface(dpy, surface))
463 return EGL_FALSE;
464 egl_surface_t const * const s = get_surface(surface);
465
466 EGLBoolean result(EGL_TRUE);
467 if (attribute == EGL_CONFIG_ID) {
468 // We need to remap EGL_CONFIG_IDs
469 *value = dp->configs[intptr_t(s->config)].configId;
470 } else {
471 result = s->cnx->egl.eglQuerySurface(
472 dp->disp[s->impl].dpy, s->surface, attribute, value);
473 }
474
475 return result;
476}
477
478// ----------------------------------------------------------------------------
479// Contexts
480// ----------------------------------------------------------------------------
481
482EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
483 EGLContext share_list, const EGLint *attrib_list)
484{
485 clearError();
486
487 egl_display_t const* dp = 0;
488 egl_connection_t* cnx = validate_display_config(dpy, config, dp);
489 if (cnx) {
490 if (share_list != EGL_NO_CONTEXT) {
491 egl_context_t* const c = get_context(share_list);
492 share_list = c->context;
493 }
494 EGLContext context = cnx->egl.eglCreateContext(
495 dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
496 dp->configs[intptr_t(config)].config,
497 share_list, attrib_list);
498 if (context != EGL_NO_CONTEXT) {
499 // figure out if it's a GLESv1 or GLESv2
500 int version = 0;
501 if (attrib_list) {
502 while (*attrib_list != EGL_NONE) {
503 GLint attr = *attrib_list++;
504 GLint value = *attrib_list++;
505 if (attr == EGL_CONTEXT_CLIENT_VERSION) {
506 if (value == 1) {
507 version = GLESv1_INDEX;
508 } else if (value == 2) {
509 version = GLESv2_INDEX;
510 }
511 }
512 };
513 }
514 egl_context_t* c = new egl_context_t(dpy, context, config,
515 dp->configs[intptr_t(config)].impl, cnx, version);
516 return c;
517 }
518 }
519 return EGL_NO_CONTEXT;
520}
521
522EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
523{
524 clearError();
525
526 egl_display_t const * const dp = validate_display(dpy);
527 if (!dp) return EGL_FALSE;
528
529 ContextRef _c(ctx);
530 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
531
532 if (!validate_display_context(dpy, ctx))
533 return EGL_FALSE;
534 egl_context_t * const c = get_context(ctx);
535 EGLBoolean result = c->cnx->egl.eglDestroyContext(
536 dp->disp[c->impl].dpy, c->context);
537 if (result == EGL_TRUE) {
538 _c.terminate();
539 }
540 return result;
541}
542
543static void loseCurrent(egl_context_t * cur_c)
544{
545 if (cur_c) {
546 egl_surface_t * cur_r = get_surface(cur_c->read);
547 egl_surface_t * cur_d = get_surface(cur_c->draw);
548
549 // by construction, these are either 0 or valid (possibly terminated)
550 // it should be impossible for these to be invalid
551 ContextRef _cur_c(cur_c);
552 SurfaceRef _cur_r(cur_r);
553 SurfaceRef _cur_d(cur_d);
554
555 cur_c->read = NULL;
556 cur_c->draw = NULL;
557
558 _cur_c.release();
559 _cur_r.release();
560 _cur_d.release();
561 }
562}
563
564EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
565 EGLSurface read, EGLContext ctx)
566{
567 clearError();
568
569 egl_display_t const * const dp = get_display(dpy);
570 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
571
572 /* If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
573 EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
574 a valid but uninitialized display. */
575 if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
576 (draw != EGL_NO_SURFACE) ) {
577 if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
578 }
579
580 // get a reference to the object passed in
581 ContextRef _c(ctx);
582 SurfaceRef _d(draw);
583 SurfaceRef _r(read);
584
585 // validate the context (if not EGL_NO_CONTEXT)
586 if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
587 // EGL_NO_CONTEXT is valid
588 return EGL_FALSE;
589 }
590
591 // these are the underlying implementation's object
592 EGLContext impl_ctx = EGL_NO_CONTEXT;
593 EGLSurface impl_draw = EGL_NO_SURFACE;
594 EGLSurface impl_read = EGL_NO_SURFACE;
595
596 // these are our objects structs passed in
597 egl_context_t * c = NULL;
598 egl_surface_t const * d = NULL;
599 egl_surface_t const * r = NULL;
600
601 // these are the current objects structs
602 egl_context_t * cur_c = get_context(getContext());
603
604 if (ctx != EGL_NO_CONTEXT) {
605 c = get_context(ctx);
606 impl_ctx = c->context;
607 } else {
608 // no context given, use the implementation of the current context
609 if (cur_c == NULL) {
610 // no current context
611 if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
612 // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
613 return setError(EGL_BAD_MATCH, EGL_FALSE);
614 }
615 // not an error, there is just no current context.
616 return EGL_TRUE;
617 }
618 }
619
620 // retrieve the underlying implementation's draw EGLSurface
621 if (draw != EGL_NO_SURFACE) {
622 d = get_surface(draw);
623 // make sure the EGLContext and EGLSurface passed in are for
624 // the same driver
625 if (c && d->impl != c->impl)
626 return setError(EGL_BAD_MATCH, EGL_FALSE);
627 impl_draw = d->surface;
628 }
629
630 // retrieve the underlying implementation's read EGLSurface
631 if (read != EGL_NO_SURFACE) {
632 r = get_surface(read);
633 // make sure the EGLContext and EGLSurface passed in are for
634 // the same driver
635 if (c && r->impl != c->impl)
636 return setError(EGL_BAD_MATCH, EGL_FALSE);
637 impl_read = r->surface;
638 }
639
640 EGLBoolean result;
641
642 if (c) {
643 result = c->cnx->egl.eglMakeCurrent(
644 dp->disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
645 } else {
646 result = cur_c->cnx->egl.eglMakeCurrent(
647 dp->disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
648 }
649
650 if (result == EGL_TRUE) {
651
652 loseCurrent(cur_c);
653
654 if (ctx != EGL_NO_CONTEXT) {
655 setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
656 egl_tls_t::setContext(ctx);
657 if (gEGLDebugLevel > 0) {
658 CreateDbgContext(c->version, c->cnx->hooks[c->version]);
659 }
660 _c.acquire();
661 _r.acquire();
662 _d.acquire();
663 c->read = read;
664 c->draw = draw;
665 } else {
666 setGLHooksThreadSpecific(&gHooksNoContext);
667 egl_tls_t::setContext(EGL_NO_CONTEXT);
668 }
669 }
670 return result;
671}
672
673
674EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
675 EGLint attribute, EGLint *value)
676{
677 clearError();
678
679 egl_display_t const * const dp = validate_display(dpy);
680 if (!dp) return EGL_FALSE;
681
682 ContextRef _c(ctx);
683 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
684
685 if (!validate_display_context(dpy, ctx))
686 return EGL_FALSE;
687
688 egl_context_t * const c = get_context(ctx);
689
690 EGLBoolean result(EGL_TRUE);
691 if (attribute == EGL_CONFIG_ID) {
692 *value = dp->configs[intptr_t(c->config)].configId;
693 } else {
694 // We need to remap EGL_CONFIG_IDs
695 result = c->cnx->egl.eglQueryContext(
696 dp->disp[c->impl].dpy, c->context, attribute, value);
697 }
698
699 return result;
700}
701
702EGLContext eglGetCurrentContext(void)
703{
704 // could be called before eglInitialize(), but we wouldn't have a context
705 // then, and this function would correctly return EGL_NO_CONTEXT.
706
707 clearError();
708
709 EGLContext ctx = getContext();
710 return ctx;
711}
712
713EGLSurface eglGetCurrentSurface(EGLint readdraw)
714{
715 // could be called before eglInitialize(), but we wouldn't have a context
716 // then, and this function would correctly return EGL_NO_SURFACE.
717
718 clearError();
719
720 EGLContext ctx = getContext();
721 if (ctx) {
722 egl_context_t const * const c = get_context(ctx);
723 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
724 switch (readdraw) {
725 case EGL_READ: return c->read;
726 case EGL_DRAW: return c->draw;
727 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
728 }
729 }
730 return EGL_NO_SURFACE;
731}
732
733EGLDisplay eglGetCurrentDisplay(void)
734{
735 // could be called before eglInitialize(), but we wouldn't have a context
736 // then, and this function would correctly return EGL_NO_DISPLAY.
737
738 clearError();
739
740 EGLContext ctx = getContext();
741 if (ctx) {
742 egl_context_t const * const c = get_context(ctx);
743 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
744 return c->dpy;
745 }
746 return EGL_NO_DISPLAY;
747}
748
749EGLBoolean eglWaitGL(void)
750{
751 // could be called before eglInitialize(), but we wouldn't have a context
752 // then, and this function would return GL_TRUE, which isn't wrong.
753
754 clearError();
755
756 EGLBoolean res = EGL_TRUE;
757 EGLContext ctx = getContext();
758 if (ctx) {
759 egl_context_t const * const c = get_context(ctx);
760 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
761 if (uint32_t(c->impl)>=2)
762 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
763 egl_connection_t* const cnx = &gEGLImpl[c->impl];
764 if (!cnx->dso)
765 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
766 res = cnx->egl.eglWaitGL();
767 }
768 return res;
769}
770
771EGLBoolean eglWaitNative(EGLint engine)
772{
773 // could be called before eglInitialize(), but we wouldn't have a context
774 // then, and this function would return GL_TRUE, which isn't wrong.
775
776 clearError();
777
778 EGLBoolean res = EGL_TRUE;
779 EGLContext ctx = getContext();
780 if (ctx) {
781 egl_context_t const * const c = get_context(ctx);
782 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
783 if (uint32_t(c->impl)>=2)
784 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
785 egl_connection_t* const cnx = &gEGLImpl[c->impl];
786 if (!cnx->dso)
787 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
788 res = cnx->egl.eglWaitNative(engine);
789 }
790 return res;
791}
792
793EGLint eglGetError(void)
794{
795 EGLint result = EGL_SUCCESS;
796 EGLint err;
797 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
798 err = EGL_SUCCESS;
799 egl_connection_t* const cnx = &gEGLImpl[i];
800 if (cnx->dso)
801 err = cnx->egl.eglGetError();
802 if (err!=EGL_SUCCESS && result==EGL_SUCCESS)
803 result = err;
804 }
805 err = egl_tls_t::getError();
806 if (result == EGL_SUCCESS)
807 result = err;
808 return result;
809}
810
811// Note: Similar implementations of these functions also exist in
812// gl2.cpp and gl.cpp, and are used by applications that call the
813// exported entry points directly.
814typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
815typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
816
817static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL;
818static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL;
819
820static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image)
821{
822 GLeglImageOES implImage =
823 (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
824 glEGLImageTargetTexture2DOES_impl(target, implImage);
825}
826
827static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image)
828{
829 GLeglImageOES implImage =
830 (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image);
831 glEGLImageTargetRenderbufferStorageOES_impl(target, implImage);
832}
833
834__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
835{
836 // eglGetProcAddress() could be the very first function called
837 // in which case we must make sure we've initialized ourselves, this
838 // happens the first time egl_get_display() is called.
839
840 clearError();
841
842 if (egl_init_drivers() == EGL_FALSE) {
843 setError(EGL_BAD_PARAMETER, NULL);
844 return NULL;
845 }
846
847 __eglMustCastToProperFunctionPointerType addr;
848 addr = findProcAddress(procname, sExtentionMap, NELEM(sExtentionMap));
849 if (addr) return addr;
850
851 // this protects accesses to sGLExtentionMap and sGLExtentionSlot
852 pthread_mutex_lock(&sExtensionMapMutex);
853
854 /*
855 * Since eglGetProcAddress() is not associated to anything, it needs
856 * to return a function pointer that "works" regardless of what
857 * the current context is.
858 *
859 * For this reason, we return a "forwarder", a small stub that takes
860 * care of calling the function associated with the context
861 * currently bound.
862 *
863 * We first look for extensions we've already resolved, if we're seeing
864 * this extension for the first time, we go through all our
865 * implementations and call eglGetProcAddress() and record the
866 * result in the appropriate implementation hooks and return the
867 * address of the forwarder corresponding to that hook set.
868 *
869 */
870
871 const String8 name(procname);
872 addr = sGLExtentionMap.valueFor(name);
873 const int slot = sGLExtentionSlot;
874
875 LOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
876 "no more slots for eglGetProcAddress(\"%s\")",
877 procname);
878
879 if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
880 bool found = false;
881 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
882 egl_connection_t* const cnx = &gEGLImpl[i];
883 if (cnx->dso && cnx->egl.eglGetProcAddress) {
884 found = true;
885 // Extensions are independent of the bound context
886 cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] =
887 cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] =
888#if EGL_TRACE
889 gHooksDebug.ext.extensions[slot] = gHooksTrace.ext.extensions[slot] =
890#endif
891 cnx->egl.eglGetProcAddress(procname);
892 }
893 }
894 if (found) {
895 addr = gExtensionForwarders[slot];
896
897 if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) {
898 glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr;
899 addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper;
900 }
901 if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) {
902 glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr;
903 addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper;
904 }
905
906 sGLExtentionMap.add(name, addr);
907 sGLExtentionSlot++;
908 }
909 }
910
911 pthread_mutex_unlock(&sExtensionMapMutex);
912 return addr;
913}
914
915EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
916{
917 EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw);
918 if (gEGLDebugLevel > 0)
919 Debug_eglSwapBuffers(dpy, draw);
920
921 clearError();
922
923 egl_display_t const * const dp = validate_display(dpy);
924 if (!dp) return EGL_FALSE;
925
926 SurfaceRef _s(draw);
927 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
928
929 if (!validate_display_surface(dpy, draw))
930 return EGL_FALSE;
931 egl_surface_t const * const s = get_surface(draw);
932 return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
933}
934
935EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
936 NativePixmapType target)
937{
938 clearError();
939
940 egl_display_t const * const dp = validate_display(dpy);
941 if (!dp) return EGL_FALSE;
942
943 SurfaceRef _s(surface);
944 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
945
946 if (!validate_display_surface(dpy, surface))
947 return EGL_FALSE;
948 egl_surface_t const * const s = get_surface(surface);
949 return s->cnx->egl.eglCopyBuffers(
950 dp->disp[s->impl].dpy, s->surface, target);
951}
952
953const char* eglQueryString(EGLDisplay dpy, EGLint name)
954{
955 clearError();
956
957 egl_display_t const * const dp = validate_display(dpy);
958 if (!dp) return (const char *) NULL;
959
960 switch (name) {
961 case EGL_VENDOR:
962 return sVendorString;
963 case EGL_VERSION:
964 return sVersionString;
965 case EGL_EXTENSIONS:
966 return sExtensionString;
967 case EGL_CLIENT_APIS:
968 return sClientApiString;
969 }
970 return setError(EGL_BAD_PARAMETER, (const char *)0);
971}
972
973
974// ----------------------------------------------------------------------------
975// EGL 1.1
976// ----------------------------------------------------------------------------
977
978EGLBoolean eglSurfaceAttrib(
979 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
980{
981 clearError();
982
983 egl_display_t const * const dp = validate_display(dpy);
984 if (!dp) return EGL_FALSE;
985
986 SurfaceRef _s(surface);
987 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
988
989 if (!validate_display_surface(dpy, surface))
990 return EGL_FALSE;
991 egl_surface_t const * const s = get_surface(surface);
992 if (s->cnx->egl.eglSurfaceAttrib) {
993 return s->cnx->egl.eglSurfaceAttrib(
994 dp->disp[s->impl].dpy, s->surface, attribute, value);
995 }
996 return setError(EGL_BAD_SURFACE, EGL_FALSE);
997}
998
999EGLBoolean eglBindTexImage(
1000 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1001{
1002 clearError();
1003
1004 egl_display_t const * const dp = validate_display(dpy);
1005 if (!dp) return EGL_FALSE;
1006
1007 SurfaceRef _s(surface);
1008 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1009
1010 if (!validate_display_surface(dpy, surface))
1011 return EGL_FALSE;
1012 egl_surface_t const * const s = get_surface(surface);
1013 if (s->cnx->egl.eglBindTexImage) {
1014 return s->cnx->egl.eglBindTexImage(
1015 dp->disp[s->impl].dpy, s->surface, buffer);
1016 }
1017 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1018}
1019
1020EGLBoolean eglReleaseTexImage(
1021 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1022{
1023 clearError();
1024
1025 egl_display_t const * const dp = validate_display(dpy);
1026 if (!dp) return EGL_FALSE;
1027
1028 SurfaceRef _s(surface);
1029 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1030
1031 if (!validate_display_surface(dpy, surface))
1032 return EGL_FALSE;
1033 egl_surface_t const * const s = get_surface(surface);
1034 if (s->cnx->egl.eglReleaseTexImage) {
1035 return s->cnx->egl.eglReleaseTexImage(
1036 dp->disp[s->impl].dpy, s->surface, buffer);
1037 }
1038 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1039}
1040
1041EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1042{
1043 clearError();
1044
1045 egl_display_t const * const dp = validate_display(dpy);
1046 if (!dp) return EGL_FALSE;
1047
1048 EGLBoolean res = EGL_TRUE;
1049 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1050 egl_connection_t* const cnx = &gEGLImpl[i];
1051 if (cnx->dso) {
1052 if (cnx->egl.eglSwapInterval) {
1053 if (cnx->egl.eglSwapInterval(
1054 dp->disp[i].dpy, interval) == EGL_FALSE) {
1055 res = EGL_FALSE;
1056 }
1057 }
1058 }
1059 }
1060 return res;
1061}
1062
1063
1064// ----------------------------------------------------------------------------
1065// EGL 1.2
1066// ----------------------------------------------------------------------------
1067
1068EGLBoolean eglWaitClient(void)
1069{
1070 clearError();
1071
1072 // could be called before eglInitialize(), but we wouldn't have a context
1073 // then, and this function would return GL_TRUE, which isn't wrong.
1074 EGLBoolean res = EGL_TRUE;
1075 EGLContext ctx = getContext();
1076 if (ctx) {
1077 egl_context_t const * const c = get_context(ctx);
1078 if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1079 if (uint32_t(c->impl)>=2)
1080 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1081 egl_connection_t* const cnx = &gEGLImpl[c->impl];
1082 if (!cnx->dso)
1083 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1084 if (cnx->egl.eglWaitClient) {
1085 res = cnx->egl.eglWaitClient();
1086 } else {
1087 res = cnx->egl.eglWaitGL();
1088 }
1089 }
1090 return res;
1091}
1092
1093EGLBoolean eglBindAPI(EGLenum api)
1094{
1095 clearError();
1096
1097 if (egl_init_drivers() == EGL_FALSE) {
1098 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1099 }
1100
1101 // bind this API on all EGLs
1102 EGLBoolean res = EGL_TRUE;
1103 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1104 egl_connection_t* const cnx = &gEGLImpl[i];
1105 if (cnx->dso) {
1106 if (cnx->egl.eglBindAPI) {
1107 if (cnx->egl.eglBindAPI(api) == EGL_FALSE) {
1108 res = EGL_FALSE;
1109 }
1110 }
1111 }
1112 }
1113 return res;
1114}
1115
1116EGLenum eglQueryAPI(void)
1117{
1118 clearError();
1119
1120 if (egl_init_drivers() == EGL_FALSE) {
1121 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1122 }
1123
1124 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1125 egl_connection_t* const cnx = &gEGLImpl[i];
1126 if (cnx->dso) {
1127 if (cnx->egl.eglQueryAPI) {
1128 // the first one we find is okay, because they all
1129 // should be the same
1130 return cnx->egl.eglQueryAPI();
1131 }
1132 }
1133 }
1134 // or, it can only be OpenGL ES
1135 return EGL_OPENGL_ES_API;
1136}
1137
1138EGLBoolean eglReleaseThread(void)
1139{
1140 clearError();
1141
1142 // If there is context bound to the thread, release it
1143 loseCurrent(get_context(getContext()));
1144
1145 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1146 egl_connection_t* const cnx = &gEGLImpl[i];
1147 if (cnx->dso) {
1148 if (cnx->egl.eglReleaseThread) {
1149 cnx->egl.eglReleaseThread();
1150 }
1151 }
1152 }
1153 egl_tls_t::clearTLS();
1154 dbgReleaseThread();
1155 return EGL_TRUE;
1156}
1157
1158EGLSurface eglCreatePbufferFromClientBuffer(
1159 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1160 EGLConfig config, const EGLint *attrib_list)
1161{
1162 clearError();
1163
1164 egl_display_t const* dp = 0;
1165 egl_connection_t* cnx = validate_display_config(dpy, config, dp);
1166 if (!cnx) return EGL_FALSE;
1167 if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1168 return cnx->egl.eglCreatePbufferFromClientBuffer(
1169 dp->disp[ dp->configs[intptr_t(config)].impl ].dpy,
1170 buftype, buffer,
1171 dp->configs[intptr_t(config)].config, attrib_list);
1172 }
1173 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1174}
1175
1176// ----------------------------------------------------------------------------
1177// EGL_EGLEXT_VERSION 3
1178// ----------------------------------------------------------------------------
1179
1180EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1181 const EGLint *attrib_list)
1182{
1183 clearError();
1184
1185 egl_display_t const * const dp = validate_display(dpy);
1186 if (!dp) return EGL_FALSE;
1187
1188 SurfaceRef _s(surface);
1189 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1190
1191 if (!validate_display_surface(dpy, surface))
1192 return EGL_FALSE;
1193
1194 egl_surface_t const * const s = get_surface(surface);
1195
1196 if (s->cnx->egl.eglLockSurfaceKHR) {
1197 return s->cnx->egl.eglLockSurfaceKHR(
1198 dp->disp[s->impl].dpy, s->surface, attrib_list);
1199 }
1200 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1201}
1202
1203EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1204{
1205 clearError();
1206
1207 egl_display_t const * const dp = validate_display(dpy);
1208 if (!dp) return EGL_FALSE;
1209
1210 SurfaceRef _s(surface);
1211 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1212
1213 if (!validate_display_surface(dpy, surface))
1214 return EGL_FALSE;
1215
1216 egl_surface_t const * const s = get_surface(surface);
1217
1218 if (s->cnx->egl.eglUnlockSurfaceKHR) {
1219 return s->cnx->egl.eglUnlockSurfaceKHR(
1220 dp->disp[s->impl].dpy, s->surface);
1221 }
1222 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1223}
1224
1225EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1226 EGLClientBuffer buffer, const EGLint *attrib_list)
1227{
1228 clearError();
1229
1230 egl_display_t const * const dp = validate_display(dpy);
1231 if (!dp) return EGL_NO_IMAGE_KHR;
1232
1233 if (ctx != EGL_NO_CONTEXT) {
1234 ContextRef _c(ctx);
1235 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1236 if (!validate_display_context(dpy, ctx))
1237 return EGL_NO_IMAGE_KHR;
1238 egl_context_t * const c = get_context(ctx);
1239 // since we have an EGLContext, we know which implementation to use
1240 EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
1241 dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list);
1242 if (image == EGL_NO_IMAGE_KHR)
1243 return image;
1244
1245 egl_image_t* result = new egl_image_t(dpy, ctx);
1246 result->images[c->impl] = image;
1247 return (EGLImageKHR)result;
1248 } else {
1249 // EGL_NO_CONTEXT is a valid parameter
1250
1251 /* Since we don't have a way to know which implementation to call,
1252 * we're calling all of them. If at least one of the implementation
1253 * succeeded, this is a success.
1254 */
1255
1256 EGLint currentError = eglGetError();
1257
1258 EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS];
1259 bool success = false;
1260 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1261 egl_connection_t* const cnx = &gEGLImpl[i];
1262 implImages[i] = EGL_NO_IMAGE_KHR;
1263 if (cnx->dso) {
1264 if (cnx->egl.eglCreateImageKHR) {
1265 implImages[i] = cnx->egl.eglCreateImageKHR(
1266 dp->disp[i].dpy, ctx, target, buffer, attrib_list);
1267 if (implImages[i] != EGL_NO_IMAGE_KHR) {
1268 success = true;
1269 }
1270 }
1271 }
1272 }
1273
1274 if (!success) {
1275 // failure, if there was an error when we entered this function,
1276 // the error flag must not be updated.
1277 // Otherwise, the error is whatever happened in the implementation
1278 // that faulted.
1279 if (currentError != EGL_SUCCESS) {
1280 setError(currentError, EGL_NO_IMAGE_KHR);
1281 }
1282 return EGL_NO_IMAGE_KHR;
1283 } else {
1284 // In case of success, we need to clear all error flags
1285 // (especially those caused by the implementation that didn't
1286 // succeed). TODO: we could avoid this if we knew this was
1287 // a "full" success (all implementation succeeded).
1288 eglGetError();
1289 }
1290
1291 egl_image_t* result = new egl_image_t(dpy, ctx);
1292 memcpy(result->images, implImages, sizeof(implImages));
1293 return (EGLImageKHR)result;
1294 }
1295}
1296
1297EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1298{
1299 clearError();
1300
1301 egl_display_t const * const dp = validate_display(dpy);
1302 if (!dp) return EGL_FALSE;
1303
1304 ImageRef _i(img);
1305 if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1306
1307 egl_image_t* image = get_image(img);
1308 bool success = false;
1309 for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) {
1310 egl_connection_t* const cnx = &gEGLImpl[i];
1311 if (image->images[i] != EGL_NO_IMAGE_KHR) {
1312 if (cnx->dso) {
1313 if (cnx->egl.eglDestroyImageKHR) {
1314 if (cnx->egl.eglDestroyImageKHR(
1315 dp->disp[i].dpy, image->images[i])) {
1316 success = true;
1317 }
1318 }
1319 }
1320 }
1321 }
1322 if (!success)
1323 return EGL_FALSE;
1324
1325 _i.terminate();
1326
1327 return EGL_TRUE;
1328}
1329
1330// ----------------------------------------------------------------------------
1331// EGL_EGLEXT_VERSION 5
1332// ----------------------------------------------------------------------------
1333
1334
1335EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1336{
1337 clearError();
1338
1339 egl_display_t const * const dp = validate_display(dpy);
1340 if (!dp) return EGL_NO_SYNC_KHR;
1341
1342 EGLContext ctx = eglGetCurrentContext();
1343 ContextRef _c(ctx);
1344 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
1345 if (!validate_display_context(dpy, ctx))
1346 return EGL_NO_SYNC_KHR;
1347 egl_context_t * const c = get_context(ctx);
1348 EGLSyncKHR result = EGL_NO_SYNC_KHR;
1349 if (c->cnx->egl.eglCreateSyncKHR) {
1350 EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR(
1351 dp->disp[c->impl].dpy, type, attrib_list);
1352 if (sync == EGL_NO_SYNC_KHR)
1353 return sync;
1354 result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync);
1355 }
1356 return (EGLSyncKHR)result;
1357}
1358
1359EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1360{
1361 clearError();
1362
1363 egl_display_t const * const dp = validate_display(dpy);
1364 if (!dp) return EGL_FALSE;
1365
1366 SyncRef _s(sync);
1367 if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1368 egl_sync_t* syncObject = get_sync(sync);
1369
1370 EGLContext ctx = syncObject->context;
1371 ContextRef _c(ctx);
1372 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1373 if (!validate_display_context(dpy, ctx))
1374 return EGL_FALSE;
1375
1376 EGLBoolean result = EGL_FALSE;
1377 egl_context_t * const c = get_context(ctx);
1378 if (c->cnx->egl.eglDestroySyncKHR) {
1379 result = c->cnx->egl.eglDestroySyncKHR(
1380 dp->disp[c->impl].dpy, syncObject->sync);
1381 if (result)
1382 _s.terminate();
1383 }
1384 return result;
1385}
1386
1387EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
1388{
1389 clearError();
1390
1391 egl_display_t const * const dp = validate_display(dpy);
1392 if (!dp) return EGL_FALSE;
1393
1394 SyncRef _s(sync);
1395 if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1396 egl_sync_t* syncObject = get_sync(sync);
1397
1398 EGLContext ctx = syncObject->context;
1399 ContextRef _c(ctx);
1400 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1401 if (!validate_display_context(dpy, ctx))
1402 return EGL_FALSE;
1403
1404 egl_context_t * const c = get_context(ctx);
1405
1406 if (c->cnx->egl.eglClientWaitSyncKHR) {
1407 return c->cnx->egl.eglClientWaitSyncKHR(
1408 dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
1409 }
1410
1411 return EGL_FALSE;
1412}
1413
1414EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
1415{
1416 clearError();
1417
1418 egl_display_t const * const dp = validate_display(dpy);
1419 if (!dp) return EGL_FALSE;
1420
1421 SyncRef _s(sync);
1422 if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1423 egl_sync_t* syncObject = get_sync(sync);
1424
1425 EGLContext ctx = syncObject->context;
1426 ContextRef _c(ctx);
1427 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1428 if (!validate_display_context(dpy, ctx))
1429 return EGL_FALSE;
1430
1431 egl_context_t * const c = get_context(ctx);
1432
1433 if (c->cnx->egl.eglGetSyncAttribKHR) {
1434 return c->cnx->egl.eglGetSyncAttribKHR(
1435 dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
1436 }
1437
1438 return EGL_FALSE;
1439}
1440
1441// ----------------------------------------------------------------------------
1442// ANDROID extensions
1443// ----------------------------------------------------------------------------
1444
1445EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
1446 EGLint left, EGLint top, EGLint width, EGLint height)
1447{
1448 clearError();
1449
1450 egl_display_t const * const dp = validate_display(dpy);
1451 if (!dp) return EGL_FALSE;
1452
1453 SurfaceRef _s(draw);
1454 if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
1455
1456 if (!validate_display_surface(dpy, draw))
1457 return EGL_FALSE;
1458 egl_surface_t const * const s = get_surface(draw);
1459 if (s->cnx->egl.eglSetSwapRectangleANDROID) {
1460 return s->cnx->egl.eglSetSwapRectangleANDROID(
1461 dp->disp[s->impl].dpy, s->surface, left, top, width, height);
1462 }
1463 return setError(EGL_BAD_DISPLAY, NULL);
1464}