graphics: Add display color sampling interface.

Add a graphics.composer@2.3 interface that will expose
color sampling hardware present on some devices to the
framework. Adds:
  getDisplayedContentSamplingAttributes
  setDisplayedContentSamplingEnabled
  getDisplayedContentSample

Test: boot up pixel3
Test: VtsHalGraphicsComposerV2_3TargetTest on revved Pixel3 hwcomposer
Bug: 116028976
Change-Id: I88455f200590926f677c47efc39e9b6678e2318c
diff --git a/graphics/composer/2.3/IComposerClient.hal b/graphics/composer/2.3/IComposerClient.hal
index dec3b25..7856658 100644
--- a/graphics/composer/2.3/IComposerClient.hal
+++ b/graphics/composer/2.3/IComposerClient.hal
@@ -161,6 +161,116 @@
                                Dataspace dataspace)
                     generates (Error error);
 
+    enum FormatColorComponent : uint8_t {
+        /* The first component  (eg, for RGBA_8888, this is R) */
+        FORMAT_COMPONENT_0 = 1 << 0,
+        /* The second component (eg, for RGBA_8888, this is G) */
+        FORMAT_COMPONENT_1 = 1 << 1,
+        /* The third component  (eg, for RGBA_8888, this is B) */
+        FORMAT_COMPONENT_2 = 1 << 2,
+        /* The fourth component (eg, for RGBA_8888, this is A) */
+        FORMAT_COMPONENT_3 = 1 << 3,
+    };
+
+    /**
+     * Query for what types of color sampling the hardware supports.
+     *
+     * @param  display        is the display where the samples are collected.
+     * @return error          is NONE upon success. Otherwise,
+     *                        BAD_DISPLAY when an invalid display was passed in, or
+     *                        UNSUPPORTED when there is no efficient way to sample.
+     * @return format         The format of the sampled pixels.
+     * @return dataspace      The dataspace of the sampled pixels.
+     * @return componentMask  The mask of which components can be sampled.
+     */
+    getDisplayedContentSamplingAttributes(Display display)
+               generates (Error error,
+                          PixelFormat format,
+                          Dataspace dataspace,
+                          bitfield<FormatColorComponent> componentMask);
+
+    /** DisplayedContentSampling values passed to setDisplayedContentSamplingEnabled. */
+    enum DisplayedContentSampling : int32_t {
+        INVALID = 0,
+
+        /** Enable content sampling. */
+        ENABLE = 1,
+
+        /** Disable content sampling. */
+        DISABLE = 2,
+    };
+
+    /**
+     * Enables or disables the collection of color content statistics
+     * on this display.
+     *
+     * Sampling occurs on the contents of the final composition on this display
+     * (i.e., the contents presented on screen). Samples should be collected after all
+     * color transforms have been applied.
+     *
+     * Sampling support is optional, and is set to DISABLE by default.
+     * On each call to ENABLE, all collected statistics must be reset.
+     *
+     * Sample data can be queried via getDisplayedContentSample().
+     *
+     * @param display        is the display to which the sampling mode is set.
+     * @param enabled        indicates whether to enable or disable sampling.
+     * @param componentMask  The mask of which components should be sampled. If zero, all supported
+     *                       components are to be enabled.
+     * @param maxFrames      is the maximum number of frames that should be stored before discard.
+     *                       The sample represents the most-recently posted frames.
+     * @return error      is NONE upon success. Otherwise,
+     *                    BAD_DISPLAY when an invalid display handle was passed in,
+     *                    BAD_PARAMETER when enabled was an invalid value, or
+     *                    NO_RESOURCES when the requested ringbuffer size via maxFrames was
+     *                                 not available.
+     *                    UNSUPPORTED when there is no efficient way to sample.
+     */
+    setDisplayedContentSamplingEnabled(
+        Display display, DisplayedContentSampling enable,
+        bitfield<FormatColorComponent> componentMask, uint64_t maxFrames)
+        generates (Error error);
+
+    /**
+     * Collects the results of display content color sampling for display.
+     *
+     * Collection of data can occur whether the sampling is in ENABLE or
+     * DISABLE state.
+     *
+     * @param  display     is the display to which the sampling is collected.
+     * @param  maxFrames   is the maximum number of frames that should be represented in the sample.
+     *                     The sample represents the most-recently posted frames.
+     *                     If maxFrames is 0, all frames are to be represented by the sample.
+     * @param  timestamp   is the timestamp after which any frames were posted that should be
+     *                     included in the sample. Timestamp is CLOCK_MONOTONIC.
+     *                     If timestamp is 0, do not filter from the sample by time.
+     * @return error       is NONE upon success. Otherwise,
+     *                     BAD_DISPLAY   when an invalid display was passed in, or
+     *                     UNSUPPORTED   when there is no efficient way to sample, or
+     *                     BAD_PARAMETER when the component is not supported by the hardware.
+     * @return frameCount  The number of frames represented by this sample.
+     * @return sampleComponent0 is a histogram counting how many times a pixel of a given value
+     *                     was displayed onscreen for FORMAT_COMPONENT_0.
+     *                     The buckets of the histogram are evenly weighted, the number of buckets
+     *                     is device specific.
+     *                     eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that
+     *                     10 red pixels were displayed onscreen in range 0x00->0x3F, 6 red pixels
+     *                     were displayed onscreen in range 0x40->0x7F, etc.
+     * @return sampleComponent1 is the same sample definition as sampleComponent0,
+     *                     but for FORMAT_COMPONENT_1.
+     * @return sampleComponent2 is the same sample definition as sampleComponent0,
+     *                     but for FORMAT_COMPONENT_2.
+     * @return sampleComponent3 is the same sample definition as sampleComponent0,
+     *                     but for FORMAT_COMPONENT_3.
+     */
+    getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp)
+               generates (Error error,
+                          uint64_t frameCount,
+                          vec<uint64_t> sampleComponent0,
+                          vec<uint64_t> sampleComponent1,
+                          vec<uint64_t> sampleComponent2,
+                          vec<uint64_t> sampleComponent3);
+
     /**
      * Executes commands from the input command message queue. Return values
      * generated by the input commands are written to the output command
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
index f9d6774..be0ef4c 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
@@ -91,6 +91,42 @@
         return Void();
     }
 
+    Return<void> getDisplayedContentSamplingAttributes(
+        uint64_t display,
+        IComposerClient::getDisplayedContentSamplingAttributes_cb hidl_cb) override {
+        common::V1_1::PixelFormat format;
+        common::V1_2::Dataspace dataspace;
+        hidl_bitfield<IComposerClient::FormatColorComponent> componentMask;
+        Error error =
+            mHal->getDisplayedContentSamplingAttributes(display, format, dataspace, componentMask);
+        hidl_cb(error, format, dataspace, componentMask);
+        return Void();
+    }
+
+    Return<Error> setDisplayedContentSamplingEnabled(
+        uint64_t display, IComposerClient::DisplayedContentSampling enable,
+        hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
+        uint64_t maxFrames) override {
+        return mHal->setDisplayedContentSamplingEnabled(display, enable, componentMask, maxFrames);
+    }
+
+    Return<void> getDisplayedContentSample(
+        uint64_t display, uint64_t maxFrames, uint64_t timestamp,
+        IComposerClient::getDisplayedContentSample_cb hidl_cb) override {
+        uint64_t frameCount;
+        hidl_vec<uint64_t> sampleComponent0;
+        hidl_vec<uint64_t> sampleComponent1;
+        hidl_vec<uint64_t> sampleComponent2;
+        hidl_vec<uint64_t> sampleComponent3;
+
+        Error error = mHal->getDisplayedContentSample(display, maxFrames, timestamp, frameCount,
+                                                      sampleComponent0, sampleComponent1,
+                                                      sampleComponent2, sampleComponent3);
+        hidl_cb(error, frameCount, sampleComponent0, sampleComponent1, sampleComponent2,
+                sampleComponent3);
+        return Void();
+    }
+
     Return<void> executeCommands_2_3(uint32_t inLength, const hidl_vec<hidl_handle>& inHandles,
                                      IComposerClient::executeCommands_2_2_cb hidl_cb) override {
         std::lock_guard<std::mutex> lock(mCommandEngineMutex);
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
index 27efc2b..8ca5d75 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
@@ -72,6 +72,18 @@
     virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort,
                                                std::vector<uint8_t>* outData) = 0;
     virtual Error setLayerColorTransform(Display display, Layer layer, const float* matrix) = 0;
+    virtual Error getDisplayedContentSamplingAttributes(
+        uint64_t display, PixelFormat& format, Dataspace& dataspace,
+        hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) = 0;
+    virtual Error setDisplayedContentSamplingEnabled(
+        uint64_t display, IComposerClient::DisplayedContentSampling enable,
+        hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames) = 0;
+    virtual Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames,
+                                            uint64_t timestamp, uint64_t& frameCount,
+                                            hidl_vec<uint64_t>& sampleComponent0,
+                                            hidl_vec<uint64_t>& sampleComponent1,
+                                            hidl_vec<uint64_t>& sampleComponent2,
+                                            hidl_vec<uint64_t>& sampleComponent3) = 0;
 };
 
 }  // namespace hal
diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
index df68f58..8d444c8 100644
--- a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
+++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
@@ -104,6 +104,65 @@
         return static_cast<Error>(err);
     }
 
+    Error getDisplayedContentSamplingAttributes(
+        uint64_t display, PixelFormat& format, Dataspace& dataspace,
+        hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) override {
+        if (!mDispatch.getDisplayedContentSamplingAttributes) {
+            return Error::UNSUPPORTED;
+        }
+        int32_t formatRaw = 0;
+        int32_t dataspaceRaw = 0;
+        uint8_t componentMaskRaw = 0;
+        int32_t errorRaw = mDispatch.getDisplayedContentSamplingAttributes(
+            mDevice, display, &formatRaw, &dataspaceRaw, &componentMaskRaw);
+        auto error = static_cast<Error>(errorRaw);
+        if (error == Error::NONE) {
+            format = static_cast<PixelFormat>(formatRaw);
+            dataspace = static_cast<Dataspace>(dataspaceRaw);
+            componentMask =
+                static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(componentMaskRaw);
+        }
+        return error;
+    };
+
+    Error setDisplayedContentSamplingEnabled(
+        uint64_t display, IComposerClient::DisplayedContentSampling enable,
+        hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
+        uint64_t maxFrames) override {
+        if (!mDispatch.setDisplayedContentSamplingEnabled) {
+            return Error::UNSUPPORTED;
+        }
+        return static_cast<Error>(mDispatch.setDisplayedContentSamplingEnabled(
+            mDevice, display, static_cast<int32_t>(enable), componentMask, maxFrames));
+    }
+
+    Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp,
+                                    uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0,
+                                    hidl_vec<uint64_t>& sampleComponent1,
+                                    hidl_vec<uint64_t>& sampleComponent2,
+                                    hidl_vec<uint64_t>& sampleComponent3) override {
+        if (!mDispatch.getDisplayedContentSample) {
+            return Error::UNSUPPORTED;
+        }
+
+        int32_t size[4] = {0};
+        auto errorRaw = mDispatch.getDisplayedContentSample(mDevice, display, maxFrames, timestamp,
+                                                            &frameCount, size, nullptr);
+        if (errorRaw != HWC2_ERROR_NONE) {
+            return static_cast<Error>(errorRaw);
+        }
+
+        sampleComponent0.resize(size[0]);
+        sampleComponent1.resize(size[1]);
+        sampleComponent2.resize(size[2]);
+        sampleComponent3.resize(size[3]);
+        uint64_t* samples[] = {sampleComponent0.data(), sampleComponent1.data(),
+                               sampleComponent2.data(), sampleComponent3.data()};
+        errorRaw = mDispatch.getDisplayedContentSample(mDevice, display, maxFrames, timestamp,
+                                                       &frameCount, size, samples);
+        return static_cast<Error>(errorRaw);
+    }
+
    protected:
     bool initDispatch() override {
         if (!BaseType2_2::initDispatch()) {
@@ -114,6 +173,12 @@
                                    &mDispatch.getDisplayIdentificationData);
         this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM,
                                    &mDispatch.setLayerColorTransform);
+        this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
+                                   &mDispatch.getDisplayedContentSamplingAttributes);
+        this->initOptionalDispatch(HWC2_FUNCTION_SET_DISPLAYED_CONTENT_SAMPLING_ENABLED,
+                                   &mDispatch.setDisplayedContentSamplingEnabled);
+        this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAYED_CONTENT_SAMPLE,
+                                   &mDispatch.getDisplayedContentSample);
         return true;
     }
 
@@ -121,6 +186,9 @@
     struct {
         HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA getDisplayIdentificationData;
         HWC2_PFN_SET_LAYER_COLOR_TRANSFORM setLayerColorTransform;
+        HWC2_PFN_GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES getDisplayedContentSamplingAttributes;
+        HWC2_PFN_SET_DISPLAYED_CONTENT_SAMPLING_ENABLED setDisplayedContentSamplingEnabled;
+        HWC2_PFN_GET_DISPLAYED_CONTENT_SAMPLE getDisplayedContentSample;
     } mDispatch = {};
 
     using BaseType2_2 = V2_2::passthrough::detail::HwcHalImpl<Hal>;
diff --git a/graphics/composer/2.3/utils/vts/ComposerVts.cpp b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
index 656c8c4..9304992 100644
--- a/graphics/composer/2.3/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
@@ -108,6 +108,48 @@
     return error == Error::NONE;
 }
 
+Error ComposerClient::getDisplayedContentSamplingAttributes(
+    uint64_t display, PixelFormat& format, Dataspace& dataspace,
+    hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) {
+    auto error = Error::BAD_PARAMETER;
+    mClient->getDisplayedContentSamplingAttributes(
+        display, [&](const auto& tmpError, const auto& tmpFormat, const auto& tmpDataspace,
+                     const auto& tmpComponentMask) {
+            error = tmpError;
+            format = tmpFormat;
+            dataspace = tmpDataspace;
+            componentMask = tmpComponentMask;
+        });
+    return error;
+}
+
+Error ComposerClient::setDisplayedContentSamplingEnabled(
+    uint64_t display, IComposerClient::DisplayedContentSampling enable,
+    hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames) {
+    return mClient->setDisplayedContentSamplingEnabled(display, enable, componentMask, maxFrames);
+}
+
+Error ComposerClient::getDisplayedContentSample(uint64_t display, uint64_t maxFrames,
+                                                uint64_t timestamp, uint64_t& frameCount,
+                                                hidl_vec<uint64_t>& sampleComponent0,
+                                                hidl_vec<uint64_t>& sampleComponent1,
+                                                hidl_vec<uint64_t>& sampleComponent2,
+                                                hidl_vec<uint64_t>& sampleComponent3) {
+    auto error = Error::BAD_PARAMETER;
+    mClient->getDisplayedContentSample(
+        display, maxFrames, timestamp,
+        [&](const auto& tmpError, const auto& tmpFrameCount, const auto& tmpSamples0,
+            const auto& tmpSamples1, const auto& tmpSamples2, const auto& tmpSamples3) {
+            error = tmpError;
+            frameCount = tmpFrameCount;
+            sampleComponent0 = tmpSamples0;
+            sampleComponent1 = tmpSamples1;
+            sampleComponent2 = tmpSamples2;
+            sampleComponent3 = tmpSamples3;
+        });
+    return error;
+}
+
 }  // namespace vts
 }  // namespace V2_3
 }  // namespace composer
diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
index ec1a2a1..4b9c955 100644
--- a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
+++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
@@ -37,6 +37,7 @@
 using common::V1_2::ColorMode;
 using common::V1_2::Dataspace;
 using V2_1::Display;
+using V2_1::Error;
 using V2_3::IComposer;
 using V2_3::IComposerClient;
 
@@ -67,6 +68,17 @@
 
     bool getDisplayIdentificationData(Display display, uint8_t* outPort,
                                       std::vector<uint8_t>* outData);
+    Error getDisplayedContentSamplingAttributes(
+        uint64_t display, PixelFormat& format, Dataspace& dataspace,
+        hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask);
+    Error setDisplayedContentSamplingEnabled(
+        uint64_t display, IComposerClient::DisplayedContentSampling enable,
+        hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames);
+    Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp,
+                                    uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0,
+                                    hidl_vec<uint64_t>& sampleComponent1,
+                                    hidl_vec<uint64_t>& sampleComponent2,
+                                    hidl_vec<uint64_t>& sampleComponent3);
 
     std::vector<ColorMode> getColorModes_2_3(Display display);
 
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
index 3ca21aa..a294825 100644
--- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -355,6 +355,78 @@
     execute();
 }
 
+TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) {
+    using common::V1_1::PixelFormat;
+    using common::V1_2::Dataspace;
+
+    int constexpr invalid = -1;
+    auto format = static_cast<PixelFormat>(invalid);
+    auto dataspace = static_cast<Dataspace>(invalid);
+    auto componentMask = static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid);
+    auto error = mComposerClient->getDisplayedContentSamplingAttributes(mPrimaryDisplay, format,
+                                                                        dataspace, componentMask);
+
+    if (error == Error::UNSUPPORTED) {
+        SUCCEED() << "Device does not support optional extension. Test skipped";
+        return;
+    }
+
+    EXPECT_EQ(error, Error::NONE);
+    EXPECT_NE(format, static_cast<PixelFormat>(invalid));
+    EXPECT_NE(dataspace, static_cast<Dataspace>(invalid));
+    EXPECT_NE(componentMask,
+              static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid));
+};
+
+TEST_F(GraphicsComposerHidlTest, SetDisplayedContentSamplingEnabled) {
+    auto const maxFrames = 10;
+    auto const enableAllComponents = 0;
+    auto error = mComposerClient->setDisplayedContentSamplingEnabled(
+        mPrimaryDisplay, IComposerClient::DisplayedContentSampling::ENABLE, enableAllComponents,
+        maxFrames);
+    if (error == Error::UNSUPPORTED) {
+        SUCCEED() << "Device does not support optional extension. Test skipped";
+        return;
+    }
+    EXPECT_EQ(error, Error::NONE);
+
+    error = mComposerClient->setDisplayedContentSamplingEnabled(
+        mPrimaryDisplay, IComposerClient::DisplayedContentSampling::DISABLE, enableAllComponents,
+        maxFrames);
+    EXPECT_EQ(error, Error::NONE);
+}
+
+TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSample) {
+    int constexpr invalid = -1;
+    auto format = static_cast<PixelFormat>(invalid);
+    auto dataspace = static_cast<Dataspace>(invalid);
+    auto componentMask = static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid);
+    auto error = mComposerClient->getDisplayedContentSamplingAttributes(mPrimaryDisplay, format,
+                                                                        dataspace, componentMask);
+
+    uint64_t maxFrames = 10;
+    uint64_t timestamp = 0;
+    uint64_t frameCount = 0;
+    hidl_array<hidl_vec<uint64_t>, 4> histogram;
+    error = mComposerClient->getDisplayedContentSample(mPrimaryDisplay, maxFrames, timestamp,
+                                                       frameCount, histogram[0], histogram[1],
+                                                       histogram[2], histogram[3]);
+    if (error == Error::UNSUPPORTED) {
+        SUCCEED() << "Device does not support optional extension. Test skipped";
+        return;
+    }
+
+    EXPECT_EQ(error, Error::NONE);
+    EXPECT_LE(frameCount, maxFrames);
+    for (auto i = 0; i < histogram.size(); i++) {
+        if (componentMask & (1 << i)) {
+            EXPECT_NE(histogram[i].size(), 0);
+        } else {
+            EXPECT_EQ(histogram[i].size(), 0);
+        }
+    }
+}
+
 }  // namespace
 }  // namespace vts
 }  // namespace V2_3