OSDN Git Service

Handle repeated swapBuffer errors
[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 <assert.h>
18 #include "HostConnection.h"
19 #include "ThreadInfo.h"
20 #include "eglDisplay.h"
21 #include "eglSync.h"
22 #include "egl_ftable.h"
23 #include <cutils/log.h>
24 #include <cutils/properties.h>
25 #include "goldfish_sync.h"
26 #include "gralloc_cb.h"
27 #include "GLClientState.h"
28 #include "GLSharedGroup.h"
29 #include "eglContext.h"
30 #include "ClientAPIExts.h"
31 #include "EGLImage.h"
32 #include "ProcessPipe.h"
33
34 #include "GLEncoder.h"
35 #ifdef WITH_GLES2
36 #include "GL2Encoder.h"
37 #endif
38
39 #if PLATFORM_SDK_VERSION >= 16
40 #include <system/window.h>
41 #else // PLATFORM_SDK_VERSION >= 16
42 #include <private/ui/android_natives_priv.h>
43 #endif // PLATFORM_SDK_VERSION >= 16
44
45 #if PLATFORM_SDK_VERSION <= 16
46 #define queueBuffer_DEPRECATED queueBuffer
47 #define dequeueBuffer_DEPRECATED dequeueBuffer
48 #define cancelBuffer_DEPRECATED cancelBuffer
49 #endif // PLATFORM_SDK_VERSION <= 16
50
51 #define DEBUG_EGL 0
52
53 #if DEBUG_EGL
54 #define DPRINT(fmt,...) ALOGD("%s: " fmt, __FUNCTION__, ##__VA_ARGS__);
55 #else
56 #define DPRINT(...)
57 #endif
58
59 template<typename T>
60 static T setErrorFunc(GLint error, T returnValue) {
61     getEGLThreadInfo()->eglError = error;
62     return returnValue;
63 }
64
65 const char *  eglStrError(EGLint err)
66 {
67     switch (err){
68         case EGL_SUCCESS:           return "EGL_SUCCESS";
69         case EGL_NOT_INITIALIZED:   return "EGL_NOT_INITIALIZED";
70         case EGL_BAD_ACCESS:        return "EGL_BAD_ACCESS";
71         case EGL_BAD_ALLOC:         return "EGL_BAD_ALLOC";
72         case EGL_BAD_ATTRIBUTE:     return "EGL_BAD_ATTRIBUTE";
73         case EGL_BAD_CONFIG:        return "EGL_BAD_CONFIG";
74         case EGL_BAD_CONTEXT:       return "EGL_BAD_CONTEXT";
75         case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
76         case EGL_BAD_DISPLAY:       return "EGL_BAD_DISPLAY";
77         case EGL_BAD_MATCH:         return "EGL_BAD_MATCH";
78         case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
79         case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
80         case EGL_BAD_PARAMETER:     return "EGL_BAD_PARAMETER";
81         case EGL_BAD_SURFACE:       return "EGL_BAD_SURFACE";
82         case EGL_CONTEXT_LOST:      return "EGL_CONTEXT_LOST";
83         default: return "UNKNOWN";
84     }
85 }
86
87 #define LOG_EGL_ERRORS 1
88
89 #ifdef LOG_EGL_ERRORS
90
91 #define setErrorReturn(error, retVal)     \
92     {                                                \
93         ALOGE("tid %d: %s(%d): error 0x%x (%s)", gettid(), __FUNCTION__, __LINE__, error, eglStrError(error));     \
94         return setErrorFunc(error, retVal);            \
95     }
96
97 #define RETURN_ERROR(ret,err)           \
98     ALOGE("tid %d: %s(%d): error 0x%x (%s)", gettid(), __FUNCTION__, __LINE__, err, eglStrError(err));    \
99     getEGLThreadInfo()->eglError = err;    \
100     return ret;
101
102 #else //!LOG_EGL_ERRORS
103
104 #define setErrorReturn(error, retVal) return setErrorFunc(error, retVal);
105
106 #define RETURN_ERROR(ret,err)           \
107     getEGLThreadInfo()->eglError = err; \
108     return ret;
109
110 #endif //LOG_EGL_ERRORS
111
112 #define VALIDATE_CONFIG(cfg,ret) \
113     if(((intptr_t)(cfg)<0)||((intptr_t)(cfg)>s_display.getNumConfigs())) { \
114         RETURN_ERROR(ret,EGL_BAD_CONFIG); \
115     }
116
117 #define VALIDATE_DISPLAY(dpy,ret) \
118     if ((dpy) != (EGLDisplay)&s_display) { \
119         RETURN_ERROR(ret, EGL_BAD_DISPLAY);    \
120     }
121
122 #define VALIDATE_DISPLAY_INIT(dpy,ret) \
123     VALIDATE_DISPLAY(dpy, ret)    \
124     if (!s_display.initialized()) {        \
125         RETURN_ERROR(ret, EGL_NOT_INITIALIZED);    \
126     }
127
128 #define DEFINE_HOST_CONNECTION \
129     HostConnection *hostCon = HostConnection::get(); \
130     ExtendedRCEncoderContext *rcEnc = (hostCon ? hostCon->rcEncoder() : NULL)
131
132 #define DEFINE_AND_VALIDATE_HOST_CONNECTION(ret) \
133     HostConnection *hostCon = HostConnection::get(); \
134     if (!hostCon) { \
135         ALOGE("egl: Failed to get host connection\n"); \
136         return ret; \
137     } \
138     ExtendedRCEncoderContext *rcEnc = hostCon->rcEncoder(); \
139     if (!rcEnc) { \
140         ALOGE("egl: Failed to get renderControl encoder context\n"); \
141         return ret; \
142     }
143
144 #define VALIDATE_CONTEXT_RETURN(context,ret)  \
145     if (!(context)) {                         \
146         RETURN_ERROR(ret,EGL_BAD_CONTEXT);    \
147     }
148
149 #define VALIDATE_SURFACE_RETURN(surface, ret)    \
150     if ((surface) != EGL_NO_SURFACE) {    \
151         egl_surface_t* s( static_cast<egl_surface_t*>(surface) );    \
152         if (s->dpy != (EGLDisplay)&s_display)    \
153             setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE);    \
154     }
155
156 // The one and only supported display object.
157 static eglDisplay s_display;
158
159 EGLContext_t::EGLContext_t(EGLDisplay dpy, EGLConfig config, EGLContext_t* shareCtx) :
160     dpy(dpy),
161     config(config),
162     read(EGL_NO_SURFACE),
163     draw(EGL_NO_SURFACE),
164     shareCtx(shareCtx),
165     rcContext(0),
166     versionString(NULL),
167     vendorString(NULL),
168     rendererString(NULL),
169     shaderVersionString(NULL),
170     extensionString(NULL),
171     deletePending(0),
172     goldfishSyncFd(-1)
173 {
174     flags = 0;
175     version = 1;
176     clientState = new GLClientState();
177     if (shareCtx)
178         sharedGroup = shareCtx->getSharedGroup();
179     else
180         sharedGroup = GLSharedGroupPtr(new GLSharedGroup());
181     assert(dpy == (EGLDisplay)&s_display);
182     s_display.onCreateContext((EGLContext)this);
183 };
184
185 int EGLContext_t::getGoldfishSyncFd() {
186     if (goldfishSyncFd < 0) {
187         goldfishSyncFd = goldfish_sync_open();
188     }
189     return goldfishSyncFd;
190 }
191
192 EGLContext_t::~EGLContext_t()
193 {
194     if (goldfishSyncFd > 0) {
195         goldfish_sync_close(goldfishSyncFd);
196         goldfishSyncFd = -1;
197     }
198     assert(dpy == (EGLDisplay)&s_display);
199     s_display.onDestroyContext((EGLContext)this);
200     delete clientState;
201     delete [] versionString;
202     delete [] vendorString;
203     delete [] rendererString;
204     delete [] shaderVersionString;
205     delete [] extensionString;
206 }
207
208 // ----------------------------------------------------------------------------
209 //egl_surface_t
210
211 //we don't need to handle depth since it's handled when window created on the host
212
213 struct egl_surface_t {
214
215     EGLDisplay          dpy;
216     EGLConfig           config;
217
218
219     egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceType);
220     virtual     ~egl_surface_t();
221
222     virtual     void        setSwapInterval(int interval) = 0;
223     virtual     EGLBoolean  swapBuffers() = 0;
224
225     EGLint      getSwapBehavior() const;
226     uint32_t    getRcSurface()   { return rcSurface; }
227     EGLint      getSurfaceType() { return surfaceType; }
228
229     EGLint      getWidth(){ return width; }
230     EGLint      getHeight(){ return height; }
231     EGLint      getNativeWidth(){ return nativeWidth; }
232     EGLint      getNativeHeight(){ return nativeHeight; }
233     void        setTextureFormat(EGLint _texFormat) { texFormat = _texFormat; }
234     EGLint      getTextureFormat() { return texFormat; }
235     void        setTextureTarget(EGLint _texTarget) { texTarget = _texTarget; }
236     EGLint      getTextureTarget() { return texTarget; }
237
238 private:
239     //
240     //Surface attributes
241     //
242     EGLint      width;
243     EGLint      height;
244     EGLint      texFormat;
245     EGLint      texTarget;
246
247     // Width of the actual window being presented (not the EGL texture)
248     // Give it some default values.
249     int nativeWidth;
250     int nativeHeight;
251
252 protected:
253     void        setWidth(EGLint w)  { width = w;  }
254     void        setHeight(EGLint h) { height = h; }
255     void        setNativeWidth(int w)  { nativeWidth = w;  }
256     void        setNativeHeight(int h) { nativeHeight = h; }
257
258     EGLint      surfaceType;
259     uint32_t    rcSurface; //handle to surface created via remote control
260 };
261
262 egl_surface_t::egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfaceType)
263     : dpy(dpy), config(config), surfaceType(surfaceType), rcSurface(0)
264 {
265     width = 0;
266     height = 0;
267     // prevent div by 0 in EGL_(HORIZONTAL|VERTICAL)_RESOLUTION queries.
268     nativeWidth = 1;
269     nativeHeight = 1;
270     texFormat = EGL_NO_TEXTURE;
271     texTarget = EGL_NO_TEXTURE;
272     assert(dpy == (EGLDisplay)&s_display);
273     s_display.onCreateSurface((EGLSurface)this);
274 }
275
276 EGLint egl_surface_t::getSwapBehavior() const {
277     return EGL_BUFFER_PRESERVED;
278 }
279
280 egl_surface_t::~egl_surface_t()
281 {
282     assert(dpy == (EGLDisplay)&s_display);
283     s_display.onDestroySurface((EGLSurface)this);
284 }
285
286 // ----------------------------------------------------------------------------
287 // egl_window_surface_t
288
289 struct egl_window_surface_t : public egl_surface_t {
290     static egl_window_surface_t* create(
291             EGLDisplay dpy, EGLConfig config, EGLint surfType,
292             ANativeWindow* window);
293
294     virtual ~egl_window_surface_t();
295
296     virtual void       setSwapInterval(int interval);
297     virtual EGLBoolean swapBuffers();
298
299 private:
300     egl_window_surface_t(
301             EGLDisplay dpy, EGLConfig config, EGLint surfType,
302             ANativeWindow* window);
303     EGLBoolean init();
304
305     ANativeWindow*              nativeWindow;
306     android_native_buffer_t*    buffer;
307 };
308
309 egl_window_surface_t::egl_window_surface_t (
310         EGLDisplay dpy, EGLConfig config, EGLint surfType,
311         ANativeWindow* window)
312 :   egl_surface_t(dpy, config, surfType),
313     nativeWindow(window),
314     buffer(NULL)
315 {
316     // keep a reference on the window
317     nativeWindow->common.incRef(&nativeWindow->common);
318 }
319
320
321 EGLBoolean egl_window_surface_t::init()
322 {
323     if (nativeWindow->dequeueBuffer_DEPRECATED(nativeWindow, &buffer) != NO_ERROR) {
324         setErrorReturn(EGL_BAD_ALLOC, EGL_FALSE);
325     }
326     setWidth(buffer->width);
327     setHeight(buffer->height);
328
329     int nativeWidth, nativeHeight;
330           nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &nativeWidth);
331           nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &nativeHeight);
332
333     setNativeWidth(nativeWidth);
334     setNativeHeight(nativeHeight);
335
336     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
337     rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uintptr_t)config,
338             getWidth(), getHeight());
339     if (!rcSurface) {
340         ALOGE("rcCreateWindowSurface returned 0");
341         return EGL_FALSE;
342     }
343     rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface,
344             ((cb_handle_t*)(buffer->handle))->hostHandle);
345
346     return EGL_TRUE;
347 }
348
349 egl_window_surface_t* egl_window_surface_t::create(
350         EGLDisplay dpy, EGLConfig config, EGLint surfType,
351         ANativeWindow* window)
352 {
353     egl_window_surface_t* wnd = new egl_window_surface_t(
354             dpy, config, surfType, window);
355     if (wnd && !wnd->init()) {
356         delete wnd;
357         wnd = NULL;
358     }
359     return wnd;
360 }
361
362 egl_window_surface_t::~egl_window_surface_t() {
363     DEFINE_HOST_CONNECTION;
364     if (rcSurface && rcEnc) {
365         rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface);
366     }
367     if (buffer) {
368         nativeWindow->cancelBuffer_DEPRECATED(nativeWindow, buffer);
369     }
370     nativeWindow->common.decRef(&nativeWindow->common);
371 }
372
373 void egl_window_surface_t::setSwapInterval(int interval)
374 {
375     nativeWindow->setSwapInterval(nativeWindow, interval);
376 }
377
378 // createNativeSync() creates an OpenGL sync object on the host
379 // using rcCreateSyncKHR. If necessary, a native fence FD will
380 // also be created through the goldfish sync device.
381 // Returns a handle to the host-side FenceSync object.
382 static uint64_t createNativeSync(EGLenum type,
383                                  const EGLint* attrib_list,
384                                  int num_actual_attribs,
385                                  bool destroy_when_signaled,
386                                  int fd_in,
387                                  int* fd_out) {
388     DEFINE_HOST_CONNECTION;
389
390     uint64_t sync_handle;
391     uint64_t thread_handle;
392
393     EGLint* actual_attribs =
394         (EGLint*)(num_actual_attribs == 0 ? NULL : attrib_list);
395
396     rcEnc->rcCreateSyncKHR(rcEnc, type,
397                            actual_attribs,
398                            num_actual_attribs * sizeof(EGLint),
399                            destroy_when_signaled,
400                            &sync_handle,
401                            &thread_handle);
402
403     if (type == EGL_SYNC_NATIVE_FENCE_ANDROID && fd_in < 0) {
404         int queue_work_err =
405             goldfish_sync_queue_work(
406                     getEGLThreadInfo()->currentContext->getGoldfishSyncFd(),
407                     sync_handle,
408                     thread_handle,
409                     fd_out);
410
411         DPRINT("got native fence fd=%d queue_work_err=%d",
412                *fd_out, queue_work_err);
413     }
414
415     return sync_handle;
416 }
417
418 // createGoldfishOpenGLNativeSync() is for creating host-only sync objects
419 // that are needed by only this goldfish opengl driver,
420 // such as in swapBuffers().
421 // The guest will not see any of these, and these sync objects will be
422 // destroyed on the host when signaled.
423 // A native fence FD is possibly returned.
424 static void createGoldfishOpenGLNativeSync(int* fd_out) {
425     createNativeSync(EGL_SYNC_NATIVE_FENCE_ANDROID,
426                      NULL /* empty attrib list */,
427                      0 /* 0 attrib count */,
428                      true /* destroy when signaled. this is host-only
429                              and there will only be one waiter */,
430                      -1 /* we want a new fd */,
431                      fd_out);
432 }
433
434 EGLBoolean egl_window_surface_t::swapBuffers()
435 {
436
437     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
438
439     // Follow up flushWindowColorBuffer with a fence command.
440     // When the fence command finishes,
441     // we're sure that the buffer on the host
442     // has been blitted.
443     //
444     // |presentFenceFd| guards the presentation of the
445     // current frame with a goldfish sync fence fd.
446     //
447     // When |presentFenceFd| is signaled, the recipient
448     // of the buffer that was sent through queueBuffer
449     // can be sure that the buffer is current.
450     //
451     // If we don't take care of this synchronization,
452     // an old frame can be processed by surfaceflinger,
453     // resulting in out of order frames.
454
455     int presentFenceFd = -1;
456
457     if (buffer == NULL) {
458         ALOGE("egl_window_surface_t::swapBuffers called with NULL buffer");
459         setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
460     }
461
462 #if PLATFORM_SDK_VERSION <= 16
463     rcEnc->rcFlushWindowColorBuffer(rcEnc, rcSurface);
464     // equivalent to glFinish if no native sync
465     eglWaitClient();
466     nativeWindow->queueBuffer(nativeWindow, buffer);
467 #else
468     if (rcEnc->hasNativeSync()) {
469         rcEnc->rcFlushWindowColorBufferAsync(rcEnc, rcSurface);
470         createGoldfishOpenGLNativeSync(&presentFenceFd);
471     } else {
472         rcEnc->rcFlushWindowColorBuffer(rcEnc, rcSurface);
473         // equivalent to glFinish if no native sync
474         eglWaitClient();
475     }
476
477     DPRINT("queueBuffer with fence %d", presentFenceFd);
478     nativeWindow->queueBuffer(nativeWindow, buffer, presentFenceFd);
479 #endif
480
481     DPRINT("calling dequeueBuffer...");
482
483 #if PLATFORM_SDK_VERSION <= 16
484     if (nativeWindow->dequeueBuffer(nativeWindow, &buffer)) {
485         buffer = NULL;
486         setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
487     }
488 #else
489     int acquireFenceFd = -1;
490     if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, &acquireFenceFd)) {
491         buffer = NULL;
492         setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
493     }
494
495     DPRINT("dequeueBuffer with fence %d", acquireFenceFd);
496
497     if (acquireFenceFd > 0) {
498         close(acquireFenceFd);
499     }
500 #endif
501
502     rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface,
503             ((cb_handle_t *)(buffer->handle))->hostHandle);
504
505     setWidth(buffer->width);
506     setHeight(buffer->height);
507
508     return EGL_TRUE;
509 }
510
511 // ----------------------------------------------------------------------------
512 //egl_pbuffer_surface_t
513
514 struct egl_pbuffer_surface_t : public egl_surface_t {
515     static egl_pbuffer_surface_t* create(EGLDisplay dpy, EGLConfig config,
516             EGLint surfType, int32_t w, int32_t h, GLenum pixelFormat);
517
518     virtual ~egl_pbuffer_surface_t();
519
520     virtual void       setSwapInterval(int interval) { (void)interval; }
521     virtual EGLBoolean swapBuffers() { return EGL_TRUE; }
522
523     uint32_t getRcColorBuffer() { return rcColorBuffer; }
524
525 private:
526     egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config, EGLint surfType,
527             int32_t w, int32_t h);
528     EGLBoolean init(GLenum format);
529
530     uint32_t rcColorBuffer;
531 };
532
533 egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy, EGLConfig config,
534         EGLint surfType, int32_t w, int32_t h)
535 :   egl_surface_t(dpy, config, surfType),
536     rcColorBuffer(0)
537 {
538     setWidth(w);
539     setHeight(h);
540 }
541
542 egl_pbuffer_surface_t::~egl_pbuffer_surface_t()
543 {
544     DEFINE_HOST_CONNECTION;
545     if (rcEnc) {
546         if (rcColorBuffer) rcEnc->rcCloseColorBuffer(rcEnc, rcColorBuffer);
547         if (rcSurface)     rcEnc->rcDestroyWindowSurface(rcEnc, rcSurface);
548     }
549 }
550
551 EGLBoolean egl_pbuffer_surface_t::init(GLenum pixelFormat)
552 {
553     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
554
555     rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uintptr_t)config,
556             getWidth(), getHeight());
557     if (!rcSurface) {
558         ALOGE("rcCreateWindowSurface returned 0");
559         return EGL_FALSE;
560     }
561
562     rcColorBuffer = rcEnc->rcCreateColorBuffer(rcEnc, getWidth(), getHeight(), pixelFormat);
563     if (!rcColorBuffer) {
564         ALOGE("rcCreateColorBuffer returned 0");
565         return EGL_FALSE;
566     }
567
568     rcEnc->rcSetWindowColorBuffer(rcEnc, rcSurface, rcColorBuffer);
569
570     return EGL_TRUE;
571 }
572
573 egl_pbuffer_surface_t* egl_pbuffer_surface_t::create(EGLDisplay dpy,
574         EGLConfig config, EGLint surfType, int32_t w, int32_t h,
575         GLenum pixelFormat)
576 {
577     egl_pbuffer_surface_t* pb = new egl_pbuffer_surface_t(dpy, config, surfType,
578             w, h);
579     if (pb && !pb->init(pixelFormat)) {
580         delete pb;
581         pb = NULL;
582     }
583     return pb;
584 }
585
586 static const char *getGLString(int glEnum)
587 {
588     EGLThreadInfo *tInfo = getEGLThreadInfo();
589     if (!tInfo || !tInfo->currentContext) {
590         return NULL;
591     }
592
593     const char** strPtr = NULL;
594
595 #define GL_VENDOR                         0x1F00
596 #define GL_RENDERER                       0x1F01
597 #define GL_VERSION                        0x1F02
598 #define GL_SHADING_LANGUAGE_VERSION       0x8B8C
599 #define GL_EXTENSIONS                     0x1F03
600
601     switch(glEnum) {
602         case GL_VERSION:
603             strPtr = &tInfo->currentContext->versionString;
604             break;
605         case GL_VENDOR:
606             strPtr = &tInfo->currentContext->vendorString;
607             break;
608         case GL_RENDERER:
609             strPtr = &tInfo->currentContext->rendererString;
610             break;
611         case GL_SHADING_LANGUAGE_VERSION:
612             strPtr = &tInfo->currentContext->shaderVersionString;
613             break;
614         case GL_EXTENSIONS:
615             strPtr = &tInfo->currentContext->extensionString;
616             break;
617     }
618
619     if (!strPtr) {
620         return NULL;
621     }
622
623     if (*strPtr != NULL) {
624         //
625         // string is already cached
626         //
627         return *strPtr;
628     }
629
630     //
631     // first query of that string - need to query host
632     //
633     DEFINE_AND_VALIDATE_HOST_CONNECTION(NULL);
634     char *hostStr = NULL;
635     int n = rcEnc->rcGetGLString(rcEnc, glEnum, NULL, 0);
636     if (n < 0) {
637         hostStr = new char[-n+1];
638         n = rcEnc->rcGetGLString(rcEnc, glEnum, hostStr, -n);
639         if (n <= 0) {
640             delete [] hostStr;
641             hostStr = NULL;
642         }
643     }
644
645     //
646     // keep the string in the context and return its value
647     //
648     *strPtr = hostStr;
649     return hostStr;
650 }
651
652 // ----------------------------------------------------------------------------
653
654 static EGLClient_eglInterface s_eglIface = {
655     getThreadInfo: getEGLThreadInfo,
656     getGLString: getGLString
657 };
658
659 #define DBG_FUNC DBG("%s\n", __FUNCTION__)
660 EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id)
661 {
662     //
663     // we support only EGL_DEFAULT_DISPLAY.
664     //
665     if (display_id != EGL_DEFAULT_DISPLAY) {
666         return EGL_NO_DISPLAY;
667     }
668
669     return (EGLDisplay)&s_display;
670 }
671
672 EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
673 {
674     VALIDATE_DISPLAY(dpy,EGL_FALSE);
675
676     if (!s_display.initialize(&s_eglIface)) {
677         return EGL_FALSE;
678     }
679     if (major!=NULL)
680         *major = s_display.getVersionMajor();
681     if (minor!=NULL)
682         *minor = s_display.getVersionMinor();
683     return EGL_TRUE;
684 }
685
686 EGLBoolean eglTerminate(EGLDisplay dpy)
687 {
688     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
689
690     s_display.terminate();
691     return EGL_TRUE;
692 }
693
694 EGLint eglGetError()
695 {
696     EGLint error = getEGLThreadInfo()->eglError;
697     getEGLThreadInfo()->eglError = EGL_SUCCESS;
698     return error;
699 }
700
701 __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
702 {
703     // search in EGL function table
704     for (int i=0; i<egl_num_funcs; i++) {
705         if (!strcmp(egl_funcs_by_name[i].name, procname)) {
706             return (__eglMustCastToProperFunctionPointerType)egl_funcs_by_name[i].proc;
707         }
708     }
709
710     // look in gles client api's extensions table
711     return (__eglMustCastToProperFunctionPointerType)ClientAPIExts::getProcAddress(procname);
712
713     // Fail - function not found.
714     return NULL;
715 }
716
717 const char* eglQueryString(EGLDisplay dpy, EGLint name)
718 {
719     VALIDATE_DISPLAY_INIT(dpy, NULL);
720
721     return s_display.queryString(name);
722 }
723
724 EGLBoolean eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
725 {
726     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
727
728     if(!num_config) {
729         RETURN_ERROR(EGL_FALSE,EGL_BAD_PARAMETER);
730     }
731
732     GLint numConfigs = s_display.getNumConfigs();
733     if (!configs) {
734         *num_config = numConfigs;
735         return EGL_TRUE;
736     }
737
738     EGLint i;
739     for (i = 0 ; i < numConfigs && i < config_size ; i++) {
740         *configs++ = (EGLConfig)(uintptr_t)i;
741     }
742     *num_config = i;
743     return EGL_TRUE;
744 }
745
746 EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
747 {
748     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
749
750     if (!num_config) {
751         setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
752     }
753
754     int attribs_size = 0;
755     if (attrib_list) {
756         const EGLint * attrib_p = attrib_list;
757         while (attrib_p[0] != EGL_NONE) {
758             attribs_size += 2;
759             attrib_p += 2;
760         }
761         attribs_size++; //for the terminating EGL_NONE
762     }
763
764     // API 19 passes EGL_SWAP_BEHAVIOR_PRESERVED_BIT to surface type,
765     // while the host never supports it.
766     // We remove the bit here.
767     EGLint* local_attrib_list = NULL;
768     if (PLATFORM_SDK_VERSION <= 19) {
769         local_attrib_list = new EGLint[attribs_size];
770         memcpy(local_attrib_list, attrib_list, attribs_size * sizeof(EGLint));
771         EGLint* local_attrib_p = local_attrib_list;
772         while (local_attrib_p[0] != EGL_NONE) {
773             if (local_attrib_p[0] == EGL_SURFACE_TYPE) {
774                 local_attrib_p[1] &= ~(EGLint)EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
775             }
776             local_attrib_p += 2;
777         }
778     }
779
780     uint32_t* tempConfigs[config_size];
781     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
782     *num_config = rcEnc->rcChooseConfig(rcEnc,
783             local_attrib_list ? local_attrib_list:(EGLint*)attrib_list,
784             attribs_size * sizeof(EGLint), (uint32_t*)tempConfigs, config_size);
785
786     if (local_attrib_list) delete [] local_attrib_list;
787     if (*num_config <= 0) {
788         EGLint err = -(*num_config);
789         *num_config = 0;
790         switch (err) {
791             case EGL_BAD_ATTRIBUTE:
792                 setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_FALSE);
793             default:
794                 return EGL_FALSE;
795         }
796     }
797
798     if (configs!=NULL) {
799         EGLint i=0;
800         for (i=0;i<(*num_config);i++) {
801              *((uintptr_t*)configs+i) = *((uint32_t*)tempConfigs+i);
802         }
803     }
804
805     return EGL_TRUE;
806 }
807
808 EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
809 {
810     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
811     VALIDATE_CONFIG(config, EGL_FALSE);
812
813     if (s_display.getConfigAttrib(config, attribute, value))
814     {
815         return EGL_TRUE;
816     }
817     else
818     {
819         RETURN_ERROR(EGL_FALSE, EGL_BAD_ATTRIBUTE);
820     }
821 }
822
823 EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
824 {
825     (void)attrib_list;
826
827     VALIDATE_DISPLAY_INIT(dpy, NULL);
828     VALIDATE_CONFIG(config, EGL_FALSE);
829     if (win == 0) {
830         setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
831     }
832
833     EGLint surfaceType;
834     if (s_display.getConfigAttrib(config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)    return EGL_FALSE;
835
836     if (!(surfaceType & EGL_WINDOW_BIT)) {
837         setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
838     }
839
840     if (static_cast<ANativeWindow*>(win)->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) {
841         setErrorReturn(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
842     }
843
844     egl_surface_t* surface = egl_window_surface_t::create(
845             &s_display, config, EGL_WINDOW_BIT, static_cast<ANativeWindow*>(win));
846     if (!surface) {
847         setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE);
848     }
849
850     return surface;
851 }
852
853 EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
854 {
855     VALIDATE_DISPLAY_INIT(dpy, NULL);
856     VALIDATE_CONFIG(config, EGL_FALSE);
857
858     EGLint surfaceType;
859     if (s_display.getConfigAttrib(config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)    return EGL_FALSE;
860
861     if (!(surfaceType & EGL_PBUFFER_BIT)) {
862         setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
863     }
864
865     int32_t w = 0;
866     int32_t h = 0;
867     EGLint texFormat = EGL_NO_TEXTURE;
868     EGLint texTarget = EGL_NO_TEXTURE;
869     while (attrib_list[0] != EGL_NONE) {
870         switch (attrib_list[0]) {
871             case EGL_WIDTH:
872                 w = attrib_list[1];
873                 if (w < 0) setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
874                 break;
875             case EGL_HEIGHT:
876                 h = attrib_list[1];
877                 if (h < 0) setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
878                 break;
879             case EGL_TEXTURE_FORMAT:
880                 texFormat = attrib_list[1];
881                 break;
882             case EGL_TEXTURE_TARGET:
883                 texTarget = attrib_list[1];
884                 break;
885             // the followings are not supported
886             case EGL_LARGEST_PBUFFER:
887             case EGL_MIPMAP_TEXTURE:
888             case EGL_VG_ALPHA_FORMAT:
889             case EGL_VG_COLORSPACE:
890                 break;
891             default:
892                 setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
893         };
894         attrib_list+=2;
895     }
896     if (((texFormat == EGL_NO_TEXTURE)&&(texTarget != EGL_NO_TEXTURE)) ||
897         ((texFormat != EGL_NO_TEXTURE)&&(texTarget == EGL_NO_TEXTURE))) {
898         setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
899     }
900     // TODO: check EGL_TEXTURE_FORMAT - need to support eglBindTexImage
901
902     GLenum pixelFormat;
903     if (s_display.getConfigGLPixelFormat(config, &pixelFormat) == EGL_FALSE)
904         setErrorReturn(EGL_BAD_MATCH, EGL_NO_SURFACE);
905
906     egl_surface_t* surface = egl_pbuffer_surface_t::create(dpy, config,
907             EGL_PBUFFER_BIT, w, h, pixelFormat);
908     if (!surface) {
909         setErrorReturn(EGL_BAD_ALLOC, EGL_NO_SURFACE);
910     }
911
912     //setup attributes
913     surface->setTextureFormat(texFormat);
914     surface->setTextureTarget(texTarget);
915
916     return surface;
917 }
918
919 EGLSurface eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
920 {
921     //XXX: Pixmap not supported. The host cannot render to a pixmap resource
922     //     located on host. In order to support Pixmaps we should either punt
923     //     to s/w rendering -or- let the host render to a buffer that will be
924     //     copied back to guest at some sync point. None of those methods not
925     //     implemented and pixmaps are not used with OpenGL anyway ...
926     VALIDATE_CONFIG(config, EGL_FALSE);
927     (void)dpy;
928     (void)pixmap;
929     (void)attrib_list;
930     return EGL_NO_SURFACE;
931 }
932
933 EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
934 {
935     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
936     VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE);
937
938     egl_surface_t* surface(static_cast<egl_surface_t*>(eglSurface));
939     delete surface;
940
941     return EGL_TRUE;
942 }
943
944 static float s_getNativeDpi() {
945     float nativeDPI = 560.0f;
946     const char* dpiPropName = "qemu.sf.lcd_density";
947     char dpiProp[PROPERTY_VALUE_MAX];
948     if (property_get(dpiPropName, dpiProp, NULL) > 0) {
949         nativeDPI = atof(dpiProp);
950     }
951     return nativeDPI;
952 }
953
954 EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface eglSurface, EGLint attribute, EGLint *value)
955 {
956     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
957     VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE);
958
959     egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
960
961     // Parameters involved in queries of EGL_(HORIZONTAL|VERTICAL)_RESOLUTION
962     float currWidth, currHeight, scaledResolution, effectiveSurfaceDPI;
963     EGLBoolean ret = EGL_TRUE;
964     switch (attribute) {
965         case EGL_CONFIG_ID:
966             ret = s_display.getConfigAttrib(surface->config, EGL_CONFIG_ID, value);
967             break;
968         case EGL_WIDTH:
969             *value = surface->getWidth();
970             break;
971         case EGL_HEIGHT:
972             *value = surface->getHeight();
973             break;
974         case EGL_TEXTURE_FORMAT:
975             if (surface->getSurfaceType() & EGL_PBUFFER_BIT) {
976                 *value = surface->getTextureFormat();
977             }
978             break;
979         case EGL_TEXTURE_TARGET:
980             if (surface->getSurfaceType() & EGL_PBUFFER_BIT) {
981                 *value = surface->getTextureTarget();
982             }
983             break;
984         case EGL_SWAP_BEHAVIOR:
985         {
986             EGLint surfaceType;
987             ret = s_display.getConfigAttrib(surface->config, EGL_SURFACE_TYPE,
988                     &surfaceType);
989             if (ret == EGL_TRUE) {
990                 if (surfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) {
991                     *value = EGL_BUFFER_PRESERVED;
992                 } else {
993                     *value = EGL_BUFFER_DESTROYED;
994                 }
995             }
996             break;
997         }
998         case EGL_LARGEST_PBUFFER:
999             // not modified for a window or pixmap surface
1000             // and we ignore it when creating a PBuffer surface (default is EGL_FALSE)
1001             if (surface->getSurfaceType() & EGL_PBUFFER_BIT) *value = EGL_FALSE;
1002             break;
1003         case EGL_MIPMAP_TEXTURE:
1004             // not modified for a window or pixmap surface
1005             // and we ignore it when creating a PBuffer surface (default is 0)
1006             if (surface->getSurfaceType() & EGL_PBUFFER_BIT) *value = false;
1007             break;
1008         case EGL_MIPMAP_LEVEL:
1009             // not modified for a window or pixmap surface
1010             // and we ignore it when creating a PBuffer surface (default is 0)
1011             if (surface->getSurfaceType() & EGL_PBUFFER_BIT) *value = 0;
1012             break;
1013         case EGL_MULTISAMPLE_RESOLVE:
1014             // ignored when creating the surface, return default
1015             *value = EGL_MULTISAMPLE_RESOLVE_DEFAULT;
1016             break;
1017         case EGL_HORIZONTAL_RESOLUTION:
1018             // pixel/mm * EGL_DISPLAY_SCALING
1019             // TODO: get the DPI from avd config
1020             currWidth = surface->getWidth();
1021             scaledResolution = currWidth / surface->getNativeWidth();
1022             effectiveSurfaceDPI =
1023                 scaledResolution * s_getNativeDpi() * EGL_DISPLAY_SCALING;
1024             *value = (EGLint)(effectiveSurfaceDPI);
1025             break;
1026         case EGL_VERTICAL_RESOLUTION:
1027             // pixel/mm * EGL_DISPLAY_SCALING
1028             // TODO: get the real DPI from avd config
1029             currHeight = surface->getHeight();
1030             scaledResolution = currHeight / surface->getNativeHeight();
1031             effectiveSurfaceDPI =
1032                 scaledResolution * s_getNativeDpi() * EGL_DISPLAY_SCALING;
1033             *value = (EGLint)(effectiveSurfaceDPI);
1034             break;
1035         case EGL_PIXEL_ASPECT_RATIO:
1036             // w / h * EGL_DISPLAY_SCALING
1037             // Please don't ask why * EGL_DISPLAY_SCALING, the document says it
1038             *value = 1 * EGL_DISPLAY_SCALING;
1039             break;
1040         case EGL_RENDER_BUFFER:
1041             switch (surface->getSurfaceType()) {
1042                 case EGL_PBUFFER_BIT:
1043                     *value = EGL_BACK_BUFFER;
1044                     break;
1045                 case EGL_PIXMAP_BIT:
1046                     *value = EGL_SINGLE_BUFFER;
1047                     break;
1048                 case EGL_WINDOW_BIT:
1049                     // ignored when creating the surface, return default
1050                     *value = EGL_BACK_BUFFER;
1051                     break;
1052                 default:
1053                     ALOGE("eglQuerySurface %x unknown surface type %x",
1054                             attribute, surface->getSurfaceType());
1055                     ret = setErrorFunc(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1056                     break;
1057             }
1058             break;
1059         case EGL_VG_COLORSPACE:
1060             // ignored when creating the surface, return default
1061             *value = EGL_VG_COLORSPACE_sRGB;
1062             break;
1063         case EGL_VG_ALPHA_FORMAT:
1064             // ignored when creating the surface, return default
1065             *value = EGL_VG_ALPHA_FORMAT_NONPRE;
1066             break;
1067         //TODO: complete other attributes
1068         default:
1069             ALOGE("eglQuerySurface %x  EGL_BAD_ATTRIBUTE", attribute);
1070             ret = setErrorFunc(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1071             break;
1072     }
1073
1074     return ret;
1075 }
1076
1077 EGLBoolean eglBindAPI(EGLenum api)
1078 {
1079     if (api != EGL_OPENGL_ES_API)
1080         setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
1081     return EGL_TRUE;
1082 }
1083
1084 EGLenum eglQueryAPI()
1085 {
1086     return EGL_OPENGL_ES_API;
1087 }
1088
1089 EGLBoolean eglWaitClient()
1090 {
1091     return eglWaitGL();
1092 }
1093
1094 EGLBoolean eglReleaseThread()
1095 {
1096     EGLThreadInfo *tInfo = getEGLThreadInfo();
1097     if (tInfo) {
1098         tInfo->eglError = EGL_SUCCESS;
1099         EGLContext_t* context = tInfo->currentContext;
1100         if (context) {
1101             // The following code is doing pretty much the same thing as
1102             // eglMakeCurrent(&s_display, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE)
1103             // with the only issue that we do not require a valid display here.
1104             DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
1105             rcEnc->rcMakeCurrent(rcEnc, 0, 0, 0);
1106              if (context->version == 2) {
1107                 hostCon->gl2Encoder()->setClientState(NULL);
1108                 hostCon->gl2Encoder()->setSharedGroup(GLSharedGroupPtr());
1109             }
1110             else {
1111                 hostCon->glEncoder()->setClientState(NULL);
1112                 hostCon->glEncoder()->setSharedGroup(GLSharedGroupPtr());
1113             }
1114             context->flags &= ~EGLContext_t::IS_CURRENT;
1115
1116             if (context->deletePending) {
1117                 if (context->rcContext) {
1118                     rcEnc->rcDestroyContext(rcEnc, context->rcContext);
1119                     context->rcContext = 0;
1120                 }
1121                 delete context;
1122             }
1123             tInfo->currentContext = 0;
1124         }
1125     }
1126     return EGL_TRUE;
1127 }
1128
1129 EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
1130 {
1131     //TODO
1132     (void)dpy;
1133     (void)buftype;
1134     (void)buffer;
1135     (void)config;
1136     (void)attrib_list;
1137     ALOGW("%s not implemented", __FUNCTION__);
1138     return 0;
1139 }
1140
1141 EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
1142 {
1143     // Right now we don't do anything when using host GPU.
1144     // This is purely just to pass the data through
1145     // without issuing a warning. We may benefit from validating the
1146     // display and surface for debug purposes.
1147     // TODO: Find cases where we actually need to do something.
1148     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
1149     VALIDATE_SURFACE_RETURN(surface, EGL_FALSE);
1150     if (surface == EGL_NO_SURFACE) {
1151         setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
1152     }
1153
1154     (void)value;
1155
1156     egl_surface_t* p_surface( static_cast<egl_surface_t*>(surface) );
1157     switch (attribute) {
1158     case EGL_MIPMAP_LEVEL:
1159         return true;
1160         break;
1161     case EGL_MULTISAMPLE_RESOLVE:
1162     {
1163         if (value == EGL_MULTISAMPLE_RESOLVE_BOX) {
1164             EGLint surface_type;
1165             s_display.getConfigAttrib(p_surface->config, EGL_SURFACE_TYPE, &surface_type);
1166             if (0 == (surface_type & EGL_MULTISAMPLE_RESOLVE_BOX_BIT)) {
1167                 setErrorReturn(EGL_BAD_MATCH, EGL_FALSE);
1168             }
1169         }
1170         return true;
1171         break;
1172     }
1173     case EGL_SWAP_BEHAVIOR:
1174         if (value == EGL_BUFFER_PRESERVED) {
1175             EGLint surface_type;
1176             s_display.getConfigAttrib(p_surface->config, EGL_SURFACE_TYPE, &surface_type);
1177             if (0 == (surface_type & EGL_SWAP_BEHAVIOR_PRESERVED_BIT)) {
1178                 setErrorReturn(EGL_BAD_MATCH, EGL_FALSE);
1179             }
1180         }
1181         return true;
1182         break;
1183     default:
1184         ALOGW("%s: attr=0x%x not implemented", __FUNCTION__, attribute);
1185         setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1186     }
1187     return false;
1188 }
1189
1190 EGLBoolean eglBindTexImage(EGLDisplay dpy, EGLSurface eglSurface, EGLint buffer)
1191 {
1192     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
1193     VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE);
1194     if (eglSurface == EGL_NO_SURFACE) {
1195         setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
1196     }
1197
1198     if (buffer != EGL_BACK_BUFFER) {
1199         setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
1200     }
1201
1202     egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
1203
1204     if (surface->getTextureFormat() == EGL_NO_TEXTURE) {
1205         setErrorReturn(EGL_BAD_MATCH, EGL_FALSE);
1206     }
1207
1208     if (!(surface->getSurfaceType() & EGL_PBUFFER_BIT)) {
1209         setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
1210     }
1211
1212     //It's now safe to cast to pbuffer surface
1213     egl_pbuffer_surface_t* pbSurface = (egl_pbuffer_surface_t*)surface;
1214
1215     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
1216     rcEnc->rcBindTexture(rcEnc, pbSurface->getRcColorBuffer());
1217
1218     return GL_TRUE;
1219 }
1220
1221 EGLBoolean eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
1222 {
1223     //TODO
1224     (void)dpy;
1225     (void)surface;
1226     (void)buffer;
1227     ALOGW("%s not implemented", __FUNCTION__);
1228     return 0;
1229 }
1230
1231 EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
1232 {
1233     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
1234     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
1235
1236     EGLContext_t* ctx = getEGLThreadInfo()->currentContext;
1237     if (!ctx) {
1238         setErrorReturn(EGL_BAD_CONTEXT, EGL_FALSE);
1239     }
1240     if (!ctx->draw) {
1241         setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
1242     }
1243     egl_surface_t* draw(static_cast<egl_surface_t*>(ctx->draw));
1244     draw->setSwapInterval(interval);
1245
1246     rcEnc->rcFBSetSwapInterval(rcEnc, interval); //TODO: implement on the host
1247
1248     return EGL_TRUE;
1249 }
1250
1251 EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
1252 {
1253     VALIDATE_DISPLAY_INIT(dpy, EGL_NO_CONTEXT);
1254     VALIDATE_CONFIG(config, EGL_NO_CONTEXT);
1255
1256     EGLint version = 1; //default
1257     while (attrib_list && attrib_list[0] != EGL_NONE) {
1258         if (attrib_list[0] == EGL_CONTEXT_CLIENT_VERSION) {
1259             version = attrib_list[1];
1260         } else if (attrib_list[0] == EGL_CONTEXT_PRIORITY_LEVEL_IMG) {
1261             // https://www.khronos.org/registry/egl/extensions/IMG/EGL_IMG_context_priority.txt
1262             // It it not yet supported in the emulator.
1263             ALOGW("EGL_CONTEXT_PRIORITY_LEVEL_IMG not supported, ignored");
1264         } else { // Only the attribute EGL_CONTEXT_CLIENT_VERSION may be specified.
1265             setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
1266         }
1267         attrib_list+=2;
1268     }
1269
1270     // Currently only support GLES1 and 2
1271     if (version != 1 && version != 2) {
1272         setErrorReturn(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
1273     }
1274
1275     uint32_t rcShareCtx = 0;
1276     EGLContext_t * shareCtx = NULL;
1277     if (share_context) {
1278         shareCtx = static_cast<EGLContext_t*>(share_context);
1279         rcShareCtx = shareCtx->rcContext;
1280         if (shareCtx->dpy != dpy)
1281             setErrorReturn(EGL_BAD_MATCH, EGL_NO_CONTEXT);
1282     }
1283
1284     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_NO_CONTEXT);
1285     // We've created EGL context. Disconnecting
1286     // would be dangerous at this point.
1287     hostCon->setGrallocOnly(false);
1288
1289     uint32_t rcContext = rcEnc->rcCreateContext(rcEnc, (uintptr_t)config, rcShareCtx, version);
1290     if (!rcContext) {
1291         ALOGE("rcCreateContext returned 0");
1292         setErrorReturn(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
1293     }
1294
1295     EGLContext_t * context = new EGLContext_t(dpy, config, shareCtx);
1296     if (!context)
1297         setErrorReturn(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
1298
1299     context->version = version;
1300     context->rcContext = rcContext;
1301
1302
1303     return context;
1304 }
1305
1306 EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
1307 {
1308     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
1309     VALIDATE_CONTEXT_RETURN(ctx, EGL_FALSE);
1310
1311     EGLContext_t * context = static_cast<EGLContext_t*>(ctx);
1312
1313     if (!context) return EGL_TRUE;
1314
1315     if (getEGLThreadInfo()->currentContext == context) {
1316         getEGLThreadInfo()->currentContext->deletePending = 1;
1317         return EGL_TRUE;
1318     }
1319
1320     if (context->rcContext) {
1321         DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
1322         rcEnc->rcDestroyContext(rcEnc, context->rcContext);
1323         context->rcContext = 0;
1324     }
1325
1326     delete context;
1327     return EGL_TRUE;
1328 }
1329
1330 EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
1331 {
1332     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
1333     VALIDATE_SURFACE_RETURN(draw, EGL_FALSE);
1334     VALIDATE_SURFACE_RETURN(read, EGL_FALSE);
1335
1336     if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
1337         setErrorReturn(EGL_BAD_MATCH, EGL_FALSE);
1338     if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
1339         setErrorReturn(EGL_BAD_MATCH, EGL_FALSE);
1340
1341     EGLContext_t * context = static_cast<EGLContext_t*>(ctx);
1342     uint32_t ctxHandle = (context) ? context->rcContext : 0;
1343     egl_surface_t * drawSurf = static_cast<egl_surface_t *>(draw);
1344     uint32_t drawHandle = (drawSurf) ? drawSurf->getRcSurface() : 0;
1345     egl_surface_t * readSurf = static_cast<egl_surface_t *>(read);
1346     uint32_t readHandle = (readSurf) ? readSurf->getRcSurface() : 0;
1347
1348     //
1349     // Nothing to do if no binding change has made
1350     //
1351     EGLThreadInfo *tInfo = getEGLThreadInfo();
1352
1353     if (tInfo->currentContext == context &&
1354         (context == NULL ||
1355         (context && context->draw == draw && context->read == read))) {
1356         return EGL_TRUE;
1357     }
1358
1359     if (tInfo->currentContext && tInfo->currentContext->deletePending) {
1360         if (tInfo->currentContext != context) {
1361             EGLContext_t * contextToDelete = tInfo->currentContext;
1362             tInfo->currentContext = 0;
1363             eglDestroyContext(dpy, contextToDelete);
1364         }
1365     }
1366
1367     if (context && (context->flags & EGLContext_t::IS_CURRENT) && (context != tInfo->currentContext)) {
1368         //context is current to another thread
1369         setErrorReturn(EGL_BAD_ACCESS, EGL_FALSE);
1370     }
1371
1372     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
1373     if (rcEnc->rcMakeCurrent(rcEnc, ctxHandle, drawHandle, readHandle) == EGL_FALSE) {
1374         ALOGE("rcMakeCurrent returned EGL_FALSE");
1375         setErrorReturn(EGL_BAD_CONTEXT, EGL_FALSE);
1376     }
1377
1378     //Now make the local bind
1379     if (context) {
1380         // This is a nontrivial context.
1381         // The thread cannot be gralloc-only anymore.
1382         hostCon->setGrallocOnly(false);
1383         context->draw = draw;
1384         context->read = read;
1385         context->flags |= EGLContext_t::IS_CURRENT;
1386         //set the client state
1387         if (context->version == 2) {
1388             hostCon->gl2Encoder()->setClientStateMakeCurrent(context->getClientState());
1389             hostCon->gl2Encoder()->setSharedGroup(context->getSharedGroup());
1390         }
1391         else {
1392             hostCon->glEncoder()->setClientState(context->getClientState());
1393             hostCon->glEncoder()->setSharedGroup(context->getSharedGroup());
1394         }
1395     }
1396     else if (tInfo->currentContext) {
1397         //release ClientState & SharedGroup
1398         if (tInfo->currentContext->version == 2) {
1399             hostCon->gl2Encoder()->setClientState(NULL);
1400             hostCon->gl2Encoder()->setSharedGroup(GLSharedGroupPtr(NULL));
1401         }
1402         else {
1403             hostCon->glEncoder()->setClientState(NULL);
1404             hostCon->glEncoder()->setSharedGroup(GLSharedGroupPtr(NULL));
1405         }
1406
1407     }
1408
1409     if (tInfo->currentContext)
1410         tInfo->currentContext->flags &= ~EGLContext_t::IS_CURRENT;
1411
1412     //Now make current
1413     tInfo->currentContext = context;
1414
1415     //Check maybe we need to init the encoder, if it's first eglMakeCurrent
1416     if (tInfo->currentContext) {
1417         if (tInfo->currentContext->version == 2) {
1418             if (!hostCon->gl2Encoder()->isInitialized()) {
1419                 s_display.gles2_iface()->init();
1420                 hostCon->gl2Encoder()->setInitialized();
1421                 ClientAPIExts::initClientFuncs(s_display.gles2_iface(), 1);
1422             }
1423         }
1424         else {
1425             if (!hostCon->glEncoder()->isInitialized()) {
1426                 s_display.gles_iface()->init();
1427                 hostCon->glEncoder()->setInitialized();
1428                 ClientAPIExts::initClientFuncs(s_display.gles_iface(), 0);
1429             }
1430         }
1431     }
1432
1433     return EGL_TRUE;
1434 }
1435
1436 EGLContext eglGetCurrentContext()
1437 {
1438     return getEGLThreadInfo()->currentContext;
1439 }
1440
1441 EGLSurface eglGetCurrentSurface(EGLint readdraw)
1442 {
1443     EGLContext_t * context = getEGLThreadInfo()->currentContext;
1444     if (!context)
1445         return EGL_NO_SURFACE; //not an error
1446
1447     switch (readdraw) {
1448         case EGL_READ:
1449             return context->read;
1450         case EGL_DRAW:
1451             return context->draw;
1452         default:
1453             setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
1454     }
1455 }
1456
1457 EGLDisplay eglGetCurrentDisplay()
1458 {
1459     EGLContext_t * context = getEGLThreadInfo()->currentContext;
1460     if (!context)
1461         return EGL_NO_DISPLAY; //not an error
1462
1463     return context->dpy;
1464 }
1465
1466 EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
1467 {
1468     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
1469     VALIDATE_CONTEXT_RETURN(ctx, EGL_FALSE);
1470
1471     EGLContext_t * context = static_cast<EGLContext_t*>(ctx);
1472
1473     EGLBoolean ret = EGL_TRUE;
1474     switch (attribute) {
1475         case EGL_CONFIG_ID:
1476             ret = s_display.getConfigAttrib(context->config, EGL_CONFIG_ID, value);
1477             break;
1478         case EGL_CONTEXT_CLIENT_TYPE:
1479             *value = EGL_OPENGL_ES_API;
1480             break;
1481         case EGL_CONTEXT_CLIENT_VERSION:
1482             *value = context->version;
1483             break;
1484         case EGL_RENDER_BUFFER:
1485             if (!context->draw)
1486                 *value = EGL_NONE;
1487             else
1488                 *value = EGL_BACK_BUFFER; //single buffer not supported
1489             break;
1490         default:
1491             ALOGE("eglQueryContext %x  EGL_BAD_ATTRIBUTE", attribute);
1492             setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1493             break;
1494     }
1495
1496     return ret;
1497 }
1498
1499 EGLBoolean eglWaitGL()
1500 {
1501     EGLThreadInfo *tInfo = getEGLThreadInfo();
1502     if (!tInfo || !tInfo->currentContext) {
1503         return EGL_FALSE;
1504     }
1505
1506     if (tInfo->currentContext->version == 2) {
1507         s_display.gles2_iface()->finish();
1508     }
1509     else {
1510         s_display.gles_iface()->finish();
1511     }
1512
1513     return EGL_TRUE;
1514 }
1515
1516 EGLBoolean eglWaitNative(EGLint engine)
1517 {
1518     (void)engine;
1519     return EGL_TRUE;
1520 }
1521
1522 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface eglSurface)
1523 {
1524     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
1525     if (eglSurface == EGL_NO_SURFACE)
1526         setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
1527
1528     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
1529
1530     egl_surface_t* d = static_cast<egl_surface_t*>(eglSurface);
1531     if (d->dpy != dpy)
1532         setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE);
1533
1534     // post the surface
1535     EGLBoolean ret = d->swapBuffers();
1536
1537     hostCon->flush();
1538     return ret;
1539 }
1540
1541 EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
1542 {
1543     //TODO :later
1544     (void)dpy;
1545     (void)surface;
1546     (void)target;
1547     return 0;
1548 }
1549
1550 EGLBoolean eglLockSurfaceKHR(EGLDisplay display, EGLSurface surface, const EGLint *attrib_list)
1551 {
1552     //TODO later
1553     (void)display;
1554     (void)surface;
1555     (void)attrib_list;
1556     return 0;
1557 }
1558
1559 EGLBoolean eglUnlockSurfaceKHR(EGLDisplay display, EGLSurface surface)
1560 {
1561     //TODO later
1562     (void)display;
1563     (void)surface;
1564     return 0;
1565 }
1566
1567 EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list)
1568 {
1569     (void)attrib_list;
1570
1571     VALIDATE_DISPLAY_INIT(dpy, EGL_NO_IMAGE_KHR);
1572
1573     if (target == EGL_NATIVE_BUFFER_ANDROID) {
1574         if (ctx != EGL_NO_CONTEXT) {
1575             setErrorReturn(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
1576         }
1577
1578         android_native_buffer_t* native_buffer = (android_native_buffer_t*)buffer;
1579
1580         if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
1581             setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1582
1583         if (native_buffer->common.version != sizeof(android_native_buffer_t))
1584             setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1585
1586         cb_handle_t *cb = (cb_handle_t *)(native_buffer->handle);
1587
1588         switch (cb->format) {
1589             case HAL_PIXEL_FORMAT_RGBA_8888:
1590             case HAL_PIXEL_FORMAT_RGBX_8888:
1591             case HAL_PIXEL_FORMAT_RGB_888:
1592             case HAL_PIXEL_FORMAT_RGB_565:
1593             case HAL_PIXEL_FORMAT_YV12:
1594             case HAL_PIXEL_FORMAT_BGRA_8888:
1595                 break;
1596             default:
1597                 setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1598         }
1599
1600         native_buffer->common.incRef(&native_buffer->common);
1601
1602         EGLImage_t *image = new EGLImage_t();
1603         image->dpy = dpy;
1604         image->target = target;
1605         image->native_buffer = native_buffer;
1606
1607         return (EGLImageKHR)image;
1608     }
1609     else if (target == EGL_GL_TEXTURE_2D_KHR) {
1610         VALIDATE_CONTEXT_RETURN(ctx, EGL_NO_IMAGE_KHR);
1611
1612         EGLContext_t *context = static_cast<EGLContext_t*>(ctx);
1613         DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_NO_IMAGE_KHR);
1614
1615         uint32_t ctxHandle = (context) ? context->rcContext : 0;
1616         GLuint texture = (GLuint)reinterpret_cast<uintptr_t>(buffer);
1617         uint32_t img = rcEnc->rcCreateClientImage(rcEnc, ctxHandle, target, texture);
1618         EGLImage_t *image = new EGLImage_t();
1619         image->dpy = dpy;
1620         image->target = target;
1621         image->host_egl_image = img;
1622
1623         return (EGLImageKHR)image;
1624     }
1625     
1626     setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
1627 }
1628
1629 EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
1630 {
1631     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
1632     EGLImage_t *image = (EGLImage_t*)img;
1633
1634     if (!image || image->dpy != dpy) {
1635         RETURN_ERROR(EGL_FALSE, EGL_BAD_PARAMETER);
1636     }
1637
1638     if (image->target == EGL_NATIVE_BUFFER_ANDROID) {
1639         android_native_buffer_t* native_buffer = image->native_buffer;
1640
1641         if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
1642             setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
1643
1644         if (native_buffer->common.version != sizeof(android_native_buffer_t))
1645             setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
1646
1647         native_buffer->common.decRef(&native_buffer->common);
1648         delete image;
1649
1650         return EGL_TRUE;
1651     }
1652     else if (image->target == EGL_GL_TEXTURE_2D_KHR) {
1653         uint32_t host_egl_image = image->host_egl_image;
1654         delete image;
1655         DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
1656         return rcEnc->rcDestroyClientImage(rcEnc, host_egl_image);
1657     }
1658
1659     setErrorReturn(EGL_BAD_PARAMETER, EGL_FALSE);
1660 }
1661
1662 #define FENCE_SYNC_HANDLE (EGLSyncKHR)0xFE4CE
1663 #define MAX_EGL_SYNC_ATTRIBS 10
1664
1665 EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type,
1666         const EGLint *attrib_list)
1667 {
1668     VALIDATE_DISPLAY(dpy, EGL_NO_SYNC_KHR);
1669     DPRINT("type for eglCreateSyncKHR: 0x%x", type);
1670
1671     DEFINE_HOST_CONNECTION;
1672
1673     if ((type != EGL_SYNC_FENCE_KHR &&
1674          type != EGL_SYNC_NATIVE_FENCE_ANDROID) ||
1675         (type != EGL_SYNC_FENCE_KHR &&
1676          !rcEnc->hasNativeSync())) {
1677         setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
1678     }
1679
1680     EGLThreadInfo *tInfo = getEGLThreadInfo();
1681     if (!tInfo || !tInfo->currentContext) {
1682         setErrorReturn(EGL_BAD_MATCH, EGL_NO_SYNC_KHR);
1683     }
1684
1685     int num_actual_attribs = 0;
1686
1687     // If attrib_list is not NULL,
1688     // ensure attrib_list contains (key, value) pairs
1689     // followed by a single EGL_NONE.
1690     // Also validate attribs.
1691     int inputFenceFd = -1;
1692     if (attrib_list) {
1693         for (int i = 0; i < MAX_EGL_SYNC_ATTRIBS; i += 2) {
1694             if (attrib_list[i] == EGL_NONE) {
1695                 num_actual_attribs = i;
1696                 break;
1697             }
1698             if (i + 1 == MAX_EGL_SYNC_ATTRIBS) {
1699                 DPRINT("ERROR: attrib list without EGL_NONE");
1700                 setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
1701             }
1702         }
1703
1704         // Validate and input attribs
1705         for (int i = 0; i < num_actual_attribs; i += 2) {
1706             if (attrib_list[i] == EGL_SYNC_TYPE_KHR) {
1707                 DPRINT("ERROR: attrib key = EGL_SYNC_TYPE_KHR");
1708             }
1709             if (attrib_list[i] == EGL_SYNC_STATUS_KHR) {
1710                 DPRINT("ERROR: attrib key = EGL_SYNC_STATUS_KHR");
1711             }
1712             if (attrib_list[i] == EGL_SYNC_CONDITION_KHR) {
1713                 DPRINT("ERROR: attrib key = EGL_SYNC_CONDITION_KHR");
1714             }
1715             EGLint attrib_key = attrib_list[i];
1716             EGLint attrib_val = attrib_list[i + 1];
1717             if (attrib_key == EGL_SYNC_NATIVE_FENCE_FD_ANDROID) {
1718                 if (attrib_val != EGL_NO_NATIVE_FENCE_FD_ANDROID) {
1719                     inputFenceFd = attrib_val;
1720                 }
1721             }
1722             DPRINT("attrib: 0x%x : 0x%x", attrib_key, attrib_val);
1723         }
1724     }
1725
1726     uint64_t sync_handle = 0;
1727     int newFenceFd = -1;
1728
1729     if (rcEnc->hasNativeSync()) {
1730         sync_handle =
1731             createNativeSync(type, attrib_list, num_actual_attribs,
1732                              false /* don't destroy when signaled on the host;
1733                                       let the guest clean this up,
1734                                       because the guest called eglCreateSyncKHR. */,
1735                              inputFenceFd,
1736                              &newFenceFd);
1737
1738     } else {
1739         // Just trigger a glFinish if the native sync on host
1740         // is unavailable.
1741         eglWaitClient();
1742     }
1743
1744     EGLSync_t* syncRes = new EGLSync_t(sync_handle);
1745
1746     if (type == EGL_SYNC_NATIVE_FENCE_ANDROID) {
1747         syncRes->type = EGL_SYNC_NATIVE_FENCE_ANDROID;
1748
1749         if (inputFenceFd < 0) {
1750             syncRes->android_native_fence_fd = newFenceFd;
1751         } else {
1752             DPRINT("has input fence fd %d",
1753                     inputFenceFd);
1754             syncRes->android_native_fence_fd = inputFenceFd;
1755         }
1756     } else {
1757         syncRes->type = EGL_SYNC_FENCE_KHR;
1758         syncRes->android_native_fence_fd = -1;
1759         if (!rcEnc->hasNativeSync()) {
1760             syncRes->status = EGL_SIGNALED_KHR;
1761         }
1762     }
1763
1764     return (EGLSyncKHR)syncRes;
1765 }
1766
1767 EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR eglsync)
1768 {
1769     (void)dpy;
1770
1771     if (!eglsync) {
1772         DPRINT("WARNING: null sync object")
1773         return EGL_TRUE;
1774     }
1775
1776     EGLSync_t* sync = static_cast<EGLSync_t*>(eglsync);
1777
1778     if (sync && sync->android_native_fence_fd > 0) {
1779         close(sync->android_native_fence_fd);
1780         sync->android_native_fence_fd = -1;
1781     }
1782
1783     if (sync) {
1784         DEFINE_HOST_CONNECTION;
1785         if (rcEnc->hasNativeSync()) {
1786             rcEnc->rcDestroySyncKHR(rcEnc, sync->handle);
1787         }
1788         delete sync;
1789     }
1790
1791     return EGL_TRUE;
1792 }
1793
1794 EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR eglsync, EGLint flags,
1795         EGLTimeKHR timeout)
1796 {
1797     (void)dpy;
1798
1799     if (!eglsync) {
1800         DPRINT("WARNING: null sync object");
1801         return EGL_CONDITION_SATISFIED_KHR;
1802     }
1803
1804     EGLSync_t* sync = (EGLSync_t*)eglsync;
1805
1806     DPRINT("sync=0x%lx (handle=0x%lx) flags=0x%x timeout=0x%llx",
1807            sync, sync->handle, flags, timeout);
1808
1809     DEFINE_HOST_CONNECTION;
1810
1811     EGLint retval;
1812     if (rcEnc->hasNativeSync()) {
1813         retval = rcEnc->rcClientWaitSyncKHR
1814             (rcEnc, sync->handle, flags, timeout);
1815     } else {
1816         retval = EGL_CONDITION_SATISFIED_KHR;
1817     }
1818     EGLint res_status;
1819     switch (sync->type) {
1820         case EGL_SYNC_FENCE_KHR:
1821             res_status = EGL_SIGNALED_KHR;
1822             break;
1823         case EGL_SYNC_NATIVE_FENCE_ANDROID:
1824             res_status = EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID;
1825             break;
1826         default:
1827             res_status = EGL_SIGNALED_KHR;
1828     }
1829     sync->status = res_status;
1830     return retval;
1831 }
1832
1833 EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR eglsync,
1834         EGLint attribute, EGLint *value)
1835 {
1836     (void)dpy;
1837
1838     EGLSync_t* sync = (EGLSync_t*)eglsync;
1839
1840     switch (attribute) {
1841     case EGL_SYNC_TYPE_KHR:
1842         *value = sync->type;
1843         return EGL_TRUE;
1844     case EGL_SYNC_STATUS_KHR:
1845         *value = sync->status;
1846         return EGL_TRUE;
1847     case EGL_SYNC_CONDITION_KHR:
1848         *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
1849         return EGL_TRUE;
1850     default:
1851         setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_FALSE);
1852     }
1853 }
1854
1855 int eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR eglsync) {
1856     (void)dpy;
1857
1858     DPRINT("call");
1859
1860     EGLSync_t* sync = (EGLSync_t*)eglsync;
1861     if (sync && sync->android_native_fence_fd > 0) {
1862         int res = dup(sync->android_native_fence_fd);
1863         return res;
1864     } else {
1865         return -1;
1866     }
1867 }
1868
1869 // TODO: Implement EGL_KHR_wait_sync
1870 EGLint eglWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR eglsync, EGLint flags) {
1871     (void)dpy;
1872     (void)eglsync;
1873     (void)flags;
1874     return EGL_TRUE;
1875 }