OSDN Git Service

[WIP] ES 3.1 guestside changes
[android-x86/device-generic-goldfish-opengl.git] / system / egl / egl.cpp
index 9132e0e..b9aaf07 100644 (file)
@@ -21,6 +21,7 @@
 #include "eglSync.h"
 #include "egl_ftable.h"
 #include <cutils/log.h>
+#include <cutils/properties.h>
 #include "goldfish_sync.h"
 #include "gralloc_cb.h"
 #include "GLClientState.h"
@@ -35,6 +36,8 @@
 #include "GL2Encoder.h"
 #endif
 
+#include <GLES3/gl31.h>
+
 #if PLATFORM_SDK_VERSION >= 16
 #include <system/window.h>
 #else // PLATFORM_SDK_VERSION >= 16
@@ -155,7 +158,7 @@ const char *  eglStrError(EGLint err)
 // The one and only supported display object.
 static eglDisplay s_display;
 
-EGLContext_t::EGLContext_t(EGLDisplay dpy, EGLConfig config, EGLContext_t* shareCtx) :
+EGLContext_t::EGLContext_t(EGLDisplay dpy, EGLConfig config, EGLContext_t* shareCtx, int maj, int min) :
     dpy(dpy),
     config(config),
     read(EGL_NO_SURFACE),
@@ -163,6 +166,8 @@ EGLContext_t::EGLContext_t(EGLDisplay dpy, EGLConfig config, EGLContext_t* share
     shareCtx(shareCtx),
     rcContext(0),
     versionString(NULL),
+    majorVersion(maj),
+    minorVersion(min),
     vendorString(NULL),
     rendererString(NULL),
     shaderVersionString(NULL),
@@ -171,9 +176,8 @@ EGLContext_t::EGLContext_t(EGLDisplay dpy, EGLConfig config, EGLContext_t* share
     goldfishSyncFd(-1)
 {
     flags = 0;
-    version = 1;
-    clientState = new GLClientState();
-    if (shareCtx)
+    clientState = new GLClientState(majorVersion, minorVersion);
+     if (shareCtx)
         sharedGroup = shareCtx->getSharedGroup();
     else
         sharedGroup = GLSharedGroupPtr(new GLSharedGroup());
@@ -453,6 +457,11 @@ EGLBoolean egl_window_surface_t::swapBuffers()
 
     int presentFenceFd = -1;
 
+    if (buffer == NULL) {
+        ALOGE("egl_window_surface_t::swapBuffers called with NULL buffer");
+        setErrorReturn(EGL_BAD_SURFACE, EGL_FALSE);
+    }
+
 #if PLATFORM_SDK_VERSION <= 16
     rcEnc->rcFlushWindowColorBuffer(rcEnc, rcSurface);
     // equivalent to glFinish if no native sync
@@ -553,8 +562,7 @@ EGLBoolean egl_pbuffer_surface_t::init(GLenum pixelFormat)
         return EGL_FALSE;
     }
 
-    rcColorBuffer = rcEnc->rcCreateColorBuffer(rcEnc, getWidth(), getHeight(),
-            pixelFormat);
+    rcColorBuffer = rcEnc->rcCreateColorBuffer(rcEnc, getWidth(), getHeight(), pixelFormat);
     if (!rcColorBuffer) {
         ALOGE("rcCreateColorBuffer returned 0");
         return EGL_FALSE;
@@ -615,13 +623,6 @@ static const char *getGLString(int glEnum)
         return NULL;
     }
 
-    if (*strPtr != NULL) {
-        //
-        // string is already cached
-        //
-        return *strPtr;
-    }
-
     //
     // first query of that string - need to query host
     //
@@ -756,10 +757,29 @@ EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig
         attribs_size++; //for the terminating EGL_NONE
     }
 
+    // API 19 passes EGL_SWAP_BEHAVIOR_PRESERVED_BIT to surface type,
+    // while the host never supports it.
+    // We remove the bit here.
+    EGLint* local_attrib_list = NULL;
+    if (PLATFORM_SDK_VERSION <= 19) {
+        local_attrib_list = new EGLint[attribs_size];
+        memcpy(local_attrib_list, attrib_list, attribs_size * sizeof(EGLint));
+        EGLint* local_attrib_p = local_attrib_list;
+        while (local_attrib_p[0] != EGL_NONE) {
+            if (local_attrib_p[0] == EGL_SURFACE_TYPE) {
+                local_attrib_p[1] &= ~(EGLint)EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
+            }
+            local_attrib_p += 2;
+        }
+    }
+
     uint32_t* tempConfigs[config_size];
     DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
-    *num_config = rcEnc->rcChooseConfig(rcEnc, (EGLint*)attrib_list, attribs_size * sizeof(EGLint), (uint32_t*)tempConfigs, config_size);
+    *num_config = rcEnc->rcChooseConfig(rcEnc,
+            local_attrib_list ? local_attrib_list:(EGLint*)attrib_list,
+            attribs_size * sizeof(EGLint), (uint32_t*)tempConfigs, config_size);
 
+    if (local_attrib_list) delete [] local_attrib_list;
     if (*num_config <= 0) {
         EGLint err = -(*num_config);
         *num_config = 0;
@@ -792,6 +812,7 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute
     }
     else
     {
+        ALOGD("%s: bad attrib 0x%x", __FUNCTION__, attribute);
         RETURN_ERROR(EGL_FALSE, EGL_BAD_ATTRIBUTE);
     }
 }
@@ -917,6 +938,16 @@ EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
     return EGL_TRUE;
 }
 
+static float s_getNativeDpi() {
+    float nativeDPI = 560.0f;
+    const char* dpiPropName = "qemu.sf.lcd_density";
+    char dpiProp[PROPERTY_VALUE_MAX];
+    if (property_get(dpiPropName, dpiProp, NULL) > 0) {
+        nativeDPI = atof(dpiProp);
+    }
+    return nativeDPI;
+}
+
 EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface eglSurface, EGLint attribute, EGLint *value)
 {
     VALIDATE_DISPLAY_INIT(dpy, EGL_FALSE);
@@ -925,8 +956,6 @@ EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface eglSurface, EGLint attribu
     egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
 
     // Parameters involved in queries of EGL_(HORIZONTAL|VERTICAL)_RESOLUTION
-    // TODO: get the DPI from avd config
-    float fakeNativeDPI = 420.0;
     float currWidth, currHeight, scaledResolution, effectiveSurfaceDPI;
     EGLBoolean ret = EGL_TRUE;
     switch (attribute) {
@@ -988,7 +1017,7 @@ EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface eglSurface, EGLint attribu
             currWidth = surface->getWidth();
             scaledResolution = currWidth / surface->getNativeWidth();
             effectiveSurfaceDPI =
-                scaledResolution * fakeNativeDPI * EGL_DISPLAY_SCALING;
+                scaledResolution * s_getNativeDpi() * EGL_DISPLAY_SCALING;
             *value = (EGLint)(effectiveSurfaceDPI);
             break;
         case EGL_VERTICAL_RESOLUTION:
@@ -997,7 +1026,7 @@ EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface eglSurface, EGLint attribu
             currHeight = surface->getHeight();
             scaledResolution = currHeight / surface->getNativeHeight();
             effectiveSurfaceDPI =
-                scaledResolution * fakeNativeDPI * EGL_DISPLAY_SCALING;
+                scaledResolution * s_getNativeDpi() * EGL_DISPLAY_SCALING;
             *value = (EGLint)(effectiveSurfaceDPI);
             break;
         case EGL_PIXEL_ASPECT_RATIO:
@@ -1071,7 +1100,7 @@ EGLBoolean eglReleaseThread()
             // with the only issue that we do not require a valid display here.
             DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_FALSE);
             rcEnc->rcMakeCurrent(rcEnc, 0, 0, 0);
-             if (context->version == 2) {
+             if (context->majorVersion > 1) {
                 hostCon->gl2Encoder()->setClientState(NULL);
                 hostCon->gl2Encoder()->setSharedGroup(GLSharedGroupPtr());
             }
@@ -1221,18 +1250,96 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_c
     VALIDATE_DISPLAY_INIT(dpy, EGL_NO_CONTEXT);
     VALIDATE_CONFIG(config, EGL_NO_CONTEXT);
 
-    EGLint version = 1; //default
+    EGLint majorVersion = 1; //default
+    EGLint minorVersion = 0;
+    EGLint context_flags = 0;
+    EGLint profile_mask = 0;
+    EGLint reset_notification_strategy = 0;
+
+    bool wantedMajorVersion = false;
+    bool wantedMinorVersion = false;
+
     while (attrib_list && attrib_list[0] != EGL_NONE) {
-        if (attrib_list[0] == EGL_CONTEXT_CLIENT_VERSION) {
-            version = attrib_list[1];
-        } else { // Only the attribute EGL_CONTEXT_CLIENT_VERSION may be specified.
+           EGLint attrib_val = attrib_list[1];
+        switch(attrib_list[0]) {
+        case EGL_CONTEXT_MAJOR_VERSION_KHR:
+            majorVersion = attrib_val;
+            wantedMajorVersion = true;
+            break;
+        case EGL_CONTEXT_MINOR_VERSION_KHR:
+            minorVersion = attrib_val;
+            wantedMinorVersion = true;
+            break;
+        case EGL_CONTEXT_FLAGS_KHR:
+            if ((attrib_val | EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR) ||
+                (attrib_val | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR)  ||
+                (attrib_val | EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR)) {
+                context_flags = attrib_val;
+            } else {
+                RETURN_ERROR(EGL_NO_CONTEXT,EGL_BAD_ATTRIBUTE);
+            }
+            break;
+        case EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR:
+            if ((attrib_val | EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR) ||
+                (attrib_val | EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR)) {
+                profile_mask = attrib_val;
+            } else {
+                RETURN_ERROR(EGL_NO_CONTEXT,EGL_BAD_ATTRIBUTE);
+            }
+            break;
+        case EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR:
+            switch (attrib_val) {
+            case EGL_NO_RESET_NOTIFICATION_KHR:
+            case EGL_LOSE_CONTEXT_ON_RESET_KHR:
+                break;
+            default:
+                RETURN_ERROR(EGL_NO_CONTEXT,EGL_BAD_ATTRIBUTE);
+            }
+            reset_notification_strategy = attrib_val;
+            break;
+        default:
             setErrorReturn(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
         }
         attrib_list+=2;
     }
 
-    // Currently only support GLES1 and 2
-    if (version != 1 && version != 2) {
+    if (!wantedMajorVersion) {
+        majorVersion = 1;
+    }
+
+    // Support up to GLES 3.2 depending on advertised version from the host system.
+    DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_NO_CONTEXT);
+    switch (majorVersion) {
+    case 1:
+    case 2:
+        break;
+    case 3:
+        if (rcEnc->getGLESMaxVersion() < GLES_MAX_VERSION_3_0) {
+            ALOGE("%s: EGL_BAD_CONFIG: no ES 3 support", __FUNCTION__);
+            setErrorReturn(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
+        }
+        switch (minorVersion) {
+            case 0:
+                break;
+            case 1:
+                if (rcEnc->getGLESMaxVersion() < GLES_MAX_VERSION_3_1) {
+                    ALOGE("%s: EGL_BAD_CONFIG: no ES 3.1 support", __FUNCTION__);
+                    setErrorReturn(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
+                }
+                break;
+            case 2:
+                if (rcEnc->getGLESMaxVersion() < GLES_MAX_VERSION_3_2) {
+                    ALOGE("%s: EGL_BAD_CONFIG: no ES 3.2 support", __FUNCTION__);
+                    setErrorReturn(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
+                }
+                break;
+            default:
+                ALOGE("%s: EGL_BAD_CONFIG: Unknown ES version %d.%d",
+                      __FUNCTION__, majorVersion, minorVersion);
+                setErrorReturn(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
+        }
+        break;
+    default:
         setErrorReturn(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
     }
 
@@ -1245,25 +1352,31 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_c
             setErrorReturn(EGL_BAD_MATCH, EGL_NO_CONTEXT);
     }
 
-    DEFINE_AND_VALIDATE_HOST_CONNECTION(EGL_NO_CONTEXT);
     // We've created EGL context. Disconnecting
     // would be dangerous at this point.
     hostCon->setGrallocOnly(false);
 
-    uint32_t rcContext = rcEnc->rcCreateContext(rcEnc, (uintptr_t)config, rcShareCtx, version);
+    int rcMajorVersion = majorVersion;
+    if (majorVersion == 3 && minorVersion == 1) {
+        rcMajorVersion = 4;
+    }
+    if (majorVersion == 3 && minorVersion == 2) {
+        rcMajorVersion = 4;
+    }
+    uint32_t rcContext = rcEnc->rcCreateContext(rcEnc, (uintptr_t)config, rcShareCtx, rcMajorVersion);
     if (!rcContext) {
         ALOGE("rcCreateContext returned 0");
         setErrorReturn(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
     }
 
-    EGLContext_t * context = new EGLContext_t(dpy, config, shareCtx);
-    if (!context)
+    EGLContext_t * context = new EGLContext_t(dpy, config, shareCtx, majorVersion, minorVersion);
+    ALOGD("%s: %p: maj %d min %d rcv %d", __FUNCTION__, context, majorVersion, minorVersion, rcMajorVersion);
+    if (!context) {
+        ALOGE("could not alloc egl context!");
         setErrorReturn(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
+    }
 
-    context->version = version;
     context->rcContext = rcContext;
-
-
     return context;
 }
 
@@ -1341,15 +1454,66 @@ EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLC
 
     //Now make the local bind
     if (context) {
+
+        ALOGD("%s: %p: ver %d %d", __FUNCTION__, context, context->majorVersion, context->minorVersion);
         // This is a nontrivial context.
         // The thread cannot be gralloc-only anymore.
         hostCon->setGrallocOnly(false);
         context->draw = draw;
         context->read = read;
         context->flags |= EGLContext_t::IS_CURRENT;
+        GLClientState* contextState =
+            context->getClientState();
+
+        if (!hostCon->gl2Encoder()->isInitialized()) {
+            s_display.gles2_iface()->init();
+            hostCon->gl2Encoder()->setInitialized();
+            ClientAPIExts::initClientFuncs(s_display.gles2_iface(), 1);
+        }
+        if (contextState->needsInitFromCaps()) {
+            // Get caps for indexed buffers from host.
+            // Some need a current context.
+            int max_transform_feedback_separate_attribs = 0;
+            int max_uniform_buffer_bindings = 0;
+            int max_atomic_counter_buffer_bindings = 0;
+            int max_shader_storage_buffer_bindings = 0;
+            int max_vertex_attrib_bindings = 0;
+            int max_color_attachments = 1;
+            int max_draw_buffers = 1;
+            if (context->majorVersion > 2) {
+                s_display.gles2_iface()->getIntegerv(
+                        GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &max_transform_feedback_separate_attribs);
+                s_display.gles2_iface()->getIntegerv(
+                        GL_MAX_UNIFORM_BUFFER_BINDINGS, &max_uniform_buffer_bindings);
+                if (context->minorVersion > 0) {
+                    s_display.gles2_iface()->getIntegerv(
+                            GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &max_atomic_counter_buffer_bindings);
+                    s_display.gles2_iface()->getIntegerv(
+                            GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &max_shader_storage_buffer_bindings);
+                    s_display.gles2_iface()->getIntegerv(
+                            GL_MAX_VERTEX_ATTRIB_BINDINGS, &max_vertex_attrib_bindings);
+                }
+                s_display.gles2_iface()->getIntegerv(
+                        GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments);
+                s_display.gles2_iface()->getIntegerv(
+                        GL_MAX_DRAW_BUFFERS, &max_draw_buffers);
+            }
+            contextState->initFromCaps(
+                    max_transform_feedback_separate_attribs,
+                    max_uniform_buffer_bindings,
+                    max_atomic_counter_buffer_bindings,
+                    max_shader_storage_buffer_bindings,
+                    max_vertex_attrib_bindings,
+                    max_color_attachments,
+                    max_draw_buffers);
+        }
+
         //set the client state
-        if (context->version == 2) {
-            hostCon->gl2Encoder()->setClientStateMakeCurrent(context->getClientState());
+        if (context->majorVersion > 1) {
+            hostCon->gl2Encoder()->setClientStateMakeCurrent(
+                    contextState,
+                    context->majorVersion,
+                    context->minorVersion);
             hostCon->gl2Encoder()->setSharedGroup(context->getSharedGroup());
         }
         else {
@@ -1359,7 +1523,7 @@ EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLC
     }
     else if (tInfo->currentContext) {
         //release ClientState & SharedGroup
-        if (tInfo->currentContext->version == 2) {
+        if (tInfo->currentContext->majorVersion > 1) {
             hostCon->gl2Encoder()->setClientState(NULL);
             hostCon->gl2Encoder()->setSharedGroup(GLSharedGroupPtr(NULL));
         }
@@ -1378,7 +1542,7 @@ EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLC
 
     //Check maybe we need to init the encoder, if it's first eglMakeCurrent
     if (tInfo->currentContext) {
-        if (tInfo->currentContext->version == 2) {
+        if (tInfo->currentContext->majorVersion  > 1) {
             if (!hostCon->gl2Encoder()->isInitialized()) {
                 s_display.gles2_iface()->init();
                 hostCon->gl2Encoder()->setInitialized();
@@ -1443,7 +1607,7 @@ EGLBoolean eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGL
             *value = EGL_OPENGL_ES_API;
             break;
         case EGL_CONTEXT_CLIENT_VERSION:
-            *value = context->version;
+            *value = context->majorVersion;
             break;
         case EGL_RENDER_BUFFER:
             if (!context->draw)
@@ -1467,7 +1631,7 @@ EGLBoolean eglWaitGL()
         return EGL_FALSE;
     }
 
-    if (tInfo->currentContext->version == 2) {
+    if (tInfo->currentContext->majorVersion > 1) {
         s_display.gles2_iface()->finish();
     }
     else {
@@ -1496,10 +1660,10 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface eglSurface)
         setErrorReturn(EGL_BAD_DISPLAY, EGL_FALSE);
 
     // post the surface
-    d->swapBuffers();
+    EGLBoolean ret = d->swapBuffers();
 
     hostCon->flush();
-    return EGL_TRUE;
+    return ret;
 }
 
 EGLBoolean eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
@@ -1586,7 +1750,7 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EG
 
         return (EGLImageKHR)image;
     }
-    
+
     setErrorReturn(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
 }
 
@@ -1720,6 +1884,9 @@ EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type,
     } else {
         syncRes->type = EGL_SYNC_FENCE_KHR;
         syncRes->android_native_fence_fd = -1;
+        if (!rcEnc->hasNativeSync()) {
+            syncRes->status = EGL_SIGNALED_KHR;
+        }
     }
 
     return (EGLSyncKHR)syncRes;