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