Hardware composer VTS test harness

Bug: 111563608
Test: VtsHalGraphicsComposerV2_2TargetTest
Change-Id: I965efe8811e45a114978a9c8dd7a440c759787ec
diff --git a/graphics/composer/2.1/utils/vts/TestCommandReader.cpp b/graphics/composer/2.1/utils/vts/TestCommandReader.cpp
index 6f8f1ad..e1dc5b6 100644
--- a/graphics/composer/2.1/utils/vts/TestCommandReader.cpp
+++ b/graphics/composer/2.1/utils/vts/TestCommandReader.cpp
@@ -26,23 +26,53 @@
 namespace vts {
 
 void TestCommandReader::parse() {
+    mCompositionChanges.clear();
     while (!isEmpty()) {
         IComposerClient::Command command;
         uint16_t length;
         ASSERT_TRUE(beginCommand(&command, &length));
 
         switch (command) {
+            case IComposerClient::Command::SELECT_DISPLAY:
+                ASSERT_EQ(2, length);
+                read64();  // display
+                break;
             case IComposerClient::Command::SET_ERROR: {
                 ASSERT_EQ(2, length);
                 auto loc = read();
                 auto err = readSigned();
                 GTEST_FAIL() << "unexpected error " << err << " at location " << loc;
             } break;
-            case IComposerClient::Command::SELECT_DISPLAY:
             case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES:
+                ASSERT_EQ(0, length % 3);
+                for (uint16_t count = 0; count < length / 3; ++count) {
+                    uint64_t layerId = read64();
+                    uint32_t composition = read();
+
+                    std::pair<uint64_t, uint32_t> compositionChange(layerId, composition);
+                    mCompositionChanges.push_back(compositionChange);
+                }
+                break;
             case IComposerClient::Command::SET_DISPLAY_REQUESTS:
+                ASSERT_EQ(1, length % 3);
+                read();  // displayRequests, ignored for now
+                for (uint16_t count = 0; count < (length - 1) / 3; ++count) {
+                    read64();  // layer
+                    // silently eat requests to clear the client target, since we won't be testing
+                    // client composition anyway
+                    ASSERT_EQ(1u, read());
+                }
+                break;
             case IComposerClient::Command::SET_PRESENT_FENCE:
+                ASSERT_EQ(1, length);
+                close(readFence());
+                break;
             case IComposerClient::Command::SET_RELEASE_FENCES:
+                ASSERT_EQ(0, length % 3);
+                for (uint16_t count = 0; count < length / 3; ++count) {
+                    read64();
+                    close(readFence());
+                }
                 break;
             default:
                 GTEST_FAIL() << "unexpected return command " << std::hex
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
index 3888eeb..b9a4a5c 100644
--- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
@@ -32,6 +32,8 @@
     // Parse all commands in the return command queue.  Call GTEST_FAIL() for
     // unexpected errors or commands.
     void parse();
+
+    std::vector<std::pair<uint64_t, uint32_t>> mCompositionChanges;
 };
 
 }  // namespace vts
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index f2596a4..459e0fe 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -138,12 +138,11 @@
 }
 
 void ComposerClient::getReadbackBufferFence(Display display, int32_t* outFence) {
-    hidl_handle handle;
     mClient->getReadbackBufferFence(display, [&](const auto& tmpError, const auto& tmpHandle) {
         ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback fence";
-        handle = tmpHandle;
+        const native_handle_t* nativeFenceHandle = tmpHandle.getNativeHandle();
+        *outFence = dup(nativeFenceHandle->data[0]);
     });
-    *outFence = 0;
 }
 
 std::vector<ColorMode> ComposerClient::getColorModes(Display display) {
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index 669fbae..acc9245 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -17,12 +17,15 @@
 cc_test {
     name: "VtsHalGraphicsComposerV2_2TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
-    srcs: ["VtsHalGraphicsComposerV2_2TargetTest.cpp"],
+    srcs: [
+        "VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
+        "VtsHalGraphicsComposerV2_2TargetTest.cpp",
+    ],
 
     // TODO(b/64437680): Assume these libs are always available on the device.
     shared_libs: [
         "libfmq",
-	"libhidltransport",
+        "libhidltransport",
         "libsync",
     ],
     static_libs: [
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
new file mode 100644
index 0000000..fc32951
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -0,0 +1,312 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "graphics_composer_hidl_hal_readback_tests@2.2"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/unique_fd.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <composer-vts/2.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+#include <composer-vts/2.2/ComposerVts.h>
+#include <mapper-vts/2.1/MapperVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+namespace {
+
+using android::hardware::hidl_handle;
+using common::V1_1::BufferUsage;
+using common::V1_1::Dataspace;
+using common::V1_1::PixelFormat;
+using mapper::V2_1::IMapper;
+using mapper::V2_1::vts::Gralloc;
+using V2_1::Display;
+using V2_1::Layer;
+using V2_1::vts::TestCommandReader;
+
+// Test environment for graphics.composer
+class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static GraphicsComposerHidlEnvironment* Instance() {
+        static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment;
+        return instance;
+    }
+    virtual void registerTestServices() override { registerTestService<IComposer>(); }
+
+   private:
+    GraphicsComposerHidlEnvironment() {}
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
+};
+
+class TestLayer {
+   public:
+    TestLayer(std::shared_ptr<ComposerClient> const client, Display display)
+        : mLayer(client->createLayer(display, kBufferSlotCount)),
+          mComposerClient(client),
+          mDisplay(display) {}
+
+    virtual ~TestLayer() { mComposerClient->destroyLayer(mDisplay, mLayer); }
+
+    virtual void write(std::shared_ptr<CommandWriterBase> writer) {
+        writer->selectLayer(mLayer);
+        writer->setLayerDisplayFrame(mDisplayFrame);
+        writer->setLayerZOrder(mZOrder);
+    }
+
+    void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; }
+    void setZOrder(uint32_t z) { mZOrder = z; }
+
+   protected:
+    Layer mLayer;
+    IComposerClient::Rect mDisplayFrame = {0, 0, 0, 0};
+    uint32_t mZOrder = 0;
+
+   private:
+    std::shared_ptr<ComposerClient> const mComposerClient;
+    const Display mDisplay;
+    static constexpr uint32_t kBufferSlotCount = 64;
+};
+
+class TestColorLayer : public TestLayer {
+   public:
+    TestColorLayer(std::shared_ptr<ComposerClient> const client, Display display)
+        : TestLayer{client, display} {}
+
+    void write(std::shared_ptr<CommandWriterBase> writer) override {
+        TestLayer::write(writer);
+        writer->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
+        writer->setLayerColor(mColor);
+    }
+
+    void setColor(IComposerClient::Color color) { mColor = color; }
+
+   private:
+    IComposerClient::Color mColor = {0xff, 0xff, 0xff, 0xff};
+};
+
+class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase {
+   protected:
+    using PowerMode = V2_1::IComposerClient::PowerMode;
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(
+            mComposer = std::make_unique<Composer>(
+                GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+        ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
+        mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
+        mComposerClient->registerCallback(mComposerCallback);
+
+        // assume the first display is primary and is never removed
+        mPrimaryDisplay = waitForFirstDisplay();
+        Config activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay);
+        width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig,
+                                                     IComposerClient::Attribute::WIDTH);
+        height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig,
+                                                      IComposerClient::Attribute::HEIGHT);
+
+        // explicitly disable vsync
+        mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
+        mComposerCallback->setVsyncAllowed(false);
+
+        // set up command writer/reader and gralloc
+        mWriter = std::make_shared<CommandWriterBase>(1024);
+        mReader = std::make_unique<TestCommandReader>();
+        mGralloc = std::make_unique<Gralloc>();
+    }
+
+    ~GraphicsComposerReadbackTest() override {
+        if (mComposerCallback != nullptr) {
+            EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+        }
+    }
+
+    void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+
+    void render(const std::vector<std::shared_ptr<TestLayer>>& layers) {
+        for (auto layer : layers) {
+            layer->write(mWriter);
+        }
+        execute();
+        mWriter->validateDisplay();
+        mWriter->presentDisplay();
+        execute();
+    }
+
+    int32_t GetBytesPerPixel(PixelFormat format) {
+        switch (format) {
+            case PixelFormat::RGBA_8888:
+                return 4;
+            case PixelFormat::RGB_888:
+                return 3;
+            default:
+                return -1;
+        }
+    }
+
+    bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
+                           const Error& error) {
+        if (error == Error::UNSUPPORTED) {
+            return false;
+        }
+        // TODO: add support for RGBA_1010102
+        if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) {
+            return false;
+        }
+        if (dataspace != Dataspace::V0_SRGB) {
+            return false;
+        }
+        return true;
+    }
+
+    void getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+                                     Dataspace* outDataspace, Error* outError) {
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+            display,
+            [&](const auto& tmpError, const auto& tmpOutPixelFormat, const auto& tmpOutDataspace) {
+                *outError = tmpError;
+                *outPixelFormat = tmpOutPixelFormat;
+                *outDataspace = tmpOutDataspace;
+            });
+
+        // Not all devices support readback.  Pass test if this is the case
+        if (!readbackSupported(*outPixelFormat, *outDataspace, *outError)) {
+            GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        }
+    }
+
+    void checkReadbackBuffer(IMapper::BufferDescriptorInfo info, uint32_t stride, void* bufferData,
+                             std::vector<IComposerClient::Color> expectedColors) {
+        int32_t bytesPerPixel = GetBytesPerPixel(info.format);
+        ASSERT_NE(-1, bytesPerPixel)
+            << "unexpected pixel format " << static_cast<int32_t>(info.format)
+            << "(expected RGBA_8888 or RGB_888)";
+        for (int row = 0; row < height; row++) {
+            for (int col = 0; col < width; col++) {
+                int pixel = row * width + col;
+                int offset = (row * stride + col) * bytesPerPixel;
+                uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+
+                EXPECT_EQ(expectedColors[pixel].r, pixelColor[0]);
+                EXPECT_EQ(expectedColors[pixel].g, pixelColor[1]);
+                EXPECT_EQ(expectedColors[pixel].b, pixelColor[2]);
+            }
+        }
+    }
+
+    std::unique_ptr<Composer> mComposer;
+    std::shared_ptr<ComposerClient> mComposerClient;
+
+    sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
+    // the first display and is assumed never to be removed
+    Display mPrimaryDisplay;
+    int32_t width;
+    int32_t height;
+    std::shared_ptr<CommandWriterBase> mWriter;
+    std::unique_ptr<TestCommandReader> mReader;
+    std::unique_ptr<Gralloc> mGralloc;
+
+   private:
+    Display waitForFirstDisplay() {
+        while (true) {
+            std::vector<Display> displays = mComposerCallback->getDisplays();
+            if (displays.empty()) {
+                usleep(5 * 1000);
+                continue;
+            }
+            return displays[0];
+        }
+    }
+};
+
+TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) {
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON);
+    mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB, RenderIntent::COLORIMETRIC);
+
+    auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+    IComposerClient::Color color({0, 0, 0xff, 0xff});
+    IComposerClient::Rect coloredSquare({100, 100, 500, 500});
+    layer->setColor(color);
+    layer->setDisplayFrame(coloredSquare);
+    layer->setZOrder(10);
+
+    std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+    // expected color for each pixel
+    std::vector<IComposerClient::Color> expectedColors(width * height);
+    for (int row = 0; row < height; row++) {
+        for (int col = 0; col < width; col++) {
+            int pixel = row * width + col;
+            if (row >= coloredSquare.top && row < coloredSquare.bottom &&
+                col >= coloredSquare.left && col < coloredSquare.right) {
+                expectedColors[pixel] = color;
+            } else {
+                expectedColors[pixel] = {0, 0, 0, 0xff};
+            }
+        }
+    }
+
+    PixelFormat pixelFormat;
+    Dataspace dataspace;
+    Error error;
+    getReadbackBufferAttributes(mPrimaryDisplay, &pixelFormat, &dataspace, &error);
+
+    IMapper::BufferDescriptorInfo info;
+    info.width = width;
+    info.height = height;
+    info.layerCount = 1;
+    info.format = pixelFormat;
+    info.usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE);
+
+    uint32_t stride;
+    const native_handle_t* buffer = mGralloc->allocate(info, /*import*/ true, &stride);
+    mComposerClient->setReadbackBuffer(mPrimaryDisplay, buffer, -1);
+
+    render(layers);
+
+    int32_t fenceHandle;
+    mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fenceHandle);
+
+    base::unique_fd fence(fenceHandle);
+
+    // lock buffer
+    // Create Rect accessRegion to specify reading the entire buffer
+    IMapper::Rect accessRegion;
+    accessRegion.left = 0;
+    accessRegion.top = 0;
+    accessRegion.width = info.width;
+    accessRegion.height = info.height;
+
+    void* bufData = mGralloc->lock(buffer, info.usage, accessRegion, fence);
+    checkReadbackBuffer(info, stride, bufData, expectedColors);
+}
+
+}  // anonymous namespace
+}  // namespace vts
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android