Snap for 12658558 from ab442012769dde089130698c8855e2b204c62efc to 25Q1-release
Change-Id: I704019cfd0234c700c1c5a46eda98c5cd248d3ea
diff --git a/compositor/DisplayInfo.h b/compositor/DisplayInfo.h
index bbcbff8..6ddc66f 100644
--- a/compositor/DisplayInfo.h
+++ b/compositor/DisplayInfo.h
@@ -46,3 +46,12 @@
kModePanelOrientationLeftUp,
kModePanelOrientationRightUp
};
+
+struct QueuedConfigTiming {
+ // In order for the new config to be applied, the client must send a new frame
+ // at this time.
+ int64_t refresh_time_ns;
+
+ // The time when the display will start to refresh at the new vsync period.
+ int64_t new_vsync_time_ns;
+};
diff --git a/drm/DrmHwc.cpp b/drm/DrmHwc.cpp
index 57293c2..aaba506 100644
--- a/drm/DrmHwc.cpp
+++ b/drm/DrmHwc.cpp
@@ -22,6 +22,7 @@
#include "backend/Backend.h"
#include "utils/log.h"
+#include "utils/properties.h"
namespace android {
@@ -196,6 +197,13 @@
}
uint32_t DrmHwc::GetMaxVirtualDisplayCount() {
+ /* Virtual display is an experimental feature.
+ * Unless explicitly set to true, return 0 for no support.
+ */
+ if (0 == property_get_bool("vendor.hwc.drm.enable_virtual_display", 0)) {
+ return 0;
+ }
+
auto writeback_count = resource_manager_.GetWritebackConnectorsCount();
writeback_count = std::min(writeback_count, 1U);
/* Currently, only 1 virtual display is supported. Other cases need testing */
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 6797c56..ffe6b11 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -96,6 +96,58 @@
Deinit();
};
+auto HwcDisplay::GetCurrentConfig() const -> const HwcDisplayConfig * {
+ auto config_iter = configs_.hwc_configs.find(configs_.active_config_id);
+ if (config_iter == configs_.hwc_configs.end()) {
+ return nullptr;
+ }
+ return &config_iter->second;
+}
+
+auto HwcDisplay::GetLastRequestedConfig() const -> const HwcDisplayConfig * {
+ auto config_iter = configs_.hwc_configs.find(staged_mode_config_id_);
+ if (config_iter == configs_.hwc_configs.end()) {
+ return nullptr;
+ }
+ return &config_iter->second;
+}
+
+auto HwcDisplay::QueueConfig(hwc2_config_t config, int64_t desired_time,
+ bool seamless, QueuedConfigTiming *out_timing)
+ -> ConfigError {
+ if (configs_.hwc_configs.count(config) == 0) {
+ ALOGE("Could not find active mode for %u", config);
+ return ConfigError::kBadConfig;
+ }
+
+ // TODO: Add support for seamless configuration changes.
+ if (seamless) {
+ return ConfigError::kSeamlessNotAllowed;
+ }
+
+ // Request a refresh from the client one vsync period before the desired
+ // time, or simply at the desired time if there is no active configuration.
+ const HwcDisplayConfig *current_config = GetCurrentConfig();
+ out_timing->refresh_time_ns = desired_time -
+ (current_config
+ ? current_config->mode.GetVSyncPeriodNs()
+ : 0);
+ out_timing->new_vsync_time_ns = desired_time;
+
+ // Queue the config change timing to be consistent with the requested
+ // refresh time.
+ staged_mode_ = configs_.hwc_configs[config].mode;
+ staged_mode_change_time_ = out_timing->refresh_time_ns;
+ staged_mode_config_id_ = config;
+
+ // Enable vsync events until the mode has been applied.
+ last_vsync_ts_ = 0;
+ vsync_tracking_en_ = true;
+ vsync_worker_->VSyncControl(true);
+
+ return ConfigError::kNone;
+}
+
void HwcDisplay::SetPipeline(std::shared_ptr<DrmDisplayPipeline> pipeline) {
Deinit();
@@ -114,22 +166,9 @@
AtomicCommitArgs a_args{};
a_args.composition = std::make_shared<DrmKmsPlan>();
GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
-/*
- * TODO:
- * Unfortunately the following causes regressions on db845c
- * with VtsHalGraphicsComposerV2_3TargetTest due to the display
- * never coming back. Patches to avoiding that issue on the
- * the kernel side unfortunately causes further crashes in
- * drm_hwcomposer, because the client detach takes longer then the
- * 1 second max VTS expects. So for now as a workaround, lets skip
- * deactivating the display on deinit, which matches previous
- * behavior prior to commit d0494d9b8097
- */
-#if 0
a_args.composition = {};
a_args.active = false;
GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
-#endif
current_plan_.reset();
backend_.reset();
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index 4680ca9..91e5df7 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -41,6 +41,13 @@
// NOLINTNEXTLINE
class HwcDisplay {
public:
+ enum ConfigError {
+ kNone,
+ kBadConfig,
+ kSeamlessNotAllowed,
+ kSeamlessNotPossible
+ };
+
HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type, DrmHwc *hwc);
HwcDisplay(const HwcDisplay &) = delete;
~HwcDisplay();
@@ -59,6 +66,18 @@
return configs_;
}
+ // Get the config representing the mode that has been committed to KMS.
+ auto GetCurrentConfig() const -> const HwcDisplayConfig *;
+
+ // Get the config that was last requested through SetActiveConfig and similar
+ // functions. This may differ from the GetCurrentConfig if the config change
+ // is queued up to take effect in the future.
+ auto GetLastRequestedConfig() const -> const HwcDisplayConfig *;
+
+ // Queue a configuration change to take effect in the future.
+ auto QueueConfig(hwc2_config_t config, int64_t desired_time, bool seamless,
+ QueuedConfigTiming *out_timing) -> ConfigError;
+
// HWC2 Hooks - these should not be used outside of the hwc2 device.
HWC2::Error AcceptDisplayChanges();
HWC2::Error CreateLayer(hwc2_layer_t *layer);
diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp
index 0266197..c0b340e 100644
--- a/hwc3/ComposerClient.cpp
+++ b/hwc3/ComposerClient.cpp
@@ -109,6 +109,8 @@
case static_cast<int32_t>(
common::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE):
return BufferColorSpace::kItuRec2020;
+ case static_cast<int32_t>(common::Dataspace::UNKNOWN):
+ return BufferColorSpace::kUndefined;
default:
ALOGE("Unsupported standard: %d", standard);
return std::nullopt;
@@ -128,6 +130,8 @@
return BufferSampleRange::kFullRange;
case static_cast<int32_t>(common::Dataspace::RANGE_LIMITED):
return BufferSampleRange::kLimitedRange;
+ case static_cast<int32_t>(common::Dataspace::UNKNOWN):
+ return BufferSampleRange::kUndefined;
default:
ALOGE("Unsupported sample range: %d", sample_range);
return std::nullopt;
@@ -603,11 +607,16 @@
return;
}
+ if (command.brightness) {
+ // TODO: Implement support for display brightness.
+ cmd_result_writer_->AddError(hwc3::Error::kUnsupported);
+ return;
+ }
+
for (const auto& layer_cmd : command.layers) {
DispatchLayerCommand(command.display, layer_cmd);
}
- // TODO: Implement support for display brightness.
if (command.colorTransformMatrix) {
ExecuteSetDisplayColorTransform(command.display,
*command.colorTransformMatrix);
@@ -650,7 +659,7 @@
}
ndk::ScopedAStatus ComposerClient::getActiveConfig(int64_t display_id,
- int32_t* config) {
+ int32_t* config_id) {
DEBUG_FUNC();
const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
HwcDisplay* display = GetDisplay(display_id);
@@ -658,13 +667,12 @@
return ToBinderStatus(hwc3::Error::kBadDisplay);
}
- uint32_t hwc2_config = 0;
- const hwc3::Error error = Hwc2toHwc3Error(
- display->GetActiveConfig(&hwc2_config));
- if (error != hwc3::Error::kNone) {
- return ToBinderStatus(error);
+ const HwcDisplayConfig* config = display->GetLastRequestedConfig();
+ if (config == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadConfig);
}
- *config = Hwc2ConfigIdToHwc3(hwc2_config);
+
+ *config_id = Hwc2ConfigIdToHwc3(config->id);
return ndk::ScopedAStatus::ok();
}
@@ -887,14 +895,15 @@
return ToBinderStatus(hwc3::Error::kBadDisplay);
}
- uint32_t hwc2_vsync_period = 0;
- auto error = Hwc2toHwc3Error(
- display->GetDisplayVsyncPeriod(&hwc2_vsync_period));
- if (error != hwc3::Error::kNone) {
- return ToBinderStatus(error);
+ // getDisplayVsyncPeriod should return the vsync period of the config that
+ // is currently committed to the kernel. If a config change is pending due to
+ // setActiveConfigWithConstraints, return the pre-change vsync period.
+ const HwcDisplayConfig* config = display->GetCurrentConfig();
+ if (config == nullptr) {
+ return ToBinderStatus(hwc3::Error::kBadConfig);
}
- *vsync_period = static_cast<int32_t>(hwc2_vsync_period);
+ *vsync_period = config->mode.GetVSyncPeriodNs();
return ndk::ScopedAStatus::ok();
}
@@ -1055,13 +1064,14 @@
ndk::ScopedAStatus ComposerClient::setActiveConfig(int64_t display_id,
int32_t config) {
DEBUG_FUNC();
- const std::unique_lock lock(hwc_->GetResMan().GetMainLock());
- HwcDisplay* display = GetDisplay(display_id);
- if (display == nullptr) {
- return ToBinderStatus(hwc3::Error::kBadDisplay);
- }
- return ToBinderStatus(Hwc2toHwc3Error(display->SetActiveConfig(config)));
+ VsyncPeriodChangeTimeline timeline;
+ VsyncPeriodChangeConstraints constraints = {
+ .desiredTimeNanos = ::android::ResourceManager::GetTimeMonotonicNs(),
+ .seamlessRequired = false,
+ };
+ return setActiveConfigWithConstraints(display_id, config, constraints,
+ &timeline);
}
ndk::ScopedAStatus ComposerClient::setActiveConfigWithConstraints(
@@ -1075,23 +1085,24 @@
return ToBinderStatus(hwc3::Error::kBadDisplay);
}
- hwc_vsync_period_change_constraints_t hwc2_constraints;
- hwc2_constraints.desiredTimeNanos = constraints.desiredTimeNanos;
- hwc2_constraints.seamlessRequired = static_cast<uint8_t>(
- constraints.seamlessRequired);
+ ::QueuedConfigTiming timing{};
+ HwcDisplay::ConfigError
+ result = display->QueueConfig(config, constraints.desiredTimeNanos,
+ constraints.seamlessRequired, &timing);
+ timeline->newVsyncAppliedTimeNanos = timing.new_vsync_time_ns;
+ timeline->refreshTimeNanos = timing.refresh_time_ns;
+ timeline->refreshRequired = true;
- hwc_vsync_period_change_timeline_t hwc2_timeline{};
- auto error = Hwc2toHwc3Error(
- display->SetActiveConfigWithConstraints(config, &hwc2_constraints,
- &hwc2_timeline));
- if (error != hwc3::Error::kNone) {
- return ToBinderStatus(error);
+ switch (result) {
+ case HwcDisplay::ConfigError::kBadConfig:
+ return ToBinderStatus(hwc3::Error::kBadConfig);
+ case HwcDisplay::ConfigError::kSeamlessNotAllowed:
+ return ToBinderStatus(hwc3::Error::kSeamlessNotAllowed);
+ case HwcDisplay::ConfigError::kSeamlessNotPossible:
+ return ToBinderStatus(hwc3::Error::kSeamlessNotPossible);
+ case HwcDisplay::ConfigError::kNone:
+ return ndk::ScopedAStatus::ok();
}
-
- timeline->refreshTimeNanos = hwc2_timeline.refreshTimeNanos;
- timeline->newVsyncAppliedTimeNanos = hwc2_timeline.newVsyncAppliedTimeNanos;
- timeline->refreshRequired = static_cast<bool>(hwc2_timeline.refreshRequired);
- return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ComposerClient::setBootDisplayConfig(int64_t /*display_id*/,
diff --git a/utils/properties.h b/utils/properties.h
index e400236..641df91 100644
--- a/utils/properties.h
+++ b/utils/properties.h
@@ -39,4 +39,37 @@
return static_cast<int>(strlen(value));
}
+/**
+ * Bluntly copied from system/core/libcutils/properties.cpp,
+ * which is part of the Android Project and licensed under Apache 2.
+ * Source:
+ * https://cs.android.com/android/platform/superproject/main/+/main:system/core/libcutils/properties.cpp;l=27
+ */
+auto inline property_get_bool(const char *key, int8_t default_value) -> int8_t {
+ if (!key)
+ return default_value;
+
+ int8_t result = default_value;
+ char buf[PROPERTY_VALUE_MAX] = {};
+
+ int len = property_get(key, buf, "");
+ if (len == 1) {
+ char ch = buf[0];
+ if (ch == '0' || ch == 'n') {
+ result = false;
+ } else if (ch == '1' || ch == 'y') {
+ result = true;
+ }
+ } else if (len > 1) {
+ if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
+ result = false;
+ } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") ||
+ !strcmp(buf, "on")) {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
#endif