Merge "VTS for the Refresh rate callback debug enabled" into udc-dev

This commit is contained in:
Ram Indani 2023-03-03 05:24:09 +00:00 committed by Android (Google) Code Review
commit 9a7999d1eb
5 changed files with 279 additions and 15 deletions

View file

@ -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<int64_t> GraphicsComposerCallback::getDisplays() const {
std::scoped_lock lock(mMutex);
return mDisplays;
@ -79,6 +84,21 @@ GraphicsComposerCallback::takeLastVsyncPeriodChangeTimeline() {
return ret;
}
std::vector<RefreshRateChangedDebugData>
GraphicsComposerCallback::takeListOfRefreshRateChangedDebugData() {
std::scoped_lock lock(mMutex);
std::vector<RefreshRateChangedDebugData> 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(

View file

@ -26,6 +26,8 @@ class GraphicsComposerCallback : public BnComposerCallback {
public:
void setVsyncAllowed(bool allowed);
void setRefreshRateChangedDebugDataEnabledCallbackAllowed(bool allowed);
std::vector<int64_t> getDisplays() const;
int32_t getInvalidHotplugCount() const;
@ -44,6 +46,10 @@ class GraphicsComposerCallback : public BnComposerCallback {
std::optional<VsyncPeriodChangeTimeline> takeLastVsyncPeriodChangeTimeline();
std::vector<RefreshRateChangedDebugData> 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<int64_t> 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<VsyncPeriodChangeTimeline> mTimeline GUARDED_BY(mMutex);
std::vector<RefreshRateChangedDebugData> 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

View file

@ -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<ScopedAStatus, int32_t> 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<RefreshRateChangedDebugData>
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;
}

View file

@ -77,6 +77,8 @@ class VtsComposerClient {
ScopedAStatus setActiveConfig(VtsDisplay* vtsDisplay, int32_t config);
ScopedAStatus setPeakRefreshRateConfig(VtsDisplay* vtsDisplay);
std::pair<ScopedAStatus, int32_t> getDisplayAttribute(int64_t display, int32_t config,
DisplayAttribute displayAttribute);
@ -183,6 +185,10 @@ class VtsComposerClient {
std::pair<ScopedAStatus, OverlayProperties> getOverlaySupport();
ndk::ScopedAStatus setRefreshRateChangedCallbackDebugEnabled(int64_t display, bool enabled);
std::vector<RefreshRateChangedDebugData> 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<int32_t, DisplayConfig> getDisplayConfigs() { return mDisplayConfigs; }
private:
int64_t mDisplayId;
int32_t mDisplayWidth;
int32_t mDisplayHeight;
std::unordered_map<int32_t, DisplayConfig> displayConfigs;
std::unordered_map<int32_t, DisplayConfig> mDisplayConfigs;
};
} // namespace aidl::android::hardware::graphics::composer3::vts

View file

@ -1217,6 +1217,14 @@ class GraphicsComposerAidlCommandTest : public GraphicsComposerAidlTest {
}
}
bool checkIfCallbackRefreshRateChangedDebugEnabledReceived(
std::function<bool(RefreshRateChangedDebugData)> filter) {
const auto list = mComposerClient->takeListOfRefreshRateChangedDebugData();
return std::any_of(list.begin(), list.end(), [&](auto refreshRateChangedDebugData) {
return filter(refreshRateChangedDebugData);
});
}
sp<GraphicBuffer> allocate(::android::PixelFormat pixelFormat) {
return sp<GraphicBuffer>::make(
static_cast<uint32_t>(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.
*/