[Graphics] Add setLayerColorTransform.

This patch adds HAL API to set per-layer color transformation with a 4x4
matrix. Given a 4x4 matrix, the matrix will be applied on the current layer
before composition.

BUG: 111562338
Test: Build, flash and boot, run VtsHalGraphicsComposerV2_3TargetTest
Change-Id: I673cfc2745d35947107dcab19f383ba5a8067605
diff --git a/graphics/composer/2.3/Android.bp b/graphics/composer/2.3/Android.bp
index 23061dd..78da099 100644
--- a/graphics/composer/2.3/Android.bp
+++ b/graphics/composer/2.3/Android.bp
@@ -12,6 +12,7 @@
     ],
     interfaces: [
         "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hidl.base@1.0",
diff --git a/graphics/composer/2.3/IComposerClient.hal b/graphics/composer/2.3/IComposerClient.hal
index 77dd3ee..089438e 100644
--- a/graphics/composer/2.3/IComposerClient.hal
+++ b/graphics/composer/2.3/IComposerClient.hal
@@ -16,12 +16,58 @@
 
 package android.hardware.graphics.composer@2.3;
 
+import android.hardware.graphics.composer@2.1::IComposerClient.Command;
 import @2.2::IComposerClient;
 import @2.1::Display;
 import @2.1::Error;
 
 interface IComposerClient extends @2.2::IComposerClient {
 
+    enum Command : @2.2::IComposerClient.Command {
+        /**
+         * SET_LAYER_COLOR_TRANSFORM has this pseudo prototype
+         *
+         *   setLayerColorTransform(float[16] matrix);
+         *
+         * This command has the following binary layout in bytes:
+         *
+         *     0 - 16 * 4: matrix
+         *
+         * Sets a matrix for color transform which will be applied on this layer
+         * before composition.
+         *
+         * If the device is not capable of apply the matrix on this layer, it must force
+         * this layer to client composition during VALIDATE_DISPLAY.
+         *
+         * The matrix provided is an affine color transformation of the following
+         * form:
+         *
+         * |r.r r.g r.b 0|
+         * |g.r g.g g.b 0|
+         * |b.r b.g b.b 0|
+         * |Tr  Tg  Tb  1|
+         *
+         * This matrix must be provided in row-major form:
+         *
+         * {r.r, r.g, r.b, 0, g.r, ...}.
+         *
+         * Given a matrix of this form and an input color [R_in, G_in, B_in],
+         * the input color must first be converted to linear space
+         * [R_linear, G_linear, B_linear], then the output linear color
+         * [R_out_linear, G_out_linear, B_out_linear] will be:
+         *
+         * R_out_linear = R_linear * r.r + G_linear * g.r + B_linear * b.r + Tr
+         * G_out_linear = R_linear * r.g + G_linear * g.g + B_linear * b.g + Tg
+         * B_out_linear = R_linear * r.b + G_linear * g.b + B_linear * b.b + Tb
+         *
+         * [R_out_linear, G_out_linear, B_out_linear] must then be converted to
+         * gamma space: [R_out, G_out, B_out] before blending.
+         *
+         * @param matrix is a 4x4 transform matrix (16 floats) as described above.
+         */
+        SET_LAYER_COLOR_TRANSFORM = 0x40d << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+    };
+
     /**
      * Returns the port and data that describe a physical display. The port is
      * a unique number that identifies a physical connector (e.g. eDP, HDMI)
@@ -42,4 +88,29 @@
                           uint8_t port,
                           vec<uint8_t> data);
 
+    /**
+     * Executes commands from the input command message queue. Return values
+     * generated by the input commands are written to the output command
+     * message queue in the form of value commands.
+     *
+     * @param inLength is the length of input commands.
+     * @param inHandles is an array of handles referenced by the input
+     *        commands.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_PARAMETER when inLength is not equal to the length of
+     *                       commands in the input command message queue.
+     *         NO_RESOURCES when the output command message queue was not
+     *                      properly drained.
+     * @param outQueueChanged indicates whether the output command message
+     *        queue has changed.
+     * @param outLength is the length of output commands.
+     * @param outHandles is an array of handles referenced by the output
+     *        commands.
+     */
+    executeCommands_2_3(uint32_t inLength,
+                        vec<handle> inHandles)
+             generates (Error error,
+                        bool outQueueChanged,
+                        uint32_t outLength,
+                        vec<handle> outHandles);
 };
diff --git a/graphics/composer/2.3/utils/command-buffer/Android.bp b/graphics/composer/2.3/utils/command-buffer/Android.bp
new file mode 100644
index 0000000..c48fe7a
--- /dev/null
+++ b/graphics/composer/2.3/utils/command-buffer/Android.bp
@@ -0,0 +1,15 @@
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.3-command-buffer",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.3",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
new file mode 100644
index 0000000..3f7b2c9
--- /dev/null
+++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2018 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
+
+#ifndef LOG_TAG
+#warn "ComposerCommandBuffer.h included without LOG_TAG"
+#endif
+
+#undef LOG_NDEBUG
+#define LOG_NDEBUG 0
+
+#include <android/hardware/graphics/composer/2.3/IComposer.h>
+#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+
+using android::hardware::MessageQueue;
+using android::hardware::graphics::composer::V2_1::Error;
+using android::hardware::graphics::composer::V2_1::IComposerCallback;
+using android::hardware::graphics::composer::V2_1::Layer;
+using android::hardware::graphics::composer::V2_3::IComposerClient;
+
+// This class helps build a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandWriterBase : public V2_2::CommandWriterBase {
+   public:
+    CommandWriterBase(uint32_t initialMaxSize) : V2_2::CommandWriterBase(initialMaxSize) {}
+
+    static constexpr uint16_t kSetLayerColorTransformLength = 16;
+    void setLayerColorTransform(const float* matrix) {
+        beginCommand_2_3(IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM,
+                         kSetLayerColorTransformLength);
+        for (int i = 0; i < 16; i++) {
+            writeFloat(matrix[i]);
+        }
+        endCommand();
+    }
+
+   protected:
+    void beginCommand_2_3(IComposerClient::Command command, uint16_t length) {
+        V2_2::CommandWriterBase::beginCommand_2_2(
+            static_cast<V2_2::IComposerClient::Command>(static_cast<int32_t>(command)), length);
+    }
+};
+
+// This class helps parse a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandReaderBase : public V2_2::CommandReaderBase {
+   public:
+    CommandReaderBase() : V2_2::CommandReaderBase(){};
+};
+
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/hal/Android.bp b/graphics/composer/2.3/utils/hal/Android.bp
index aa46df1..3ee9300 100644
--- a/graphics/composer/2.3/utils/hal/Android.bp
+++ b/graphics/composer/2.3/utils/hal/Android.bp
@@ -26,9 +26,11 @@
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.2-hal",
+        "android.hardware.graphics.composer@2.3-command-buffer",
     ],
     export_header_lib_headers: [
         "android.hardware.graphics.composer@2.2-hal",
+        "android.hardware.graphics.composer@2.3-command-buffer",
     ],
     export_include_dirs: ["include"],
 }
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 e717d84..c805472 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
@@ -22,6 +22,7 @@
 
 #include <android/hardware/graphics/composer/2.3/IComposerClient.h>
 #include <composer-hal/2.3/ComposerClient.h>
+#include <composer-hal/2.3/ComposerCommandEngine.h>
 #include <composer-hal/2.3/ComposerHal.h>
 
 namespace android {
@@ -55,10 +56,27 @@
         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);
+        bool outChanged = false;
+        uint32_t outLength = 0;
+        hidl_vec<hidl_handle> outHandles;
+        Error error =
+            mCommandEngine->execute(inLength, inHandles, &outChanged, &outLength, &outHandles);
+
+        hidl_cb(error, outChanged, outLength, outHandles);
+
+        mCommandEngine->reset();
+
+        return Void();
+    }
+
    private:
     using BaseType2_2 = V2_2::hal::detail::ComposerClientImpl<Interface, Hal>;
     using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
-
+    using BaseType2_1::mCommandEngine;
+    using BaseType2_1::mCommandEngineMutex;
     using BaseType2_1::mHal;
 };
 
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
new file mode 100644
index 0000000..c3dcbcd
--- /dev/null
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 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
+
+#ifndef LOG_TAG
+#warning "ComposerCommandEngine.h included without LOG_TAG"
+#endif
+
+#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
+#include <composer-hal/2.1/ComposerCommandEngine.h>
+#include <composer-hal/2.2/ComposerCommandEngine.h>
+#include <composer-hal/2.2/ComposerResources.h>
+#include <composer-hal/2.3/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace hal {
+
+class ComposerCommandEngine : public V2_2::hal::ComposerCommandEngine {
+   public:
+    ComposerCommandEngine(ComposerHal* hal, V2_2::hal::ComposerResources* resources)
+        : BaseType2_2(hal, resources), mHal(hal) {}
+
+   protected:
+    bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override {
+        switch (static_cast<IComposerClient::Command>(command)) {
+            case IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM:
+                return executeSetLayerColorTransform(length);
+            default:
+                return BaseType2_2::executeCommand(command, length);
+        }
+    }
+
+    bool executeSetLayerColorTransform(uint16_t length) {
+        if (length != CommandWriterBase::kSetLayerColorTransformLength) {
+            return false;
+        }
+
+        float matrix[16];
+        for (int i = 0; i < 16; i++) {
+            matrix[i] = readFloat();
+        }
+        auto err = mHal->setLayerColorTransform(mCurrentDisplay, mCurrentLayer, matrix);
+        if (err != Error::NONE) {
+            mWriter.setError(getCommandLoc(), err);
+        }
+
+        return true;
+    }
+
+   private:
+    using BaseType2_1 = V2_1::hal::ComposerCommandEngine;
+    using BaseType2_1::mWriter;
+    using BaseType2_2 = V2_2::hal::ComposerCommandEngine;
+
+    ComposerHal* mHal;
+};
+
+}  // namespace hal
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
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 37ea0a3..0f6205a 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
@@ -27,11 +27,13 @@
 
 using V2_1::Display;
 using V2_1::Error;
+using V2_1::Layer;
 
 class ComposerHal : public V2_2::hal::ComposerHal {
    public:
     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;
 };
 
 }  // 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 53f2d1b..ed1878b 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
@@ -66,6 +66,14 @@
         return Error::NONE;
     }
 
+    Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override {
+        if (!mDispatch.setLayerColorTransform) {
+            return Error::UNSUPPORTED;
+        }
+        int32_t err = mDispatch.setLayerColorTransform(mDevice, display, layer, matrix);
+        return static_cast<Error>(err);
+    }
+
    protected:
     bool initDispatch() override {
         if (!BaseType2_2::initDispatch()) {
@@ -74,12 +82,15 @@
 
         this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA,
                                    &mDispatch.getDisplayIdentificationData);
+        this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM,
+                                   &mDispatch.setLayerColorTransform);
         return true;
     }
 
    private:
     struct {
         HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA getDisplayIdentificationData;
+        HWC2_PFN_SET_LAYER_COLOR_TRANSFORM setLayerColorTransform;
     } mDispatch = {};
 
     using BaseType2_2 = V2_2::passthrough::detail::HwcHalImpl<Hal>;
diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp
index 0553258..19438cb 100644
--- a/graphics/composer/2.3/utils/vts/Android.bp
+++ b/graphics/composer/2.3/utils/vts/Android.bp
@@ -31,6 +31,7 @@
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
         "android.hardware.graphics.composer@2.2-command-buffer",
+        "android.hardware.graphics.composer@2.3-command-buffer",
     ],
     cflags: [
         "-O0",
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index df696c9..7548cb5 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -40,5 +40,6 @@
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
         "android.hardware.graphics.composer@2.2-command-buffer",
+        "android.hardware.graphics.composer@2.3-command-buffer",
     ],
 }
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
index f4e34f0..1030ddc 100644
--- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -20,7 +20,9 @@
 
 #include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
+#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
 #include <composer-vts/2.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.1/TestCommandReader.h>
 #include <composer-vts/2.3/ComposerVts.h>
 
 namespace android {
@@ -65,6 +67,9 @@
         // explicitly disable vsync
         mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
         mComposerCallback->setVsyncAllowed(false);
+
+        mWriter = std::make_unique<CommandWriterBase>(1024);
+        mReader = std::make_unique<V2_1::vts::TestCommandReader>();
     }
 
     void TearDown() override {
@@ -75,11 +80,18 @@
         }
     }
 
+    void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+
+    // use the slot count usually set by SF
+    static constexpr uint32_t kBufferSlotCount = 64;
+
     std::unique_ptr<Composer> mComposer;
     std::unique_ptr<ComposerClient> mComposerClient;
     sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
     // the first display and is assumed never to be removed
     Display mPrimaryDisplay;
+    std::unique_ptr<CommandWriterBase> mWriter;
+    std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
 
    private:
     Display waitForFirstDisplay() {
@@ -115,6 +127,31 @@
     }
 }
 
+/**
+ * Test IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM.
+ * TODO Add color to the layer, use matrix to keep only red component,
+ * and check.
+ */
+TEST_F(GraphicsComposerHidlTest, SetLayerColorTransform) {
+    Layer layer;
+    ASSERT_NO_FATAL_FAILURE(layer =
+                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(layer);
+
+    // clang-format off
+    const std::array<float, 16> matrix = {{
+        1.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 1.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 1.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 1.0f,
+    }};
+    // clang-format on
+
+    mWriter->setLayerColorTransform(matrix.data());
+    execute();
+}
+
 }  // namespace
 }  // namespace vts
 }  // namespace V2_3