blob: 8731cf695fda653f1f753171525688e206890a6e [file] [edit]
/**
* 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 <cutils/ashmem.h>
#include <gtest/gtest.h>
#include <ui/DisplayId.h>
#include <ui/GraphicBuffer.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
#include <algorithm>
#include <cstdint>
#include <unordered_map>
#include "ComposerClientWrapper.h"
#include "GraphicsComposerCallback.h"
#include "Readback.h"
#include "RenderEngine.h"
namespace aidl::android::hardware::graphics::composer3::vts {
namespace {
using namespace ::aidl::android::hardware::graphics::composer3::libhwc_aidl_test;
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<ComposerClientWrapper>(name);
ASSERT_TRUE(mComposerClient->createClient().isOk());
const auto& [status, displays] = mComposerClient->getDisplays();
ASSERT_TRUE(status.isOk());
mAllDisplays = displays;
setUpDisplayProperties();
for (const auto& display : mAllDisplays) {
// explicitly disable vsync
EXPECT_TRUE(mComposerClient->setVsync(display.getDisplayId(), /*enable*/ false).isOk());
}
mComposerClient->setVsyncAllowed(/*isAllowed*/ false);
}
void TearDown() override {
std::unordered_map<int64_t, ComposerClientWriter*> displayWriters;
ASSERT_FALSE(mAllDisplays.empty());
for (const auto& display : mAllDisplays) {
ASSERT_TRUE(
mComposerClient->setPowerMode(display.getDisplayId(), PowerMode::OFF).isOk());
const auto errors = mDisplayProperties.at(display.getDisplayId()).reader.takeErrors();
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty());
displayWriters[display.getDisplayId()] =
&mDisplayProperties.at(display.getDisplayId()).writer;
}
ASSERT_TRUE(mComposerClient->tearDown(displayWriters));
mComposerClient.reset();
}
void setUpDisplayProperties() {
for (const auto& display : mAllDisplays) {
auto props = ReadbackHelper::setupDisplayProperty(display, mComposerClient);
mDisplayProperties.emplace(display.getDisplayId(), std::move(props));
}
}
// Gets and Updates the dataspace and check if readback is supported given the default pixel
// format and the current dataspace. Dataspace can get updated after calls to
// ComposerClientWrapper::setColorMode so it's essential to get the latest dataspace.
std::pair<common::Dataspace, bool> GetDataspaceAndIfReadBackSupported(int64_t displayId) {
auto [status, readBackBufferAttributes] =
mComposerClient->getReadbackBufferAttributes(displayId);
if (status.isOk()) {
auto dataspace = readBackBufferAttributes.dataspace;
mDisplayProperties.at(displayId).dataspace = dataspace;
// We are making an assumption that Pixel Format never changes, so assert for this
// assumption. If this is not the case on any display, then we should stop caching it.
// The cached format is used in initializing TestRenderEngine.
assertPixelFormatConsistency(displayId, readBackBufferAttributes.format);
return std::make_pair(std::move(dataspace),
ReadbackHelper::readbackSupported(
mDisplayProperties.at(displayId).pixelFormat, dataspace));
}
EXPECT_NO_FATAL_FAILURE(
assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED));
return {common::Dataspace::UNKNOWN, false};
}
int64_t getInvalidDisplayId() const { return mComposerClient->getInvalidDisplayId(); }
void assertServiceSpecificError(const ScopedAStatus& status, int32_t serviceSpecificError) {
ASSERT_EQ(status.getExceptionCode(), EX_SERVICE_SPECIFIC);
ASSERT_EQ(status.getServiceSpecificError(), serviceSpecificError);
}
void assertPixelFormatConsistency(int64_t displayId, common::PixelFormat currentPixelFormat) {
ASSERT_EQ(mDisplayProperties.at(displayId).pixelFormat, currentPixelFormat);
}
std::pair<bool, ::android::sp<::android::GraphicBuffer>> allocateBuffer(
const DisplayWrapper& display, uint32_t usage) {
const auto width = static_cast<uint32_t>(display.getDisplayWidth());
const auto height = static_cast<uint32_t>(display.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<std::shared_ptr<TestLayer>>& layers, int64_t displayId) {
for (const auto& layer : layers) {
layer->write(mDisplayProperties.at(displayId).writer);
}
execute(displayId);
}
void execute(int64_t displayId) {
auto commands = mDisplayProperties.at(displayId).writer.takePendingCommands();
if (commands.empty()) {
return;
}
auto [status, results] = mComposerClient->executeCommands(commands);
ASSERT_TRUE(status.isOk()) << "executeCommands failed " << status.getDescription();
mDisplayProperties.at(displayId).reader.parse(std::move(results));
}
std::shared_ptr<ComposerClientWrapper> mComposerClient;
std::vector<DisplayWrapper> mAllDisplays;
std::unordered_map<int64_t, DisplayProperties> mDisplayProperties;
static constexpr uint32_t kClientTargetSlotCount = 64;
};
class GraphicsCompositionTest : public GraphicsCompositionTestBase,
public testing::WithParamInterface<std::string> {
public:
void SetUp() override { SetUpBase(GetParam()); }
};
TEST_P(GraphicsCompositionTest, SingleSolidColorLayer) {
for (const DisplayWrapper& display : mAllDisplays) {
auto& testColorModes = mDisplayProperties.at(display.getDisplayId()).testColorModes;
for (ColorMode mode : testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
auto layer = std::make_shared<TestColorLayer>(
*mComposerClient, display.getDisplayId(),
mDisplayProperties.at(display.getDisplayId()).writer);
common::Rect coloredSquare(
{0, 0, display.getDisplayWidth(), display.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>(display.getDisplayWidth() * display.getDisplayHeight()));
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), coloredSquare,
BLUE);
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
// if hwc cannot handle and asks for composition change, just skip the test on this
// display->
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
continue;
}
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
testRenderEngine->setRenderLayers(layers);
ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
}
}
}
TEST_P(GraphicsCompositionTest, SetLayerBuffer) {
for (const DisplayWrapper& display : mAllDisplays) {
auto& testColorModes = mDisplayProperties.at(display.getDisplayId()).testColorModes;
for (ColorMode mode : testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
std::vector<Color> expectedColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
ReadbackHelper::fillColorsArea(
expectedColors, display.getDisplayWidth(),
{0, 0, display.getDisplayWidth(), display.getDisplayHeight() / 4}, RED);
ReadbackHelper::fillColorsArea(
expectedColors, display.getDisplayWidth(),
{0, display.getDisplayHeight() / 4, display.getDisplayWidth(),
display.getDisplayHeight() / 2},
GREEN);
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
{0, display.getDisplayHeight() / 2,
display.getDisplayWidth(), display.getDisplayHeight()},
BLUE);
auto layer = std::make_shared<TestBufferLayer>(
*mComposerClient,
*mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
display.getDisplayId(), display.getDisplayWidth(), display.getDisplayHeight(),
common::PixelFormat::RGBA_8888,
mDisplayProperties.at(display.getDisplayId()).writer);
layer->setDisplayFrame({0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
layer->setZOrder(10);
layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
continue;
}
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
testRenderEngine->setRenderLayers(layers);
ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
}
}
}
TEST_P(GraphicsCompositionTest, SetLayerBufferNoEffect) {
for (const DisplayWrapper& display : mAllDisplays) {
auto& testColorModes = mDisplayProperties.at(display.getDisplayId()).testColorModes;
for (ColorMode mode : testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
auto& writer = mDisplayProperties.at(display.getDisplayId()).writer;
auto layer = std::make_shared<TestColorLayer>(*mComposerClient, display.getDisplayId(),
writer);
common::Rect coloredSquare(
{0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
layer->setColor(BLUE);
layer->setDisplayFrame(coloredSquare);
layer->setZOrder(10);
layer->write(mDisplayProperties.at(display.getDisplayId()).writer);
// 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(display, usage);
ASSERT_TRUE(graphicBufferStatus);
const auto& buffer = graphicBuffer->handle;
mDisplayProperties.at(display.getDisplayId())
.writer.setLayerBuffer(display.getDisplayId(), layer->getLayer(), /*slot*/ 0,
buffer,
/*acquireFence*/ -1);
// expected color for each pixel
std::vector<Color> expectedColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), coloredSquare,
BLUE);
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
continue;
}
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
}
}
TEST_P(GraphicsCompositionTest, SetReadbackBuffer) {
for (const DisplayWrapper& display : mAllDisplays) {
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
}
}
TEST_P(GraphicsCompositionTest, SetReadbackBuffer_BadDisplay) {
for (const DisplayWrapper& display : mAllDisplays) {
auto [_, readbackSupported] = GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
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(display, 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) {
for (const DisplayWrapper& display : mAllDisplays) {
auto [_, readbackSupported] = GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
const native_handle_t bufferHandle{};
ndk::ScopedFileDescriptor releaseFence = ndk::ScopedFileDescriptor(-1);
const auto status = mComposerClient->setReadbackBuffer(display.getDisplayId(),
&bufferHandle, releaseFence);
EXPECT_FALSE(status.isOk());
EXPECT_NO_FATAL_FAILURE(
assertServiceSpecificError(status, IComposerClient::EX_BAD_PARAMETER));
}
}
TEST_P(GraphicsCompositionTest, GetReadbackBufferFenceInactive) {
for (const DisplayWrapper& display : mAllDisplays) {
auto [_, readbackSupported] = GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
const auto& [status, releaseFence] =
mComposerClient->getReadbackBufferFence(display.getDisplayId());
EXPECT_FALSE(status.isOk());
EXPECT_NO_FATAL_FAILURE(
assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED));
EXPECT_EQ(-1, releaseFence.get());
}
}
TEST_P(GraphicsCompositionTest, ClientComposition) {
for (const DisplayWrapper& display : mAllDisplays) {
EXPECT_TRUE(
mComposerClient
->setClientTargetSlotCount(display.getDisplayId(), kClientTargetSlotCount)
.isOk());
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
std::vector<Color> expectedColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
ReadbackHelper::fillColorsArea(
expectedColors, display.getDisplayWidth(),
{0, 0, display.getDisplayWidth(), display.getDisplayHeight() / 4}, RED);
ReadbackHelper::fillColorsArea(
expectedColors, display.getDisplayWidth(),
{0, display.getDisplayHeight() / 4, display.getDisplayWidth(),
display.getDisplayHeight() / 2},
GREEN);
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
{0, display.getDisplayHeight() / 2,
display.getDisplayWidth(), display.getDisplayHeight()},
BLUE);
auto layer = std::make_shared<TestBufferLayer>(
*mComposerClient,
*mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
display.getDisplayId(), display.getDisplayWidth(), display.getDisplayHeight(),
PixelFormat::RGBA_8888, mDisplayProperties.at(display.getDisplayId()).writer);
layer->setDisplayFrame({0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
layer->setZOrder(10);
layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
auto changedCompositionTypes =
mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId());
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, display.getDisplayWidth(), display.getDisplayHeight()};
// create client target buffer
const auto& [graphicBufferStatus, graphicBuffer] =
allocateBuffer(display, clientUsage);
ASSERT_TRUE(graphicBufferStatus);
const auto& buffer = graphicBuffer->handle;
void* clientBufData;
const auto stride = static_cast<uint32_t>(graphicBuffer->stride);
int bytesPerPixel = -1;
int bytesPerStride = -1;
graphicBuffer->lock(clientUsage, layer->getAccessRegion(), &clientBufData,
&bytesPerPixel, &bytesPerStride);
ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(
layer->getWidth(), layer->getHeight(), stride, bytesPerPixel, clientBufData,
clientFormat, expectedColors));
int32_t clientFence;
const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
ASSERT_EQ(::android::OK, unlockStatus);
mDisplayProperties.at(display.getDisplayId())
.writer.setClientTarget(display.getDisplayId(), /*slot*/ 0, buffer,
clientFence, clientDataspace,
std::vector<common::Rect>(1, damage), 1.f);
layer->setToClientComposition(mDisplayProperties.at(display.getDisplayId()).writer);
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
changedCompositionTypes =
mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId());
ASSERT_TRUE(changedCompositionTypes.empty());
}
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
}
}
void generateLuts(Luts* luts, LutProperties::Dimension dimension, int32_t size,
LutProperties::SamplingKey key) {
size_t bufferSize = dimension == LutProperties::Dimension::ONE_D
? static_cast<size_t>(size) * sizeof(float)
: static_cast<size_t>(size * size * size) * sizeof(float);
int32_t fd = ashmem_create_region("lut_shared_mem", bufferSize);
void* ptr = mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
std::vector<float> buffers(static_cast<size_t>(size), 0.5f);
memcpy(ptr, buffers.data(), bufferSize);
munmap(ptr, bufferSize);
luts->pfd = ndk::ScopedFileDescriptor(fd);
luts->offsets = std::vector<int32_t>{0};
luts->lutProperties = {LutProperties{dimension, size, {key}}};
}
// @VsrTest = 4.4-016
TEST_P(GraphicsCompositionTest, Luts) {
const auto& [status, properties] = mComposerClient->getOverlaySupport();
if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
ALOGI("getOverlaySupport is not supported");
GTEST_SKIP();
}
if (!properties.lutProperties) {
ALOGI("lutProperties are not supported");
GTEST_SKIP();
}
bool supportsHlg = false;
for (const auto& i : properties.combinations) {
bool supportsBt2020Gamut =
std::any_of(i.standards.cbegin(), i.standards.cend(), [](const auto& standard) {
return standard == common::Dataspace::STANDARD_BT2020;
});
bool supportsHlgTransfer = std::any_of(
i.transfers.cbegin(), i.transfers.cend(),
[](const auto& transfer) { return transfer == common::Dataspace::TRANSFER_HLG; });
bool supportsFullRange = std::any_of(
i.ranges.cbegin(), i.ranges.cend(),
[](const auto& range) { return range == common::Dataspace::RANGE_FULL; });
supportsHlg = supportsBt2020Gamut && supportsHlgTransfer && supportsFullRange;
if (supportsHlg) {
break;
}
}
for (const DisplayWrapper& display : mAllDisplays) {
ASSERT_TRUE(
mComposerClient
->setClientTargetSlotCount(display.getDisplayId(), kClientTargetSlotCount)
.isOk());
auto& testColorModes = mDisplayProperties.at(display.getDisplayId()).testColorModes;
for (const auto& lutProperties : *properties.lutProperties) {
if (!lutProperties) {
continue;
}
auto& l = *lutProperties;
for (const auto& key : l.samplingKeys) {
for (ColorMode mode : testColorModes) {
EXPECT_TRUE(mComposerClient
->setColorMode(display.getDisplayId(), mode,
RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
common::Rect coloredSquare(
{0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
// expected color for each pixel
std::vector<Color> expectedColors(static_cast<size_t>(
display.getDisplayWidth() * display.getDisplayHeight()));
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
coloredSquare, WHITE);
auto layer = std::make_shared<TestBufferLayer>(
*mComposerClient,
*mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
display.getDisplayId(), display.getDisplayWidth(),
display.getDisplayHeight(), PixelFormat::RGBA_8888,
mDisplayProperties.at(display.getDisplayId()).writer);
layer->setDisplayFrame(coloredSquare);
layer->setZOrder(10);
// Fallback to sRGB support if the device doesn't support HLG
// This is to accommodate nascent devices that support LUTs but only for HDR
// formats, without compromising test coverage of the LUT feature altogether
layer->setDataspace(supportsHlg ? Dataspace::BT2020_HLG : Dataspace::SRGB);
Luts luts;
generateLuts(&luts, l.dimension, l.size, key);
layer->setLuts(std::move(luts));
ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
ReadbackBuffer readbackBuffer(
display.getDisplayId(), mComposerClient, display.getDisplayWidth(),
display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat, dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId())
.reader.takeErrors()
.empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
// We should be guaranteed to use DPU composition here
ASSERT_TRUE(supportsHlg);
auto changedCompositionTypes =
mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId());
ASSERT_TRUE(changedCompositionTypes.empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId())
.reader.takeErrors()
.empty());
ReadbackHelper::fillColorsArea(
expectedColors, display.getDisplayWidth(), coloredSquare,
{188.f / 255.f, 188.f / 255.f, 188.f / 255.f, 1.0f});
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
auto& testRenderEngine =
mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
testRenderEngine->setRenderLayers(layers);
ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
mComposerClient->destroyLayer(
display.getDisplayId(), layer->getLayer(),
&mDisplayProperties.at(display.getDisplayId()).writer);
}
}
}
}
}
TEST_P(GraphicsCompositionTest, MixedColorSpaces) {
const auto& [status, properties] = mComposerClient->getOverlaySupport();
if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED) {
ALOGI("getOverlaySupport is not supported");
GTEST_SKIP();
}
if (properties.supportMixedColorSpaces == false) {
ALOGI("supportMixedColorSpaces is not supported");
GTEST_SKIP();
}
for (const DisplayWrapper& display : mAllDisplays) {
ASSERT_TRUE(
mComposerClient
->setClientTargetSlotCount(display.getDisplayId(), kClientTargetSlotCount)
.isOk());
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
// sRGB layer
auto srgbLayer = std::make_shared<TestBufferLayer>(
*mComposerClient,
*mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
display.getDisplayId(), display.getDisplayWidth(),
display.getDisplayHeight() / 2, PixelFormat::RGBA_8888,
mDisplayProperties.at(display.getDisplayId()).writer);
std::vector<Color> sRgbDeviceColors(srgbLayer->getWidth() * srgbLayer->getHeight());
ReadbackHelper::fillColorsArea(sRgbDeviceColors, display.getDisplayWidth(),
{0, 0, static_cast<int32_t>(srgbLayer->getWidth()),
static_cast<int32_t>(srgbLayer->getHeight())},
GREEN);
srgbLayer->setDisplayFrame({0, 0, static_cast<int32_t>(srgbLayer->getWidth()),
static_cast<int32_t>(srgbLayer->getHeight())});
srgbLayer->setZOrder(10);
srgbLayer->setDataspace(Dataspace::SRGB);
ASSERT_NO_FATAL_FAILURE(srgbLayer->setBuffer(sRgbDeviceColors));
// display P3 layer
auto displayP3Layer = std::make_shared<TestBufferLayer>(
*mComposerClient,
*mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
display.getDisplayId(), display.getDisplayWidth(),
display.getDisplayHeight() / 2, PixelFormat::RGBA_8888,
mDisplayProperties.at(display.getDisplayId()).writer);
std::vector<Color> displayP3DeviceColors(
static_cast<size_t>(displayP3Layer->getWidth() * displayP3Layer->getHeight()));
ReadbackHelper::fillColorsArea(displayP3DeviceColors, display.getDisplayWidth(),
{0, 0, static_cast<int32_t>(displayP3Layer->getWidth()),
static_cast<int32_t>(displayP3Layer->getHeight())},
RED);
displayP3Layer->setDisplayFrame({0, display.getDisplayHeight() / 2,
display.getDisplayWidth(),
display.getDisplayHeight()});
displayP3Layer->setZOrder(10);
displayP3Layer->setDataspace(Dataspace::DISPLAY_P3);
ASSERT_NO_FATAL_FAILURE(displayP3Layer->setBuffer(displayP3DeviceColors));
writeLayers({srgbLayer, displayP3Layer}, display.getDisplayId());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
auto changedCompositionTypes =
mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId());
ASSERT_TRUE(changedCompositionTypes.empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
changedCompositionTypes =
mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId());
ASSERT_TRUE(changedCompositionTypes.empty());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mComposerClient->destroyLayer(display.getDisplayId(), srgbLayer->getLayer(),
&mDisplayProperties.at(display.getDisplayId()).writer);
mComposerClient->destroyLayer(display.getDisplayId(), displayP3Layer->getLayer(),
&mDisplayProperties.at(display.getDisplayId()).writer);
}
}
}
TEST_P(GraphicsCompositionTest, DeviceAndClientComposition) {
for (const DisplayWrapper& display : mAllDisplays) {
ASSERT_TRUE(
mComposerClient
->setClientTargetSlotCount(display.getDisplayId(), kClientTargetSlotCount)
.isOk());
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
std::vector<Color> expectedColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
ReadbackHelper::fillColorsArea(
expectedColors, display.getDisplayWidth(),
{0, 0, display.getDisplayWidth(), display.getDisplayHeight() / 2}, GREEN);
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
{0, display.getDisplayHeight() / 2,
display.getDisplayWidth(), display.getDisplayHeight()},
RED);
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
auto deviceLayer = std::make_shared<TestBufferLayer>(
*mComposerClient,
*mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
display.getDisplayId(), display.getDisplayWidth(),
display.getDisplayHeight() / 2, PixelFormat::RGBA_8888,
mDisplayProperties.at(display.getDisplayId()).writer);
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));
ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
deviceLayer->write(mDisplayProperties.at(display.getDisplayId()).writer);
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 = display.getDisplayWidth();
int32_t clientHeight = display.getDisplayHeight() / 2;
auto clientLayer = std::make_shared<TestBufferLayer>(
*mComposerClient,
*mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
display.getDisplayId(), clientWidth, clientHeight, PixelFormat::RGBA_FP16,
mDisplayProperties.at(display.getDisplayId()).writer, Composition::DEVICE);
common::Rect clientFrame = {0, display.getDisplayHeight() / 2,
display.getDisplayWidth(), display.getDisplayHeight()};
clientLayer->setDisplayFrame(clientFrame);
clientLayer->setZOrder(0);
clientLayer->write(mDisplayProperties.at(display.getDisplayId()).writer);
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
auto changedCompositionTypes =
mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId());
if (changedCompositionTypes.size() != 1) {
continue;
}
// create client target buffer
ASSERT_EQ(Composition::CLIENT, changedCompositionTypes[0].composition);
const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(display, clientUsage);
ASSERT_TRUE(graphicBufferStatus);
const auto& buffer = graphicBuffer->handle;
void* clientBufData;
int bytesPerPixel = -1;
int bytesPerStride = -1;
graphicBuffer->lock(clientUsage,
{0, 0, display.getDisplayWidth(), display.getDisplayHeight()},
&clientBufData, &bytesPerPixel, &bytesPerStride);
std::vector<Color> clientColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
ReadbackHelper::fillColorsArea(clientColors, display.getDisplayWidth(), clientFrame,
RED);
ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(
static_cast<uint32_t>(display.getDisplayWidth()),
static_cast<uint32_t>(display.getDisplayHeight()), graphicBuffer->getStride(),
bytesPerPixel, clientBufData, clientFormat, clientColors));
int32_t clientFence;
const auto unlockStatus = graphicBuffer->unlockAsync(&clientFence);
ASSERT_EQ(::android::OK, unlockStatus);
mDisplayProperties.at(display.getDisplayId())
.writer.setClientTarget(display.getDisplayId(), /*slot*/ 0, buffer, clientFence,
clientDataspace,
std::vector<common::Rect>(1, clientFrame), 1.f);
clientLayer->setToClientComposition(
mDisplayProperties.at(display.getDisplayId()).writer);
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
changedCompositionTypes =
mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId());
ASSERT_TRUE(changedCompositionTypes.empty());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
}
}
TEST_P(GraphicsCompositionTest, SetLayerDamage) {
for (const DisplayWrapper& display : mAllDisplays) {
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
common::Rect redRect = {0, 0, display.getDisplayWidth() / 4,
display.getDisplayHeight() / 4};
std::vector<Color> expectedColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), redRect, RED);
auto layer = std::make_shared<TestBufferLayer>(
*mComposerClient,
*mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
display.getDisplayId(), display.getDisplayWidth(), display.getDisplayHeight(),
PixelFormat::RGBA_8888, mDisplayProperties.at(display.getDisplayId()).writer);
layer->setDisplayFrame({0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
layer->setZOrder(10);
layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
continue;
}
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
// update surface damage and recheck
redRect = {display.getDisplayWidth() / 4, display.getDisplayHeight() / 4,
display.getDisplayWidth() / 2, display.getDisplayHeight() / 2};
ReadbackHelper::clearColors(expectedColors, display.getDisplayWidth(),
display.getDisplayHeight(), display.getDisplayWidth());
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), redRect, RED);
ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors));
layer->setSurfaceDamage(std::vector<common::Rect>(
1, {0, 0, display.getDisplayWidth() / 2, display.getDisplayWidth() / 2}));
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
}
}
TEST_P(GraphicsCompositionTest, SetLayerPlaneAlpha) {
for (const DisplayWrapper& display : mAllDisplays) {
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
auto layer = std::make_shared<TestColorLayer>(
*mComposerClient, display.getDisplayId(),
mDisplayProperties.at(display.getDisplayId()).writer);
layer->setColor(RED);
layer->setDisplayFrame({0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
layer->setZOrder(10);
layer->setAlpha(0);
layer->setBlendMode(BlendMode::PREMULTIPLIED);
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
continue;
}
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
std::vector<Color> expectedColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
testRenderEngine->setRenderLayers(layers);
ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
}
}
}
TEST_P(GraphicsCompositionTest, SetLayerSourceCrop) {
for (const DisplayWrapper& display : mAllDisplays) {
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
std::vector<Color> expectedColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
ReadbackHelper::fillColorsArea(
expectedColors, display.getDisplayWidth(),
{0, 0, display.getDisplayWidth(), display.getDisplayHeight() / 4}, RED);
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
{0, display.getDisplayHeight() / 2,
display.getDisplayWidth(), display.getDisplayHeight()},
BLUE);
auto layer = std::make_shared<TestBufferLayer>(
*mComposerClient,
*mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
display.getDisplayId(), display.getDisplayWidth(), display.getDisplayHeight(),
PixelFormat::RGBA_8888, mDisplayProperties.at(display.getDisplayId()).writer);
layer->setDisplayFrame({0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
layer->setZOrder(10);
layer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
layer->setSourceCrop({0, static_cast<float>(display.getDisplayHeight() / 2),
static_cast<float>(display.getDisplayWidth()),
static_cast<float>(display.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, display.getDisplayWidth(),
{0, 0, display.getDisplayWidth(), display.getDisplayHeight()}, BLUE);
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
continue;
}
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
testRenderEngine->setRenderLayers(layers);
ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
}
}
}
TEST_P(GraphicsCompositionTest, SetLayerZOrder) {
for (const DisplayWrapper& display : mAllDisplays) {
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
common::Rect redRect = {0, 0, display.getDisplayWidth(),
display.getDisplayHeight() / 2};
common::Rect blueRect = {0, display.getDisplayHeight() / 4, display.getDisplayWidth(),
display.getDisplayHeight()};
auto redLayer = std::make_shared<TestColorLayer>(
*mComposerClient, display.getDisplayId(),
mDisplayProperties.at(display.getDisplayId()).writer);
redLayer->setColor(RED);
redLayer->setDisplayFrame(redRect);
auto blueLayer = std::make_shared<TestColorLayer>(
*mComposerClient, display.getDisplayId(),
mDisplayProperties.at(display.getDisplayId()).writer);
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>(display.getDisplayWidth() * display.getDisplayHeight()));
// red in front of blue
redLayer->setZOrder(10);
// fill blue first so that red will overwrite on overlap
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), blueRect,
BLUE);
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), redRect, RED);
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
continue;
}
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
redLayer->setZOrder(1);
ReadbackHelper::clearColors(expectedColors, display.getDisplayWidth(),
display.getDisplayHeight(), display.getDisplayWidth());
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), redRect, RED);
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), blueRect,
BLUE);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
testRenderEngine->setRenderLayers(layers);
ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
}
}
}
TEST_P(GraphicsCompositionTest, SetLayerBrightnessDims) {
for (const DisplayWrapper& display : mAllDisplays) {
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
const common::Rect redRect = {0, 0, display.getDisplayWidth(),
display.getDisplayHeight() / 2};
const common::Rect dimmerRedRect = {0, display.getDisplayHeight() / 2,
display.getDisplayWidth(),
display.getDisplayHeight()};
static constexpr float kMaxBrightnessNits = 300.f;
const auto redLayer = std::make_shared<TestColorLayer>(
*mComposerClient, display.getDisplayId(),
mDisplayProperties.at(display.getDisplayId()).writer);
redLayer->setColor(RED);
redLayer->setDisplayFrame(redRect);
redLayer->setWhitePointNits(kMaxBrightnessNits);
redLayer->setBrightness(1.f);
const auto dimmerRedLayer = std::make_shared<TestColorLayer>(
*mComposerClient, display.getDisplayId(),
mDisplayProperties.at(display.getDisplayId()).writer);
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<std::shared_ptr<TestLayer>> layers = {redLayer, dimmerRedLayer};
std::vector<Color> expectedColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), redRect, RED);
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(), dimmerRedRect,
DIM_RED);
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
ALOGI(" Readback verification not supported for GPU composition for color mode %d",
mode);
continue;
}
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
testRenderEngine->setRenderLayers(layers);
ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
}
}
}
class GraphicsBlendModeCompositionTest
: public GraphicsCompositionTestBase,
public testing::WithParamInterface<std::tuple<std::string, std::string>> {
public:
void SetUp() override {
SetUpBase(std::get<0>(GetParam()));
for (const DisplayWrapper& display : mAllDisplays) {
// 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
auto& testColorModes = mDisplayProperties.at(display.getDisplayId()).testColorModes;
testColorModes.erase(
std::remove_if(testColorModes.begin(), testColorModes.end(),
[](ColorMode mode) { return mode != ColorMode::SRGB; }),
testColorModes.end());
}
}
void setBackgroundColor(int64_t displayId, Color color) {
mDisplayGfx[displayId].backgroundColor = color;
}
void setTopLayerColor(int64_t displayId, Color color) {
mDisplayGfx[displayId].topLayerColor = color;
}
void setUpLayers(const DisplayWrapper& display, BlendMode blendMode) {
auto& layers = mDisplayGfx[display.getDisplayId()].layers;
layers.clear();
std::vector<Color> topLayerPixelColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
ReadbackHelper::fillColorsArea(
topLayerPixelColors, display.getDisplayWidth(),
{0, 0, display.getDisplayWidth(), display.getDisplayHeight()},
mDisplayGfx[display.getDisplayId()].topLayerColor);
auto backgroundLayer = std::make_shared<TestColorLayer>(
*mComposerClient, display.getDisplayId(),
mDisplayProperties.at(display.getDisplayId()).writer);
backgroundLayer->setDisplayFrame(
{0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
backgroundLayer->setZOrder(0);
backgroundLayer->setColor(mDisplayGfx[display.getDisplayId()].backgroundColor);
auto layer = std::make_shared<TestBufferLayer>(
*mComposerClient, *mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
display.getDisplayId(), display.getDisplayWidth(), display.getDisplayHeight(),
PixelFormat::RGBA_8888, mDisplayProperties.at(display.getDisplayId()).writer);
layer->setDisplayFrame({0, 0, display.getDisplayWidth(), display.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())));
layers.push_back(backgroundLayer);
layers.push_back(layer);
}
void setExpectedColors(const DisplayWrapper& display, std::vector<Color>& expectedColors) {
auto& layers = mDisplayGfx[display.getDisplayId()].layers;
ASSERT_EQ(2, layers.size());
ReadbackHelper::clearColors(expectedColors, display.getDisplayWidth(),
display.getDisplayHeight(), display.getDisplayWidth());
auto layer = layers[1];
BlendMode blendMode = layer->getBlendMode();
auto& topLayerColor = mDisplayGfx[display.getDisplayId()].topLayerColor;
auto& backgroundColor = mDisplayGfx[display.getDisplayId()].backgroundColor;
float alpha = topLayerColor.a * layer->getAlpha();
if (blendMode == BlendMode::NONE) {
for (auto& expectedColor : expectedColors) {
expectedColor.r = topLayerColor.r * layer->getAlpha();
expectedColor.g = topLayerColor.g * layer->getAlpha();
expectedColor.b = topLayerColor.b * layer->getAlpha();
expectedColor.a = alpha;
}
} else if (blendMode == BlendMode::PREMULTIPLIED) {
for (auto& expectedColor : expectedColors) {
expectedColor.r =
topLayerColor.r * layer->getAlpha() + backgroundColor.r * (1.0f - alpha);
expectedColor.g =
topLayerColor.g * layer->getAlpha() + backgroundColor.g * (1.0f - alpha);
expectedColor.b =
topLayerColor.b * layer->getAlpha() + backgroundColor.b * (1.0f - alpha);
expectedColor.a = alpha + backgroundColor.a * (1.0f - alpha);
}
} else if (blendMode == BlendMode::COVERAGE) {
for (auto& expectedColor : expectedColors) {
expectedColor.r = topLayerColor.r * alpha + backgroundColor.r * (1.0f - alpha);
expectedColor.g = topLayerColor.g * alpha + backgroundColor.g * (1.0f - alpha);
expectedColor.b = topLayerColor.b * alpha + backgroundColor.b * (1.0f - alpha);
expectedColor.a = topLayerColor.a * alpha + backgroundColor.a * (1.0f - alpha);
}
}
}
protected:
struct DisplayGraphics {
std::vector<std::shared_ptr<TestLayer>> layers;
Color backgroundColor = BLACK;
Color topLayerColor = RED;
};
std::unordered_map<int64_t, struct DisplayGraphics> mDisplayGfx;
};
TEST_P(GraphicsBlendModeCompositionTest, None) {
for (const DisplayWrapper& display : mAllDisplays) {
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
std::vector<Color> expectedColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
setBackgroundColor(display.getDisplayId(), BLACK);
setTopLayerColor(display.getDisplayId(), TRANSLUCENT_RED);
setUpLayers(display, BlendMode::NONE);
setExpectedColors(display, expectedColors);
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
auto& layers = mDisplayGfx[display.getDisplayId()].layers;
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
continue;
}
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
testRenderEngine->setRenderLayers(layers);
ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
}
}
}
TEST_P(GraphicsBlendModeCompositionTest, Coverage) {
for (const DisplayWrapper& display : mAllDisplays) {
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
std::vector<Color> expectedColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
setBackgroundColor(display.getDisplayId(), BLACK);
setTopLayerColor(display.getDisplayId(), TRANSLUCENT_RED);
setUpLayers(display, BlendMode::COVERAGE);
setExpectedColors(display, expectedColors);
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
auto& layers = mDisplayGfx[display.getDisplayId()].layers;
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
continue;
}
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
}
}
}
TEST_P(GraphicsBlendModeCompositionTest, Premultiplied) {
for (const DisplayWrapper& display : mAllDisplays) {
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
std::vector<Color> expectedColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
setBackgroundColor(display.getDisplayId(), BLACK);
setTopLayerColor(display.getDisplayId(), TRANSLUCENT_RED);
setUpLayers(display, BlendMode::PREMULTIPLIED);
setExpectedColors(display, expectedColors);
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
auto& layers = mDisplayGfx[display.getDisplayId()].layers;
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
continue;
}
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
testRenderEngine->setRenderLayers(layers);
ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
}
}
}
class GraphicsTransformCompositionTest : public GraphicsCompositionTest {
protected:
void SetUp() override {
GraphicsCompositionTest::SetUp();
for (const DisplayWrapper& display : mAllDisplays) {
auto backgroundLayer = std::make_shared<TestColorLayer>(
*mComposerClient, display.getDisplayId(),
mDisplayProperties.at(display.getDisplayId()).writer);
backgroundLayer->setColor({0.0f, 0.0f, 0.0f, 0.0f});
backgroundLayer->setDisplayFrame(
{0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
backgroundLayer->setZOrder(0);
int& sideLength = mDisplayGfx[display.getDisplayId()].sideLength;
sideLength = display.getDisplayWidth() < display.getDisplayHeight()
? display.getDisplayWidth()
: display.getDisplayHeight();
common::Rect redRect = {0, 0, sideLength / 2, sideLength / 2};
common::Rect blueRect = {sideLength / 2, sideLength / 2, sideLength, sideLength};
auto& bufferLayer = mDisplayGfx[display.getDisplayId()].bufferLayer;
bufferLayer = std::make_shared<TestBufferLayer>(
*mComposerClient,
*mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
display.getDisplayId(), static_cast<uint32_t>(sideLength),
static_cast<uint32_t>(sideLength), PixelFormat::RGBA_8888,
mDisplayProperties.at(display.getDisplayId()).writer);
bufferLayer->setDisplayFrame({0, 0, sideLength, sideLength});
bufferLayer->setZOrder(10);
std::vector<Color> baseColors(static_cast<size_t>(sideLength * sideLength));
ReadbackHelper::fillColorsArea(baseColors, sideLength, redRect, RED);
ReadbackHelper::fillColorsArea(baseColors, sideLength, blueRect, BLUE);
ASSERT_NO_FATAL_FAILURE(bufferLayer->setBuffer(baseColors));
mDisplayGfx[display.getDisplayId()].layers = {backgroundLayer, bufferLayer};
}
}
protected:
struct DisplayGraphics {
std::shared_ptr<TestBufferLayer> bufferLayer;
std::vector<std::shared_ptr<TestLayer>> layers;
int sideLength;
};
std::unordered_map<int64_t, struct DisplayGraphics> mDisplayGfx;
};
TEST_P(GraphicsTransformCompositionTest, FLIP_H) {
for (const DisplayWrapper display : mAllDisplays) {
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
auto status = mComposerClient->setColorMode(display.getDisplayId(), mode,
RenderIntent::COLORIMETRIC);
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
(status.getServiceSpecificError() == IComposerClient::EX_UNSUPPORTED ||
status.getServiceSpecificError() == IComposerClient::EX_BAD_PARAMETER)) {
ALOGI("ColorMode not supported on Display %" PRId64 " for ColorMode %d",
display.getDisplayId(), mode);
continue;
}
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
auto& bufferLayer = mDisplayGfx[display.getDisplayId()].bufferLayer;
bufferLayer->setTransform(Transform::FLIP_H);
bufferLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
std::vector<Color> expectedColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
int& sideLength = mDisplayGfx[display.getDisplayId()].sideLength;
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
{sideLength / 2, 0, sideLength, sideLength / 2}, RED);
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
{0, sideLength / 2, sideLength / 2, sideLength}, BLUE);
auto& layers = mDisplayGfx[display.getDisplayId()].layers;
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
continue;
}
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
testRenderEngine->setRenderLayers(layers);
ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
}
}
}
TEST_P(GraphicsTransformCompositionTest, FLIP_V) {
for (const DisplayWrapper display : mAllDisplays) {
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
auto& bufferLayer = mDisplayGfx[display.getDisplayId()].bufferLayer;
bufferLayer->setTransform(Transform::FLIP_V);
bufferLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
std::vector<Color> expectedColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
int& sideLength = mDisplayGfx[display.getDisplayId()].sideLength;
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
{0, sideLength / 2, sideLength / 2, sideLength}, RED);
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
{sideLength / 2, 0, sideLength, sideLength / 2}, BLUE);
auto& layers = mDisplayGfx[display.getDisplayId()].layers;
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
continue;
}
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
testRenderEngine->setRenderLayers(layers);
ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
}
}
}
TEST_P(GraphicsTransformCompositionTest, ROT_180) {
for (const DisplayWrapper display : mAllDisplays) {
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
ReadbackBuffer readbackBuffer(display.getDisplayId(), mComposerClient,
display.getDisplayWidth(), display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat,
dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
auto& bufferLayer = mDisplayGfx[display.getDisplayId()].bufferLayer;
bufferLayer->setTransform(Transform::ROT_180);
bufferLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode));
std::vector<Color> expectedColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
int& sideLength = mDisplayGfx[display.getDisplayId()].sideLength;
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
{sideLength / 2, sideLength / 2, sideLength, sideLength},
RED);
ReadbackHelper::fillColorsArea(expectedColors, display.getDisplayWidth(),
{0, 0, sideLength / 2, sideLength / 2}, BLUE);
auto& layers = mDisplayGfx[display.getDisplayId()].layers;
writeLayers(layers, display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
continue;
}
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
auto& testRenderEngine = mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
testRenderEngine->setRenderLayers(layers);
ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
ASSERT_NO_FATAL_FAILURE(testRenderEngine->checkColorBuffer(expectedColors));
}
}
}
class GraphicsColorManagementCompositionTest
: public GraphicsCompositionTestBase,
public testing::WithParamInterface<std::tuple<std::string, Dataspace, Dataspace, Dataspace>> {
public:
void SetUp() override {
SetUpBase(std::get<0>(GetParam()));
for (const DisplayWrapper& display : mAllDisplays) {
// for some reason only sRGB reliably works
auto& testColorModes = mDisplayProperties.at(display.getDisplayId()).testColorModes;
testColorModes.erase(
std::remove_if(testColorModes.begin(), testColorModes.end(),
[](ColorMode mode) { return mode != ColorMode::SRGB; }),
testColorModes.end());
auto standard = std::get<1>(GetParam());
auto transfer = std::get<2>(GetParam());
auto range = std::get<3>(GetParam());
mDisplayGfx[display.getDisplayId()].layerDataspace = static_cast<Dataspace>(
static_cast<int32_t>(standard) | static_cast<int32_t>(transfer) |
static_cast<int32_t>(range));
ALOGD("Invoking test for dataspace: {%s, %s, %s}", toString(standard).c_str(),
toString(transfer).c_str(), toString(range).c_str());
}
}
void makeLayer(const DisplayWrapper& display) {
auto& layer = mDisplayGfx[display.getDisplayId()].layer;
layer = std::make_shared<TestBufferLayer>(
*mComposerClient, *mDisplayProperties.at(display.getDisplayId()).testRenderEngine,
display.getDisplayId(), display.getDisplayWidth(), display.getDisplayHeight(),
common::PixelFormat::RGBA_8888,
mDisplayProperties.at(display.getDisplayId()).writer);
layer->setDisplayFrame({0, 0, display.getDisplayWidth(), display.getDisplayHeight()});
layer->setZOrder(10);
layer->setAlpha(1.f);
layer->setDataspace(mDisplayGfx[display.getDisplayId()].layerDataspace);
}
void fillColor(const DisplayWrapper& display, Color color) {
std::vector<Color> baseColors(
static_cast<size_t>(display.getDisplayWidth() * display.getDisplayHeight()));
ReadbackHelper::fillColorsArea(baseColors, display.getDisplayWidth(),
common::Rect{.left = 0,
.top = 0,
.right = display.getDisplayWidth(),
.bottom = display.getDisplayHeight()},
color);
ASSERT_NO_FATAL_FAILURE(mDisplayGfx[display.getDisplayId()].layer->setBuffer(baseColors));
}
struct DisplayGraphics {
Dataspace layerDataspace;
std::shared_ptr<TestBufferLayer> layer;
};
std::unordered_map<int64_t, struct DisplayGraphics> mDisplayGfx;
};
// @VsrTest = 4.4-015
TEST_P(GraphicsColorManagementCompositionTest, ColorConversion) {
for (const DisplayWrapper display : mAllDisplays) {
for (ColorMode mode : mDisplayProperties.at(display.getDisplayId()).testColorModes) {
EXPECT_TRUE(
mComposerClient
->setColorMode(display.getDisplayId(), mode, RenderIntent::COLORIMETRIC)
.isOk());
auto [dataspace, readbackSupported] =
GetDataspaceAndIfReadBackSupported(display.getDisplayId());
if (!readbackSupported) {
continue;
}
auto& clientCompositionDisplaySettings =
mDisplayProperties.at(display.getDisplayId()).clientCompositionDisplaySettings;
clientCompositionDisplaySettings.outputDataspace =
static_cast<::android::ui::Dataspace>(dataspace);
mDisplayProperties.at(display.getDisplayId())
.testRenderEngine->setDisplaySettings(clientCompositionDisplaySettings);
makeLayer(display);
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(
display.getDisplayId(), mComposerClient, display.getDisplayWidth(),
display.getDisplayHeight(),
mDisplayProperties.at(display.getDisplayId()).pixelFormat, dataspace);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
fillColor(display, color);
auto& layer = mDisplayGfx[display.getDisplayId()].layer;
writeLayers({layer}, display.getDisplayId());
EXPECT_TRUE(mComposerClient->setPowerMode(display.getDisplayId(), PowerMode::ON)
.isOk());
ASSERT_TRUE(
mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.validateDisplay(display.getDisplayId(),
ComposerClientWriter::kNoTimestamp,
ComposerClientWrapper::kNoFrameIntervalNs);
execute(display.getDisplayId());
if (!mDisplayProperties.at(display.getDisplayId())
.reader.takeChangedCompositionTypes(display.getDisplayId())
.empty()) {
continue;
}
ASSERT_TRUE(
mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
mDisplayProperties.at(display.getDisplayId())
.writer.presentDisplay(display.getDisplayId());
execute(display.getDisplayId());
ASSERT_TRUE(
mDisplayProperties.at(display.getDisplayId()).reader.takeErrors().empty());
auto& testRenderEngine =
mDisplayProperties.at(display.getDisplayId()).testRenderEngine;
testRenderEngine->setRenderLayers({layer});
ASSERT_NO_FATAL_FAILURE(testRenderEngine->drawLayers());
ASSERT_NO_FATAL_FAILURE(
testRenderEngine->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