Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a7999d1 authored by Ram Indani's avatar Ram Indani Committed by Android (Google) Code Review
Browse files

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

parents ad7aa390 9dd8c488
Loading
Loading
Loading
Loading
+30 −3
Original line number Diff line number Diff line
@@ -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(
+11 −0
Original line number Diff line number Diff line
@@ -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
+31 −4
Original line number Diff line number Diff line
@@ -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;
}
+11 −6
Original line number Diff line number Diff line
@@ -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
+196 −2
Original line number Diff line number Diff line
@@ -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.
 */