Add HDR dataspaces to EGL

bug: 63710530
Test: adb shell /data/nativetest/EGL_test/EGL_test
Test: adb -d shell am start -n \
      com.drawelements.deqp/android.app.NativeActivity \
      -e cmdLine '"deqp --deqp-case=dEQP-EGL.functional.hdr_color.* \
      --deqp-log-filename=/sdcard/dEQP-Log.qpa"'
Change-Id: I52c43539806c901c674f037489d502d771080a30
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 94dfe6a..484e0ba 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -468,12 +468,17 @@
         return HAL_DATASPACE_V0_SCRGB;
     } else if (colorspace == EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT) {
         return HAL_DATASPACE_V0_SCRGB_LINEAR;
+    } else if (colorspace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT) {
+        return HAL_DATASPACE_BT2020_LINEAR;
+    } else if (colorspace == EGL_GL_COLORSPACE_BT2020_PQ_EXT) {
+        return HAL_DATASPACE_BT2020_PQ;
     }
     return dataSpace;
 }
 
-// Return true if we stripped any EGL_GL_COLORSPACE_KHR attributes.
-static EGLBoolean stripColorSpaceAttribute(egl_display_ptr dp, const EGLint* attrib_list,
+// Return true if we stripped any EGL_GL_COLORSPACE_KHR or HDR metadata attributes.
+// Protect devices from attributes they don't recognize that are  managed by Android
+static EGLBoolean stripAttributes(egl_display_ptr dp, const EGLint* attrib_list,
                                            EGLint format,
                                            std::vector<EGLint>& stripped_attrib_list) {
     std::vector<EGLint> allowedColorSpaces;
@@ -494,33 +499,64 @@
             break;
     }
 
+    if (!attrib_list) return false;
+
     bool stripped = false;
-    if (attrib_list && dp->haveExtension("EGL_KHR_gl_colorspace")) {
-        for (const EGLint* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) {
-            if (attr[0] == EGL_GL_COLORSPACE_KHR) {
-                EGLint colorSpace = attr[1];
-                bool found = false;
-                // Verify that color space is allowed
-                for (auto it : allowedColorSpaces) {
-                    if (colorSpace == it) {
-                        found = true;
+    for (const EGLint* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) {
+        switch (attr[0]) {
+            case EGL_GL_COLORSPACE_KHR: {
+                    EGLint colorSpace = attr[1];
+                    bool found = false;
+                    // Verify that color space is allowed
+                    for (auto it : allowedColorSpaces) {
+                        if (colorSpace == it) {
+                            found = true;
+                        }
+                    }
+                    if (found && dp->haveExtension("EGL_KHR_gl_colorspace")) {
+                        stripped = true;
+                    } else {
+                        stripped_attrib_list.push_back(attr[0]);
+                        stripped_attrib_list.push_back(attr[1]);
                     }
                 }
-                if (!found) {
+                break;
+            case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT:
+            case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT:
+            case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT:
+            case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT:
+            case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT:
+            case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT:
+            case EGL_SMPTE2086_WHITE_POINT_X_EXT:
+            case EGL_SMPTE2086_WHITE_POINT_Y_EXT:
+            case EGL_SMPTE2086_MAX_LUMINANCE_EXT:
+            case EGL_SMPTE2086_MIN_LUMINANCE_EXT:
+                if (dp->haveExtension("EGL_EXT_surface_SMPTE2086_metadata")) {
                     stripped = true;
                 } else {
                     stripped_attrib_list.push_back(attr[0]);
                     stripped_attrib_list.push_back(attr[1]);
                 }
-            } else {
+                break;
+            case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT:
+            case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT:
+                if (dp->haveExtension("EGL_EXT_surface_CTA861_3_metadata")) {
+                    stripped = true;
+                } else {
+                    stripped_attrib_list.push_back(attr[0]);
+                    stripped_attrib_list.push_back(attr[1]);
+                }
+                break;
+            default:
                 stripped_attrib_list.push_back(attr[0]);
                 stripped_attrib_list.push_back(attr[1]);
-            }
+                break;
         }
     }
+
+    // Make sure there is at least one attribute
     if (stripped) {
         stripped_attrib_list.push_back(EGL_NONE);
-        stripped_attrib_list.push_back(EGL_NONE);
     }
     return stripped;
 }
@@ -544,10 +580,10 @@
                     // is available, so no need to verify.
                     found = true;
                     verify = false;
-                } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_linear &&
+                } else if (colorSpace == EGL_GL_COLORSPACE_BT2020_LINEAR_EXT &&
                            dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_linear")) {
                     found = true;
-                } else if (colorSpace == EGL_EXT_gl_colorspace_bt2020_pq &&
+                } else if (colorSpace == EGL_GL_COLORSPACE_BT2020_PQ_EXT &&
                            dp->haveExtension("EGL_EXT_gl_colorspace_bt2020_pq")) {
                     found = true;
                 } else if (colorSpace == EGL_GL_COLORSPACE_SCRGB_EXT &&
@@ -664,10 +700,43 @@
     }
 }
 
+EGLBoolean setSurfaceMetadata(egl_surface_t* s, NativeWindowType window,
+                              const EGLint *attrib_list) {
+    // set any HDR metadata
+    bool smpte2086 = false;
+    bool cta8613 = false;
+    if (attrib_list == nullptr) return EGL_TRUE;
+
+    for (const EGLint* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) {
+        smpte2086 |= s->setSmpte2086Attribute(attr[0], attr[1]);
+        cta8613 |= s->setCta8613Attribute(attr[0], attr[1]);
+    }
+    if (smpte2086) {
+        int err = native_window_set_buffers_smpte2086_metadata(window, s->getSmpte2086Metadata());
+        if (err != 0) {
+            ALOGE("error setting native window smpte2086 metadata: %s (%d)",
+                  strerror(-err), err);
+            native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+            return EGL_FALSE;
+        }
+    }
+    if (cta8613) {
+        int err = native_window_set_buffers_cta861_3_metadata(window, s->getCta8613Metadata());
+        if (err != 0) {
+            ALOGE("error setting native window CTS 861.3 metadata: %s (%d)",
+                  strerror(-err), err);
+            native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+            return EGL_FALSE;
+        }
+    }
+    return EGL_TRUE;
+}
+
 EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
                                     NativeWindowType window,
                                     const EGLint *attrib_list)
 {
+    const EGLint *origAttribList = attrib_list;
     clearError();
 
     egl_connection_t* cnx = NULL;
@@ -705,7 +774,7 @@
         }
 
         std::vector<EGLint> strippedAttribList;
-        if (stripColorSpaceAttribute(dp, attrib_list, format, strippedAttribList)) {
+        if (stripAttributes(dp, attrib_list, format, strippedAttribList)) {
             // Had to modify the attribute list due to use of color space.
             // Use modified list from here on.
             attrib_list = strippedAttribList.data();
@@ -741,7 +810,11 @@
         if (surface != EGL_NO_SURFACE) {
             egl_surface_t* s =
                     new egl_surface_t(dp.get(), config, window, surface, colorSpace, cnx);
-            return s;
+
+            if (setSurfaceMetadata(s, window, origAttribList)) {
+                return s;
+            }
+            eglDestroySurface(dpy, s);
         }
 
         // EGLSurface creation failed
@@ -802,7 +875,7 @@
         // colorspace. We do need to filter out color spaces the
         // driver doesn't know how to process.
         std::vector<EGLint> strippedAttribList;
-        if (stripColorSpaceAttribute(dp, attrib_list, format, strippedAttribList)) {
+        if (stripAttributes(dp, attrib_list, format, strippedAttribList)) {
             // Had to modify the attribute list due to use of color space.
             // Use modified list from here on.
             attrib_list = strippedAttribList.data();
@@ -850,12 +923,14 @@
         return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
 
     egl_surface_t const * const s = get_surface(surface);
-    if (attribute == EGL_GL_COLORSPACE_KHR) {
-        *value = s->getColorSpace();
+    if (s->getColorSpaceAttribute(attribute, value)) {
+        return EGL_TRUE;
+    } else if (s->getSmpte2086Attribute(attribute, value)) {
+        return EGL_TRUE;
+    } else if (s->getCta8613Attribute(attribute, value)) {
         return EGL_TRUE;
     }
-    return s->cnx->egl.eglQuerySurface(
-            dp->disp.dpy, s->surface, attribute, value);
+    return s->cnx->egl.eglQuerySurface(dp->disp.dpy, s->surface, attribute, value);
 }
 
 void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 3c1edd1..0f36614 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -214,6 +214,23 @@
                     "EGL_EXT_gl_colorspace_display_p3_linear EGL_EXT_gl_colorspace_display_p3 ");
         }
 
+        bool hasHdrBoardConfig =
+                getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasHDRDisplay>(false);
+
+        if (hasHdrBoardConfig) {
+            // hasHDRBoardConfig indicates the system is capable of supporting HDR content.
+            // Typically that means there is an HDR capable display attached, but could be
+            // support for attaching an HDR display. In either case, advertise support for
+            // HDR color spaces.
+            mExtensionString.append(
+                    "EGL_EXT_gl_colorspace_bt2020_linear EGL_EXT_gl_colorspace_bt2020_pq ");
+        }
+
+        // Always advertise HDR metadata extensions since it's okay for an application
+        // to specify such information even though it may not be used by the system.
+        mExtensionString.append(
+                "EGL_EXT_surface_SMPTE2086_metadata EGL_EXT_surface_CTA861_3_metadata ");
+
         char const* start = gExtensionString;
         do {
             // length of the extension name
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index 72b4823..13b94b6 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -63,7 +63,9 @@
         win(win),
         cnx(cnx),
         connected(true),
-        colorSpace(colorSpace) {
+        colorSpace(colorSpace),
+        smpte2086_metadata({}),
+        cta861_3_metadata({}) {
     if (win) {
         win->incStrong(this);
     }
@@ -86,6 +88,123 @@
     }
 }
 
+EGLBoolean egl_surface_t::setSmpte2086Attribute(EGLint attribute, EGLint value) {
+    switch (attribute) {
+            break;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT:
+            smpte2086_metadata.displayPrimaryRed.x = value;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT:
+            smpte2086_metadata.displayPrimaryRed.y = value;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT:
+            smpte2086_metadata.displayPrimaryGreen.x = value;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT:
+            smpte2086_metadata.displayPrimaryGreen.y = value;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT:
+            smpte2086_metadata.displayPrimaryBlue.x = value;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT:
+            smpte2086_metadata.displayPrimaryBlue.y = value;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_WHITE_POINT_X_EXT:
+            smpte2086_metadata.whitePoint.x = value;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_WHITE_POINT_Y_EXT:
+            smpte2086_metadata.whitePoint.y = value;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_MAX_LUMINANCE_EXT:
+            smpte2086_metadata.maxLuminance = value;
+            return EGL_TRUE;
+        case EGL_SMPTE2086_MIN_LUMINANCE_EXT:
+            smpte2086_metadata.minLuminance = value;
+            return EGL_TRUE;
+    }
+    return EGL_FALSE;
+}
+
+EGLBoolean egl_surface_t::setCta8613Attribute(EGLint attribute, EGLint value) {
+    switch (attribute) {
+        case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT:
+            cta861_3_metadata.maxContentLightLevel = value;
+            return EGL_TRUE;
+        case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT:
+            cta861_3_metadata.maxFrameAverageLightLevel = value;
+            return EGL_TRUE;
+    }
+    return EGL_FALSE;
+}
+
+EGLBoolean egl_surface_t::getColorSpaceAttribute(EGLint attribute, EGLint* value) const {
+    if (attribute == EGL_GL_COLORSPACE_KHR) {
+        *value = colorSpace;
+        return EGL_TRUE;
+    }
+    return EGL_FALSE;
+}
+
+EGLBoolean egl_surface_t::getSmpte2086Attribute(EGLint attribute, EGLint *value) const {
+    switch (attribute) {
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT:
+            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryRed.x);
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT:
+            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryRed.y);
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT:
+            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryGreen.x);
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT:
+            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryGreen.y);
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT:
+            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryBlue.x);
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT:
+            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.displayPrimaryBlue.y);
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_WHITE_POINT_X_EXT:
+            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.whitePoint.x);
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_WHITE_POINT_Y_EXT:
+            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.whitePoint.y);
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_MAX_LUMINANCE_EXT:
+            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.maxLuminance);
+            return EGL_TRUE;
+            break;
+        case EGL_SMPTE2086_MIN_LUMINANCE_EXT:
+            *value = *reinterpret_cast<const int*>(&smpte2086_metadata.minLuminance);
+            return EGL_TRUE;
+            break;
+    }
+    return EGL_FALSE;
+}
+
+EGLBoolean egl_surface_t::getCta8613Attribute(EGLint attribute, EGLint *value) const {
+    switch (attribute) {
+        case EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT:
+            *value = *reinterpret_cast<const int*>(&cta861_3_metadata.maxContentLightLevel);
+            return EGL_TRUE;
+            break;
+        case EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT:
+            *value = *reinterpret_cast<const int*>(&cta861_3_metadata.maxFrameAverageLightLevel);
+            return EGL_TRUE;
+            break;
+    }
+    return EGL_FALSE;
+}
+
 void egl_surface_t::terminate() {
     disconnect();
     egl_object_t::terminate();
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 7c3075c..a9020a1 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -137,6 +137,13 @@
     ANativeWindow* getNativeWindow() { return win; }
     ANativeWindow* getNativeWindow() const { return win; }
     EGLint getColorSpace() const { return colorSpace; }
+    EGLBoolean setSmpte2086Attribute(EGLint attribute, EGLint value);
+    EGLBoolean setCta8613Attribute(EGLint attribute, EGLint value);
+    EGLBoolean getColorSpaceAttribute(EGLint attribute, EGLint* value) const;
+    EGLBoolean getSmpte2086Attribute(EGLint attribute, EGLint* value) const;
+    EGLBoolean getCta8613Attribute(EGLint attribute, EGLint* value) const;
+    const android_smpte2086_metadata* getSmpte2086Metadata() const { return &smpte2086_metadata; }
+    const android_cta861_3_metadata* getCta8613Metadata() const { return &cta861_3_metadata; }
 
     // Try to keep the order of these fields and size unchanged. It's not public API, but
     // it's not hard to imagine native games accessing them.
@@ -150,6 +157,8 @@
     bool connected;
     void disconnect();
     EGLint colorSpace;
+    android_smpte2086_metadata smpte2086_metadata;
+    android_cta861_3_metadata cta861_3_metadata;
 };
 
 class egl_context_t: public egl_object_t {