blob: 7d4314f4df94a7abf80b4babc4379b9312f3a4e3 [file] [log] [blame]
/*
* Copyright (C) 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.
*/
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#include <cutils/properties.h>
#include <gui/BufferItemConsumer.h>
#include "TransactionTestHarnesses.h"
namespace android {
using android::hardware::graphics::common::V1_1::BufferUsage;
class LayerTypeAndRenderTypeTransactionTest
: public LayerTypeTransactionHarness,
public ::testing::WithParamInterface<std::tuple<uint32_t, RenderPath>> {
public:
LayerTypeAndRenderTypeTransactionTest()
: LayerTypeTransactionHarness(std::get<0>(GetParam())),
mRenderPathHarness(LayerRenderPathTestHarness(this, std::get<1>(GetParam()))) {}
std::unique_ptr<ScreenCapture> getScreenCapture() {
return mRenderPathHarness.getScreenCapture();
}
protected:
LayerRenderPathTestHarness mRenderPathHarness;
};
::testing::Environment* const binderEnv =
::testing::AddGlobalTestEnvironment(new BinderEnvironment());
INSTANTIATE_TEST_CASE_P(
LayerTypeAndRenderTypeTransactionTests, LayerTypeAndRenderTypeTransactionTest,
::testing::Combine(
::testing::Values(
static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)),
::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT)));
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetSizeInvalid) {
// cannot test robustness against invalid sizes (zero or really huge)
}
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZBasic) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
Transaction().setLayer(layerR, mLayerZBase + 1).apply();
{
SCOPED_TRACE("layerR");
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setLayer(layerG, mLayerZBase + 2).apply();
{
SCOPED_TRACE("layerG");
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
}
}
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetRelativeZBug64572777) {
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
Transaction()
.setPosition(layerG, 16, 16)
.setRelativeLayer(layerG, layerR->getHandle(), 1)
.apply();
Transaction().reparent(layerG, nullptr).apply();
// layerG should have been removed
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsHidden) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply();
{
SCOPED_TRACE("layer hidden");
getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
}
Transaction().setFlags(layer, 0, layer_state_t::eLayerHidden).apply();
{
SCOPED_TRACE("layer shown");
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
}
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsOpaque) {
const Color translucentRed = {100, 0, 0, 100};
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, translucentRed, 32, 32));
ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
Transaction()
.setLayer(layerR, mLayerZBase + 1)
.setFlags(layerR, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque)
.apply();
{
SCOPED_TRACE("layerR opaque");
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, 0, 0, 255});
}
Transaction().setFlags(layerR, 0, layer_state_t::eLayerOpaque).apply();
{
SCOPED_TRACE("layerR translucent");
const uint8_t g = uint8_t(255 - translucentRed.a);
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, g, 0, 255});
}
}
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZNegative) {
sp<SurfaceControl> parent =
LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
ISurfaceComposerClient::eFXSurfaceContainer);
Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
sp<SurfaceControl> layerR;
sp<SurfaceControl> layerG;
ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
Transaction()
.reparent(layerR, parent->getHandle())
.reparent(layerG, parent->getHandle())
.apply();
Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply();
{
SCOPED_TRACE("layerR");
auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
Transaction().setLayer(layerR, -3).apply();
{
SCOPED_TRACE("layerG");
auto shot = getScreenCapture();
shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
}
}
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetAlphaClamped) {
const Color color = {64, 0, 0, 255};
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, color, 32, 32));
Transaction().setAlpha(layer, 2.0f).apply();
{
SCOPED_TRACE("clamped to 1.0f");
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), color);
}
Transaction().setAlpha(layer, -1.0f).apply();
{
SCOPED_TRACE("clamped to 0.0f");
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
}
}
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) {
sp<SurfaceControl> layer;
const uint8_t size = 64;
const uint8_t testArea = 4;
const float cornerRadius = 20.0f;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size));
if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
Transaction()
.setCornerRadius(layer, cornerRadius)
.setCrop_legacy(layer, Rect(0, 0, size, size))
.apply();
} else {
Transaction()
.setCornerRadius(layer, cornerRadius)
.setFrame(layer, Rect(0, 0, size, size))
.apply();
}
{
const uint8_t bottom = size - 1;
const uint8_t right = size - 1;
auto shot = getScreenCapture();
// Transparent corners
shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK);
shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::BLACK);
shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::BLACK);
// Solid center
shot->expectColor(Rect(size / 2 - testArea / 2, size / 2 - testArea / 2,
size / 2 + testArea / 2, size / 2 + testArea / 2),
Color::RED);
}
}
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusRotated) {
sp<SurfaceControl> parent;
sp<SurfaceControl> child;
const uint8_t size = 64;
const uint8_t testArea = 4;
const float cornerRadius = 20.0f;
ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, size, size));
ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size));
auto transaction = Transaction()
.setCornerRadius(parent, cornerRadius)
.setCrop_legacy(parent, Rect(0, 0, size, size))
.reparent(child, parent->getHandle())
.setPosition(child, 0, size)
// Rotate by half PI
.setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f);
if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
transaction.setCrop_legacy(parent, Rect(0, 0, size, size));
} else {
transaction.setFrame(parent, Rect(0, 0, size, size));
}
transaction.apply();
{
const uint8_t bottom = size - 1;
const uint8_t right = size - 1;
auto shot = getScreenCapture();
// Edges are transparent
shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK);
shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::BLACK);
shot->expectColor(Rect(0, bottom - testArea, testArea, bottom - testArea), Color::BLACK);
shot->expectColor(Rect(right - testArea, bottom - testArea, right, bottom), Color::BLACK);
// Solid center
shot->expectColor(Rect(size / 2 - testArea / 2, size / 2 - testArea / 2,
size / 2 + testArea / 2, size / 2 + testArea / 2),
Color::GREEN);
}
}
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) {
sp<SurfaceControl> parent;
sp<SurfaceControl> child;
const uint8_t size = 64;
const uint8_t testArea = 4;
const float cornerRadius = 20.0f;
ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, size, size));
ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2));
if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
Transaction()
.setCornerRadius(parent, cornerRadius)
.setCrop_legacy(parent, Rect(0, 0, size, size))
.reparent(child, parent->getHandle())
.setPosition(child, 0, size / 2)
.apply();
} else {
Transaction()
.setCornerRadius(parent, cornerRadius)
.setFrame(parent, Rect(0, 0, size, size))
.reparent(child, parent->getHandle())
.setFrame(child, Rect(0, size / 2, size, size))
.apply();
}
{
const uint8_t bottom = size - 1;
const uint8_t right = size - 1;
auto shot = getScreenCapture();
// Top edge of child should not have rounded corners because it's translated in the parent
shot->expectColor(Rect(0, size / 2, right, static_cast<int>(bottom - cornerRadius)),
Color::GREEN);
// But bottom edges should have been clipped according to parent bounds
shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
shot->expectColor(Rect(right - testArea, bottom - testArea, right, bottom), Color::BLACK);
}
}
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadius) {
char value[PROPERTY_VALUE_MAX];
property_get("ro.surface_flinger.supports_background_blur", value, "0");
if (!atoi(value)) {
// This device doesn't support blurs, no-op.
return;
}
auto size = 256;
auto center = size / 2;
auto blurRadius = 50;
sp<SurfaceControl> backgroundLayer;
ASSERT_NO_FATAL_FAILURE(backgroundLayer = createLayer("background", size, size));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(backgroundLayer, Color::GREEN, size, size));
sp<SurfaceControl> leftLayer;
ASSERT_NO_FATAL_FAILURE(leftLayer = createLayer("left", size / 2, size));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(leftLayer, Color::RED, size / 2, size));
sp<SurfaceControl> blurLayer;
ASSERT_NO_FATAL_FAILURE(blurLayer = createLayer("blur", size, size));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(blurLayer, Color::TRANSPARENT, size, size));
Transaction().setBackgroundBlurRadius(blurLayer, blurRadius).apply();
auto shot = getScreenCapture();
// Edges are mixed
shot->expectColor(Rect(center - 1, center - 5, center, center + 5), Color{150, 150, 0, 255},
50 /* tolerance */);
shot->expectColor(Rect(center, center - 5, center + 1, center + 5), Color{150, 150, 0, 255},
50 /* tolerance */);
}
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusOnMultipleLayers) {
char value[PROPERTY_VALUE_MAX];
property_get("ro.surface_flinger.supports_background_blur", value, "0");
if (!atoi(value)) {
// This device doesn't support blurs, no-op.
return;
}
auto size = 256;
auto center = size / 2;
auto blurRadius = 50;
sp<SurfaceControl> backgroundLayer;
ASSERT_NO_FATAL_FAILURE(backgroundLayer = createLayer("background", size, size));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(backgroundLayer, Color::GREEN, size, size));
sp<SurfaceControl> leftLayer;
ASSERT_NO_FATAL_FAILURE(leftLayer = createLayer("left", size / 2, size));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(leftLayer, Color::RED, size / 2, size));
sp<SurfaceControl> blurLayer1;
auto centralSquareSize = size / 2;
ASSERT_NO_FATAL_FAILURE(blurLayer1 =
createLayer("blur1", centralSquareSize, centralSquareSize));
ASSERT_NO_FATAL_FAILURE(
fillLayerColor(blurLayer1, Color::BLUE, centralSquareSize, centralSquareSize));
sp<SurfaceControl> blurLayer2;
ASSERT_NO_FATAL_FAILURE(blurLayer2 = createLayer("blur2", size, size));
ASSERT_NO_FATAL_FAILURE(
fillLayerColor(blurLayer2, Color::TRANSPARENT, centralSquareSize, centralSquareSize));
Transaction()
.setBackgroundBlurRadius(blurLayer1, blurRadius)
.setBackgroundBlurRadius(blurLayer2, blurRadius)
.apply();
auto shot = getScreenCapture();
shot->expectColor(Rect(center - 5, center - 5, center, center), Color{100, 100, 100, 255},
40 /* tolerance */);
}
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) {
sp<SurfaceControl> bufferLayer;
ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED, 32, 32));
// color is ignored
Transaction().setColor(bufferLayer, half3(0.0f, 1.0f, 0.0f)).apply();
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetLayerStackBasic) {
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
{
SCOPED_TRACE("non-existing layer stack");
getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
}
Transaction().setLayerStack(layer, mDisplayLayerStack).apply();
{
SCOPED_TRACE("original layer stack");
getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
}
}
TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBufferFormat) {
int32_t width = 100;
int32_t height = 100;
Rect crop = Rect(0, 0, width, height);
sp<SurfaceControl> behindLayer = createColorLayer("Behind layer", Color::RED);
sp<SurfaceControl> layer;
ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height, 0, nullptr, nullptr,
PIXEL_FORMAT_RGBX_8888));
Transaction()
.setLayer(layer, INT32_MAX - 1)
.show(layer)
.setLayerStack(behindLayer, mDisplayLayerStack)
.setCrop_legacy(behindLayer, crop)
.setLayer(behindLayer, INT32_MAX - 2)
.show(behindLayer)
.apply();
sp<Surface> surface = layer->getSurface();
sp<GraphicBuffer> buffer =
new GraphicBuffer(width, height, PIXEL_FORMAT_RGBX_8888, 1,
BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
BufferUsage::COMPOSER_OVERLAY,
"test");
ASSERT_NO_FATAL_FAILURE(
TransactionUtils::fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT));
if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
Surface::attachAndQueueBufferWithDataspace(surface.get(), buffer, ui::Dataspace::V0_SRGB);
} else {
Transaction().setBuffer(layer, buffer).apply();
}
{
SCOPED_TRACE("Buffer Opaque Format");
auto shot = screenshot();
shot->expectColor(crop, Color::BLACK);
}
buffer = new GraphicBuffer(width, height, PIXEL_FORMAT_RGBA_8888, 1,
BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
BufferUsage::COMPOSER_OVERLAY,
"test");
ASSERT_NO_FATAL_FAILURE(
TransactionUtils::fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT));
if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
Surface::attachAndQueueBufferWithDataspace(surface.get(), buffer, ui::Dataspace::V0_SRGB);
} else {
Transaction().setBuffer(layer, buffer).apply();
}
{
SCOPED_TRACE("Buffer Transparent Format");
auto shot = screenshot();
shot->expectColor(crop, Color::RED);
}
}
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion"