From 5f9f9a45ae9416aca58ca15f95c27f8b6c904d5f Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 2 Jan 2020 14:28:39 -0800 Subject: [PATCH] composer: vts: send a refresh command when required + test fix When calling to setActiveConfigWithConstraints, the implementation may need the client to send a refresh frame before the active config can be changed. In addition, testing with a device with composer 2.4 revealed few bugs which are fixed by this change. Fix: 143775556 Test: adb shell data/nativetest64/VtsHalGraphicsComposerV2_4TargetTest/VtsHalGraphicsComposerV2_4TargetTest Change-Id: Iafa1e85de60d99190d5d813f1d42924a62d94cc5 --- graphics/composer/2.4/utils/vts/Android.bp | 1 + .../composer/2.4/utils/vts/ComposerVts.cpp | 4 + .../utils/vts/GraphicsComposerCallback.cpp | 137 ++++++++ .../include/composer-vts/2.4/ComposerVts.h | 2 + .../2.4/GraphicsComposerCallback.h | 74 +++++ .../VtsHalGraphicsComposerV2_4TargetTest.cpp | 309 ++++++++++++------ 6 files changed, 431 insertions(+), 96 deletions(-) create mode 100644 graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp create mode 100644 graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp index b87a116865..673c15eb28 100644 --- a/graphics/composer/2.4/utils/vts/Android.bp +++ b/graphics/composer/2.4/utils/vts/Android.bp @@ -19,6 +19,7 @@ cc_library_static { defaults: ["hidl_defaults"], srcs: [ "ComposerVts.cpp", + "GraphicsComposerCallback.cpp", ], static_libs: [ "VtsHalHidlTargetTestBase", diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp index 5b06d6d3ff..8a9c00608d 100644 --- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp +++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp @@ -84,6 +84,10 @@ int32_t ComposerClient::getDisplayAttribute_2_4( return value; } +void ComposerClient::registerCallback_2_4(const sp& callback) { + mClient->registerCallback_2_4(callback); +} + Error ComposerClient::getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) { Error error = Error::NONE; mClient->getDisplayVsyncPeriod(display, [&](const auto& tmpError, const auto& tmpVsyncPeriod) { diff --git a/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp b/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp new file mode 100644 index 0000000000..c9366a8495 --- /dev/null +++ b/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp @@ -0,0 +1,137 @@ +/* + * 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. + */ + +#include + +namespace android::hardware::graphics::composer::V2_4::vts { + +void GraphicsComposerCallback::setVsyncAllowed(bool allowed) { + std::lock_guard lock(mMutex); + mVsyncAllowed = allowed; +} + +std::vector GraphicsComposerCallback::getDisplays() const { + std::lock_guard lock(mMutex); + return std::vector(mDisplays.begin(), mDisplays.end()); +} + +int32_t GraphicsComposerCallback::getInvalidHotplugCount() const { + std::lock_guard lock(mMutex); + return mInvalidHotplugCount; +} + +int32_t GraphicsComposerCallback::getInvalidRefreshCount() const { + std::lock_guard lock(mMutex); + return mInvalidRefreshCount; +} + +int32_t GraphicsComposerCallback::getInvalidVsyncCount() const { + std::lock_guard lock(mMutex); + return mInvalidVsyncCount; +} + +int32_t GraphicsComposerCallback::getInvalidVsync_2_4Count() const { + std::lock_guard lock(mMutex); + return mInvalidVsync_2_4Count; +} + +int32_t GraphicsComposerCallback::getInvalidVsyncPeriodChangeCount() const { + std::lock_guard lock(mMutex); + return mInvalidVsyncPeriodChangeCount; +} + +int32_t GraphicsComposerCallback::getInvalidSeamlessPossibleCount() const { + std::lock_guard lock(mMutex); + return mInvalidSeamlessPossibleCount; +} + +std::optional +GraphicsComposerCallback::takeLastVsyncPeriodChangeTimeline() { + std::lock_guard lock(mMutex); + + std::optional ret; + ret.swap(mTimeline); + + return ret; +} + +Return GraphicsComposerCallback::onHotplug(Display display, Connection connection) { + std::lock_guard lock(mMutex); + + if (connection == Connection::CONNECTED) { + if (!mDisplays.insert(display).second) { + mInvalidHotplugCount++; + } + } else if (connection == Connection::DISCONNECTED) { + if (!mDisplays.erase(display)) { + mInvalidHotplugCount++; + } + } + + return Void(); +} + +Return GraphicsComposerCallback::onRefresh(Display display) { + std::lock_guard lock(mMutex); + + if (mDisplays.count(display) == 0) { + mInvalidRefreshCount++; + } + + return Void(); +} + +Return GraphicsComposerCallback::onVsync(Display, int64_t) { + std::lock_guard lock(mMutex); + + // On composer 2.4, onVsync is not expected at all + mInvalidVsyncCount++; + + return Void(); +} + +Return GraphicsComposerCallback::onVsync_2_4(Display display, int64_t, VsyncPeriodNanos) { + std::lock_guard lock(mMutex); + + if (!mVsyncAllowed || mDisplays.count(display) == 0) { + mInvalidVsync_2_4Count++; + } + + return Void(); +} + +Return GraphicsComposerCallback::onVsyncPeriodTimingChanged( + Display display, const VsyncPeriodChangeTimeline& updatedTimeline) { + std::lock_guard lock(mMutex); + + if (mDisplays.count(display) == 0) { + mInvalidVsyncPeriodChangeCount++; + } + + mTimeline = updatedTimeline; + + return Void(); +} + +Return GraphicsComposerCallback::onSeamlessPossible(Display) { + std::lock_guard lock(mMutex); + + mInvalidSeamlessPossibleCount++; + + return Void(); +} + +} // namespace android::hardware::graphics::composer::V2_4::vts \ No newline at end of file diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h index b094bc8028..df75a48655 100644 --- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h @@ -77,6 +77,8 @@ class ComposerClient : public V2_3::vts::ComposerClient { int32_t getDisplayAttribute_2_4(Display display, Config config, IComposerClient::Attribute attribute); + void registerCallback_2_4(const sp& callback); + Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriods); Error setActiveConfigWithConstraints( diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h new file mode 100644 index 0000000000..f4e23ae1fd --- /dev/null +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h @@ -0,0 +1,74 @@ +/* + * 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 + +#include + +#include +#include + +namespace android::hardware::graphics::composer::V2_4::vts { + +using Display = V2_1::Display; + +// IComposerCallback to be installed with IComposerClient::registerCallback. +class GraphicsComposerCallback : public IComposerCallback { + public: + void setVsyncAllowed(bool allowed); + + std::vector getDisplays() const; + + int32_t getInvalidHotplugCount() const; + + int32_t getInvalidRefreshCount() const; + + int32_t getInvalidVsyncCount() const; + + int32_t getInvalidVsync_2_4Count() const; + + int32_t getInvalidVsyncPeriodChangeCount() const; + + int32_t getInvalidSeamlessPossibleCount() const; + + std::optional takeLastVsyncPeriodChangeTimeline(); + + private: + Return onHotplug(Display display, Connection connection) override; + Return onRefresh(Display display) override; + Return onVsync(Display display, int64_t) override; + Return onVsync_2_4(Display display, int64_t, VsyncPeriodNanos vsyncPeriodNanos) override; + Return onVsyncPeriodTimingChanged( + Display display, const VsyncPeriodChangeTimeline& updatedTimeline) override; + Return onSeamlessPossible(Display display) override; + + mutable std::mutex mMutex; + // the set of all currently connected displays + std::unordered_set mDisplays; + // true only when vsync is enabled + bool mVsyncAllowed = true; + + std::optional mTimeline; + + // track invalid callbacks + int32_t mInvalidHotplugCount = 0; + int32_t mInvalidRefreshCount = 0; + int32_t mInvalidVsyncCount = 0; + int32_t mInvalidVsync_2_4Count = 0; + int32_t mInvalidVsyncPeriodChangeCount = 0; + int32_t mInvalidSeamlessPossibleCount = 0; +}; + +} // namespace android::hardware::graphics::composer::V2_4::vts diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index 5a96d779a8..800ff08a17 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -22,13 +22,15 @@ #include #include #include -#include #include #include +#include #include #include #include #include +#include +#include #include namespace android { @@ -45,7 +47,9 @@ using common::V1_2::ColorMode; using common::V1_2::Dataspace; using common::V1_2::PixelFormat; using mapper::V2_0::IMapper; -using mapper::V2_0::vts::Gralloc; +using V2_1::Layer; +using V2_2::Transform; +using V2_2::vts::Gralloc; using ContentType = IComposerClient::ContentType; using DisplayCapability = IComposerClient::DisplayCapability; @@ -57,8 +61,8 @@ class GraphicsComposerHidlTest : public ::testing::TestWithParam { mComposer = std::make_unique(IComposer::getService(GetParam()))); ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient()); - mComposerCallback = new V2_1::vts::GraphicsComposerCallback; - mComposerClient->registerCallback(mComposerCallback); + mComposerCallback = new GraphicsComposerCallback; + mComposerClient->registerCallback_2_4(mComposerCallback); // assume the first display is primary and is never removed mPrimaryDisplay = waitForFirstDisplay(); @@ -80,6 +84,9 @@ class GraphicsComposerHidlTest : public ::testing::TestWithParam { EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount()); EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount()); EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidVsync_2_4Count()); + EXPECT_EQ(0, mComposerCallback->getInvalidVsyncPeriodChangeCount()); + EXPECT_EQ(0, mComposerCallback->getInvalidSeamlessPossibleCount()); } } @@ -117,8 +124,19 @@ class GraphicsComposerHidlTest : public ::testing::TestWithParam { void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } - void Test_setActiveConfigWithConstraints( - const IComposerClient::VsyncPeriodChangeConstraints& constraints); + void forEachTwoConfigs(Display display, std::function func) { + const auto displayConfigs = mComposerClient->getDisplayConfigs(display); + for (const Config config1 : displayConfigs) { + for (const Config config2 : displayConfigs) { + if (config1 != config2) { + func(config1, config2); + } + } + } + } + + // use the slot count usually set by SF + static constexpr uint32_t kBufferSlotCount = 64; void Test_setContentType(const ContentType& contentType, const char* contentTypeStr); void Test_setContentTypeForDisplay(const Display& display, @@ -127,7 +145,7 @@ class GraphicsComposerHidlTest : public ::testing::TestWithParam { std::unique_ptr mComposer; std::unique_ptr mComposerClient; - sp mComposerCallback; + sp mComposerCallback; // the first display and is assumed never to be removed Display mPrimaryDisplay; Display mInvalidDisplayId; @@ -156,6 +174,12 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique()); + const Config activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay); + mDisplayWidth = mComposerClient->getDisplayAttribute_2_4(mPrimaryDisplay, activeConfig, + IComposerClient::Attribute::WIDTH); + mDisplayHeight = mComposerClient->getDisplayAttribute_2_4( + mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT); + mWriter = std::make_unique(1024); mReader = std::make_unique(); } @@ -166,21 +190,27 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest { } const native_handle_t* allocate() { - IMapper::BufferDescriptorInfo info{}; - info.width = 64; - info.height = 64; - info.layerCount = 1; - info.format = static_cast(PixelFormat::RGBA_8888); - info.usage = - static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); - - return mGralloc->allocate(info); + return mGralloc->allocate( + /*width*/ 64, /*height*/ 64, /*layerCount*/ 1, + static_cast(PixelFormat::RGBA_8888), + static_cast(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN)); } void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); } + void Test_setActiveConfigWithConstraints( + const IComposerClient::VsyncPeriodChangeConstraints& constraints, bool refreshMiss); + + void sendRefreshFrame(const VsyncPeriodChangeTimeline&); + + void waitForVsyncPeriodChange(Display display, const VsyncPeriodChangeTimeline& timeline, + int64_t desiredTimeNanos, int64_t oldPeriodNanos, + int64_t newPeriodNanos); + std::unique_ptr mWriter; std::unique_ptr mReader; + int32_t mDisplayWidth; + int32_t mDisplayHeight; private: std::unique_ptr mGralloc; @@ -219,7 +249,12 @@ TEST_P(GraphicsComposerHidlTest, GetDisplayAttribute_2_4) { IComposerClient::Attribute::CONFIG_GROUP, }}; for (auto attribute : requiredAttributes) { - mComposerClient->getDisplayAttribute_2_4(mPrimaryDisplay, config, attribute); + mComposerClient->getRaw()->getDisplayAttribute_2_4( + mPrimaryDisplay, config, attribute, + [&](const auto& tmpError, const auto& value) { + EXPECT_EQ(Error::NONE, tmpError); + EXPECT_NE(-1, value); + }); } const std::array optionalAttributes = {{ @@ -244,20 +279,20 @@ TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod_BadDisplay) { TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod) { for (Display display : mComposerCallback->getDisplays()) { for (Config config : mComposerClient->getDisplayConfigs(display)) { - mComposerClient->setActiveConfig(display, config); - - VsyncPeriodNanos vsyncPeriodNanos; - VsyncPeriodNanos expectedvsyncPeriodNanos = mComposerClient->getDisplayAttribute_2_4( + VsyncPeriodNanos expectedVsyncPeriodNanos = mComposerClient->getDisplayAttribute_2_4( display, config, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); + + mComposerClient->setActiveConfig(display, config); + VsyncPeriodNanos vsyncPeriodNanos; int retryCount = 100; do { std::this_thread::sleep_for(10ms); EXPECT_EQ(Error::NONE, mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); --retryCount; - } while (retryCount > 0); + } while (vsyncPeriodNanos != expectedVsyncPeriodNanos && retryCount > 0); - EXPECT_EQ(vsyncPeriodNanos, expectedvsyncPeriodNanos); + EXPECT_EQ(vsyncPeriodNanos, expectedVsyncPeriodNanos); } } } @@ -295,101 +330,178 @@ TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_SeamlessNotAllow constraints.desiredTimeNanos = systemTime(); for (Display display : mComposerCallback->getDisplays()) { - for (Config config : mComposerClient->getDisplayConfigs(display)) { - int32_t configGroup = mComposerClient->getDisplayAttribute_2_4( - display, config, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP); - - for (Config otherConfig : mComposerClient->getDisplayConfigs(display)) { - int32_t otherConfigGroup = mComposerClient->getDisplayAttribute_2_4( - display, otherConfig, - IComposerClient::IComposerClient::Attribute::CONFIG_GROUP); - if (configGroup != otherConfigGroup) { - mComposerClient->setActiveConfig(display, config); - EXPECT_EQ(Error::SEAMLESS_NOT_ALLOWED, - mComposerClient->setActiveConfigWithConstraints( - display, otherConfig, constraints, &timeline)); - } + forEachTwoConfigs(display, [&](Config config1, Config config2) { + const auto configGroup1 = mComposerClient->getDisplayAttribute_2_4( + display, config1, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP); + const auto configGroup2 = mComposerClient->getDisplayAttribute_2_4( + display, config2, IComposerClient::IComposerClient::Attribute::CONFIG_GROUP); + if (configGroup1 != configGroup2) { + mComposerClient->setActiveConfig(display, config1); + EXPECT_EQ(Error::SEAMLESS_NOT_ALLOWED, + mComposerClient->setActiveConfigWithConstraints(display, config2, + constraints, &timeline)); } - } + }); } } -void GraphicsComposerHidlTest::Test_setActiveConfigWithConstraints( - const IComposerClient::VsyncPeriodChangeConstraints& constraints) { +static inline auto toTimePoint(nsecs_t time) { + return std::chrono::time_point(std::chrono::nanoseconds(time)); +} + +void GraphicsComposerHidlCommandTest::sendRefreshFrame(const VsyncPeriodChangeTimeline& timeline) { + // Refresh time should be before newVsyncAppliedTimeNanos + EXPECT_LT(timeline.refreshTimeNanos, timeline.newVsyncAppliedTimeNanos); + + std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos)); + + mWriter->selectDisplay(mPrimaryDisplay); + mComposerClient->setPowerMode(mPrimaryDisplay, V2_1::IComposerClient::PowerMode::ON); + mComposerClient->setColorMode_2_3(mPrimaryDisplay, ColorMode::NATIVE, + RenderIntent::COLORIMETRIC); + + auto handle = allocate(); + ASSERT_NE(nullptr, handle); + + IComposerClient::Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight}; + + Layer layer; + ASSERT_NO_FATAL_FAILURE( + layer = mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount)); + mWriter->selectLayer(layer); + mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE); + mWriter->setLayerDisplayFrame(displayFrame); + mWriter->setLayerPlaneAlpha(1); + mWriter->setLayerSourceCrop({0, 0, (float)mDisplayWidth, (float)mDisplayHeight}); + mWriter->setLayerTransform(static_cast(0)); + mWriter->setLayerVisibleRegion(std::vector(1, displayFrame)); + mWriter->setLayerZOrder(10); + mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE); + mWriter->setLayerSurfaceDamage(std::vector(1, displayFrame)); + mWriter->setLayerBuffer(0, handle, -1); + mWriter->setLayerDataspace(Dataspace::UNKNOWN); + + mWriter->validateDisplay(); + execute(); + if (mReader->mCompositionChanges.size() != 0) { + GTEST_SUCCEED() << "Composition change requested, skipping test"; + return; + } + + ASSERT_EQ(0, mReader->mErrors.size()); + mWriter->presentDisplay(); + execute(); + ASSERT_EQ(0, mReader->mErrors.size()); + + mWriter->selectLayer(layer); + auto handle2 = allocate(); + ASSERT_NE(nullptr, handle2); + mWriter->setLayerBuffer(0, handle2, -1); + mWriter->setLayerSurfaceDamage(std::vector(1, {0, 0, 10, 10})); + mWriter->presentDisplay(); + execute(); +} + +void GraphicsComposerHidlCommandTest::waitForVsyncPeriodChange( + Display display, const VsyncPeriodChangeTimeline& timeline, int64_t desiredTimeNanos, + int64_t oldPeriodNanos, int64_t newPeriodNanos) { + const auto CHANGE_DEADLINE = toTimePoint(timeline.newVsyncAppliedTimeNanos) + 100ms; + while (std::chrono::steady_clock::now() <= CHANGE_DEADLINE) { + VsyncPeriodNanos vsyncPeriodNanos; + EXPECT_EQ(Error::NONE, mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); + if (systemTime() <= desiredTimeNanos) { + EXPECT_EQ(vsyncPeriodNanos, oldPeriodNanos); + } else if (vsyncPeriodNanos == newPeriodNanos) { + break; + } + std::this_thread::sleep_for(std::chrono::nanoseconds(oldPeriodNanos)); + } +} + +void GraphicsComposerHidlCommandTest::Test_setActiveConfigWithConstraints( + const IComposerClient::VsyncPeriodChangeConstraints& constraints, bool refreshMiss) { VsyncPeriodChangeTimeline timeline = {}; for (Display display : mComposerCallback->getDisplays()) { - for (Config config : mComposerClient->getDisplayConfigs(display)) { - mComposerClient->setActiveConfig(display, config); + forEachTwoConfigs(display, [&](Config config1, Config config2) { + mComposerClient->setActiveConfig(display, config1); - int32_t configVsyncPeriod = mComposerClient->getDisplayAttribute_2_4( - display, config, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); - for (Config otherConfig : mComposerClient->getDisplayConfigs(display)) { - if (config == otherConfig) { - continue; - } + int32_t vsyncPeriod1 = mComposerClient->getDisplayAttribute_2_4( + display, config1, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); + int32_t vsyncPeriod2 = mComposerClient->getDisplayAttribute_2_4( + display, config2, IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); - int32_t otherVsyncPeriod = mComposerClient->getDisplayAttribute_2_4( - display, otherConfig, - IComposerClient::IComposerClient::Attribute::VSYNC_PERIOD); - - if (configVsyncPeriod == otherVsyncPeriod) { - continue; - } - - EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints( - display, otherConfig, constraints, &timeline)); - - if (timeline.refreshRequired) { - // TODO(b/143775556): handle this case; - continue; - } - - EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos); - - // Refresh rate should change within a reasonable time - constexpr nsecs_t kReasonableTimeForChange = 1'000'000'000; // 1 second - EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <= - kReasonableTimeForChange); - - while (systemTime() <= timeline.newVsyncAppliedTimeNanos) { - VsyncPeriodNanos vsyncPeriodNanos; - EXPECT_EQ(Error::NONE, - mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); - - if (systemTime() <= constraints.desiredTimeNanos) { - EXPECT_NE(vsyncPeriodNanos, otherVsyncPeriod); - } - - if (vsyncPeriodNanos == otherVsyncPeriod) { - break; - } - std::this_thread::sleep_for(10ms); - } - VsyncPeriodNanos vsyncPeriodNanos; - EXPECT_EQ(Error::NONE, - mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); - EXPECT_EQ(vsyncPeriodNanos, otherVsyncPeriod); + if (vsyncPeriod1 == vsyncPeriod2) { + return; // continue } - } + + EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigWithConstraints( + display, config2, constraints, &timeline)); + + EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos); + // Refresh rate should change within a reasonable time + constexpr std::chrono::nanoseconds kReasonableTimeForChange = 1s; // 1 second + EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <= + kReasonableTimeForChange.count()); + + if (timeline.refreshRequired) { + if (refreshMiss) { + // Miss the refresh frame on purpose to make sure the implementation sends a + // callback + std::this_thread::sleep_until(toTimePoint(timeline.refreshTimeNanos) + 100ms); + } + sendRefreshFrame(timeline); + } + waitForVsyncPeriodChange(display, timeline, constraints.desiredTimeNanos, vsyncPeriod1, + vsyncPeriod2); + + // At this point the refresh rate should have changed already, however in rare + // cases the implementation might have missed the deadline. In this case a new + // timeline should have been provided. + auto newTimelime = mComposerCallback->takeLastVsyncPeriodChangeTimeline(); + if (timeline.refreshRequired && refreshMiss) { + EXPECT_TRUE(newTimelime.has_value()); + } + + if (newTimelime.has_value()) { + if (timeline.refreshRequired) { + sendRefreshFrame(newTimelime.value()); + } + waitForVsyncPeriodChange(display, newTimelime.value(), constraints.desiredTimeNanos, + vsyncPeriod1, vsyncPeriod2); + } + + VsyncPeriodNanos vsyncPeriodNanos; + EXPECT_EQ(Error::NONE, + mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos)); + EXPECT_EQ(vsyncPeriodNanos, vsyncPeriod2); + }); } } -TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints) { +TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints) { IComposerClient::VsyncPeriodChangeConstraints constraints; constraints.seamlessRequired = false; constraints.desiredTimeNanos = systemTime(); - Test_setActiveConfigWithConstraints(constraints); + Test_setActiveConfigWithConstraints(constraints, false); } -TEST_P(GraphicsComposerHidlTest, setActiveConfigWithConstraints_delayed) { +TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_Delayed) { IComposerClient::VsyncPeriodChangeConstraints constraints; - constexpr auto kDelayForChange = 300ms; + constexpr nsecs_t kDelayForChange = 300'000'000; // 300ms constraints.seamlessRequired = false; - constraints.desiredTimeNanos = systemTime() + kDelayForChange.count(); - Test_setActiveConfigWithConstraints(constraints); + constraints.desiredTimeNanos = systemTime() + kDelayForChange; + Test_setActiveConfigWithConstraints(constraints, false); +} + +TEST_P(GraphicsComposerHidlCommandTest, setActiveConfigWithConstraints_MissRefresh) { + IComposerClient::VsyncPeriodChangeConstraints constraints; + + constraints.seamlessRequired = false; + constraints.desiredTimeNanos = systemTime(); + Test_setActiveConfigWithConstraints(constraints, true); } TEST_P(GraphicsComposerHidlTest, setAutoLowLatencyModeBadDisplay) { @@ -508,6 +620,11 @@ INSTANTIATE_TEST_SUITE_P( testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), android::hardware::PrintInstanceNameToString); +INSTANTIATE_TEST_SUITE_P( + PerInstance, GraphicsComposerHidlCommandTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)), + android::hardware::PrintInstanceNameToString); + } // namespace } // namespace vts } // namespace V2_4