Handle egl context

Added EGLContext functionality to emulator's accelerated EGL implementation.

Change-Id: Idde7d701808839f8d89c6c081a9f3216bdea7a52
diff --git a/tools/emulator/opengl/system/egl/egl.cpp b/tools/emulator/opengl/system/egl/egl.cpp
index 229536d..d186f2e 100644
--- a/tools/emulator/opengl/system/egl/egl.cpp
+++ b/tools/emulator/opengl/system/egl/egl.cpp
@@ -43,9 +43,9 @@
     }
 
 #define VALIDATE_DISPLAY_INIT(dpy,ret) \
-    VALIDATE_DISPLAY(dpy, ret) \
-    if (!s_display.initialized()) { \
-        getEGLThreadInfo()->eglError = EGL_NOT_INITIALIZED; \
+    VALIDATE_DISPLAY(dpy, ret)    \
+    if (!s_display.initialized()) {        \
+        getEGLThreadInfo()->eglError = EGL_NOT_INITIALIZED;    \
         return ret; \
     }
 
@@ -65,6 +65,43 @@
         return ret; \
     }
 
+#define VALIDATE_CONTEXT_RETURN(context,ret)        \
+    if (!context) {                                    \
+        RETURN_ERROR(ret,EGL_BAD_CONTEXT);    \
+    }
+
+#define VALIDATE_SURFACE_RETURN(surface, ret)    \
+    if (surface != EGL_NO_SURFACE) {    \
+        egl_surface_t* s( static_cast<egl_surface_t*>(surface) );    \
+        if (!s->isValid())    \
+            return setError(EGL_BAD_SURFACE, EGL_FALSE);    \
+        if (s->dpy != (EGLDisplay)&s_display)    \
+            return setError(EGL_BAD_DISPLAY, EGL_FALSE);    \
+    }
+
+
+// ----------------------------------------------------------------------------
+//EGLContext_t
+
+struct EGLContext_t {
+
+    //XXX: do we need this?
+    enum {
+        IS_CURRENT      =   0x00010000,
+        NEVER_CURRENT   =   0x00020000
+    };
+
+    EGLContext_t(EGLDisplay dpy, EGLConfig config) : dpy(dpy), config(config), read(EGL_NO_SURFACE), draw(EGL_NO_SURFACE), rcContext(0) {};
+    ~EGLContext_t(){};
+//    EGLBoolean    rcCreate();
+//    EGLBoolean    rcDestroy();
+    uint32_t            flags; //XXX: do we need this?
+    EGLDisplay          dpy;
+    EGLConfig           config;
+    EGLSurface          read;
+    EGLSurface          draw;
+    uint32_t             rcContext;
+};
 
 // ----------------------------------------------------------------------------
 //egl_surface_t
@@ -75,14 +112,13 @@
 
     EGLDisplay          dpy;
     EGLConfig           config;
-    EGLContext          ctx;
 
     egl_surface_t(EGLDisplay dpy, EGLConfig config);
     virtual     ~egl_surface_t();
-    virtual     EGLBoolean         createRc() = 0;
-    virtual     EGLBoolean         destroyRc() = 0;
-    void         setRcSurface(uint32_t handle){ rcSurface = handle; }
-    uint32_t     getRcSurface(){ return rcSurface; }
+    virtual    EGLBoolean       rcCreate() = 0;
+    virtual    EGLBoolean       rcDestroy() = 0;
+    void       setRcSurface(uint32_t handle){ rcSurface = handle; }
+    uint32_t    getRcSurface(){ return rcSurface; }
 
     virtual     EGLBoolean    isValid(){ return valid; }
     virtual     EGLint      getWidth() const = 0;
@@ -94,7 +130,7 @@
 };
 
 egl_surface_t::egl_surface_t(EGLDisplay dpy, EGLConfig config)
-    : dpy(dpy), config(config), ctx(0), valid(EGL_FALSE), rcSurface(0)
+    : dpy(dpy), config(config), valid(EGL_FALSE), rcSurface(0)
 {
 }
 
@@ -119,8 +155,8 @@
             ANativeWindow* window);
 
     ~egl_window_surface_t();
-    virtual     EGLBoolean     createRc();
-    virtual     EGLBoolean     destroyRc();
+    virtual     EGLBoolean     rcCreate();
+    virtual     EGLBoolean     rcDestroy();
 
 };
 
@@ -142,7 +178,7 @@
     nativeWindow->common.decRef(&nativeWindow->common);
 }
 
-EGLBoolean egl_window_surface_t::createRc()
+EGLBoolean egl_window_surface_t::rcCreate()
 {
     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
     uint32_t rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uint32_t)config, getWidth(), getHeight());
@@ -154,10 +190,10 @@
     return EGL_TRUE;
 }
 
-EGLBoolean egl_window_surface_t::destroyRc()
+EGLBoolean egl_window_surface_t::rcDestroy()
 {
     if (!rcSurface) {
-        LOGE("destroyRc called on invalid rcSurface");
+        LOGE("rcDestroy called on invalid rcSurface");
         return EGL_FALSE;
     }
 
@@ -185,8 +221,8 @@
             int32_t w, int32_t h, GLenum format);
 
     virtual ~egl_pbuffer_surface_t();
-    virtual     EGLBoolean     createRc();
-    virtual     EGLBoolean     destroyRc();
+    virtual     EGLBoolean     rcCreate();
+    virtual     EGLBoolean     rcDestroy();
 
     uint32_t    getRcColorBuffer(){ return rcColorBuffer; }
     void         setRcColorBuffer(uint32_t colorBuffer){ rcColorBuffer = colorBuffer; }
@@ -207,7 +243,7 @@
     rcColorBuffer = 0;
 }
 
-EGLBoolean egl_pbuffer_surface_t::createRc()
+EGLBoolean egl_pbuffer_surface_t::rcCreate()
 {
     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
     rcSurface = rcEnc->rcCreateWindowSurface(rcEnc, (uint32_t)config, getWidth(), getHeight());
@@ -225,7 +261,7 @@
     return EGL_TRUE;
 }
 
-EGLBoolean egl_pbuffer_surface_t::destroyRc()
+EGLBoolean egl_pbuffer_surface_t::rcDestroy()
 {
     if ((!rcSurface)||(!rcColorBuffer)) {
         LOGE("destroyRc called on invalid rcSurface");
@@ -398,8 +434,12 @@
 
     egl_surface_t* surface;
     surface = new egl_window_surface_t(&s_display, config, static_cast<ANativeWindow*>(win));
-    if (!surface) setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
-    if (!surface->createRc()) setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+    if (!surface)
+        return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+    if (!surface->rcCreate()) {
+        delete surface;
+        return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+    }
 
     return surface;
 }
@@ -429,8 +469,12 @@
         return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
 
     egl_surface_t* surface = new egl_pbuffer_surface_t(dpy, config, w, h, pixelFormat);
-    if (!surface) setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
-    if (!surface->createRc()) setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+    if (!surface)
+        return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+    if (!surface->rcCreate()) {
+        delete surface;
+        return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+    }
 
     return surface;
 }
@@ -448,18 +492,13 @@
 EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
 {
     VALIDATE_DISPLAY_INIT(dpy, NULL);
+    VALIDATE_SURFACE_RETURN(eglSurface, EGL_FALSE);
 
-    if (eglSurface != EGL_NO_SURFACE)
-    {
-        egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
-        if (!surface->isValid())
-            return setError(EGL_BAD_SURFACE, EGL_FALSE);
-        if (surface->dpy != dpy)
-            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
+    egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
 
-        surface->destroyRc();
-        delete surface;
-    }
+    surface->rcDestroy();
+    delete surface;
+
     return EGL_TRUE;
 }
 
@@ -471,14 +510,14 @@
 
 EGLBoolean eglBindAPI(EGLenum api)
 {
-    //TODO
-    return 0;
+    if (api != EGL_OPENGL_ES_API)
+        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
+    return EGL_TRUE;
 }
 
 EGLenum eglQueryAPI()
 {
-    //TODO
-    return 0;
+    return EGL_OPENGL_ES_API;
 }
 
 EGLBoolean eglWaitClient()
@@ -525,38 +564,123 @@
 
 EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
 {
-    //TODO
-    return 0;
+    VALIDATE_DISPLAY_INIT(dpy, EGL_NO_CONTEXT);
+    VALIDATE_CONFIG(config, EGL_NO_CONTEXT);
+
+
+    EGLint version = 1; //default
+    while (attrib_list[0]) {
+        if (attrib_list[0] == EGL_CONTEXT_CLIENT_VERSION) version = attrib_list[1];
+        attrib_list+=2;
+    }
+
+    uint32_t rcShareCtx = 0;
+    if (share_context) {
+        EGLContext_t * shareCtx = static_cast<EGLContext_t*>(share_context);
+        rcShareCtx = shareCtx->rcContext;
+        if (shareCtx->dpy != dpy)
+            return setError(EGL_BAD_MATCH, EGL_NO_CONTEXT);
+    }
+
+    DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_NO_CONTEXT);
+    uint32_t rcContext = rcEnc->rcCreateContext(rcEnc, (uint32_t)config, rcShareCtx, version);
+    if (!rcContext) {
+        LOGE("rcCreateContext returned 0");
+        return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
+    }
+
+    EGLContext_t * context = new EGLContext_t(dpy, config);
+    if (!context)
+        return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
+
+    context->rcContext = rcContext;
+
+
+    return context;
 }
 
 EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
 {
-    //TODO
-    return 0;
+    VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
+    VALIDATE_CONTEXT_RETURN(ctx, EGL_FALSE);
+
+    EGLContext_t * context = static_cast<EGLContext_t*>(ctx);
+    if (context->rcContext) {
+        DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
+        rcEnc->rcDestroyContext(rcEnc, context->rcContext);
+        context->rcContext = 0;
+    }
+
+    if (getEGLThreadInfo()->currentContext == context)
+        getEGLThreadInfo()->currentContext = NULL;
+
+    delete context;
+    return EGL_TRUE;
 }
 
 EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
 {
-    //TODO
-    return 0;
+    VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
+    VALIDATE_SURFACE_RETURN(draw, EGL_FALSE);
+    VALIDATE_SURFACE_RETURN(read, EGL_FALSE);
+
+    if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
+        return setError(EGL_BAD_MATCH, EGL_FALSE);
+    if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
+        return setError(EGL_BAD_MATCH, EGL_FALSE);
+
+    EGLContext_t * context = static_cast<EGLContext_t*>(ctx);
+    uint32_t ctxHandle = (context) ? context->rcContext : 0;
+    egl_surface_t * drawSurf = static_cast<egl_surface_t *>(draw);
+    uint32_t drawHandle = (drawSurf) ? drawSurf->getRcSurface() : 0;
+    egl_surface_t * readSurf = static_cast<egl_surface_t *>(read);
+    uint32_t readHandle = (readSurf) ? readSurf->getRcSurface() : 0;
+
+    DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
+    if (rcEnc->rcMakeCurrent(rcEnc, ctxHandle, drawHandle, readHandle) == EGL_FALSE) {
+        LOGE("rcMakeCurrent returned EGL_FALSE");
+        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
+    }
+
+    //Now make the local bind
+    if (context) {
+        context->draw = draw;
+        context->read = read;
+    }
+    //Now make current
+    getEGLThreadInfo()->currentContext = context;
+
+    return EGL_TRUE;
 }
 
 EGLContext eglGetCurrentContext()
 {
-    //TODO
-    return 0;
+    return getEGLThreadInfo()->currentContext;
 }
 
 EGLSurface eglGetCurrentSurface(EGLint readdraw)
 {
-    //TODO
-    return 0;
+    EGLContext_t * context = getEGLThreadInfo()->currentContext;
+    if (!context)
+        return EGL_NO_SURFACE; //not an error
+
+    switch (readdraw) {
+        case EGL_READ:
+            return context->read;
+        case EGL_DRAW:
+            return context->draw;
+        default:
+            return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+    }
 }
 
 EGLDisplay eglGetCurrentDisplay()
 {
-    //TODO
-    return 0;
+    EGLContext_t * context = getEGLThreadInfo()->currentContext;
+    if (!context)
+        return EGL_NO_DISPLAY; //not an error
+
+    return context->dpy;
 }
 
 EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)