diff options
author | Roman Stratiienko <roman.o.stratiienko@globallogic.com> | 2022-01-21 15:12:56 +0200 |
---|---|---|
committer | Roman Stratiienko <roman.o.stratiienko@globallogic.com> | 2022-02-04 11:16:32 +0200 |
commit | d0c035b44a844af5017c0c3b2507af2f3907c36c (patch) | |
tree | 0204a64b0bf4d16f320678377be9620143dd0119 | |
parent | 099c31156d4d916c1e18ec00ab163de77bd17a94 (diff) | |
download | drm_hwcomposer-d0c035b44a844af5017c0c3b2507af2f3907c36c.tar.gz |
drm_hwcomposer: Implement SetActiveConfigWithConstraints
Enough to get 100% passes in Composer 2.4 VTS.
Some SOCs require a VTS fix to pass [1]
[1]: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/1954544
Signed-off-by: Roman Stratiienko <roman.o.stratiienko@globallogic.com>
-rw-r--r-- | drm/ResourceManager.cpp | 8 | ||||
-rw-r--r-- | drm/ResourceManager.h | 2 | ||||
-rw-r--r-- | hwc2_device/DrmHwcTwo.cpp | 22 | ||||
-rw-r--r-- | hwc2_device/DrmHwcTwo.h | 4 | ||||
-rw-r--r-- | hwc2_device/HwcDisplay.cpp | 98 | ||||
-rw-r--r-- | hwc2_device/HwcDisplay.h | 8 | ||||
-rw-r--r-- | hwc2_device/HwcDisplayConfigs.cpp | 16 | ||||
-rw-r--r-- | hwc2_device/HwcDisplayConfigs.h | 12 |
8 files changed, 127 insertions, 43 deletions
diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp index 789eca3..b294180 100644 --- a/drm/ResourceManager.cpp +++ b/drm/ResourceManager.cpp @@ -21,6 +21,7 @@ #include <fcntl.h> #include <sys/stat.h> +#include <ctime> #include <sstream> #include "bufferinfo/BufferInfoGetter.h" @@ -114,6 +115,13 @@ int ResourceManager::AddDrmDevice(const std::string &path) { return ret; } +auto ResourceManager::GetTimeMonotonicNs() -> int64_t { + struct timespec ts {}; + clock_gettime(CLOCK_MONOTONIC, &ts); + constexpr int64_t kNsInSec = 1000000000LL; + return int64_t(ts.tv_sec) * kNsInSec + int64_t(ts.tv_nsec); +} + void ResourceManager::UpdateFrontendDisplays() { auto ordered_connectors = GetOrderedConnectors(); diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h index c4c3edd..88ba878 100644 --- a/drm/ResourceManager.h +++ b/drm/ResourceManager.h @@ -56,6 +56,8 @@ class ResourceManager { return main_lock_; } + static auto GetTimeMonotonicNs() -> int64_t; + private: auto AddDrmDevice(std::string const &path) -> int; auto GetOrderedConnectors() -> std::vector<DrmConnector *>; diff --git a/hwc2_device/DrmHwcTwo.cpp b/hwc2_device/DrmHwcTwo.cpp index 37901ee..f1a5490 100644 --- a/hwc2_device/DrmHwcTwo.cpp +++ b/hwc2_device/DrmHwcTwo.cpp @@ -174,6 +174,11 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor, vsync_2_4_callback_ = std::make_pair(HWC2_PFN_VSYNC_2_4(function), data); break; } + case HWC2::Callback::VsyncPeriodTimingChanged: { + period_timing_changed_callback_ = std:: + make_pair(HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED(function), data); + break; + } #endif default: break; @@ -220,4 +225,21 @@ void DrmHwcTwo::SendVsyncEventToClient( } } +void DrmHwcTwo::SendVsyncPeriodTimingChangedEventToClient( + [[maybe_unused]] hwc2_display_t displayid, + [[maybe_unused]] int64_t timestamp) const { +#if PLATFORM_SDK_VERSION > 29 + hwc_vsync_period_change_timeline_t timeline = { + .newVsyncAppliedTimeNanos = timestamp, + .refreshRequired = false, + .refreshTimeNanos = 0, + }; + if (period_timing_changed_callback_.first != nullptr && + period_timing_changed_callback_.second != nullptr) { + period_timing_changed_callback_ + .first(period_timing_changed_callback_.second, displayid, &timeline); + } +#endif +} + } // namespace android diff --git a/hwc2_device/DrmHwcTwo.h b/hwc2_device/DrmHwcTwo.h index 5379cba..0e72251 100644 --- a/hwc2_device/DrmHwcTwo.h +++ b/hwc2_device/DrmHwcTwo.h @@ -33,6 +33,8 @@ class DrmHwcTwo : public PipelineToFrontendBindingInterface { std::pair<HWC2_PFN_VSYNC, hwc2_callback_data_t> vsync_callback_{}; #if PLATFORM_SDK_VERSION > 29 std::pair<HWC2_PFN_VSYNC_2_4, hwc2_callback_data_t> vsync_2_4_callback_{}; + std::pair<HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED, hwc2_callback_data_t> + period_timing_changed_callback_{}; #endif std::pair<HWC2_PFN_REFRESH, hwc2_callback_data_t> refresh_callback_{}; @@ -66,6 +68,8 @@ class DrmHwcTwo : public PipelineToFrontendBindingInterface { void SendVsyncEventToClient(hwc2_display_t displayid, int64_t timestamp, uint32_t vsync_period) const; + void SendVsyncPeriodTimingChangedEventToClient(hwc2_display_t displayid, + int64_t timestamp) const; private: void SendHotplugEventToClient(hwc2_display_t displayid, bool connected); diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp index 656aa94..d7b753a 100644 --- a/hwc2_device/HwcDisplay.cpp +++ b/hwc2_device/HwcDisplay.cpp @@ -141,7 +141,10 @@ HWC2::Error HwcDisplay::Init() { if (vsync_flattening_en_) { ProcessFlatenningVsyncInternal(); } - if (!vsync_event_en_ && !vsync_flattening_en_) { + if (vsync_tracking_en_) { + last_vsync_ts_ = timestamp; + } + if (!vsync_event_en_ && !vsync_flattening_en_ && !vsync_tracking_en_) { vsync_worker_.VSyncControl(false); } }); @@ -215,10 +218,10 @@ HWC2::Error HwcDisplay::DestroyLayer(hwc2_layer_t layer) { } HWC2::Error HwcDisplay::GetActiveConfig(hwc2_config_t *config) const { - if (configs_.hwc_configs.count(configs_.active_config_id) == 0) + if (configs_.hwc_configs.count(staged_mode_config_id_) == 0) return HWC2::Error::BadConfig; - *config = configs_.active_config_id; + *config = staged_mode_config_id_; return HWC2::Error::None; } @@ -321,7 +324,7 @@ HWC2::Error HwcDisplay::GetDisplayAttribute(hwc2_config_t config, case HWC2::Attribute::ConfigGroup: /* Dispite ConfigGroup is a part of HWC2.4 API, framework * able to request it even if service @2.1 is used */ - *value = hwc_config.group_id; + *value = int(hwc_config.group_id); break; #endif default: @@ -436,6 +439,26 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) { return HWC2::Error::None; } + int PrevModeVsyncPeriodNs = static_cast<int>( + 1E9 / GetPipe().connector->Get()->GetActiveMode().v_refresh()); + + auto mode_update_commited_ = false; + if (staged_mode_ && + staged_mode_change_time_ <= ResourceManager::GetTimeMonotonicNs()) { + client_layer_.SetLayerDisplayFrame( + (hwc_rect_t){.left = 0, + .top = 0, + .right = static_cast<int>(staged_mode_->h_display()), + .bottom = static_cast<int>(staged_mode_->v_display())}); + + configs_.active_config_id = staged_mode_config_id_; + + a_args.display_mode = *staged_mode_; + if (!a_args.test_only) { + mode_update_commited_ = true; + } + } + // order the layers by z-order bool use_client_layer = false; uint32_t client_z_order = UINT32_MAX; @@ -498,9 +521,6 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) { } a_args.composition = composition; - if (staged_mode) { - a_args.display_mode = *staged_mode; - } ret = GetPipe().compositor->ExecuteAtomicCommit(a_args); if (ret) { @@ -509,8 +529,13 @@ HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) { return HWC2::Error::BadParameter; } - if (!a_args.test_only) { - staged_mode.reset(); + if (mode_update_commited_) { + staged_mode_.reset(); + vsync_tracking_en_ = false; + if (last_vsync_ts_ != 0) { + hwc2_->SendVsyncPeriodTimingChangedEventToClient( + handle_, last_vsync_ts_ + PrevModeVsyncPeriodNs); + } } return HWC2::Error::None; @@ -548,30 +573,24 @@ HWC2::Error HwcDisplay::PresentDisplay(int32_t *present_fence) { return HWC2::Error::None; } -HWC2::Error HwcDisplay::SetActiveConfig(hwc2_config_t config) { - int conf = static_cast<int>(config); - - if (configs_.hwc_configs.count(conf) == 0) { - ALOGE("Could not find active mode for %d", conf); +HWC2::Error HwcDisplay::SetActiveConfigInternal(uint32_t config, + int64_t change_time) { + if (configs_.hwc_configs.count(config) == 0) { + ALOGE("Could not find active mode for %u", config); return HWC2::Error::BadConfig; } - auto &mode = configs_.hwc_configs[conf].mode; - - staged_mode = mode; - - configs_.active_config_id = conf; - - // Setup the client layer's dimensions - hwc_rect_t display_frame = {.left = 0, - .top = 0, - .right = static_cast<int>(mode.h_display()), - .bottom = static_cast<int>(mode.v_display())}; - client_layer_.SetLayerDisplayFrame(display_frame); + staged_mode_ = configs_.hwc_configs[config].mode; + staged_mode_change_time_ = change_time; + staged_mode_config_id_ = config; return HWC2::Error::None; } +HWC2::Error HwcDisplay::SetActiveConfig(hwc2_config_t config) { + return SetActiveConfigInternal(config, ResourceManager::GetTimeMonotonicNs()); +} + /* Find API details at: * https://cs.android.com/android/platform/superproject/+/android-11.0.0_r3:hardware/libhardware/include/hardware/hwcomposer2.h;l=1861 */ @@ -736,14 +755,37 @@ HWC2::Error HwcDisplay::GetDisplayConnectionType(uint32_t *outType) { } HWC2::Error HwcDisplay::SetActiveConfigWithConstraints( - hwc2_config_t /*config*/, + hwc2_config_t config, hwc_vsync_period_change_constraints_t *vsyncPeriodChangeConstraints, hwc_vsync_period_change_timeline_t *outTimeline) { if (vsyncPeriodChangeConstraints == nullptr || outTimeline == nullptr) { return HWC2::Error::BadParameter; } - return HWC2::Error::BadConfig; + uint32_t current_vsync_period{}; + GetDisplayVsyncPeriod(¤t_vsync_period); + + if (vsyncPeriodChangeConstraints->seamlessRequired) { + return HWC2::Error::SeamlessNotAllowed; + } + + outTimeline->refreshTimeNanos = vsyncPeriodChangeConstraints + ->desiredTimeNanos - + current_vsync_period; + auto ret = SetActiveConfigInternal(config, outTimeline->refreshTimeNanos); + if (ret != HWC2::Error::None) { + return ret; + } + + outTimeline->refreshRequired = true; + outTimeline->newVsyncAppliedTimeNanos = vsyncPeriodChangeConstraints + ->desiredTimeNanos; + + last_vsync_ts_ = 0; + vsync_tracking_en_ = true; + vsync_worker_.VSyncControl(true); + + return HWC2::Error::None; } HWC2::Error HwcDisplay::SetAutoLowLatencyMode(bool /*on*/) { diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h index 5a5c98e..e7ce7ef 100644 --- a/hwc2_device/HwcDisplay.h +++ b/hwc2_device/HwcDisplay.h @@ -195,7 +195,9 @@ class HwcDisplay { DrmHwcTwo *const hwc2_; - std::optional<DrmMode> staged_mode; + std::optional<DrmMode> staged_mode_; + int64_t staged_mode_change_time_{}; + uint32_t staged_mode_config_id_{}; DrmDisplayPipeline *const pipeline_; @@ -204,6 +206,8 @@ class HwcDisplay { VSyncWorker vsync_worker_; bool vsync_event_en_{}; bool vsync_flattening_en_{}; + bool vsync_tracking_en_{}; + int64_t last_vsync_ts_{}; const hwc2_display_t handle_; HWC2::DisplayType type_; @@ -223,6 +227,8 @@ class HwcDisplay { std::string DumpDelta(HwcDisplay::Stats delta); HWC2::Error Init(); + + HWC2::Error SetActiveConfigInternal(uint32_t config, int64_t change_time); }; } // namespace android diff --git a/hwc2_device/HwcDisplayConfigs.cpp b/hwc2_device/HwcDisplayConfigs.cpp index c28ec9f..6a3ed5a 100644 --- a/hwc2_device/HwcDisplayConfigs.cpp +++ b/hwc2_device/HwcDisplayConfigs.cpp @@ -32,7 +32,7 @@ constexpr uint32_t kHeadlessModeDisplayVRefresh = 60; namespace android { // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -int HwcDisplayConfigs::last_config_id = 1; +uint32_t HwcDisplayConfigs::last_config_id = 1; void HwcDisplayConfigs::FillHeadless() { hwc_configs.clear(); @@ -77,15 +77,15 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) { mm_height = connector.GetMmHeight(); preferred_config_id = 0; - int preferred_config_group_id = 0; + uint32_t preferred_config_group_id = 0; - int first_config_id = last_config_id; - int last_group_id = 1; + uint32_t first_config_id = last_config_id; + uint32_t last_group_id = 1; /* Group modes */ for (const auto &mode : connector.GetModes()) { /* Find group for the new mode or create new group */ - int group_found = 0; + uint32_t group_found = 0; for (auto &hwc_config : hwc_configs) { if (mode.h_display() == hwc_config.second.mode.h_display() && mode.v_display() == hwc_config.second.mode.v_display()) { @@ -128,7 +128,7 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) { preferred_config_group_id = 1; } - for (int group = 1; group < last_group_id; group++) { + for (uint32_t group = 1; group < last_group_id; group++) { bool has_interlaced = false; bool has_progressive = false; for (auto &hwc_config : hwc_configs) { @@ -179,8 +179,8 @@ HWC2::Error HwcDisplayConfigs::Update(DrmConnector &connector) { * otherwise android.graphics.cts.SetFrameRateTest CTS will fail */ constexpr float kMinFpsDelta = 1.0; // FPS - for (int m1 = first_config_id; m1 < last_config_id; m1++) { - for (int m2 = first_config_id; m2 < last_config_id; m2++) { + for (uint32_t m1 = first_config_id; m1 < last_config_id; m1++) { + for (uint32_t m2 = first_config_id; m2 < last_config_id; m2++) { if (m1 != m2 && hwc_configs[m1].group_id == hwc_configs[m2].group_id && !hwc_configs[m1].disabled && !hwc_configs[m2].disabled && fabsf(hwc_configs[m1].mode.v_refresh() - diff --git a/hwc2_device/HwcDisplayConfigs.h b/hwc2_device/HwcDisplayConfigs.h index 75852a6..7c173d6 100644 --- a/hwc2_device/HwcDisplayConfigs.h +++ b/hwc2_device/HwcDisplayConfigs.h @@ -28,8 +28,8 @@ namespace android { class DrmConnector; struct HwcDisplayConfig { - int id{}; - int group_id{}; + uint32_t id{}; + uint32_t group_id{}; DrmMode mode; bool disabled{}; @@ -42,13 +42,13 @@ struct HwcDisplayConfigs { HWC2::Error Update(DrmConnector &conn); void FillHeadless(); - std::map<int /*config_id*/, struct HwcDisplayConfig> hwc_configs; + std::map<uint32_t /*config_id*/, struct HwcDisplayConfig> hwc_configs; - int active_config_id = 0; - int preferred_config_id = 0; + uint32_t active_config_id = 0; + uint32_t preferred_config_id = 0; // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) - static int last_config_id; + static uint32_t last_config_id; uint32_t mm_width = 0; uint32_t mm_height = 0; |