surfaceflinger: simplify P3 support in RE

RE always knows how to convert sRGB/P3/BT2020 to P3.  The conversion
is enabled by SurfaceFlinger whenever the color mode is P3 (and when
hasWideColorDisplay is true).  This change simplifies or removes
some wide color state functions from RE, and moves the burden to
SurfaceFlinger.  It also changes GLES20RenderEngine::drawMesh to
inspect mDataSpace and mOutputDataSpace directly.

This allows us to enable the conversion in more cases more easily.
For example, we can choose to set the RE output dataspace to P3 even
when the display color mode is NATIVE.

Test: manual with UiBench
Change-Id: I5e701dd6b01764efbbab967dc4a26a4d008dfc09
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 9ecf8ce..ea7dc2f 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -210,42 +210,16 @@
     }
 }
 
-void GLES20RenderEngine::setColorMode(android_color_mode mode) {
-    ALOGV("setColorMode: %s (0x%x)", decodeColorMode(mode).c_str(), mode);
-
-    if (mColorMode == mode) return;
-
-    if (!mPlatformHasWideColor || !mDisplayHasWideColor || mode == HAL_COLOR_MODE_SRGB ||
-        mode == HAL_COLOR_MODE_NATIVE) {
-        // We are returning back to our default color_mode
-        mUseWideColor = false;
-        mWideColorFrameCount = 0;
-    } else {
-        mUseWideColor = true;
-    }
-
-    mColorMode = mode;
-}
-
-void GLES20RenderEngine::setSourceDataSpace(android_dataspace source) {
-    if (source == HAL_DATASPACE_UNKNOWN) {
-        // Treat UNKNOWN as SRGB
-        source = HAL_DATASPACE_V0_SRGB;
-    }
-    mDataSpace = source;
-}
-
 void GLES20RenderEngine::setSourceY410BT2020(bool enable) {
     mState.setY410BT2020(enable);
 }
 
-void GLES20RenderEngine::setWideColor(bool hasWideColor) {
-    ALOGV("setWideColor: %s", hasWideColor ? "true" : "false");
-    mDisplayHasWideColor = hasWideColor;
+void GLES20RenderEngine::setSourceDataSpace(android_dataspace source) {
+    mDataSpace = source;
 }
 
-bool GLES20RenderEngine::usesWideColor() {
-    return mUseWideColor;
+void GLES20RenderEngine::setOutputDataSpace(android_dataspace dataspace) {
+    mOutputDataSpace = dataspace;
 }
 
 void GLES20RenderEngine::setupLayerTexturing(const Texture& texture) {
@@ -326,17 +300,13 @@
     glVertexAttribPointer(Program::position, mesh.getVertexSize(), GL_FLOAT, GL_FALSE,
                           mesh.getByteStride(), mesh.getPositions());
 
-    if (usesWideColor()) {
+    // DISPLAY_P3 is the only supported wide color output
+    if (mPlatformHasWideColor && mOutputDataSpace == HAL_DATASPACE_DISPLAY_P3) {
         Description wideColorState = mState;
         switch (int(mDataSpace)) {
             case HAL_DATASPACE_DISPLAY_P3:
                 // input matches output
                 break;
-            case HAL_DATASPACE_V0_SCRGB_LINEAR:
-                wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
-                wideColorState.setInputTransferFunction(Description::TransferFunction::LINEAR);
-                wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
-                break;
             case HAL_DATASPACE_BT2020_PQ:
             case HAL_DATASPACE_BT2020_ITU_PQ:
                 wideColorState.setColorMatrix(mState.getColorMatrix() * mBt2020ToDisplayP3);
@@ -345,8 +315,13 @@
                 wideColorState.enableToneMapping(true);
                 break;
             default:
+                // treat all other dataspaces as sRGB
                 wideColorState.setColorMatrix(mState.getColorMatrix() * mSrgbToDisplayP3);
-                wideColorState.setInputTransferFunction(Description::TransferFunction::SRGB);
+                if ((mDataSpace & HAL_DATASPACE_TRANSFER_MASK) == HAL_DATASPACE_TRANSFER_LINEAR) {
+                    wideColorState.setInputTransferFunction(Description::TransferFunction::LINEAR);
+                } else {
+                    wideColorState.setInputTransferFunction(Description::TransferFunction::SRGB);
+                }
                 wideColorState.setOutputTransferFunction(Description::TransferFunction::SRGB);
                 ALOGV("drawMesh: gamut transform applied");
                 break;
@@ -356,8 +331,9 @@
         glDrawArrays(mesh.getPrimitive(), 0, mesh.getVertexCount());
 
         if (outputDebugPPMs) {
+            static uint64_t wideColorFrameCount = 0;
             std::ostringstream out;
-            out << "/data/texture_out" << mWideColorFrameCount++;
+            out << "/data/texture_out" << wideColorFrameCount++;
             writePPM(out.str().c_str(), mVpWidth, mVpHeight);
         }
     } else {
@@ -373,11 +349,9 @@
 
 void GLES20RenderEngine::dump(String8& result) {
     RenderEngine::dump(result);
-    if (usesWideColor()) {
-        result.append("Wide-color: On\n");
-    } else {
-        result.append("Wide-color: Off\n");
-    }
+    result.appendFormat("RenderEngine last dataspace conversion: (%s) to (%s)\n",
+                        dataspaceDetails(mDataSpace).c_str(),
+                        dataspaceDetails(mOutputDataSpace).c_str());
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
index 6e86ea2..db3f792 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
@@ -72,27 +72,20 @@
                                     const half4& color) override;
 
     // Color management related functions and state
-    void setColorMode(android_color_mode mode);
-    void setSourceDataSpace(android_dataspace source);
-    void setSourceY410BT2020(bool enable);
-    void setWideColor(bool hasWideColor);
-    bool usesWideColor();
-
-    // Current color mode of display using the render engine
-    android_color_mode mColorMode = HAL_COLOR_MODE_NATIVE;
+    void setSourceY410BT2020(bool enable) override;
+    void setSourceDataSpace(android_dataspace source) override;
+    void setOutputDataSpace(android_dataspace dataspace) override;
 
     // Current dataspace of layer being rendered
-    android_dataspace mDataSpace = HAL_DATASPACE_V0_SRGB;
+    android_dataspace mDataSpace = HAL_DATASPACE_UNKNOWN;
 
-    // Indicate if wide-color mode is needed or not
-    bool mDisplayHasWideColor = false;
-    bool mUseWideColor = false;
-    uint64_t mWideColorFrameCount = 0;
+    // Current output dataspace of the render engine
+    android_dataspace mOutputDataSpace = HAL_DATASPACE_UNKNOWN;
 
     // Currently only supporting sRGB, BT2020 and DisplayP3 color spaces
+    const bool mPlatformHasWideColor = false;
     mat4 mSrgbToDisplayP3;
     mat4 mBt2020ToDisplayP3;
-    bool mPlatformHasWideColor = false;
 
     virtual void setupLayerTexturing(const Texture& texture);
     virtual void setupLayerBlackedOut();
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index eacef38..d140574 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -108,11 +108,6 @@
                                           bool yswap, Transform::orientation_flags rotation) = 0;
     virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
                                     const half4& color) = 0;
-    virtual void setColorMode(android_color_mode mode) = 0;
-    virtual void setSourceDataSpace(android_dataspace source) = 0;
-    virtual void setSourceY410BT2020(bool enable) = 0;
-    virtual void setWideColor(bool hasWideColor) = 0;
-    virtual bool usesWideColor() = 0;
     virtual void setupLayerTexturing(const Texture& texture) = 0;
     virtual void setupLayerBlackedOut() = 0;
     virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
@@ -122,6 +117,11 @@
     virtual void disableTexturing() = 0;
     virtual void disableBlending() = 0;
 
+    // wide color support
+    virtual void setSourceY410BT2020(bool enable) = 0;
+    virtual void setSourceDataSpace(android_dataspace source) = 0;
+    virtual void setOutputDataSpace(android_dataspace dataspace) = 0;
+
     // drawing
     virtual void drawMesh(const Mesh& mesh) = 0;
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 0961058..87fd2f1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2738,10 +2738,13 @@
     if (hasClientComposition) {
         ALOGV("hasClientComposition");
 
-        getBE().mRenderEngine->setWideColor(
-                displayDevice->getWideColorSupport() && !mForceNativeColorMode);
-        getBE().mRenderEngine->setColorMode(mForceNativeColorMode ?
-                HAL_COLOR_MODE_NATIVE : displayDevice->getActiveColorMode());
+        android_dataspace outputDataspace = HAL_DATASPACE_UNKNOWN;
+        if (!mForceNativeColorMode && displayDevice->getWideColorSupport() &&
+                displayDevice->getActiveColorMode() == HAL_COLOR_MODE_DISPLAY_P3) {
+            outputDataspace = HAL_DATASPACE_DISPLAY_P3;
+        }
+        getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
+
         if (!displayDevice->makeCurrent()) {
             ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
                   displayDevice->getDisplayName().string());
@@ -4596,9 +4599,12 @@
         ALOGE("Invalid crop rect: b = %d (> %d)", sourceCrop.bottom, raHeight);
     }
 
-    engine.setWideColor(renderArea.getWideColorSupport() && !mForceNativeColorMode);
-    engine.setColorMode(mForceNativeColorMode ? HAL_COLOR_MODE_NATIVE
-                                              : renderArea.getActiveColorMode());
+    android_dataspace outputDataspace = HAL_DATASPACE_UNKNOWN;
+    if (!mForceNativeColorMode && renderArea.getWideColorSupport() &&
+            renderArea.getActiveColorMode() == HAL_COLOR_MODE_DISPLAY_P3) {
+        outputDataspace = HAL_DATASPACE_DISPLAY_P3;
+    }
+    getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
 
     // make sure to clear all GL error flags
     engine.checkErrors();
diff --git a/services/surfaceflinger/tests/unittests/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/MockRenderEngine.h
index aefbfcf..6d3e17f 100644
--- a/services/surfaceflinger/tests/unittests/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/MockRenderEngine.h
@@ -57,17 +57,15 @@
     MOCK_METHOD6(setViewportAndProjection,
                  void(size_t, size_t, Rect, size_t, bool, Transform::orientation_flags));
     MOCK_METHOD4(setupLayerBlending, void(bool, bool, bool, const half4&));
-    MOCK_METHOD1(setColorMode, void(android_color_mode));
-    MOCK_METHOD1(setSourceDataSpace, void(android_dataspace));
-    MOCK_METHOD1(setSourceY410BT2020, void(bool));
-    MOCK_METHOD1(setWideColor, void(bool));
-    MOCK_METHOD0(usesWideColor, bool());
     MOCK_METHOD1(setupLayerTexturing, void(const Texture&));
     MOCK_METHOD0(setupLayerBlackedOut, void());
     MOCK_METHOD4(setupFillWithColor, void(float, float, float, float));
     MOCK_METHOD1(setupColorTransform, mat4(const mat4&));
     MOCK_METHOD0(disableTexturing, void());
     MOCK_METHOD0(disableBlending, void());
+    MOCK_METHOD1(setSourceY410BT2020, void(bool));
+    MOCK_METHOD1(setSourceDataSpace, void(android_dataspace));
+    MOCK_METHOD1(setOutputDataSpace, void(android_dataspace));
     MOCK_METHOD2(bindNativeBufferAsFrameBuffer,
                  void(ANativeWindowBuffer*, RE::BindNativeBufferAsFramebuffer*));
     MOCK_METHOD1(unbindNativeBufferAsFrameBuffer, void(RE::BindNativeBufferAsFramebuffer*));