blob: f3e11d811c3970a1535e01a732fd8910d15fb61e [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.
*/
#pragma once
#include <gtest/gtest.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
#include <ui/DisplayConfig.h>
#include "BufferGenerator.h"
#include "utils/ScreenshotUtils.h"
#include "utils/TransactionUtils.h"
namespace android {
using android::hardware::graphics::common::V1_1::BufferUsage;
class LayerTransactionTest : public ::testing::Test {
protected:
void SetUp() override {
mClient = new SurfaceComposerClient;
ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed));
}
virtual void TearDown() {
mBlackBgSurface = 0;
mClient->dispose();
mClient = 0;
}
virtual sp<SurfaceControl> createLayer(const sp<SurfaceComposerClient>& client,
const char* name, uint32_t width, uint32_t height,
uint32_t flags = 0, SurfaceControl* parent = nullptr,
uint32_t* outTransformHint = nullptr,
PixelFormat format = PIXEL_FORMAT_RGBA_8888) {
auto layer =
createSurface(client, name, width, height, format, flags, parent, outTransformHint);
Transaction t;
t.setLayerStack(layer, mDisplayLayerStack).setLayer(layer, mLayerZBase);
status_t error = t.apply();
if (error != NO_ERROR) {
ADD_FAILURE() << "failed to initialize SurfaceControl";
layer.clear();
}
return layer;
}
virtual sp<SurfaceControl> createSurface(const sp<SurfaceComposerClient>& client,
const char* name, uint32_t width, uint32_t height,
PixelFormat format, uint32_t flags,
SurfaceControl* parent = nullptr,
uint32_t* outTransformHint = nullptr) {
auto layer = client->createSurface(String8(name), width, height, format, flags, parent,
LayerMetadata(), outTransformHint);
EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
return layer;
}
virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
uint32_t flags = 0, SurfaceControl* parent = nullptr,
uint32_t* outTransformHint = nullptr,
PixelFormat format = PIXEL_FORMAT_RGBA_8888) {
return createLayer(mClient, name, width, height, flags, parent, outTransformHint, format);
}
sp<SurfaceControl> createColorLayer(const char* name, const Color& color,
SurfaceControl* parent = nullptr) {
auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */,
PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceEffect, parent);
asTransaction([&](Transaction& t) {
t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f});
t.setAlpha(colorLayer, color.a / 255.0f);
});
return colorLayer;
}
ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
// wait for previous transactions (such as setSize) to complete
Transaction().apply(true);
ANativeWindow_Buffer buffer = {};
EXPECT_EQ(NO_ERROR, layer->getSurface()->lock(&buffer, nullptr));
return buffer;
}
void postBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost());
// wait for the newly posted buffer to be latched
waitForLayerBuffers();
}
virtual void fillBufferQueueLayerColor(const sp<SurfaceControl>& layer, const Color& color,
int32_t bufferWidth, int32_t bufferHeight) {
ANativeWindow_Buffer buffer;
ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
TransactionUtils::fillANativeWindowBufferColor(buffer,
Rect(0, 0, bufferWidth, bufferHeight),
color);
postBufferQueueLayerBuffer(layer);
}
virtual void fillBufferStateLayerColor(const sp<SurfaceControl>& layer, const Color& color,
int32_t bufferWidth, int32_t bufferHeight) {
sp<GraphicBuffer> buffer =
new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
BufferUsage::COMPOSER_OVERLAY,
"test");
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight),
color);
Transaction().setBuffer(layer, buffer).apply();
}
void fillLayerColor(uint32_t mLayerType, const sp<SurfaceControl>& layer, const Color& color,
int32_t bufferWidth, int32_t bufferHeight) {
switch (mLayerType) {
case ISurfaceComposerClient::eFXSurfaceBufferQueue:
fillBufferQueueLayerColor(layer, color, bufferWidth, bufferHeight);
break;
case ISurfaceComposerClient::eFXSurfaceBufferState:
fillBufferStateLayerColor(layer, color, bufferWidth, bufferHeight);
break;
default:
ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType;
}
}
void fillLayerQuadrant(uint32_t mLayerType, const sp<SurfaceControl>& layer,
int32_t bufferWidth, int32_t bufferHeight, const Color& topLeft,
const Color& topRight, const Color& bottomLeft,
const Color& bottomRight) {
switch (mLayerType) {
case ISurfaceComposerClient::eFXSurfaceBufferQueue:
fillBufferQueueLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight,
bottomLeft, bottomRight);
break;
case ISurfaceComposerClient::eFXSurfaceBufferState:
fillBufferStateLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight,
bottomLeft, bottomRight);
break;
default:
ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType;
}
}
virtual void fillBufferQueueLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
int32_t bufferHeight, const Color& topLeft,
const Color& topRight, const Color& bottomLeft,
const Color& bottomRight) {
ANativeWindow_Buffer buffer;
ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
const int32_t halfW = bufferWidth / 2;
const int32_t halfH = bufferHeight / 2;
TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH),
topRight);
TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight),
bottomLeft);
TransactionUtils::fillANativeWindowBufferColor(buffer,
Rect(halfW, halfH, bufferWidth,
bufferHeight),
bottomRight);
postBufferQueueLayerBuffer(layer);
}
virtual void fillBufferStateLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
int32_t bufferHeight, const Color& topLeft,
const Color& topRight, const Color& bottomLeft,
const Color& bottomRight) {
sp<GraphicBuffer> buffer =
new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
BufferUsage::COMPOSER_OVERLAY,
"test");
ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
const int32_t halfW = bufferWidth / 2;
const int32_t halfH = bufferHeight / 2;
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
TransactionUtils::fillGraphicBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH),
topRight);
TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight),
bottomLeft);
TransactionUtils::fillGraphicBufferColor(buffer,
Rect(halfW, halfH, bufferWidth, bufferHeight),
bottomRight);
Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply();
}
std::unique_ptr<ScreenCapture> screenshot() {
std::unique_ptr<ScreenCapture> screenshot;
ScreenCapture::captureScreen(&screenshot);
return screenshot;
}
void asTransaction(const std::function<void(Transaction&)>& exec) {
Transaction t;
exec(t);
t.apply(true);
}
static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
static BufferGenerator bufferGenerator;
return bufferGenerator.get(outBuffer, outFence);
}
sp<SurfaceComposerClient> mClient;
sp<IBinder> mDisplay;
uint32_t mDisplayWidth;
uint32_t mDisplayHeight;
uint32_t mDisplayLayerStack;
Rect mDisplayRect = Rect::INVALID_RECT;
// leave room for ~256 layers
const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256;
sp<SurfaceControl> mBlackBgSurface;
bool mColorManagementUsed;
private:
void SetUpDisplay() {
mDisplay = mClient->getInternalDisplayToken();
ASSERT_FALSE(mDisplay == nullptr) << "failed to get display";
DisplayConfig config;
ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplay, &config));
mDisplayRect = Rect(config.resolution);
mDisplayWidth = mDisplayRect.getWidth();
mDisplayHeight = mDisplayRect.getHeight();
// After a new buffer is queued, SurfaceFlinger is notified and will
// latch the new buffer on next vsync. Let's heuristically wait for 3
// vsyncs.
mBufferPostDelay = static_cast<int32_t>(1e6 / config.refreshRate) * 3;
mDisplayLayerStack = 0;
mBlackBgSurface =
createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */,
PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
// set layer stack (b/68888219)
Transaction t;
t.setDisplayLayerStack(mDisplay, mDisplayLayerStack);
t.setCrop_legacy(mBlackBgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight));
t.setLayerStack(mBlackBgSurface, mDisplayLayerStack);
t.setColor(mBlackBgSurface, half3{0, 0, 0});
t.setLayer(mBlackBgSurface, mLayerZBase);
t.apply();
}
void waitForLayerBuffers() {
// Request an empty transaction to get applied synchronously to ensure the buffer is
// latched.
Transaction().apply(true);
usleep(mBufferPostDelay);
}
int32_t mBufferPostDelay;
friend class LayerRenderPathTestHarness;
};
} // namespace android