Support 10-bit VTS readback

Some devices require this for VTS

Bug: 329526845
Test: builds
Test: VtsHalGraphicsComposer3_TargetTest
Change-Id: I94d9611c9ec64be867ade6933a07ae9e97b459a1
diff --git a/graphics/composer/aidl/vts/ReadbackVts.cpp b/graphics/composer/aidl/vts/ReadbackVts.cpp
index 283b8ce..9d5928d 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.cpp
+++ b/graphics/composer/aidl/vts/ReadbackVts.cpp
@@ -16,6 +16,7 @@
 
 #include "ReadbackVts.h"
 #include <aidl/android/hardware/graphics/common/BufferUsage.h>
+#include <cmath>
 #include "RenderEngineVts.h"
 #include "renderengine/ExternalTexture.h"
 #include "renderengine/impl/ExternalTexture.h"
@@ -106,37 +107,72 @@
     return layerSettings;
 }
 
-int32_t ReadbackHelper::GetBytesPerPixel(common::PixelFormat pixelFormat) {
+int32_t ReadbackHelper::GetBitsPerChannel(common::PixelFormat pixelFormat) {
     switch (pixelFormat) {
+        case common::PixelFormat::RGBA_1010102:
+            return 10;
         case common::PixelFormat::RGBA_8888:
-            return 4;
         case common::PixelFormat::RGB_888:
-            return 3;
+            return 8;
         default:
             return -1;
     }
 }
 
-void ReadbackHelper::fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData,
+int32_t ReadbackHelper::GetAlphaBits(common::PixelFormat pixelFormat) {
+    switch (pixelFormat) {
+        case common::PixelFormat::RGBA_8888:
+            return 8;
+        case common::PixelFormat::RGBA_1010102:
+            return 2;
+        case common::PixelFormat::RGB_888:
+            return 0;
+        default:
+            return -1;
+    }
+}
+
+void ReadbackHelper::fillBuffer(uint32_t width, uint32_t height, uint32_t stride,
+                                int32_t bytesPerPixel, void* bufferData,
                                 common::PixelFormat pixelFormat,
                                 std::vector<Color> desiredPixelColors) {
     ASSERT_TRUE(pixelFormat == common::PixelFormat::RGB_888 ||
-                pixelFormat == common::PixelFormat::RGBA_8888);
-    int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
+                pixelFormat == common::PixelFormat::RGBA_8888 ||
+                pixelFormat == common::PixelFormat::RGBA_1010102);
+    int32_t bitsPerChannel = GetBitsPerChannel(pixelFormat);
+    int32_t alphaBits = GetAlphaBits(pixelFormat);
+    ASSERT_NE(-1, alphaBits);
+    ASSERT_NE(-1, bitsPerChannel);
     ASSERT_NE(-1, bytesPerPixel);
-    for (int row = 0; row < height; row++) {
-        for (int col = 0; col < width; col++) {
-            auto pixel = row * static_cast<int32_t>(width) + col;
+
+    uint32_t maxValue = (1 << bitsPerChannel) - 1;
+    uint32_t maxAlphaValue = (1 << alphaBits) - 1;
+    for (uint32_t row = 0; row < height; row++) {
+        for (uint32_t col = 0; col < width; col++) {
+            auto pixel = row * width + col;
             Color srcColor = desiredPixelColors[static_cast<size_t>(pixel)];
 
-            int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
-            uint8_t* pixelColor = (uint8_t*)bufferData + offset;
-            pixelColor[0] = static_cast<uint8_t>(std::round(255.0f * srcColor.r));
-            pixelColor[1] = static_cast<uint8_t>(std::round(255.0f * srcColor.g));
-            pixelColor[2] = static_cast<uint8_t>(std::round(255.0f * srcColor.b));
+            uint32_t offset = (row * stride + col) * static_cast<uint32_t>(bytesPerPixel);
 
-            if (bytesPerPixel == 4) {
-                pixelColor[3] = static_cast<uint8_t>(std::round(255.0f * srcColor.a));
+            uint32_t* pixelStart = (uint32_t*)((uint8_t*)bufferData + offset);
+
+            uint32_t red = static_cast<uint32_t>(std::round(maxValue * srcColor.r));
+            uint32_t green = static_cast<uint32_t>(std::round(maxValue * srcColor.g));
+            uint32_t blue = static_cast<uint32_t>(std::round(maxValue * srcColor.b));
+
+            // Boo we're not word aligned so special case this.
+            if (pixelFormat == common::PixelFormat::RGB_888) {
+                uint8_t* pixelColor = (uint8_t*)pixelStart;
+                pixelColor[0] = static_cast<uint8_t>(red);
+                pixelColor[1] = static_cast<uint8_t>(green);
+                pixelColor[2] = static_cast<uint8_t>(blue);
+            } else {
+                uint32_t alpha = static_cast<uint32_t>(std::round(maxAlphaValue * srcColor.a));
+                uint32_t color = (alpha << (32 - alphaBits)) |
+                                 (blue << (32 - alphaBits - bitsPerChannel)) |
+                                 (green << (32 - alphaBits - bitsPerChannel * 2)) |
+                                 (red << (32 - alphaBits - bitsPerChannel * 3));
+                *pixelStart = color;
             }
         }
     }
@@ -165,7 +201,8 @@
 bool ReadbackHelper::readbackSupported(const common::PixelFormat& pixelFormat,
                                        const common::Dataspace& dataspace) {
     if (pixelFormat != common::PixelFormat::RGB_888 &&
-        pixelFormat != common::PixelFormat::RGBA_8888) {
+        pixelFormat != common::PixelFormat::RGBA_8888 &&
+        pixelFormat != common::PixelFormat::RGBA_1010102) {
         return false;
     }
     if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
@@ -175,36 +212,110 @@
 }
 
 void ReadbackHelper::compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
-                                         const uint32_t stride, const uint32_t width,
-                                         const uint32_t height, common::PixelFormat pixelFormat) {
-    const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
-    ASSERT_NE(-1, bytesPerPixel);
-    for (int row = 0; row < height; row++) {
-        for (int col = 0; col < width; col++) {
-            auto pixel = row * static_cast<int32_t>(width) + col;
-            int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
-            uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+                                         const uint32_t stride, int32_t bytesPerPixel,
+                                         const uint32_t width, const uint32_t height,
+                                         common::PixelFormat pixelFormat) {
+    int32_t bitsPerChannel = GetBitsPerChannel(pixelFormat);
+    int32_t alphaBits = GetAlphaBits(pixelFormat);
+    ASSERT_GT(bytesPerPixel, 0);
+    ASSERT_NE(-1, alphaBits);
+    ASSERT_NE(-1, bitsPerChannel);
+    uint32_t maxValue = (1 << bitsPerChannel) - 1;
+    uint32_t maxAlphaValue = (1 << alphaBits) - 1;
+    for (uint32_t row = 0; row < height; row++) {
+        for (uint32_t col = 0; col < width; col++) {
+            auto pixel = row * width + col;
             const Color expectedColor = expectedColors[static_cast<size_t>(pixel)];
-            ASSERT_EQ(std::round(255.0f * expectedColor.r), pixelColor[0]);
-            ASSERT_EQ(std::round(255.0f * expectedColor.g), pixelColor[1]);
-            ASSERT_EQ(std::round(255.0f * expectedColor.b), pixelColor[2]);
+
+            uint32_t offset = (row * stride + col) * static_cast<uint32_t>(bytesPerPixel);
+            uint32_t* pixelStart = (uint32_t*)((uint8_t*)bufferData + offset);
+
+            uint32_t expectedRed = static_cast<uint32_t>(std::round(maxValue * expectedColor.r));
+            uint32_t expectedGreen = static_cast<uint32_t>(std::round(maxValue * expectedColor.g));
+            uint32_t expectedBlue = static_cast<uint32_t>(std::round(maxValue * expectedColor.b));
+
+            // Boo we're not word aligned so special case this.
+            if (pixelFormat == common::PixelFormat::RGB_888) {
+                uint8_t* pixelColor = (uint8_t*)pixelStart;
+                ASSERT_EQ(pixelColor[0], static_cast<uint8_t>(expectedRed))
+                        << "Red channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(pixelColor[1], static_cast<uint8_t>(expectedGreen))
+                        << "Green channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(pixelColor[2], static_cast<uint8_t>(expectedBlue))
+                        << "Blue channel mismatch at (" << row << ", " << col << ")";
+            } else {
+                uint32_t expectedAlpha =
+                        static_cast<uint32_t>(std::round(maxAlphaValue * expectedColor.a));
+
+                uint32_t actualRed =
+                        (*pixelStart >> (32 - alphaBits - bitsPerChannel * 3)) & maxValue;
+                uint32_t actualGreen =
+                        (*pixelStart >> (32 - alphaBits - bitsPerChannel * 2)) & maxValue;
+                uint32_t actualBlue = (*pixelStart >> (32 - alphaBits - bitsPerChannel)) & maxValue;
+                uint32_t actualAlpha = (*pixelStart >> (32 - alphaBits)) & maxAlphaValue;
+
+                ASSERT_EQ(expectedRed, actualRed)
+                        << "Red channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(expectedGreen, actualGreen)
+                        << "Green channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(expectedBlue, actualBlue)
+                        << "Blue channel mismatch at (" << row << ", " << col << ")";
+            }
         }
     }
 }
 
 void ReadbackHelper::compareColorBuffers(void* expectedBuffer, void* actualBuffer,
-                                         const uint32_t stride, const uint32_t width,
-                                         const uint32_t height, common::PixelFormat pixelFormat) {
-    const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
-    ASSERT_NE(-1, bytesPerPixel);
-    for (int row = 0; row < height; row++) {
-        for (int col = 0; col < width; col++) {
-            int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
-            uint8_t* expectedColor = (uint8_t*)expectedBuffer + offset;
-            uint8_t* actualColor = (uint8_t*)actualBuffer + offset;
-            ASSERT_EQ(expectedColor[0], actualColor[0]);
-            ASSERT_EQ(expectedColor[1], actualColor[1]);
-            ASSERT_EQ(expectedColor[2], actualColor[2]);
+                                         const uint32_t stride, int32_t bytesPerPixel,
+                                         const uint32_t width, const uint32_t height,
+                                         common::PixelFormat pixelFormat) {
+    int32_t bitsPerChannel = GetBitsPerChannel(pixelFormat);
+    int32_t alphaBits = GetAlphaBits(pixelFormat);
+    ASSERT_GT(bytesPerPixel, 0);
+    ASSERT_NE(-1, alphaBits);
+    ASSERT_NE(-1, bitsPerChannel);
+    uint32_t maxValue = (1 << bitsPerChannel) - 1;
+    uint32_t maxAlphaValue = (1 << alphaBits) - 1;
+    for (uint32_t row = 0; row < height; row++) {
+        for (uint32_t col = 0; col < width; col++) {
+            uint32_t offset = (row * stride + col) * static_cast<uint32_t>(bytesPerPixel);
+            uint32_t* expectedStart = (uint32_t*)((uint8_t*)expectedBuffer + offset);
+            uint32_t* actualStart = (uint32_t*)((uint8_t*)actualBuffer + offset);
+
+            // Boo we're not word aligned so special case this.
+            if (pixelFormat == common::PixelFormat::RGB_888) {
+                uint8_t* expectedPixel = (uint8_t*)expectedStart;
+                uint8_t* actualPixel = (uint8_t*)actualStart;
+                ASSERT_EQ(actualPixel[0], expectedPixel[0])
+                        << "Red channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(actualPixel[1], expectedPixel[1])
+                        << "Green channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(actualPixel[2], expectedPixel[2])
+                        << "Blue channel mismatch at (" << row << ", " << col << ")";
+            } else {
+                uint32_t expectedRed =
+                        (*expectedStart >> (32 - alphaBits - bitsPerChannel * 3)) & maxValue;
+                uint32_t expectedGreen =
+                        (*expectedStart >> (32 - alphaBits - bitsPerChannel * 2)) & maxValue;
+                uint32_t expectedBlue =
+                        (*expectedStart >> (32 - alphaBits - bitsPerChannel)) & maxValue;
+                uint32_t expectedAlpha = (*expectedStart >> (32 - alphaBits)) & maxAlphaValue;
+
+                uint32_t actualRed =
+                        (*actualStart >> (32 - alphaBits - bitsPerChannel * 3)) & maxValue;
+                uint32_t actualGreen =
+                        (*actualStart >> (32 - alphaBits - bitsPerChannel * 2)) & maxValue;
+                uint32_t actualBlue =
+                        (*actualStart >> (32 - alphaBits - bitsPerChannel)) & maxValue;
+                uint32_t actualAlpha = (*actualStart >> (32 - alphaBits)) & maxAlphaValue;
+
+                ASSERT_EQ(expectedRed, actualRed)
+                        << "Red channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(expectedGreen, actualGreen)
+                        << "Green channel mismatch at (" << row << ", " << col << ")";
+                ASSERT_EQ(expectedBlue, actualBlue)
+                        << "Blue channel mismatch at (" << row << ", " << col << ")";
+            }
         }
     }
 }
@@ -258,12 +369,13 @@
     auto status = mGraphicBuffer->lockAsync(mUsage, mAccessRegion, &bufData, dup(bufferFence.get()),
                                             &bytesPerPixel, &bytesPerStride);
     EXPECT_EQ(::android::OK, status);
-    ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
+    ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888 ||
+                mPixelFormat == PixelFormat::RGBA_1010102);
     const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
                                     ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
                                     : mGraphicBuffer->getStride();
-    ReadbackHelper::compareColorBuffers(expectedColors, bufData, stride, mWidth, mHeight,
-                                        mPixelFormat);
+    ReadbackHelper::compareColorBuffers(expectedColors, bufData, stride, bytesPerPixel, mWidth,
+                                        mHeight, mPixelFormat);
     status = mGraphicBuffer->unlock();
     EXPECT_EQ(::android::OK, status);
 }
@@ -353,8 +465,8 @@
                                     ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
                                     : mGraphicBuffer->getStride();
     EXPECT_EQ(::android::OK, status);
-    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bufData,
-                                                       mPixelFormat, expectedColors));
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bytesPerPixel,
+                                                       bufData, mPixelFormat, expectedColors));
 
     const auto unlockStatus = mGraphicBuffer->unlockAsync(&mFillFence);
     ASSERT_EQ(::android::OK, unlockStatus);
diff --git a/graphics/composer/aidl/vts/ReadbackVts.h b/graphics/composer/aidl/vts/ReadbackVts.h
index 8ac0f4b..e3b2384 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.h
+++ b/graphics/composer/aidl/vts/ReadbackVts.h
@@ -172,10 +172,12 @@
 
     static Dataspace getDataspaceForColorMode(ColorMode mode);
 
-    static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
+    static int32_t GetBitsPerChannel(PixelFormat pixelFormat);
+    static int32_t GetAlphaBits(PixelFormat pixelFormat);
 
-    static void fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData,
-                           PixelFormat pixelFormat, std::vector<Color> desiredPixelColors);
+    static void fillBuffer(uint32_t width, uint32_t height, uint32_t stride, int32_t bytesPerPixel,
+                           void* bufferData, PixelFormat pixelFormat,
+                           std::vector<Color> desiredPixelColors);
 
     static void clearColors(std::vector<Color>& expectedColors, int32_t width, int32_t height,
                             int32_t displayWidth);
@@ -189,11 +191,12 @@
     static const std::vector<Dataspace> dataspaces;
 
     static void compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
-                                    const uint32_t stride, const uint32_t width,
-                                    const uint32_t height, PixelFormat pixelFormat);
-    static void compareColorBuffers(void* expectedBuffer, void* actualBuffer, const uint32_t stride,
+                                    const uint32_t stride, int32_t bytesPerPixel,
                                     const uint32_t width, const uint32_t height,
                                     PixelFormat pixelFormat);
+    static void compareColorBuffers(void* expectedBuffer, void* actualBuffer, const uint32_t stride,
+                                    int32_t bytesPerPixel, const uint32_t width,
+                                    const uint32_t height, PixelFormat pixelFormat);
 };
 
 class ReadbackBuffer {
diff --git a/graphics/composer/aidl/vts/RenderEngineVts.cpp b/graphics/composer/aidl/vts/RenderEngineVts.cpp
index 4e7f773..48cb8ae 100644
--- a/graphics/composer/aidl/vts/RenderEngineVts.cpp
+++ b/graphics/composer/aidl/vts/RenderEngineVts.cpp
@@ -83,7 +83,7 @@
     const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
                                     ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
                                     : mGraphicBuffer->getStride();
-    ReadbackHelper::compareColorBuffers(expectedColors, bufferData, stride,
+    ReadbackHelper::compareColorBuffers(expectedColors, bufferData, stride, bytesPerPixel,
                                         mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
                                         mFormat);
     ASSERT_EQ(::android::OK, mGraphicBuffer->unlock());
@@ -110,7 +110,7 @@
 
     ASSERT_EQ(renderedStride, bufferStride);
 
-    ReadbackHelper::compareColorBuffers(renderedBufferData, bufferData, bufferStride,
+    ReadbackHelper::compareColorBuffers(renderedBufferData, bufferData, bufferStride, bytesPerPixel,
                                         mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
                                         mFormat);
     ASSERT_EQ(::android::OK, buffer->unlock());
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 3d9253f..9db8794 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -496,11 +496,14 @@
             const auto& buffer = graphicBuffer->handle;
             void* clientBufData;
             const auto stride = static_cast<uint32_t>(graphicBuffer->stride);
-            graphicBuffer->lock(clientUsage, layer->getAccessRegion(), &clientBufData);
+            int bytesPerPixel = -1;
+            int bytesPerStride = -1;
+            graphicBuffer->lock(clientUsage, layer->getAccessRegion(), &clientBufData,
+                                &bytesPerPixel, &bytesPerStride);
 
-            ASSERT_NO_FATAL_FAILURE(
-                    ReadbackHelper::fillBuffer(layer->getWidth(), layer->getHeight(), stride,
-                                               clientBufData, clientFormat, expectedColors));
+            ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(
+                    layer->getWidth(), layer->getHeight(), stride, bytesPerPixel, clientBufData,
+                    clientFormat, expectedColors));
             int32_t clientFence;
             const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
             ASSERT_EQ(::android::OK, unlockStatus);
@@ -677,15 +680,18 @@
         const auto& buffer = graphicBuffer->handle;
 
         void* clientBufData;
+        int bytesPerPixel = -1;
+        int bytesPerStride = -1;
         graphicBuffer->lock(clientUsage, {0, 0, getDisplayWidth(), getDisplayHeight()},
-                            &clientBufData);
+                            &clientBufData, &bytesPerPixel, &bytesPerStride);
 
         std::vector<Color> clientColors(
                 static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
         ReadbackHelper::fillColorsArea(clientColors, getDisplayWidth(), clientFrame, RED);
         ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(
                 static_cast<uint32_t>(getDisplayWidth()), static_cast<uint32_t>(getDisplayHeight()),
-                graphicBuffer->getStride(), clientBufData, clientFormat, clientColors));
+                graphicBuffer->getStride(), bytesPerPixel, clientBufData, clientFormat,
+                clientColors));
         int32_t clientFence;
         const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
         ASSERT_EQ(::android::OK, unlockStatus);