From bab8ba921fdf8bb1d9fa972a269e46ebee004444 Mon Sep 17 00:00:00 2001 From: ramindani Date: Thu, 18 Nov 2021 01:24:11 +0000 Subject: [PATCH] Readback tests from VTS 2.2 Tests are from https://source.corp.google.com/android/hardware/interfaces/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp;rcl=4796867049599ae1618d63cb93a38b269687164b;l=52 Test: atest VtsHalGraphicsComposer3_TargetTest BUG: 202766745 Change-Id: I495819c168429873dc88decb20f398569c1a8128 --- .../composer3/vts/functional/Android.bp | 15 +- .../VtsHalGraphicsComposer3_ReadbackTest.cpp | 1360 +++++++++++++++++ .../vts/functional/composer-vts/Android.bp | 14 + .../functional/composer-vts/ReadbackVts.cpp | 360 +++++ .../composer-vts/RenderEngineVts.cpp | 89 ++ .../composer-vts/include/ReadbackVts.h | 214 +++ .../composer-vts/include/RenderEngineVts.h | 71 + 7 files changed, 2122 insertions(+), 1 deletion(-) create mode 100644 graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp create mode 100644 graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp create mode 100644 graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/RenderEngineVts.cpp create mode 100644 graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h create mode 100644 graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/RenderEngineVts.h diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp index c011f737a1..9bf860934e 100644 --- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp +++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/Android.bp @@ -19,7 +19,7 @@ package { // A large-scale-change added 'default_applicable_licenses' to import // all of the 'license_kinds' from "hardware_interfaces_license" // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 + // SPDX-license-identifier-Apache-2.0 default_applicable_licenses: ["hardware_interfaces_license"], } @@ -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", diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp new file mode 100644 index 0000000000..6f83b90b13 --- /dev/null +++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_ReadbackTest.cpp @@ -0,0 +1,1360 @@ +/** + * 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. + */ + +#define LOG_TAG "graphics_composer_aidl_hal_readback_tests@3" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "composer-vts/include/GraphicsComposerCallback.h" +#include "composer-vts/include/TestCommandReader.h" + +namespace aidl::android::hardware::graphics::composer3::vts { +namespace { + +using ::android::Rect; +using common::Dataspace; +using common::PixelFormat; + +class GraphicsCompositionTestBase : public ::testing::Test { + protected: + void SetUpBase(const std::string& name) { + ndk::SpAIBinder binder(AServiceManager_waitForService(name.c_str())); + ASSERT_NE(binder, nullptr); + ASSERT_NO_FATAL_FAILURE(mComposer = IComposer::fromBinder(binder)); + ASSERT_NE(mComposer, nullptr); + ASSERT_NO_FATAL_FAILURE(mComposer->createClient(&mComposerClient)); + mComposerCallback = ::ndk::SharedRefBase::make(); + mComposerClient->registerCallback(mComposerCallback); + + // assume the first display is primary and is never removed + mPrimaryDisplay = waitForFirstDisplay(); + + int32_t activeConfig; + EXPECT_TRUE(mComposerClient->getActiveConfig(mPrimaryDisplay, &activeConfig).isOk()); + EXPECT_TRUE(mComposerClient + ->getDisplayAttribute(mPrimaryDisplay, activeConfig, + DisplayAttribute::WIDTH, &mDisplayWidth) + .isOk()); + EXPECT_TRUE(mComposerClient + ->getDisplayAttribute(mPrimaryDisplay, activeConfig, + DisplayAttribute::HEIGHT, &mDisplayHeight) + .isOk()); + + setTestColorModes(); + + // explicitly disable vsync + EXPECT_TRUE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, false).isOk()); + mComposerCallback->setVsyncAllowed(false); + + // set up command writer/reader and gralloc + mWriter = std::make_shared(1024); + mReader = std::make_unique(); + mGraphicBuffer = allocate(); + + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON)); + + ASSERT_NO_FATAL_FAILURE( + mTestRenderEngine = std::unique_ptr(new TestRenderEngine( + ::android::renderengine::RenderEngineCreationArgs::Builder() + .setPixelFormat(static_cast(common::PixelFormat::RGBA_8888)) + .setImageCacheSize(TestRenderEngine::sMaxFrameBufferAcquireBuffers) + .setUseColorManagerment(true) + .setEnableProtectedContext(false) + .setPrecacheToneMapperShaderOnly(false) + .setContextPriority(::android::renderengine::RenderEngine:: + ContextPriority::HIGH) + .build()))); + + ::android::renderengine::DisplaySettings clientCompositionDisplay; + clientCompositionDisplay.physicalDisplay = Rect(mDisplayWidth, mDisplayHeight); + clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay; + + mTestRenderEngine->initGraphicBuffer( + static_cast(mDisplayWidth), static_cast(mDisplayHeight), 1, + static_cast( + static_cast(common::BufferUsage::CPU_READ_OFTEN) | + static_cast(common::BufferUsage::CPU_WRITE_OFTEN) | + static_cast(common::BufferUsage::GPU_RENDER_TARGET))); + mTestRenderEngine->setDisplaySettings(clientCompositionDisplay); + } + + void TearDown() override { + ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF)); + EXPECT_EQ(0, mReader->mErrors.size()); + EXPECT_EQ(0, mReader->mCompositionChanges.size()); + if (mComposerCallback != nullptr) { + EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); + } + } + + ::android::sp<::android::GraphicBuffer> allocate() { + return ::android::sp<::android::GraphicBuffer>::make( + mDisplayWidth, mDisplayHeight, ::android::PIXEL_FORMAT_RGBA_8888, + /*layerCount*/ 1, + static_cast(static_cast(common::BufferUsage::CPU_WRITE_OFTEN) | + static_cast(common::BufferUsage::CPU_READ_OFTEN)), + "VtsHalGraphicsComposer3_ReadbackTest"); + } + + void clearCommandReaderState() { + mReader->mCompositionChanges.clear(); + mReader->mErrors.clear(); + } + + void writeLayers(const std::vector>& layers) { + for (auto layer : layers) { + layer->write(mWriter); + } + execute(); + } + + void execute() { + TestCommandReader* reader = mReader.get(); + CommandWriterBase* writer = mWriter.get(); + bool queueChanged = false; + int32_t commandLength = 0; + std::vector commandHandles; + ASSERT_TRUE(writer->writeQueue(&queueChanged, &commandLength, &commandHandles)); + + if (queueChanged) { + auto ret = mComposerClient->setInputCommandQueue(writer->getMQDescriptor()); + ASSERT_TRUE(ret.isOk()); + } + + ExecuteCommandsStatus commandStatus; + EXPECT_TRUE(mComposerClient->executeCommands(commandLength, commandHandles, &commandStatus) + .isOk()); + + if (commandStatus.queueChanged) { + MQDescriptor outputCommandQueue; + ASSERT_TRUE(mComposerClient->getOutputCommandQueue(&outputCommandQueue).isOk()); + reader->setMQDescriptor(outputCommandQueue); + } + ASSERT_TRUE(reader->readQueue(commandStatus.length, std::move(commandStatus.handles))); + reader->parse(); + reader->reset(); + writer->reset(); + } + + std::shared_ptr mComposer; + std::shared_ptr mComposerClient; + + std::shared_ptr mComposerCallback; + // the first display and is assumed never to be removed + int64_t mPrimaryDisplay; + int32_t mDisplayWidth; + int32_t mDisplayHeight; + std::vector mTestColorModes; + std::shared_ptr mWriter; + std::unique_ptr mReader; + ::android::sp<::android::GraphicBuffer> mGraphicBuffer; + std::unique_ptr mTestRenderEngine; + + bool mHasReadbackBuffer; + common::PixelFormat mPixelFormat; + common::Dataspace mDataspace; + + static constexpr uint32_t kClientTargetSlotCount = 64; + + private: + int64_t waitForFirstDisplay() { + while (true) { + std::vector displays = mComposerCallback->getDisplays(); + if (displays.empty()) { + usleep(5 * 1000); + continue; + } + return displays[0]; + } + } + + void setTestColorModes() { + mTestColorModes.clear(); + std::vector modes; + EXPECT_TRUE(mComposerClient->getColorModes(mPrimaryDisplay, &modes).isOk()); + + for (ColorMode mode : modes) { + if (std::find(ReadbackHelper::colorModes.begin(), ReadbackHelper::colorModes.end(), + mode) != ReadbackHelper::colorModes.end()) { + mTestColorModes.push_back(mode); + } + } + } +}; + +class GraphicsCompositionTest : public GraphicsCompositionTestBase, + public testing::WithParamInterface { + public: + void SetUp() override { SetUpBase(GetParam()); } +}; + +TEST_P(GraphicsCompositionTest, SingleSolidColorLayer) { + for (ColorMode mode : mTestColorModes) { + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + ReadbackBufferAttributes readBackBufferAttributes; + const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + auto layer = std::make_shared(mComposerClient, mPrimaryDisplay); + common::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setColor(BLUE); + layer->setDisplayFrame(coloredSquare); + layer->setZOrder(10); + + std::vector> layers = {layer}; + + // expected color for each pixel + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + // if hwc cannot handle and asks for composition change, + // just succeed the test + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(layers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); + } +} + +TEST_P(GraphicsCompositionTest, SetLayerBuffer) { + for (ColorMode mode : mTestColorModes) { + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + ReadbackBufferAttributes readBackBufferAttributes; + const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, + GREEN); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, + BLUE); + + auto layer = std::make_shared( + mComposerClient, mGraphicBuffer, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth, + mDisplayHeight, common::PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); + + std::vector> layers = {layer}; + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + + mWriter->presentDisplay(); + execute(); + + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(layers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); + } +} + +TEST_P(GraphicsCompositionTest, SetLayerBufferNoEffect) { + for (ColorMode mode : mTestColorModes) { + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + ReadbackBufferAttributes readBackBufferAttributes; + const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + auto layer = std::make_shared(mComposerClient, mPrimaryDisplay); + common::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setColor(BLUE); + layer->setDisplayFrame(coloredSquare); + layer->setZOrder(10); + layer->write(mWriter); + + // This following buffer call should have no effect + uint64_t usage = + static_cast(static_cast(common::BufferUsage::CPU_READ_OFTEN) | + static_cast(common::BufferUsage::CPU_WRITE_OFTEN)); + + mGraphicBuffer->reallocate(static_cast(mDisplayWidth), + static_cast(mDisplayHeight), 1, + static_cast(common::PixelFormat::RGBA_8888), usage); + mWriter->setLayerBuffer(0, mGraphicBuffer->handle, -1); + + // expected color for each pixel + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + mWriter->validateDisplay(); + execute(); + + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + } +} + +TEST_P(GraphicsCompositionTest, ClientComposition) { + EXPECT_TRUE(mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount) + .isOk()); + + for (ColorMode mode : mTestColorModes) { + mWriter->selectDisplay(mPrimaryDisplay); + EXPECT_TRUE(mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC) + .isOk()); + + ReadbackBufferAttributes readBackBufferAttributes; + const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, + GREEN); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, + BLUE); + + auto layer = std::make_shared( + mComposerClient, mGraphicBuffer, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth, + mDisplayHeight, PixelFormat::RGBA_FP16); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + + std::vector> layers = {layer}; + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + + if (!mReader->mCompositionChanges.empty()) { + ASSERT_EQ(1, mReader->mCompositionChanges.size()); + ASSERT_EQ(1, mReader->mCompositionChanges[0].second); + + PixelFormat clientFormat = PixelFormat::RGBA_8888; + auto clientUsage = static_cast( + static_cast(common::BufferUsage::CPU_READ_OFTEN) | + static_cast(common::BufferUsage::CPU_WRITE_OFTEN) | + static_cast(common::BufferUsage::COMPOSER_CLIENT_TARGET)); + Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode); + common::Rect damage{0, 0, mDisplayWidth, mDisplayHeight}; + + // create client target buffer + mGraphicBuffer->reallocate(layer->getWidth(), layer->getHeight(), + static_cast(common::PixelFormat::RGBA_8888), + layer->getLayerCount(), clientUsage); + + ASSERT_NE(nullptr, mGraphicBuffer->handle); + + void* clientBufData; + mGraphicBuffer->lock(clientUsage, layer->getAccessRegion(), &clientBufData); + + ASSERT_NO_FATAL_FAILURE( + ReadbackHelper::fillBuffer(layer->getWidth(), layer->getHeight(), + static_cast(mGraphicBuffer->stride), + clientBufData, clientFormat, expectedColors)); + EXPECT_EQ(::android::OK, mGraphicBuffer->unlock()); + + ndk::ScopedFileDescriptor fenceHandle; + EXPECT_TRUE( + mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fenceHandle).isOk()); + + layer->setToClientComposition(mWriter); + mWriter->acceptDisplayChanges(); + mWriter->setClientTarget(0, mGraphicBuffer->handle, fenceHandle.get(), clientDataspace, + std::vector(1, damage)); + execute(); + ASSERT_EQ(0, mReader->mCompositionChanges.size()); + } + ASSERT_EQ(0, mReader->mErrors.size()); + + mWriter->presentDisplay(); + execute(); + + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + } +} + +TEST_P(GraphicsCompositionTest, DeviceAndClientComposition) { + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount)); + + for (ColorMode mode : mTestColorModes) { + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + ReadbackBufferAttributes readBackBufferAttributes; + const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + auto deviceLayer = std::make_shared( + mComposerClient, mGraphicBuffer, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth, + mDisplayHeight / 2, PixelFormat::RGBA_8888); + std::vector deviceColors(deviceLayer->getWidth() * deviceLayer->getHeight()); + ReadbackHelper::fillColorsArea(deviceColors, static_cast(deviceLayer->getWidth()), + {0, 0, static_cast(deviceLayer->getWidth()), + static_cast(deviceLayer->getHeight())}, + GREEN); + deviceLayer->setDisplayFrame({0, 0, static_cast(deviceLayer->getWidth()), + static_cast(deviceLayer->getHeight())}); + deviceLayer->setZOrder(10); + deviceLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors)); + deviceLayer->write(mWriter); + + PixelFormat clientFormat = PixelFormat::RGBA_8888; + auto clientUsage = static_cast( + static_cast(common::BufferUsage::CPU_READ_OFTEN) | + static_cast(common::BufferUsage::CPU_WRITE_OFTEN) | + static_cast(common::BufferUsage::COMPOSER_CLIENT_TARGET)); + Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode); + int32_t clientWidth = mDisplayWidth; + int32_t clientHeight = mDisplayHeight / 2; + + auto clientLayer = std::make_shared( + mComposerClient, mGraphicBuffer, *mTestRenderEngine, mPrimaryDisplay, clientWidth, + clientHeight, PixelFormat::RGBA_FP16, Composition::DEVICE); + common::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}; + clientLayer->setDisplayFrame(clientFrame); + clientLayer->setZOrder(0); + clientLayer->write(mWriter); + mWriter->validateDisplay(); + execute(); + + if (mReader->mCompositionChanges.size() != 1) { + mReader->mCompositionChanges.clear(); + continue; + } + // create client target buffer + ASSERT_EQ(1, mReader->mCompositionChanges[0].second); + mGraphicBuffer->reallocate(static_cast(mDisplayWidth), + static_cast(mDisplayHeight), + static_cast(common::PixelFormat::RGBA_8888), + clientLayer->getLayerCount(), clientUsage); + ASSERT_NE(nullptr, mGraphicBuffer->handle); + + void* clientBufData; + mGraphicBuffer->lock(clientUsage, {0, 0, mDisplayWidth, mDisplayHeight}, &clientBufData); + + std::vector clientColors(static_cast(mDisplayWidth * mDisplayHeight)); + ReadbackHelper::fillColorsArea(clientColors, mDisplayWidth, clientFrame, RED); + ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer( + static_cast(mDisplayWidth), static_cast(mDisplayHeight), + mGraphicBuffer->getStride(), clientBufData, clientFormat, clientColors)); + EXPECT_EQ(::android::OK, mGraphicBuffer->unlock()); + + ndk::ScopedFileDescriptor fenceHandle; + EXPECT_TRUE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fenceHandle).isOk()); + + clientLayer->setToClientComposition(mWriter); + mWriter->acceptDisplayChanges(); + mWriter->setClientTarget(0, mGraphicBuffer->handle, fenceHandle.get(), clientDataspace, + std::vector(1, clientFrame)); + execute(); + ASSERT_EQ(0, mReader->mCompositionChanges.size()); + ASSERT_EQ(0, mReader->mErrors.size()); + + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + } +} + +TEST_P(GraphicsCompositionTest, SetLayerDamage) { + for (ColorMode mode : mTestColorModes) { + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + ReadbackBufferAttributes readBackBufferAttributes; + const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + common::Rect redRect = {0, 0, mDisplayWidth / 4, mDisplayHeight / 4}; + + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + + auto layer = std::make_shared( + mComposerClient, mGraphicBuffer, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth, + mDisplayHeight, PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); + + std::vector> layers = {layer}; + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + + // update surface damage and recheck + redRect = {mDisplayWidth / 4, mDisplayHeight / 4, mDisplayWidth / 2, mDisplayHeight / 2}; + ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + + ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors)); + layer->setSurfaceDamage( + std::vector(1, {0, 0, mDisplayWidth / 2, mDisplayWidth / 2})); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_EQ(0, mReader->mCompositionChanges.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + } +} + +TEST_P(GraphicsCompositionTest, SetLayerPlaneAlpha) { + for (ColorMode mode : mTestColorModes) { + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + ReadbackBufferAttributes readBackBufferAttributes; + const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + auto layer = std::make_shared(mComposerClient, mPrimaryDisplay); + layer->setColor(RED); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + layer->setAlpha(0); + layer->setBlendMode(BlendMode::PREMULTIPLIED); + + std::vector> layers = {layer}; + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(layers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); + } +} + +TEST_P(GraphicsCompositionTest, SetLayerSourceCrop) { + for (ColorMode mode : mTestColorModes) { + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + ReadbackBufferAttributes readBackBufferAttributes; + const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, + BLUE); + + auto layer = std::make_shared( + mComposerClient, mGraphicBuffer, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth, + mDisplayHeight, PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + layer->setSourceCrop({0, static_cast(mDisplayHeight / 2), + static_cast(mDisplayWidth), + static_cast(mDisplayHeight)}); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); + + std::vector> layers = {layer}; + + // update expected colors to match crop + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight}, BLUE); + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(layers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); + } +} + +TEST_P(GraphicsCompositionTest, SetLayerZOrder) { + for (ColorMode mode : mTestColorModes) { + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + ReadbackBufferAttributes readBackBufferAttributes; + const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + common::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2}; + common::Rect blueRect = {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight}; + auto redLayer = std::make_shared(mComposerClient, mPrimaryDisplay); + redLayer->setColor(RED); + redLayer->setDisplayFrame(redRect); + + auto blueLayer = std::make_shared(mComposerClient, mPrimaryDisplay); + blueLayer->setColor(BLUE); + blueLayer->setDisplayFrame(blueRect); + blueLayer->setZOrder(5); + + std::vector> layers = {redLayer, blueLayer}; + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + + // red in front of blue + redLayer->setZOrder(10); + + // fill blue first so that red will overwrite on overlap + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + + redLayer->setZOrder(1); + ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + ASSERT_EQ(0, mReader->mCompositionChanges.size()); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(layers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); + } +} + +class GraphicsBlendModeCompositionTest + : public GraphicsCompositionTestBase, + public testing::WithParamInterface> { + public: + void SetUp() override { + SetUpBase(std::get<0>(GetParam())); + mBackgroundColor = BLACK; + mTopLayerColor = RED; + } + + void setBackgroundColor(Color color) { mBackgroundColor = color; } + + void setTopLayerColor(Color color) { mTopLayerColor = color; } + + void setUpLayers(BlendMode blendMode) { + mLayers.clear(); + std::vector topLayerPixelColors(static_cast(mDisplayWidth * mDisplayHeight)); + ReadbackHelper::fillColorsArea(topLayerPixelColors, mDisplayWidth, + {0, 0, mDisplayWidth, mDisplayHeight}, mTopLayerColor); + + auto backgroundLayer = std::make_shared(mComposerClient, mPrimaryDisplay); + backgroundLayer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + backgroundLayer->setZOrder(0); + backgroundLayer->setColor(mBackgroundColor); + + auto layer = std::make_shared( + mComposerClient, mGraphicBuffer, *mTestRenderEngine, mPrimaryDisplay, mDisplayWidth, + mDisplayHeight, PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + layer->setZOrder(10); + layer->setDataspace(Dataspace::UNKNOWN, mWriter); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(topLayerPixelColors)); + + layer->setBlendMode(blendMode); + layer->setAlpha(std::stof(std::get<1>(GetParam()))); + + mLayers.push_back(backgroundLayer); + mLayers.push_back(layer); + } + + void setExpectedColors(std::vector& expectedColors) { + ASSERT_EQ(2, mLayers.size()); + ReadbackHelper::clearColors(expectedColors, mDisplayWidth, mDisplayHeight, mDisplayWidth); + + auto layer = mLayers[1]; + BlendMode blendMode = layer->getBlendMode(); + float alpha = mTopLayerColor.a / 255.0f * layer->getAlpha(); + if (blendMode == BlendMode::NONE) { + for (auto& expectedColor : expectedColors) { + expectedColor.r = mTopLayerColor.r * static_cast(layer->getAlpha()); + expectedColor.g = mTopLayerColor.g * static_cast(layer->getAlpha()); + expectedColor.b = mTopLayerColor.b * static_cast(layer->getAlpha()); + expectedColor.a = static_cast(alpha * 255.0); + } + } else if (blendMode == BlendMode::PREMULTIPLIED) { + for (auto& expectedColor : expectedColors) { + expectedColor.r = static_cast( + mTopLayerColor.r * static_cast(layer->getAlpha()) + + mBackgroundColor.r * (1.0 - alpha)); + expectedColor.g = static_cast(mTopLayerColor.g * layer->getAlpha() + + mBackgroundColor.g * (1.0 - alpha)); + expectedColor.b = static_cast(mTopLayerColor.b * layer->getAlpha() + + mBackgroundColor.b * (1.0 - alpha)); + expectedColor.a = static_cast(alpha + mBackgroundColor.a * (1.0 - alpha)); + } + } else if (blendMode == BlendMode::COVERAGE) { + for (auto& expectedColor : expectedColors) { + expectedColor.r = static_cast(mTopLayerColor.r * alpha + + mBackgroundColor.r * (1.0 - alpha)); + expectedColor.g = static_cast(mTopLayerColor.g * alpha + + mBackgroundColor.g * (1.0 - alpha)); + expectedColor.b = static_cast(mTopLayerColor.b * alpha + + mBackgroundColor.b * (1.0 - alpha)); + expectedColor.a = static_cast(mTopLayerColor.a * alpha + + mBackgroundColor.a * (1.0 - alpha)); + } + } + } + + protected: + std::vector> mLayers; + Color mBackgroundColor; + Color mTopLayerColor; +}; + +TEST_P(GraphicsBlendModeCompositionTest, None) { + for (ColorMode mode : mTestColorModes) { + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + ReadbackBufferAttributes readBackBufferAttributes; + const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + + setBackgroundColor(BLACK); + setTopLayerColor(TRANSLUCENT_RED); + setUpLayers(BlendMode::NONE); + setExpectedColors(expectedColors); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(mLayers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); + } +} + +TEST_P(GraphicsBlendModeCompositionTest, Coverage) { + for (ColorMode mode : mTestColorModes) { + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + ReadbackBufferAttributes readBackBufferAttributes; + const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + + setBackgroundColor(BLACK); + setTopLayerColor(TRANSLUCENT_RED); + + setUpLayers(BlendMode::COVERAGE); + setExpectedColors(expectedColors); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + } +} + +TEST_P(GraphicsBlendModeCompositionTest, Premultiplied) { + for (ColorMode mode : mTestColorModes) { + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + ReadbackBufferAttributes readBackBufferAttributes; + const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + mWriter->selectDisplay(mPrimaryDisplay); + + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + + setBackgroundColor(BLACK); + setTopLayerColor(TRANSLUCENT_RED); + setUpLayers(BlendMode::PREMULTIPLIED); + setExpectedColors(expectedColors); + + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(mLayers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); + } +} + +class GraphicsTransformCompositionTest : public GraphicsCompositionTest { + protected: + void SetUp() override { + GraphicsCompositionTest::SetUp(); + mWriter->selectDisplay(mPrimaryDisplay); + auto backgroundLayer = std::make_shared(mComposerClient, mPrimaryDisplay); + backgroundLayer->setColor({0, 0, 0, 0}); + backgroundLayer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight}); + backgroundLayer->setZOrder(0); + + mSideLength = mDisplayWidth < mDisplayHeight ? mDisplayWidth : mDisplayHeight; + common::Rect redRect = {0, 0, mSideLength / 2, mSideLength / 2}; + common::Rect blueRect = {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength}; + + mLayer = std::make_shared(mComposerClient, mGraphicBuffer, + *mTestRenderEngine, mPrimaryDisplay, mSideLength, + mSideLength, PixelFormat::RGBA_8888); + mLayer->setDisplayFrame({0, 0, mSideLength, mSideLength}); + mLayer->setZOrder(10); + + std::vector baseColors(static_cast(mSideLength * mSideLength)); + ReadbackHelper::fillColorsArea(baseColors, mSideLength, redRect, RED); + ReadbackHelper::fillColorsArea(baseColors, mSideLength, blueRect, BLUE); + ASSERT_NO_FATAL_FAILURE(mLayer->setBuffer(baseColors)); + mLayers = {backgroundLayer, mLayer}; + } + + protected: + std::shared_ptr mLayer; + std::vector> mLayers; + int mSideLength; +}; + +TEST_P(GraphicsTransformCompositionTest, FLIP_H) { + for (ColorMode mode : mTestColorModes) { + ASSERT_NE(nullptr, mWriter); + mWriter->selectDisplay(mPrimaryDisplay); + auto error = + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC); + if (!error.isOk() && + (error.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED || + error.getServiceSpecificError() == IComposerClient::EX_BAD_PARAMETER)) { + SUCCEED() << "ColorMode not supported, skip test"; + return; + } + + ReadbackBufferAttributes readBackBufferAttributes; + error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + mLayer->setTransform(Transform::FLIP_H); + mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE); + + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(mLayers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); + } +} + +TEST_P(GraphicsTransformCompositionTest, FLIP_V) { + for (ColorMode mode : mTestColorModes) { + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + ReadbackBufferAttributes readBackBufferAttributes; + const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + mLayer->setTransform(Transform::FLIP_V); + mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE); + + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(mLayers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); + } +} + +TEST_P(GraphicsTransformCompositionTest, ROT_180) { + for (ColorMode mode : mTestColorModes) { + mWriter->selectDisplay(mPrimaryDisplay); + ASSERT_NO_FATAL_FAILURE( + mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC)); + + ReadbackBufferAttributes readBackBufferAttributes; + const auto error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, + &readBackBufferAttributes); + + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + mHasReadbackBuffer = + error.isOk() && ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); + if (!mHasReadbackBuffer) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGraphicBuffer, + mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + mLayer->setTransform(Transform::ROT_180); + mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + + std::vector expectedColors(static_cast(mDisplayWidth * mDisplayHeight)); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength}, + RED); + ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, + {0, 0, mSideLength / 2, mSideLength / 2}, BLUE); + + writeLayers(mLayers); + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->validateDisplay(); + execute(); + if (!mReader->mCompositionChanges.empty()) { + clearCommandReaderState(); + GTEST_SUCCEED(); + return; + } + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + mTestRenderEngine->setRenderLayers(mLayers); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); + ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->checkColorBuffer(expectedColors)); + } +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsCompositionTest); +INSTANTIATE_TEST_SUITE_P( + PerInstance, GraphicsCompositionTest, + testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)), + ::android::PrintInstanceNameToString); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsBlendModeCompositionTest); +INSTANTIATE_TEST_SUITE_P(BlendMode, GraphicsBlendModeCompositionTest, + testing::Combine(testing::ValuesIn(::android::getAidlHalInstanceNames( + IComposer::descriptor)), + testing::Values("0.2", "1.0"))); + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsTransformCompositionTest); +INSTANTIATE_TEST_SUITE_P( + PerInstance, GraphicsTransformCompositionTest, + testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)), + ::android::PrintInstanceNameToString); + +} // namespace +} // namespace aidl::android::hardware::graphics::composer3::vts \ No newline at end of file diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/Android.bp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/Android.bp index 00ea4f3d05..2b058c7fdb 100644 --- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/Android.bp +++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/Android.bp @@ -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", diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp new file mode 100644 index 0000000000..e832cb7fc5 --- /dev/null +++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/ReadbackVts.cpp @@ -0,0 +1,360 @@ +/** + * 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 +#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 ReadbackHelper::colorModes = {ColorMode::SRGB, ColorMode::DISPLAY_P3}; +const std::vector ReadbackHelper::dataspaces = {common::Dataspace::SRGB, + common::Dataspace::DISPLAY_P3}; + +void TestLayer::write(const std::shared_ptr& 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(mDisplayFrame.left), static_cast(mDisplayFrame.top), + static_cast(mDisplayFrame.right), static_cast(mDisplayFrame.bottom)); + + const ::android::mat4 translation = ::android::mat4::translate(::android::vec4( + (static_cast(mTransform) & static_cast(Transform::FLIP_H) + ? static_cast(-mDisplayFrame.right) + : 0.0f), + (static_cast(mTransform) & static_cast(Transform::FLIP_V) + ? static_cast(-mDisplayFrame.bottom) + : 0.0f), + 0.0f, 1.0f)); + + const ::android::mat4 scale = ::android::mat4::scale(::android::vec4( + static_cast(mTransform) & static_cast(Transform::FLIP_H) ? -1.0f + : 1.0f, + static_cast(mTransform) & static_cast(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 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(width) + col; + Color srcColor = desiredPixelColors[static_cast(pixel)]; + + int offset = (row * static_cast(stride) + col) * bytesPerPixel; + uint8_t* pixelColor = (uint8_t*)bufferData + offset; + pixelColor[0] = static_cast(srcColor.r); + pixelColor[1] = static_cast(srcColor.g); + pixelColor[2] = static_cast(srcColor.b); + + if (bytesPerPixel == 4) { + pixelColor[3] = static_cast(srcColor.a); + } + } + } +} + +void ReadbackHelper::clearColors(std::vector& 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(pixel)] = BLACK; + } + } +} + +void ReadbackHelper::fillColorsArea(std::vector& 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(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& 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(width) + col; + int offset = (row * stride + col) * bytesPerPixel; + uint8_t* pixelColor = (uint8_t*)bufferData + offset; + + ASSERT_EQ(static_cast(expectedColors[static_cast(pixel)].r), + pixelColor[0]); + ASSERT_EQ(static_cast(expectedColors[static_cast(pixel)].g), + pixelColor[1]); + ASSERT_EQ(static_cast(expectedColors[static_cast(pixel)].b), + pixelColor[2]); + } + } +} + +ReadbackBuffer::ReadbackBuffer(int64_t display, const std::shared_ptr& 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(width); + mHeight = static_cast(height); + mLayerCount = 1; + mUsage = static_cast(static_cast(common::BufferUsage::CPU_READ_OFTEN) | + static_cast(common::BufferUsage::GPU_TEXTURE)); + + mAccessRegion.top = 0; + mAccessRegion.left = 0; + mAccessRegion.right = static_cast(width); + mAccessRegion.bottom = static_cast(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 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(mStride), mWidth, mHeight, + mPixelFormat); + status = mGraphicBuffer->unlock(); + EXPECT_EQ(::android::OK, status); +} + +void TestColorLayer::write(const std::shared_ptr& 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((static_cast<::android::half>(mColor.a) / 255.0)); + return layerSettings; +} + +TestBufferLayer::TestBufferLayer(const std::shared_ptr& 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(common::BufferUsage::CPU_READ_OFTEN) | + static_cast(common::BufferUsage::CPU_WRITE_OFTEN) | + static_cast(common::BufferUsage::COMPOSER_OVERLAY) | + static_cast(common::BufferUsage::GPU_TEXTURE)); + + mAccessRegion.top = 0; + mAccessRegion.left = 0; + mAccessRegion.right = static_cast(width); + mAccessRegion.bottom = static_cast(height); + + setSourceCrop({0, 0, (float)width, (float)height}); +} + +void TestBufferLayer::write(const std::shared_ptr& writer) { + TestLayer::write(writer); + writer->setLayerCompositionType(mComposition); + writer->setLayerVisibleRegion(std::vector(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(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(mWidth)); + const float scaleY = (mSourceCrop.bottom - mSourceCrop.top) / (static_cast(mHeight)); + const float translateX = mSourceCrop.left / (static_cast(mWidth)); + const float translateY = mSourceCrop.top / (static_cast(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& 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 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& writer) { + writer->selectLayer(mLayer); + writer->setLayerDataspace(dataspace); +} + +void TestBufferLayer::setToClientComposition(const std::shared_ptr& writer) { + writer->selectLayer(mLayer); + writer->setLayerCompositionType(Composition::CLIENT); +} + +} // namespace aidl::android::hardware::graphics::composer3::vts \ No newline at end of file diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/RenderEngineVts.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/RenderEngineVts.cpp new file mode 100644 index 0000000000..e83750e508 --- /dev/null +++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/RenderEngineVts.cpp @@ -0,0 +1,89 @@ +/** + * 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(args.pixelFormat); + mRenderEngine = ::android::renderengine::RenderEngine::create(args); +} + +TestRenderEngine::~TestRenderEngine() { + mRenderEngine.release(); +} + +void TestRenderEngine::setRenderLayers(std::vector> layers) { + sort(layers.begin(), layers.end(), + [](const std::shared_ptr& lhs, const std::shared_ptr& 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(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& expectedColors) { + void* bufferData; + ASSERT_EQ(0, + mGraphicBuffer->lock(static_cast(mGraphicBuffer->getUsage()), &bufferData)); + ReadbackHelper::compareColorBuffers( + expectedColors, bufferData, static_cast(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 diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h new file mode 100644 index 0000000000..58989d8286 --- /dev/null +++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/ReadbackVts.h @@ -0,0 +1,214 @@ +/** + * 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. + */ + +#pragma once + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion + +namespace aidl::android::hardware::graphics::composer3::vts { + +using ::android::renderengine::LayerSettings; +using common::Dataspace; +using common::PixelFormat; +using IMapper2_1 = ::android::hardware::graphics::mapper::V2_1::IMapper; + +static const Color BLACK = {0, 0, 0, static_cast(0xff)}; +static const Color RED = {static_cast(0xff), 0, 0, static_cast(0xff)}; +static const Color TRANSLUCENT_RED = {static_cast(0xff), 0, 0, 0x33}; +static const Color GREEN = {0, static_cast(0xff), 0, static_cast(0xff)}; +static const Color BLUE = {0, 0, static_cast(0xff), static_cast(0xff)}; +static const Color WHITE = {static_cast(0xff), static_cast(0xff), + static_cast(0xff), static_cast(0xff)}; + +class TestRenderEngine; + +class TestLayer { + public: + TestLayer(const std::shared_ptr& client, int32_t display) + : mComposerClient(client) { + client->createLayer(display, kBufferSlotCount, &mLayer); + } + + // ComposerClient will take care of destroying layers, no need to explicitly + // call destroyLayers here + virtual ~TestLayer(){}; + + virtual void write(const std::shared_ptr& writer); + virtual LayerSettings toRenderEngineLayerSettings(); + + void setDisplayFrame(Rect frame) { mDisplayFrame = frame; } + void setSourceCrop(FRect crop) { mSourceCrop = crop; } + void setZOrder(uint32_t z) { mZOrder = z; } + + void setSurfaceDamage(std::vector surfaceDamage) { + mSurfaceDamage = std::move(surfaceDamage); + } + + void setTransform(Transform transform) { mTransform = transform; } + void setAlpha(float alpha) { mAlpha = alpha; } + void setBlendMode(BlendMode blendMode) { mBlendMode = blendMode; } + + BlendMode getBlendMode() const { return mBlendMode; } + + uint32_t getZOrder() const { return mZOrder; } + + float getAlpha() const { return mAlpha; } + + protected: + int64_t mLayer; + Rect mDisplayFrame = {0, 0, 0, 0}; + std::vector mSurfaceDamage; + Transform mTransform = static_cast(0); + FRect mSourceCrop = {0, 0, 0, 0}; + static constexpr uint32_t kBufferSlotCount = 64; + float mAlpha = 1.0; + BlendMode mBlendMode = BlendMode::NONE; + uint32_t mZOrder = 0; + + private: + std::shared_ptr const mComposerClient; +}; + +class TestColorLayer : public TestLayer { + public: + TestColorLayer(const std::shared_ptr& client, int32_t display) + : TestLayer{client, display} {} + + void write(const std::shared_ptr& writer) override; + + LayerSettings toRenderEngineLayerSettings() override; + + void setColor(Color color) { mColor = color; } + + private: + Color mColor = WHITE; +}; + +class TestBufferLayer : public TestLayer { + public: + TestBufferLayer(const std::shared_ptr& client, + const ::android::sp<::android::GraphicBuffer>& graphicBuffer, + TestRenderEngine& renderEngine, int32_t display, uint32_t width, + uint32_t height, common::PixelFormat format, + Composition composition = Composition::DEVICE); + + void write(const std::shared_ptr& writer) override; + + LayerSettings toRenderEngineLayerSettings() override; + + void fillBuffer(std::vector& expectedColors); + + void setBuffer(std::vector colors); + + void setDataspace(Dataspace dataspace, const std::shared_ptr& writer); + + void setToClientComposition(const std::shared_ptr& writer); + + uint32_t getWidth() const { return mWidth; } + + uint32_t getHeight() const { return mHeight; } + + ::android::Rect getAccessRegion() const { return mAccessRegion; } + + uint32_t getLayerCount() const { return mLayerCount; } + + protected: + Composition mComposition; + ::android::sp<::android::GraphicBuffer> mGraphicBuffer; + TestRenderEngine& mRenderEngine; + int32_t mFillFence; + uint32_t mWidth; + uint32_t mHeight; + uint32_t mLayerCount; + PixelFormat mPixelFormat; + uint32_t mUsage; + uint32_t mStride; + ::android::Rect mAccessRegion; +}; + +class ReadbackHelper { + public: + static std::string getColorModeString(ColorMode mode); + + static std::string getDataspaceString(Dataspace dataspace); + + static Dataspace getDataspaceForColorMode(ColorMode mode); + + static int32_t GetBytesPerPixel(PixelFormat pixelFormat); + + static void fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData, + PixelFormat pixelFormat, std::vector desiredPixelColors); + + static void clearColors(std::vector& expectedColors, int32_t width, int32_t height, + int32_t displayWidth); + + static void fillColorsArea(std::vector& expectedColors, int32_t stride, Rect area, + Color color); + + static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace); + + static const std::vector colorModes; + static const std::vector dataspaces; + + static void compareColorBuffers(std::vector& expectedColors, void* bufferData, + const int32_t stride, const uint32_t width, + const uint32_t height, PixelFormat pixelFormat); +}; + +class ReadbackBuffer { + public: + ReadbackBuffer(int64_t display, const std::shared_ptr& client, + const ::android::sp<::android::GraphicBuffer>& graphicBuffer, int32_t width, + int32_t height, common::PixelFormat pixelFormat, common::Dataspace dataspace); + + void setReadbackBuffer(); + + void checkReadbackBuffer(std::vector expectedColors); + + ::android::sp<::android::GraphicBuffer> allocate(); + + protected: + uint32_t mWidth; + uint32_t mHeight; + uint32_t mLayerCount; + uint32_t mUsage; + uint32_t mStride; + PixelFormat mPixelFormat; + Dataspace mDataspace; + int64_t mDisplay; + ::android::sp<::android::GraphicBuffer> mGraphicBuffer; + std::shared_ptr mComposerClient; + ::android::Rect mAccessRegion; + native_handle_t mBufferHandle; +}; + +} // namespace aidl::android::hardware::graphics::composer3::vts \ No newline at end of file diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/RenderEngineVts.h b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/RenderEngineVts.h new file mode 100644 index 0000000000..eaff6d7851 --- /dev/null +++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/composer-vts/include/RenderEngineVts.h @@ -0,0 +1,71 @@ +/** + * 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. + */ +#pragma once + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion + +namespace aidl::android::hardware::graphics::composer3::vts { + +using ::android::hardware::graphics::mapper::V2_1::IMapper; +using ::android::renderengine::DisplaySettings; +using ::android::renderengine::ExternalTexture; +using ::android::renderengine::RenderEngineCreationArgs; + +class TestRenderEngine { + public: + static constexpr uint32_t sMaxFrameBufferAcquireBuffers = 2; + + TestRenderEngine(const RenderEngineCreationArgs& args); + ~TestRenderEngine(); + + void setRenderLayers(std::vector> layers); + void initGraphicBuffer(uint32_t width, uint32_t height, uint32_t layerCount, uint64_t usage); + void setDisplaySettings(DisplaySettings& displaySettings) { + mDisplaySettings = displaySettings; + }; + void drawLayers(); + void checkColorBuffer(std::vector& expectedColors); + + ::android::renderengine::RenderEngine& getInternalRenderEngine() { return *mRenderEngine; } + + private: + common::PixelFormat mFormat; + std::vector<::android::renderengine::LayerSettings> mCompositionLayers; + std::unique_ptr<::android::renderengine::RenderEngine> mRenderEngine; + std::vector<::android::renderengine::LayerSettings> mRenderLayers; + ::android::sp<::android::GraphicBuffer> mGraphicBuffer; + + DisplaySettings mDisplaySettings; +}; + +} // namespace aidl::android::hardware::graphics::composer3::vts \ No newline at end of file