Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98d7c3ec authored by Ram Indani's avatar Ram Indani Committed by Android (Google) Code Review
Browse files

Merge "Readback tests from VTS 2.2"

parents 2e7ea6c1 bab8ba92
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -28,20 +28,29 @@ cc_test {
    defaults: [
        "VtsHalTargetTestDefaults",
        "use_libaidlvintf_gtest_helper_static",
        // Needed for librenderengine
        "skia_deps",
    ],
    srcs: [
        "VtsHalGraphicsComposer3_TargetTest.cpp",
        "VtsHalGraphicsComposer3_ReadbackTest.cpp",
        "composer-vts/GraphicsComposerCallback.cpp",
        "composer-vts/TestCommandReader.cpp",
    ],

    shared_libs: [
        "libEGL",
        "libGLESv1_CM",
        "libGLESv2",
        "libbinder_ndk",
        "libbinder",
        "libfmq",
        "libbase",
        "libsync",
        "libui",
        "libgui",
        "libhidlbase",
        "libprocessgroup",
        "android.hardware.graphics.mapper@2.0",
        "android.hardware.graphics.mapper@2.1",
        "android.hardware.graphics.mapper@3.0",
@@ -69,6 +78,10 @@ cc_test {
        "android.hardware.graphics.mapper@3.0-vts",
        "android.hardware.graphics.mapper@4.0-vts",
        "libaidlcommonsupport",
        "libgtest",
        "librenderengine",
        "libshaders",
        "libtonemap",
    ],
    cflags: [
        "-Wconversion",
+1360 −0

File added.

Preview size limit exceeded, changes collapsed.

+14 −0
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ cc_library_static {
    srcs: [
        "GraphicsComposerCallback.cpp",
        "TestCommandReader.cpp",
        "ReadbackVts.cpp",
        "RenderEngineVts.cpp",
    ],
    header_libs: [
        "android.hardware.graphics.composer3-command-buffer",
@@ -38,20 +40,32 @@ cc_library_static {
        "android.hardware.graphics.common-V3-ndk",
        "android.hardware.common-V2-ndk",
        "android.hardware.common.fmq-V1-ndk",
        "libarect",
        "libgtest",
        "libbase",
        "libfmq",
        "libsync",
        "libmath",
        "libaidlcommonsupport",
        "libnativewindow",
        "librenderengine",
        "libshaders",
        "libtonemap",
        "android.hardware.graphics.mapper@2.0-vts",
        "android.hardware.graphics.mapper@2.1-vts",
        "android.hardware.graphics.mapper@3.0-vts",
        "android.hardware.graphics.mapper@4.0-vts",
    ],
    shared_libs: [
        "libbinder_ndk",
        "libhidlbase",
        "libui",
        "android.hardware.graphics.composer3-V1-ndk",
    ],
    export_static_lib_headers: [
        "android.hardware.graphics.mapper@2.1-vts",
        "librenderengine",
    ],
    cflags: [
        "-O0",
        "-g",
+360 −0
Original line number Diff line number Diff line
/**
 * Copyright (c) 2021, 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.
 */

// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"

#include "include/ReadbackVts.h"
#include <aidl/android/hardware/graphics/common/BufferUsage.h>
#include "include/RenderEngineVts.h"
#include "renderengine/ExternalTexture.h"

// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop  // ignored "-Wconversion

namespace aidl::android::hardware::graphics::composer3::vts {

const std::vector<ColorMode> ReadbackHelper::colorModes = {ColorMode::SRGB, ColorMode::DISPLAY_P3};
const std::vector<Dataspace> ReadbackHelper::dataspaces = {common::Dataspace::SRGB,
                                                           common::Dataspace::DISPLAY_P3};

void TestLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
    writer->selectLayer(mLayer);
    writer->setLayerDisplayFrame(mDisplayFrame);
    writer->setLayerSourceCrop(mSourceCrop);
    writer->setLayerZOrder(mZOrder);
    writer->setLayerSurfaceDamage(mSurfaceDamage);
    writer->setLayerTransform(mTransform);
    writer->setLayerPlaneAlpha(mAlpha);
    writer->setLayerBlendMode(mBlendMode);
}

std::string ReadbackHelper::getColorModeString(ColorMode mode) {
    switch (mode) {
        case ColorMode::SRGB:
            return {"SRGB"};
        case ColorMode::DISPLAY_P3:
            return {"DISPLAY_P3"};
        default:
            return {"Unsupported color mode for readback"};
    }
}

std::string ReadbackHelper::getDataspaceString(common::Dataspace dataspace) {
    switch (dataspace) {
        case common::Dataspace::SRGB:
            return {"SRGB"};
        case common::Dataspace::DISPLAY_P3:
            return {"DISPLAY_P3"};
        case common::Dataspace::UNKNOWN:
            return {"UNKNOWN"};
        default:
            return {"Unsupported dataspace for readback"};
    }
}

Dataspace ReadbackHelper::getDataspaceForColorMode(ColorMode mode) {
    switch (mode) {
        case ColorMode::DISPLAY_P3:
            return Dataspace::DISPLAY_P3;
        case ColorMode::SRGB:
        default:
            return common::Dataspace::UNKNOWN;
    }
}

LayerSettings TestLayer::toRenderEngineLayerSettings() {
    LayerSettings layerSettings;

    layerSettings.alpha = ::android::half(mAlpha);
    layerSettings.disableBlending = mBlendMode == BlendMode::NONE;
    layerSettings.geometry.boundaries = ::android::FloatRect(
            static_cast<float>(mDisplayFrame.left), static_cast<float>(mDisplayFrame.top),
            static_cast<float>(mDisplayFrame.right), static_cast<float>(mDisplayFrame.bottom));

    const ::android::mat4 translation = ::android::mat4::translate(::android::vec4(
            (static_cast<uint64_t>(mTransform) & static_cast<uint64_t>(Transform::FLIP_H)
                     ? static_cast<float>(-mDisplayFrame.right)
                     : 0.0f),
            (static_cast<uint64_t>(mTransform) & static_cast<uint64_t>(Transform::FLIP_V)
                     ? static_cast<float>(-mDisplayFrame.bottom)
                     : 0.0f),
            0.0f, 1.0f));

    const ::android::mat4 scale = ::android::mat4::scale(::android::vec4(
            static_cast<uint64_t>(mTransform) & static_cast<uint64_t>(Transform::FLIP_H) ? -1.0f
                                                                                         : 1.0f,
            static_cast<uint64_t>(mTransform) & static_cast<uint64_t>(Transform::FLIP_V) ? -1.0f
                                                                                         : 1.0f,
            1.0f, 1.0f));

    layerSettings.geometry.positionTransform = scale * translation;

    return layerSettings;
}

int32_t ReadbackHelper::GetBytesPerPixel(common::PixelFormat pixelFormat) {
    switch (pixelFormat) {
        case common::PixelFormat::RGBA_8888:
            return 4;
        case common::PixelFormat::RGB_888:
            return 3;
        default:
            return -1;
    }
}

void ReadbackHelper::fillBuffer(uint32_t width, uint32_t height, uint32_t stride, 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);
    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;
            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>(srcColor.r);
            pixelColor[1] = static_cast<uint8_t>(srcColor.g);
            pixelColor[2] = static_cast<uint8_t>(srcColor.b);

            if (bytesPerPixel == 4) {
                pixelColor[3] = static_cast<uint8_t>(srcColor.a);
            }
        }
    }
}

void ReadbackHelper::clearColors(std::vector<Color>& expectedColors, int32_t width, int32_t height,
                                 int32_t displayWidth) {
    for (int row = 0; row < height; row++) {
        for (int col = 0; col < width; col++) {
            int pixel = row * displayWidth + col;
            expectedColors[static_cast<size_t>(pixel)] = BLACK;
        }
    }
}

void ReadbackHelper::fillColorsArea(std::vector<Color>& expectedColors, int32_t stride, Rect area,
                                    Color color) {
    for (int row = area.top; row < area.bottom; row++) {
        for (int col = area.left; col < area.right; col++) {
            int pixel = row * stride + col;
            expectedColors[static_cast<size_t>(pixel)] = color;
        }
    }
}

bool ReadbackHelper::readbackSupported(const common::PixelFormat& pixelFormat,
                                       const common::Dataspace& dataspace) {
    if (pixelFormat != common::PixelFormat::RGB_888 &&
        pixelFormat != common::PixelFormat::RGBA_8888) {
        return false;
    }
    if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
        return false;
    }
    return true;
}

void ReadbackHelper::compareColorBuffers(std::vector<Color>& expectedColors, void* bufferData,
                                         const int32_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 * stride + col) * bytesPerPixel;
            uint8_t* pixelColor = (uint8_t*)bufferData + offset;

            ASSERT_EQ(static_cast<int8_t>(expectedColors[static_cast<size_t>(pixel)].r),
                      pixelColor[0]);
            ASSERT_EQ(static_cast<int8_t>(expectedColors[static_cast<size_t>(pixel)].g),
                      pixelColor[1]);
            ASSERT_EQ(static_cast<int8_t>(expectedColors[static_cast<size_t>(pixel)].b),
                      pixelColor[2]);
        }
    }
}

ReadbackBuffer::ReadbackBuffer(int64_t display, const std::shared_ptr<IComposerClient>& client,
                               const ::android::sp<::android::GraphicBuffer>& graphicBuffer,
                               int32_t width, int32_t height, common::PixelFormat pixelFormat,
                               common::Dataspace dataspace) {
    mDisplay = display;

    mComposerClient = client;
    mGraphicBuffer = graphicBuffer;

    mPixelFormat = pixelFormat;
    mDataspace = dataspace;

    mWidth = static_cast<uint32_t>(width);
    mHeight = static_cast<uint32_t>(height);
    mLayerCount = 1;
    mUsage = static_cast<uint64_t>(static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
                                   static_cast<uint64_t>(common::BufferUsage::GPU_TEXTURE));

    mAccessRegion.top = 0;
    mAccessRegion.left = 0;
    mAccessRegion.right = static_cast<int32_t>(width);
    mAccessRegion.bottom = static_cast<int32_t>(height);
}

::android::sp<::android::GraphicBuffer> ReadbackBuffer::allocate() {
    return ::android::sp<::android::GraphicBuffer>::make(
            mWidth, mHeight, static_cast<::android::PixelFormat>(mPixelFormat), mLayerCount, mUsage,
            "ReadbackVts");
}

void ReadbackBuffer::setReadbackBuffer() {
    mGraphicBuffer = allocate();
    ASSERT_NE(nullptr, mGraphicBuffer);
    ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
    aidl::android::hardware::common::NativeHandle bufferHandle =
            ::android::dupToAidl(mGraphicBuffer->handle);
    ::ndk::ScopedFileDescriptor fence = ::ndk::ScopedFileDescriptor(-1);
    EXPECT_TRUE(mComposerClient->setReadbackBuffer(mDisplay, bufferHandle, fence).isOk());
}

void ReadbackBuffer::checkReadbackBuffer(std::vector<Color> expectedColors) {
    // lock buffer for reading
    ndk::ScopedFileDescriptor fenceHandle;
    EXPECT_TRUE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle).isOk());

    int outBytesPerPixel;
    int outBytesPerStride;
    auto status = mGraphicBuffer->lockAsync(mUsage, mAccessRegion, nullptr, fenceHandle.get(),
                                            &outBytesPerPixel, &outBytesPerStride);
    EXPECT_EQ(::android::OK, status);
    ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
    ReadbackHelper::compareColorBuffers(expectedColors, mGraphicBuffer.get(),
                                        static_cast<int32_t>(mStride), mWidth, mHeight,
                                        mPixelFormat);
    status = mGraphicBuffer->unlock();
    EXPECT_EQ(::android::OK, status);
}

void TestColorLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
    TestLayer::write(writer);
    writer->setLayerCompositionType(Composition::SOLID_COLOR);
    writer->setLayerColor(mColor);
}

LayerSettings TestColorLayer::toRenderEngineLayerSettings() {
    LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();

    layerSettings.source.solidColor =
            ::android::half3(static_cast<::android::half>(mColor.r) / 255.0,
                             static_cast<::android::half>(mColor.g) / 255.0,
                             static_cast<::android::half>(mColor.b) / 255.0);
    layerSettings.alpha =
            mAlpha * static_cast<float>((static_cast<::android::half>(mColor.a) / 255.0));
    return layerSettings;
}

TestBufferLayer::TestBufferLayer(const std::shared_ptr<IComposerClient>& client,
                                 const ::android::sp<::android::GraphicBuffer>& graphicBuffer,
                                 TestRenderEngine& renderEngine, int32_t display, uint32_t width,
                                 uint32_t height, common::PixelFormat format,
                                 Composition composition)
    : TestLayer{client, display}, mRenderEngine(renderEngine) {
    mGraphicBuffer = graphicBuffer;
    mComposition = composition;
    mWidth = width;
    mHeight = height;
    mLayerCount = 1;
    mPixelFormat = format;
    mUsage = (static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
              static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
              static_cast<uint64_t>(common::BufferUsage::COMPOSER_OVERLAY) |
              static_cast<uint64_t>(common::BufferUsage::GPU_TEXTURE));

    mAccessRegion.top = 0;
    mAccessRegion.left = 0;
    mAccessRegion.right = static_cast<int32_t>(width);
    mAccessRegion.bottom = static_cast<int32_t>(height);

    setSourceCrop({0, 0, (float)width, (float)height});
}

void TestBufferLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
    TestLayer::write(writer);
    writer->setLayerCompositionType(mComposition);
    writer->setLayerVisibleRegion(std::vector<Rect>(1, mDisplayFrame));
    if (mGraphicBuffer->handle != nullptr)
        writer->setLayerBuffer(0, mGraphicBuffer->handle, mFillFence);
}

LayerSettings TestBufferLayer::toRenderEngineLayerSettings() {
    LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
    layerSettings.source.buffer.buffer = std::make_shared<::android::renderengine::ExternalTexture>(
            ::android::sp<::android::GraphicBuffer>::make(
                    mGraphicBuffer->handle, ::android::GraphicBuffer::CLONE_HANDLE, mWidth, mHeight,
                    static_cast<int32_t>(mPixelFormat), 1, mUsage, mStride),
            mRenderEngine.getInternalRenderEngine(),
            ::android::renderengine::ExternalTexture::Usage::READABLE);

    layerSettings.source.buffer.usePremultipliedAlpha = mBlendMode == BlendMode::PREMULTIPLIED;

    const float scaleX = (mSourceCrop.right - mSourceCrop.left) / (static_cast<float>(mWidth));
    const float scaleY = (mSourceCrop.bottom - mSourceCrop.top) / (static_cast<float>(mHeight));
    const float translateX = mSourceCrop.left / (static_cast<float>(mWidth));
    const float translateY = mSourceCrop.top / (static_cast<float>(mHeight));

    layerSettings.source.buffer.textureTransform =
            ::android::mat4::translate(::android::vec4(translateX, translateY, 0, 1)) *
            ::android::mat4::scale(::android::vec4(scaleX, scaleY, 1.0, 1.0));

    return layerSettings;
}

void TestBufferLayer::fillBuffer(std::vector<Color>& expectedColors) {
    void* bufData;
    auto status = mGraphicBuffer->lock(mUsage, &bufData);
    EXPECT_EQ(::android::OK, status);
    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, mStride, bufData,
                                                       mPixelFormat, expectedColors));
    EXPECT_EQ(::android::OK, mGraphicBuffer->unlock());
}

void TestBufferLayer::setBuffer(std::vector<Color> colors) {
    mGraphicBuffer->reallocate(mWidth, mHeight, static_cast<::android::PixelFormat>(mPixelFormat),
                               mLayerCount, mUsage);
    ASSERT_NE(nullptr, mGraphicBuffer);
    ASSERT_NE(nullptr, mGraphicBuffer->handle);
    ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
    ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
}

void TestBufferLayer::setDataspace(common::Dataspace dataspace,
                                   const std::shared_ptr<CommandWriterBase>& writer) {
    writer->selectLayer(mLayer);
    writer->setLayerDataspace(dataspace);
}

void TestBufferLayer::setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer) {
    writer->selectLayer(mLayer);
    writer->setLayerCompositionType(Composition::CLIENT);
}

}  // namespace aidl::android::hardware::graphics::composer3::vts
 No newline at end of file
+89 −0
Original line number Diff line number Diff line
/**
 * Copyright (c) 2021, 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.
 */

#include "include/RenderEngineVts.h"

namespace aidl::android::hardware::graphics::composer3::vts {

using ::android::hardware::graphics::mapper::V2_1::IMapper;
using ::android::renderengine::DisplaySettings;
using ::android::renderengine::LayerSettings;
using ::android::renderengine::RenderEngineCreationArgs;

TestRenderEngine::TestRenderEngine(const RenderEngineCreationArgs& args) {
    mFormat = static_cast<common::PixelFormat>(args.pixelFormat);
    mRenderEngine = ::android::renderengine::RenderEngine::create(args);
}

TestRenderEngine::~TestRenderEngine() {
    mRenderEngine.release();
}

void TestRenderEngine::setRenderLayers(std::vector<std::shared_ptr<TestLayer>> layers) {
    sort(layers.begin(), layers.end(),
         [](const std::shared_ptr<TestLayer>& lhs, const std::shared_ptr<TestLayer>& rhs) -> bool {
             return lhs->getZOrder() < rhs->getZOrder();
         });

    if (!mCompositionLayers.empty()) {
        mCompositionLayers.clear();
    }
    for (auto& layer : layers) {
        LayerSettings settings = layer->toRenderEngineLayerSettings();
        mCompositionLayers.push_back(settings);
    }
}

void TestRenderEngine::initGraphicBuffer(uint32_t width, uint32_t height, uint32_t layerCount,
                                         uint64_t usage) {
    mGraphicBuffer = ::android::sp<::android::GraphicBuffer>::make(
            width, height, static_cast<int32_t>(mFormat), layerCount, usage);
}

void TestRenderEngine::drawLayers() {
    ::android::base::unique_fd bufferFence;

    std::vector<::android::renderengine::LayerSettings> compositionLayers;
    compositionLayers.reserve(mCompositionLayers.size());
    std::transform(mCompositionLayers.begin(), mCompositionLayers.end(),
                   std::back_insert_iterator(compositionLayers),
                   [](::android::renderengine::LayerSettings& settings)
                           -> ::android::renderengine::LayerSettings { return settings; });
    auto texture = std::make_shared<::android::renderengine::ExternalTexture>(
            mGraphicBuffer, *mRenderEngine,
            ::android::renderengine::ExternalTexture::Usage::WRITEABLE);
    auto [status, readyFence] = mRenderEngine
                                        ->drawLayers(mDisplaySettings, compositionLayers, texture,
                                                     true, std::move(bufferFence))
                                        .get();
    int fd = readyFence.release();
    if (fd != -1) {
        ASSERT_EQ(0, sync_wait(fd, -1));
        ASSERT_EQ(0, close(fd));
    }
}

void TestRenderEngine::checkColorBuffer(std::vector<Color>& expectedColors) {
    void* bufferData;
    ASSERT_EQ(0,
              mGraphicBuffer->lock(static_cast<uint32_t>(mGraphicBuffer->getUsage()), &bufferData));
    ReadbackHelper::compareColorBuffers(
            expectedColors, bufferData, static_cast<int32_t>(mGraphicBuffer->getStride()),
            mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(), mFormat);
    ASSERT_EQ(::android::OK, mGraphicBuffer->unlock());
}

}  // namespace aidl::android::hardware::graphics::composer3::vts
 No newline at end of file
Loading