composer 2.4: add api to control vsync period
Add new functions to improve vsync period switching by the platform:
- Adding a list of supported vsync periods to Config to avoid the need to expose
separate Configs for each vsync period.
- Adding an API to set the vsync period with timeline constraints to allow better
synchronization with vsync period change.
- Extending onVsync() callback to provide the current vsync period.
Test: rev up composer to 2.4 and test refresh rate switching
Bug: 141329414
Change-Id: I1a6f395d9634edadc68649d02f624f00173ec519
diff --git a/graphics/composer/2.4/Android.bp b/graphics/composer/2.4/Android.bp
index 0e1bc09..5f700be 100644
--- a/graphics/composer/2.4/Android.bp
+++ b/graphics/composer/2.4/Android.bp
@@ -7,7 +7,9 @@
enabled: true,
},
srcs: [
+ "types.hal",
"IComposer.hal",
+ "IComposerCallback.hal",
"IComposerClient.hal",
],
interfaces: [
diff --git a/graphics/composer/2.4/IComposerCallback.hal b/graphics/composer/2.4/IComposerCallback.hal
new file mode 100644
index 0000000..5c3f8bd
--- /dev/null
+++ b/graphics/composer/2.4/IComposerCallback.hal
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019 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.
+ */
+
+package android.hardware.graphics.composer@2.4;
+
+import @2.1::Display;
+import @2.1::IComposerCallback;
+
+interface IComposerCallback extends @2.1::IComposerCallback {
+ /**
+ * Notifies the client that a vsync event has occurred. This callback must
+ * only be triggered when vsync is enabled for this display (through
+ * setVsyncEnabled).
+ *
+ * @param display is the display which has received a vsync event
+ * @param timestamp is the CLOCK_MONOTONIC time at which the vsync event
+ * occurred, in nanoseconds.
+ * @param vsyncPeriodNanos is the display vsync period in nanoseconds i.e. the next onVsync_2_4
+ * is expected to be called vsyncPeriodNanos nanoseconds after this call.
+ */
+ oneway onVsync_2_4(Display display, int64_t timestamp, VsyncPeriodNanos vsyncPeriodNanos);
+};
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
index 60445f5..c2102d5 100644
--- a/graphics/composer/2.4/IComposerClient.hal
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -16,6 +16,8 @@
package android.hardware.graphics.composer@2.4;
+import IComposerCallback;
+import @2.1::Config;
import @2.1::Display;
import @2.1::Error;
import @2.3::IComposerClient;
@@ -50,6 +52,32 @@
};
/**
+ * Constraints for changing vsync period.
+ */
+ struct VsyncPeriodChangeConstraints {
+ /**
+ * Time in CLOCK_MONOTONIC after which the vsync period may change
+ * (i.e., the vsync period must not change before this time).
+ */
+ int64_t desiredTimeNanos;
+ /**
+ * If true, requires that the vsync period change must happen seamlessly without
+ * a noticeable visual artifact.
+ */
+ bool seamlessRequired;
+ };
+
+ /**
+ * Provides a IComposerCallback object for the device to call.
+ *
+ * This function must be called only once.
+ *
+ * @param callback is the IComposerCallback object.
+ */
+ @entry
+ registerCallback_2_4(IComposerCallback callback);
+
+ /**
* Provides a list of supported capabilities (as described in the
* definition of DisplayCapability above). This list must not change after
* initialization.
@@ -69,4 +97,63 @@
* @return type is the connection type of the display.
*/
getDisplayConnectionType(Display display) generates (Error error, DisplayConnectionType type);
+
+ /**
+ * Provides a list of the vsync periods supported by the display in the given configuration
+ *
+ * @param display is the display for which the vsync periods are queried.
+ * @param config is the display configuration for which the vsync periods are queried.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_CONFIG when an invalid config handle was passed in.
+ * @return supportedVsyncPeriods is a list of supported vsync periods.
+ */
+ getSupportedDisplayVsyncPeriods(Display display, Config config)
+ generates (Error error, vec<VsyncPeriodNanos> supportedVsyncPeriods);
+
+ /**
+ * Retrieves which vsync period the display is currently using.
+ *
+ * If no display configuration is currently active, this function must
+ * return BAD_CONFIG. If the vsync period is about to change due to a
+ * setActiveConfigAndVsyncPeriod call, this function must return the current vsync period
+ * until the change takes place.
+ *
+ * @param display is the display for which the vsync period is queried.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_CONFIG when no configuration is currently active.
+ * @return vsyncPeriodNanos is the current vsync period of the display.
+ */
+ getDisplayVsyncPeriod(Display display)
+ generates (Error error, VsyncPeriodNanos vsyncPeriodNanos);
+
+ /**
+ * Sets the active configuration and the refresh rate for this display.
+ * If the config is the same as the current config, only the vsync period shall change.
+ * Upon returning, the given display configuration, except vsync period, must be active and
+ * remain so until either this function is called again or the display is disconnected.
+ * When the display starts to refresh at the new vsync period, onVsync_2_4 callback must be
+ * called with the new vsync period.
+ *
+ * @param display is the display for which the active config is set.
+ * @param config is the new display configuration.
+ * @param vsyncPeriodNanos is the new display vsync period.
+ * @param vsyncPeriodChangeConstraints are the constraints required for changing vsync period.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * BAD_CONFIG when the configuration handle passed in is not valid
+ * for this display.
+ * BAD_VSYNC_PERIOD when an invalid vsync period is passed in.
+ * SEAMLESS_NOT_POSSIBLE when seamlessRequired was true but the display cannot achieve
+ * the vsync period change without a noticeable visual artifact.
+ * @return newVsyncAppliedTime is the time in CLOCK_MONOTONIC when the new display will start to
+ * refresh at the new vsync period.
+ */
+ setActiveConfigAndVsyncPeriod(Display display, Config config,
+ VsyncPeriodNanos vsyncPeriodNanos,
+ VsyncPeriodChangeConstraints vsyncPeriodChangeConstraints)
+ generates (Error error, int64_t newVsyncAppliedTime);
};
diff --git a/graphics/composer/2.4/types.hal b/graphics/composer/2.4/types.hal
new file mode 100644
index 0000000..b45d7a6
--- /dev/null
+++ b/graphics/composer/2.4/types.hal
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 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.
+ */
+
+package android.hardware.graphics.composer@2.4;
+
+import @2.1::Error;
+
+enum Error : @2.1::Error {
+ /**
+ * Invalid vsync period
+ */
+ BAD_VSYNC_PERIOD = 9,
+ /**
+ * Seamless requirements cannot be met
+ */
+ SEAMLESS_NOT_POSSIBLE = 10,
+};
+
+typedef uint32_t VsyncPeriodNanos;
diff --git a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
index 6b64c16..cb391be 100644
--- a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
+++ b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
@@ -34,7 +34,7 @@
namespace V2_4 {
using android::hardware::MessageQueue;
-using android::hardware::graphics::composer::V2_1::Error;
+using android::hardware::graphics::composer::V2_4::Error;
using android::hardware::graphics::composer::V2_4::IComposerClient;
// This class helps build a command queue. Note that all sizes/lengths are in
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
index c810186..ddf209b 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
@@ -20,8 +20,10 @@
#warning "ComposerClient.h included without LOG_TAG"
#endif
+#include <android/hardware/graphics/composer/2.4/IComposerCallback.h>
#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
#include <composer-hal/2.4/ComposerHal.h>
+#include <composer-resources/2.1/ComposerResources.h>
namespace android {
namespace hardware {
@@ -38,6 +40,54 @@
public:
ComposerClientImpl(Hal* hal) : BaseType2_3(hal) {}
+ ~ComposerClientImpl() override { mHal->unregisterEventCallback_2_4(); }
+
+ class HalEventCallback : public Hal::EventCallback_2_4 {
+ public:
+ HalEventCallback(const sp<IComposerCallback> callback,
+ V2_1::hal::ComposerResources* resources)
+ : mCallback(callback), mResources(resources) {}
+
+ void onHotplug(Display display, IComposerCallback::Connection connected) override {
+ if (connected == IComposerCallback::Connection::CONNECTED) {
+ mResources->addPhysicalDisplay(display);
+ } else if (connected == IComposerCallback::Connection::DISCONNECTED) {
+ mResources->removeDisplay(display);
+ }
+
+ auto ret = mCallback->onHotplug(display, connected);
+ ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s", ret.description().c_str());
+ }
+
+ void onRefresh(Display display) override {
+ mResources->setDisplayMustValidateState(display, true);
+ auto ret = mCallback->onRefresh(display);
+ ALOGE_IF(!ret.isOk(), "failed to send onRefresh: %s", ret.description().c_str());
+ }
+
+ void onVsync(Display display, int64_t timestamp) override {
+ auto ret = mCallback->onVsync(display, timestamp);
+ ALOGE_IF(!ret.isOk(), "failed to send onVsync: %s", ret.description().c_str());
+ }
+
+ void onVsync_2_4(Display display, int64_t timestamp,
+ VsyncPeriodNanos vsyncPeriodNanos) override {
+ auto ret = mCallback->onVsync_2_4(display, timestamp, vsyncPeriodNanos);
+ ALOGE_IF(!ret.isOk(), "failed to send onVsync_2_4: %s", ret.description().c_str());
+ }
+
+ protected:
+ const sp<IComposerCallback> mCallback;
+ V2_1::hal::ComposerResources* const mResources;
+ };
+
+ Return<void> registerCallback_2_4(const sp<IComposerCallback>& callback) override {
+ // no locking as we require this function to be called only once
+ mHalEventCallback_2_4 = std::make_unique<HalEventCallback>(callback, mResources.get());
+ mHal->registerEventCallback_2_4(mHalEventCallback_2_4.get());
+ return Void();
+ }
+
Return<void> getDisplayCapabilities_2_4(
Display display, IComposerClient::getDisplayCapabilities_2_4_cb hidl_cb) override {
std::vector<IComposerClient::DisplayCapability> capabilities;
@@ -54,6 +104,36 @@
return Void();
}
+ Return<void> getSupportedDisplayVsyncPeriods(
+ Display display, Config config,
+ IComposerClient::getSupportedDisplayVsyncPeriods_cb hidl_cb) override {
+ std::vector<VsyncPeriodNanos> supportedVsyncPeriods;
+ Error error =
+ mHal->getSupportedDisplayVsyncPeriods(display, config, &supportedVsyncPeriods);
+ hidl_cb(error, supportedVsyncPeriods);
+ return Void();
+ }
+
+ Return<void> getDisplayVsyncPeriod(Display display,
+ IComposerClient::getDisplayVsyncPeriod_cb hidl_cb) override {
+ VsyncPeriodNanos vsyncPeriods;
+ Error error = mHal->getDisplayVsyncPeriod(display, &vsyncPeriods);
+ hidl_cb(error, vsyncPeriods);
+ return Void();
+ }
+
+ Return<void> setActiveConfigAndVsyncPeriod(
+ Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos,
+ const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+ IComposerClient::setActiveConfigAndVsyncPeriod_cb hidl_cb) override {
+ int64_t newVsyncAppliedTime = 0;
+ Error error = mHal->setActiveConfigAndVsyncPeriod(display, config, vsyncPeriodNanos,
+ vsyncPeriodChangeConstraints,
+ &newVsyncAppliedTime);
+ hidl_cb(error, newVsyncAppliedTime);
+ return Void();
+ }
+
static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
auto client = std::make_unique<ComposerClientImpl>(hal);
return client->init() ? std::move(client) : nullptr;
@@ -63,6 +143,8 @@
using BaseType2_3 = V2_3::hal::detail::ComposerClientImpl<Interface, Hal>;
using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
using BaseType2_1::mHal;
+ std::unique_ptr<HalEventCallback> mHalEventCallback_2_4;
+ using BaseType2_1::mResources;
};
} // namespace detail
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
index c3bb535..0739f62 100644
--- a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
@@ -16,6 +16,7 @@
#pragma once
+#include <android/hardware/graphics/composer/2.4/types.h>
#include <composer-hal/2.3/ComposerHal.h>
namespace android {
@@ -30,16 +31,39 @@
using common::V1_2::Dataspace;
using common::V1_2::Hdr;
using common::V1_2::PixelFormat;
+using V2_1::Config;
using V2_1::Display;
-using V2_1::Error;
using V2_1::Layer;
+using V2_4::Error;
+using V2_4::VsyncPeriodNanos;
class ComposerHal : public V2_3::hal::ComposerHal {
public:
+ class EventCallback_2_4 {
+ public:
+ virtual ~EventCallback_2_4() = default;
+ virtual void onHotplug(Display display, IComposerCallback::Connection connected) = 0;
+ virtual void onRefresh(Display display) = 0;
+ virtual void onVsync(Display display, int64_t timestamp) = 0;
+ virtual void onVsync_2_4(Display display, int64_t timestamp,
+ VsyncPeriodNanos vsyncPeriodNanos) = 0;
+ };
+
+ virtual void registerEventCallback_2_4(EventCallback_2_4* callback) = 0;
+
+ virtual void unregisterEventCallback_2_4() = 0;
+
virtual Error getDisplayCapabilities_2_4(
Display display, std::vector<IComposerClient::DisplayCapability>* outCapabilities) = 0;
virtual Error getDisplayConnectionType(Display display,
IComposerClient::DisplayConnectionType* outType) = 0;
+ virtual Error getSupportedDisplayVsyncPeriods(
+ Display display, Config config, std::vector<VsyncPeriodNanos>* outVsyncPeriod) = 0;
+ virtual Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) = 0;
+ virtual Error setActiveConfigAndVsyncPeriod(
+ Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos,
+ const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+ int64_t* outNewVsyncAppliedTime) = 0;
};
} // namespace hal
diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
index fd05f66..3420c8c 100644
--- a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
@@ -22,6 +22,7 @@
#include <type_traits>
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
#include <composer-hal/2.4/ComposerHal.h>
#include <composer-passthrough/2.3/HwcHal.h>
@@ -39,18 +40,49 @@
using common::V1_2::Dataspace;
using common::V1_2::Hdr;
using common::V1_2::PixelFormat;
+using V2_1::Config;
using V2_1::Display;
-using V2_1::Error;
+using V2_4::Error;
// HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2
template <typename Hal>
class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl<Hal> {
public:
+ void registerEventCallback_2_4(hal::ComposerHal::EventCallback_2_4* callback) override {
+ mEventCallback_2_4 = callback;
+
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this,
+ reinterpret_cast<hwc2_function_pointer_t>(hotplugHook));
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this,
+ reinterpret_cast<hwc2_function_pointer_t>(refreshHook));
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this,
+ reinterpret_cast<hwc2_function_pointer_t>(vsyncHook));
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_2_4, this,
+ reinterpret_cast<hwc2_function_pointer_t>(vsync_2_4_Hook));
+ }
+
+ void unregisterEventCallback_2_4() override {
+ // we assume the callback functions
+ //
+ // - can be unregistered
+ // - can be in-flight
+ // - will never be called afterward
+ //
+ // which is likely incorrect
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_HOTPLUG, this, nullptr);
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_REFRESH, this, nullptr);
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC, this, nullptr);
+ mDispatch.registerCallback(mDevice, HWC2_CALLBACK_VSYNC_2_4, this, nullptr);
+
+ mEventCallback_2_4 = nullptr;
+ }
+
Error getDisplayCapabilities_2_4(
Display display,
std::vector<IComposerClient::DisplayCapability>* outCapabilities) override {
std::vector<V2_3::IComposerClient::DisplayCapability> capabilities;
- Error error = BaseType2_3::getDisplayCapabilities(display, &capabilities);
+ V2_3::Error error_2_3 = BaseType2_3::getDisplayCapabilities(display, &capabilities);
+ Error error = static_cast<Error>(error_2_3);
if (error != Error::NONE) {
return error;
}
@@ -74,6 +106,63 @@
return static_cast<Error>(error);
}
+ Error getSupportedDisplayVsyncPeriods(Display display, Config config,
+ std::vector<VsyncPeriodNanos>* outVsyncPeriods) override {
+ if (!mDispatch.getSupportedDisplayVsyncPeriods) {
+ return Error::UNSUPPORTED;
+ }
+
+ uint32_t count = 0;
+ int32_t error = mDispatch.getSupportedDisplayVsyncPeriods(mDevice, display, config, &count,
+ nullptr);
+ if (error != HWC2_ERROR_NONE) {
+ return static_cast<Error>(error);
+ }
+ outVsyncPeriods->resize(count);
+ error = mDispatch.getSupportedDisplayVsyncPeriods(mDevice, display, config, &count,
+ outVsyncPeriods->data());
+ if (error != HWC2_ERROR_NONE) {
+ *outVsyncPeriods = std::vector<VsyncPeriodNanos>();
+ return static_cast<Error>(error);
+ }
+ return Error::NONE;
+ }
+
+ Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) override {
+ if (!mDispatch.getDisplayVsyncPeriod) {
+ return Error::UNSUPPORTED;
+ }
+
+ int32_t error = mDispatch.getDisplayVsyncPeriod(mDevice, display, outVsyncPeriod);
+ if (error != HWC2_ERROR_NONE) {
+ return static_cast<Error>(error);
+ }
+ return Error::NONE;
+ }
+
+ Error setActiveConfigAndVsyncPeriod(
+ Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos,
+ const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+ int64_t* outNewVsyncAppliedTime) override {
+ if (!mDispatch.setActiveConfigAndVsyncPeriod) {
+ return Error::UNSUPPORTED;
+ }
+
+ hwc_vsync_period_change_constraints_t vsync_period_change_constraints;
+ vsync_period_change_constraints.desiredTimeNanos =
+ vsyncPeriodChangeConstraints.desiredTimeNanos;
+ vsync_period_change_constraints.seamlessRequired =
+ vsyncPeriodChangeConstraints.seamlessRequired;
+
+ int32_t error = mDispatch.setActiveConfigAndVsyncPeriod(
+ mDevice, display, config, vsyncPeriodNanos, &vsync_period_change_constraints,
+ outNewVsyncAppliedTime);
+ if (error != HWC2_ERROR_NONE) {
+ return static_cast<Error>(error);
+ }
+ return Error::NONE;
+ }
+
protected:
bool initDispatch() override {
if (!BaseType2_3::initDispatch()) {
@@ -82,14 +171,51 @@
this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_CONNECTION_TYPE,
&mDispatch.getDisplayConnectionType);
+ this->initOptionalDispatch(HWC2_FUNCTION_REGISTER_CALLBACK, &mDispatch.registerCallback);
+ this->initOptionalDispatch(HWC2_FUNCTION_GET_SUPPORTED_DISPLAY_VSYNC_PERIODS,
+ &mDispatch.getSupportedDisplayVsyncPeriods);
+ this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_VSYNC_PERIOD,
+ &mDispatch.getDisplayVsyncPeriod);
+ this->initOptionalDispatch(HWC2_FUNCTION_SET_ACTIVE_CONFIG_AND_VSYNC_PERIOD,
+ &mDispatch.setActiveConfigAndVsyncPeriod);
return true;
}
+ static void hotplugHook(hwc2_callback_data_t callbackData, hwc2_display_t display,
+ int32_t connected) {
+ auto hal = static_cast<HwcHalImpl*>(callbackData);
+ hal->mEventCallback_2_4->onHotplug(display,
+ static_cast<IComposerCallback::Connection>(connected));
+ }
+
+ static void refreshHook(hwc2_callback_data_t callbackData, hwc2_display_t display) {
+ auto hal = static_cast<HwcHalImpl*>(callbackData);
+ hal->mEventCallback_2_4->onRefresh(display);
+ }
+
+ static void vsyncHook(hwc2_callback_data_t callbackData, hwc2_display_t display,
+ int64_t timestamp) {
+ auto hal = static_cast<HwcHalImpl*>(callbackData);
+ hal->mEventCallback_2_4->onVsync(display, timestamp);
+ }
+
+ static void vsync_2_4_Hook(hwc2_callback_data_t callbackData, hwc2_display_t display,
+ int64_t timestamp, hwc2_vsync_period_t vsyncPeriodNanos) {
+ auto hal = static_cast<HwcHalImpl*>(callbackData);
+ hal->mEventCallback_2_4->onVsync_2_4(display, timestamp, vsyncPeriodNanos);
+ }
+
private:
struct {
HWC2_PFN_GET_DISPLAY_CONNECTION_TYPE getDisplayConnectionType;
+ HWC2_PFN_REGISTER_CALLBACK registerCallback;
+ HWC2_PFN_GET_SUPPORTED_DISPLAY_VSYNC_PERIODS getSupportedDisplayVsyncPeriods;
+ HWC2_PFN_GET_DISPLAY_VSYNC_PERIOD getDisplayVsyncPeriod;
+ HWC2_PFN_SET_ACTIVE_CONFIG_AND_VSYNC_PERIOD setActiveConfigAndVsyncPeriod;
} mDispatch = {};
+ hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr;
+
using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>;
using BaseType2_3 = V2_3::passthrough::detail::HwcHalImpl<Hal>;
using BaseType2_1::mDevice;
diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
index 937b50e..b02a59a 100644
--- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
@@ -25,7 +25,7 @@
namespace V2_4 {
namespace vts {
-using V2_1::Error;
+using V2_4::Error;
Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
@@ -70,6 +70,40 @@
return error;
}
+Error ComposerClient::getSupportedDisplayVsyncPeriods(
+ Display display, Config config, std::vector<VsyncPeriodNanos>* outSupportedVsyncPeriods) {
+ Error error = Error::NONE;
+ mClient->getSupportedDisplayVsyncPeriods(
+ display, config, [&](const auto& tmpError, const auto& tmpSupportedVsyncPeriods) {
+ error = tmpError;
+ *outSupportedVsyncPeriods = tmpSupportedVsyncPeriods;
+ });
+ return error;
+}
+
+Error ComposerClient::getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriod) {
+ Error error = Error::NONE;
+ mClient->getDisplayVsyncPeriod(display, [&](const auto& tmpError, const auto& tmpVsyncPeriod) {
+ error = tmpError;
+ *outVsyncPeriod = tmpVsyncPeriod;
+ });
+ return error;
+}
+
+Error ComposerClient::setActiveConfigAndVsyncPeriod(
+ Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos,
+ const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+ int64_t* outNewVsyncAppliedTime) {
+ Error error = Error::NONE;
+ mClient->setActiveConfigAndVsyncPeriod(
+ display, config, vsyncPeriodNanos, vsyncPeriodChangeConstraints,
+ [&](const auto& tmpError, const auto& tmpNewVsyncAppliedTime) {
+ error = tmpError;
+ *outNewVsyncAppliedTime = tmpNewVsyncAppliedTime;
+ });
+ return error;
+}
+
} // namespace vts
} // namespace V2_4
} // namespace composer
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 a7d7f86..e8a3905 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
@@ -37,10 +37,12 @@
using common::V1_2::Dataspace;
using common::V1_2::Hdr;
using common::V1_2::PixelFormat;
+using V2_1::Config;
using V2_1::Display;
-using V2_1::Error;
+using V2_4::Error;
using V2_4::IComposer;
using V2_4::IComposerClient;
+using V2_4::VsyncPeriodNanos;
class ComposerClient;
@@ -74,6 +76,16 @@
Error getDisplayConnectionType(Display display,
IComposerClient::DisplayConnectionType* outType);
+ Error getSupportedDisplayVsyncPeriods(Display display, Config config,
+ std::vector<VsyncPeriodNanos>* outSupportedVsyncPeriods);
+
+ Error getDisplayVsyncPeriod(Display display, VsyncPeriodNanos* outVsyncPeriods);
+
+ Error setActiveConfigAndVsyncPeriod(
+ Display display, Config config, VsyncPeriodNanos vsyncPeriodNanos,
+ const IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+ int64_t* outNewVsyncAppliedTime);
+
private:
const sp<IComposerClient> mClient;
};
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index 76c0039..3d967fc 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "graphics_composer_hidl_hal_test@2.4"
#include <algorithm>
+#include <thread>
#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
@@ -26,6 +27,7 @@
#include <composer-vts/2.1/TestCommandReader.h>
#include <composer-vts/2.4/ComposerVts.h>
#include <mapper-vts/2.0/MapperVts.h>
+#include <utils/Timers.h>
namespace android {
namespace hardware {
@@ -110,8 +112,27 @@
return 0;
}
+ // returns an invalid config id (one that has not been registered to a
+ // display). Currently assuming that a device will never have close to
+ // std::numeric_limit<uint64_t>::max() configs registered while running tests
+ Display GetInvalidConfigId(Display display) {
+ std::vector<Config> validConfigs = mComposerClient->getDisplayConfigs(display);
+ uint64_t id = std::numeric_limits<uint64_t>::max();
+ while (id > 0) {
+ if (std::find(validConfigs.begin(), validConfigs.end(), id) == validConfigs.end()) {
+ return id;
+ }
+ id--;
+ }
+
+ return 0;
+ }
+
void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+ void Test_setActiveConfigAndVsyncPeriod(
+ const IComposerClient::VsyncPeriodChangeConstraints& constraints);
+
std::unique_ptr<Composer> mComposer;
std::unique_ptr<ComposerClient> mComposerClient;
sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
@@ -189,6 +210,162 @@
}
}
+TEST_F(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods_BadDisplay) {
+ std::vector<VsyncPeriodNanos> supportedVsyncPeriods;
+ EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->getSupportedDisplayVsyncPeriods(
+ mInvalidDisplayId, Config(0), &supportedVsyncPeriods));
+}
+
+TEST_F(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods_BadConfig) {
+ for (Display display : mComposerCallback->getDisplays()) {
+ Config invalidConfigId = GetInvalidConfigId(display);
+ std::vector<VsyncPeriodNanos> supportedVsyncPeriods;
+ EXPECT_EQ(Error::BAD_CONFIG, mComposerClient->getSupportedDisplayVsyncPeriods(
+ display, invalidConfigId, &supportedVsyncPeriods));
+ }
+}
+
+TEST_F(GraphicsComposerHidlTest, getSupportedDisplayVsyncPeriods) {
+ for (Display display : mComposerCallback->getDisplays()) {
+ for (Config config : mComposerClient->getDisplayConfigs(display)) {
+ std::vector<VsyncPeriodNanos> supportedVsyncPeriods;
+
+ // Get the default vsync period from the config
+ VsyncPeriodNanos defaultVsyncPeiord = mComposerClient->getDisplayAttribute(
+ display, config, IComposerClient::Attribute::VSYNC_PERIOD);
+ // Get all supported vsync periods for this config
+ EXPECT_EQ(Error::NONE, mComposerClient->getSupportedDisplayVsyncPeriods(
+ display, config, &supportedVsyncPeriods));
+ // Default vsync period must be present in the list
+ EXPECT_NE(std::find(supportedVsyncPeriods.begin(), supportedVsyncPeriods.end(),
+ defaultVsyncPeiord),
+ supportedVsyncPeriods.end());
+
+ // Each vsync period must be unique
+ std::unordered_set<VsyncPeriodNanos> vsyncPeriodSet;
+ for (VsyncPeriodNanos vsyncPeriodNanos : supportedVsyncPeriods) {
+ EXPECT_TRUE(vsyncPeriodSet.insert(vsyncPeriodNanos).second);
+ }
+ }
+ }
+}
+
+TEST_F(GraphicsComposerHidlTest, getDisplayVsyncPeriod_BadDisplay) {
+ VsyncPeriodNanos vsyncPeriodNanos;
+ EXPECT_EQ(Error::BAD_DISPLAY,
+ mComposerClient->getDisplayVsyncPeriod(mInvalidDisplayId, &vsyncPeriodNanos));
+}
+
+TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadDisplay) {
+ int64_t newVsyncAppliedTime;
+ IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+ constraints.seamlessRequired = false;
+ constraints.desiredTimeNanos = systemTime();
+
+ EXPECT_EQ(Error::BAD_DISPLAY, mComposerClient->setActiveConfigAndVsyncPeriod(
+ mInvalidDisplayId, Config(0), VsyncPeriodNanos(0),
+ constraints, &newVsyncAppliedTime));
+}
+
+TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadConfig) {
+ int64_t newVsyncAppliedTime;
+ IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+ constraints.seamlessRequired = false;
+ constraints.desiredTimeNanos = systemTime();
+
+ for (Display display : mComposerCallback->getDisplays()) {
+ Config invalidConfigId = GetInvalidConfigId(display);
+ EXPECT_EQ(Error::BAD_CONFIG, mComposerClient->setActiveConfigAndVsyncPeriod(
+ display, invalidConfigId, VsyncPeriodNanos(0),
+ constraints, &newVsyncAppliedTime));
+ }
+}
+
+TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_BadVsyncPeriod) {
+ int64_t newVsyncAppliedTime;
+ IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+ constraints.seamlessRequired = false;
+ constraints.desiredTimeNanos = systemTime();
+
+ for (Display display : mComposerCallback->getDisplays()) {
+ for (Config config : mComposerClient->getDisplayConfigs(display)) {
+ EXPECT_EQ(Error::BAD_VSYNC_PERIOD, mComposerClient->setActiveConfigAndVsyncPeriod(
+ display, config, VsyncPeriodNanos(0),
+ constraints, &newVsyncAppliedTime));
+ }
+ }
+}
+
+void GraphicsComposerHidlTest::Test_setActiveConfigAndVsyncPeriod(
+ const IComposerClient::VsyncPeriodChangeConstraints& constraints) {
+ int64_t newVsyncAppliedTime;
+
+ for (Display display : mComposerCallback->getDisplays()) {
+ for (Config config : mComposerClient->getDisplayConfigs(display)) {
+ std::vector<VsyncPeriodNanos> supportedVsyncPeriods;
+
+ EXPECT_EQ(Error::NONE, mComposerClient->getSupportedDisplayVsyncPeriods(
+ display, config, &supportedVsyncPeriods));
+ for (VsyncPeriodNanos newVsyncPeriod : supportedVsyncPeriods) {
+ VsyncPeriodNanos vsyncPeriodNanos;
+ EXPECT_EQ(Error::NONE,
+ mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+
+ if (vsyncPeriodNanos == newVsyncPeriod) {
+ continue;
+ }
+
+ EXPECT_EQ(Error::NONE, mComposerClient->setActiveConfigAndVsyncPeriod(
+ display, config, newVsyncPeriod, constraints,
+ &newVsyncAppliedTime));
+
+ EXPECT_TRUE(newVsyncAppliedTime >= constraints.desiredTimeNanos);
+
+ // Refresh rate should change within a reasonable time
+ constexpr nsecs_t kReasonableTimeForChange = 1'000'000'000; // 1 second
+ EXPECT_TRUE(newVsyncAppliedTime - constraints.desiredTimeNanos <=
+ kReasonableTimeForChange);
+
+ while (systemTime() <= newVsyncAppliedTime) {
+ EXPECT_EQ(Error::NONE,
+ mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+ if (systemTime() <= constraints.desiredTimeNanos) {
+ EXPECT_NE(vsyncPeriodNanos, newVsyncPeriod);
+ }
+
+ if (vsyncPeriodNanos == newVsyncPeriod) {
+ break;
+ }
+ std::this_thread::sleep_for(10ms);
+ }
+ EXPECT_EQ(Error::NONE,
+ mComposerClient->getDisplayVsyncPeriod(display, &vsyncPeriodNanos));
+ EXPECT_EQ(vsyncPeriodNanos, newVsyncPeriod);
+ }
+ }
+ }
+}
+
+TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod) {
+ IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+ constraints.seamlessRequired = false;
+ constraints.desiredTimeNanos = systemTime();
+ Test_setActiveConfigAndVsyncPeriod(constraints);
+}
+
+TEST_F(GraphicsComposerHidlTest, setActiveConfigAndVsyncPeriod_delayed) {
+ IComposerClient::VsyncPeriodChangeConstraints constraints;
+
+ constexpr auto kDelayForChange = 300ms;
+ constraints.seamlessRequired = false;
+ constraints.desiredTimeNanos = systemTime() + kDelayForChange.count();
+ Test_setActiveConfigAndVsyncPeriod(constraints);
+}
+
} // namespace
} // namespace vts
} // namespace V2_4