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