aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Stratiienko <roman.o.stratiienko@globallogic.com>2022-01-21 15:12:56 +0200
committerRoman Stratiienko <roman.o.stratiienko@globallogic.com>2022-02-04 11:16:32 +0200
commitd0c035b44a844af5017c0c3b2507af2f3907c36c (patch)
tree0204a64b0bf4d16f320678377be9620143dd0119
parent099c31156d4d916c1e18ec00ab163de77bd17a94 (diff)
downloaddrm_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.cpp8
-rw-r--r--drm/ResourceManager.h2
-rw-r--r--hwc2_device/DrmHwcTwo.cpp22
-rw-r--r--hwc2_device/DrmHwcTwo.h4
-rw-r--r--hwc2_device/HwcDisplay.cpp98
-rw-r--r--hwc2_device/HwcDisplay.h8
-rw-r--r--hwc2_device/HwcDisplayConfigs.cpp16
-rw-r--r--hwc2_device/HwcDisplayConfigs.h12
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(&current_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;