/** * 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 "GraphicsComposerCallback.h" #include "ReadbackVts.h" #include "RenderEngineVts.h" #include "VtsComposerClient.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) { mComposerClient = std::make_shared(name); ASSERT_TRUE(mComposerClient->createClient().isOk()); const auto& [status, displays] = mComposerClient->getDisplays(); ASSERT_TRUE(status.isOk()); mDisplays = displays; mWriter.reset(new ComposerClientWriter(getPrimaryDisplayId())); 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()); const auto format = getHasReadbackBuffer() ? mPixelFormat : common::PixelFormat::RGBA_8888; ASSERT_NO_FATAL_FAILURE( mTestRenderEngine = std::unique_ptr(new TestRenderEngine( ::android::renderengine::RenderEngineCreationArgs::Builder() .setPixelFormat(static_cast(format)) .setImageCacheSize(TestRenderEngine::sMaxFrameBufferAcquireBuffers) .setEnableProtectedContext(false) .setPrecacheToneMapperShaderOnly(false) .setContextPriority(::android::renderengine::RenderEngine:: ContextPriority::HIGH) .build()))); mClientCompositionDisplaySettings.physicalDisplay = Rect(getDisplayWidth(), getDisplayHeight()); mClientCompositionDisplaySettings.clip = mClientCompositionDisplaySettings.physicalDisplay; mTestRenderEngine->initGraphicBuffer( static_cast(getDisplayWidth()), static_cast(getDisplayHeight()), /*layerCount*/ 1U, 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(mClientCompositionDisplaySettings); } void TearDown() override { ASSERT_FALSE(mDisplays.empty()); ASSERT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::OFF).isOk()); ASSERT_TRUE(mComposerClient->tearDown(mWriter.get())); 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(); } void assertServiceSpecificError(const ScopedAStatus& status, int32_t serviceSpecificError) { ASSERT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC); ASSERT_EQ(status.getServiceSpecificError(), serviceSpecificError); } std::pair> allocateBuffer(uint32_t usage) { const auto width = static_cast(getDisplayWidth()); const auto height = static_cast(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}; } void writeLayers(const std::vector>& layers) { for (const auto& layer : layers) { layer->write(*mWriter); } execute(); } void execute() { auto commands = mWriter->takePendingCommands(); if (commands.empty()) { return; } auto [status, results] = mComposerClient->executeCommands(commands); ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription(); mReader.parse(std::move(results)); } bool getHasReadbackBuffer() { auto [status, readBackBufferAttributes] = mComposerClient->getReadbackBufferAttributes(getPrimaryDisplayId()); if (status.isOk()) { mPixelFormat = readBackBufferAttributes.format; mDataspace = readBackBufferAttributes.dataspace; return ReadbackHelper::readbackSupported(mPixelFormat, mDataspace); } EXPECT_NO_FATAL_FAILURE( assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED)); return false; } std::shared_ptr mComposerClient; std::vector mDisplays; // use the slot count usually set by SF std::vector mTestColorModes; std::unique_ptr mWriter; ComposerClientReader mReader; std::unique_ptr mTestRenderEngine; common::PixelFormat mPixelFormat; common::Dataspace mDataspace; ::android::renderengine::DisplaySettings mClientCompositionDisplaySettings; 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 { public: void SetUp() override { SetUpBase(GetParam()); } }; TEST_P(GraphicsCompositionTest, SingleSolidColorLayer) { for (ColorMode mode : mTestColorModes) { EXPECT_TRUE(mComposerClient ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) .isOk()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); if (!isSupported) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; return; } auto layer = std::make_shared(mComposerClient, getPrimaryDisplayId(), *mWriter); common::Rect coloredSquare({0, 0, getDisplayWidth(), getDisplayHeight()}); layer->setColor(BLUE); layer->setDisplayFrame(coloredSquare); layer->setZOrder(10); std::vector> layers = {layer}; // expected color for each pixel std::vector expectedColors( static_cast(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, VtsComposerClient::kNoFrameIntervalNs); 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()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); 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 expectedColors( static_cast(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( mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(), getDisplayHeight(), common::PixelFormat::RGBA_8888, *mWriter); layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); layer->setZOrder(10); layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode)); ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); std::vector> layers = {layer}; writeLayers(layers); ASSERT_TRUE(mReader.takeErrors().empty()); mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp, VtsComposerClient::kNoFrameIntervalNs); 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()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); if (!isSupported) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; return; } auto layer = std::make_shared(mComposerClient, getPrimaryDisplayId(), *mWriter); 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(common::BufferUsage::CPU_WRITE_OFTEN) | static_cast(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 expectedColors( static_cast(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, VtsComposerClient::kNoFrameIntervalNs); 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) { bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); 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) { bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); if (!isSupported) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; return; } const auto usage = static_cast(common::BufferUsage::CPU_WRITE_OFTEN) | static_cast(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()); EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_DISPLAY)); } TEST_P(GraphicsCompositionTest, SetReadbackBuffer_BadParameter) { bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); 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()); EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_BAD_PARAMETER)); } TEST_P(GraphicsCompositionTest, GetReadbackBufferFenceInactive) { bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); if (!isSupported) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; return; } const auto& [status, releaseFence] = mComposerClient->getReadbackBufferFence(getPrimaryDisplayId()); EXPECT_FALSE(status.isOk()); EXPECT_NO_FATAL_FAILURE(assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED)); 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()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); if (!isSupported) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; return; } std::vector expectedColors( static_cast(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( mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(), getDisplayHeight(), PixelFormat::RGBA_FP16, *mWriter); layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); layer->setZOrder(10); layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode)); std::vector> 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, VtsComposerClient::kNoFrameIntervalNs); 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( 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, 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(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(1, damage), 1.f); layer->setToClientComposition(*mWriter); mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp, VtsComposerClient::kNoFrameIntervalNs); 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, MixedColorSpaces) { ASSERT_TRUE( mComposerClient->setClientTargetSlotCount(getPrimaryDisplayId(), kClientTargetSlotCount) .isOk()); const auto& [status, properties] = mComposerClient->getOverlaySupport(); if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC && status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) { GTEST_SUCCEED() << "getOverlaySupport is not supported"; return; } if (properties.supportMixedColorSpaces == false) { GTEST_SUCCEED() << "supportMixedColorSpaces is not supported"; return; } for (ColorMode mode : mTestColorModes) { EXPECT_TRUE(mComposerClient ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) .isOk()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); if (!isSupported) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; return; } // sRGB layer auto srgbLayer = std::make_shared( mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(), getDisplayHeight() / 2, PixelFormat::RGBA_8888, *mWriter); std::vector sRgbDeviceColors(srgbLayer->getWidth() * srgbLayer->getHeight()); ReadbackHelper::fillColorsArea(sRgbDeviceColors, getDisplayWidth(), {0, 0, static_cast(srgbLayer->getWidth()), static_cast(srgbLayer->getHeight())}, GREEN); srgbLayer->setDisplayFrame({0, 0, static_cast(srgbLayer->getWidth()), static_cast(srgbLayer->getHeight())}); srgbLayer->setZOrder(10); srgbLayer->setDataspace(Dataspace::SRGB); ASSERT_NO_FATAL_FAILURE(srgbLayer->setBuffer(sRgbDeviceColors)); // display P3 layer auto displayP3Layer = std::make_shared( mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(), getDisplayHeight() / 2, PixelFormat::RGBA_8888, *mWriter); std::vector displayP3DeviceColors( static_cast(displayP3Layer->getWidth() * displayP3Layer->getHeight())); ReadbackHelper::fillColorsArea(displayP3DeviceColors, getDisplayWidth(), {0, 0, static_cast(displayP3Layer->getWidth()), static_cast(displayP3Layer->getHeight())}, RED); displayP3Layer->setDisplayFrame( {0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}); displayP3Layer->setZOrder(10); displayP3Layer->setDataspace(Dataspace::DISPLAY_P3); ASSERT_NO_FATAL_FAILURE(displayP3Layer->setBuffer(displayP3DeviceColors)); writeLayers({srgbLayer, displayP3Layer}); mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp, VtsComposerClient::kNoFrameIntervalNs); execute(); auto changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId()); ASSERT_TRUE(changedCompositionTypes.empty()); mWriter->presentDisplay(getPrimaryDisplayId()); execute(); changedCompositionTypes = mReader.takeChangedCompositionTypes(getPrimaryDisplayId()); ASSERT_TRUE(changedCompositionTypes.empty()); ASSERT_TRUE(mReader.takeErrors().empty()); } } TEST_P(GraphicsCompositionTest, DeviceAndClientComposition) { ASSERT_TRUE( mComposerClient->setClientTargetSlotCount(getPrimaryDisplayId(), kClientTargetSlotCount) .isOk()); for (ColorMode mode : mTestColorModes) { EXPECT_TRUE(mComposerClient ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) .isOk()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); if (!isSupported) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; return; } std::vector expectedColors( static_cast(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( mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(), getDisplayHeight() / 2, PixelFormat::RGBA_8888, *mWriter); 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)); 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 = getDisplayWidth(); int32_t clientHeight = getDisplayHeight() / 2; auto clientLayer = std::make_shared( mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), clientWidth, clientHeight, PixelFormat::RGBA_FP16, *mWriter, Composition::DEVICE); common::Rect clientFrame = {0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}; clientLayer->setDisplayFrame(clientFrame); clientLayer->setZOrder(0); clientLayer->write(*mWriter); mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp, VtsComposerClient::kNoFrameIntervalNs); 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 clientColors( static_cast(getDisplayWidth() * getDisplayHeight())); ReadbackHelper::fillColorsArea(clientColors, getDisplayWidth(), clientFrame, RED); ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer( static_cast(getDisplayWidth()), static_cast(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(1, clientFrame), 1.f); clientLayer->setToClientComposition(*mWriter); mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp, VtsComposerClient::kNoFrameIntervalNs); 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()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); if (!isSupported) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; return; } common::Rect redRect = {0, 0, getDisplayWidth() / 4, getDisplayHeight() / 4}; std::vector expectedColors( static_cast(getDisplayWidth() * getDisplayHeight())); ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), redRect, RED); auto layer = std::make_shared( mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(), getDisplayHeight(), PixelFormat::RGBA_8888, *mWriter); layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); layer->setZOrder(10); layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode)); ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); std::vector> 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, VtsComposerClient::kNoFrameIntervalNs); 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(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, VtsComposerClient::kNoFrameIntervalNs); 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()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); if (!isSupported) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; return; } auto layer = std::make_shared(mComposerClient, getPrimaryDisplayId(), *mWriter); layer->setColor(RED); layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); layer->setZOrder(10); layer->setAlpha(0); layer->setBlendMode(BlendMode::PREMULTIPLIED); std::vector> 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, VtsComposerClient::kNoFrameIntervalNs); 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 expectedColors( static_cast(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()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); if (!isSupported) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; return; } std::vector expectedColors( static_cast(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( mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(), getDisplayHeight(), PixelFormat::RGBA_8888, *mWriter); layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); layer->setZOrder(10); layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode)); layer->setSourceCrop({0, static_cast(getDisplayHeight() / 2), static_cast(getDisplayWidth()), static_cast(getDisplayHeight())}); ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors)); std::vector> 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, VtsComposerClient::kNoFrameIntervalNs); 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()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); 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(mComposerClient, getPrimaryDisplayId(), *mWriter); redLayer->setColor(RED); redLayer->setDisplayFrame(redRect); auto blueLayer = std::make_shared(mComposerClient, getPrimaryDisplayId(), *mWriter); blueLayer->setColor(BLUE); blueLayer->setDisplayFrame(blueRect); blueLayer->setZOrder(5); std::vector> layers = {redLayer, blueLayer}; std::vector expectedColors( static_cast(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, VtsComposerClient::kNoFrameIntervalNs); 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, VtsComposerClient::kNoFrameIntervalNs); 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) { for (ColorMode mode : mTestColorModes) { EXPECT_TRUE(mComposerClient ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) .isOk()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); 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()}; static constexpr float kMaxBrightnessNits = 300.f; const auto redLayer = std::make_shared(mComposerClient, getPrimaryDisplayId(), *mWriter); redLayer->setColor(RED); redLayer->setDisplayFrame(redRect); redLayer->setWhitePointNits(kMaxBrightnessNits); redLayer->setBrightness(1.f); const auto dimmerRedLayer = std::make_shared(mComposerClient, getPrimaryDisplayId(), *mWriter); 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(kMaxBrightnessNits * kDimmingRatio); dimmerRedLayer->setBrightness(kDimmingRatio); const std::vector> layers = {redLayer, dimmerRedLayer}; std::vector expectedColors( static_cast(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, VtsComposerClient::kNoFrameIntervalNs); 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> { 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.erase( std::remove_if(mTestColorModes.begin(), mTestColorModes.end(), [](ColorMode mode) { return mode != ColorMode::SRGB; }), mTestColorModes.end()); 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(getDisplayWidth() * getDisplayHeight())); ReadbackHelper::fillColorsArea(topLayerPixelColors, getDisplayWidth(), {0, 0, getDisplayWidth(), getDisplayHeight()}, mTopLayerColor); auto backgroundLayer = std::make_shared(mComposerClient, getPrimaryDisplayId(), *mWriter); backgroundLayer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); backgroundLayer->setZOrder(0); backgroundLayer->setColor(mBackgroundColor); auto layer = std::make_shared( mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(), getDisplayHeight(), PixelFormat::RGBA_8888, *mWriter); layer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); layer->setZOrder(10); layer->setDataspace(Dataspace::UNKNOWN); 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, 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> mLayers; Color mBackgroundColor; Color mTopLayerColor; }; TEST_P(GraphicsBlendModeCompositionTest, None) { for (ColorMode mode : mTestColorModes) { EXPECT_TRUE(mComposerClient ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) .isOk()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); if (!isSupported) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; return; } std::vector expectedColors( static_cast(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, VtsComposerClient::kNoFrameIntervalNs); 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()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); if (!isSupported) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; return; } std::vector expectedColors( static_cast(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, VtsComposerClient::kNoFrameIntervalNs); 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()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); if (!isSupported) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; return; } std::vector expectedColors( static_cast(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, VtsComposerClient::kNoFrameIntervalNs); 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(mComposerClient, getPrimaryDisplayId(), *mWriter); 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(mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), mSideLength, mSideLength, PixelFormat::RGBA_8888, *mWriter); 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) { auto status = mComposerClient->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC); if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC && (status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED || status.getServiceSpecificError() == IComposerClient::EX_BAD_PARAMETER)) { SUCCEED() << "ColorMode not supported, skip test"; return; } bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); 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)); std::vector expectedColors( static_cast(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, VtsComposerClient::kNoFrameIntervalNs); 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()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); 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)); std::vector expectedColors( static_cast(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, VtsComposerClient::kNoFrameIntervalNs); 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()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); 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)); std::vector expectedColors( static_cast(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, VtsComposerClient::kNoFrameIntervalNs); 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 GraphicsColorManagementCompositionTest : public GraphicsCompositionTestBase, public testing::WithParamInterface> { public: void SetUp() override { SetUpBase(std::get<0>(GetParam())); // for some reason only sRGB reliably works mTestColorModes.erase( std::remove_if(mTestColorModes.begin(), mTestColorModes.end(), [](ColorMode mode) { return mode != ColorMode::SRGB; }), mTestColorModes.end()); auto standard = std::get<1>(GetParam()); auto transfer = std::get<2>(GetParam()); auto range = std::get<3>(GetParam()); mLayerDataspace = static_cast(static_cast(standard) | static_cast(transfer) | static_cast(range)); ALOGD("Invoking test for dataspace: {%s, %s, %s}", toString(standard).c_str(), toString(transfer).c_str(), toString(range).c_str()); } void makeLayer() { mLayer = std::make_shared( mComposerClient, *mTestRenderEngine, getPrimaryDisplayId(), getDisplayWidth(), getDisplayHeight(), common::PixelFormat::RGBA_8888, *mWriter); mLayer->setDisplayFrame({0, 0, getDisplayWidth(), getDisplayHeight()}); mLayer->setZOrder(10); mLayer->setAlpha(1.f); mLayer->setDataspace(mLayerDataspace); } void fillColor(Color color) { std::vector baseColors(static_cast(getDisplayWidth() * getDisplayHeight())); ReadbackHelper::fillColorsArea(baseColors, getDisplayWidth(), common::Rect{.left = 0, .top = 0, .right = getDisplayWidth(), .bottom = getDisplayHeight()}, color); ASSERT_NO_FATAL_FAILURE(mLayer->setBuffer(baseColors)); } Dataspace mLayerDataspace; std::shared_ptr mLayer; }; TEST_P(GraphicsColorManagementCompositionTest, ColorConversion) { for (ColorMode mode : mTestColorModes) { EXPECT_TRUE(mComposerClient ->setColorMode(getPrimaryDisplayId(), mode, RenderIntent::COLORIMETRIC) .isOk()); bool isSupported; ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer()); if (!isSupported) { GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace"; return; } mClientCompositionDisplaySettings.outputDataspace = static_cast<::android::ui::Dataspace>(mDataspace); mTestRenderEngine->setDisplaySettings(mClientCompositionDisplaySettings); makeLayer(); for (auto color : {LIGHT_RED, LIGHT_GREEN, LIGHT_BLUE}) { ALOGD("Testing color: %f, %f, %f, %f with color mode: %d", color.r, color.g, color.b, color.a, mode); ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(), getDisplayHeight(), mPixelFormat, mDataspace); ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer()); fillColor(color); writeLayers({mLayer}); EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::ON).isOk()); ASSERT_TRUE(mReader.takeErrors().empty()); mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp, VtsComposerClient::kNoFrameIntervalNs); execute(); if (!mReader.takeChangedCompositionTypes(getPrimaryDisplayId()).empty()) { continue; } ASSERT_TRUE(mReader.takeErrors().empty()); mWriter->presentDisplay(getPrimaryDisplayId()); execute(); ASSERT_TRUE(mReader.takeErrors().empty()); mTestRenderEngine->setRenderLayers({mLayer}); ASSERT_NO_FATAL_FAILURE(mTestRenderEngine->drawLayers()); ASSERT_NO_FATAL_FAILURE( mTestRenderEngine->checkColorBuffer(readbackBuffer.getBuffer())); } } } 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); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsColorManagementCompositionTest); INSTANTIATE_TEST_SUITE_P(PerInstance, GraphicsColorManagementCompositionTest, testing::Combine(testing::ValuesIn(::android::getAidlHalInstanceNames( IComposer::descriptor)), // Only check sRGB, but verify that extended range // doesn't trigger any gamma shifts testing::Values(Dataspace::STANDARD_BT709), testing::Values(Dataspace::TRANSFER_SRGB), // Don't test limited range until we send YUV overlays testing::Values(Dataspace::RANGE_FULL, Dataspace::RANGE_EXTENDED))); } // namespace } // namespace aidl::android::hardware::graphics::composer3::vts