blob: ed9db9450ca485b41948f5c8d189c03c05ff1157 [file] [log] [blame]
Jesse Hall47743382013-02-08 11:13:46 -08001/*
Mathias Agopian518ec112011-05-13 16:21:08 -07002 ** Copyright 2007, The Android Open Source Project
3 **
Jesse Hall47743382013-02-08 11:13:46 -08004 ** 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
Mathias Agopian518ec112011-05-13 16:21:08 -07007 **
Jesse Hall47743382013-02-08 11:13:46 -08008 ** http://www.apache.org/licenses/LICENSE-2.0
Mathias Agopian518ec112011-05-13 16:21:08 -07009 **
Jesse Hall47743382013-02-08 11:13:46 -080010 ** 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
Mathias Agopian518ec112011-05-13 16:21:08 -070014 ** limitations under the License.
15 */
16
Jamie Gennis1c8e95c2012-02-23 19:27:23 -080017#define ATRACE_TAG ATRACE_TAG_GRAPHICS
18
Mathias Agopian518ec112011-05-13 16:21:08 -070019#include <ctype.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include <hardware/gralloc.h>
24#include <system/window.h>
25
26#include <EGL/egl.h>
27#include <EGL/eglext.h>
Mathias Agopian518ec112011-05-13 16:21:08 -070028
29#include <cutils/log.h>
30#include <cutils/atomic.h>
Mathias Agopian7db993a2012-03-25 00:49:46 -070031#include <cutils/compiler.h>
Mathias Agopian518ec112011-05-13 16:21:08 -070032#include <cutils/properties.h>
33#include <cutils/memory.h>
34
35#include <utils/KeyedVector.h>
36#include <utils/SortedVector.h>
37#include <utils/String8.h>
Jamie Gennis1c8e95c2012-02-23 19:27:23 -080038#include <utils/Trace.h>
Mathias Agopian518ec112011-05-13 16:21:08 -070039
40#include "egl_impl.h"
41#include "egl_tls.h"
Siva Velusamy0469dd62011-11-30 15:05:37 -080042#include "glestrace.h"
Mathias Agopian518ec112011-05-13 16:21:08 -070043#include "hooks.h"
44
45#include "egl_display.h"
46#include "egl_impl.h"
47#include "egl_object.h"
48#include "egl_tls.h"
Mathias Agopianada798b2012-02-13 17:09:30 -080049#include "egldefs.h"
Mathias Agopian518ec112011-05-13 16:21:08 -070050
51using namespace android;
52
53// ----------------------------------------------------------------------------
54
Mathias Agopianbc2d79e2011-11-29 17:55:46 -080055#define EGL_VERSION_HW_ANDROID 0x3143
56
Mathias Agopian518ec112011-05-13 16:21:08 -070057struct extention_map_t {
58 const char* name;
59 __eglMustCastToProperFunctionPointerType address;
60};
61
62static const extention_map_t sExtentionMap[] = {
63 { "eglLockSurfaceKHR",
64 (__eglMustCastToProperFunctionPointerType)&eglLockSurfaceKHR },
65 { "eglUnlockSurfaceKHR",
66 (__eglMustCastToProperFunctionPointerType)&eglUnlockSurfaceKHR },
67 { "eglCreateImageKHR",
68 (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
69 { "eglDestroyImageKHR",
70 (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
Jonas Yang1c3d72a2011-08-26 20:04:39 +080071 { "eglGetSystemTimeFrequencyNV",
72 (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV },
73 { "eglGetSystemTimeNV",
74 (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeNV },
Mathias Agopian518ec112011-05-13 16:21:08 -070075};
76
77// accesses protected by sExtensionMapMutex
78static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
79static int sGLExtentionSlot = 0;
80static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER;
81
82static void(*findProcAddress(const char* name,
83 const extention_map_t* map, size_t n))() {
84 for (uint32_t i=0 ; i<n ; i++) {
85 if (!strcmp(name, map[i].name)) {
86 return map[i].address;
87 }
88 }
89 return NULL;
90}
91
92// ----------------------------------------------------------------------------
93
Mathias Agopian518ec112011-05-13 16:21:08 -070094namespace android {
95extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
96extern EGLBoolean egl_init_drivers();
97extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
Siva Velusamya73a9772012-12-18 14:56:55 -080098extern int getEGLDebugLevel();
99extern void setEGLDebugLevel(int level);
Mathias Agopian518ec112011-05-13 16:21:08 -0700100extern gl_hooks_t gHooksTrace;
Mathias Agopian518ec112011-05-13 16:21:08 -0700101} // namespace android;
102
103// ----------------------------------------------------------------------------
104
105static inline void clearError() { egl_tls_t::clearError(); }
106static inline EGLContext getContext() { return egl_tls_t::getContext(); }
107
108// ----------------------------------------------------------------------------
109
110EGLDisplay eglGetDisplay(EGLNativeDisplayType display)
111{
112 clearError();
113
114 uint32_t index = uint32_t(display);
115 if (index >= NUM_DISPLAYS) {
116 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
117 }
118
119 if (egl_init_drivers() == EGL_FALSE) {
120 return setError(EGL_BAD_PARAMETER, EGL_NO_DISPLAY);
121 }
122
123 EGLDisplay dpy = egl_display_t::getFromNativeDisplay(display);
124 return dpy;
125}
126
127// ----------------------------------------------------------------------------
128// Initialization
129// ----------------------------------------------------------------------------
130
131EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
132{
133 clearError();
134
Jesse Hallb29e5e82012-04-04 16:53:42 -0700135 egl_display_ptr dp = get_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -0700136 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
137
138 EGLBoolean res = dp->initialize(major, minor);
139
140 return res;
141}
142
143EGLBoolean eglTerminate(EGLDisplay dpy)
144{
145 // NOTE: don't unload the drivers b/c some APIs can be called
146 // after eglTerminate() has been called. eglTerminate() only
147 // terminates an EGLDisplay, not a EGL itself.
148
149 clearError();
150
Jesse Hallb29e5e82012-04-04 16:53:42 -0700151 egl_display_ptr dp = get_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -0700152 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
153
154 EGLBoolean res = dp->terminate();
Jesse Hall47743382013-02-08 11:13:46 -0800155
Mathias Agopian518ec112011-05-13 16:21:08 -0700156 return res;
157}
158
159// ----------------------------------------------------------------------------
160// configuration
161// ----------------------------------------------------------------------------
162
163EGLBoolean eglGetConfigs( EGLDisplay dpy,
164 EGLConfig *configs,
165 EGLint config_size, EGLint *num_config)
166{
167 clearError();
168
Jesse Hallb29e5e82012-04-04 16:53:42 -0700169 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -0700170 if (!dp) return EGL_FALSE;
171
Mathias Agopian7773c432012-02-13 20:06:08 -0800172 if (num_config==0) {
173 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -0700174 }
175
Mathias Agopian7773c432012-02-13 20:06:08 -0800176 EGLBoolean res = EGL_FALSE;
177 *num_config = 0;
178
179 egl_connection_t* const cnx = &gEGLImpl;
180 if (cnx->dso) {
181 res = cnx->egl.eglGetConfigs(
182 dp->disp.dpy, configs, config_size, num_config);
Mathias Agopian518ec112011-05-13 16:21:08 -0700183 }
Mathias Agopian7773c432012-02-13 20:06:08 -0800184
185 return res;
Mathias Agopian518ec112011-05-13 16:21:08 -0700186}
187
188EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
189 EGLConfig *configs, EGLint config_size,
190 EGLint *num_config)
191{
192 clearError();
193
Jesse Hallb29e5e82012-04-04 16:53:42 -0700194 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -0700195 if (!dp) return EGL_FALSE;
196
197 if (num_config==0) {
198 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
199 }
200
Mathias Agopian518ec112011-05-13 16:21:08 -0700201 EGLBoolean res = EGL_FALSE;
202 *num_config = 0;
203
Mathias Agopianada798b2012-02-13 17:09:30 -0800204 egl_connection_t* const cnx = &gEGLImpl;
205 if (cnx->dso) {
Romain Guy1cffc802012-10-15 18:13:05 -0700206 if (attrib_list) {
207 char value[PROPERTY_VALUE_MAX];
208 property_get("debug.egl.force_msaa", value, "false");
209
210 if (!strcmp(value, "true")) {
211 size_t attribCount = 0;
212 EGLint attrib = attrib_list[0];
213
214 // Only enable MSAA if the context is OpenGL ES 2.0 and
Romain Guybe3c3e42012-10-15 19:25:18 -0700215 // if no caveat is requested
Romain Guy1cffc802012-10-15 18:13:05 -0700216 const EGLint *attribRendererable = NULL;
217 const EGLint *attribCaveat = NULL;
218
219 // Count the number of attributes and look for
Romain Guybe3c3e42012-10-15 19:25:18 -0700220 // EGL_RENDERABLE_TYPE and EGL_CONFIG_CAVEAT
Romain Guy1cffc802012-10-15 18:13:05 -0700221 while (attrib != EGL_NONE) {
222 attrib = attrib_list[attribCount];
223 switch (attrib) {
224 case EGL_RENDERABLE_TYPE:
225 attribRendererable = &attrib_list[attribCount];
226 break;
227 case EGL_CONFIG_CAVEAT:
228 attribCaveat = &attrib_list[attribCount];
229 break;
230 }
231 attribCount++;
232 }
233
234 if (attribRendererable && attribRendererable[1] == EGL_OPENGL_ES2_BIT &&
235 (!attribCaveat || attribCaveat[1] != EGL_NONE)) {
Jesse Hall47743382013-02-08 11:13:46 -0800236
Romain Guy1cffc802012-10-15 18:13:05 -0700237 // Insert 2 extra attributes to force-enable MSAA 4x
238 EGLint aaAttribs[attribCount + 4];
239 aaAttribs[0] = EGL_SAMPLE_BUFFERS;
240 aaAttribs[1] = 1;
241 aaAttribs[2] = EGL_SAMPLES;
242 aaAttribs[3] = 4;
243
244 memcpy(&aaAttribs[4], attrib_list, attribCount * sizeof(EGLint));
245
246 EGLint numConfigAA;
247 EGLBoolean resAA = cnx->egl.eglChooseConfig(
248 dp->disp.dpy, aaAttribs, configs, config_size, &numConfigAA);
249
250 if (resAA == EGL_TRUE && numConfigAA > 0) {
251 ALOGD("Enabling MSAA 4x");
252 *num_config = numConfigAA;
253 return resAA;
254 }
255 }
256 }
257 }
258
Mathias Agopian7773c432012-02-13 20:06:08 -0800259 res = cnx->egl.eglChooseConfig(
260 dp->disp.dpy, attrib_list, configs, config_size, num_config);
Mathias Agopian518ec112011-05-13 16:21:08 -0700261 }
262 return res;
263}
264
265EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
266 EGLint attribute, EGLint *value)
267{
268 clearError();
269
Jesse Hallb29e5e82012-04-04 16:53:42 -0700270 egl_connection_t* cnx = NULL;
271 const egl_display_ptr dp = validate_display_connection(dpy, cnx);
272 if (!dp) return EGL_FALSE;
Jesse Hall47743382013-02-08 11:13:46 -0800273
Mathias Agopian518ec112011-05-13 16:21:08 -0700274 return cnx->egl.eglGetConfigAttrib(
Mathias Agopian7773c432012-02-13 20:06:08 -0800275 dp->disp.dpy, config, attribute, value);
Mathias Agopian518ec112011-05-13 16:21:08 -0700276}
277
278// ----------------------------------------------------------------------------
279// surfaces
280// ----------------------------------------------------------------------------
281
282EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
283 NativeWindowType window,
284 const EGLint *attrib_list)
285{
286 clearError();
287
Jesse Hallb29e5e82012-04-04 16:53:42 -0700288 egl_connection_t* cnx = NULL;
289 egl_display_ptr dp = validate_display_connection(dpy, cnx);
290 if (dp) {
Mathias Agopianada798b2012-02-13 17:09:30 -0800291 EGLDisplay iDpy = dp->disp.dpy;
Mathias Agopian518ec112011-05-13 16:21:08 -0700292 EGLint format;
293
Mathias Agopian81a63352011-07-29 17:55:48 -0700294 if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
Steve Blocke6f43dd2012-01-06 19:20:56 +0000295 ALOGE("EGLNativeWindowType %p already connected to another API",
Mathias Agopian81a63352011-07-29 17:55:48 -0700296 window);
297 return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
298 }
299
Mathias Agopian518ec112011-05-13 16:21:08 -0700300 // set the native window's buffers format to match this config
301 if (cnx->egl.eglGetConfigAttrib(iDpy,
Mathias Agopian7773c432012-02-13 20:06:08 -0800302 config, EGL_NATIVE_VISUAL_ID, &format)) {
Mathias Agopian518ec112011-05-13 16:21:08 -0700303 if (format != 0) {
Jamie Gennisbee205f2011-07-01 13:12:07 -0700304 int err = native_window_set_buffers_format(window, format);
305 if (err != 0) {
Steve Blocke6f43dd2012-01-06 19:20:56 +0000306 ALOGE("error setting native window pixel format: %s (%d)",
Jamie Gennisbee205f2011-07-01 13:12:07 -0700307 strerror(-err), err);
Mathias Agopian81a63352011-07-29 17:55:48 -0700308 native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
Jamie Gennisbee205f2011-07-01 13:12:07 -0700309 return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
310 }
Mathias Agopian518ec112011-05-13 16:21:08 -0700311 }
312 }
313
Jamie Gennis59769462011-11-19 18:04:43 -0800314 // the EGL spec requires that a new EGLSurface default to swap interval
315 // 1, so explicitly set that on the window here.
316 ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window);
317 anw->setSwapInterval(anw, 1);
318
Mathias Agopian518ec112011-05-13 16:21:08 -0700319 EGLSurface surface = cnx->egl.eglCreateWindowSurface(
Mathias Agopian7773c432012-02-13 20:06:08 -0800320 iDpy, config, window, attrib_list);
Mathias Agopian518ec112011-05-13 16:21:08 -0700321 if (surface != EGL_NO_SURFACE) {
Jesse Hallb29e5e82012-04-04 16:53:42 -0700322 egl_surface_t* s = new egl_surface_t(dp.get(), config, window,
323 surface, cnx);
Mathias Agopian518ec112011-05-13 16:21:08 -0700324 return s;
325 }
Mathias Agopian81a63352011-07-29 17:55:48 -0700326
327 // EGLSurface creation failed
328 native_window_set_buffers_format(window, 0);
329 native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
Mathias Agopian518ec112011-05-13 16:21:08 -0700330 }
331 return EGL_NO_SURFACE;
332}
333
334EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
335 NativePixmapType pixmap,
336 const EGLint *attrib_list)
337{
338 clearError();
339
Jesse Hallb29e5e82012-04-04 16:53:42 -0700340 egl_connection_t* cnx = NULL;
341 egl_display_ptr dp = validate_display_connection(dpy, cnx);
342 if (dp) {
Mathias Agopian518ec112011-05-13 16:21:08 -0700343 EGLSurface surface = cnx->egl.eglCreatePixmapSurface(
Mathias Agopian7773c432012-02-13 20:06:08 -0800344 dp->disp.dpy, config, pixmap, attrib_list);
Mathias Agopian518ec112011-05-13 16:21:08 -0700345 if (surface != EGL_NO_SURFACE) {
Jesse Hallb29e5e82012-04-04 16:53:42 -0700346 egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
347 surface, cnx);
Mathias Agopian518ec112011-05-13 16:21:08 -0700348 return s;
349 }
350 }
351 return EGL_NO_SURFACE;
352}
353
354EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
355 const EGLint *attrib_list)
356{
357 clearError();
358
Jesse Hallb29e5e82012-04-04 16:53:42 -0700359 egl_connection_t* cnx = NULL;
360 egl_display_ptr dp = validate_display_connection(dpy, cnx);
361 if (dp) {
Mathias Agopian518ec112011-05-13 16:21:08 -0700362 EGLSurface surface = cnx->egl.eglCreatePbufferSurface(
Mathias Agopian7773c432012-02-13 20:06:08 -0800363 dp->disp.dpy, config, attrib_list);
Mathias Agopian518ec112011-05-13 16:21:08 -0700364 if (surface != EGL_NO_SURFACE) {
Jesse Hallb29e5e82012-04-04 16:53:42 -0700365 egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL,
366 surface, cnx);
Mathias Agopian518ec112011-05-13 16:21:08 -0700367 return s;
368 }
369 }
370 return EGL_NO_SURFACE;
371}
Jesse Hall47743382013-02-08 11:13:46 -0800372
Mathias Agopian518ec112011-05-13 16:21:08 -0700373EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
374{
375 clearError();
376
Jesse Hallb29e5e82012-04-04 16:53:42 -0700377 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -0700378 if (!dp) return EGL_FALSE;
379
Jesse Hallb29e5e82012-04-04 16:53:42 -0700380 SurfaceRef _s(dp.get(), surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700381 if (!_s.get())
382 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -0700383
384 egl_surface_t * const s = get_surface(surface);
Mathias Agopianada798b2012-02-13 17:09:30 -0800385 EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
Mathias Agopian518ec112011-05-13 16:21:08 -0700386 if (result == EGL_TRUE) {
Mathias Agopian518ec112011-05-13 16:21:08 -0700387 _s.terminate();
388 }
389 return result;
390}
391
392EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
393 EGLint attribute, EGLint *value)
394{
395 clearError();
396
Jesse Hallb29e5e82012-04-04 16:53:42 -0700397 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -0700398 if (!dp) return EGL_FALSE;
399
Jesse Hallb29e5e82012-04-04 16:53:42 -0700400 SurfaceRef _s(dp.get(), surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700401 if (!_s.get())
402 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -0700403
Mathias Agopian518ec112011-05-13 16:21:08 -0700404 egl_surface_t const * const s = get_surface(surface);
Mathias Agopian7773c432012-02-13 20:06:08 -0800405 return s->cnx->egl.eglQuerySurface(
406 dp->disp.dpy, s->surface, attribute, value);
Mathias Agopian518ec112011-05-13 16:21:08 -0700407}
408
Jamie Gennise8696a42012-01-15 18:54:57 -0800409void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800410 ATRACE_CALL();
Jamie Gennise8696a42012-01-15 18:54:57 -0800411 clearError();
412
Jesse Hallb29e5e82012-04-04 16:53:42 -0700413 const egl_display_ptr dp = validate_display(dpy);
Jamie Gennise8696a42012-01-15 18:54:57 -0800414 if (!dp) {
415 return;
416 }
417
Jesse Hallb29e5e82012-04-04 16:53:42 -0700418 SurfaceRef _s(dp.get(), surface);
Jamie Gennise8696a42012-01-15 18:54:57 -0800419 if (!_s.get()) {
420 setError(EGL_BAD_SURFACE, EGL_FALSE);
421 return;
422 }
423
424 int64_t timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
425
426 egl_surface_t const * const s = get_surface(surface);
427 native_window_set_buffers_timestamp(s->win.get(), timestamp);
428}
429
Mathias Agopian518ec112011-05-13 16:21:08 -0700430// ----------------------------------------------------------------------------
431// Contexts
432// ----------------------------------------------------------------------------
433
434EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
435 EGLContext share_list, const EGLint *attrib_list)
436{
437 clearError();
438
Jesse Hallb29e5e82012-04-04 16:53:42 -0700439 egl_connection_t* cnx = NULL;
440 const egl_display_ptr dp = validate_display_connection(dpy, cnx);
441 if (dpy) {
Mathias Agopian518ec112011-05-13 16:21:08 -0700442 if (share_list != EGL_NO_CONTEXT) {
443 egl_context_t* const c = get_context(share_list);
444 share_list = c->context;
445 }
446 EGLContext context = cnx->egl.eglCreateContext(
Mathias Agopian7773c432012-02-13 20:06:08 -0800447 dp->disp.dpy, config, share_list, attrib_list);
Mathias Agopian518ec112011-05-13 16:21:08 -0700448 if (context != EGL_NO_CONTEXT) {
449 // figure out if it's a GLESv1 or GLESv2
450 int version = 0;
451 if (attrib_list) {
452 while (*attrib_list != EGL_NONE) {
453 GLint attr = *attrib_list++;
454 GLint value = *attrib_list++;
455 if (attr == EGL_CONTEXT_CLIENT_VERSION) {
456 if (value == 1) {
Mathias Agopian7773c432012-02-13 20:06:08 -0800457 version = egl_connection_t::GLESv1_INDEX;
Jesse Hall47743382013-02-08 11:13:46 -0800458 } else if (value == 2 || value == 3) {
Mathias Agopian7773c432012-02-13 20:06:08 -0800459 version = egl_connection_t::GLESv2_INDEX;
Mathias Agopian518ec112011-05-13 16:21:08 -0700460 }
461 }
462 };
463 }
Jesse Hallb29e5e82012-04-04 16:53:42 -0700464 egl_context_t* c = new egl_context_t(dpy, context, config, cnx,
465 version);
Siva Velusamy0469dd62011-11-30 15:05:37 -0800466#if EGL_TRACE
Siva Velusamya73a9772012-12-18 14:56:55 -0800467 if (getEGLDebugLevel() > 0)
Siva Velusamy0469dd62011-11-30 15:05:37 -0800468 GLTrace_eglCreateContext(version, c);
469#endif
Mathias Agopian518ec112011-05-13 16:21:08 -0700470 return c;
Mathias Agopian500407a2012-09-24 17:57:48 -0700471 } else {
472 EGLint error = eglGetError();
473 ALOGE_IF(error == EGL_SUCCESS,
474 "eglCreateContext(%p, %p, %p, %p) returned EGL_NO_CONTEXT "
475 "but no EGL error!",
476 dpy, config, share_list, attrib_list);
Mathias Agopian518ec112011-05-13 16:21:08 -0700477 }
478 }
479 return EGL_NO_CONTEXT;
480}
481
482EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
483{
484 clearError();
485
Jesse Hallb29e5e82012-04-04 16:53:42 -0700486 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700487 if (!dp)
488 return EGL_FALSE;
Mathias Agopian518ec112011-05-13 16:21:08 -0700489
Jesse Hallb29e5e82012-04-04 16:53:42 -0700490 ContextRef _c(dp.get(), ctx);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700491 if (!_c.get())
492 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
Jesse Hall47743382013-02-08 11:13:46 -0800493
Mathias Agopian518ec112011-05-13 16:21:08 -0700494 egl_context_t * const c = get_context(ctx);
Mathias Agopianada798b2012-02-13 17:09:30 -0800495 EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context);
Mathias Agopian518ec112011-05-13 16:21:08 -0700496 if (result == EGL_TRUE) {
497 _c.terminate();
498 }
499 return result;
500}
501
Mathias Agopian518ec112011-05-13 16:21:08 -0700502EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
503 EGLSurface read, EGLContext ctx)
504{
505 clearError();
506
Jesse Hallb29e5e82012-04-04 16:53:42 -0700507 egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -0700508 if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);
509
Mathias Agopian5b287a62011-05-16 18:58:55 -0700510 // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
511 // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
512 // a valid but uninitialized display.
Mathias Agopian518ec112011-05-13 16:21:08 -0700513 if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
514 (draw != EGL_NO_SURFACE) ) {
515 if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
516 }
517
518 // get a reference to the object passed in
Jesse Hallb29e5e82012-04-04 16:53:42 -0700519 ContextRef _c(dp.get(), ctx);
520 SurfaceRef _d(dp.get(), draw);
521 SurfaceRef _r(dp.get(), read);
Mathias Agopian518ec112011-05-13 16:21:08 -0700522
523 // validate the context (if not EGL_NO_CONTEXT)
Mathias Agopian5b287a62011-05-16 18:58:55 -0700524 if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
Mathias Agopian518ec112011-05-13 16:21:08 -0700525 // EGL_NO_CONTEXT is valid
526 return EGL_FALSE;
527 }
528
529 // these are the underlying implementation's object
530 EGLContext impl_ctx = EGL_NO_CONTEXT;
531 EGLSurface impl_draw = EGL_NO_SURFACE;
532 EGLSurface impl_read = EGL_NO_SURFACE;
533
534 // these are our objects structs passed in
535 egl_context_t * c = NULL;
536 egl_surface_t const * d = NULL;
537 egl_surface_t const * r = NULL;
538
539 // these are the current objects structs
540 egl_context_t * cur_c = get_context(getContext());
Jesse Hall47743382013-02-08 11:13:46 -0800541
Mathias Agopian518ec112011-05-13 16:21:08 -0700542 if (ctx != EGL_NO_CONTEXT) {
543 c = get_context(ctx);
544 impl_ctx = c->context;
545 } else {
546 // no context given, use the implementation of the current context
547 if (cur_c == NULL) {
548 // no current context
549 if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
550 // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
551 return setError(EGL_BAD_MATCH, EGL_FALSE);
552 }
553 // not an error, there is just no current context.
554 return EGL_TRUE;
555 }
556 }
557
558 // retrieve the underlying implementation's draw EGLSurface
559 if (draw != EGL_NO_SURFACE) {
560 d = get_surface(draw);
Mathias Agopian518ec112011-05-13 16:21:08 -0700561 impl_draw = d->surface;
562 }
563
564 // retrieve the underlying implementation's read EGLSurface
565 if (read != EGL_NO_SURFACE) {
566 r = get_surface(read);
Mathias Agopian518ec112011-05-13 16:21:08 -0700567 impl_read = r->surface;
568 }
569
Mathias Agopian518ec112011-05-13 16:21:08 -0700570
Jesse Hallb29e5e82012-04-04 16:53:42 -0700571 EGLBoolean result = dp->makeCurrent(c, cur_c,
Mathias Agopianfb87e542012-01-30 18:20:52 -0800572 draw, read, ctx,
573 impl_draw, impl_read, impl_ctx);
Mathias Agopian518ec112011-05-13 16:21:08 -0700574
575 if (result == EGL_TRUE) {
Mathias Agopianfb87e542012-01-30 18:20:52 -0800576 if (c) {
Mathias Agopian518ec112011-05-13 16:21:08 -0700577 setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
578 egl_tls_t::setContext(ctx);
Siva Velusamy0469dd62011-11-30 15:05:37 -0800579#if EGL_TRACE
Siva Velusamya73a9772012-12-18 14:56:55 -0800580 if (getEGLDebugLevel() > 0)
Siva Velusamy93a826f2011-12-14 12:19:56 -0800581 GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx);
Siva Velusamy0469dd62011-11-30 15:05:37 -0800582#endif
Mathias Agopian518ec112011-05-13 16:21:08 -0700583 _c.acquire();
584 _r.acquire();
585 _d.acquire();
Mathias Agopian518ec112011-05-13 16:21:08 -0700586 } else {
587 setGLHooksThreadSpecific(&gHooksNoContext);
588 egl_tls_t::setContext(EGL_NO_CONTEXT);
589 }
Mathias Agopian5fecea72011-08-25 18:38:24 -0700590 } else {
Steve Blocke6f43dd2012-01-06 19:20:56 +0000591 // this will ALOGE the error
Mathias Agopian5fecea72011-08-25 18:38:24 -0700592 result = setError(c->cnx->egl.eglGetError(), EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -0700593 }
594 return result;
595}
596
597
598EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
599 EGLint attribute, EGLint *value)
600{
601 clearError();
602
Jesse Hallb29e5e82012-04-04 16:53:42 -0700603 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -0700604 if (!dp) return EGL_FALSE;
605
Jesse Hallb29e5e82012-04-04 16:53:42 -0700606 ContextRef _c(dp.get(), ctx);
Mathias Agopian518ec112011-05-13 16:21:08 -0700607 if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
608
Mathias Agopian518ec112011-05-13 16:21:08 -0700609 egl_context_t * const c = get_context(ctx);
Mathias Agopian7773c432012-02-13 20:06:08 -0800610 return c->cnx->egl.eglQueryContext(
611 dp->disp.dpy, c->context, attribute, value);
Mathias Agopian518ec112011-05-13 16:21:08 -0700612
Mathias Agopian518ec112011-05-13 16:21:08 -0700613}
614
615EGLContext eglGetCurrentContext(void)
616{
617 // could be called before eglInitialize(), but we wouldn't have a context
618 // then, and this function would correctly return EGL_NO_CONTEXT.
619
620 clearError();
621
622 EGLContext ctx = getContext();
623 return ctx;
624}
625
626EGLSurface eglGetCurrentSurface(EGLint readdraw)
627{
628 // could be called before eglInitialize(), but we wouldn't have a context
629 // then, and this function would correctly return EGL_NO_SURFACE.
630
631 clearError();
632
633 EGLContext ctx = getContext();
634 if (ctx) {
635 egl_context_t const * const c = get_context(ctx);
636 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
637 switch (readdraw) {
638 case EGL_READ: return c->read;
Jesse Hall47743382013-02-08 11:13:46 -0800639 case EGL_DRAW: return c->draw;
Mathias Agopian518ec112011-05-13 16:21:08 -0700640 default: return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
641 }
642 }
643 return EGL_NO_SURFACE;
644}
645
646EGLDisplay eglGetCurrentDisplay(void)
647{
648 // could be called before eglInitialize(), but we wouldn't have a context
649 // then, and this function would correctly return EGL_NO_DISPLAY.
650
651 clearError();
652
653 EGLContext ctx = getContext();
654 if (ctx) {
655 egl_context_t const * const c = get_context(ctx);
656 if (!c) return setError(EGL_BAD_CONTEXT, EGL_NO_SURFACE);
657 return c->dpy;
658 }
659 return EGL_NO_DISPLAY;
660}
661
662EGLBoolean eglWaitGL(void)
663{
Mathias Agopian518ec112011-05-13 16:21:08 -0700664 clearError();
665
Mathias Agopianada798b2012-02-13 17:09:30 -0800666 egl_connection_t* const cnx = &gEGLImpl;
667 if (!cnx->dso)
668 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
669
670 return cnx->egl.eglWaitGL();
Mathias Agopian518ec112011-05-13 16:21:08 -0700671}
672
673EGLBoolean eglWaitNative(EGLint engine)
674{
Mathias Agopian518ec112011-05-13 16:21:08 -0700675 clearError();
676
Mathias Agopianada798b2012-02-13 17:09:30 -0800677 egl_connection_t* const cnx = &gEGLImpl;
678 if (!cnx->dso)
679 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
680
681 return cnx->egl.eglWaitNative(engine);
Mathias Agopian518ec112011-05-13 16:21:08 -0700682}
683
684EGLint eglGetError(void)
685{
Mathias Agopianada798b2012-02-13 17:09:30 -0800686 EGLint err = EGL_SUCCESS;
687 egl_connection_t* const cnx = &gEGLImpl;
688 if (cnx->dso) {
689 err = cnx->egl.eglGetError();
Mathias Agopian518ec112011-05-13 16:21:08 -0700690 }
Mathias Agopianada798b2012-02-13 17:09:30 -0800691 if (err == EGL_SUCCESS) {
692 err = egl_tls_t::getError();
693 }
694 return err;
Mathias Agopian518ec112011-05-13 16:21:08 -0700695}
696
Mathias Agopian518ec112011-05-13 16:21:08 -0700697__eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
698{
699 // eglGetProcAddress() could be the very first function called
700 // in which case we must make sure we've initialized ourselves, this
701 // happens the first time egl_get_display() is called.
702
703 clearError();
704
705 if (egl_init_drivers() == EGL_FALSE) {
706 setError(EGL_BAD_PARAMETER, NULL);
707 return NULL;
708 }
709
Jesse Hall25838592012-04-05 15:53:28 -0700710 // These extensions should not be exposed to applications. They're used
711 // internally by the Android EGL layer.
712 if (!strcmp(procname, "eglSetBlobCacheFuncsANDROID") ||
Jamie Gennis331841b2012-09-06 14:52:00 -0700713 !strcmp(procname, "eglDupNativeFenceFDANDROID") ||
Jamie Gennis010dd4f2012-09-09 17:46:17 -0700714 !strcmp(procname, "eglWaitSyncANDROID") ||
Jesse Hall25838592012-04-05 15:53:28 -0700715 !strcmp(procname, "eglHibernateProcessIMG") ||
716 !strcmp(procname, "eglAwakenProcessIMG")) {
Jamie Gennisaca51c02011-11-03 17:42:43 -0700717 return NULL;
718 }
719
Mathias Agopian518ec112011-05-13 16:21:08 -0700720 __eglMustCastToProperFunctionPointerType addr;
721 addr = findProcAddress(procname, sExtentionMap, NELEM(sExtentionMap));
722 if (addr) return addr;
723
Jamie Gennisaca51c02011-11-03 17:42:43 -0700724
Mathias Agopian518ec112011-05-13 16:21:08 -0700725 // this protects accesses to sGLExtentionMap and sGLExtentionSlot
726 pthread_mutex_lock(&sExtensionMapMutex);
727
728 /*
729 * Since eglGetProcAddress() is not associated to anything, it needs
730 * to return a function pointer that "works" regardless of what
731 * the current context is.
732 *
733 * For this reason, we return a "forwarder", a small stub that takes
734 * care of calling the function associated with the context
735 * currently bound.
736 *
737 * We first look for extensions we've already resolved, if we're seeing
738 * this extension for the first time, we go through all our
739 * implementations and call eglGetProcAddress() and record the
740 * result in the appropriate implementation hooks and return the
741 * address of the forwarder corresponding to that hook set.
742 *
743 */
744
745 const String8 name(procname);
746 addr = sGLExtentionMap.valueFor(name);
747 const int slot = sGLExtentionSlot;
748
Steve Blocke6f43dd2012-01-06 19:20:56 +0000749 ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
Mathias Agopian518ec112011-05-13 16:21:08 -0700750 "no more slots for eglGetProcAddress(\"%s\")",
751 procname);
752
Siva Velusamy0469dd62011-11-30 15:05:37 -0800753#if EGL_TRACE
754 gl_hooks_t *debugHooks = GLTrace_getGLHooks();
755#endif
756
Mathias Agopian518ec112011-05-13 16:21:08 -0700757 if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) {
758 bool found = false;
Mathias Agopianada798b2012-02-13 17:09:30 -0800759
760 egl_connection_t* const cnx = &gEGLImpl;
761 if (cnx->dso && cnx->egl.eglGetProcAddress) {
Mathias Agopianada798b2012-02-13 17:09:30 -0800762 // Extensions are independent of the bound context
luliuhui69d10072012-08-30 11:15:36 +0800763 addr =
Mathias Agopian7773c432012-02-13 20:06:08 -0800764 cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] =
765 cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] =
Mathias Agopian518ec112011-05-13 16:21:08 -0700766#if EGL_TRACE
Mathias Agopianada798b2012-02-13 17:09:30 -0800767 debugHooks->ext.extensions[slot] =
768 gHooksTrace.ext.extensions[slot] =
Mathias Agopian518ec112011-05-13 16:21:08 -0700769#endif
Mathias Agopianada798b2012-02-13 17:09:30 -0800770 cnx->egl.eglGetProcAddress(procname);
luliuhui69d10072012-08-30 11:15:36 +0800771 if (addr) found = true;
Mathias Agopian518ec112011-05-13 16:21:08 -0700772 }
Mathias Agopianada798b2012-02-13 17:09:30 -0800773
Mathias Agopian518ec112011-05-13 16:21:08 -0700774 if (found) {
luliuhui69d10072012-08-30 11:15:36 +0800775#if USE_FAST_TLS_KEY
Mathias Agopian518ec112011-05-13 16:21:08 -0700776 addr = gExtensionForwarders[slot];
luliuhui69d10072012-08-30 11:15:36 +0800777#endif
Mathias Agopian518ec112011-05-13 16:21:08 -0700778 sGLExtentionMap.add(name, addr);
779 sGLExtentionSlot++;
780 }
781 }
782
783 pthread_mutex_unlock(&sExtensionMapMutex);
784 return addr;
785}
786
Jamie Gennis28ef8d72012-04-05 20:34:54 -0700787class FrameCompletionThread : public Thread {
788public:
789
790 static void queueSync(EGLSyncKHR sync) {
791 static sp<FrameCompletionThread> thread(new FrameCompletionThread);
792 static bool running = false;
793 if (!running) {
794 thread->run("GPUFrameCompletion");
795 running = true;
796 }
797 {
798 Mutex::Autolock lock(thread->mMutex);
799 ScopedTrace st(ATRACE_TAG, String8::format("kicked off frame %d",
800 thread->mFramesQueued).string());
801 thread->mQueue.push_back(sync);
802 thread->mCondition.signal();
803 thread->mFramesQueued++;
804 ATRACE_INT("GPU Frames Outstanding", thread->mQueue.size());
805 }
806 }
807
808private:
809 FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {}
810
811 virtual bool threadLoop() {
812 EGLSyncKHR sync;
813 uint32_t frameNum;
814 {
815 Mutex::Autolock lock(mMutex);
816 while (mQueue.isEmpty()) {
817 mCondition.wait(mMutex);
818 }
819 sync = mQueue[0];
820 frameNum = mFramesCompleted;
821 }
822 EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
823 {
824 ScopedTrace st(ATRACE_TAG, String8::format("waiting for frame %d",
825 frameNum).string());
826 EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR);
827 if (result == EGL_FALSE) {
828 ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError());
829 } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
830 ALOGE("FrameCompletion: timeout waiting for fence");
831 }
832 eglDestroySyncKHR(dpy, sync);
833 }
834 {
835 Mutex::Autolock lock(mMutex);
836 mQueue.removeAt(0);
837 mFramesCompleted++;
838 ATRACE_INT("GPU Frames Outstanding", mQueue.size());
839 }
840 return true;
841 }
842
843 uint32_t mFramesQueued;
844 uint32_t mFramesCompleted;
845 Vector<EGLSyncKHR> mQueue;
846 Condition mCondition;
847 Mutex mMutex;
848};
849
Mathias Agopian518ec112011-05-13 16:21:08 -0700850EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
851{
Jamie Gennis1c8e95c2012-02-23 19:27:23 -0800852 ATRACE_CALL();
Mathias Agopian518ec112011-05-13 16:21:08 -0700853 clearError();
854
Jesse Hallb29e5e82012-04-04 16:53:42 -0700855 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -0700856 if (!dp) return EGL_FALSE;
857
Jesse Hallb29e5e82012-04-04 16:53:42 -0700858 SurfaceRef _s(dp.get(), draw);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700859 if (!_s.get())
860 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -0700861
Siva Velusamy0469dd62011-11-30 15:05:37 -0800862#if EGL_TRACE
Siva Velusamya73a9772012-12-18 14:56:55 -0800863 gl_hooks_t const *trace_hooks = getGLTraceThreadSpecific();
864 if (getEGLDebugLevel() > 0) {
865 if (trace_hooks == NULL) {
866 if (GLTrace_start() < 0) {
867 ALOGE("Disabling Tracer for OpenGL ES");
868 setEGLDebugLevel(0);
869 } else {
870 // switch over to the trace version of hooks
871 EGLContext ctx = egl_tls_t::getContext();
872 egl_context_t * const c = get_context(ctx);
873 if (c) {
874 setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
875 GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx);
876 }
877 }
878 }
879
Siva Velusamy0469dd62011-11-30 15:05:37 -0800880 GLTrace_eglSwapBuffers(dpy, draw);
Siva Velusamya73a9772012-12-18 14:56:55 -0800881 } else if (trace_hooks != NULL) {
882 // tracing is now disabled, so switch back to the non trace version
883 EGLContext ctx = egl_tls_t::getContext();
884 egl_context_t * const c = get_context(ctx);
885 if (c) setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
886 GLTrace_stop();
887 }
Siva Velusamy0469dd62011-11-30 15:05:37 -0800888#endif
889
Mathias Agopian518ec112011-05-13 16:21:08 -0700890 egl_surface_t const * const s = get_surface(draw);
Mathias Agopian7db993a2012-03-25 00:49:46 -0700891
892 if (CC_UNLIKELY(dp->finishOnSwap)) {
893 uint32_t pixel;
894 egl_context_t * const c = get_context( egl_tls_t::getContext() );
895 if (c) {
896 // glReadPixels() ensures that the frame is complete
897 s->cnx->hooks[c->version]->gl.glReadPixels(0,0,1,1,
898 GL_RGBA,GL_UNSIGNED_BYTE,&pixel);
899 }
900 }
901
Jamie Gennis28ef8d72012-04-05 20:34:54 -0700902 EGLBoolean result = s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
903
904 if (CC_UNLIKELY(dp->traceGpuCompletion)) {
905 EGLSyncKHR sync = EGL_NO_SYNC_KHR;
906 {
907 sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
908 }
909 if (sync != EGL_NO_SYNC_KHR) {
910 FrameCompletionThread::queueSync(sync);
911 }
912 }
913
914 return result;
Mathias Agopian518ec112011-05-13 16:21:08 -0700915}
916
917EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
918 NativePixmapType target)
919{
920 clearError();
921
Jesse Hallb29e5e82012-04-04 16:53:42 -0700922 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -0700923 if (!dp) return EGL_FALSE;
924
Jesse Hallb29e5e82012-04-04 16:53:42 -0700925 SurfaceRef _s(dp.get(), surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700926 if (!_s.get())
927 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -0700928
Mathias Agopian518ec112011-05-13 16:21:08 -0700929 egl_surface_t const * const s = get_surface(surface);
Mathias Agopianada798b2012-02-13 17:09:30 -0800930 return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target);
Mathias Agopian518ec112011-05-13 16:21:08 -0700931}
932
933const char* eglQueryString(EGLDisplay dpy, EGLint name)
934{
935 clearError();
936
Jesse Hallb29e5e82012-04-04 16:53:42 -0700937 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -0700938 if (!dp) return (const char *) NULL;
939
940 switch (name) {
941 case EGL_VENDOR:
Mathias Agopian4b9511c2011-11-13 23:52:47 -0800942 return dp->getVendorString();
Mathias Agopian518ec112011-05-13 16:21:08 -0700943 case EGL_VERSION:
Mathias Agopian4b9511c2011-11-13 23:52:47 -0800944 return dp->getVersionString();
Mathias Agopian518ec112011-05-13 16:21:08 -0700945 case EGL_EXTENSIONS:
Mathias Agopian4b9511c2011-11-13 23:52:47 -0800946 return dp->getExtensionString();
Mathias Agopian518ec112011-05-13 16:21:08 -0700947 case EGL_CLIENT_APIS:
Mathias Agopian4b9511c2011-11-13 23:52:47 -0800948 return dp->getClientApiString();
Mathias Agopianada798b2012-02-13 17:09:30 -0800949 case EGL_VERSION_HW_ANDROID:
950 return dp->disp.queryString.version;
Mathias Agopian518ec112011-05-13 16:21:08 -0700951 }
952 return setError(EGL_BAD_PARAMETER, (const char *)0);
953}
954
955
956// ----------------------------------------------------------------------------
957// EGL 1.1
958// ----------------------------------------------------------------------------
959
960EGLBoolean eglSurfaceAttrib(
961 EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
962{
963 clearError();
964
Jesse Hallb29e5e82012-04-04 16:53:42 -0700965 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -0700966 if (!dp) return EGL_FALSE;
967
Jesse Hallb29e5e82012-04-04 16:53:42 -0700968 SurfaceRef _s(dp.get(), surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700969 if (!_s.get())
970 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -0700971
Mathias Agopian518ec112011-05-13 16:21:08 -0700972 egl_surface_t const * const s = get_surface(surface);
973 if (s->cnx->egl.eglSurfaceAttrib) {
974 return s->cnx->egl.eglSurfaceAttrib(
Mathias Agopianada798b2012-02-13 17:09:30 -0800975 dp->disp.dpy, s->surface, attribute, value);
Mathias Agopian518ec112011-05-13 16:21:08 -0700976 }
977 return setError(EGL_BAD_SURFACE, EGL_FALSE);
978}
979
980EGLBoolean eglBindTexImage(
981 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
982{
983 clearError();
984
Jesse Hallb29e5e82012-04-04 16:53:42 -0700985 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -0700986 if (!dp) return EGL_FALSE;
987
Jesse Hallb29e5e82012-04-04 16:53:42 -0700988 SurfaceRef _s(dp.get(), surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -0700989 if (!_s.get())
990 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -0700991
Mathias Agopian518ec112011-05-13 16:21:08 -0700992 egl_surface_t const * const s = get_surface(surface);
993 if (s->cnx->egl.eglBindTexImage) {
994 return s->cnx->egl.eglBindTexImage(
Mathias Agopianada798b2012-02-13 17:09:30 -0800995 dp->disp.dpy, s->surface, buffer);
Mathias Agopian518ec112011-05-13 16:21:08 -0700996 }
997 return setError(EGL_BAD_SURFACE, EGL_FALSE);
998}
999
1000EGLBoolean eglReleaseTexImage(
1001 EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1002{
1003 clearError();
1004
Jesse Hallb29e5e82012-04-04 16:53:42 -07001005 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -07001006 if (!dp) return EGL_FALSE;
1007
Jesse Hallb29e5e82012-04-04 16:53:42 -07001008 SurfaceRef _s(dp.get(), surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -07001009 if (!_s.get())
1010 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -07001011
Mathias Agopian518ec112011-05-13 16:21:08 -07001012 egl_surface_t const * const s = get_surface(surface);
1013 if (s->cnx->egl.eglReleaseTexImage) {
1014 return s->cnx->egl.eglReleaseTexImage(
Mathias Agopianada798b2012-02-13 17:09:30 -08001015 dp->disp.dpy, s->surface, buffer);
Mathias Agopian518ec112011-05-13 16:21:08 -07001016 }
1017 return setError(EGL_BAD_SURFACE, EGL_FALSE);
1018}
1019
1020EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1021{
1022 clearError();
1023
Jesse Hallb29e5e82012-04-04 16:53:42 -07001024 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -07001025 if (!dp) return EGL_FALSE;
1026
1027 EGLBoolean res = EGL_TRUE;
Mathias Agopianada798b2012-02-13 17:09:30 -08001028 egl_connection_t* const cnx = &gEGLImpl;
1029 if (cnx->dso && cnx->egl.eglSwapInterval) {
1030 res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval);
Mathias Agopian518ec112011-05-13 16:21:08 -07001031 }
Mathias Agopianada798b2012-02-13 17:09:30 -08001032
Mathias Agopian518ec112011-05-13 16:21:08 -07001033 return res;
1034}
1035
1036
1037// ----------------------------------------------------------------------------
1038// EGL 1.2
1039// ----------------------------------------------------------------------------
1040
1041EGLBoolean eglWaitClient(void)
1042{
1043 clearError();
1044
Mathias Agopianada798b2012-02-13 17:09:30 -08001045 egl_connection_t* const cnx = &gEGLImpl;
1046 if (!cnx->dso)
1047 return setError(EGL_BAD_CONTEXT, EGL_FALSE);
1048
1049 EGLBoolean res;
1050 if (cnx->egl.eglWaitClient) {
1051 res = cnx->egl.eglWaitClient();
1052 } else {
1053 res = cnx->egl.eglWaitGL();
Mathias Agopian518ec112011-05-13 16:21:08 -07001054 }
1055 return res;
1056}
1057
1058EGLBoolean eglBindAPI(EGLenum api)
1059{
1060 clearError();
1061
1062 if (egl_init_drivers() == EGL_FALSE) {
1063 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1064 }
1065
1066 // bind this API on all EGLs
1067 EGLBoolean res = EGL_TRUE;
Mathias Agopianada798b2012-02-13 17:09:30 -08001068 egl_connection_t* const cnx = &gEGLImpl;
1069 if (cnx->dso && cnx->egl.eglBindAPI) {
1070 res = cnx->egl.eglBindAPI(api);
Mathias Agopian518ec112011-05-13 16:21:08 -07001071 }
1072 return res;
1073}
1074
1075EGLenum eglQueryAPI(void)
1076{
1077 clearError();
1078
1079 if (egl_init_drivers() == EGL_FALSE) {
1080 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1081 }
1082
Mathias Agopianada798b2012-02-13 17:09:30 -08001083 egl_connection_t* const cnx = &gEGLImpl;
1084 if (cnx->dso && cnx->egl.eglQueryAPI) {
1085 return cnx->egl.eglQueryAPI();
Mathias Agopian518ec112011-05-13 16:21:08 -07001086 }
Mathias Agopianada798b2012-02-13 17:09:30 -08001087
Mathias Agopian518ec112011-05-13 16:21:08 -07001088 // or, it can only be OpenGL ES
1089 return EGL_OPENGL_ES_API;
1090}
1091
1092EGLBoolean eglReleaseThread(void)
1093{
1094 clearError();
1095
1096 // If there is context bound to the thread, release it
Mathias Agopianfb87e542012-01-30 18:20:52 -08001097 egl_display_t::loseCurrent(get_context(getContext()));
Mathias Agopian518ec112011-05-13 16:21:08 -07001098
Mathias Agopianada798b2012-02-13 17:09:30 -08001099 egl_connection_t* const cnx = &gEGLImpl;
1100 if (cnx->dso && cnx->egl.eglReleaseThread) {
1101 cnx->egl.eglReleaseThread();
Mathias Agopian518ec112011-05-13 16:21:08 -07001102 }
Mathias Agopianada798b2012-02-13 17:09:30 -08001103
Mathias Agopian518ec112011-05-13 16:21:08 -07001104 egl_tls_t::clearTLS();
Siva Velusamy0469dd62011-11-30 15:05:37 -08001105#if EGL_TRACE
Siva Velusamya73a9772012-12-18 14:56:55 -08001106 if (getEGLDebugLevel() > 0)
Siva Velusamy0469dd62011-11-30 15:05:37 -08001107 GLTrace_eglReleaseThread();
1108#endif
Mathias Agopian518ec112011-05-13 16:21:08 -07001109 return EGL_TRUE;
1110}
1111
1112EGLSurface eglCreatePbufferFromClientBuffer(
1113 EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
1114 EGLConfig config, const EGLint *attrib_list)
1115{
1116 clearError();
1117
Jesse Hallb29e5e82012-04-04 16:53:42 -07001118 egl_connection_t* cnx = NULL;
1119 const egl_display_ptr dp = validate_display_connection(dpy, cnx);
1120 if (!dp) return EGL_FALSE;
Mathias Agopian518ec112011-05-13 16:21:08 -07001121 if (cnx->egl.eglCreatePbufferFromClientBuffer) {
1122 return cnx->egl.eglCreatePbufferFromClientBuffer(
Mathias Agopian7773c432012-02-13 20:06:08 -08001123 dp->disp.dpy, buftype, buffer, config, attrib_list);
Mathias Agopian518ec112011-05-13 16:21:08 -07001124 }
1125 return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE);
1126}
1127
1128// ----------------------------------------------------------------------------
1129// EGL_EGLEXT_VERSION 3
1130// ----------------------------------------------------------------------------
1131
1132EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
1133 const EGLint *attrib_list)
1134{
1135 clearError();
1136
Jesse Hallb29e5e82012-04-04 16:53:42 -07001137 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -07001138 if (!dp) return EGL_FALSE;
1139
Jesse Hallb29e5e82012-04-04 16:53:42 -07001140 SurfaceRef _s(dp.get(), surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -07001141 if (!_s.get())
1142 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -07001143
1144 egl_surface_t const * const s = get_surface(surface);
Mathias Agopian518ec112011-05-13 16:21:08 -07001145 if (s->cnx->egl.eglLockSurfaceKHR) {
1146 return s->cnx->egl.eglLockSurfaceKHR(
Mathias Agopianada798b2012-02-13 17:09:30 -08001147 dp->disp.dpy, s->surface, attrib_list);
Mathias Agopian518ec112011-05-13 16:21:08 -07001148 }
1149 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1150}
1151
1152EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
1153{
1154 clearError();
1155
Jesse Hallb29e5e82012-04-04 16:53:42 -07001156 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -07001157 if (!dp) return EGL_FALSE;
1158
Jesse Hallb29e5e82012-04-04 16:53:42 -07001159 SurfaceRef _s(dp.get(), surface);
Mathias Agopian5b287a62011-05-16 18:58:55 -07001160 if (!_s.get())
1161 return setError(EGL_BAD_SURFACE, EGL_FALSE);
Mathias Agopian518ec112011-05-13 16:21:08 -07001162
1163 egl_surface_t const * const s = get_surface(surface);
Mathias Agopian518ec112011-05-13 16:21:08 -07001164 if (s->cnx->egl.eglUnlockSurfaceKHR) {
Mathias Agopianada798b2012-02-13 17:09:30 -08001165 return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface);
Mathias Agopian518ec112011-05-13 16:21:08 -07001166 }
1167 return setError(EGL_BAD_DISPLAY, EGL_FALSE);
1168}
1169
1170EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
1171 EGLClientBuffer buffer, const EGLint *attrib_list)
1172{
1173 clearError();
1174
Jesse Hallb29e5e82012-04-04 16:53:42 -07001175 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -07001176 if (!dp) return EGL_NO_IMAGE_KHR;
1177
Jesse Hallb29e5e82012-04-04 16:53:42 -07001178 ContextRef _c(dp.get(), ctx);
Mathias Agopian7c0441a2012-02-14 17:14:36 -08001179 egl_context_t * const c = _c.get();
Mathias Agopian518ec112011-05-13 16:21:08 -07001180
Mathias Agopian7c0441a2012-02-14 17:14:36 -08001181 EGLImageKHR result = EGL_NO_IMAGE_KHR;
1182 egl_connection_t* const cnx = &gEGLImpl;
1183 if (cnx->dso && cnx->egl.eglCreateImageKHR) {
1184 result = cnx->egl.eglCreateImageKHR(
1185 dp->disp.dpy,
1186 c ? c->context : EGL_NO_CONTEXT,
1187 target, buffer, attrib_list);
Mathias Agopian518ec112011-05-13 16:21:08 -07001188 }
Mathias Agopian7c0441a2012-02-14 17:14:36 -08001189 return result;
Mathias Agopian518ec112011-05-13 16:21:08 -07001190}
1191
1192EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1193{
1194 clearError();
1195
Jesse Hallb29e5e82012-04-04 16:53:42 -07001196 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -07001197 if (!dp) return EGL_FALSE;
1198
Steven Holte646a5c52012-06-04 20:02:11 -07001199 EGLBoolean result = EGL_FALSE;
Mathias Agopianada798b2012-02-13 17:09:30 -08001200 egl_connection_t* const cnx = &gEGLImpl;
Mathias Agopian7c0441a2012-02-14 17:14:36 -08001201 if (cnx->dso && cnx->egl.eglDestroyImageKHR) {
Steven Holte646a5c52012-06-04 20:02:11 -07001202 result = cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img);
Mathias Agopian518ec112011-05-13 16:21:08 -07001203 }
Steven Holte646a5c52012-06-04 20:02:11 -07001204 return result;
Mathias Agopian518ec112011-05-13 16:21:08 -07001205}
1206
1207// ----------------------------------------------------------------------------
1208// EGL_EGLEXT_VERSION 5
1209// ----------------------------------------------------------------------------
1210
1211
1212EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
1213{
1214 clearError();
1215
Jesse Hallb29e5e82012-04-04 16:53:42 -07001216 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -07001217 if (!dp) return EGL_NO_SYNC_KHR;
1218
Mathias Agopian518ec112011-05-13 16:21:08 -07001219 EGLSyncKHR result = EGL_NO_SYNC_KHR;
Mathias Agopian7c0441a2012-02-14 17:14:36 -08001220 egl_connection_t* const cnx = &gEGLImpl;
1221 if (cnx->dso && cnx->egl.eglCreateSyncKHR) {
1222 result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list);
Mathias Agopian518ec112011-05-13 16:21:08 -07001223 }
Mathias Agopian7c0441a2012-02-14 17:14:36 -08001224 return result;
Mathias Agopian518ec112011-05-13 16:21:08 -07001225}
1226
1227EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1228{
1229 clearError();
1230
Jesse Hallb29e5e82012-04-04 16:53:42 -07001231 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -07001232 if (!dp) return EGL_FALSE;
1233
Mathias Agopian518ec112011-05-13 16:21:08 -07001234 EGLBoolean result = EGL_FALSE;
Mathias Agopian7c0441a2012-02-14 17:14:36 -08001235 egl_connection_t* const cnx = &gEGLImpl;
1236 if (cnx->dso && cnx->egl.eglDestroySyncKHR) {
1237 result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync);
Mathias Agopian518ec112011-05-13 16:21:08 -07001238 }
1239 return result;
1240}
1241
Mathias Agopian7c0441a2012-02-14 17:14:36 -08001242EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync,
1243 EGLint flags, EGLTimeKHR timeout)
Mathias Agopian518ec112011-05-13 16:21:08 -07001244{
1245 clearError();
1246
Jesse Hallb29e5e82012-04-04 16:53:42 -07001247 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -07001248 if (!dp) return EGL_FALSE;
1249
Mathias Agopian7c0441a2012-02-14 17:14:36 -08001250 EGLBoolean result = EGL_FALSE;
1251 egl_connection_t* const cnx = &gEGLImpl;
1252 if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) {
1253 result = cnx->egl.eglClientWaitSyncKHR(
1254 dp->disp.dpy, sync, flags, timeout);
Mathias Agopian518ec112011-05-13 16:21:08 -07001255 }
Mathias Agopian7c0441a2012-02-14 17:14:36 -08001256 return result;
Mathias Agopian518ec112011-05-13 16:21:08 -07001257}
1258
Mathias Agopian7c0441a2012-02-14 17:14:36 -08001259EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync,
1260 EGLint attribute, EGLint *value)
Mathias Agopian518ec112011-05-13 16:21:08 -07001261{
1262 clearError();
1263
Jesse Hallb29e5e82012-04-04 16:53:42 -07001264 const egl_display_ptr dp = validate_display(dpy);
Mathias Agopian518ec112011-05-13 16:21:08 -07001265 if (!dp) return EGL_FALSE;
1266
Mathias Agopian7c0441a2012-02-14 17:14:36 -08001267 EGLBoolean result = EGL_FALSE;
1268 egl_connection_t* const cnx = &gEGLImpl;
1269 if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) {
1270 result = cnx->egl.eglGetSyncAttribKHR(
1271 dp->disp.dpy, sync, attribute, value);
Mathias Agopian518ec112011-05-13 16:21:08 -07001272 }
Mathias Agopian7c0441a2012-02-14 17:14:36 -08001273 return result;
Mathias Agopian518ec112011-05-13 16:21:08 -07001274}
1275
1276// ----------------------------------------------------------------------------
1277// ANDROID extensions
1278// ----------------------------------------------------------------------------
1279
Jamie Gennis331841b2012-09-06 14:52:00 -07001280EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync)
1281{
1282 clearError();
1283
1284 const egl_display_ptr dp = validate_display(dpy);
1285 if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID;
1286
1287 EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID;
1288 egl_connection_t* const cnx = &gEGLImpl;
1289 if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) {
1290 result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync);
1291 }
1292 return result;
1293}
Jonas Yang1c3d72a2011-08-26 20:04:39 +08001294
Jamie Gennis010dd4f2012-09-09 17:46:17 -07001295EGLint eglWaitSyncANDROID(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags)
1296{
1297 clearError();
1298
1299 const egl_display_ptr dp = validate_display(dpy);
1300 if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID;
1301
1302 EGLint result = EGL_FALSE;
1303 egl_connection_t* const cnx = &gEGLImpl;
1304 if (cnx->dso && cnx->egl.eglWaitSyncANDROID) {
1305 result = cnx->egl.eglWaitSyncANDROID(dp->disp.dpy, sync, flags);
1306 }
1307 return result;
1308}
1309
Jonas Yang1c3d72a2011-08-26 20:04:39 +08001310// ----------------------------------------------------------------------------
1311// NVIDIA extensions
1312// ----------------------------------------------------------------------------
1313EGLuint64NV eglGetSystemTimeFrequencyNV()
1314{
1315 clearError();
1316
1317 if (egl_init_drivers() == EGL_FALSE) {
1318 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1319 }
1320
1321 EGLuint64NV ret = 0;
Mathias Agopianada798b2012-02-13 17:09:30 -08001322 egl_connection_t* const cnx = &gEGLImpl;
Jonas Yang1c3d72a2011-08-26 20:04:39 +08001323
Mathias Agopianada798b2012-02-13 17:09:30 -08001324 if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) {
1325 return cnx->egl.eglGetSystemTimeFrequencyNV();
Jonas Yang1c3d72a2011-08-26 20:04:39 +08001326 }
1327
Mathias Agopian0e8bbee2011-10-05 19:15:05 -07001328 return setErrorQuiet(EGL_BAD_DISPLAY, 0);
Jonas Yang1c3d72a2011-08-26 20:04:39 +08001329}
1330
1331EGLuint64NV eglGetSystemTimeNV()
1332{
1333 clearError();
1334
1335 if (egl_init_drivers() == EGL_FALSE) {
1336 return setError(EGL_BAD_PARAMETER, EGL_FALSE);
1337 }
1338
1339 EGLuint64NV ret = 0;
Mathias Agopianada798b2012-02-13 17:09:30 -08001340 egl_connection_t* const cnx = &gEGLImpl;
Jonas Yang1c3d72a2011-08-26 20:04:39 +08001341
Mathias Agopianada798b2012-02-13 17:09:30 -08001342 if (cnx->dso && cnx->egl.eglGetSystemTimeNV) {
1343 return cnx->egl.eglGetSystemTimeNV();
Jonas Yang1c3d72a2011-08-26 20:04:39 +08001344 }
1345
Mathias Agopian0e8bbee2011-10-05 19:15:05 -07001346 return setErrorQuiet(EGL_BAD_DISPLAY, 0);
Jonas Yang1c3d72a2011-08-26 20:04:39 +08001347}