[SurfaceFlinger] Add composition unit tests
Adds some simple tests to verify the hardware and software composition
of a range of layer types, using mocks to verify the right calls are
made to the HWC and RE interfaces
Test: atest libsurfaceflinger_unittest
Bug: 76421986
Bug: 76432611
Change-Id: Ic3f81008c2182048851a8ab32388e54ee815927a
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
new file mode 100644
index 0000000..5aa6e27
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -0,0 +1,1275 @@
+/*
+ * Copyright 2018 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "CompositionTest"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <gui/IProducerListener.h>
+#include <log/log.h>
+#include <system/window.h>
+#include <utils/String8.h>
+
+#include "BufferQueueLayer.h"
+#include "ColorLayer.h"
+#include "Layer.h"
+
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockMessageQueue.h"
+#include "mock/RenderEngine/MockRenderEngine.h"
+
+namespace android {
+namespace {
+
+using testing::_;
+using testing::ByMove;
+using testing::DoAll;
+using testing::IsNull;
+using testing::Mock;
+using testing::NotNull;
+using testing::Ref;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SetArgPointee;
+
+using android::Hwc2::Error;
+using android::Hwc2::IComposer;
+using android::Hwc2::IComposerClient;
+using android::Hwc2::Transform;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+constexpr hwc2_display_t HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
+constexpr hwc2_layer_t HWC_LAYER = 5000;
+constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0);
+
+constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
+constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
+
+constexpr int DEFAULT_CONFIG_ID = 0;
+constexpr int DEFAULT_TEXTURE_ID = 6000;
+constexpr int DEFAULT_LAYER_STACK = 7000;
+
+constexpr int DEFAULT_DISPLAY_MAX_LUMINANCE = 500;
+
+constexpr int DEFAULT_SIDEBAND_STREAM = 51;
+
+class CompositionTest : public testing::Test {
+public:
+ CompositionTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ mFlinger.mutableEventControlThread().reset(mEventControlThread);
+ mFlinger.mutableEventThread().reset(mEventThread);
+ mFlinger.mutableEventQueue().reset(mMessageQueue);
+
+ mFlinger.mutablePrimaryDispSync().reset(mPrimaryDispSync);
+ EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*mPrimaryDispSync, getPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+
+ mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
+ setupComposer(0);
+ }
+
+ ~CompositionTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ void setupComposer(int virtualDisplayCount) {
+ mComposer = new Hwc2::mock::Composer();
+ EXPECT_CALL(*mComposer, getCapabilities())
+ .WillOnce(Return(std::vector<IComposer::Capability>()));
+ EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+ Mock::VerifyAndClear(mComposer);
+ }
+
+ void setupForceGeometryDirty() {
+ // TODO: This requires the visible region and other related
+ // state to be set, and is problematic for BufferLayers since they are
+ // not visible without a buffer (and setting up a buffer looks like a
+ // pain)
+ // mFlinger.mutableVisibleRegionsDirty() = true;
+
+ mFlinger.mutableGeometryInvalid() = true;
+ }
+
+ template <typename Case>
+ void displayRefreshCompositionDirtyGeometry();
+
+ template <typename Case>
+ void displayRefreshCompositionDirtyFrame();
+
+ template <typename Case>
+ void captureScreenComposition();
+
+ std::unordered_set<HWC2::Capability> mDefaultCapabilities = {HWC2::Capability::SidebandStream};
+
+ TestableSurfaceFlinger mFlinger;
+ sp<DisplayDevice> mDisplay;
+ sp<DisplayDevice> mExternalDisplay;
+ sp<mock::DisplaySurface> mDisplaySurface = new mock::DisplaySurface();
+ renderengine::mock::Surface* mRenderSurface = new renderengine::mock::Surface();
+
+ mock::EventThread* mEventThread = new mock::EventThread();
+ mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
+
+ Hwc2::mock::Composer* mComposer = nullptr;
+ renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
+ mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+ mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+ renderengine::mock::Image* mReImage = new renderengine::mock::Image();
+ renderengine::mock::Framebuffer* mReFrameBuffer = new renderengine::mock::Framebuffer();
+
+ sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
+
+ sp<GraphicBuffer> mCaptureScreenBuffer;
+};
+
+template <typename LayerCase>
+void CompositionTest::displayRefreshCompositionDirtyGeometry() {
+ setupForceGeometryDirty();
+ LayerCase::setupForDirtyGeometry(this);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
+ mFlinger.onMessageReceived(MessageQueue::REFRESH);
+
+ LayerCase::cleanup(this);
+}
+
+template <typename LayerCase>
+void CompositionTest::displayRefreshCompositionDirtyFrame() {
+ LayerCase::setupForDirtyFrame(this);
+
+ // --------------------------------------------------------------------
+ // Invocation
+
+ mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
+ mFlinger.onMessageReceived(MessageQueue::REFRESH);
+
+ LayerCase::cleanup(this);
+}
+
+template <typename LayerCase>
+void CompositionTest::captureScreenComposition() {
+ LayerCase::setupForScreenCapture(this);
+
+ const Rect sourceCrop(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
+ constexpr int32_t minLayerZ = -1;
+ constexpr int32_t maxLayerZ = 1000;
+ constexpr bool useIdentityTransform = true;
+ constexpr bool forSystem = true;
+
+ DisplayRenderArea renderArea(mDisplay, sourceCrop, DEFAULT_DISPLAY_WIDTH,
+ DEFAULT_DISPLAY_HEIGHT, ui::Transform::ROT_0);
+
+ auto traverseLayers = [this](const LayerVector::Visitor& visitor) {
+ return mFlinger.traverseLayersInDisplay(mDisplay, minLayerZ, maxLayerZ, visitor);
+ };
+
+ // TODO: Eliminate expensive/real allocation if possible.
+ const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+ mCaptureScreenBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
+ HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot");
+
+ int fd = -1;
+ status_t result =
+ mFlinger.captureScreenImplLocked(renderArea, traverseLayers, mCaptureScreenBuffer.get(),
+ useIdentityTransform, forSystem, &fd);
+ if (fd >= 0) {
+ close(fd);
+ }
+
+ EXPECT_EQ(NO_ERROR, result);
+
+ LayerCase::cleanup(this);
+}
+
+/* ------------------------------------------------------------------------
+ * Variants for each display configuration which can be tested
+ */
+
+template <typename Derived>
+struct BaseDisplayVariant {
+ static constexpr bool IS_SECURE = true;
+ static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
+
+ static void setupPreconditions(CompositionTest* test) {
+ FakeHwcDisplayInjector(DisplayDevice::DISPLAY_PRIMARY, HWC2::DisplayType::Physical)
+ .setCapabilities(&test->mDefaultCapabilities)
+ .inject(&test->mFlinger, test->mComposer);
+
+ test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DisplayDevice::DISPLAY_PRIMARY,
+ DisplayDevice::DISPLAY_PRIMARY)
+ .setDisplaySize(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT)
+ .setDisplaySurface(test->mDisplaySurface)
+ .setRenderSurface(std::unique_ptr<renderengine::Surface>(
+ test->mRenderSurface))
+ .setSecure(Derived::IS_SECURE)
+ .setPowerMode(Derived::INIT_POWER_MODE)
+ .inject();
+ test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK);
+ }
+
+ template <typename Case>
+ static void setupCommonCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
+ .Times(1);
+ EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+ EXPECT_CALL(*test->mComposer, getDisplayRequests(HWC_DISPLAY, _, _, _)).Times(1);
+ EXPECT_CALL(*test->mComposer, acceptDisplayChanges(HWC_DISPLAY)).Times(1);
+ EXPECT_CALL(*test->mComposer, presentDisplay(HWC_DISPLAY, _)).Times(1);
+ EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1);
+
+ EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
+ EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+
+ EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface)))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*test->mRenderEngine,
+ setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+ Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::Transform::ROT_0))
+ .Times(1);
+
+ EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
+ EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1);
+
+ Case::CompositionType::setupHwcSetCallExpectations(test);
+ Case::CompositionType::setupHwcGetCallExpectations(test);
+ }
+
+ template <typename Case>
+ static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
+ // Called once with a non-null value to set a framebuffer, and then
+ // again with nullptr to clear it.
+ EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull())).WillOnce(Return(true));
+ EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull())).WillOnce(Return(true));
+
+ EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
+ EXPECT_CALL(*test->mRenderEngine, createFramebuffer())
+ .WillOnce(Return(
+ ByMove(std::unique_ptr<renderengine::Framebuffer>(test->mReFrameBuffer))));
+ EXPECT_CALL(*test->mRenderEngine, bindFrameBuffer(test->mReFrameBuffer)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, unbindFrameBuffer(test->mReFrameBuffer)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, clearWithColor(0, 0, 0, 1)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd())));
+ EXPECT_CALL(*test->mRenderEngine, finish()).WillOnce(Return(true));
+
+ EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::SRGB)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
+ .Times(1);
+ // This expectation retires on saturation as setViewportAndProjection is
+ // called an extra time for the code path this setup is for.
+ // TODO: Investigate this extra call
+ EXPECT_CALL(*test->mRenderEngine,
+ setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+ Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::Transform::ROT_0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1);
+ }
+
+ static void setupNonEmptyFrameCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mDisplaySurface, beginFrame(true)).Times(1);
+ }
+
+ static void setupEmptyFrameCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mDisplaySurface, beginFrame(false)).Times(1);
+ }
+
+ static void setupHwcCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)).Times(1);
+
+ EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+ }
+
+ static void setupRECompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
+ .Times(1);
+ EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
+ .WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
+
+ EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
+ .Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setupColorTransform(_)).Times(2);
+ // These expectations retire on saturation as the code path these
+ // expectations are for appears to make an extra call to them.
+ // TODO: Investigate this extra call
+ EXPECT_CALL(*test->mRenderEngine,
+ setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+ Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::Transform::ROT_0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface)))
+ .WillOnce(Return(true))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*test->mRenderSurface, swapBuffers()).Times(1);
+ }
+
+ template <typename Case>
+ static void setupRELayerCompositionCallExpectations(CompositionTest* test) {
+ Case::Layer::setupRECompositionCallExpectations(test);
+ }
+
+ template <typename Case>
+ static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) {
+ Case::Layer::setupREScreenshotCompositionCallExpectations(test);
+
+ EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+ }
+};
+
+struct DefaultDisplaySetupVariant : public BaseDisplayVariant<DefaultDisplaySetupVariant> {};
+
+struct InsecureDisplaySetupVariant : public BaseDisplayVariant<InsecureDisplaySetupVariant> {
+ static constexpr bool IS_SECURE = false;
+
+ template <typename Case>
+ static void setupRELayerCompositionCallExpectations(CompositionTest* test) {
+ Case::Layer::setupInsecureRECompositionCallExpectations(test);
+
+ // TODO: Investigate this extra call
+ EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+ }
+
+ template <typename Case>
+ static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) {
+ Case::Layer::setupInsecureREScreenshotCompositionCallExpectations(test);
+
+ EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+ }
+};
+
+struct PoweredOffDisplaySetupVariant : public BaseDisplayVariant<PoweredOffDisplaySetupVariant> {
+ static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_OFF;
+
+ template <typename Case>
+ static void setupCommonCompositionCallExpectations(CompositionTest* test) {
+ // TODO: This seems like an unnecessary call if display is powered off.
+ EXPECT_CALL(*test->mComposer,
+ setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
+ .Times(1);
+
+ // TODO: This seems like an unnecessary call if display is powered off.
+ Case::CompositionType::setupHwcSetCallExpectations(test);
+ }
+
+ static void setupHwcCompositionCallExpectations(CompositionTest*) {}
+
+ static void setupRECompositionCallExpectations(CompositionTest* test) {
+ // TODO: This seems like an unnecessary call if display is powered off.
+ EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
+ .WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
+ }
+
+ template <typename Case>
+ static void setupRELayerCompositionCallExpectations(CompositionTest*) {}
+};
+
+/* ------------------------------------------------------------------------
+ * Variants for each layer configuration which can be tested
+ */
+
+template <typename LayerProperties>
+struct BaseLayerProperties {
+ static constexpr uint32_t WIDTH = 100;
+ static constexpr uint32_t HEIGHT = 100;
+ static constexpr PixelFormat FORMAT = PIXEL_FORMAT_RGBA_8888;
+ static constexpr uint64_t USAGE =
+ GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_SW_WRITE_NEVER;
+ static constexpr android_dataspace DATASPACE = HAL_DATASPACE_UNKNOWN;
+ static constexpr uint32_t SCALING_MODE = 0;
+ static constexpr uint32_t TRANSFORM = 0;
+ static constexpr uint32_t LAYER_FLAGS = 0;
+ static constexpr float COLOR[] = {1.f, 1.f, 1.f, 1.f};
+ static constexpr IComposerClient::BlendMode BLENDMODE =
+ IComposerClient::BlendMode::PREMULTIPLIED;
+
+ static void enqueueBuffer(CompositionTest*, sp<BufferQueueLayer> layer) {
+ auto producer = layer->getProducer();
+
+ IGraphicBufferProducer::QueueBufferOutput qbo;
+ status_t result = producer->connect(nullptr, NATIVE_WINDOW_API_EGL, false, &qbo);
+ if (result != NO_ERROR) {
+ ALOGE("Failed to connect() (%d)", result);
+ return;
+ }
+
+ int slot;
+ sp<Fence> fence;
+ result = producer->dequeueBuffer(&slot, &fence, LayerProperties::WIDTH,
+ LayerProperties::HEIGHT, LayerProperties::FORMAT,
+ LayerProperties::USAGE, nullptr, nullptr);
+ if (result != IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+ ALOGE("Failed to dequeueBuffer() (%d)", result);
+ return;
+ }
+
+ sp<GraphicBuffer> buffer;
+ result = producer->requestBuffer(slot, &buffer);
+ if (result != NO_ERROR) {
+ ALOGE("Failed to requestBuffer() (%d)", result);
+ return;
+ }
+
+ IGraphicBufferProducer::QueueBufferInput qbi(systemTime(), false /* isAutoTimestamp */,
+ LayerProperties::DATASPACE,
+ Rect(LayerProperties::WIDTH,
+ LayerProperties::HEIGHT),
+ LayerProperties::SCALING_MODE,
+ LayerProperties::TRANSFORM, Fence::NO_FENCE);
+ result = producer->queueBuffer(slot, qbi, &qbo);
+ if (result != NO_ERROR) {
+ ALOGE("Failed to queueBuffer (%d)", result);
+ return;
+ }
+ }
+
+ static void setupLatchedBuffer(CompositionTest* test, sp<BufferQueueLayer> layer) {
+ // TODO: Eliminate the complexity of actually creating a buffer
+ EXPECT_CALL(*test->mRenderEngine, getMaxTextureSize()).WillOnce(Return(16384));
+ EXPECT_CALL(*test->mRenderEngine, getMaxViewportDims()).WillOnce(Return(16384));
+ status_t err =
+ layer->setDefaultBufferProperties(LayerProperties::WIDTH, LayerProperties::HEIGHT,
+ LayerProperties::FORMAT);
+ ASSERT_EQ(NO_ERROR, err);
+ Mock::VerifyAndClear(test->mRenderEngine);
+
+ EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+ enqueueBuffer(test, layer);
+ Mock::VerifyAndClear(test->mMessageQueue);
+
+ EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*test->mRenderEngine, createImage())
+ .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
+ EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, checkErrors()).Times(1);
+ EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, false)).WillOnce(Return(true));
+ bool ignoredRecomputeVisibleRegions;
+ layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
+ Mock::VerifyAndClear(test->mRenderEngine);
+ Mock::VerifyAndClear(test->mReImage);
+ }
+
+ static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+ setupLatchedBuffer(test, layer);
+ }
+
+ static void setupBufferLayerPostFrameCallExpectations(CompositionTest* test) {
+ // BufferLayer::onPostComposition(), when there is no present fence
+ EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY, _))
+ .WillOnce(DoAll(SetArgPointee<1>(DEFAULT_CONFIG_ID), Return(Error::NONE)));
+ }
+
+ static void setupHwcSetGeometryCallExpectations(CompositionTest* test) {
+ // TODO: Coverage of other values
+ EXPECT_CALL(*test->mComposer,
+ setLayerBlendMode(HWC_DISPLAY, HWC_LAYER, LayerProperties::BLENDMODE))
+ .Times(1);
+ // TODO: Coverage of other values for origin
+ EXPECT_CALL(*test->mComposer,
+ setLayerDisplayFrame(HWC_DISPLAY, HWC_LAYER,
+ IComposerClient::Rect({0, 0, LayerProperties::WIDTH,
+ LayerProperties::HEIGHT})))
+ .Times(1);
+ EXPECT_CALL(*test->mComposer,
+ setLayerPlaneAlpha(HWC_DISPLAY, HWC_LAYER, LayerProperties::COLOR[3]))
+ .Times(1);
+ // TODO: Coverage of other values
+ EXPECT_CALL(*test->mComposer, setLayerZOrder(HWC_DISPLAY, HWC_LAYER, 0u)).Times(1);
+ // TODO: Coverage of other values
+ EXPECT_CALL(*test->mComposer, setLayerInfo(HWC_DISPLAY, HWC_LAYER, 0u, 0u)).Times(1);
+
+ // These expectations retire on saturation as the code path these
+ // expectations are for appears to make an extra call to them.
+ // TODO: Investigate this extra call
+ EXPECT_CALL(*test->mComposer, setLayerTransform(HWC_DISPLAY, HWC_LAYER, DEFAULT_TRANSFORM))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+
+ static void setupHwcSetSourceCropBufferCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+ IComposerClient::FRect({0.f, 0.f, LayerProperties::WIDTH,
+ LayerProperties::HEIGHT})))
+ .Times(1);
+ }
+
+ static void setupHwcSetSourceCropColorCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+ IComposerClient::FRect({0.f, 0.f, 0.f, 0.f})))
+ .Times(1);
+ }
+
+ static void setupHwcSetPerFrameCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerVisibleRegion(HWC_DISPLAY, HWC_LAYER,
+ std::vector<IComposerClient::Rect>({IComposerClient::Rect(
+ {0, 0, LayerProperties::WIDTH,
+ LayerProperties::HEIGHT})})))
+ .Times(1);
+ }
+
+ static void setupHwcSetPerFrameColorCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
+
+ // TODO: use COLOR
+ EXPECT_CALL(*test->mComposer,
+ setLayerColor(HWC_DISPLAY, HWC_LAYER,
+ IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
+ .Times(1);
+
+ // TODO: ColorLayer::onPreComposition() always returns true, triggering an
+ // extra layer update in SurfaceFlinger::preComposition(). This seems
+ // wrong on the surface.
+ EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+ }
+
+ static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
+ EXPECT_CALL(*test->mComposer, setLayerBuffer(HWC_DISPLAY, HWC_LAYER, _, _, _)).Times(1);
+
+ setupBufferLayerPostFrameCallExpectations(test);
+ }
+
+ static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine,
+ setupLayerBlending(true, false, false,
+ half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
+ LayerProperties::COLOR[2], LayerProperties::COLOR[3])))
+ .Times(1);
+
+ EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setupLayerTexturing(_)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setSourceY410BT2020(false)).Times(1);
+ // This call retires on saturation as the code that renders a texture disables the state,
+ // along with a top-level disable to ensure it is disabled for non-buffer layers.
+ EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1).RetiresOnSaturation();
+ }
+
+ static void setupREBufferCompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
+
+ // TODO - Investigate and eliminate these differences between display
+ // composition and screenshot composition.
+ EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+ }
+
+ static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
+ setupREBufferCompositionCallExpectations(test);
+ }
+
+ static void setupREBufferScreenshotCompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
+ }
+
+ static void setupInsecureREBufferScreenshotCompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
+ }
+
+ static void setupREColorCompositionCommonCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+ }
+
+ static void setupREColorCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine,
+ setupLayerBlending(true, false, true,
+ half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
+ LayerProperties::COLOR[2], LayerProperties::COLOR[3])))
+ .Times(1);
+ EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
+ }
+
+ static void setupREColorScreenshotCompositionCallExpectations(CompositionTest* test) {
+ setupREColorCompositionCallExpectations(test);
+ }
+};
+
+struct DefaultLayerProperties : public BaseLayerProperties<DefaultLayerProperties> {};
+
+struct ColorLayerProperties : public BaseLayerProperties<ColorLayerProperties> {};
+
+struct SidebandLayerProperties : public BaseLayerProperties<SidebandLayerProperties> {
+ using Base = BaseLayerProperties<SidebandLayerProperties>;
+ static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE;
+
+ static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+ sp<NativeHandle> stream =
+ NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM),
+ false);
+ test->mFlinger.setLayerSidebandStream(layer, stream);
+ }
+
+ static void setupHwcSetSourceCropBufferCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+ IComposerClient::FRect({0.f, 0.f, -1.f, -1.f})))
+ .Times(1);
+ }
+
+ static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerSidebandStream(HWC_DISPLAY, HWC_LAYER,
+ reinterpret_cast<native_handle_t*>(
+ DEFAULT_SIDEBAND_STREAM)))
+ .WillOnce(Return(Error::NONE));
+
+ EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
+ }
+
+ static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, setupFillWithColor(0, 0, 0, 1)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+ }
+};
+
+struct SecureLayerProperties : public BaseLayerProperties<SecureLayerProperties> {
+ using Base = BaseLayerProperties<SecureLayerProperties>;
+
+ static constexpr uint32_t LAYER_FLAGS = ISurfaceComposerClient::eSecure;
+
+ static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setupLayerBlackedOut()).Times(1);
+
+ EXPECT_CALL(*test->mRenderEngine,
+ setupLayerBlending(true, false, false,
+ half4(Base::COLOR[0], Base::COLOR[1], Base::COLOR[2],
+ Base::COLOR[3])))
+ .Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
+ EXPECT_CALL(*test->mRenderEngine, setSourceY410BT2020(false)).Times(1);
+ // This call retires on saturation as the code that renders a texture disables the state,
+ // along with a top-level disable to ensure it is disabled for non-buffer layers.
+ EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1).RetiresOnSaturation();
+ }
+
+ static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
+ setupInsecureREBufferCompositionCommonCallExpectations(test);
+ Base::setupBufferLayerPostFrameCallExpectations(test);
+ }
+
+ static void setupInsecureREBufferScreenshotCompositionCallExpectations(CompositionTest* test) {
+ setupInsecureREBufferCompositionCommonCallExpectations(test);
+ }
+};
+
+struct CursorLayerProperties : public BaseLayerProperties<CursorLayerProperties> {
+ using Base = BaseLayerProperties<CursorLayerProperties>;
+
+ static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+ Base::setupLayerState(test, layer);
+ test->mFlinger.setLayerPotentialCursor(layer, true);
+ }
+};
+
+struct NoLayerVariant {
+ using FlingerLayerType = sp<BufferQueueLayer>;
+
+ static FlingerLayerType createLayer(CompositionTest*) { return FlingerLayerType(); }
+ static void injectLayer(CompositionTest*, FlingerLayerType) {}
+ static void cleanupInjectedLayers(CompositionTest*) {}
+
+ static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {}
+ static void setupCallExpectationsForDirtyFrame(CompositionTest*) {}
+};
+
+template <typename LayerProperties>
+struct BaseLayerVariant {
+ template <typename L, typename F>
+ static sp<L> createLayerWithFactory(CompositionTest* test, F factory) {
+ EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(0);
+
+ sp<L> layer = factory();
+
+ Mock::VerifyAndClear(test->mComposer);
+ Mock::VerifyAndClear(test->mRenderEngine);
+ Mock::VerifyAndClear(test->mMessageQueue);
+
+ auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
+ layerDrawingState.layerStack = DEFAULT_LAYER_STACK;
+ layerDrawingState.active.w = 100;
+ layerDrawingState.active.h = 100;
+ layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
+ LayerProperties::COLOR[2], LayerProperties::COLOR[3]);
+
+ layer->setVisibleRegion(Region(Rect(0, 0, 100, 100)));
+
+ return layer;
+ }
+
+ static void injectLayer(CompositionTest* test, sp<Layer> layer) {
+ EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
+ .WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
+
+ layer->createHwcLayer(test->mFlinger.mFlinger->getBE().mHwc.get(), test->mDisplay->getId());
+
+ Mock::VerifyAndClear(test->mComposer);
+
+ Vector<sp<Layer>> layers;
+ layers.add(layer);
+ test->mDisplay->setVisibleLayersSortedByZ(layers);
+ test->mFlinger.mutableDrawingState().layersSortedByZ.add(layer);
+ }
+
+ static void cleanupInjectedLayers(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, destroyLayer(HWC_DISPLAY, HWC_LAYER))
+ .WillOnce(Return(Error::NONE));
+ for (auto layer : test->mFlinger.mutableDrawingState().layersSortedByZ) {
+ layer->destroyHwcLayer(test->mDisplay->getId());
+ }
+ test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
+ }
+};
+
+template <typename LayerProperties>
+struct ColorLayerVariant : public BaseLayerVariant<LayerProperties> {
+ using Base = BaseLayerVariant<LayerProperties>;
+ using FlingerLayerType = sp<ColorLayer>;
+
+ static FlingerLayerType createLayer(CompositionTest* test) {
+ FlingerLayerType layer = Base::template createLayerWithFactory<ColorLayer>(test, [test]() {
+ return new ColorLayer(test->mFlinger.mFlinger.get(), sp<Client>(),
+ String8("test-layer"), LayerProperties::WIDTH,
+ LayerProperties::HEIGHT, LayerProperties::LAYER_FLAGS);
+ });
+ return layer;
+ }
+
+ static void setupRECompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREColorCompositionCommonCallExpectations(test);
+ LayerProperties::setupREColorCompositionCallExpectations(test);
+ }
+
+ static void setupREScreenshotCompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREColorScreenshotCompositionCallExpectations(test);
+ }
+
+ static void setupCallExpectationsForDirtyGeometry(CompositionTest* test) {
+ LayerProperties::setupHwcSetGeometryCallExpectations(test);
+ LayerProperties::setupHwcSetSourceCropColorCallExpectations(test);
+ }
+
+ static void setupCallExpectationsForDirtyFrame(CompositionTest* test) {
+ LayerProperties::setupHwcSetPerFrameCallExpectations(test);
+ LayerProperties::setupHwcSetPerFrameColorCallExpectations(test);
+ }
+};
+
+template <typename LayerProperties>
+struct BufferLayerVariant : public BaseLayerVariant<LayerProperties> {
+ using Base = BaseLayerVariant<LayerProperties>;
+ using FlingerLayerType = sp<BufferQueueLayer>;
+
+ static FlingerLayerType createLayer(CompositionTest* test) {
+ test->mFlinger.mutableTexturePool().push_back(DEFAULT_TEXTURE_ID);
+
+ FlingerLayerType layer =
+ Base::template createLayerWithFactory<BufferQueueLayer>(test, [test]() {
+ return new BufferQueueLayer(test->mFlinger.mFlinger.get(), sp<Client>(),
+ String8("test-layer"), LayerProperties::WIDTH,
+ LayerProperties::HEIGHT,
+ LayerProperties::LAYER_FLAGS);
+ });
+
+ LayerProperties::setupLayerState(test, layer);
+
+ return layer;
+ }
+
+ static void cleanupInjectedLayers(CompositionTest* test) {
+ EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(2);
+ Base::cleanupInjectedLayers(test);
+ }
+
+ static void setupCallExpectationsForDirtyGeometry(CompositionTest* test) {
+ LayerProperties::setupHwcSetGeometryCallExpectations(test);
+ LayerProperties::setupHwcSetSourceCropBufferCallExpectations(test);
+ }
+
+ static void setupCallExpectationsForDirtyFrame(CompositionTest* test) {
+ LayerProperties::setupHwcSetPerFrameCallExpectations(test);
+ LayerProperties::setupHwcSetPerFrameBufferCallExpectations(test);
+ }
+
+ static void setupRECompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREBufferCompositionCallExpectations(test);
+ }
+
+ static void setupInsecureRECompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupInsecureREBufferCompositionCallExpectations(test);
+ }
+
+ static void setupREScreenshotCompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupREBufferScreenshotCompositionCallExpectations(test);
+ }
+
+ static void setupInsecureREScreenshotCompositionCallExpectations(CompositionTest* test) {
+ LayerProperties::setupInsecureREBufferScreenshotCompositionCallExpectations(test);
+ }
+};
+
+/* ------------------------------------------------------------------------
+ * Variants to control how the composition type is changed
+ */
+
+struct NoCompositionTypeVariant {
+ static void setupHwcSetCallExpectations(CompositionTest*) {}
+
+ static void setupHwcGetCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, getChangedCompositionTypes(HWC_DISPLAY, _, _)).Times(1);
+ }
+};
+
+template <IComposerClient::Composition CompositionType>
+struct KeepCompositionTypeVariant {
+ static constexpr HWC2::Composition TYPE = static_cast<HWC2::Composition>(CompositionType);
+
+ static void setupHwcSetCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, CompositionType))
+ .Times(1);
+ }
+
+ static void setupHwcGetCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, getChangedCompositionTypes(HWC_DISPLAY, _, _)).Times(1);
+ }
+};
+
+template <IComposerClient::Composition InitialCompositionType,
+ IComposerClient::Composition FinalCompositionType>
+struct ChangeCompositionTypeVariant {
+ static constexpr HWC2::Composition TYPE = static_cast<HWC2::Composition>(FinalCompositionType);
+
+ static void setupHwcSetCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, InitialCompositionType))
+ .Times(1);
+ }
+
+ static void setupHwcGetCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, getChangedCompositionTypes(HWC_DISPLAY, _, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::Layer>{
+ static_cast<Hwc2::Layer>(HWC_LAYER)}),
+ SetArgPointee<2>(std::vector<IComposerClient::Composition>{
+ FinalCompositionType}),
+ Return(Error::NONE)));
+ }
+};
+
+/* ------------------------------------------------------------------------
+ * Variants to select how the composition is expected to be handled
+ */
+
+struct CompositionResultBaseVariant {
+ static void setupLayerState(CompositionTest*, sp<Layer>) {}
+
+ template <typename Case>
+ static void setupCallExpectationsForDirtyGeometry(CompositionTest* test) {
+ Case::Layer::setupCallExpectationsForDirtyGeometry(test);
+ }
+
+ template <typename Case>
+ static void setupCallExpectationsForDirtyFrame(CompositionTest* test) {
+ Case::Layer::setupCallExpectationsForDirtyFrame(test);
+ }
+};
+
+struct NoCompositionResultVariant : public CompositionResultBaseVariant {
+ template <typename Case>
+ static void setupCallExpectations(CompositionTest* test) {
+ Case::Display::setupEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupHwcCompositionCallExpectations(test);
+ }
+};
+
+struct HwcCompositionResultVariant : public CompositionResultBaseVariant {
+ template <typename Case>
+ static void setupCallExpectations(CompositionTest* test) {
+ Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupHwcCompositionCallExpectations(test);
+ }
+};
+
+struct RECompositionResultVariant : public CompositionResultBaseVariant {
+ template <typename Case>
+ static void setupCallExpectations(CompositionTest* test) {
+ Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupRECompositionCallExpectations(test);
+ Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
+ }
+};
+
+struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
+ static void setupLayerState(CompositionTest*, sp<Layer> layer) {
+ layer->forceClientComposition(DisplayDevice::DISPLAY_PRIMARY);
+ }
+
+ template <typename Case>
+ static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {}
+
+ template <typename Case>
+ static void setupCallExpectationsForDirtyFrame(CompositionTest*) {}
+};
+
+struct EmptyScreenshotResultVariant {
+ static void setupLayerState(CompositionTest*, sp<Layer>) {}
+
+ template <typename Case>
+ static void setupCallExpectations(CompositionTest*) {}
+};
+
+struct REScreenshotResultVariant : public EmptyScreenshotResultVariant {
+ using Base = EmptyScreenshotResultVariant;
+
+ template <typename Case>
+ static void setupCallExpectations(CompositionTest* test) {
+ Base::template setupCallExpectations<Case>(test);
+ Case::Display::template setupRELayerScreenshotCompositionCallExpectations<Case>(test);
+ }
+};
+
+/* ------------------------------------------------------------------------
+ * Composition test case, containing all the variants being tested
+ */
+
+template <typename DisplayCase, typename LayerCase, typename CompositionTypeCase,
+ typename CompositionResultCase>
+struct CompositionCase {
+ using ThisCase =
+ CompositionCase<DisplayCase, LayerCase, CompositionTypeCase, CompositionResultCase>;
+ using Display = DisplayCase;
+ using Layer = LayerCase;
+ using CompositionType = CompositionTypeCase;
+ using CompositionResult = CompositionResultCase;
+
+ static void setupCommon(CompositionTest* test) {
+ Display::setupPreconditions(test);
+
+ auto layer = Layer::createLayer(test);
+ Layer::injectLayer(test, layer);
+ CompositionResult::setupLayerState(test, layer);
+ }
+
+ static void setupForDirtyGeometry(CompositionTest* test) {
+ setupCommon(test);
+
+ Display::template setupCommonCompositionCallExpectations<ThisCase>(test);
+ CompositionResult::template setupCallExpectationsForDirtyGeometry<ThisCase>(test);
+ CompositionResult::template setupCallExpectationsForDirtyFrame<ThisCase>(test);
+ CompositionResult::template setupCallExpectations<ThisCase>(test);
+ }
+
+ static void setupForDirtyFrame(CompositionTest* test) {
+ setupCommon(test);
+
+ Display::template setupCommonCompositionCallExpectations<ThisCase>(test);
+ CompositionResult::template setupCallExpectationsForDirtyFrame<ThisCase>(test);
+ CompositionResult::template setupCallExpectations<ThisCase>(test);
+ }
+
+ static void setupForScreenCapture(CompositionTest* test) {
+ setupCommon(test);
+
+ Display::template setupCommonScreensCaptureCallExpectations<ThisCase>(test);
+ CompositionResult::template setupCallExpectations<ThisCase>(test);
+ }
+
+ static void cleanup(CompositionTest* test) {
+ Layer::cleanupInjectedLayers(test);
+
+ for (auto& hwcDisplay : test->mFlinger.mFakeHwcDisplays) {
+ hwcDisplay->mutableLayers().clear();
+ }
+
+ test->mDisplay->setVisibleLayersSortedByZ(Vector<sp<android::Layer>>());
+ }
+};
+
+/* ------------------------------------------------------------------------
+ * Composition cases to test
+ */
+
+TEST_F(CompositionTest, noLayersDoesMinimalWorkWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<DefaultDisplaySetupVariant, NoLayerVariant, NoCompositionTypeVariant,
+ NoCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, noLayersDoesMinimalWorkWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, NoLayerVariant, NoCompositionTypeVariant,
+ NoCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, noLayersDoesMinimalWorkToCaptureScreen) {
+ captureScreenComposition<
+ CompositionCase<DefaultDisplaySetupVariant, NoLayerVariant, NoCompositionTypeVariant,
+ EmptyScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ * Simple buffer layers
+ */
+
+TEST_F(CompositionTest, HWCComposedNormalBufferLayerWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedNormalBufferLayerWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedNormalBufferLayer) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ ChangeCompositionTypeVariant<IComposerClient::Composition::DEVICE,
+ IComposerClient::Composition::CLIENT>,
+ RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenNormalBufferLayer) {
+ captureScreenComposition<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ * Single-color layers
+ */
+
+TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedColorLayer) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ ChangeCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR,
+ IComposerClient::Composition::CLIENT>,
+ RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenColorLayer) {
+ captureScreenComposition<
+ CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ * Layers with sideband buffers
+ */
+
+TEST_F(CompositionTest, HWCComposedSidebandBufferLayerWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::SIDEBAND>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedSidebandBufferLayerWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::SIDEBAND>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedSidebandBufferLayer) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+ ChangeCompositionTypeVariant<IComposerClient::Composition::SIDEBAND,
+ IComposerClient::Composition::CLIENT>,
+ RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenSidebandBufferLayer) {
+ captureScreenComposition<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+ NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ * Layers with ISurfaceComposerClient::eSecure, on a secure display
+ */
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedSecureBufferLayer) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+ ChangeCompositionTypeVariant<IComposerClient::Composition::DEVICE,
+ IComposerClient::Composition::CLIENT>,
+ RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenSecureBufferLayerOnSecureDisplay) {
+ captureScreenComposition<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+ NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ * Layers with ISurfaceComposerClient::eSecure, on a non-secure display
+ */
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerOnInsecureDisplayWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<InsecureDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+ ForcedClientCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerOnInsecureDisplayWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<InsecureDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+ ForcedClientCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenSecureBufferLayerOnInsecureDisplay) {
+ captureScreenComposition<
+ CompositionCase<InsecureDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+ NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ * Cursor layers
+ */
+
+TEST_F(CompositionTest, HWCComposedCursorLayerWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::CURSOR>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedCursorLayerWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::CURSOR>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedCursorLayer) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+ ChangeCompositionTypeVariant<IComposerClient::Composition::CURSOR,
+ IComposerClient::Composition::CLIENT>,
+ RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenCursorLayer) {
+ captureScreenComposition<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+ NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ * Simple buffer layer on a display which is powered off.
+ */
+
+TEST_F(CompositionTest, displayOffHWCComposedNormalBufferLayerWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<CompositionCase<
+ PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, displayOffHWCComposedNormalBufferLayerWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<CompositionCase<
+ PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+ HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, displayOffREComposedNormalBufferLayer) {
+ displayRefreshCompositionDirtyFrame<CompositionCase<
+ PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ ChangeCompositionTypeVariant<IComposerClient::Composition::DEVICE,
+ IComposerClient::Composition::CLIENT>,
+ RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenNormalBufferLayerOnPoweredOffDisplay) {
+ captureScreenComposition<CompositionCase<
+ PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+} // namespace
+} // namespace android