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