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