blob: b179f35109f90e0306355742365da2a9cd7fecbe [file] [log] [blame]
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <composer-vts/2.2/ReadbackVts.h>
namespace android {
namespace hardware {
namespace graphics {
namespace composer {
namespace V2_2 {
namespace vts {
void TestLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
writer->selectLayer(mLayer);
writer->setLayerDisplayFrame(mDisplayFrame);
writer->setLayerSourceCrop(mSourceCrop);
writer->setLayerZOrder(mZOrder);
writer->setLayerSurfaceDamage(mSurfaceDamage);
writer->setLayerTransform(mTransform);
writer->setLayerPlaneAlpha(mAlpha);
writer->setLayerBlendMode(mBlendMode);
}
const std::vector<ColorMode> ReadbackHelper::colorModes = {ColorMode::SRGB, ColorMode::DISPLAY_P3};
const std::vector<Dataspace> ReadbackHelper::dataspaces = {Dataspace::V0_SRGB,
Dataspace::DISPLAY_P3};
std::string ReadbackHelper::getColorModeString(ColorMode mode) {
switch (mode) {
case ColorMode::SRGB:
return std::string("SRGB");
case ColorMode::DISPLAY_P3:
return std::string("DISPLAY_P3");
default:
return std::string("Unsupported color mode for readback");
}
}
std::string ReadbackHelper::getDataspaceString(Dataspace dataspace) {
switch (dataspace) {
case Dataspace::V0_SRGB:
return std::string("V0_SRGB");
case Dataspace::DISPLAY_P3:
return std::string("DISPLAY_P3");
case Dataspace::UNKNOWN:
return std::string("UNKNOWN");
default:
return std::string("Unsupported dataspace for readback");
}
}
Dataspace ReadbackHelper::getDataspaceForColorMode(ColorMode mode) {
switch (mode) {
case ColorMode::DISPLAY_P3:
return Dataspace::DISPLAY_P3;
case ColorMode::SRGB:
default:
return Dataspace::UNKNOWN;
}
}
LayerSettings TestLayer::toRenderEngineLayerSettings() {
LayerSettings layerSettings;
layerSettings.alpha = half(mAlpha);
layerSettings.disableBlending = mBlendMode == IComposerClient::BlendMode::NONE;
layerSettings.geometry.boundaries = FloatRect(
static_cast<float>(mDisplayFrame.left), static_cast<float>(mDisplayFrame.top),
static_cast<float>(mDisplayFrame.right), static_cast<float>(mDisplayFrame.bottom));
const mat4 translation = mat4::translate(
vec4((mTransform & Transform::FLIP_H ? -mDisplayFrame.right : 0.0f),
(mTransform & Transform::FLIP_V ? -mDisplayFrame.bottom : 0.0f), 0.0f, 1.0f));
const mat4 scale = mat4::scale(vec4(mTransform & Transform::FLIP_H ? -1.0f : 1.0f,
mTransform & Transform::FLIP_V ? -1.0f : 1.0f, 1.0f, 1.0f));
layerSettings.geometry.positionTransform = scale * translation;
return layerSettings;
}
int32_t ReadbackHelper::GetBytesPerPixel(PixelFormat pixelFormat) {
switch (pixelFormat) {
case PixelFormat::RGBA_8888:
return 4;
case PixelFormat::RGB_888:
return 3;
default:
return -1;
}
}
void ReadbackHelper::fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
PixelFormat pixelFormat,
std::vector<IComposerClient::Color> desiredPixelColors) {
ASSERT_TRUE(pixelFormat == PixelFormat::RGB_888 || pixelFormat == PixelFormat::RGBA_8888);
int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
ASSERT_NE(-1, bytesPerPixel);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int pixel = row * width + col;
IComposerClient::Color srcColor = desiredPixelColors[pixel];
int offset = (row * stride + col) * bytesPerPixel;
uint8_t* pixelColor = (uint8_t*)bufferData + offset;
pixelColor[0] = srcColor.r;
pixelColor[1] = srcColor.g;
pixelColor[2] = srcColor.b;
if (bytesPerPixel == 4) {
pixelColor[3] = srcColor.a;
}
}
}
}
void ReadbackHelper::clearColors(std::vector<IComposerClient::Color>& expectedColors, int32_t width,
int32_t height, int32_t displayWidth) {
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int pixel = row * displayWidth + col;
expectedColors[pixel] = BLACK;
}
}
}
void ReadbackHelper::fillColorsArea(std::vector<IComposerClient::Color>& expectedColors,
int32_t stride, IComposerClient::Rect area,
IComposerClient::Color color) {
for (int row = area.top; row < area.bottom; row++) {
for (int col = area.left; col < area.right; col++) {
int pixel = row * stride + col;
expectedColors[pixel] = color;
}
}
}
bool ReadbackHelper::readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
const Error error) {
if (error != Error::NONE) {
return false;
}
// TODO: add support for RGBA_1010102
if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) {
return false;
}
if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
return false;
}
return true;
}
void ReadbackHelper::compareColorBuffers(std::vector<IComposerClient::Color>& expectedColors,
void* bufferData, const uint32_t stride,
const uint32_t width, const uint32_t height,
const PixelFormat pixelFormat) {
const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
ASSERT_NE(-1, bytesPerPixel);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int pixel = row * width + col;
int offset = (row * stride + col) * bytesPerPixel;
uint8_t* pixelColor = (uint8_t*)bufferData + offset;
ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]);
ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]);
ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]);
}
}
}
ReadbackBuffer::ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
const std::shared_ptr<Gralloc>& gralloc, uint32_t width,
uint32_t height, PixelFormat pixelFormat, Dataspace dataspace) {
mDisplay = display;
mComposerClient = client;
mGralloc = gralloc;
mPixelFormat = pixelFormat;
mDataspace = dataspace;
mWidth = width;
mHeight = height;
mLayerCount = 1;
mFormat = mPixelFormat;
mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE);
mAccessRegion.top = 0;
mAccessRegion.left = 0;
mAccessRegion.width = width;
mAccessRegion.height = height;
}
ReadbackBuffer::~ReadbackBuffer() {
if (mBufferHandle != nullptr) {
mGralloc->freeBuffer(mBufferHandle);
}
}
void ReadbackBuffer::setReadbackBuffer() {
if (mBufferHandle != nullptr) {
mGralloc->freeBuffer(mBufferHandle);
mBufferHandle = nullptr;
}
mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
/*import*/ true, &mStride);
ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount,
mFormat, mUsage, mStride));
ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle, -1));
}
void ReadbackBuffer::checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors) {
// lock buffer for reading
int32_t fenceHandle;
ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle));
void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, fenceHandle);
ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
ReadbackHelper::compareColorBuffers(expectedColors, bufData, mStride, mWidth, mHeight,
mPixelFormat);
int32_t unlockFence = mGralloc->unlock(mBufferHandle);
if (unlockFence != -1) {
sync_wait(unlockFence, -1);
close(unlockFence);
}
}
void TestColorLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
TestLayer::write(writer);
writer->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
writer->setLayerColor(mColor);
}
LayerSettings TestColorLayer::toRenderEngineLayerSettings() {
LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
layerSettings.source.solidColor =
half3(static_cast<half>(mColor.r) / 255.0, static_cast<half>(mColor.g) / 255.0,
static_cast<half>(mColor.b) / 255.0);
layerSettings.alpha = mAlpha * (static_cast<half>(mColor.a) / 255.0);
return layerSettings;
}
TestBufferLayer::TestBufferLayer(const std::shared_ptr<ComposerClient>& client,
const std::shared_ptr<Gralloc>& gralloc, Display display,
int32_t width, int32_t height, PixelFormat format,
IComposerClient::Composition composition)
: TestLayer{client, display} {
mGralloc = gralloc;
mComposition = composition;
mWidth = width;
mHeight = height;
mLayerCount = 1;
mFormat = format;
mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE);
mAccessRegion.top = 0;
mAccessRegion.left = 0;
mAccessRegion.width = width;
mAccessRegion.height = height;
setSourceCrop({0, 0, (float)width, (float)height});
}
TestBufferLayer::~TestBufferLayer() {
if (mBufferHandle != nullptr) {
mGralloc->freeBuffer(mBufferHandle);
}
}
void TestBufferLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
TestLayer::write(writer);
writer->setLayerCompositionType(mComposition);
writer->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, mDisplayFrame));
if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence);
}
LayerSettings TestBufferLayer::toRenderEngineLayerSettings() {
LayerSettings layerSettings = TestLayer::toRenderEngineLayerSettings();
layerSettings.source.buffer.buffer =
new GraphicBuffer(mBufferHandle, GraphicBuffer::CLONE_HANDLE, mWidth, mHeight,
static_cast<int32_t>(mFormat), 1, mUsage, mStride);
layerSettings.source.buffer.usePremultipliedAlpha =
mBlendMode == IComposerClient::BlendMode::PREMULTIPLIED;
const float scaleX = (mSourceCrop.right - mSourceCrop.left) / (mWidth);
const float scaleY = (mSourceCrop.bottom - mSourceCrop.top) / (mHeight);
const float translateX = mSourceCrop.left / (mWidth);
const float translateY = mSourceCrop.top / (mHeight);
layerSettings.source.buffer.textureTransform =
mat4::translate(vec4(translateX, translateY, 0, 1)) *
mat4::scale(vec4(scaleX, scaleY, 1.0, 1.0));
return layerSettings;
}
void TestBufferLayer::fillBuffer(std::vector<IComposerClient::Color> expectedColors) {
void* bufData = mGralloc->lock(mBufferHandle, mUsage, mAccessRegion, -1);
ASSERT_NO_FATAL_FAILURE(
ReadbackHelper::fillBuffer(mWidth, mHeight, mStride, bufData, mFormat, expectedColors));
mFillFence = mGralloc->unlock(mBufferHandle);
if (mFillFence != -1) {
sync_wait(mFillFence, -1);
close(mFillFence);
}
}
void TestBufferLayer::setBuffer(std::vector<IComposerClient::Color> colors) {
if (mBufferHandle != nullptr) {
mGralloc->freeBuffer(mBufferHandle);
mBufferHandle = nullptr;
}
mBufferHandle = mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
/*import*/ true, &mStride);
ASSERT_NE(nullptr, mBufferHandle);
ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mWidth, mHeight, mLayerCount,
mFormat, mUsage, mStride));
}
void TestBufferLayer::setDataspace(Dataspace dataspace,
const std::shared_ptr<CommandWriterBase>& writer) {
writer->selectLayer(mLayer);
writer->setLayerDataspace(dataspace);
}
void TestBufferLayer::setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer) {
writer->selectLayer(mLayer);
writer->setLayerCompositionType(IComposerClient::Composition::CLIENT);
}
} // namespace vts
} // namespace V2_2
} // namespace composer
} // namespace graphics
} // namespace hardware
} // namespace android