diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index e5e2dc05d..c01725db5 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -82,6 +82,7 @@ extern char const * const gExtensionString = "EGL_KHR_image_base " // mandatory "EGL_KHR_image_pixmap " "EGL_KHR_lock_surface " + "EGL_KHR_gl_colorspace " "EGL_KHR_gl_texture_2D_image " "EGL_KHR_gl_texture_cubemap_image " "EGL_KHR_gl_renderbuffer_image " @@ -365,6 +366,33 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, // surfaces // ---------------------------------------------------------------------------- +// The EGL_KHR_gl_colorspace spec hasn't been published 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_888: return HAL_PIXEL_FORMAT_RGB_888; + } + } 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_A_8888; + case HAL_PIXEL_FORMAT_BGRA_8888: return HAL_PIXEL_FORMAT_sRGB_A_8888; + case HAL_PIXEL_FORMAT_RGB_888: return HAL_PIXEL_FORMAT_sRGB_888; + } + } + return fmt; +} + EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list) @@ -375,7 +403,6 @@ 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 (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) { ALOGE("EGLNativeWindowType %p already connected to another API", @@ -383,19 +410,36 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, 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 this config. + // 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. + 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")) { + format = modifyFormatColorspace(format, *(attr+1)); } } } + 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. diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index 8d7890bad..038052198 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -44,6 +44,16 @@ extern void setGLHooksThreadSpecific(gl_hooks_t const *value); // ---------------------------------------------------------------------------- +static bool findExtension(const char* exts, const char* name, size_t nameLen) { + if (exts) { + const char* match = strstr(exts, name); + if (match && (match[nameLen] == '\0' || match[nameLen] == ' ')) { + return true; + } + } + return false; +} + egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS]; egl_display_t::egl_display_t() : @@ -196,14 +206,9 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { if (len) { // NOTE: we could avoid the copy if we had strnstr. const String8 ext(start, len); - // now look for this extension - if (disp.queryString.extensions) { - // if we find it, add this extension string to our list - // (and don't forget the space) - const char* match = strstr(disp.queryString.extensions, ext.string()); - if (match && (match[len] == ' ' || match[len] == 0)) { - mExtensionString.append(start, len+1); - } + if (findExtension(disp.queryString.extensions, ext.string(), + len)) { + mExtensionString.append(start, len+1); } } // process the next extension string, and skip the space. @@ -367,6 +372,13 @@ EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c, return result; } +bool egl_display_t::haveExtension(const char* name, size_t nameLen) const { + if (!nameLen) { + nameLen = strlen(name); + } + return findExtension(mExtensionString.string(), name, nameLen); +} + // ---------------------------------------------------------------------------- bool egl_display_t::HibernationMachine::incWakeCount(WakeRefStrength strength) { diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h index 754085ce7..87f27f800 100644 --- a/opengl/libs/EGL/egl_display.h +++ b/opengl/libs/EGL/egl_display.h @@ -99,6 +99,8 @@ public: char const * getClientApiString() const { return mClientApiString.string(); } char const * getExtensionString() const { return mExtensionString.string(); } + bool haveExtension(const char* name, size_t nameLen = 0) const; + inline uint32_t getRefsCount() const { return refs; } struct strings_t { diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index a63a80a29..531db203b 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -572,6 +572,7 @@ bool Layer::getOpacityForFormat(uint32_t format) { switch (format) { case HAL_PIXEL_FORMAT_RGBA_8888: case HAL_PIXEL_FORMAT_BGRA_8888: + case HAL_PIXEL_FORMAT_sRGB_A_8888: return false; } // in all other case, we have no blending (also for unknown formats)