From 9dd8c4882b79c60e0bcf769bba6505e147b604f8 Mon Sep 17 00:00:00 2001 From: ramindani Date: Tue, 21 Feb 2023 18:07:56 -0800 Subject: [PATCH] VTS for the Refresh rate callback debug enabled BUG: 202734676 Test: atest VtsHalGraphicsComposer3_TargetTest with the patch of Ibc80d66eae6b21c3cf84d35fa819e97ccc509ede Change-Id: I02bdf061420fe12ef4548008d66bb73e8cd416e8 --- .../aidl/vts/GraphicsComposerCallback.cpp | 33 ++- .../aidl/vts/GraphicsComposerCallback.h | 11 + .../composer/aidl/vts/VtsComposerClient.cpp | 35 +++- .../composer/aidl/vts/VtsComposerClient.h | 17 +- .../VtsHalGraphicsComposer3_TargetTest.cpp | 198 +++++++++++++++++- 5 files changed, 279 insertions(+), 15 deletions(-) diff --git a/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp b/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp index 4fb5d01249..7b3a2b431f 100644 --- a/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp +++ b/graphics/composer/aidl/vts/GraphicsComposerCallback.cpp @@ -29,6 +29,11 @@ void GraphicsComposerCallback::setVsyncAllowed(bool allowed) { mVsyncAllowed = allowed; } +void GraphicsComposerCallback::setRefreshRateChangedDebugDataEnabledCallbackAllowed(bool allowed) { + std::scoped_lock lock(mMutex); + mRefreshRateChangedDebugDataEnabledCallbackAllowed = allowed; +} + std::vector GraphicsComposerCallback::getDisplays() const { std::scoped_lock lock(mMutex); return mDisplays; @@ -79,6 +84,21 @@ GraphicsComposerCallback::takeLastVsyncPeriodChangeTimeline() { return ret; } +std::vector +GraphicsComposerCallback::takeListOfRefreshRateChangedDebugData() { + std::scoped_lock lock(mMutex); + + std::vector ret; + ret.swap(mRefreshRateChangedDebugData); + + return ret; +} + +int32_t GraphicsComposerCallback::getInvalidRefreshRateDebugEnabledCallbackCount() const { + std::scoped_lock lock(mMutex); + return mInvalidRefreshRateDebugEnabledCallbackCount; +} + ::ndk::ScopedAStatus GraphicsComposerCallback::onHotplug(int64_t in_display, bool in_connected) { std::scoped_lock lock(mMutex); @@ -125,9 +145,16 @@ GraphicsComposerCallback::takeLastVsyncPeriodChangeTimeline() { } ::ndk::ScopedAStatus GraphicsComposerCallback::onRefreshRateChangedDebug( - const RefreshRateChangedDebugData&) { - // TODO(b/202734676) Add implementation for Vts tests - return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + const RefreshRateChangedDebugData& data) { + std::scoped_lock lock(mMutex); + + const auto it = std::find(mDisplays.begin(), mDisplays.end(), data.display); + if (mRefreshRateChangedDebugDataEnabledCallbackAllowed && it != mDisplays.end()) { + mRefreshRateChangedDebugData.push_back(data); + } else { + mInvalidRefreshRateDebugEnabledCallbackCount++; + } + return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus GraphicsComposerCallback::onVsyncPeriodTimingChanged( diff --git a/graphics/composer/aidl/vts/GraphicsComposerCallback.h b/graphics/composer/aidl/vts/GraphicsComposerCallback.h index 9c3bc70f73..13e992a4e1 100644 --- a/graphics/composer/aidl/vts/GraphicsComposerCallback.h +++ b/graphics/composer/aidl/vts/GraphicsComposerCallback.h @@ -26,6 +26,8 @@ class GraphicsComposerCallback : public BnComposerCallback { public: void setVsyncAllowed(bool allowed); + void setRefreshRateChangedDebugDataEnabledCallbackAllowed(bool allowed); + std::vector getDisplays() const; int32_t getInvalidHotplugCount() const; @@ -44,6 +46,10 @@ class GraphicsComposerCallback : public BnComposerCallback { std::optional takeLastVsyncPeriodChangeTimeline(); + std::vector takeListOfRefreshRateChangedDebugData(); + + int32_t getInvalidRefreshRateDebugEnabledCallbackCount() const; + private: virtual ::ndk::ScopedAStatus onHotplug(int64_t in_display, bool in_connected) override; virtual ::ndk::ScopedAStatus onRefresh(int64_t in_display) override; @@ -63,9 +69,13 @@ class GraphicsComposerCallback : public BnComposerCallback { std::vector mDisplays GUARDED_BY(mMutex); // true only when vsync is enabled bool mVsyncAllowed GUARDED_BY(mMutex) = true; + // true only when RefreshRateChangedCallbackDebugEnabled is set to true. + bool mRefreshRateChangedDebugDataEnabledCallbackAllowed GUARDED_BY(mMutex) = false; std::optional mTimeline GUARDED_BY(mMutex); + std::vector mRefreshRateChangedDebugData GUARDED_BY(mMutex); + int32_t mVsyncIdleCount GUARDED_BY(mMutex) = 0; int64_t mVsyncIdleTime GUARDED_BY(mMutex) = 0; @@ -75,6 +85,7 @@ class GraphicsComposerCallback : public BnComposerCallback { int32_t mInvalidVsyncCount GUARDED_BY(mMutex) = 0; int32_t mInvalidVsyncPeriodChangeCount GUARDED_BY(mMutex) = 0; int32_t mInvalidSeamlessPossibleCount GUARDED_BY(mMutex) = 0; + int32_t mInvalidRefreshRateDebugEnabledCallbackCount GUARDED_BY(mMutex) = 0; }; } // namespace aidl::android::hardware::graphics::composer3::vts diff --git a/graphics/composer/aidl/vts/VtsComposerClient.cpp b/graphics/composer/aidl/vts/VtsComposerClient.cpp index e03ef254c8..25b0ca0a17 100644 --- a/graphics/composer/aidl/vts/VtsComposerClient.cpp +++ b/graphics/composer/aidl/vts/VtsComposerClient.cpp @@ -119,6 +119,24 @@ ScopedAStatus VtsComposerClient::setActiveConfig(VtsDisplay* vtsDisplay, int32_t return updateDisplayProperties(vtsDisplay, config); } +ScopedAStatus VtsComposerClient::setPeakRefreshRateConfig(VtsDisplay* vtsDisplay) { + const auto displayId = vtsDisplay->getDisplayId(); + auto [activeStatus, activeConfig] = getActiveConfig(displayId); + EXPECT_TRUE(activeStatus.isOk()); + auto peakDisplayConfig = vtsDisplay->getDisplayConfig(activeConfig); + auto peakConfig = activeConfig; + + const auto displayConfigs = vtsDisplay->getDisplayConfigs(); + for (const auto [config, displayConfig] : displayConfigs) { + if (displayConfig.configGroup == peakDisplayConfig.configGroup && + displayConfig.vsyncPeriod < peakDisplayConfig.vsyncPeriod) { + peakDisplayConfig = displayConfig; + peakConfig = config; + } + } + return setActiveConfig(vtsDisplay, peakConfig); +} + std::pair VtsComposerClient::getDisplayAttribute( int64_t display, int32_t config, DisplayAttribute displayAttribute) { int32_t outDisplayAttribute; @@ -375,10 +393,15 @@ int64_t VtsComposerClient::getVsyncIdleTime() { return mComposerCallback->getVsyncIdleTime(); } -ndk::ScopedAStatus VtsComposerClient::setRefreshRateChangedCallbackDebugEnabled( - int64_t /* display */, bool /* enabled */) { - // TODO(b/202734676) Add implementation for VTS tests - return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); +ndk::ScopedAStatus VtsComposerClient::setRefreshRateChangedCallbackDebugEnabled(int64_t display, + bool enabled) { + mComposerCallback->setRefreshRateChangedDebugDataEnabledCallbackAllowed(enabled); + return mComposerClient->setRefreshRateChangedCallbackDebugEnabled(display, enabled); +} + +std::vector +VtsComposerClient::takeListOfRefreshRateChangedDebugData() { + return mComposerCallback->takeListOfRefreshRateChangedDebugData(); } int64_t VtsComposerClient::getInvalidDisplayId() { @@ -545,6 +568,10 @@ bool VtsComposerClient::verifyComposerCallbackParams() { ALOGE("Invalid seamless possible count"); isValid = false; } + if (mComposerCallback->getInvalidRefreshRateDebugEnabledCallbackCount() != 0) { + ALOGE("Invalid refresh rate debug enabled callback count"); + isValid = false; + } } return isValid; } diff --git a/graphics/composer/aidl/vts/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h index 81a62b372e..ea3318c2ce 100644 --- a/graphics/composer/aidl/vts/VtsComposerClient.h +++ b/graphics/composer/aidl/vts/VtsComposerClient.h @@ -77,6 +77,8 @@ class VtsComposerClient { ScopedAStatus setActiveConfig(VtsDisplay* vtsDisplay, int32_t config); + ScopedAStatus setPeakRefreshRateConfig(VtsDisplay* vtsDisplay); + std::pair getDisplayAttribute(int64_t display, int32_t config, DisplayAttribute displayAttribute); @@ -183,6 +185,10 @@ class VtsComposerClient { std::pair getOverlaySupport(); + ndk::ScopedAStatus setRefreshRateChangedCallbackDebugEnabled(int64_t display, bool enabled); + + std::vector takeListOfRefreshRateChangedDebugData(); + private: ScopedAStatus addDisplayConfig(VtsDisplay* vtsDisplay, int32_t config); ScopedAStatus updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config); @@ -197,9 +203,6 @@ class VtsComposerClient { bool verifyComposerCallbackParams(); - ndk::ScopedAStatus setRefreshRateChangedCallbackDebugEnabled(int64_t /* display */, - bool /* enabled */); - // Keep track of displays and layers. When a test fails/ends, // the VtsComposerClient::tearDown should be called from the // test tearDown to clean up the resources for the test. @@ -245,15 +248,17 @@ class VtsDisplay { }; void addDisplayConfig(int32_t config, DisplayConfig displayConfig) { - displayConfigs.insert({config, displayConfig}); + mDisplayConfigs.insert({config, displayConfig}); } - DisplayConfig getDisplayConfig(int32_t config) { return displayConfigs.find(config)->second; } + DisplayConfig getDisplayConfig(int32_t config) { return mDisplayConfigs.find(config)->second; } + + std::unordered_map getDisplayConfigs() { return mDisplayConfigs; } private: int64_t mDisplayId; int32_t mDisplayWidth; int32_t mDisplayHeight; - std::unordered_map displayConfigs; + std::unordered_map mDisplayConfigs; }; } // namespace aidl::android::hardware::graphics::composer3::vts diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp index 4974e71636..37576b958c 100644 --- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp +++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp @@ -1217,6 +1217,14 @@ class GraphicsComposerAidlCommandTest : public GraphicsComposerAidlTest { } } + bool checkIfCallbackRefreshRateChangedDebugEnabledReceived( + std::function filter) { + const auto list = mComposerClient->takeListOfRefreshRateChangedDebugData(); + return std::any_of(list.begin(), list.end(), [&](auto refreshRateChangedDebugData) { + return filter(refreshRateChangedDebugData); + }); + } + sp allocate(::android::PixelFormat pixelFormat) { return sp::make( static_cast(getPrimaryDisplay().getDisplayWidth()), @@ -1316,7 +1324,7 @@ class GraphicsComposerAidlCommandTest : public GraphicsComposerAidlTest { return vsyncPeriod; } - int64_t createOnScreenLayer() { + int64_t createOnScreenLayer(Composition composition = Composition::DEVICE) { const auto& [status, layer] = mComposerClient->createLayer(getPrimaryDisplayId(), kBufferSlotCount); EXPECT_TRUE(status.isOk()); @@ -1324,12 +1332,25 @@ class GraphicsComposerAidlCommandTest : public GraphicsComposerAidlTest { getPrimaryDisplay().getDisplayHeight()}; FRect cropRect{0, 0, (float)getPrimaryDisplay().getDisplayWidth(), (float)getPrimaryDisplay().getDisplayHeight()}; - configureLayer(getPrimaryDisplay(), layer, Composition::DEVICE, displayFrame, cropRect); + configureLayer(getPrimaryDisplay(), layer, composition, displayFrame, cropRect); auto& writer = getWriter(getPrimaryDisplayId()); writer.setLayerDataspace(getPrimaryDisplayId(), layer, common::Dataspace::UNKNOWN); return layer; } + void sendBufferUpdate(int64_t layer) { + const auto buffer = allocate(::android::PIXEL_FORMAT_RGBA_8888); + ASSERT_NE(nullptr, buffer->handle); + + auto& writer = getWriter(getPrimaryDisplayId()); + writer.setLayerBuffer(getPrimaryDisplayId(), layer, /*slot*/ 0, buffer->handle, + /*acquireFence*/ -1); + + const sp<::android::Fence> presentFence = + presentAndGetFence(ComposerClientWriter::kNoTimestamp); + presentFence->waitForever(LOG_TAG); + } + bool hasDisplayCapability(int64_t display, DisplayCapability cap) { const auto& [status, capabilities] = mComposerClient->getDisplayCapabilities(display); EXPECT_TRUE(status.isOk()); @@ -2268,6 +2289,179 @@ TEST_P(GraphicsComposerAidlCommandTest, SetIdleTimerEnabled_Timeout_2) { EXPECT_TRUE(mComposerClient->setPowerMode(getPrimaryDisplayId(), PowerMode::OFF).isOk()); } +TEST_P(GraphicsComposerAidlCommandTest, SetRefreshRateChangedCallbackDebug_Unsupported) { + if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) { + auto status = mComposerClient->setRefreshRateChangedCallbackDebugEnabled( + getPrimaryDisplayId(), /*enabled*/ true); + EXPECT_FALSE(status.isOk()); + EXPECT_NO_FATAL_FAILURE( + assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED)); + + status = mComposerClient->setRefreshRateChangedCallbackDebugEnabled(getPrimaryDisplayId(), + /*enabled*/ false); + EXPECT_FALSE(status.isOk()); + EXPECT_NO_FATAL_FAILURE( + assertServiceSpecificError(status, IComposerClient::EX_UNSUPPORTED)); + } +} + +TEST_P(GraphicsComposerAidlCommandTest, SetRefreshRateChangedCallbackDebug_Enabled) { + if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) { + GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is not supported"; + return; + } + + const auto displayId = getPrimaryDisplayId(); + EXPECT_TRUE(mComposerClient->setPowerMode(displayId, PowerMode::ON).isOk()); + // Enable the callback + ASSERT_TRUE(mComposerClient + ->setRefreshRateChangedCallbackDebugEnabled(displayId, + /*enabled*/ true) + .isOk()); + std::this_thread::sleep_for(100ms); + + const bool isCallbackReceived = checkIfCallbackRefreshRateChangedDebugEnabledReceived( + [&](auto refreshRateChangedDebugData) { + return displayId == refreshRateChangedDebugData.display; + }); + + // Check that we immediately got a callback + EXPECT_TRUE(isCallbackReceived); + + ASSERT_TRUE(mComposerClient + ->setRefreshRateChangedCallbackDebugEnabled(displayId, + /*enabled*/ false) + .isOk()); +} + +TEST_P(GraphicsComposerAidlCommandTest, + SetRefreshRateChangedCallbackDebugEnabled_noCallbackWhenIdle) { + if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) { + GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is not supported"; + return; + } + + auto display = getEditablePrimaryDisplay(); + const auto displayId = display.getDisplayId(); + + if (!hasDisplayCapability(displayId, DisplayCapability::DISPLAY_IDLE_TIMER)) { + GTEST_SUCCEED() << "DisplayCapability::DISPLAY_IDLE_TIMER is not supported"; + return; + } + + EXPECT_TRUE(mComposerClient->setPowerMode(displayId, PowerMode::ON).isOk()); + EXPECT_TRUE(mComposerClient->setPeakRefreshRateConfig(&display).isOk()); + + ASSERT_TRUE(mComposerClient->setIdleTimerEnabled(displayId, /*timeoutMs*/ 500).isOk()); + // Enable the callback + ASSERT_TRUE(mComposerClient + ->setRefreshRateChangedCallbackDebugEnabled(displayId, + /*enabled*/ true) + .isOk()); + + const bool isCallbackReceived = checkIfCallbackRefreshRateChangedDebugEnabledReceived( + [&](auto refreshRateChangedDebugData) { + return displayId == refreshRateChangedDebugData.display; + }); + + int retryCount = 3; + do { + // Wait for 1s so that we enter the idle state + std::this_thread::sleep_for(1s); + if (!isCallbackReceived) { + // DID NOT receive a callback, we are in the idle state. + break; + } + } while (--retryCount > 0); + + if (retryCount == 0) { + GTEST_SUCCEED() << "Unable to enter the idle mode"; + return; + } + + // Send the REFRESH_RATE_INDICATOR update + ASSERT_NO_FATAL_FAILURE( + sendBufferUpdate(createOnScreenLayer(Composition::REFRESH_RATE_INDICATOR))); + std::this_thread::sleep_for(1s); + EXPECT_FALSE(isCallbackReceived) + << "A callback should not be received for REFRESH_RATE_INDICATOR"; + + EXPECT_TRUE(mComposerClient + ->setRefreshRateChangedCallbackDebugEnabled(displayId, + /*enabled*/ false) + .isOk()); +} + +TEST_P(GraphicsComposerAidlCommandTest, + SetRefreshRateChangedCallbackDebugEnabled_SetActiveConfigWithConstraints) { + if (!hasCapability(Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG)) { + GTEST_SUCCEED() << "Capability::REFRESH_RATE_CHANGED_CALLBACK_DEBUG is not supported"; + return; + } + + VsyncPeriodChangeConstraints constraints; + constraints.seamlessRequired = false; + constraints.desiredTimeNanos = systemTime(); + + for (VtsDisplay& display : mDisplays) { + const auto displayId = display.getDisplayId(); + EXPECT_TRUE(mComposerClient->setPowerMode(displayId, PowerMode::ON).isOk()); + + // Enable the callback + ASSERT_TRUE(mComposerClient + ->setRefreshRateChangedCallbackDebugEnabled(displayId, /*enabled*/ true) + .isOk()); + + forEachTwoConfigs(displayId, [&](int32_t config1, int32_t config2) { + const int32_t vsyncPeriod1 = display.getDisplayConfig(config1).vsyncPeriod; + const int32_t vsyncPeriod2 = display.getDisplayConfig(config2).vsyncPeriod; + + if (vsyncPeriod1 == vsyncPeriod2) { + return; // continue + } + + EXPECT_TRUE(mComposerClient->setActiveConfig(&display, config1).isOk()); + sendRefreshFrame(display, nullptr); + + const auto& [status, timeline] = + mComposerClient->setActiveConfigWithConstraints(&display, config2, constraints); + EXPECT_TRUE(status.isOk()); + + if (timeline.refreshRequired) { + sendRefreshFrame(display, &timeline); + } + + const auto isCallbackReceived = checkIfCallbackRefreshRateChangedDebugEnabledReceived( + [&](auto refreshRateChangedDebugData) { + constexpr int kVsyncThreshold = 1000; + return displayId == refreshRateChangedDebugData.display && + std::abs(vsyncPeriod2 - + refreshRateChangedDebugData.vsyncPeriodNanos) <= + kVsyncThreshold; + }); + + int retryCount = 3; + do { + std::this_thread::sleep_for(100ms); + if (isCallbackReceived) { + GTEST_SUCCEED() << "Received a callback successfully"; + break; + } + } while (--retryCount > 0); + + if (retryCount == 0) { + GTEST_FAIL() << "failed to get a callback for the display " << displayId + << " with config " << config2; + } + }); + + EXPECT_TRUE( + mComposerClient + ->setRefreshRateChangedCallbackDebugEnabled(displayId, /*enabled*/ false) + .isOk()); + } +} + /* * Test that no two display configs are exactly the same. */