diff options
Diffstat (limited to 'graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp')
-rw-r--r-- | graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp | 1455 |
1 files changed, 1455 insertions, 0 deletions
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp new file mode 100644 index 0000000000..f75af85300 --- /dev/null +++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp @@ -0,0 +1,1455 @@ +/** + * 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 <aidl/Gtest.h> +#include <aidl/Vintf.h> +#include <aidl/android/hardware/graphics/common/BufferUsage.h> +#include <aidl/android/hardware/graphics/composer3/IComposer.h> +#include <gtest/gtest.h> +#include <ui/DisplayId.h> +#include <ui/DisplayIdentification.h> +#include <ui/GraphicBuffer.h> +#include <ui/PixelFormat.h> +#include <ui/Rect.h> +#include "GraphicsComposerCallback.h" +#include "ReadbackVts.h" +#include "RenderEngineVts.h" +#include "VtsComposerClient.h" + +// tinyxml2 does implicit conversions >:( +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#include <tinyxml2.h> +#pragma clang diagnostic pop + +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) { + mComposerClient = std::make_shared<VtsComposerClient>(name); + ASSERT_TRUE(mComposerClient->createClient().isOk()); + + const auto& [status, displays] = mComposerClient->getDisplays(); + ASSERT_TRUE(status.isOk()); + mDisplays = displays; + + setTestColorModes(); + + // explicitly disable vsync + for (const auto& display : mDisplays) { + EXPECT_TRUE(mComposerClient->setVsync(display.getDisplayId(), /*enable*/ false).isOk()); + } + mComposerClient->setVsyncAllowed(/*isAllowed*/ false); + + EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk()); + + ASSERT_NO_FATAL_FAILURE( + mTestRenderEngine = std::unique_ptr<TestRenderEngine>(new TestRenderEngine( + ::android::renderengine::RenderEngineCreationArgs::Builder() + .setPixelFormat(static_cast<int>(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(getDisplayWidth(), getDisplayHeight()); + clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay; + + mTestRenderEngine->initGraphicBuffer( + static_cast<uint32_t>(getDisplayWidth()), static_cast<uint32_t>(getDisplayHeight()), + /*layerCount*/ 1U, + static_cast<uint64_t>( + static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) | + static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) | + static_cast<uint64_t>(common::BufferUsage::GPU_RENDER_TARGET))); + mTestRenderEngine->setDisplaySettings(clientCompositionDisplay); + } + + void TearDown() override { + ASSERT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::OFF).isOk()); + ASSERT_TRUE(mComposerClient->tearDown()); + mComposerClient.reset(); + const auto errors = mReader.takeErrors(); + ASSERT_TRUE(mReader.takeErrors().empty()); + ASSERT_TRUE(mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()); + } + + const VtsDisplay& getPrimaryDisplay() const { return mDisplays[0]; } + + int64_t getPrimaryDisplayId() const { return getPrimaryDisplay().getDisplayId(); } + + int64_t getInvalidDisplayId() const { return mComposerClient->getInvalidDisplayId(); } + + int32_t getDisplayWidth() const { return getPrimaryDisplay().getDisplayWidth(); } + + int32_t getDisplayHeight() const { return getPrimaryDisplay().getDisplayHeight(); } + + std::pair<bool, ::android::sp<::android::GraphicBuffer>> allocateBuffer(uint32_t usage) { + const auto width = static_cast<uint32_t>(getDisplayWidth()); + const auto height = static_cast<uint32_t>(getDisplayHeight()); + + const auto& graphicBuffer = ::android::sp<::android::GraphicBuffer>::make( + width, height, ::android::PIXEL_FORMAT_RGBA_8888, + /*layerCount*/ 1u, usage, "VtsHalGraphicsComposer3_ReadbackTest"); + + if (graphicBuffer && ::android::OK == graphicBuffer->initCheck()) { + return {true, graphicBuffer}; + } + return {false, graphicBuffer}; + } + + uint64_t getStableDisplayId(int64_t display) { + const auto& [status, identification] = + mComposerClient->getDisplayIdentificationData(display); + EXPECT_TRUE(status.isOk()); + + if (const auto info = ::android::parseDisplayIdentificationData( + static_cast<uint8_t>(identification.port), identification.data)) { + return info->id.value; + } + + return ::android::PhysicalDisplayId::fromPort(static_cast<uint8_t>(identification.port)) + .value; + } + + // Gets the per-display XML config + std::unique_ptr<tinyxml2::XMLDocument> getDisplayConfigXml(int64_t display) { + std::stringstream pathBuilder; + pathBuilder << "/vendor/etc/displayconfig/display_id_" << getStableDisplayId(display) + << ".xml"; + const std::string path = pathBuilder.str(); + auto document = std::make_unique<tinyxml2::XMLDocument>(); + const tinyxml2::XMLError error = document->LoadFile(path.c_str()); + if (error == tinyxml2::XML_SUCCESS) { + return document; + } else { + return nullptr; + } + } + + // Gets the max display brightness for this display. + // If the display config xml does not exist, then assume that the display is not well-configured + // enough to provide a display brightness, so return nullopt. + std::optional<float> getMaxDisplayBrightnessNits(int64_t display) { + const auto document = getDisplayConfigXml(display); + if (!document) { + // Assume the device doesn't support display brightness + return std::nullopt; + } + + const auto root = document->RootElement(); + if (!root) { + // If there's somehow no root element, then this isn't a valid config + return std::nullopt; + } + + const auto screenBrightnessMap = root->FirstChildElement("screenBrightnessMap"); + if (!screenBrightnessMap) { + // A valid display config must have a screen brightness map + return std::nullopt; + } + + auto point = screenBrightnessMap->FirstChildElement("point"); + float maxNits = -1.f; + while (point != nullptr) { + const auto nits = point->FirstChildElement("nits"); + if (nits) { + maxNits = std::max(maxNits, nits->FloatText(-1.f)); + } + point = point->NextSiblingElement("point"); + } + + if (maxNits < 0.f) { + // If we got here, then there were no point elements containing a nit value, so this + // config isn't valid + return std::nullopt; + } + + return maxNits; + } + + void writeLayers(const std::vector<std::shared_ptr<TestLayer>>& layers) { + for (const auto& layer : layers) { + layer->write(mWriter); + } + execute(); + } + + void execute() { + const auto& commands = mWriter.getPendingCommands(); + if (commands.empty()) { + mWriter.reset(); + return; + } + + auto [status, results] = mComposerClient->executeCommands(commands); + ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription(); + + mReader.parse(std::move(results)); + mWriter.reset(); + } + + std::pair<ScopedAStatus, bool> getHasReadbackBuffer() { + auto [status, readBackBufferAttributes] = + mComposerClient->getReadbackBufferAttributes(getPrimaryDisplayId()); + if (status.isOk()) { + mPixelFormat = readBackBufferAttributes.format; + mDataspace = readBackBufferAttributes.dataspace; + return {std::move(status), ReadbackHelper::readbackSupported(mPixelFormat, mDataspace)}; + } + return {std::move(status), false}; + } + + std::shared_ptr<VtsComposerClient> mComposerClient; + std::vector<VtsDisplay> mDisplays; + // use the slot count usually set by SF + std::vector<ColorMode> mTestColorModes; + ComposerClientWriter mWriter; + ComposerClientReader mReader; + std::unique_ptr<TestRenderEngine> mTestRenderEngine; + common::PixelFormat mPixelFormat; + common::Dataspace mDataspace; + + static constexpr uint32_t kClientTargetSlotCount = 64; + + private: + void setTestColorModes() { + mTestColorModes.clear(); + const auto& [status, modes] = mComposerClient->getColorModes(getPrimaryDisplayId()); + ASSERT_TRUE(status.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<std::string> { + public: + void SetUp() override { SetUpBase(GetParam()); } +}; + +TEST_P(GraphicsCompositionTest, SingleSolidColorLayer) { + for (ColorMode mode : mTestColorModes) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + auto layer = std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId()); + common::Rect coloredSquare({0, 0, getDisplayWidth(), getDisplayHeight()}); + layer->setColor(BLUE); + layer->setDisplayFrame(coloredSquare); + layer->setZOrder(10); + + std::vector<std::shared_ptr<TestLayer>> layers = {layer}; + + // expected color for each pixel + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), coloredSquare, BLUE); + + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + // if hwc cannot handle and asks for composition change, + // just succeed the test + if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { + GTEST_SUCCEED(); + return; + } + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + + 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) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), + {0, 0, getDisplayWidth(), getDisplayHeight() / 4}, RED); + ReadbackHelper::fillColorsArea( + expectedColors, getDisplayWidth(), + {0, getDisplayHeight() / 4, getDisplayWidth(), getDisplayHeight() / 2}, GREEN); + ReadbackHelper::fillColorsArea( + expectedColors, getDisplayWidth(), + {0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}, BLUE); + + auto layer = std::make_shared<TestBufferLayer>( + mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(), + getDisplayHeight(), common::PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); + layer->setZOrder(10); + layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); + + std::vector<std::shared_ptr<TestLayer>> layers = {layer}; + + writeLayers(layers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + + if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { + GTEST_SUCCEED(); + return; + } + ASSERT_TRUE(mReader.takeErrors().empty()); + + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + + ASSERT_TRUE(mReader.takeErrors().empty()); + + 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) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + auto layer = std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId()); + common::Rect coloredSquare({0, 0, getDisplayWidth(), getDisplayHeight()}); + layer->setColor(BLUE); + layer->setDisplayFrame(coloredSquare); + layer->setZOrder(10); + layer->write(mWriter); + + // This following buffer call should have no effect + const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) | + static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN); + const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(usage); + ASSERT_TRUE(graphicBufferStatus); + const auto& buffer = graphicBuffer->handle; + mWriter.setLayerBuffer(getPrimaryDisplayId(), layer->getLayer(), /*slot*/ 0, buffer, + /*acquireFence*/ -1); + + // expected color for each pixel + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), coloredSquare, BLUE); + + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + + if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { + GTEST_SUCCEED(); + return; + } + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + } +} + +TEST_P(GraphicsCompositionTest, SetReadbackBuffer) { + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); +} + +TEST_P(GraphicsCompositionTest, SetReadbackBuffer_BadDisplay) { + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) | + static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN); + const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(usage); + ASSERT_TRUE(graphicBufferStatus); + const auto& bufferHandle = graphicBuffer->handle; + ::ndk::ScopedFileDescriptor fence = ::ndk::ScopedFileDescriptor(-1); + + const auto status = + mComposerClient->setReadbackBuffer(getInvalidDisplayId(), bufferHandle, fence); + + EXPECT_FALSE(status.isOk()); + ASSERT_EQ(IComposerClient::EX_BAD_DISPLAY, status.getServiceSpecificError()); +} + +TEST_P(GraphicsCompositionTest, SetReadbackBuffer_BadParameter) { + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + const native_handle_t bufferHandle{}; + ndk::ScopedFileDescriptor releaseFence = ndk::ScopedFileDescriptor(-1); + const auto status = + mComposerClient->setReadbackBuffer(getPrimaryDisplayId(), &bufferHandle, releaseFence); + + EXPECT_FALSE(status.isOk()); + ASSERT_EQ(IComposerClient::EX_BAD_PARAMETER, status.getServiceSpecificError()); +} + +TEST_P(GraphicsCompositionTest, GetReadbackBufferFenceInactive) { + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + const auto& [status, releaseFence] = + mComposerClient->getReadbackBufferFence(getPrimaryDisplayId()); + + EXPECT_FALSE(status.isOk()); + EXPECT_EQ(IComposerClient::EX_UNSUPPORTED, status.getServiceSpecificError()); + EXPECT_EQ(-1, releaseFence.get()); +} + +TEST_P(GraphicsCompositionTest, ClientComposition) { + EXPECT_TRUE( + mComposerClient->setClientTargetSlotCount(getPrimaryDisplayId(), kClientTargetSlotCount) + .isOk()); + + for (ColorMode mode : mTestColorModes) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), + {0, 0, getDisplayWidth(), getDisplayHeight() / 4}, RED); + ReadbackHelper::fillColorsArea( + expectedColors, getDisplayWidth(), + {0, getDisplayHeight() / 4, getDisplayWidth(), getDisplayHeight() / 2}, GREEN); + ReadbackHelper::fillColorsArea( + expectedColors, getDisplayWidth(), + {0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}, BLUE); + + auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine, + getPrimaryDisplayId(), getDisplayWidth(), + getDisplayHeight(), PixelFormat::RGBA_FP16); + layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); + layer->setZOrder(10); + layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + + std::vector<std::shared_ptr<TestLayer>> layers = {layer}; + + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(layers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + + auto changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId()); + if (!changedCompositionTypes.empty()) { + ASSERT_EQ(1, changedCompositionTypes.size()); + ASSERT_EQ(Composition::CLIENT, changedCompositionTypes[0].composition); + + PixelFormat clientFormat = PixelFormat::RGBA_8888; + auto clientUsage = static_cast<uint32_t>( + static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN) | + static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) | + static_cast<uint32_t>(common::BufferUsage::COMPOSER_CLIENT_TARGET)); + Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode); + common::Rect damage{0, 0, getDisplayWidth(), getDisplayHeight()}; + + // create client target buffer + const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(clientUsage); + ASSERT_TRUE(graphicBufferStatus); + const auto& buffer = graphicBuffer->handle; + void* clientBufData; + const auto stride = static_cast<uint32_t>(graphicBuffer->stride); + graphicBuffer->lock(clientUsage, layer->getAccessRegion(), &clientBufData); + + ASSERT_NO_FATAL_FAILURE( + ReadbackHelper::fillBuffer(layer->getWidth(), layer->getHeight(), stride, + clientBufData, clientFormat, expectedColors)); + int32_t clientFence; + const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence); + ASSERT_EQ(::android::OK, unlockStatus); + mWriter.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, buffer, clientFence, + clientDataspace, std::vector<common::Rect>(1, damage)); + layer->setToClientComposition(mWriter); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId()); + ASSERT_TRUE(changedCompositionTypes.empty()); + } + ASSERT_TRUE(mReader.takeErrors().empty()); + + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + + ASSERT_TRUE(mReader.takeErrors().empty()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + } +} + +TEST_P(GraphicsCompositionTest, DeviceAndClientComposition) { + ASSERT_TRUE( + mComposerClient->setClientTargetSlotCount(getPrimaryDisplayId(), kClientTargetSlotCount) + .isOk()); + + for (ColorMode mode : mTestColorModes) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), + {0, 0, getDisplayWidth(), getDisplayHeight() / 2}, GREEN); + ReadbackHelper::fillColorsArea( + expectedColors, getDisplayWidth(), + {0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}, RED); + + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + auto deviceLayer = std::make_shared<TestBufferLayer>( + mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(), + getDisplayHeight() / 2, PixelFormat::RGBA_8888); + std::vector<Color> deviceColors(deviceLayer->getWidth() * deviceLayer->getHeight()); + ReadbackHelper::fillColorsArea(deviceColors, static_cast<int32_t>(deviceLayer->getWidth()), + {0, 0, static_cast<int32_t>(deviceLayer->getWidth()), + static_cast<int32_t>(deviceLayer->getHeight())}, + GREEN); + deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->getWidth()), + static_cast<int32_t>(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<uint32_t>( + static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) | + static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) | + static_cast<uint32_t>(common::BufferUsage::COMPOSER_CLIENT_TARGET)); + Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode); + int32_t clientWidth = getDisplayWidth(); + int32_t clientHeight = getDisplayHeight() / 2; + + auto clientLayer = std::make_shared<TestBufferLayer>( + mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), clientWidth, + clientHeight, PixelFormat::RGBA_FP16, Composition::DEVICE); + common::Rect clientFrame = {0, getDisplayHeight() / 2, getDisplayWidth(), + getDisplayHeight()}; + clientLayer->setDisplayFrame(clientFrame); + clientLayer->setZOrder(0); + clientLayer->write(mWriter); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + + auto changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId()); + if (changedCompositionTypes.size() != 1) { + continue; + } + // create client target buffer + ASSERT_EQ(Composition::CLIENT, changedCompositionTypes[0].composition); + const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(clientUsage); + ASSERT_TRUE(graphicBufferStatus); + const auto& buffer = graphicBuffer->handle; + + void* clientBufData; + graphicBuffer->lock(clientUsage, {0, 0, getDisplayWidth(), getDisplayHeight()}, + &clientBufData); + + std::vector<Color> clientColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + ReadbackHelper::fillColorsArea(clientColors, getDisplayWidth(), clientFrame, RED); + ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer( + static_cast<uint32_t>(getDisplayWidth()), static_cast<uint32_t>(getDisplayHeight()), + graphicBuffer->getStride(), clientBufData, clientFormat, clientColors)); + int32_t clientFence; + const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence); + ASSERT_EQ(::android::OK, unlockStatus); + mWriter.setClientTarget(getPrimaryDisplayId(), /*slot*/ 0, buffer, clientFence, + clientDataspace, std::vector<common::Rect>(1, clientFrame)); + clientLayer->setToClientComposition(mWriter); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId()); + ASSERT_TRUE(changedCompositionTypes.empty()); + ASSERT_TRUE(mReader.takeErrors().empty()); + + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + } +} + +TEST_P(GraphicsCompositionTest, SetLayerDamage) { + for (ColorMode mode : mTestColorModes) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + common::Rect redRect = {0, 0, getDisplayWidth() / 4, getDisplayHeight() / 4}; + + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), redRect, RED); + + auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine, + getPrimaryDisplayId(), getDisplayWidth(), + getDisplayHeight(), PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); + layer->setZOrder(10); + layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); + + std::vector<std::shared_ptr<TestLayer>> layers = {layer}; + + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { + GTEST_SUCCEED(); + return; + } + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + + // update surface damage and recheck + redRect = {getDisplayWidth() / 4, getDisplayHeight() / 4, getDisplayWidth() / 2, + getDisplayHeight() / 2}; + ReadbackHelper::clearColors(expectedColors, getDisplayWidth(), getDisplayHeight(), + getDisplayWidth()); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), redRect, RED); + + ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors)); + layer->setSurfaceDamage( + std::vector<common::Rect>(1, {0, 0, getDisplayWidth() / 2, getDisplayWidth() / 2})); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + ASSERT_TRUE(mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()); + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + } +} + +TEST_P(GraphicsCompositionTest, SetLayerPlaneAlpha) { + for (ColorMode mode : mTestColorModes) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + auto layer = std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId()); + layer->setColor(RED); + layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); + layer->setZOrder(10); + layer->setAlpha(0); + layer->setBlendMode(BlendMode::PREMULTIPLIED); + + std::vector<std::shared_ptr<TestLayer>> layers = {layer}; + + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { + GTEST_SUCCEED(); + return; + } + ASSERT_TRUE(mReader.takeErrors().empty()); + + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + + 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) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), + {0, 0, getDisplayWidth(), getDisplayHeight() / 4}, RED); + ReadbackHelper::fillColorsArea( + expectedColors, getDisplayWidth(), + {0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}, BLUE); + + auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine, + getPrimaryDisplayId(), getDisplayWidth(), + getDisplayHeight(), PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); + layer->setZOrder(10); + layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + layer->setSourceCrop({0, static_cast<float>(getDisplayHeight() / 2), + static_cast<float>(getDisplayWidth()), + static_cast<float>(getDisplayHeight())}); + ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); + + std::vector<std::shared_ptr<TestLayer>> layers = {layer}; + + // update expected colors to match crop + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), + {0, 0, getDisplayWidth(), getDisplayHeight()}, BLUE); + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(layers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { + GTEST_SUCCEED(); + return; + } + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + 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) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + common::Rect redRect = {0, 0, getDisplayWidth(), getDisplayHeight() / 2}; + common::Rect blueRect = {0, getDisplayHeight() / 4, getDisplayWidth(), getDisplayHeight()}; + auto redLayer = std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId()); + redLayer->setColor(RED); + redLayer->setDisplayFrame(redRect); + + auto blueLayer = std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId()); + blueLayer->setColor(BLUE); + blueLayer->setDisplayFrame(blueRect); + blueLayer->setZOrder(5); + + std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, blueLayer}; + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + + // red in front of blue + redLayer->setZOrder(10); + + // fill blue first so that red will overwrite on overlap + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), blueRect, BLUE); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), redRect, RED); + + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { + GTEST_SUCCEED(); + return; + } + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + + redLayer->setZOrder(1); + ReadbackHelper::clearColors(expectedColors, getDisplayWidth(), getDisplayHeight(), + getDisplayWidth()); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), redRect, RED); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), blueRect, BLUE); + + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + ASSERT_TRUE(mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + + 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, SetLayerBrightnessDims) { + const auto& [status, capabilities] = + mComposerClient->getDisplayCapabilities(getPrimaryDisplayId()); + ASSERT_TRUE(status.isOk()); + + const bool brightnessSupport = std::find(capabilities.begin(), capabilities.end(), + DisplayCapability::BRIGHTNESS) != capabilities.end(); + + if (!brightnessSupport) { + GTEST_SUCCEED() << "Cannot verify dimming behavior without brightness support"; + return; + } + + const std::optional<float> maxBrightnessNitsOptional = + getMaxDisplayBrightnessNits(getPrimaryDisplayId()); + + ASSERT_TRUE(maxBrightnessNitsOptional.has_value()); + + const float maxBrightnessNits = *maxBrightnessNitsOptional; + + // Preconditions to successfully run are knowing the max brightness and successfully applying + // the max brightness + ASSERT_GT(maxBrightnessNits, 0.f); + mWriter.setDisplayBrightness(getPrimaryDisplayId(), /*brightness*/ 1.f); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + + for (ColorMode mode : mTestColorModes) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace for " + "color mode: " + << toString(mode); + continue; + } + const common::Rect redRect = {0, 0, getDisplayWidth(), getDisplayHeight() / 2}; + const common::Rect dimmerRedRect = {0, getDisplayHeight() / 2, getDisplayWidth(), + getDisplayHeight()}; + const auto redLayer = + std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId()); + redLayer->setColor(RED); + redLayer->setDisplayFrame(redRect); + redLayer->setWhitePointNits(maxBrightnessNits); + redLayer->setBrightness(1.f); + + const auto dimmerRedLayer = + std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId()); + dimmerRedLayer->setColor(RED); + dimmerRedLayer->setDisplayFrame(dimmerRedRect); + // Intentionally use a small dimming ratio as some implementations may be more likely to + // kick into GPU composition to apply dithering when the dimming ratio is high. + static constexpr float kDimmingRatio = 0.9f; + dimmerRedLayer->setWhitePointNits(maxBrightnessNits * kDimmingRatio); + dimmerRedLayer->setBrightness(kDimmingRatio); + + const std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, dimmerRedLayer}; + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), redRect, RED); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), dimmerRedRect, DIM_RED); + + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + writeLayers(layers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { + GTEST_SUCCEED() + << "Readback verification not supported for GPU composition for color mode: " + << toString(mode); + continue; + } + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + + 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<std::tuple<std::string, std::string>> { + public: + void SetUp() override { + SetUpBase(std::get<0>(GetParam())); + // TODO(b/219590743) we should remove the below SRGB color mode + // once we have the BlendMode test fix for all the versions of the ColorMode + mTestColorModes = {ColorMode::SRGB}; + mBackgroundColor = BLACK; + mTopLayerColor = RED; + } + + void setBackgroundColor(Color color) { mBackgroundColor = color; } + + void setTopLayerColor(Color color) { mTopLayerColor = color; } + + void setUpLayers(BlendMode blendMode) { + mLayers.clear(); + std::vector<Color> topLayerPixelColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + ReadbackHelper::fillColorsArea(topLayerPixelColors, getDisplayWidth(), + {0, 0, getDisplayWidth(), getDisplayHeight()}, + mTopLayerColor); + + auto backgroundLayer = + std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId()); + backgroundLayer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); + backgroundLayer->setZOrder(0); + backgroundLayer->setColor(mBackgroundColor); + + auto layer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine, + getPrimaryDisplayId(), getDisplayWidth(), + getDisplayHeight(), PixelFormat::RGBA_8888); + layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); + 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<Color>& expectedColors) { + ASSERT_EQ(2, mLayers.size()); + ReadbackHelper::clearColors(expectedColors, getDisplayWidth(), getDisplayHeight(), + getDisplayWidth()); + + auto layer = mLayers[1]; + BlendMode blendMode = layer->getBlendMode(); + float alpha = mTopLayerColor.a * layer->getAlpha(); + if (blendMode == BlendMode::NONE) { + for (auto& expectedColor : expectedColors) { + expectedColor.r = mTopLayerColor.r * layer->getAlpha(); + expectedColor.g = mTopLayerColor.g * layer->getAlpha(); + expectedColor.b = mTopLayerColor.b * layer->getAlpha(); + expectedColor.a = alpha; + } + } else if (blendMode == BlendMode::PREMULTIPLIED) { + for (auto& expectedColor : expectedColors) { + expectedColor.r = + mTopLayerColor.r * layer->getAlpha() + mBackgroundColor.r * (1.0f - alpha); + expectedColor.g = + mTopLayerColor.g * layer->getAlpha() + mBackgroundColor.g * (1.0f - alpha); + expectedColor.b = + mTopLayerColor.b * layer->getAlpha() + mBackgroundColor.b * (1.0f - alpha); + expectedColor.a = alpha + mBackgroundColor.a * (1.0f - alpha); + } + } else if (blendMode == BlendMode::COVERAGE) { + for (auto& expectedColor : expectedColors) { + expectedColor.r = mTopLayerColor.r * alpha + mBackgroundColor.r * (1.0f - alpha); + expectedColor.g = mTopLayerColor.g * alpha + mBackgroundColor.g * (1.0f - alpha); + expectedColor.b = mTopLayerColor.b * alpha + mBackgroundColor.b * (1.0f - alpha); + expectedColor.a = mTopLayerColor.a * alpha + mBackgroundColor.a * (1.0f - alpha); + } + } + } + + protected: + std::vector<std::shared_ptr<TestLayer>> mLayers; + Color mBackgroundColor; + Color mTopLayerColor; +}; +// TODO(b/219576457) Enable tests once we have fixed the bug on composer. +TEST_P(GraphicsBlendModeCompositionTest, DISABLED_None) { + for (ColorMode mode : mTestColorModes) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + + setBackgroundColor(BLACK); + setTopLayerColor(TRANSLUCENT_RED); + setUpLayers(BlendMode::NONE); + setExpectedColors(expectedColors); + + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(mLayers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { + GTEST_SUCCEED(); + return; + } + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + + 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) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + + setBackgroundColor(BLACK); + setTopLayerColor(TRANSLUCENT_RED); + + setUpLayers(BlendMode::COVERAGE); + setExpectedColors(expectedColors); + + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(mLayers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { + GTEST_SUCCEED(); + return; + } + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors)); + } +} + +TEST_P(GraphicsBlendModeCompositionTest, Premultiplied) { + for (ColorMode mode : mTestColorModes) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + + setBackgroundColor(BLACK); + setTopLayerColor(TRANSLUCENT_RED); + setUpLayers(BlendMode::PREMULTIPLIED); + setExpectedColors(expectedColors); + + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + writeLayers(mLayers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { + GTEST_SUCCEED(); + return; + } + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + 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(); + + auto backgroundLayer = + std::make_shared<TestColorLayer>(mComposerClient, getPrimaryDisplayId()); + backgroundLayer->setColor({0.0f, 0.0f, 0.0f, 0.0f}); + backgroundLayer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); + backgroundLayer->setZOrder(0); + + mSideLength = + getDisplayWidth() < getDisplayHeight() ? getDisplayWidth() : getDisplayHeight(); + common::Rect redRect = {0, 0, mSideLength / 2, mSideLength / 2}; + common::Rect blueRect = {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength}; + + mLayer = std::make_shared<TestBufferLayer>(mComposerClient, *mTestRenderEngine, + getPrimaryDisplayId(), mSideLength, mSideLength, + PixelFormat::RGBA_8888); + mLayer->setDisplayFrame({0, 0, mSideLength, mSideLength}); + mLayer->setZOrder(10); + + std::vector<Color> baseColors(static_cast<size_t>(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<TestBufferLayer> mLayer; + std::vector<std::shared_ptr<TestLayer>> mLayers; + int mSideLength; +}; + +TEST_P(GraphicsTransformCompositionTest, FLIP_H) { + for (ColorMode mode : mTestColorModes) { + auto status = mComposerClient->setColorMode(getPrimaryDisplayId(), mode, + RenderIntent::COLORIMETRIC); + if (!status.isOk() && + (status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED || + status.getServiceSpecificError() == IComposerClient::EX_BAD_PARAMETER)) { + SUCCEED() << "ColorMode not supported, skip test"; + return; + } + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + mLayer->setTransform(Transform::FLIP_H); + mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), + {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), + {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE); + + writeLayers(mLayers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { + GTEST_SUCCEED(); + return; + } + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + + 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) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + mLayer->setTransform(Transform::FLIP_V); + mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), + {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), + {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE); + + writeLayers(mLayers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { + GTEST_SUCCEED(); + return; + } + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + 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) { + EXPECT_TRUE(mComposerClient + ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) + .isOk()); + + const auto& [readbackStatus, isSupported] = getHasReadbackBuffer(); + EXPECT_TRUE(readbackStatus.isOk()); + if (!isSupported) { + GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; + return; + } + ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), + getDisplayHeight(), mPixelFormat, mDataspace); + ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); + + mLayer->setTransform(Transform::ROT_180); + mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter); + + std::vector<Color> expectedColors( + static_cast<size_t>(getDisplayWidth() * getDisplayHeight())); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), + {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength}, + RED); + ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), + {0, 0, mSideLength / 2, mSideLength / 2}, BLUE); + + writeLayers(mLayers); + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp); + execute(); + if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { + GTEST_SUCCEED(); + return; + } + ASSERT_TRUE(mReader.takeErrors().empty()); + mWriter.presentDisplay(getPrimaryDisplayId()); + execute(); + ASSERT_TRUE(mReader.takeErrors().empty()); + 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 |