OSDN Git Service

Implement a couple more surface attributes in eglQuerySurface.
[android-x86/device-generic-goldfish-opengl.git] / system / egl / egl.cpp
1 /*
2 * Copyright (C) 2011 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 "HostConnection.h"
18 #include "ThreadInfo.h"
19 #include "eglDisplay.h"
20 #include "egl_ftable.h"
21 #include <cutils/log.h>
22 #include "gralloc_cb.h"
23 #include "GLClientState.h"
24 #include "GLSharedGroup.h"
25 #include "eglContext.h"
26 #include "ClientAPIExts.h"
27
28 #include "GLEncoder.h"
29 #ifdef WITH_GLES2
30 #include "GL2Encoder.h"
31 #endif
32
33 #include <system/window.h>
34
35 template<typename T>
36 static T setErrorFunc(GLint error, T returnValue) {
37     getEGLThreadInfo()->eglError = error;
38     return returnValue;
39 }
40
41 const char *  eglStrError(EGLint err)
42 {
43     switch (err){
44         case EGL_SUCCESS:           return "EGL_SUCCESS";
45         case EGL_NOT_INITIALIZED:   return "EGL_NOT_INITIALIZED";
46         case EGL_BAD_ACCESS:        return "EGL_BAD_ACCESS";
47         case EGL_BAD_ALLOC:         return "EGL_BAD_ALLOC";
48         case EGL_BAD_ATTRIBUTE:     return "EGL_BAD_ATTRIBUTE";
49         case EGL_BAD_CONFIG:        return "EGL_BAD_CONFIG";
50         case EGL_BAD_CONTEXT:       return "EGL_BAD_CONTEXT";
51         case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
52         case EGL_BAD_DISPLAY:       return "EGL_BAD_DISPLAY";
53         case EGL_BAD_MATCH:         return "EGL_BAD_MATCH";
54         case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
55         case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
56         case EGL_BAD_PARAMETER:     return "EGL_BAD_PARAMETER";
57         case EGL_BAD_SURFACE:       return "EGL_BAD_SURFACE";
58         case EGL_CONTEXT_LOST:      return "EGL_CONTEXT_LOST";
59         default: return "UNKNOWN";
60     }
61 }
62
63 #define LOG_EGL_ERRORS 1
64
65 #ifdef LOG_EGL_ERRORS
66
67 #define setErrorReturn(error, retVal)     \
68     {                                                \
69         ALOGE("tid %d: %s(%d): error 0x%x (%s)", gettid(), __FUNCTION__, __LINE__, error, eglStrError(error));     \
70         return setErrorFunc(error, retVal);            \
71     }
72
73 #define RETURN_ERROR(ret,err)           \
74     ALOGE("tid %d: %s(%d): error 0x%x (%s)", gettid(), __FUNCTION__, __LINE__, err, eglStrError(err));    \
75     getEGLThreadInfo()->eglError = err;    \
76     return ret;
77
78 #else //!LOG_EGL_ERRORS
79
80 #define setErrorReturn(error, retVal) return setErrorFunc(error, retVal);
81
82 #define RETURN_ERROR(ret,err)           \
83     getEGLThreadInfo()->eglError = err; \
84     return ret;
85
86 #endif //LOG_EGL_ERRORS
87
88 #define VALIDATE_CONFIG(cfg,ret) \
89     if(((intptr_t)cfg<0)||((intptr_t)cfg>s_display.getNumConfigs())) { \
90         RETURN_ERROR(ret,EGL_BAD_CONFIG); \
91     }
92
93 #define VALIDATE_DISPLAY(dpy,ret) \
94     if ((dpy) != (EGLDisplay)&s_display) { \
95         RETURN_ERROR(ret, EGL_BAD_DISPLAY);    \
96     }
97
98 #define VALIDATE_DISPLAY_INIT(dpy,ret) \
99     VALIDATE_DISPLAY(dpy, ret)    \
100     if (!s_display.initialized()) {        \
101         RETURN_ERROR(ret, EGL_NOT_INITIALIZED);    \
102     }
103
104 #define DEFINE_HOST_CONNECTION \
105     HostConnection *hostCon = HostConnection::get(); \
106     renderControl_encoder_context_t *rcEnc = (hostCon ? hostCon->rcEncoder() : NULL)
107
108 #define DEFINE_AND_VALIDATE_HOST_CONNECTION(ret) \
109     HostConnection *hostCon = HostConnection::get(); \
110     if (!hostCon) { \
111         ALOGE("egl: Failed to get host connection\n"); \
112         return ret; \
113     } \
114     renderControl_encoder_context_t *rcEnc = hostCon->rcEncoder(); \
115     if (!rcEnc) { \
116         ALOGE("egl: Failed to get renderControl encoder context\n"); \
117         return ret; \
118     }
119
120 #define VALIDATE_CONTEXT_RETURN(context,ret)        \
121     if (!context) {                                    \
122         RETURN_ERROR(ret,EGL_BAD_CONTEXT);    \
123     }
124
125 #define VALIDATE_SURFACE_RETURN(surface, ret)    \
126     if (surface != EGL_NO_SURFACE) {    \
127         egl_surface_t* s( static_cast<egl_surface_t*>(surface) );    \
128         if (s->dpy != (EGLDisplay)&s_display)    \
129             setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE);    \
130     }
131
132
133 EGLContext_t::EGLContext_t(EGLDisplay dpy, EGLConfig config, EGLContext_t* shareCtx) :
134     dpy(dpy),
135     config(config),
136     read(EGL_NO_SURFACE),
137     draw(EGL_NO_SURFACE),
138     shareCtx(shareCtx),
139     rcContext(0),
140     versionString(NULL),
141     vendorString(NULL),
142     rendererString(NULL),
143     shaderVersionString(NULL),
144     extensionString(NULL),
145     deletePending(0)
146 {
147     flags = 0;
148     version = 1;
149     clientState = new GLClientState();
150     if (shareCtx)
151         sharedGroup = shareCtx->getSharedGroup();
152     else
153         sharedGroup = GLSharedGroupPtr(new GLSharedGroup());
154 };
155
156 EGLContext_t::~EGLContext_t()
157 {
158     delete clientState;
159     delete [] versionString;
160     delete [] vendorString;
161     delete [] rendererString;
162     delete [] shaderVersionString;
163     delete [] extensionString;
164 }
165
166 // ----------------------------------------------------------------------------
167 //egl_surface_t
168
169 //we don't need to handle depth since it's handled when window created on the host
170
171 struct egl_surface_t {
172
173     EGLDisplay          dpy;
174     EGLConfig           config;
175
176
177     egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceType);
178     virtual     ~egl_surface_t();
179
180     virtual     void        setSwapInterval(int interval) = 0;
181     virtual     EGLBoolean  swapBuffers() = 0;
182
183     EGLint      getSwapBehavior() const;
184     uint32_t    getRcSurface()   { return rcSurface; }
185     EGLint      getSurfaceType() { return surfaceType; }
186
187     EGLint      getWidth(){ return width; }
188     EGLint      getHeight(){ return height; }
189     void        setTextureFormat(EGLint _texFormat) { texFormat = _texFormat; }
190     EGLint      getTextureFormat() { return texFormat; }
191     void        setTextureTarget(EGLint _texTarget) { texTarget = _texTarget; }
192     EGLint      getTextureTarget() { return texTarget; }
193
194 private:
195     //
196     //Surface attributes
197     //
198     EGLint      width;
199     EGLint      height;
200     EGLint      texFormat;
201     EGLint      texTarget;
202
203 protected:
204     void        setWidth(EGLint w)  { width = w;  }
205     void        setHeight(EGLint h) { height = h; }
206
207     EGLint      surfaceType;
208     uint32_t    rcSurface; //handle to surface created via remote control
209 };
210
211 egl_surface_t::egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceType)
212     : dpy(dpy), config(config), surfaceType(surfaceType), rcSurface(0)
213 {
214     width = 0;
215     height = 0;
216     texFormat = EGL_NO_TEXTURE;
217     texTarget = EGL_NO_TEXTURE;
218 }
219
220 EGLint egl_surface_t::getSwapBehavior() const {
221     return EGL_BUFFER_PRESERVED;
222 }
223
224 egl_surface_t::~egl_surface_t()
225 {
226 }
227
228 // ----------------------------------------------------------------------------
229 // egl_window_surface_t
230
231 struct egl_window_surface_t : public egl_surface_t {
232     static egl_window_surface_t* create(
233             EGLDisplay dpy, EGLConfig config, EGLint surfType,
234             ANativeWindow* window);
235
236     virtual ~egl_window_surface_t();
237
238     virtual void       setSwapInterval(int interval);
239     virtual EGLBoolean swapBuffers();
240
241 private:
242     egl_window_surface_t(
243             EGLDisplay dpy, EGLConfig config, EGLint surfType,
244             ANativeWindow* window);
245     EGLBoolean init();
246
247     ANativeWindow*              nativeWindow;
248     android_native_buffer_t*    buffer;
249 };
250
251 egl_window_surface_t::egl_window_surface_t (
252         EGLDisplay dpy, EGLConfig config, EGLint surfType,
253         ANativeWindow* window)
254 :   egl_surface_t(dpy, config, surfType),
255     nativeWindow(window),
256     buffer(NULL)
257 {
258     // keep a reference on the window
259     nativeWindow->common.incRef(&nativeWindow->common);
260 }
261
262 EGLBoolean egl_window_surface_t::init()
263 {
264     if (nativeWindow->dequeueBuffer_DEPRECATED(nativeWindow, &buffer) != NO_ERROR) {
265         setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE);
266     }
267     setWidth(buffer->width);
268     setHeight(buffer->height);
269
270     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
271     rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uintptr_t)config,
272             getWidth(), getHeight());
273     if (!rcSurface) {
274         ALOGE("rcCreateWindowSurface returned 0");
275         return EGL_FALSE;
276     }
277     rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface,
278             ((cb_handle_t*)(buffer->handle))->hostHandle);
279
280     return EGL_TRUE;
281 }
282
283 egl_window_surface_t* egl_window_surface_t::create(
284         EGLDisplay dpy, EGLConfig config, EGLint surfType,
285         ANativeWindow* window)
286 {
287     egl_window_surface_t* wnd = new egl_window_surface_t(
288             dpy, config, surfType, window);
289     if (wnd && !wnd->init()) {
290         delete wnd;
291         wnd = NULL;
292     }
293     return wnd;
294 }
295
296 egl_window_surface_t::~egl_window_surface_t() {
297     DEFINE_HOST_CONNECTION;
298     if (rcSurface && rcEnc) {
299         rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface);
300     }
301     if (buffer) {
302         nativeWindow->cancelBuffer_DEPRECATED(nativeWindow, buffer);
303     }
304     nativeWindow->common.decRef(&nativeWindow->common);
305 }
306
307 void egl_window_surface_t::setSwapInterval(int interval)
308 {
309     nativeWindow->setSwapInterval(nativeWindow, interval);
310 }
311
312 EGLBoolean egl_window_surface_t::swapBuffers()
313 {
314     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
315
316     rcEnc->rcFlushWindowColorBuffer(rcEnc, rcSurface);
317
318     nativeWindow->queueBuffer_DEPRECATED(nativeWindow, buffer);
319     if (nativeWindow->dequeueBuffer_DEPRECATED(nativeWindow, &buffer)) {
320         buffer = NULL;
321         setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE);
322     }
323
324     rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface,
325             ((cb_handle_t *)(buffer->handle))->hostHandle);
326
327     setWidth(buffer->width);
328     setHeight(buffer->height);
329
330     return EGL_TRUE;
331 }
332
333 // ----------------------------------------------------------------------------
334 //egl_pbuffer_surface_t
335
336 struct egl_pbuffer_surface_t : public egl_surface_t {
337     static egl_pbuffer_surface_t* create(EGLDisplay dpy, EGLConfig config,
338             EGLint surfType, int32_t w, int32_t h, GLenum pixelFormat);
339
340     virtual ~egl_pbuffer_surface_t();
341
342     virtual void       setSwapInterval(int interval) { (void)interval; }
343     virtual EGLBoolean swapBuffers() { return EGL_TRUE; }
344
345     uint32_t getRcColorBuffer() { return rcColorBuffer; }
346
347 private:
348     egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfType,
349             int32_t w, int32_t h);
350     EGLBoolean init(GLenum format);
351
352     uint32_t rcColorBuffer;
353 };
354
355 egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config,
356         EGLint surfType, int32_t w, int32_t h)
357 :   egl_surface_t(dpy, config, surfType),
358     rcColorBuffer(0)
359 {
360     setWidth(w);
361     setHeight(h);
362 }
363
364 egl_pbuffer_surface_t::~egl_pbuffer_surface_t()
365 {
366     DEFINE_HOST_CONNECTION;
367     if (rcEnc) {
368         if (rcColorBuffer) rcEnc->rcCloseColorBuffer(rcEnc, rcColorBuffer);
369         if (rcSurface)     rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface);
370     }
371 }
372
373 EGLBoolean egl_pbuffer_surface_t::init(GLenum pixelFormat)
374 {
375     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
376
377     rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uintptr_t)config,
378             getWidth(), getHeight());
379     if (!rcSurface) {
380         ALOGE("rcCreateWindowSurface returned 0");
381         return EGL_FALSE;
382     }
383
384     rcColorBuffer = rcEnc->rcCreateColorBuffer(rcEnc, getWidth(), getHeight(),
385             pixelFormat);
386     if (!rcColorBuffer) {
387         ALOGE("rcCreateColorBuffer returned 0");
388         return EGL_FALSE;
389     }
390
391     rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, rcColorBuffer);
392
393     return EGL_TRUE;
394 }
395
396 egl_pbuffer_surface_t* egl_pbuffer_surface_t::create(EGLDisplay dpy,
397         EGLConfig config, EGLint surfType, int32_t w, int32_t h,
398         GLenum pixelFormat)
399 {
400     egl_pbuffer_surface_t* pb = new egl_pbuffer_surface_t(dpy, config, surfType,
401             w, h);
402     if (pb && !pb->init(pixelFormat)) {
403         delete pb;
404         pb = NULL;
405     }
406     return pb;
407 }
408
409 static const char *getGLString(int glEnum)
410 {
411     EGLThreadInfo *tInfo = getEGLThreadInfo();
412     if (!tInfo || !tInfo->currentContext) {
413         return NULL;
414     }
415
416     const char** strPtr = NULL;
417
418 #define GL_VENDOR                         0x1F00
419 #define GL_RENDERER                       0x1F01
420 #define GL_VERSION                        0x1F02
421 #define GL_SHADING_LANGUAGE_VERSION       0x8B8C
422 #define GL_EXTENSIONS                     0x1F03
423
424     switch(glEnum) {
425         case GL_VERSION:
426             strPtr = &tInfo->currentContext->versionString;
427             break;
428         case GL_VENDOR:
429             strPtr = &tInfo->currentContext->vendorString;
430             break;
431         case GL_RENDERER:
432             strPtr = &tInfo->currentContext->rendererString;
433             break;
434         case GL_SHADING_LANGUAGE_VERSION:
435             strPtr = &tInfo->currentContext->shaderVersionString;
436             break;
437         case GL_EXTENSIONS:
438             strPtr = &tInfo->currentContext->extensionString;
439             break;
440     }
441
442     if (!strPtr) {
443         return NULL;
444     }
445
446     if (*strPtr != NULL) {
447         //
448         // string is already cached
449         //
450         return *strPtr;
451     }
452
453     //
454     // first query of that string - need to query host
455     //
456     DEFINE_AND_VALIDATE_HOST_CONNECTION(NULL);
457     char *hostStr = NULL;
458     int n = rcEnc->rcGetGLString(rcEnc, glEnum, NULL, 0);
459     if (n < 0) {
460         hostStr = new char[-n+1];
461         n = rcEnc->rcGetGLString(rcEnc, glEnum, hostStr, -n);
462         if (n <= 0) {
463             delete [] hostStr;
464             hostStr = NULL;
465         }
466     }
467
468     //
469     // keep the string in the context and return its value
470     //
471     *strPtr = hostStr;
472     return hostStr;
473 }
474
475 // ----------------------------------------------------------------------------
476
477 // The one and only supported display object.
478 static eglDisplay s_display;
479
480 static EGLClient_eglInterface s_eglIface = {
481     getThreadInfo: getEGLThreadInfo,
482     getGLString: getGLString
483 };
484
485 #define DBG_FUNC DBG("%s\n", __FUNCTION__)
486 EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id)
487 {
488     //
489     // we support only EGL_DEFAULT_DISPLAY.
490     //
491     if (display_id != EGL_DEFAULT_DISPLAY) {
492         return EGL_NO_DISPLAY;
493     }
494
495     return (EGLDisplay)&s_display;
496 }
497
498 EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
499 {
500     VALIDATE_DISPLAY(dpy,EGL_FALSE);
501
502     if (!s_display.initialize(&s_eglIface)) {
503         return EGL_FALSE;
504     }
505     if (major!=NULL)
506         *major = s_display.getVersionMajor();
507     if (minor!=NULL)
508         *minor = s_display.getVersionMinor();
509     return EGL_TRUE;
510 }
511
512 EGLBoolean eglTerminate(EGLDisplay dpy)
513 {
514     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
515
516     s_display.terminate();
517     return EGL_TRUE;
518 }
519
520 EGLint eglGetError()
521 {
522     EGLint error = getEGLThreadInfo()->eglError;
523     getEGLThreadInfo()->eglError = EGL_SUCCESS;
524     return error;
525 }
526
527 __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
528 {
529     // search in EGL function table
530     for (int i=0; i<egl_num_funcs; i++) {
531         if (!strcmp(egl_funcs_by_name[i].name, procname)) {
532             return (__eglMustCastToProperFunctionPointerType)egl_funcs_by_name[i].proc;
533         }
534     }
535
536     // look in gles client api's extensions table
537     return (__eglMustCastToProperFunctionPointerType)ClientAPIExts::getProcAddress(procname);
538
539     // Fail - function not found.
540     return NULL;
541 }
542
543 const char* eglQueryString(EGLDisplay dpy, EGLint name)
544 {
545     VALIDATE_DISPLAY_INIT(dpy, NULL);
546
547     return s_display.queryString(name);
548 }
549
550 EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
551 {
552     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
553
554     if(!num_config) {
555         RETURN_ERROR(EGL_FALSE,EGL_BAD_PARAMETER);
556     }
557
558     GLint numConfigs = s_display.getNumConfigs();
559     if (!configs) {
560         *num_config = numConfigs;
561         return EGL_TRUE;
562     }
563
564     EGLint i;
565     for (i = 0 ; i < numConfigs && i < config_size ; i++) {
566         *configs++ = (EGLConfig)(uintptr_t)i;
567     }
568     *num_config = i;
569     return EGL_TRUE;
570 }
571
572 EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
573 {
574     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
575
576     int attribs_size = 0;
577     if (attrib_list) {
578         const EGLint * attrib_p = attrib_list;
579         while (attrib_p[0] != EGL_NONE) {
580             attribs_size += 2;
581             attrib_p += 2;
582         }
583         attribs_size++; //for the terminating EGL_NONE
584     }
585
586     uint32_t* tempConfigs[config_size];
587     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
588     *num_config = rcEnc->rcChooseConfig(rcEnc, (EGLint*)attrib_list, attribs_size * sizeof(EGLint), (uint32_t*)tempConfigs, config_size);
589     if (configs!=NULL) {
590         EGLint i=0;
591         for (i=0;i<(*num_config);i++) {
592              *((uintptr_t*)configs+i) = *((uint32_t*)tempConfigs+i);
593         }
594     }
595
596     if (*num_config <= 0)
597         return EGL_FALSE;
598     return EGL_TRUE;
599 }
600
601 EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
602 {
603     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
604     VALIDATE_CONFIG(config, EGL_FALSE);
605
606     if (s_display.getConfigAttrib(config, attribute, value))
607     {
608         return EGL_TRUE;
609     }
610     else
611     {
612         RETURN_ERROR(EGL_FALSE, EGL_BAD_ATTRIBUTE);
613     }
614 }
615
616 EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
617 {
618     (void)attrib_list;
619
620     VALIDATE_DISPLAY_INIT(dpy, NULL);
621     VALIDATE_CONFIG(config, EGL_FALSE);
622     if (win == 0) {
623         setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
624     }
625
626     EGLint surfaceType;
627     if (s_display.getConfigAttrib(config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)    return EGL_FALSE;
628
629     if (!(surfaceType & EGL_WINDOW_BIT)) {
630         setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
631     }
632
633     if (static_cast<ANativeWindow*>(win)->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) {
634         setErrorReturn(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
635     }
636
637     egl_surface_t* surface = egl_window_surface_t::create(
638             &s_display, config, EGL_WINDOW_BIT, static_cast<ANativeWindow*>(win));
639     if (!surface) {
640         setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE);
641     }
642
643     return surface;
644 }
645
646 EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
647 {
648     VALIDATE_DISPLAY_INIT(dpy, NULL);
649     VALIDATE_CONFIG(config, EGL_FALSE);
650
651     EGLint surfaceType;
652     if (s_display.getConfigAttrib(config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)    return EGL_FALSE;
653
654     if (!(surfaceType & EGL_PBUFFER_BIT)) {
655         setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
656     }
657
658     int32_t w = 0;
659     int32_t h = 0;
660     EGLint texFormat = EGL_NO_TEXTURE;
661     EGLint texTarget = EGL_NO_TEXTURE;
662     while (attrib_list[0] != EGL_NONE) {
663         switch (attrib_list[0]) {
664             case EGL_WIDTH:
665                 w = attrib_list[1];
666                 break;
667             case EGL_HEIGHT:
668                 h = attrib_list[1];
669                 break;
670             case EGL_TEXTURE_FORMAT:
671                 texFormat = attrib_list[1];
672                 break;
673             case EGL_TEXTURE_TARGET:
674                 texTarget = attrib_list[1];
675                 break;
676             default:
677                 break;
678         };
679         attrib_list+=2;
680     }
681     if (((texFormat == EGL_NO_TEXTURE)&&(texTarget != EGL_NO_TEXTURE)) ||
682         ((texFormat != EGL_NO_TEXTURE)&&(texTarget == EGL_NO_TEXTURE))) {
683         setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
684     }
685     // TODO: check EGL_TEXTURE_FORMAT - need to support eglBindTexImage
686
687     GLenum pixelFormat;
688     if (s_display.getConfigGLPixelFormat(config, &pixelFormat) == EGL_FALSE)
689         setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
690
691     egl_surface_t* surface = egl_pbuffer_surface_t::create(dpy, config,
692             EGL_PBUFFER_BIT, w, h, pixelFormat);
693     if (!surface) {
694         setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE);
695     }
696
697     //setup attributes
698     surface->setTextureFormat(texFormat);
699     surface->setTextureTarget(texTarget);
700
701     return surface;
702 }
703
704 EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
705 {
706     //XXX: Pixmap not supported. The host cannot render to a pixmap resource
707     //     located on host. In order to support Pixmaps we should either punt
708     //     to s/w rendering -or- let the host render to a buffer that will be
709     //     copied back to guest at some sync point. None of those methods not
710     //     implemented and pixmaps are not used with OpenGL anyway ...
711     (void)dpy;
712     (void)config;
713     (void)pixmap;
714     (void)attrib_list;
715     return EGL_NO_SURFACE;
716 }
717
718 EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
719 {
720     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
721     VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE);
722
723     egl_surface_t* surface(static_cast<egl_surface_t*>(eglSurface));
724     delete surface;
725
726     return EGL_TRUE;
727 }
728
729 EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface eglSurface, EGLint attribute, EGLint *value)
730 {
731     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
732     VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE);
733
734     egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
735     EGLBoolean ret = EGL_TRUE;
736     switch (attribute) {
737         case EGL_CONFIG_ID:
738             ret = s_display.getConfigAttrib(surface->config, EGL_CONFIG_ID, value);
739             break;
740         case EGL_WIDTH:
741             *value = surface->getWidth();
742             break;
743         case EGL_HEIGHT:
744             *value = surface->getHeight();
745             break;
746         case EGL_TEXTURE_FORMAT:
747             *value = surface->getTextureFormat();
748             break;
749         case EGL_TEXTURE_TARGET:
750             *value = surface->getTextureTarget();
751             break;
752         case EGL_SWAP_BEHAVIOR:
753             *value = surface->getSwapBehavior();
754             break;
755         case EGL_LARGEST_PBUFFER:
756             // not modified for a window or pixmap surface
757             // and we ignore it when creating a PBuffer surface (default is EGL_FALSE)
758             if (surface->getSurfaceType() & EGL_PBUFFER_BIT) *value = EGL_FALSE;
759             break;
760         case EGL_MIPMAP_LEVEL:
761             // not modified for a window or pixmap surface
762             // and we ignore it when creating a PBuffer surface (default is 0)
763             if (surface->getSurfaceType() & EGL_PBUFFER_BIT) *value = 0;
764             break;
765         case EGL_MULTISAMPLE_RESOLVE:
766             // ignored when creating the surface, return default
767             *value = EGL_MULTISAMPLE_RESOLVE_DEFAULT;
768             break;
769         //TODO: complete other attributes
770         default:
771             ALOGE("eglQuerySurface %x  EGL_BAD_ATTRIBUTE", attribute);
772             ret = setErrorFunc(EGL_BAD_ATTRIBUTE, EGL_FALSE);
773             break;
774     }
775
776     return ret;
777 }
778
779 EGLBoolean eglBindAPI(EGLenum api)
780 {
781     if (api != EGL_OPENGL_ES_API)
782         setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
783     return EGL_TRUE;
784 }
785
786 EGLenum eglQueryAPI()
787 {
788     return EGL_OPENGL_ES_API;
789 }
790
791 EGLBoolean eglWaitClient()
792 {
793     return eglWaitGL();
794 }
795
796 EGLBoolean eglReleaseThread()
797 {
798     EGLThreadInfo *tInfo = getEGLThreadInfo();
799     if (tInfo && tInfo->currentContext) {
800         return eglMakeCurrent(&s_display, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE);
801     }
802     return EGL_TRUE;
803 }
804
805 EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
806 {
807     //TODO
808     (void)dpy;
809     (void)buftype;
810     (void)buffer;
811     (void)config;
812     (void)attrib_list;
813     ALOGW("%s not implemented", __FUNCTION__);
814     return 0;
815 }
816
817 EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
818 {
819     //TODO
820     (void)dpy;
821     (void)surface;
822     (void)attribute;
823     (void)value;
824     ALOGW("%s not implemented", __FUNCTION__);
825     return 0;
826 }
827
828 EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface eglSurface, EGLint buffer)
829 {
830     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
831     VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE);
832     if (eglSurface == EGL_NO_SURFACE) {
833         setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
834     }
835
836     if (buffer != EGL_BACK_BUFFER) {
837         setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
838     }
839
840     egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
841
842     if (surface->getTextureFormat() == EGL_NO_TEXTURE) {
843         setErrorReturn(EGL_BAD_MATCH, EGL_FALSE);
844     }
845
846     if (!(surface->getSurfaceType() & EGL_PBUFFER_BIT)) {
847         setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
848     }
849
850     //It's now safe to cast to pbuffer surface
851     egl_pbuffer_surface_t* pbSurface = (egl_pbuffer_surface_t*)surface;
852
853     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
854     rcEnc->rcBindTexture(rcEnc, pbSurface->getRcColorBuffer());
855
856     return GL_TRUE;
857 }
858
859 EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
860 {
861     //TODO
862     (void)dpy;
863     (void)surface;
864     (void)buffer;
865     ALOGW("%s not implemented", __FUNCTION__);
866     return 0;
867 }
868
869 EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
870 {
871     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
872     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
873
874     EGLContext_t* ctx = getEGLThreadInfo()->currentContext;
875     if (!ctx) {
876         setErrorReturn(EGL_BAD_CONTEXT, EGL_FALSE);
877     }
878     if (!ctx->draw) {
879         setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
880     }
881     egl_surface_t* draw(static_cast<egl_surface_t*>(ctx->draw));
882     draw->setSwapInterval(interval);
883
884     rcEnc->rcFBSetSwapInterval(rcEnc, interval); //TODO: implement on the host
885
886     return EGL_TRUE;
887 }
888
889 EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
890 {
891     VALIDATE_DISPLAY_INIT(dpy, EGL_NO_CONTEXT);
892     VALIDATE_CONFIG(config, EGL_NO_CONTEXT);
893
894     EGLint version = 1; //default
895     while (attrib_list && attrib_list[0] != EGL_NONE) {
896         if (attrib_list[0] == EGL_CONTEXT_CLIENT_VERSION) version = attrib_list[1];
897         attrib_list+=2;
898     }
899
900     uint32_t rcShareCtx = 0;
901     EGLContext_t * shareCtx = NULL;
902     if (share_context) {
903         shareCtx = static_cast<EGLContext_t*>(share_context);
904         rcShareCtx = shareCtx->rcContext;
905         if (shareCtx->dpy != dpy)
906             setErrorReturn(EGL_BAD_MATCH, EGL_NO_CONTEXT);
907     }
908
909     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_NO_CONTEXT);
910     uint32_t rcContext = rcEnc->rcCreateContext(rcEnc, (uintptr_t)config, rcShareCtx, version);
911     if (!rcContext) {
912         ALOGE("rcCreateContext returned 0");
913         setErrorReturn(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
914     }
915
916     EGLContext_t * context = new EGLContext_t(dpy, config, shareCtx);
917     if (!context)
918         setErrorReturn(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
919
920     context->version = version;
921     context->rcContext = rcContext;
922
923
924     return context;
925 }
926
927 EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
928 {
929     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
930     VALIDATE_CONTEXT_RETURN(ctx, EGL_FALSE);
931
932     EGLContext_t * context = static_cast<EGLContext_t*>(ctx);
933
934     if (!context) return EGL_TRUE;
935
936     if (getEGLThreadInfo()->currentContext == context) {
937         getEGLThreadInfo()->currentContext->deletePending = 1;
938         return EGL_TRUE;
939     }
940
941     if (context->rcContext) {
942         DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
943         rcEnc->rcDestroyContext(rcEnc, context->rcContext);
944         context->rcContext = 0;
945     }
946
947     delete context;
948     return EGL_TRUE;
949 }
950
951 EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
952 {
953     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
954     VALIDATE_SURFACE_RETURN(draw, EGL_FALSE);
955     VALIDATE_SURFACE_RETURN(read, EGL_FALSE);
956
957     if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
958         setErrorReturn(EGL_BAD_MATCH, EGL_FALSE);
959     if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
960         setErrorReturn(EGL_BAD_MATCH, EGL_FALSE);
961
962     EGLContext_t * context = static_cast<EGLContext_t*>(ctx);
963     uint32_t ctxHandle = (context) ? context->rcContext : 0;
964     egl_surface_t * drawSurf = static_cast<egl_surface_t *>(draw);
965     uint32_t drawHandle = (drawSurf) ? drawSurf->getRcSurface() : 0;
966     egl_surface_t * readSurf = static_cast<egl_surface_t *>(read);
967     uint32_t readHandle = (readSurf) ? readSurf->getRcSurface() : 0;
968
969     //
970     // Nothing to do if no binding change has made
971     //
972     EGLThreadInfo *tInfo = getEGLThreadInfo();
973
974     if (tInfo->currentContext == context &&
975         (context == NULL ||
976         (context && context->draw == draw && context->read == read))) {
977         return EGL_TRUE;
978     }
979
980     if (tInfo->currentContext && tInfo->currentContext->deletePending) {
981         if (tInfo->currentContext != context) {
982             EGLContext_t * contextToDelete = tInfo->currentContext;
983             tInfo->currentContext = 0;
984             eglDestroyContext(dpy, contextToDelete);
985         }
986     }
987
988     if (context && (context->flags & EGLContext_t::IS_CURRENT) && (context != tInfo->currentContext)) {
989         //context is current to another thread
990         setErrorReturn(EGL_BAD_ACCESS, EGL_FALSE);
991     }
992
993     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
994     if (rcEnc->rcMakeCurrent(rcEnc, ctxHandle, drawHandle, readHandle) == EGL_FALSE) {
995         ALOGE("rcMakeCurrent returned EGL_FALSE");
996         setErrorReturn(EGL_BAD_CONTEXT, EGL_FALSE);
997     }
998
999     //Now make the local bind
1000     if (context) {
1001         context->draw = draw;
1002         context->read = read;
1003         context->flags |= EGLContext_t::IS_CURRENT;
1004         //set the client state
1005         if (context->version == 2) {
1006             hostCon->gl2Encoder()->setClientState(context->getClientState());
1007             hostCon->gl2Encoder()->setSharedGroup(context->getSharedGroup());
1008         }
1009         else {
1010             hostCon->glEncoder()->setClientState(context->getClientState());
1011             hostCon->glEncoder()->setSharedGroup(context->getSharedGroup());
1012         }
1013     }
1014     else if (tInfo->currentContext) {
1015         //release ClientState & SharedGroup
1016         if (tInfo->currentContext->version == 2) {
1017             hostCon->gl2Encoder()->setClientState(NULL);
1018             hostCon->gl2Encoder()->setSharedGroup(GLSharedGroupPtr(NULL));
1019         }
1020         else {
1021             hostCon->glEncoder()->setClientState(NULL);
1022             hostCon->glEncoder()->setSharedGroup(GLSharedGroupPtr(NULL));
1023         }
1024
1025     }
1026
1027     if (tInfo->currentContext)
1028         tInfo->currentContext->flags &= ~EGLContext_t::IS_CURRENT;
1029
1030     //Now make current
1031     tInfo->currentContext = context;
1032
1033     //Check maybe we need to init the encoder, if it's first eglMakeCurrent
1034     if (tInfo->currentContext) {
1035         if (tInfo->currentContext->version == 2) {
1036             if (!hostCon->gl2Encoder()->isInitialized()) {
1037                 s_display.gles2_iface()->init();
1038                 hostCon->gl2Encoder()->setInitialized();
1039                 ClientAPIExts::initClientFuncs(s_display.gles2_iface(), 1);
1040             }
1041         }
1042         else {
1043             if (!hostCon->glEncoder()->isInitialized()) {
1044                 s_display.gles_iface()->init();
1045                 hostCon->glEncoder()->setInitialized();
1046                 ClientAPIExts::initClientFuncs(s_display.gles_iface(), 0);
1047             }
1048         }
1049     }
1050
1051     return EGL_TRUE;
1052 }
1053
1054 EGLContext eglGetCurrentContext()
1055 {
1056     return getEGLThreadInfo()->currentContext;
1057 }
1058
1059 EGLSurface eglGetCurrentSurface(EGLint readdraw)
1060 {
1061     EGLContext_t * context = getEGLThreadInfo()->currentContext;
1062     if (!context)
1063         return EGL_NO_SURFACE; //not an error
1064
1065     switch (readdraw) {
1066         case EGL_READ:
1067             return context->read;
1068         case EGL_DRAW:
1069             return context->draw;
1070         default:
1071             setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1072     }
1073 }
1074
1075 EGLDisplay eglGetCurrentDisplay()
1076 {
1077     EGLContext_t * context = getEGLThreadInfo()->currentContext;
1078     if (!context)
1079         return EGL_NO_DISPLAY; //not an error
1080
1081     return context->dpy;
1082 }
1083
1084 EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
1085 {
1086     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
1087     VALIDATE_CONTEXT_RETURN(ctx, EGL_FALSE);
1088
1089     EGLContext_t * context = static_cast<EGLContext_t*>(ctx);
1090
1091     EGLBoolean ret = EGL_TRUE;
1092     switch (attribute) {
1093         case EGL_CONFIG_ID:
1094             ret = s_display.getConfigAttrib(context->config, EGL_CONFIG_ID, value);
1095             break;
1096         case EGL_CONTEXT_CLIENT_TYPE:
1097             *value = EGL_OPENGL_ES_API;
1098             break;
1099         case EGL_CONTEXT_CLIENT_VERSION:
1100             *value = context->version;
1101             break;
1102         case EGL_RENDER_BUFFER:
1103             if (!context->draw)
1104                 *value = EGL_NONE;
1105             else
1106                 *value = EGL_BACK_BUFFER; //single buffer not supported
1107             break;
1108         default:
1109             ALOGE("eglQueryContext %x  EGL_BAD_ATTRIBUTE", attribute);
1110             setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1111             break;
1112     }
1113
1114     return ret;
1115 }
1116
1117 EGLBoolean eglWaitGL()
1118 {
1119     EGLThreadInfo *tInfo = getEGLThreadInfo();
1120     if (!tInfo || !tInfo->currentContext) {
1121         return EGL_FALSE;
1122     }
1123
1124     if (tInfo->currentContext->version == 2) {
1125         s_display.gles2_iface()->finish();
1126     }
1127     else {
1128         s_display.gles_iface()->finish();
1129     }
1130
1131     return EGL_TRUE;
1132 }
1133
1134 EGLBoolean eglWaitNative(EGLint engine)
1135 {
1136     (void)engine;
1137     return EGL_TRUE;
1138 }
1139
1140 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface eglSurface)
1141 {
1142     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
1143     if (eglSurface == EGL_NO_SURFACE)
1144         setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
1145
1146     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
1147
1148     egl_surface_t* d = static_cast<egl_surface_t*>(eglSurface);
1149     if (d->dpy != dpy)
1150         setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE);
1151
1152     // post the surface
1153     d->swapBuffers();
1154
1155     hostCon->flush();
1156     return EGL_TRUE;
1157 }
1158
1159 EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
1160 {
1161     //TODO :later
1162     (void)dpy;
1163     (void)surface;
1164     (void)target;
1165     return 0;
1166 }
1167
1168 EGLBoolean eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list)
1169 {
1170     //TODO later
1171     (void)display;
1172     (void)surface;
1173     (void)attrib_list;
1174     return 0;
1175 }
1176
1177 EGLBoolean eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface)
1178 {
1179     //TODO later
1180     (void)display;
1181     (void)surface;
1182     return 0;
1183 }
1184
1185 EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)
1186 {
1187     (void)attrib_list;
1188
1189     VALIDATE_DISPLAY_INIT(dpy, EGL_NO_IMAGE_KHR);
1190     if (ctx != EGL_NO_CONTEXT) {
1191         setErrorReturn(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1192     }
1193     if (target != EGL_NATIVE_BUFFER_ANDROID) {
1194         setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1195     }
1196
1197     android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
1198
1199     if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
1200         setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1201
1202     if (native_buffer->common.version != sizeof(android_native_buffer_t))
1203         setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1204
1205     cb_handle_t *cb = (cb_handle_t *)(native_buffer->handle);
1206
1207     switch (cb->format) {
1208         case HAL_PIXEL_FORMAT_RGBA_8888:
1209         case HAL_PIXEL_FORMAT_RGBX_8888:
1210         case HAL_PIXEL_FORMAT_RGB_888:
1211         case HAL_PIXEL_FORMAT_RGB_565:
1212         case HAL_PIXEL_FORMAT_BGRA_8888:
1213             break;
1214         default:
1215             setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1216     }
1217
1218     native_buffer->common.incRef(&native_buffer->common);
1219     return (EGLImageKHR)native_buffer;
1220 }
1221
1222 EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1223 {
1224     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
1225     android_native_buffer_t* native_buffer = (android_native_buffer_t*)img;
1226
1227     if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
1228         setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
1229
1230     if (native_buffer->common.version != sizeof(android_native_buffer_t))
1231         setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
1232
1233     native_buffer->common.decRef(&native_buffer->common);
1234
1235     return EGL_TRUE;
1236 }
1237
1238 #define FENCE_SYNC_HANDLE (EGLSyncKHR)0xFE4CE
1239
1240 EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type,
1241         const EGLint *attrib_list)
1242 {
1243     // TODO: This implementation could be faster. We should require the host EGL
1244     // to support KHR_fence_sync, or at least pipe the fence command to the host
1245     // and wait for it (probably involving a glFinish on the host) in
1246     // eglClientWaitSyncKHR.
1247
1248     VALIDATE_DISPLAY(dpy, EGL_NO_SYNC_KHR);
1249
1250     if (type != EGL_SYNC_FENCE_KHR ||
1251             (attrib_list != NULL && attrib_list[0] != EGL_NONE)) {
1252         setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
1253     }
1254
1255     EGLThreadInfo *tInfo = getEGLThreadInfo();
1256     if (!tInfo || !tInfo->currentContext) {
1257         setErrorReturn(EGL_BAD_MATCH, EGL_NO_SYNC_KHR);
1258     }
1259
1260     if (tInfo->currentContext->version == 2) {
1261         s_display.gles2_iface()->finish();
1262     } else {
1263         s_display.gles_iface()->finish();
1264     }
1265
1266     return FENCE_SYNC_HANDLE;
1267 }
1268
1269 EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
1270 {
1271     (void)dpy;
1272
1273     if (sync != FENCE_SYNC_HANDLE) {
1274         setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
1275     }
1276
1277     return EGL_TRUE;
1278 }
1279
1280 EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags,
1281         EGLTimeKHR timeout)
1282 {
1283     (void)dpy;
1284     (void)flags;
1285     (void)timeout;
1286
1287     if (sync != FENCE_SYNC_HANDLE) {
1288         setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
1289     }
1290
1291     return EGL_CONDITION_SATISFIED_KHR;
1292 }
1293
1294 EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync,
1295         EGLint attribute, EGLint *value)
1296 {
1297     (void)dpy;
1298
1299     if (sync != FENCE_SYNC_HANDLE) {
1300         setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
1301     }
1302
1303     switch (attribute) {
1304     case EGL_SYNC_TYPE_KHR:
1305         *value = EGL_SYNC_FENCE_KHR;
1306         return EGL_TRUE;
1307     case EGL_SYNC_STATUS_KHR:
1308         *value = EGL_SIGNALED_KHR;
1309         return EGL_TRUE;
1310     case EGL_SYNC_CONDITION_KHR:
1311         *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
1312         return EGL_TRUE;
1313     default:
1314         setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1315     }
1316 }