Merge "Fix vr_hwc crash when re-entering vr" into pi-dev
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 8e393c0..ff22048 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -503,7 +503,7 @@
     using namespace ::android::hidl::manager::V1_0;
     using namespace ::android::hidl::base::V1_0;
     using std::literals::chrono_literals::operator""s;
-    auto ret = timeoutIPC(2s, manager, &IServiceManager::debugDump, [&] (const auto &infos) {
+    auto ret = timeoutIPC(10s, manager, &IServiceManager::debugDump, [&] (const auto &infos) {
         std::map<std::string, TableEntry> entries;
         for (const auto &info : infos) {
             std::string interfaceName = std::string{info.interfaceName.c_str()} + "/" +
diff --git a/opengl/include/GLES2/gl2ext.h b/opengl/include/GLES2/gl2ext.h
index 3ad39d9..e8d7515 100644
--- a/opengl/include/GLES2/gl2ext.h
+++ b/opengl/include/GLES2/gl2ext.h
@@ -3612,17 +3612,6 @@
 #define GL_SHADER_BINARY_VIV              0x8FC4
 #endif /* GL_VIV_shader_binary */
 
-/* Temporary hack to allow frameworks/base/libs/hwui/debug to build.
- * This function was removed from the Khronos version of the headers
- * (it is specified with the EXT prefix, not OES). */
-#ifndef GL_ANDROID_draw_elements_base_vertex_backwards_compatibility
-#define GL_ANDROID_draw_elements_base_vertex_backwards_compatibility 1
-typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSBASEVERTEXOESPROC) (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glMultiDrawElementsBaseVertexOES (GLenum mode, const GLsizei *count, GLenum type, const void *const*indices, GLsizei primcount, const GLint *basevertex);
-#endif
-#endif /* GL_ANDROID_draw_elements_base_vertex_backwards_compatibility */
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 58a774b..d90ab1d 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -55,6 +55,7 @@
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
 using android::ui::ColorMode;
+using android::ui::RenderIntent;
 
 /*
  * Initialize the display to the specified values.
@@ -75,8 +76,8 @@
         std::unique_ptr<RE::Surface> renderSurface,
         int displayWidth,
         int displayHeight,
-        bool supportWideColor,
-        bool supportHdr,
+        bool hasWideColorGamut,
+        bool hasHdr10,
         int initialPowerMode)
     : lastCompositionHadVisibleLayers(false),
       mFlinger(flinger),
@@ -98,8 +99,8 @@
       mActiveConfig(0),
       mActiveColorMode(ColorMode::NATIVE),
       mColorTransform(HAL_COLOR_TRANSFORM_IDENTITY),
-      mDisplayHasWideColor(supportWideColor),
-      mDisplayHasHdr(supportHdr)
+      mHasWideColorGamut(hasWideColorGamut),
+      mHasHdr10(hasHdr10)
 {
     // clang-format on
 
@@ -268,6 +269,14 @@
     return mActiveColorMode;
 }
 
+RenderIntent DisplayDevice::getActiveRenderIntent() const {
+    return mActiveRenderIntent;
+}
+
+void DisplayDevice::setActiveRenderIntent(RenderIntent renderIntent) {
+    mActiveRenderIntent = renderIntent;
+}
+
 void DisplayDevice::setColorTransform(const mat4& transform) {
     const bool isIdentity = (transform == mat4());
     mColorTransform =
@@ -279,10 +288,15 @@
 }
 
 void DisplayDevice::setCompositionDataSpace(ui::Dataspace dataspace) {
+    mCompositionDataSpace = dataspace;
     ANativeWindow* const window = mNativeWindow.get();
     native_window_set_buffers_data_space(window, static_cast<android_dataspace>(dataspace));
 }
 
+ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
+    return mCompositionDataSpace;
+}
+
 // ----------------------------------------------------------------------------
 
 void DisplayDevice::setLayerStack(uint32_t stack) {
@@ -464,8 +478,8 @@
                         tr[0][1], tr[1][1], tr[2][1], tr[0][2], tr[1][2], tr[2][2]);
     auto const surface = static_cast<Surface*>(window);
     ui::Dataspace dataspace = surface->getBuffersDataSpace();
-    result.appendFormat("   wideColor=%d, hdr=%d, colorMode=%s, dataspace: %s (%d)\n",
-                        mDisplayHasWideColor, mDisplayHasHdr,
+    result.appendFormat("   wideColorGamut=%d, hdr10=%d, colorMode=%s, dataspace: %s (%d)\n",
+                        mHasWideColorGamut, mHasHdr10,
                         decodeColorMode(mActiveColorMode).c_str(),
                         dataspaceDetails(static_cast<android_dataspace>(dataspace)).c_str(), dataspace);
 
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e844d11..bedf765 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -84,8 +84,8 @@
             std::unique_ptr<RE::Surface> renderSurface,
             int displayWidth,
             int displayHeight,
-            bool supportWideColor,
-            bool supportHdr,
+            bool hasWideColorGamut,
+            bool hasHdr10,
             int initialPowerMode);
     // clang-format on
 
@@ -135,8 +135,8 @@
     // machine happy without actually queueing a buffer if nothing has changed
     status_t beginFrame(bool mustRecompose) const;
     status_t prepareFrame(HWComposer& hwc);
-    bool getWideColorSupport() const { return mDisplayHasWideColor; }
-    bool getHdrSupport() const { return mDisplayHasHdr; }
+    bool hasWideColorGamut() const { return mHasWideColorGamut; }
+    bool hasHdr10() const { return mHasHdr10; }
 
     void swapBuffers(HWComposer& hwc) const;
 
@@ -165,9 +165,12 @@
 
     ui::ColorMode getActiveColorMode() const;
     void setActiveColorMode(ui::ColorMode mode);
+    ui::RenderIntent getActiveRenderIntent() const;
+    void setActiveRenderIntent(ui::RenderIntent renderIntent);
     android_color_transform_t getColorTransform() const;
     void setColorTransform(const mat4& transform);
     void setCompositionDataSpace(ui::Dataspace dataspace);
+    ui::Dataspace getCompositionDataSpace() const;
 
     /* ------------------------------------------------------------------------
      * Display active config management.
@@ -241,14 +244,17 @@
     int mActiveConfig;
     // current active color mode
     ui::ColorMode mActiveColorMode;
+    // Current active render intent.
+    ui::RenderIntent mActiveRenderIntent;
+    ui::Dataspace mCompositionDataSpace;
     // Current color transform
     android_color_transform_t mColorTransform;
 
     // Need to know if display is wide-color capable or not.
     // Initialized by SurfaceFlinger when the DisplayDevice is created.
     // Fed to RenderEngine during composition.
-    bool mDisplayHasWideColor;
-    bool mDisplayHasHdr;
+    bool mHasWideColorGamut;
+    bool mHasHdr10;
 };
 
 struct DisplayDeviceState {
@@ -290,9 +296,9 @@
     bool isSecure() const override { return mDevice->isSecure(); }
     bool needsFiltering() const override { return mDevice->needsFiltering(); }
     Rect getSourceCrop() const override { return mSourceCrop; }
-    bool getWideColorSupport() const override { return mDevice->getWideColorSupport(); }
-    ui::ColorMode getActiveColorMode() const override {
-        return mDevice->getActiveColorMode();
+    bool getWideColorSupport() const override { return mDevice->hasWideColorGamut(); }
+    ui::Dataspace getDataSpace() const override {
+        return mDevice->getCompositionDataSpace();
     }
 
 private:
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 9d356d8..8c0050e 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1643,6 +1643,21 @@
     return true;
 }
 
+// Dataspace::UNKNOWN, Dataspace::SRGB, Dataspace::SRGB_LINEAR,
+// Dataspace::V0_SRGB and Dataspace::V0_SRGB_LINEAR are considered legacy
+// SRGB data space for now.
+// Note that Dataspace::V0_SRGB and Dataspace::V0_SRGB_LINEAR are not legacy
+// data space, however since framework doesn't distinguish them out of legacy
+// SRGB, we have to treat them as the same for now.
+bool Layer::isLegacySrgbDataSpace() const {
+    // TODO(lpy) b/77652630, need to figure out when UNKNOWN can be treated as SRGB.
+    return mDrawingState.dataSpace == ui::Dataspace::UNKNOWN ||
+        mDrawingState.dataSpace == ui::Dataspace::SRGB ||
+        mDrawingState.dataSpace == ui::Dataspace::SRGB_LINEAR ||
+        mDrawingState.dataSpace == ui::Dataspace::V0_SRGB ||
+        mDrawingState.dataSpace == ui::Dataspace::V0_SRGB_LINEAR;
+}
+
 void Layer::setParent(const sp<Layer>& layer) {
     mCurrentParent = layer;
 }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8d2a048..d382a1a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -297,6 +297,13 @@
     bool reparent(const sp<IBinder>& newParentHandle);
     bool detachChildren();
 
+    // Before color management is introduced, contents on Android have to be
+    // desaturated in order to match what they appears like visually.
+    // With color management, these contents will appear desaturated, thus
+    // needed to be saturated so that they match what they are designed for
+    // visually. When returns true, legacy SRGB data space is passed to HWC.
+    bool isLegacySrgbDataSpace() const;
+
     // If we have received a new buffer this frame, we will pass its surface
     // damage down to hardware composer. Otherwise, we must send a region with
     // one empty rect.
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index bf0707f..4f812fc 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -25,15 +25,14 @@
     virtual bool isSecure() const = 0;
     virtual bool needsFiltering() const = 0;
     virtual Rect getSourceCrop() const = 0;
+    virtual bool getWideColorSupport() const = 0;
+    virtual ui::Dataspace getDataSpace() const = 0;
 
     virtual void render(std::function<void()> drawLayers) { drawLayers(); }
 
     int getReqHeight() const { return mReqHeight; };
     int getReqWidth() const { return mReqWidth; };
     Transform::orientation_flags getRotationFlags() const { return mRotationFlags; };
-    virtual bool getWideColorSupport() const = 0;
-    virtual ui::ColorMode getActiveColorMode() const = 0;
-
     status_t updateDimensions();
 
 private:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 183c1eb..a8680e2 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -157,6 +157,31 @@
     return std::string(value) == "true";
 }
 
+DisplayColorSetting toDisplayColorSetting(int value) {
+    switch(value) {
+        case 0:
+            return DisplayColorSetting::MANAGED;
+        case 1:
+            return DisplayColorSetting::UNMANAGED;
+        case 2:
+            return DisplayColorSetting::ENHANCED;
+        default:
+            return DisplayColorSetting::MANAGED;
+    }
+}
+
+std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) {
+    switch(displayColorSetting) {
+        case DisplayColorSetting::MANAGED:
+            return std::string("Natural Mode");
+        case DisplayColorSetting::UNMANAGED:
+            return std::string("Saturated Mode");
+        case DisplayColorSetting::ENHANCED:
+            return std::string("Auto Color Mode");
+    }
+    return std::string("Unknown Display Color Setting");
+}
+
 NativeWindowSurface::~NativeWindowSurface() = default;
 
 namespace impl {
@@ -690,6 +715,9 @@
         ALOGE("Run StartPropertySetThread failed!");
     }
 
+    mLegacySrgbSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(HWC_DISPLAY_PRIMARY,
+            Dataspace::SRGB_LINEAR);
+
     ALOGV("Done initializing");
 }
 
@@ -697,14 +725,13 @@
     char value[PROPERTY_VALUE_MAX];
 
     property_get("persist.sys.sf.color_saturation", value, "1.0");
-    mSaturation = atof(value);
-    ALOGV("Saturation is set to %.2f", mSaturation);
+    mGlobalSaturationFactor = atof(value);
+    ALOGV("Saturation is set to %.2f", mGlobalSaturationFactor);
 
     property_get("persist.sys.sf.native_mode", value, "0");
-    mForceNativeColorMode = atoi(value) == 1;
-    if (mForceNativeColorMode) {
-        ALOGV("Forcing native color mode");
-    }
+    mDisplayColorSetting = toDisplayColorSetting(atoi(value));
+    ALOGV("Display Color Setting is set to %s.",
+          decodeDisplayColorSetting(mDisplayColorSetting).c_str());
 }
 
 void SurfaceFlinger::startBootAnim() {
@@ -989,11 +1016,29 @@
 }
 
 void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw,
-        ColorMode mode) {
+                                                ColorMode mode, Dataspace dataSpace) {
     int32_t type = hw->getDisplayType();
     ColorMode currentMode = hw->getActiveColorMode();
+    Dataspace currentDataSpace = hw->getCompositionDataSpace();
+    RenderIntent currentRenderIntent = hw->getActiveRenderIntent();
 
-    if (mode == currentMode) {
+    // Natural Mode means it's color managed and the color must be right,
+    // thus we pick RenderIntent::COLORIMETRIC as render intent.
+    // Native Mode means the display is not color managed, and whichever
+    // render intent is picked doesn't matter, thus return
+    // RenderIntent::COLORIMETRIC as default here.
+    RenderIntent renderIntent = RenderIntent::COLORIMETRIC;
+
+    // In Auto Color Mode, we want to strech to panel color space, right now
+    // only the built-in display supports it.
+    if (mDisplayColorSetting == DisplayColorSetting::ENHANCED &&
+        mBuiltinDisplaySupportsEnhance &&
+        hw->getDisplayType() == DisplayDevice::DISPLAY_PRIMARY) {
+        renderIntent = RenderIntent::ENHANCE;
+    }
+
+    if (mode == currentMode && dataSpace == currentDataSpace &&
+        renderIntent == currentRenderIntent) {
         return;
     }
 
@@ -1002,11 +1047,15 @@
         return;
     }
 
-    ALOGD("Set active color mode: %s (%d), type=%d", decodeColorMode(mode).c_str(), mode,
-          hw->getDisplayType());
-
     hw->setActiveColorMode(mode);
-    getHwComposer().setActiveColorMode(type, mode, RenderIntent::COLORIMETRIC);
+    hw->setCompositionDataSpace(dataSpace);
+    hw->setActiveRenderIntent(renderIntent);
+    getHwComposer().setActiveColorMode(type, mode, renderIntent);
+
+    ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), type=%d",
+          decodeColorMode(mode).c_str(), mode,
+          decodeRenderIntent(renderIntent).c_str(), renderIntent,
+          hw->getDisplayType());
 }
 
 
@@ -1037,7 +1086,7 @@
                 ALOGW("Attempt to set active color mode %s %d for virtual display",
                       decodeColorMode(mMode).c_str(), mMode);
             } else {
-                mFlinger.setActiveColorModeInternal(hw, mMode);
+                mFlinger.setActiveColorModeInternal(hw, mMode, Dataspace::UNKNOWN);
             }
             return true;
         }
@@ -1072,7 +1121,7 @@
     std::unique_ptr<HdrCapabilities> capabilities =
             getBE().mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId());
     if (capabilities) {
-        if (displayDevice->getWideColorSupport() && !displayDevice->getHdrSupport()) {
+        if (displayDevice->hasWideColorGamut() && !displayDevice->hasHdr10()) {
             // insert HDR10 as we will force client composition for HDR10
             // layers
             std::vector<int32_t> types = capabilities->getSupportedHdrTypes();
@@ -1821,73 +1870,78 @@
 }
 
 mat4 SurfaceFlinger::computeSaturationMatrix() const {
-    if (mSaturation == 1.0f) {
+    if (mGlobalSaturationFactor == 1.0f) {
         return mat4();
     }
 
     // Rec.709 luma coefficients
     float3 luminance{0.213f, 0.715f, 0.072f};
-    luminance *= 1.0f - mSaturation;
+    luminance *= 1.0f - mGlobalSaturationFactor;
     return mat4(
-        vec4{luminance.r + mSaturation, luminance.r, luminance.r, 0.0f},
-        vec4{luminance.g, luminance.g + mSaturation, luminance.g, 0.0f},
-        vec4{luminance.b, luminance.b, luminance.b + mSaturation, 0.0f},
+        vec4{luminance.r + mGlobalSaturationFactor, luminance.r, luminance.r, 0.0f},
+        vec4{luminance.g, luminance.g + mGlobalSaturationFactor, luminance.g, 0.0f},
+        vec4{luminance.b, luminance.b, luminance.b + mGlobalSaturationFactor, 0.0f},
         vec4{0.0f, 0.0f, 0.0f, 1.0f}
     );
 }
 
-// pickColorMode translates a given dataspace into the best available color mode.
-// Currently only support sRGB and Display-P3.
-ColorMode SurfaceFlinger::pickColorMode(Dataspace dataSpace) const {
-    if (mForceNativeColorMode) {
-        return ColorMode::NATIVE;
+// Returns a dataspace that fits all visible layers.  The returned dataspace
+// can only be one of
+//
+//  - Dataspace::V0_SRGB
+//  - Dataspace::DISPLAY_P3
+//  - Dataspace::V0_SCRGB_LINEAR
+// TODO(b/73825729) Add BT2020 data space.
+ui::Dataspace SurfaceFlinger::getBestDataspace(
+        const sp<const DisplayDevice>& displayDevice) const {
+    Dataspace bestDataspace = Dataspace::V0_SRGB;
+    for (const auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+        switch (layer->getDataSpace()) {
+            case Dataspace::V0_SCRGB:
+            case Dataspace::V0_SCRGB_LINEAR:
+                // return immediately
+                return Dataspace::V0_SCRGB_LINEAR;
+            case Dataspace::BT2020_PQ:
+            case Dataspace::BT2020_ITU_PQ:
+                // Historically, HDR dataspaces are ignored by SurfaceFlinger. But
+                // since SurfaceFlinger simulates HDR support now, it should honor
+                // them unless there is also native support.
+                if (!displayDevice->hasHdr10()) {
+                    return Dataspace::V0_SCRGB_LINEAR;
+                }
+                break;
+            case Dataspace::DISPLAY_P3:
+                bestDataspace = Dataspace::DISPLAY_P3;
+                break;
+            default:
+                break;
+        }
     }
 
-    switch (dataSpace) {
-        // treat Unknown as regular SRGB buffer, since that's what the rest of the
-        // system expects.
-        case Dataspace::UNKNOWN:
-        case Dataspace::SRGB:
-        case Dataspace::V0_SRGB:
-            return ColorMode::SRGB;
-            break;
-
-        case Dataspace::DISPLAY_P3:
-            return ColorMode::DISPLAY_P3;
-            break;
-
-        default:
-            // TODO (courtneygo): Do we want to assert an error here?
-            ALOGE("No color mode mapping for %s (%#x)",
-                  dataspaceDetails(static_cast<android_dataspace>(dataSpace)).c_str(),
-                  dataSpace);
-            return ColorMode::SRGB;
-            break;
-    }
+    return bestDataspace;
 }
 
-Dataspace SurfaceFlinger::bestTargetDataSpace(
-        Dataspace a, Dataspace b, bool hasHdr) const {
-    // Only support sRGB and Display-P3 right now.
-    if (a == Dataspace::DISPLAY_P3 || b == Dataspace::DISPLAY_P3) {
-        return Dataspace::DISPLAY_P3;
-    }
-    if (a == Dataspace::V0_SCRGB_LINEAR || b == Dataspace::V0_SCRGB_LINEAR) {
-        return Dataspace::DISPLAY_P3;
-    }
-    if (a == Dataspace::V0_SCRGB || b == Dataspace::V0_SCRGB) {
-        return Dataspace::DISPLAY_P3;
-    }
-    if (!hasHdr) {
-        if (a == Dataspace::BT2020_PQ || b == Dataspace::BT2020_PQ) {
-            return Dataspace::DISPLAY_P3;
-        }
-        if (a == Dataspace::BT2020_ITU_PQ || b == Dataspace::BT2020_ITU_PQ) {
-            return Dataspace::DISPLAY_P3;
-        }
+// Pick the ColorMode / Dataspace for the display device.
+// TODO(b/73825729) Add BT2020 color mode.
+void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice,
+        ColorMode* outMode, Dataspace* outDataSpace) const {
+    if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) {
+        *outMode = ColorMode::NATIVE;
+        *outDataSpace = Dataspace::UNKNOWN;
+        return;
     }
 
-    return Dataspace::V0_SRGB;
+    switch (getBestDataspace(displayDevice)) {
+        case Dataspace::DISPLAY_P3:
+        case Dataspace::V0_SCRGB_LINEAR:
+            *outMode = ColorMode::DISPLAY_P3;
+            *outDataSpace = Dataspace::DISPLAY_P3;
+            break;
+        default:
+            *outMode = ColorMode::SRGB;
+            *outDataSpace = Dataspace::V0_SRGB;
+            break;
+    }
 }
 
 void SurfaceFlinger::setUpHWComposer() {
@@ -1970,7 +2024,7 @@
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
             if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
                  layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
-                    !displayDevice->getHdrSupport()) {
+                    !displayDevice->hasHdr10()) {
                 layer->forceClientComposition(hwcId);
             }
 
@@ -1984,19 +2038,10 @@
         }
 
         if (hasWideColorDisplay) {
-            ColorMode newColorMode;
-            Dataspace newDataSpace = Dataspace::V0_SRGB;
-
-            for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-                newDataSpace = bestTargetDataSpace(layer->getDataSpace(), newDataSpace,
-                        displayDevice->getHdrSupport());
-                ALOGV("layer: %s, dataspace: %s (%#x), newDataSpace: %s (%#x)",
-                      layer->getName().string(), dataspaceDetails(static_cast<android_dataspace>(layer->getDataSpace())).c_str(),
-                      layer->getDataSpace(), dataspaceDetails(static_cast<android_dataspace>(newDataSpace)).c_str(), newDataSpace);
-            }
-            newColorMode = pickColorMode(newDataSpace);
-
-            setActiveColorModeInternal(displayDevice, newColorMode);
+            ColorMode colorMode;
+            Dataspace dataSpace;
+            pickColorMode(displayDevice, &colorMode, &dataSpace);
+            setActiveColorModeInternal(displayDevice, colorMode, dataSpace);
         }
     }
 
@@ -2204,29 +2249,40 @@
 sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
         const wp<IBinder>& display, int hwcId, const DisplayDeviceState& state,
         const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) {
-    bool hasWideColorSupport = false;
+    bool hasWideColorGamut = false;
     if (hasWideColorDisplay) {
-        std::vector<ColorMode> modes = getHwComposer().getColorModes(state.type);
+        std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
         for (ColorMode colorMode : modes) {
             switch (colorMode) {
                 case ColorMode::DISPLAY_P3:
                 case ColorMode::ADOBE_RGB:
                 case ColorMode::DCI_P3:
-                    hasWideColorSupport = true;
+                    hasWideColorGamut = true;
                     break;
+                // TODO(lpy) Handle BT2020, BT2100_PQ and BT2100_HLG properly.
                 default:
                     break;
             }
+
+            std::vector<RenderIntent> renderIntents = getHwComposer().getRenderIntents(hwcId,
+                                                                                       colorMode);
+            if (state.type == DisplayDevice::DISPLAY_PRIMARY) {
+                for (auto intent : renderIntents) {
+                    if (intent == RenderIntent::ENHANCE) {
+                        mBuiltinDisplaySupportsEnhance = true;
+                        break;
+                    }
+                }
+            }
         }
     }
 
-    bool hasHdrSupport = false;
-    std::unique_ptr<HdrCapabilities> hdrCapabilities =
-            getHwComposer().getHdrCapabilities(state.type);
+    bool hasHdr10 = false;
+    std::unique_ptr<HdrCapabilities> hdrCapabilities = getHwComposer().getHdrCapabilities(hwcId);
     if (hdrCapabilities) {
         const std::vector<int32_t> types = hdrCapabilities->getSupportedHdrTypes();
         auto iter = std::find(types.cbegin(), types.cend(), HAL_HDR_HDR10);
-        hasHdrSupport = iter != types.cend();
+        hasHdr10 = iter != types.cend();
     }
 
     auto nativeWindowSurface = mCreateNativeWindowSurface(producer);
@@ -2260,18 +2316,19 @@
     sp<DisplayDevice> hw =
             new DisplayDevice(this, state.type, hwcId, state.isSecure, display, nativeWindow,
                               dispSurface, std::move(renderSurface), displayWidth, displayHeight,
-                              hasWideColorSupport, hasHdrSupport, initialPowerMode);
+                              hasWideColorGamut, hasHdr10, initialPowerMode);
 
     if (maxFrameBufferAcquiredBuffers >= 3) {
         nativeWindowSurface->preallocateBuffers();
     }
 
     ColorMode defaultColorMode = ColorMode::NATIVE;
-    if (hasWideColorSupport) {
+    Dataspace defaultDataSpace = Dataspace::UNKNOWN;
+    if (hasWideColorGamut) {
         defaultColorMode = ColorMode::SRGB;
+        defaultDataSpace = Dataspace::V0_SRGB;
     }
-    setActiveColorModeInternal(hw, defaultColorMode);
-    hw->setCompositionDataSpace(Dataspace::UNKNOWN);
+    setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace);
     hw->setLayerStack(state.layerStack);
     hw->setProjection(state.orientation, state.viewport, state.frame);
     hw->setDisplayName(state.displayName);
@@ -2822,23 +2879,27 @@
     const Region bounds(displayDevice->bounds());
     const DisplayRenderArea renderArea(displayDevice);
     const auto hwcId = displayDevice->getHwcDisplayId();
+    const bool hasClientComposition = getBE().mHwc->hasClientComposition(hwcId);
+    const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(hwcId);
+    const bool skipClientColorTransform = getBE().mHwc->hasCapability(
+        HWC2::Capability::SkipClientColorTransform);
+    ATRACE_INT("hasClientComposition", hasClientComposition);
 
     mat4 oldColorMatrix;
-    const bool applyColorMatrix = !getBE().mHwc->hasDeviceComposition(hwcId) &&
-            !getBE().mHwc->hasCapability(HWC2::Capability::SkipClientColorTransform);
+    mat4 legacySrgbSaturationMatrix = mLegacySrgbSaturationMatrix;
+    const bool applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
     if (applyColorMatrix) {
-        mat4 colorMatrix = mColorMatrix * mDaltonizer();
+        mat4 colorMatrix = mColorMatrix * computeSaturationMatrix() * mDaltonizer();
         oldColorMatrix = getRenderEngine().setupColorTransform(colorMatrix);
+        legacySrgbSaturationMatrix = colorMatrix * legacySrgbSaturationMatrix;
     }
 
-    bool hasClientComposition = getBE().mHwc->hasClientComposition(hwcId);
     if (hasClientComposition) {
         ALOGV("hasClientComposition");
 
         Dataspace outputDataspace = Dataspace::UNKNOWN;
-        if (displayDevice->getWideColorSupport() &&
-              displayDevice->getActiveColorMode() == ColorMode::DISPLAY_P3) {
-            outputDataspace = Dataspace::DISPLAY_P3;
+        if (displayDevice->hasWideColorGamut()) {
+            outputDataspace = displayDevice->getCompositionDataSpace();
         }
         getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
 
@@ -2855,7 +2916,6 @@
         }
 
         // Never touch the framebuffer if we don't have any framebuffer layers
-        const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(hwcId);
         if (hasDeviceComposition) {
             // when using overlays, we assume a fully transparent framebuffer
             // NOTE: we could reduce how much we need to clear, for instance
@@ -2930,7 +2990,20 @@
                         break;
                     }
                     case HWC2::Composition::Client: {
+                        // Only apply saturation matrix layer that is legacy SRGB dataspace
+                        // when auto color mode is on.
+                        bool restore = false;
+                        mat4 savedMatrix;
+                        if (mDisplayColorSetting == DisplayColorSetting::ENHANCED &&
+                            layer->isLegacySrgbDataSpace()) {
+                            savedMatrix =
+                                getRenderEngine().setupColorTransform(legacySrgbSaturationMatrix);
+                            restore = true;
+                        }
                         layer->draw(renderArea, clip);
+                        if (restore) {
+                            getRenderEngine().setupColorTransform(savedMatrix);
+                        }
                         break;
                     }
                     default:
@@ -4004,7 +4077,7 @@
 
 void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
     result.appendFormat("hasWideColorDisplay: %d\n", hasWideColorDisplay);
-    result.appendFormat("forceNativeColorMode: %d\n", mForceNativeColorMode);
+    result.appendFormat("DisplayColorSetting: %d\n", mDisplayColorSetting);
 
     // TODO: print out if wide-color mode is active or not
 
@@ -4500,15 +4573,22 @@
                 return NO_ERROR;
             }
             case 1022: { // Set saturation boost
-                mSaturation = std::max(0.0f, std::min(data.readFloat(), 2.0f));
+                mGlobalSaturationFactor = std::max(0.0f, std::min(data.readFloat(), 2.0f));
 
                 invalidateHwcGeometry();
                 repaintEverything();
                 return NO_ERROR;
             }
             case 1023: { // Set native mode
-                mForceNativeColorMode = data.readInt32() == 1;
+                int32_t value = data.readInt32();
+                if (value > 2) {
+                    return BAD_VALUE;
+                }
+                if (value == 2 && !mBuiltinDisplaySupportsEnhance) {
+                    return BAD_VALUE;
+                }
 
+                mDisplayColorSetting = toDisplayColorSetting(value);
                 invalidateHwcGeometry();
                 repaintEverything();
                 return NO_ERROR;
@@ -4535,6 +4615,23 @@
                 reply->writeBool(mTracing.isEnabled());
                 return NO_ERROR;
             }
+            // Is a DisplayColorSetting supported?
+            case 1027: {
+                int32_t value = data.readInt32();
+                switch (value) {
+                    case 0:
+                        reply->writeBool(hasWideColorDisplay);
+                        return NO_ERROR;
+                    case 1:
+                        reply->writeBool(true);
+                        return NO_ERROR;
+                    case 2:
+                        reply->writeBool(mBuiltinDisplaySupportsEnhance);
+                        return NO_ERROR;
+                    default:
+                        return BAD_VALUE;
+                }
+            }
         }
     }
     return err;
@@ -4602,6 +4699,7 @@
                 mCrop(crop),
                 mFlinger(flinger),
                 mChildrenOnly(childrenOnly) {}
+        const Transform& getTransform() const override { return mTransform; }
         Rect getBounds() const override {
             const Layer::State& layerState(mLayer->getDrawingState());
             return Rect(layerState.active.w, layerState.active.h);
@@ -4610,7 +4708,15 @@
         int getWidth() const override { return mLayer->getDrawingState().active.w; }
         bool isSecure() const override { return false; }
         bool needsFiltering() const override { return false; }
-        const Transform& getTransform() const { return mTransform; }
+        Rect getSourceCrop() const override {
+            if (mCrop.isEmpty()) {
+                return getBounds();
+            } else {
+                return mCrop;
+            }
+        }
+        bool getWideColorSupport() const override { return false; }
+        Dataspace getDataSpace() const override { return Dataspace::UNKNOWN; }
 
         class ReparentForDrawing {
         public:
@@ -4639,16 +4745,6 @@
             }
         }
 
-        Rect getSourceCrop() const override {
-            if (mCrop.isEmpty()) {
-                return getBounds();
-            } else {
-                return mCrop;
-            }
-        }
-        bool getWideColorSupport() const override { return false; }
-        ColorMode getActiveColorMode() const override { return ColorMode::NATIVE; }
-
     private:
         const sp<Layer> mLayer;
         const Rect mCrop;
@@ -4820,9 +4916,8 @@
     }
 
     Dataspace outputDataspace = Dataspace::UNKNOWN;
-    if (renderArea.getWideColorSupport() &&
-          renderArea.getActiveColorMode() == ColorMode::DISPLAY_P3) {
-        outputDataspace = Dataspace::DISPLAY_P3;
+    if (renderArea.getWideColorSupport()) {
+        outputDataspace = renderArea.getDataSpace();
     }
     getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a29d1d7..14028ff 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -123,6 +123,12 @@
     eTransactionMask          = 0x0f,
 };
 
+enum class DisplayColorSetting : int32_t {
+    MANAGED = 0,
+    UNMANAGED = 1,
+    ENHANCED = 2,
+};
+
 // A thin interface to abstract creating instances of Surface (gui/Surface.h) to
 // use as a NativeWindow.
 class NativeWindowSurface {
@@ -467,7 +473,9 @@
                               bool stateLockHeld);
 
     // Called on the main thread in response to setActiveColorMode()
-    void setActiveColorModeInternal(const sp<DisplayDevice>& hw, ui::ColorMode colorMode);
+    void setActiveColorModeInternal(const sp<DisplayDevice>& hw,
+                                    ui::ColorMode colorMode,
+                                    ui::Dataspace dataSpace);
 
     // Returns whether the transaction actually modified any state
     bool handleMessageTransaction();
@@ -641,9 +649,10 @@
 
     // Given a dataSpace, returns the appropriate color_mode to use
     // to display that dataSpace.
-    ui::ColorMode pickColorMode(ui::Dataspace dataSpace) const;
-    ui::Dataspace bestTargetDataSpace(ui::Dataspace a, ui::Dataspace b,
-            bool hasHdr) const;
+    ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& displayDevice) const;
+    void pickColorMode(const sp<DisplayDevice>& displayDevice,
+                       ui::ColorMode* outMode,
+                       ui::Dataspace* outDataSpace) const;
 
     mat4 computeSaturationMatrix() const;
 
@@ -846,7 +855,6 @@
 
     size_t mNumLayers;
 
-
     // Verify that transaction is being called by an approved process:
     // either AID_GRAPHICS or AID_SYSTEM.
     status_t CheckTransactCodeCredentials(uint32_t code);
@@ -856,8 +864,12 @@
     static bool useVrFlinger;
     std::thread::id mMainThreadId;
 
-    float mSaturation = 1.0f;
-    bool mForceNativeColorMode = false;
+    DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::MANAGED;
+    // Applied on sRGB layers when the render intent is non-colorimetric.
+    mat4 mLegacySrgbSaturationMatrix;
+    // Applied globally.
+    float mGlobalSaturationFactor = 1.0f;
+    bool mBuiltinDisplaySupportsEnhance = false;
 
     using CreateBufferQueueFunction =
             std::function<void(sp<IGraphicBufferProducer>* /* outProducer */,