Files
hardware_interfaces/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
ramindani d575109c1e Check Exception Code for Service specific error
Before checking the service specific error
we need to check that getExceptionCode returns
EX_SERVICE_SPECIFIC error code. Added a method and
used that to do the two checks together for exceptionCode
and for the service specific error code, so that we don't
repeat two lines in all the tests that need them.

EXPECT_NO_FATAL_FAILURES print the correct line number of the test
or iteration of the test when used with helper functions, and
testing guidelines recommend it too here: go/gunitadvanced#propagating-fatal-failures

Test: atest VtsHalGraphicsComposer3_TargetTest
BUG: 205152739
Change-Id: I1d3c3aa9b34dcefb14be507ff61b73b6f08a5204
2022-04-25 20:44:04 +00:00

1466 lines
66 KiB
C++

/**
* 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(); }
void assertServiceSpecificError(const ScopedAStatus& status, int32_t serviceSpecificError) {
ASSERT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
ASSERT_EQ(status.getServiceSpecificError(), serviceSpecificError);
}
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();
}
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<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());
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<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());
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<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());
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<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) {
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<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());
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<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());
bool isSupported;
ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
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());
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<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());
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<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());
bool isSupported;
ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
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());
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<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, maxBrightnessNits);
execute();
ASSERT_TRUE(mReader.takeErrors().empty());
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()};
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.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<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;
};
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<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());
bool isSupported;
ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
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());
bool isSupported;
ASSERT_NO_FATAL_FAILURE(isSupported = getHasReadbackBuffer());
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.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), 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());
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), 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());
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), 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