SF: Separate out display color handling

This creates a new class for the purpose of holding all the
functionality related to how colors are handled on the output display.

Test: atest libsurfaceflinger_unittest libcompositionengine_test
Bug: 121291683
Change-Id: Idcd4808c42d17ca37656993131d280ead3137a52
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
index 9ba6671..dbcd3bd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
@@ -26,6 +26,7 @@
 namespace android::compositionengine {
 
 struct RenderSurfaceCreationArgs;
+struct DisplayColorProfileCreationArgs;
 
 /**
  * A display is a composition target which may be backed by a hardware composer
@@ -45,6 +46,10 @@
     // Releases the use of the HWC display, if any
     virtual void disconnect() = 0;
 
+    // Creates a render color mode for the display
+    virtual void createDisplayColorProfile(DisplayColorProfileCreationArgs&&) = 0;
+
+    // Creates a render surface for the display
     virtual void createRenderSurface(RenderSurfaceCreationArgs&&) = 0;
 
 protected:
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
new file mode 100644
index 0000000..e2a0d42
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include <ui/GraphicTypes.h>
+
+namespace android {
+
+class HdrCapabilities;
+
+namespace compositionengine {
+
+/**
+ * Encapsulates all the state and functionality for how colors should be
+ * transformed for a display
+ */
+class DisplayColorProfile {
+public:
+    constexpr static float sDefaultMinLumiance = 0.0;
+    constexpr static float sDefaultMaxLumiance = 500.0;
+
+    virtual ~DisplayColorProfile();
+
+    // Returns true if the profile is valid. This is meant to be checked post-
+    // construction and prior to use, as not everything is set up by the
+    // constructor.
+    virtual bool isValid() const = 0;
+
+    // Returns true if the profile supports the indicated render intent
+    virtual bool hasRenderIntent(ui::RenderIntent) const = 0;
+
+    // Returns true if the profile supports the indicated dataspace
+    virtual bool hasLegacyHdrSupport(ui::Dataspace) const = 0;
+
+    // Obtains the best combination of color mode and render intent for the
+    // input values
+    virtual void getBestColorMode(ui::Dataspace dataspace, ui::RenderIntent intent,
+                                  ui::Dataspace* outDataspace, ui::ColorMode* outMode,
+                                  ui::RenderIntent* outIntent) const = 0;
+
+    // Returns true if the profile supports a wide color gamut
+    virtual bool hasWideColorGamut() const = 0;
+
+    // Returns the per-frame metadata value for this profile
+    virtual int32_t getSupportedPerFrameMetadata() const = 0;
+
+    // Returns true if HWC for this profile supports HDR10Plus
+    virtual bool hasHDR10PlusSupport() const = 0;
+
+    // Returns true if HWC for this profile supports HDR10
+    virtual bool hasHDR10Support() const = 0;
+
+    // Returns true if HWC for this profile supports HLG
+    virtual bool hasHLGSupport() const = 0;
+
+    // Returns true if HWC for this profile supports DolbyVision
+    virtual bool hasDolbyVisionSupport() const = 0;
+
+    // Gets the supported HDR capabilities for the profile
+    virtual const HdrCapabilities& getHdrCapabilities() const = 0;
+
+    // Debugging
+    virtual void dump(std::string&) const = 0;
+};
+
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h
new file mode 100644
index 0000000..ef0f925
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfileCreationArgs.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <unordered_map>
+#include <vector>
+
+#include <ui/GraphicTypes.h>
+#include <ui/HdrCapabilities.h>
+
+namespace android::compositionengine {
+
+/**
+ * A parameter object for creating DisplayColorProfile instances
+ */
+struct DisplayColorProfileCreationArgs {
+    using HwcColorModes = std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>;
+
+    // True if this display supports a wide color gamut
+    bool hasWideColorGamut;
+
+    // The HDR capabilities supported by the HWC
+    HdrCapabilities hdrCapabilities;
+
+    // The per-frame metadata supported by the HWC
+    int32_t supportedPerFrameMetadata;
+
+    // The mapping of color modes and render intents supported by the HWC
+    HwcColorModes hwcColorModes;
+};
+
+/**
+ * A helper for setting up a DisplayColorProfileCreationArgs value in-line.
+ *
+ * Prefer this builder over raw structure initialization.
+ *
+ * Instead of:
+ *
+ *   DisplayColorProfileCreationArgs{false, HdrCapabilities(), 0,
+ *                                   HwcColorModes()}
+ *
+ * Prefer:
+ *
+ *  DisplayColorProfileCreationArgsBuilder().setHasWideColorGamut(false)
+ *      .setIsVirtual(false).setDisplayId(displayId).Build();
+ */
+class DisplayColorProfileCreationArgsBuilder {
+public:
+    DisplayColorProfileCreationArgs Build() { return std::move(mArgs); }
+
+    DisplayColorProfileCreationArgsBuilder& setHasWideColorGamut(bool hasWideColorGamut) {
+        mArgs.hasWideColorGamut = hasWideColorGamut;
+        return *this;
+    }
+    DisplayColorProfileCreationArgsBuilder& setHdrCapabilities(HdrCapabilities&& hdrCapabilities) {
+        mArgs.hdrCapabilities = std::move(hdrCapabilities);
+        return *this;
+    }
+    DisplayColorProfileCreationArgsBuilder& setSupportedPerFrameMetadata(
+            int32_t supportedPerFrameMetadata) {
+        mArgs.supportedPerFrameMetadata = supportedPerFrameMetadata;
+        return *this;
+    }
+    DisplayColorProfileCreationArgsBuilder& setHwcColorModes(
+            DisplayColorProfileCreationArgs::HwcColorModes&& hwcColorModes) {
+        mArgs.hwcColorModes = std::move(hwcColorModes);
+        return *this;
+    }
+
+private:
+    DisplayColorProfileCreationArgs mArgs;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 7814bcb..2d00f0c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -26,6 +26,7 @@
 
 namespace android::compositionengine {
 
+class DisplayColorProfile;
 class RenderSurface;
 
 namespace impl {
@@ -72,6 +73,9 @@
     // Sets a debug name for the output
     virtual void setName(const std::string&) = 0;
 
+    // Gets the current render color mode for the output
+    virtual DisplayColorProfile* getDisplayColorProfile() const = 0;
+
     // Gets the current render surface for the output
     virtual RenderSurface* getRenderSurface() const = 0;
 
@@ -98,7 +102,8 @@
 protected:
     ~Output() = default;
 
-    virtual void setRenderSurface(std::unique_ptr<RenderSurface> surface) = 0;
+    virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
+    virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
 };
 
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 5609382..0e20c43 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -46,6 +46,7 @@
     bool isSecure() const override;
     bool isVirtual() const override;
     void disconnect() override;
+    void createDisplayColorProfile(compositionengine::DisplayColorProfileCreationArgs&&) override;
     void createRenderSurface(compositionengine::RenderSurfaceCreationArgs&&) override;
 
 private:
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
new file mode 100644
index 0000000..49c2d2c
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <unordered_map>
+#include <vector>
+
+#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
+#include <ui/HdrCapabilities.h>
+
+namespace android::compositionengine {
+
+class CompositionEngine;
+class Display;
+
+namespace impl {
+
+class DisplayColorProfile : public compositionengine::DisplayColorProfile {
+public:
+    DisplayColorProfile(DisplayColorProfileCreationArgs&&);
+    ~DisplayColorProfile() override;
+
+    bool isValid() const override;
+
+    bool hasRenderIntent(ui::RenderIntent intent) const override;
+    bool hasLegacyHdrSupport(ui::Dataspace dataspace) const override;
+    void getBestColorMode(ui::Dataspace dataspace, ui::RenderIntent intent,
+                          ui::Dataspace* outDataspace, ui::ColorMode* outMode,
+                          ui::RenderIntent* outIntent) const override;
+
+    bool hasWideColorGamut() const override;
+    int32_t getSupportedPerFrameMetadata() const override;
+
+    // Whether h/w composer has native support for specific HDR type.
+    bool hasHDR10PlusSupport() const override;
+    bool hasHDR10Support() const override;
+    bool hasHLGSupport() const override;
+    bool hasDolbyVisionSupport() const override;
+
+    const HdrCapabilities& getHdrCapabilities() const override;
+
+    void dump(std::string&) const override;
+
+private:
+    void populateColorModes(const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes);
+    void addColorMode(const DisplayColorProfileCreationArgs::HwcColorModes& hwcColorModes,
+                      const ui::ColorMode mode, const ui::RenderIntent intent);
+
+    // Mappings from desired Dataspace/RenderIntent to the supported
+    // Dataspace/ColorMode/RenderIntent.
+    using ColorModeKey = uint64_t;
+    struct ColorModeValue {
+        ui::Dataspace dataspace;
+        ui::ColorMode colorMode;
+        ui::RenderIntent renderIntent;
+    };
+
+    static ColorModeKey getColorModeKey(ui::Dataspace dataspace, ui::RenderIntent intent) {
+        return (static_cast<uint64_t>(dataspace) << 32) | static_cast<uint32_t>(intent);
+    }
+
+    // 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 mHasWideColorGamut{false};
+    int32_t mSupportedPerFrameMetadata{0};
+    bool mHasHdr10Plus{false};
+    bool mHasHdr10{false};
+    bool mHasHLG{false};
+    bool mHasDolbyVision{false};
+    HdrCapabilities mHdrCapabilities;
+    std::unordered_map<ColorModeKey, ColorModeValue> mColorModes;
+};
+
+std::unique_ptr<compositionengine::DisplayColorProfile> createDisplayColorProfile(
+        DisplayColorProfileCreationArgs&&);
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 86a1662..521e1d7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -48,6 +48,9 @@
     const std::string& getName() const override;
     void setName(const std::string&) override;
 
+    compositionengine::DisplayColorProfile* getDisplayColorProfile() const override;
+    void setDisplayColorProfile(std::unique_ptr<compositionengine::DisplayColorProfile>) override;
+
     compositionengine::RenderSurface* getRenderSurface() const override;
     void setRenderSurface(std::unique_ptr<compositionengine::RenderSurface>) override;
 
@@ -58,6 +61,7 @@
     bool belongsInOutput(uint32_t) const override;
 
     // Testing
+    void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
     void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
 
 protected:
@@ -73,6 +77,7 @@
 
     OutputCompositionState mState;
 
+    std::unique_ptr<compositionengine::DisplayColorProfile> mDisplayColorProfile;
     std::unique_ptr<compositionengine::RenderSurface> mRenderSurface;
 };
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
index e4adfc5..d763aa6 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -17,7 +17,7 @@
 #pragma once
 
 #include <compositionengine/Display.h>
-#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/DisplayColorProfileCreationArgs.h>
 #include <compositionengine/RenderSurfaceCreationArgs.h>
 #include <compositionengine/mock/Output.h>
 #include <gmock/gmock.h>
@@ -38,6 +38,7 @@
 
     MOCK_METHOD0(disconnect, void());
 
+    MOCK_METHOD1(createDisplayColorProfile, void(DisplayColorProfileCreationArgs&&));
     MOCK_METHOD1(createRenderSurface, void(RenderSurfaceCreationArgs&&));
 };
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
new file mode 100644
index 0000000..8056c9d
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <compositionengine/DisplayColorProfile.h>
+#include <gmock/gmock.h>
+#include <ui/HdrCapabilities.h>
+
+namespace android::compositionengine::mock {
+
+class DisplayColorProfile : public compositionengine::DisplayColorProfile {
+public:
+    DisplayColorProfile();
+    ~DisplayColorProfile() override;
+
+    MOCK_CONST_METHOD0(isValid, bool());
+
+    MOCK_CONST_METHOD1(hasRenderIntent, bool(ui::RenderIntent));
+    MOCK_CONST_METHOD1(hasLegacyHdrSupport, bool(ui::Dataspace));
+    MOCK_CONST_METHOD5(getBestColorMode,
+                       void(ui::Dataspace, ui::RenderIntent, ui::Dataspace*, ui::ColorMode*,
+                            ui::RenderIntent*));
+    MOCK_CONST_METHOD0(hasWideColorGamut, bool());
+    MOCK_CONST_METHOD0(getSupportedPerFrameMetadata, int32_t());
+    MOCK_CONST_METHOD0(hasHDR10PlusSupport, bool());
+    MOCK_CONST_METHOD0(hasHDR10Support, bool());
+    MOCK_CONST_METHOD0(hasHLGSupport, bool());
+    MOCK_CONST_METHOD0(hasDolbyVisionSupport, bool());
+
+    MOCK_CONST_METHOD0(getHdrCapabilities, const HdrCapabilities&());
+
+    MOCK_CONST_METHOD1(dump, void(std::string&));
+};
+
+} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 3f2cc05..37f7007 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <compositionengine/DisplayColorProfile.h>
 #include <compositionengine/Output.h>
 #include <compositionengine/RenderSurface.h>
 #include <compositionengine/impl/OutputCompositionState.h>
@@ -43,6 +44,9 @@
     MOCK_CONST_METHOD0(getName, const std::string&());
     MOCK_METHOD1(setName, void(const std::string&));
 
+    MOCK_CONST_METHOD0(getDisplayColorProfile, DisplayColorProfile*());
+    MOCK_METHOD1(setDisplayColorProfile, void(std::unique_ptr<DisplayColorProfile>));
+
     MOCK_CONST_METHOD0(getRenderSurface, RenderSurface*());
     MOCK_METHOD1(setRenderSurface, void(std::unique_ptr<RenderSurface>));