OSDN Git Service

Pre-test native window pointer for validity
[android-x86/frameworks-native.git] / opengl / libs / EGL / eglApi.cpp
index 74d3973..c2ac564 100644 (file)
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
+#include <dlfcn.h>
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include <hardware/gralloc.h>
 #include <system/window.h>
+#include <sys/mman.h>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 
 using namespace android;
 
+// This extension has not been ratified yet, so can't be shipped.
+// Implementation is incomplete and untested.
+#define ENABLE_EGL_KHR_GL_COLORSPACE 0
+
 // ----------------------------------------------------------------------------
 
 namespace android {
@@ -58,21 +64,32 @@ struct extention_map_t {
 };
 
 /*
- * This is the list of EGL extensions exposed to applications,
- * some of them are mandatory because used by the ANDROID system.
+ * This is the list of EGL extensions exposed to applications.
+ *
+ * Some of them (gBuiltinExtensionString) are implemented entirely in this EGL
+ * wrapper and are always available.
  *
- * Mandatory extensions are required per the CDD and not explicitly
- * checked during EGL initialization. the system *assumes* these extensions
- * are present. the system may not function properly if some mandatory
- * extensions are missing.
+ * The rest (gExtensionString) depend on support in the EGL driver, and are
+ * only available if the driver supports them. However, some of these must be
+ * supported because they are used by the Android system itself; these are
+ * listd as mandatory below and are required by the CDD. The system *assumes*
+ * the mandatory extensions are present and may not function properly if some
+ * are missing.
  *
- * NOTE: gExtensionString MUST have a single space as the last character.
+ * NOTE: Both strings MUST have a single space as the last character.
  */
+extern char const * const gBuiltinExtensionString =
+        "EGL_KHR_get_all_proc_addresses "
+        "EGL_ANDROID_presentation_time "
+        ;
 extern char const * const gExtensionString  =
         "EGL_KHR_image "                        // mandatory
         "EGL_KHR_image_base "                   // mandatory
         "EGL_KHR_image_pixmap "
         "EGL_KHR_lock_surface "
+#if (ENABLE_EGL_KHR_GL_COLORSPACE != 0)
+        "EGL_KHR_gl_colorspace "
+#endif
         "EGL_KHR_gl_texture_2D_image "
         "EGL_KHR_gl_texture_cubemap_image "
         "EGL_KHR_gl_renderbuffer_image "
@@ -83,7 +100,7 @@ extern char const * const gExtensionString  =
         "EGL_NV_system_time "
         "EGL_ANDROID_image_native_buffer "      // mandatory
         "EGL_KHR_wait_sync "                    // strongly recommended
-        "EGL_ANDROID_presentation_time "
+        "EGL_ANDROID_recordable "               // mandatory
         ;
 
 // extensions not exposed to applications but used by the ANDROID system
@@ -91,8 +108,7 @@ extern char const * const gExtensionString  =
 //      "EGL_IMG_hibernate_process "            // optional
 //      "EGL_ANDROID_native_fence_sync "        // strongly recommended
 //      "EGL_ANDROID_framebuffer_target "       // mandatory for HWC 1.1
-//      "EGL_ANDROID_recordable "               // mandatory
-
+//      "EGL_ANDROID_image_crop "               // optional
 
 /*
  * EGL Extensions entry-points exposed to 3rd party applications
@@ -354,9 +370,63 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
 }
 
 // ----------------------------------------------------------------------------
+// Utility procedure to test a NativeWindowType for validity before referencing
+// through the pointer.  It's not feasible to test for deliberate forgeries,
+// but this heuristic is good enough to test for basic accidental cases, using
+// the special "magic" value placed in a native-window structure.
+// ----------------------------------------------------------------------------
+EGLBoolean isValidNativeWindow(NativeWindowType window)
+{
+    ANativeWindow *nwindow = static_cast<ANativeWindow*>(window);
+    // the msync system call returns with ENOMEM error for unmapped memory
+    // pages.  This is used here as a way to test whether we can read through a
+    // pointer without getting a segfault.
+    uintptr_t pagesize = (uintptr_t) sysconf(_SC_PAGESIZE);
+    uintptr_t addr = ((uintptr_t)(&nwindow->common.magic)) & (~(pagesize - 1));
+    int rc = msync((void *)addr, pagesize, MS_ASYNC);
+    if (0 == rc) {
+        if (nwindow->common.magic == ANDROID_NATIVE_WINDOW_MAGIC)
+            return EGL_TRUE;
+        else
+            return EGL_FALSE;
+    }
+    if (ENOMEM == errno)
+        return EGL_FALSE;
+    ALOGE("error unexpected msync error: %s (%d)",
+                            strerror(-errno), errno);
+    return EGL_FALSE;
+}
+
+
+// ----------------------------------------------------------------------------
 // surfaces
 // ----------------------------------------------------------------------------
 
+// The EGL_KHR_gl_colorspace spec hasn't been ratified yet, so these haven't
+// been added to the Khronos egl.h.
+#define EGL_GL_COLORSPACE_KHR           EGL_VG_COLORSPACE
+#define EGL_GL_COLORSPACE_SRGB_KHR      EGL_VG_COLORSPACE_sRGB
+#define EGL_GL_COLORSPACE_LINEAR_KHR    EGL_VG_COLORSPACE_LINEAR
+
+// Turn linear formats into corresponding sRGB formats when colorspace is
+// EGL_GL_COLORSPACE_SRGB_KHR, or turn sRGB formats into corresponding linear
+// formats when colorspace is EGL_GL_COLORSPACE_LINEAR_KHR. In any cases where
+// the modification isn't possible, the original format is returned.
+static int modifyFormatColorspace(int fmt, EGLint colorspace) {
+    if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) {
+        switch (fmt) {
+            case HAL_PIXEL_FORMAT_sRGB_A_8888: return HAL_PIXEL_FORMAT_RGBA_8888;
+            case HAL_PIXEL_FORMAT_sRGB_X_8888: return HAL_PIXEL_FORMAT_RGBX_8888;
+        }
+    } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) {
+        switch (fmt) {
+            case HAL_PIXEL_FORMAT_RGBA_8888: return HAL_PIXEL_FORMAT_sRGB_A_8888;
+            case HAL_PIXEL_FORMAT_RGBX_8888: return HAL_PIXEL_FORMAT_sRGB_X_8888;
+        }
+    }
+    return fmt;
+}
+
 EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
                                     NativeWindowType window,
                                     const EGLint *attrib_list)
@@ -367,27 +437,101 @@ EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
     egl_display_ptr dp = validate_display_connection(dpy, cnx);
     if (dp) {
         EGLDisplay iDpy = dp->disp.dpy;
-        EGLint format;
 
+        if (!isValidNativeWindow(window)) {
+            ALOGE("EGLNativeWindow %p invalid", window);
+            return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+        }
         if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
             ALOGE("EGLNativeWindowType %p already connected to another API",
                     window);
-            return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+            return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
         }
 
-        // set the native window's buffers format to match this config
-        if (cnx->egl.eglGetConfigAttrib(iDpy,
-                config, EGL_NATIVE_VISUAL_ID, &format)) {
-            if (format != 0) {
-                int err = native_window_set_buffers_format(window, format);
-                if (err != 0) {
-                    ALOGE("error setting native window pixel format: %s (%d)",
-                            strerror(-err), err);
-                    native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
-                    return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+        // Set the native window's buffers format to match what this config requests.
+        // Whether to use sRGB gamma is not part of the EGLconfig, but is part
+        // of our native format. So if sRGB gamma is requested, we have to
+        // modify the EGLconfig's format before setting the native window's
+        // format.
+#if WORKAROUND_BUG_10194508
+#warning "WORKAROUND_10194508 enabled"
+        EGLint format;
+        if (!cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_NATIVE_VISUAL_ID,
+                &format)) {
+            ALOGE("eglGetConfigAttrib(EGL_NATIVE_VISUAL_ID) failed: %#x",
+                    eglGetError());
+            format = 0;
+        }
+        if (attrib_list) {
+            for (const EGLint* attr = attrib_list; *attr != EGL_NONE;
+                    attr += 2) {
+                if (*attr == EGL_GL_COLORSPACE_KHR &&
+                        dp->haveExtension("EGL_KHR_gl_colorspace")) {
+                    if (ENABLE_EGL_KHR_GL_COLORSPACE) {
+                        format = modifyFormatColorspace(format, *(attr+1));
+                    } else {
+                        // Normally we'd pass through unhandled attributes to
+                        // the driver. But in case the driver implements this
+                        // extension but we're disabling it, we want to prevent
+                        // it getting through -- support will be broken without
+                        // our help.
+                        ALOGE("sRGB window surfaces not supported");
+                        return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+                    }
                 }
             }
         }
+#else
+        // by default, just pick RGBA_8888
+        EGLint format = HAL_PIXEL_FORMAT_RGBA_8888;
+
+        EGLint a = 0;
+        cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_ALPHA_SIZE, &a);
+        if (a > 0) {
+            // alpha-channel requested, there's really only one suitable format
+            format = HAL_PIXEL_FORMAT_RGBA_8888;
+        } else {
+            EGLint r, g, b;
+            r = g = b = 0;
+            cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_RED_SIZE,   &r);
+            cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_GREEN_SIZE, &g);
+            cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_BLUE_SIZE,  &b);
+            EGLint colorDepth = r + g + b;
+            if (colorDepth <= 16) {
+                format = HAL_PIXEL_FORMAT_RGB_565;
+            } else {
+                format = HAL_PIXEL_FORMAT_RGBX_8888;
+            }
+        }
+
+        // now select a corresponding sRGB format if needed
+        if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
+            for (const EGLint* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
+                if (*attr == EGL_GL_COLORSPACE_KHR) {
+                    if (ENABLE_EGL_KHR_GL_COLORSPACE) {
+                        format = modifyFormatColorspace(format, *(attr+1));
+                    } else {
+                        // Normally we'd pass through unhandled attributes to
+                        // the driver. But in case the driver implements this
+                        // extension but we're disabling it, we want to prevent
+                        // it getting through -- support will be broken without
+                        // our help.
+                        ALOGE("sRGB window surfaces not supported");
+                        return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+                    }
+                }
+            }
+        }
+#endif
+        if (format != 0) {
+            int err = native_window_set_buffers_format(window, format);
+            if (err != 0) {
+                ALOGE("error setting native window pixel format: %s (%d)",
+                        strerror(-err), err);
+                native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+                return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+            }
+        }
 
         // the EGL spec requires that a new EGLSurface default to swap interval
         // 1, so explicitly set that on the window here.
@@ -498,11 +642,6 @@ void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
         setError(EGL_BAD_SURFACE, EGL_FALSE);
         return;
     }
-
-    int64_t timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
-
-    egl_surface_t const * const s = get_surface(surface);
-    native_window_set_buffers_timestamp(s->win.get(), timestamp);
 }
 
 // ----------------------------------------------------------------------------
@@ -516,8 +655,11 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
 
     egl_connection_t* cnx = NULL;
     const egl_display_ptr dp = validate_display_connection(dpy, cnx);
-    if (dpy) {
+    if (dp) {
         if (share_list != EGL_NO_CONTEXT) {
+            if (!ContextRef(dp.get(), share_list).get()) {
+                return setError(EGL_BAD_CONTEXT, EGL_NO_CONTEXT);
+            }
             egl_context_t* const c = get_context(share_list);
             share_list = c->context;
         }
@@ -546,12 +688,6 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
                 GLTrace_eglCreateContext(version, c);
 #endif
             return c;
-        } else {
-            EGLint error = eglGetError();
-            ALOGE_IF(error == EGL_SUCCESS,
-                    "eglCreateContext(%p, %p, %p, %p) returned EGL_NO_CONTEXT "
-                    "but no EGL error!",
-                    dpy, config, share_list, attrib_list);
         }
     }
     return EGL_NO_CONTEXT;
@@ -601,7 +737,7 @@ EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
     // validate the context (if not EGL_NO_CONTEXT)
     if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
         // EGL_NO_CONTEXT is valid
-        return EGL_FALSE;
+        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
     }
 
     // these are the underlying implementation's object
@@ -622,12 +758,12 @@ EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
         impl_ctx = c->context;
     } else {
         // no context given, use the implementation of the current context
+        if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
+            // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
+            return setError(EGL_BAD_MATCH, EGL_FALSE);
+        }
         if (cur_c == NULL) {
             // no current context
-            if (draw != EGL_NO_SURFACE || read != EGL_NO_SURFACE) {
-                // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
-                return setError(EGL_BAD_MATCH, EGL_FALSE);
-            }
             // not an error, there is just no current context.
             return EGL_TRUE;
         }
@@ -635,12 +771,14 @@ EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
 
     // retrieve the underlying implementation's draw EGLSurface
     if (draw != EGL_NO_SURFACE) {
+        if (!_d.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
         d = get_surface(draw);
         impl_draw = d->surface;
     }
 
     // retrieve the underlying implementation's read EGLSurface
     if (read != EGL_NO_SURFACE) {
+        if (!_r.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
         r = get_surface(read);
         impl_read = r->surface;
     }
@@ -667,7 +805,8 @@ EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
         }
     } else {
         // this will ALOGE the error
-        result = setError(c->cnx->egl.eglGetError(), EGL_FALSE);
+        egl_connection_t* const cnx = &gEGLImpl;
+        result = setError(cnx->egl.eglGetError(), EGL_FALSE);
     }
     return result;
 }
@@ -772,6 +911,20 @@ EGLint eglGetError(void)
     return err;
 }
 
+static __eglMustCastToProperFunctionPointerType findBuiltinGLWrapper(
+        const char* procname) {
+    const egl_connection_t* cnx = &gEGLImpl;
+    void* proc = NULL;
+
+    proc = dlsym(cnx->libGles2, procname);
+    if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
+
+    proc = dlsym(cnx->libGles1, procname);
+    if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
+
+    return NULL;
+}
+
 __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
 {
     // eglGetProcAddress() could be the very first function called
@@ -793,6 +946,8 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
     addr = findProcAddress(procname, sExtensionMap, NELEM(sExtensionMap));
     if (addr) return addr;
 
+    addr = findBuiltinGLWrapper(procname);
+    if (addr) return addr;
 
     // this protects accesses to sGLExtentionMap and sGLExtentionSlot
     pthread_mutex_lock(&sExtensionMapMutex);
@@ -844,9 +999,7 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
             }
 
             if (found) {
-#if USE_FAST_TLS_KEY
                 addr = gExtensionForwarders[slot];
-#endif
                 sGLExtentionMap.add(name, addr);
                 sGLExtentionSlot++;
             }
@@ -1177,6 +1330,11 @@ EGLBoolean eglReleaseThread(void)
 {
     clearError();
 
+#if EGL_TRACE
+    if (getEGLDebugLevel() > 0)
+        GLTrace_eglReleaseThread();
+#endif
+
     // If there is context bound to the thread, release it
     egl_display_t::loseCurrent(get_context(getContext()));
 
@@ -1184,12 +1342,7 @@ EGLBoolean eglReleaseThread(void)
     if (cnx->dso && cnx->egl.eglReleaseThread) {
         cnx->egl.eglReleaseThread();
     }
-
     egl_tls_t::clearTLS();
-#if EGL_TRACE
-    if (getEGLDebugLevel() > 0)
-        GLTrace_eglReleaseThread();
-#endif
     return EGL_TRUE;
 }