[SurfaceFlinger] Decouple color management from wide color display property.

Previously, device is only color managed when the display is wide color gamut
display. This patch decouples this logic out so that device can have color
management even if it only has calibrated sRGB display.

BUG: 111505327
Test: Build, flash and check all color settings.
Change-Id: I5db31cdf1bde2f0e5b1fed269895d294f2353c44
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index efaeaa2..ee69b83 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -23,6 +23,7 @@
         "android.hardware.configstore-utils",
         "android.hardware.configstore@1.0",
         "android.hardware.configstore@1.1",
+        "android.hardware.configstore@1.2",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
@@ -175,6 +176,7 @@
         "android.frameworks.displayservice@1.0",
         "android.hardware.configstore-utils",
         "android.hardware.configstore@1.0",
+        "android.hardware.configstore@1.2",
         "android.hardware.graphics.allocator@2.0",
         "libbinder",
         "libcutils",
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 2186594..136d12f 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -114,7 +114,7 @@
       : RenderEngine(featureFlags),
         mVpWidth(0),
         mVpHeight(0),
-        mPlatformHasWideColor((featureFlags & WIDE_COLOR_SUPPORT) != 0) {
+        mUseColorManagement(featureFlags & USE_COLOR_MANAGEMENT) {
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
 
@@ -132,7 +132,7 @@
 
     // mColorBlindnessCorrection = M;
 
-    if (mPlatformHasWideColor) {
+    if (mUseColorManagement) {
         ColorSpace srgb(ColorSpace::sRGB());
         ColorSpace displayP3(ColorSpace::DisplayP3());
         ColorSpace bt2020(ColorSpace::BT2020());
@@ -322,8 +322,8 @@
     // BT2020 data space, in that case, the output data space is set to be
     // BT2020_HLG or BT2020_PQ respectively. In GPU fall back we need
     // to respect this and convert non-HDR content to HDR format.
-    if (mPlatformHasWideColor) {
-        Description wideColorState = mState;
+    if (mUseColorManagement) {
+        Description managedState = mState;
         Dataspace inputStandard = static_cast<Dataspace>(mDataSpace & Dataspace::STANDARD_MASK);
         Dataspace inputTransfer = static_cast<Dataspace>(mDataSpace & Dataspace::TRANSFER_MASK);
         Dataspace outputStandard = static_cast<Dataspace>(mOutputDataSpace &
@@ -336,26 +336,26 @@
             // The supported input color spaces are standard RGB, Display P3 and BT2020.
             switch (inputStandard) {
                 case Dataspace::STANDARD_DCI_P3:
-                    wideColorState.setInputTransformMatrix(mDisplayP3ToXyz);
+                    managedState.setInputTransformMatrix(mDisplayP3ToXyz);
                     break;
                 case Dataspace::STANDARD_BT2020:
-                    wideColorState.setInputTransformMatrix(mBt2020ToXyz);
+                    managedState.setInputTransformMatrix(mBt2020ToXyz);
                     break;
                 default:
-                    wideColorState.setInputTransformMatrix(mSrgbToXyz);
+                    managedState.setInputTransformMatrix(mSrgbToXyz);
                     break;
             }
 
             // The supported output color spaces are BT2020, Display P3 and standard RGB.
             switch (outputStandard) {
                 case Dataspace::STANDARD_BT2020:
-                    wideColorState.setOutputTransformMatrix(mXyzToBt2020);
+                    managedState.setOutputTransformMatrix(mXyzToBt2020);
                     break;
                 case Dataspace::STANDARD_DCI_P3:
-                    wideColorState.setOutputTransformMatrix(mXyzToDisplayP3);
+                    managedState.setOutputTransformMatrix(mXyzToDisplayP3);
                     break;
                 default:
-                    wideColorState.setOutputTransformMatrix(mXyzToSrgb);
+                    managedState.setOutputTransformMatrix(mXyzToSrgb);
                     break;
             }
         } else if (inputStandard != outputStandard) {
@@ -370,9 +370,9 @@
             // - sRGB
             // - Display P3
             if (outputStandard == Dataspace::STANDARD_BT709) {
-                wideColorState.setOutputTransformMatrix(mDisplayP3ToSrgb);
+                managedState.setOutputTransformMatrix(mDisplayP3ToSrgb);
             } else if (outputStandard == Dataspace::STANDARD_DCI_P3) {
-                wideColorState.setOutputTransformMatrix(mSrgbToDisplayP3);
+                managedState.setOutputTransformMatrix(mSrgbToDisplayP3);
             }
         }
 
@@ -380,44 +380,44 @@
         // - there is a color matrix that is not an identity matrix, or
         // - there is an output transform matrix that is not an identity matrix, or
         // - the input transfer function doesn't match the output transfer function.
-        if (wideColorState.hasColorMatrix() || wideColorState.hasOutputTransformMatrix() ||
+        if (managedState.hasColorMatrix() || managedState.hasOutputTransformMatrix() ||
             inputTransfer != outputTransfer) {
             switch (inputTransfer) {
                 case Dataspace::TRANSFER_ST2084:
-                    wideColorState.setInputTransferFunction(Description::TransferFunction::ST2084);
+                    managedState.setInputTransferFunction(Description::TransferFunction::ST2084);
                     break;
                 case Dataspace::TRANSFER_HLG:
-                    wideColorState.setInputTransferFunction(Description::TransferFunction::HLG);
+                    managedState.setInputTransferFunction(Description::TransferFunction::HLG);
                     break;
                 case Dataspace::TRANSFER_LINEAR:
-                    wideColorState.setInputTransferFunction(Description::TransferFunction::LINEAR);
+                    managedState.setInputTransferFunction(Description::TransferFunction::LINEAR);
                     break;
                 default:
-                    wideColorState.setInputTransferFunction(Description::TransferFunction::SRGB);
+                    managedState.setInputTransferFunction(Description::TransferFunction::SRGB);
                     break;
             }
 
             switch (outputTransfer) {
                 case Dataspace::TRANSFER_ST2084:
-                    wideColorState.setOutputTransferFunction(Description::TransferFunction::ST2084);
+                    managedState.setOutputTransferFunction(Description::TransferFunction::ST2084);
                     break;
                 case Dataspace::TRANSFER_HLG:
-                    wideColorState.setOutputTransferFunction(Description::TransferFunction::HLG);
+                    managedState.setOutputTransferFunction(Description::TransferFunction::HLG);
                     break;
                 default:
-                    wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
+                    managedState.setOutputTransferFunction(Description::TransferFunction::SRGB);
                     break;
             }
         }
 
-        ProgramCache::getInstance().useProgram(wideColorState);
+        ProgramCache::getInstance().useProgram(managedState);
 
         glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
 
         if (outputDebugPPMs) {
-            static uint64_t wideColorFrameCount = 0;
+            static uint64_t managedColorFrameCount = 0;
             std::ostringstream out;
-            out << "/data/texture_out" << wideColorFrameCount++;
+            out << "/data/texture_out" << managedColorFrameCount++;
             writePPM(out.str().c_str(), mVpWidth, mVpHeight);
         }
     } else {
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index f682225..d8cb73b 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -94,8 +94,9 @@
     // Current output dataspace of the render engine
     ui::Dataspace mOutputDataSpace = ui::Dataspace::UNKNOWN;
 
-    // Currently only supporting sRGB, BT2020 and DisplayP3 color spaces
-    const bool mPlatformHasWideColor = false;
+    // Whether device supports color management, currently color management
+    // supports sRGB, DisplayP3 color spaces.
+    const bool mUseColorManagement = false;
     mat4 mSrgbToDisplayP3;
     mat4 mDisplayP3ToSrgb;
     mat3 mSrgbToXyz;
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
index 9dc6858..a1d0561 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp
@@ -82,7 +82,7 @@
 
 ProgramCache::~ProgramCache() {}
 
-void ProgramCache::primeCache(bool hasWideColor) {
+void ProgramCache::primeCache(bool useColorManagement) {
     uint32_t shaderCount = 0;
     uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK | Key::ALPHA_MASK | Key::TEXTURE_MASK;
     // Prime the cache for all combinations of the above masks,
@@ -105,7 +105,7 @@
     }
 
     // Prime for sRGB->P3 conversion
-    if (hasWideColor) {
+    if (useColorManagement) {
         Key shaderKey;
         shaderKey.set(Key::BLEND_MASK | Key::TEXTURE_MASK | Key::OUTPUT_TRANSFORM_MATRIX_MASK |
                               Key::INPUT_TF_MASK | Key::OUTPUT_TF_MASK,
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h
index 983e7ba..424633e 100644
--- a/services/surfaceflinger/RenderEngine/ProgramCache.h
+++ b/services/surfaceflinger/RenderEngine/ProgramCache.h
@@ -161,7 +161,7 @@
     ~ProgramCache();
 
     // Generate shaders to populate the cache
-    void primeCache(bool hasWideColor);
+    void primeCache(bool useColorManagement);
 
     // useProgram lookup a suitable program in the cache or generates one
     // if none can be found.
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 39f7e30..e5dbe2f 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -596,7 +596,7 @@
 }
 
 void RenderEngine::primeCache() const {
-    ProgramCache::getInstance().primeCache(mFeatureFlags & WIDE_COLOR_SUPPORT);
+    ProgramCache::getInstance().primeCache(mFeatureFlags & USE_COLOR_MANAGEMENT);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 2ed2cc7..6213784 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -56,7 +56,7 @@
 class RenderEngine {
 public:
     enum FeatureFlag {
-        WIDE_COLOR_SUPPORT = 1 << 0 // Platform has a wide color display
+        USE_COLOR_MANAGEMENT = 1 << 0, // Device manages color
     };
 
     virtual ~RenderEngine() = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c0c684a..690f936 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -93,6 +93,7 @@
 
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
+#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
 #include <android/hardware/configstore/1.1/types.h>
 #include <configstore/Utils.h>
 
@@ -176,6 +177,7 @@
 int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
 // TODO(courtneygo): Rename hasWideColorDisplay to clarify its actual meaning.
 bool SurfaceFlinger::hasWideColorDisplay;
+bool SurfaceFlinger::useColorManagement;
 
 
 std::string getHwcServiceName() {
@@ -302,6 +304,8 @@
 
     hasWideColorDisplay =
             getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
+    useColorManagement =
+            getBool<V1_2::ISurfaceFlingerConfigs, &V1_2::ISurfaceFlingerConfigs::useColorManagement>(false);
 
     V1_1::DisplayOrientation primaryDisplayOrientation =
         getDisplayOrientation< V1_1::ISurfaceFlingerConfigs, &V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>(
@@ -597,11 +601,10 @@
     mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
 
     // Get a RenderEngine for the given display / config (can't fail)
+    int32_t renderEngineFeature = 0;
+    renderEngineFeature |= (useColorManagement ? RE::RenderEngine::USE_COLOR_MANAGEMENT : 0);
     getBE().mRenderEngine =
-            RE::impl::RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,
-                                           hasWideColorDisplay
-                                                   ? RE::RenderEngine::WIDE_COLOR_SUPPORT
-                                                   : 0);
+            RE::impl::RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888, renderEngineFeature);
     LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine");
 
     LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
@@ -1541,7 +1544,7 @@
             layer->setPerFrameData(display);
         }
 
-        if (hasWideColorDisplay) {
+        if (useColorManagement) {
             ColorMode  colorMode;
             Dataspace dataSpace;
             RenderIntent renderIntent;
@@ -2199,7 +2202,7 @@
     HdrCapabilities hdrCapabilities;
     int32_t supportedPerFrameMetadata = 0;
 
-    if (hasWideColorDisplay && displayId >= 0) {
+    if (useColorManagement && displayId >= 0) {
         std::vector<ColorMode> modes = getHwComposer().getColorModes(displayId);
         for (ColorMode colorMode : modes) {
             if (isWideColorMode(colorMode)) {
@@ -4137,7 +4140,8 @@
 }
 
 void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
-    result.appendFormat("hasWideColorDisplay: %d\n", hasWideColorDisplay);
+    result.appendFormat("Device has wide color display: %d\n", hasWideColorDisplay);
+    result.appendFormat("Device uses color management: %d\n", useColorManagement);
     result.appendFormat("DisplayColorSetting: %s\n",
             decodeDisplayColorSetting(mDisplayColorSetting).c_str());
 
@@ -4711,7 +4715,9 @@
                 repaintEverything();
                 return NO_ERROR;
             }
-            case 1024: { // Is wide color gamut rendering/color management supported?
+            // TODO(b/111505327): Find out whether the usage of 1024 can switch to 1030,
+            // deprecate 1024 if they can.
+            case 1024: { // Does device have wide color gamut display?
                 reply->writeBool(hasWideColorDisplay);
                 return NO_ERROR;
             }
@@ -4743,7 +4749,7 @@
                 DisplayColorSetting setting = static_cast<DisplayColorSetting>(data.readInt32());
                 switch (setting) {
                     case DisplayColorSetting::MANAGED:
-                        reply->writeBool(hasWideColorDisplay);
+                        reply->writeBool(useColorManagement);
                         break;
                     case DisplayColorSetting::UNMANAGED:
                         reply->writeBool(true);
@@ -4791,6 +4797,11 @@
                 ATRACE_INT("PeriodDivisor", divisor);
                 return NO_ERROR;
             }
+            // Is device color managed?
+            case 1030: {
+                reply->writeBool(useColorManagement);
+                return NO_ERROR;
+            }
         }
     }
     return err;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c06c74f..3e68c70 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -283,13 +283,13 @@
     // FramebufferSurface
     static int64_t maxFrameBufferAcquiredBuffers;
 
-    // Indicate if platform supports color management on its
-    // wide-color display. This is typically found on devices
-    // with wide gamut (e.g. Display-P3) display.
-    // This also allows devices with wide-color displays that don't
-    // want to support color management to disable color management.
+    // Indicate if a device has wide color gamut display. This is typically
+    // found on devices with wide color gamut (e.g. Display-P3) display.
     static bool hasWideColorDisplay;
 
+    // Indicate if device wants color management on its display.
+    static bool useColorManagement;
+
     static char const* getServiceName() ANDROID_API {
         return "SurfaceFlinger";
     }
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index b4aec36..1f57b8e 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -137,6 +137,7 @@
 
     // Default to no wide color display support configured
     mFlinger.mutableHasWideColorDisplay() = false;
+    mFlinger.mutableUseColorManagement() = false;
     mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
 
     // Default to using HWC virtual displays
@@ -455,6 +456,7 @@
 
     static void injectConfigChange(DisplayTransactionTest* test) {
         test->mFlinger.mutableHasWideColorDisplay() = false;
+        test->mFlinger.mutableUseColorManagement() = false;
         test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
     }
 
@@ -473,6 +475,7 @@
     static constexpr bool WIDE_COLOR_SUPPORTED = true;
 
     static void injectConfigChange(DisplayTransactionTest* test) {
+        test->mFlinger.mutableUseColorManagement() = true;
         test->mFlinger.mutableHasWideColorDisplay() = true;
         test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
     }
@@ -501,6 +504,7 @@
     static constexpr bool WIDE_COLOR_SUPPORTED = false;
 
     static void injectConfigChange(DisplayTransactionTest* test) {
+        test->mFlinger.mutableUseColorManagement() = true;
         test->mFlinger.mutableHasWideColorDisplay() = true;
     }
 
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 9df4264..d8e7581 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -113,6 +113,7 @@
      */
 
     auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; }
+    auto& mutableUseColorManagement() { return SurfaceFlinger::useColorManagement; }
 
     auto& mutableDisplayTokens() { return mFlinger->mDisplayTokens; }
     auto& mutableCurrentState() { return mFlinger->mCurrentState; }