blob: ee12276994990adb4c12a5c37d2e856d9f261a3e [file] [log] [blame]
/*
* Copyright 2020 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
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wextra"
#include <type_traits>
#include "DisplayIdentificationTestHelpers.h"
#include <binder/IPCThreadState.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/mock/Display.h>
#include <compositionengine/mock/DisplayColorProfile.h>
#include <compositionengine/mock/DisplaySurface.h>
#include <compositionengine/mock/RenderSurface.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <gui/mock/GraphicBufferConsumer.h>
#include <gui/mock/GraphicBufferProducer.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
#include <renderengine/mock/RenderEngine.h>
#include <ui/DebugUtils.h>
#include "FakeDisplayInjector.h"
#include "TestableScheduler.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/DisplayHardware/MockDisplayMode.h"
#include "mock/DisplayHardware/MockPowerAdvisor.h"
#include "mock/MockEventThread.h"
#include "mock/MockNativeWindowSurface.h"
#include "mock/MockVsyncController.h"
#include "mock/system/window/MockNativeWindow.h"
namespace android {
// TODO: Do not polute the android namespace
namespace hal = android::hardware::graphics::composer::hal;
using testing::_;
using testing::AnyNumber;
using testing::DoAll;
using testing::Mock;
using testing::ResultOf;
using testing::Return;
using testing::SetArgPointee;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
using hal::ColorMode;
using hal::Connection;
using hal::DisplayType;
using hal::Error;
using hal::Hdr;
using hal::HWDisplayId;
using hal::IComposer;
using hal::IComposerClient;
using hal::PerFrameMetadataKey;
using hal::PowerMode;
class DisplayTransactionTest : public testing::Test {
public:
~DisplayTransactionTest() override;
// --------------------------------------------------------------------
// Mock/Fake injection
void injectMockScheduler(PhysicalDisplayId);
void injectMockComposer(int virtualDisplayCount);
void injectFakeBufferQueueFactory();
void injectFakeNativeWindowSurfaceFactory();
sp<DisplayDevice> injectDefaultInternalDisplay(
std::function<void(TestableSurfaceFlinger::FakeDisplayDeviceInjector&)> injectExtra) {
return mFakeDisplayInjector.injectInternalDisplay(injectExtra);
}
// --------------------------------------------------------------------
// Postcondition helpers
bool hasPhysicalHwcDisplay(hal::HWDisplayId) const;
bool hasTransactionFlagSet(int32_t flag) const;
bool hasDisplayDevice(const sp<IBinder>& displayToken) const;
const DisplayDevice& getDisplayDevice(const sp<IBinder>& displayToken) const;
bool hasCurrentDisplayState(const sp<IBinder>& displayToken) const;
const DisplayDeviceState& getCurrentDisplayState(const sp<IBinder>& displayToken) const;
bool hasDrawingDisplayState(const sp<IBinder>& displayToken) const;
const DisplayDeviceState& getDrawingDisplayState(const sp<IBinder>& displayToken) const;
// --------------------------------------------------------------------
// Test instances
TestableSurfaceFlinger mFlinger;
sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make();
sp<GraphicBuffer> mBuffer =
sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888,
GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN);
Hwc2::mock::PowerAdvisor mPowerAdvisor;
FakeDisplayInjector mFakeDisplayInjector{mFlinger, mPowerAdvisor, mNativeWindow};
// These mocks are created by the test, but are destroyed by SurfaceFlinger
// by virtue of being stored into a std::unique_ptr. However we still need
// to keep a reference to them for use in setting up call expectations.
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
Hwc2::mock::Composer* mComposer = nullptr;
mock::EventThread* mEventThread = new mock::EventThread;
mock::EventThread* mSFEventThread = new mock::EventThread;
// These mocks are created only when expected to be created via a factory.
sp<mock::GraphicBufferConsumer> mConsumer;
sp<mock::GraphicBufferProducer> mProducer;
surfaceflinger::mock::NativeWindowSurface* mNativeWindowSurface = nullptr;
protected:
DisplayTransactionTest(bool withMockScheduler = true);
};
constexpr int32_t DEFAULT_VSYNC_PERIOD = 16'666'667;
constexpr int32_t DEFAULT_DPI = 320;
constexpr int DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT = HAL_PIXEL_FORMAT_RGB_565;
constexpr int POWER_MODE_LEET = 1337; // An out of range power mode value
/* ------------------------------------------------------------------------
* Boolean avoidance
*
* To make calls and template instantiations more readable, we define some
* local enums along with an implicit bool conversion.
*/
#define BOOL_SUBSTITUTE(TYPENAME) enum class TYPENAME : bool { FALSE = false, TRUE = true };
BOOL_SUBSTITUTE(Async);
BOOL_SUBSTITUTE(Primary);
BOOL_SUBSTITUTE(Secure);
BOOL_SUBSTITUTE(Virtual);
template <typename PhysicalDisplay>
struct PhysicalDisplayIdType {};
template <uint64_t displayId>
using HalVirtualDisplayIdType = std::integral_constant<uint64_t, displayId>;
struct GpuVirtualDisplayIdType {};
template <typename>
struct IsPhysicalDisplayId : std::bool_constant<false> {};
template <typename PhysicalDisplay>
struct IsPhysicalDisplayId<PhysicalDisplayIdType<PhysicalDisplay>> : std::bool_constant<true> {};
template <typename>
struct DisplayIdGetter;
template <typename PhysicalDisplay>
struct DisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
static PhysicalDisplayId get() {
if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
return PhysicalDisplayId::fromPort(static_cast<bool>(PhysicalDisplay::PRIMARY)
? LEGACY_DISPLAY_TYPE_PRIMARY
: LEGACY_DISPLAY_TYPE_EXTERNAL);
}
const auto info =
parseDisplayIdentificationData(PhysicalDisplay::PORT,
PhysicalDisplay::GET_IDENTIFICATION_DATA());
return info ? info->id : PhysicalDisplayId::fromPort(PhysicalDisplay::PORT);
}
};
template <uint64_t displayId>
struct DisplayIdGetter<HalVirtualDisplayIdType<displayId>> {
static HalVirtualDisplayId get() { return HalVirtualDisplayId(displayId); }
};
template <>
struct DisplayIdGetter<GpuVirtualDisplayIdType> {
static GpuVirtualDisplayId get() { return GpuVirtualDisplayId(0); }
};
template <typename>
struct DisplayConnectionTypeGetter {
static constexpr std::optional<ui::DisplayConnectionType> value;
};
template <typename PhysicalDisplay>
struct DisplayConnectionTypeGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
static constexpr std::optional<ui::DisplayConnectionType> value =
PhysicalDisplay::CONNECTION_TYPE;
};
template <typename>
struct HwcDisplayIdGetter {
static constexpr std::optional<HWDisplayId> value;
};
constexpr HWDisplayId HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID = 1010;
template <uint64_t displayId>
struct HwcDisplayIdGetter<HalVirtualDisplayIdType<displayId>> {
static constexpr std::optional<HWDisplayId> value = HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID;
};
template <typename PhysicalDisplay>
struct HwcDisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
static constexpr std::optional<HWDisplayId> value = PhysicalDisplay::HWC_DISPLAY_ID;
};
// DisplayIdType can be:
// 1) PhysicalDisplayIdType<...> for generated ID of physical display backed by HWC.
// 2) HalVirtualDisplayIdType<...> for hard-coded ID of virtual display backed by HWC.
// 3) GpuVirtualDisplayIdType for virtual display without HWC backing.
template <typename DisplayIdType, int width, int height, Async async, Secure secure,
Primary primary, int grallocUsage, int displayFlags>
struct DisplayVariant {
using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>;
using HWC_DISPLAY_ID_OPT = HwcDisplayIdGetter<DisplayIdType>;
static constexpr int WIDTH = width;
static constexpr int HEIGHT = height;
static constexpr ui::Size RESOLUTION{WIDTH, HEIGHT};
static constexpr int GRALLOC_USAGE = grallocUsage;
// Whether the display is virtual or physical
static constexpr Virtual VIRTUAL =
IsPhysicalDisplayId<DisplayIdType>{} ? Virtual::FALSE : Virtual::TRUE;
// When creating native window surfaces for the framebuffer, whether those should be async
static constexpr Async ASYNC = async;
// Whether the display should be treated as secure
static constexpr Secure SECURE = secure;
// Whether the display is primary
static constexpr Primary PRIMARY = primary;
static constexpr int DISPLAY_FLAGS = displayFlags;
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder();
ceDisplayArgs.setId(DISPLAY_ID::get())
.setPixels(RESOLUTION)
.setPowerAdvisor(&test->mPowerAdvisor);
auto compositionDisplay =
compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
ceDisplayArgs.build());
auto injector =
TestableSurfaceFlinger::FakeDisplayDeviceInjector(test->mFlinger,
compositionDisplay,
CONNECTION_TYPE::value,
HWC_DISPLAY_ID_OPT::value,
static_cast<bool>(PRIMARY));
injector.setSecure(static_cast<bool>(SECURE));
injector.setNativeWindow(test->mNativeWindow);
// Creating a DisplayDevice requires getting default dimensions from the
// native window along with some other initial setup.
EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT))
.WillRepeatedly(Return(0));
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT))
.WillRepeatedly(Return(0));
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64))
.WillRepeatedly(Return(0));
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT))
.WillRepeatedly(Return(0));
return injector;
}
// Called by tests to set up any native window creation call expectations.
static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mNativeWindowSurface, getNativeWindow())
.WillOnce(Return(test->mNativeWindow));
EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT))
.WillRepeatedly(Return(0));
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT))
.WillRepeatedly(Return(0));
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64))
.WillRepeatedly(Return(0));
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT))
.WillRepeatedly(Return(0));
}
static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR));
EXPECT_CALL(*test->mConsumer, setConsumerName(_)).WillRepeatedly(Return(NO_ERROR));
EXPECT_CALL(*test->mConsumer, setConsumerUsageBits(GRALLOC_USAGE))
.WillRepeatedly(Return(NO_ERROR));
EXPECT_CALL(*test->mConsumer, setDefaultBufferSize(WIDTH, HEIGHT))
.WillRepeatedly(Return(NO_ERROR));
EXPECT_CALL(*test->mConsumer, setMaxAcquiredBufferCount(_))
.WillRepeatedly(Return(NO_ERROR));
}
static void setupFramebufferProducerBufferQueueCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mProducer, allocateBuffers(0, 0, 0, 0)).WillRepeatedly(Return());
}
};
template <HWDisplayId hwcDisplayId, DisplayType hwcDisplayType, typename DisplayVariant,
typename PhysicalDisplay = void>
struct HwcDisplayVariant {
// The display id supplied by the HWC
static constexpr HWDisplayId HWC_DISPLAY_ID = hwcDisplayId;
// The HWC display type
static constexpr DisplayType HWC_DISPLAY_TYPE = hwcDisplayType;
// The HWC active configuration id
static constexpr hal::HWConfigId HWC_ACTIVE_CONFIG_ID = 2001;
static constexpr PowerMode INIT_POWER_MODE = hal::PowerMode::ON;
static void injectPendingHotplugEvent(DisplayTransactionTest* test, Connection connection) {
test->mFlinger.mutablePendingHotplugEvents().emplace_back(
TestableSurfaceFlinger::HotplugEvent{HWC_DISPLAY_ID, connection});
}
// Called by tests to inject a HWC display setup
template <bool kInitPowerMode = true>
static void injectHwcDisplayWithNoDefaultCapabilities(DisplayTransactionTest* test) {
const auto displayId = DisplayVariant::DISPLAY_ID::get();
ASSERT_FALSE(GpuVirtualDisplayId::tryCast(displayId));
TestableSurfaceFlinger::FakeHwcDisplayInjector(displayId, HWC_DISPLAY_TYPE,
static_cast<bool>(DisplayVariant::PRIMARY))
.setHwcDisplayId(HWC_DISPLAY_ID)
.setResolution(DisplayVariant::RESOLUTION)
.setActiveConfig(HWC_ACTIVE_CONFIG_ID)
.setPowerMode(kInitPowerMode ? std::make_optional(INIT_POWER_MODE) : std::nullopt)
.inject(&test->mFlinger, test->mComposer);
}
// Called by tests to inject a HWC display setup
template <bool kInitPowerMode = true>
static void injectHwcDisplay(DisplayTransactionTest* test) {
if constexpr (kInitPowerMode) {
EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY_ID, _))
.WillOnce(DoAll(SetArgPointee<1>(std::vector<DisplayCapability>({})),
Return(Error::NONE)));
EXPECT_CALL(*test->mComposer, setPowerMode(HWC_DISPLAY_ID, INIT_POWER_MODE))
.WillOnce(Return(Error::NONE));
}
injectHwcDisplayWithNoDefaultCapabilities<kInitPowerMode>(test);
}
static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
DisplayTransactionTest* test) {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
.setId(DisplayVariant::DISPLAY_ID::get())
.setPixels(DisplayVariant::RESOLUTION)
.setIsSecure(static_cast<bool>(DisplayVariant::SECURE))
.setPowerAdvisor(&test->mPowerAdvisor)
.setName(std::string("Injected display for ") +
test_info->test_case_name() + "." + test_info->name())
.build();
return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
ceDisplayArgs);
}
static void setupHwcGetConfigsCallExpectations(DisplayTransactionTest* test) {
if (HWC_DISPLAY_TYPE == DisplayType::PHYSICAL) {
EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(std::vector<hal::HWConfigId>{
HWC_ACTIVE_CONFIG_ID}),
Return(Error::NONE)));
EXPECT_CALL(*test->mComposer,
getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
IComposerClient::Attribute::WIDTH, _))
.WillRepeatedly(
DoAll(SetArgPointee<3>(DisplayVariant::WIDTH), Return(Error::NONE)));
EXPECT_CALL(*test->mComposer,
getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
IComposerClient::Attribute::HEIGHT, _))
.WillRepeatedly(
DoAll(SetArgPointee<3>(DisplayVariant::HEIGHT), Return(Error::NONE)));
EXPECT_CALL(*test->mComposer,
getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
IComposerClient::Attribute::VSYNC_PERIOD, _))
.WillRepeatedly(
DoAll(SetArgPointee<3>(DEFAULT_VSYNC_PERIOD), Return(Error::NONE)));
EXPECT_CALL(*test->mComposer,
getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
IComposerClient::Attribute::DPI_X, _))
.WillRepeatedly(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
EXPECT_CALL(*test->mComposer,
getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
IComposerClient::Attribute::DPI_Y, _))
.WillRepeatedly(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
EXPECT_CALL(*test->mComposer,
getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
IComposerClient::Attribute::CONFIG_GROUP, _))
.WillRepeatedly(DoAll(SetArgPointee<3>(-1), Return(Error::NONE)));
} else {
EXPECT_CALL(*test->mComposer, getDisplayConfigs(_, _)).Times(0);
EXPECT_CALL(*test->mComposer, getDisplayAttribute(_, _, _, _)).Times(0);
}
}
template <bool kFailedHotplug = false>
static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
if constexpr (!kFailedHotplug) {
constexpr auto CONNECTION_TYPE =
PhysicalDisplay::CONNECTION_TYPE == ui::DisplayConnectionType::Internal
? IComposerClient::DisplayConnectionType::INTERNAL
: IComposerClient::DisplayConnectionType::EXTERNAL;
EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _))
.WillOnce(DoAll(SetArgPointee<1>(CONNECTION_TYPE),
Return(hal::V2_4::Error::NONE)));
}
EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_))
.WillOnce(Return(hal::Error::NONE));
setupHwcGetConfigsCallExpectations(test);
if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
.WillOnce(DoAll(SetArgPointee<1>(PhysicalDisplay::PORT),
SetArgPointee<2>(PhysicalDisplay::GET_IDENTIFICATION_DATA()),
Return(Error::NONE)));
} else {
EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
.WillOnce(Return(Error::UNSUPPORTED));
}
}
// Called by tests to set up HWC call expectations
static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY_ID, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(HWC_ACTIVE_CONFIG_ID), Return(Error::NONE)));
}
};
// Physical displays are expected to be synchronous, secure, and have a HWC display for output.
constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY =
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
constexpr int PHYSICAL_DISPLAY_FLAGS = 0x1;
template <typename PhysicalDisplay, int width, int height>
struct PhysicalDisplayVariant
: DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, Async::FALSE,
Secure::TRUE, PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY,
PHYSICAL_DISPLAY_FLAGS>,
HwcDisplayVariant<PhysicalDisplay::HWC_DISPLAY_ID, DisplayType::PHYSICAL,
DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height,
Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY,
GRALLOC_USAGE_PHYSICAL_DISPLAY, PHYSICAL_DISPLAY_FLAGS>,
PhysicalDisplay> {};
template <bool hasIdentificationData>
struct PrimaryDisplay {
static constexpr auto CONNECTION_TYPE = ui::DisplayConnectionType::Internal;
static constexpr Primary PRIMARY = Primary::TRUE;
static constexpr uint8_t PORT = 255;
static constexpr HWDisplayId HWC_DISPLAY_ID = 1001;
static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
static constexpr auto GET_IDENTIFICATION_DATA = getInternalEdid;
};
template <ui::DisplayConnectionType connectionType, bool hasIdentificationData>
struct SecondaryDisplay {
static constexpr auto CONNECTION_TYPE = connectionType;
static constexpr Primary PRIMARY = Primary::FALSE;
static constexpr uint8_t PORT = 254;
static constexpr HWDisplayId HWC_DISPLAY_ID = 1002;
static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
static constexpr auto GET_IDENTIFICATION_DATA =
connectionType == ui::DisplayConnectionType::Internal ? getInternalEdid
: getExternalEdid;
};
struct TertiaryDisplay {
static constexpr Primary PRIMARY = Primary::FALSE;
static constexpr uint8_t PORT = 253;
static constexpr HWDisplayId HWC_DISPLAY_ID = 1003;
static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
};
using PrimaryDisplayVariant = PhysicalDisplayVariant<PrimaryDisplay<false>, 3840, 2160>;
using InnerDisplayVariant = PhysicalDisplayVariant<PrimaryDisplay<true>, 1840, 2208>;
using OuterDisplayVariant =
PhysicalDisplayVariant<SecondaryDisplay<ui::DisplayConnectionType::Internal, true>, 1080,
2092>;
using ExternalDisplayVariant =
PhysicalDisplayVariant<SecondaryDisplay<ui::DisplayConnectionType::External, false>, 1920,
1280>;
using TertiaryDisplayVariant = PhysicalDisplayVariant<TertiaryDisplay, 1600, 1200>;
// A virtual display not supported by the HWC.
constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0;
constexpr int VIRTUAL_DISPLAY_FLAGS = 0x0;
template <int width, int height, Secure secure>
struct NonHwcVirtualDisplayVariant
: DisplayVariant<GpuVirtualDisplayIdType, width, height, Async::TRUE, secure, Primary::FALSE,
GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY, VIRTUAL_DISPLAY_FLAGS> {
using Base = DisplayVariant<GpuVirtualDisplayIdType, width, height, Async::TRUE, secure,
Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY,
VIRTUAL_DISPLAY_FLAGS>;
static void injectHwcDisplay(DisplayTransactionTest*) {}
static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
DisplayTransactionTest* test) {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
.setId(Base::DISPLAY_ID::get())
.setPixels(Base::RESOLUTION)
.setIsSecure(static_cast<bool>(Base::SECURE))
.setPowerAdvisor(&test->mPowerAdvisor)
.setName(std::string("Injected display for ") +
test_info->test_case_name() + "." + test_info->name())
.build();
return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
ceDisplayArgs);
}
static void setupHwcGetConfigsCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getDisplayConfigs(_, _)).Times(0);
EXPECT_CALL(*test->mComposer, getDisplayAttribute(_, _, _, _)).Times(0);
}
static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
}
static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
Base::setupNativeWindowSurfaceCreationCallExpectations(test);
EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1);
}
};
// A virtual display supported by the HWC.
constexpr uint32_t GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY = GRALLOC_USAGE_HW_COMPOSER;
template <int width, int height, Secure secure>
struct HwcVirtualDisplayVariant
: DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Async::TRUE, secure,
Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY, VIRTUAL_DISPLAY_FLAGS>,
HwcDisplayVariant<HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID, DisplayType::VIRTUAL,
DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Async::TRUE,
secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY,
VIRTUAL_DISPLAY_FLAGS>> {
using Base = DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Async::TRUE, secure,
Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER, VIRTUAL_DISPLAY_FLAGS>;
using Self = HwcVirtualDisplayVariant<width, height, secure>;
static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
DisplayTransactionTest* test) {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
const auto displayId = Base::DISPLAY_ID::get();
auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
.setId(displayId)
.setPixels(Base::RESOLUTION)
.setIsSecure(static_cast<bool>(Base::SECURE))
.setPowerAdvisor(&test->mPowerAdvisor)
.setName(std::string("Injected display for ") +
test_info->test_case_name() + "." + test_info->name())
.build();
auto compositionDisplay =
compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
ceDisplayArgs);
// Insert display data so that the HWC thinks it created the virtual display.
test->mFlinger.mutableHwcDisplayData().try_emplace(displayId);
return compositionDisplay;
}
static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
Base::setupNativeWindowSurfaceCreationCallExpectations(test);
EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1);
}
static void setupHwcVirtualDisplayCreationCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _))
.WillOnce(DoAll(SetArgPointee<3>(Self::HWC_DISPLAY_ID), Return(Error::NONE)));
EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
}
};
// For this variant, the display is not a HWC display, so no HDR support should
// be configured.
struct NonHwcDisplayHdrSupportVariant {
static constexpr bool HDR10_PLUS_SUPPORTED = false;
static constexpr bool HDR10_SUPPORTED = false;
static constexpr bool HDR_HLG_SUPPORTED = false;
static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getHdrCapabilities(_, _, _, _, _)).Times(0);
}
};
// For this variant, the composer should respond with am empty list of HDR
// modes, so no HDR support should be configured.
template <typename Display>
struct HdrNotSupportedVariant {
static constexpr bool HDR10_PLUS_SUPPORTED = false;
static constexpr bool HDR10_SUPPORTED = false;
static constexpr bool HDR_HLG_SUPPORTED = false;
static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>()), Return(Error::NONE)));
}
};
struct NonHwcPerFrameMetadataSupportVariant {
static constexpr int PER_FRAME_METADATA_KEYS = 0;
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(_)).Times(0);
}
};
template <typename Display>
struct NoPerFrameMetadataSupportVariant {
static constexpr int PER_FRAME_METADATA_KEYS = 0;
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
.WillOnce(Return(std::vector<PerFrameMetadataKey>()));
}
};
// For this variant, SurfaceFlinger should configure itself with wide display
// support, but the display should respond with an empty list of supported color
// modes. Wide-color support for the display should not be configured.
template <typename Display>
struct WideColorNotSupportedVariant {
static constexpr bool WIDE_COLOR_SUPPORTED = false;
static void injectConfigChange(DisplayTransactionTest* test) {
test->mFlinger.mutableSupportsWideColor() = true;
}
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0);
}
};
// For this variant, SurfaceFlinger should not configure itself with wide
// display support, so the display should not be configured for wide-color
// support.
struct WideColorSupportNotConfiguredVariant {
static constexpr bool WIDE_COLOR_SUPPORTED = false;
static void injectConfigChange(DisplayTransactionTest* test) {
test->mFlinger.mutableSupportsWideColor() = false;
test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
}
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getRenderIntents(_, _, _)).Times(0);
EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0);
}
};
/* ------------------------------------------------------------------------
* Typical display configurations to test
*/
template <typename DisplayPolicy, typename WideColorSupportPolicy, typename HdrSupportPolicy,
typename PerFrameMetadataSupportPolicy>
struct Case {
using Display = DisplayPolicy;
using WideColorSupport = WideColorSupportPolicy;
using HdrSupport = HdrSupportPolicy;
using PerFrameMetadataSupport = PerFrameMetadataSupportPolicy;
};
using SimplePrimaryDisplayCase =
Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
HdrNotSupportedVariant<PrimaryDisplayVariant>,
NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
using SimpleExternalDisplayCase =
Case<ExternalDisplayVariant, WideColorNotSupportedVariant<ExternalDisplayVariant>,
HdrNotSupportedVariant<ExternalDisplayVariant>,
NoPerFrameMetadataSupportVariant<ExternalDisplayVariant>>;
using SimpleTertiaryDisplayCase =
Case<TertiaryDisplayVariant, WideColorNotSupportedVariant<TertiaryDisplayVariant>,
HdrNotSupportedVariant<TertiaryDisplayVariant>,
NoPerFrameMetadataSupportVariant<TertiaryDisplayVariant>>;
using NonHwcVirtualDisplayCase =
Case<NonHwcVirtualDisplayVariant<1024, 768, Secure::FALSE>,
WideColorSupportNotConfiguredVariant, NonHwcDisplayHdrSupportVariant,
NonHwcPerFrameMetadataSupportVariant>;
using SimpleHwcVirtualDisplayVariant = HwcVirtualDisplayVariant<1024, 768, Secure::TRUE>;
using HwcVirtualDisplayCase =
Case<SimpleHwcVirtualDisplayVariant, WideColorSupportNotConfiguredVariant,
HdrNotSupportedVariant<SimpleHwcVirtualDisplayVariant>,
NoPerFrameMetadataSupportVariant<SimpleHwcVirtualDisplayVariant>>;
inline DisplayModePtr createDisplayMode(DisplayModeId modeId, Fps refreshRate, int32_t group = 0,
ui::Size resolution = ui::Size(1920, 1080)) {
return mock::createDisplayMode(modeId, refreshRate, group, resolution,
PrimaryDisplayVariant::DISPLAY_ID::get());
}
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"