1
0
Fork 0

drm_hwcomposer: Deprecate usage of HWC2 setActiveConfig*

Setting a config is currently implemented by queuing a config change to
take effect at the next vsync. Add HwcDisplay::QueueConfig to support
this functionality, which is implemented using the HWC2
setActiveConfigWithConstraints and setActiveConfigInternal as a
reference.

Implement HWC3 setActiveConfig and setActiveConfigWithConstraints in
terms of HwcDisplay::QueueConfig.

Change-Id: I127f569fe889e7370de1987137345b5b75ff04b6
Signed-off-by: Drew Davenport <ddavenport@google.com>
This commit is contained in:
Drew Davenport 2024-10-24 10:15:12 -06:00
parent 85be25d045
commit 8998f8b04a
4 changed files with 83 additions and 25 deletions

View file

@ -46,3 +46,12 @@ enum PanelOrientation {
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;
};

View file

@ -96,7 +96,7 @@ HwcDisplay::~HwcDisplay() {
Deinit();
};
const HwcDisplayConfig *HwcDisplay::GetCurrentConfig() const {
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;
@ -104,7 +104,7 @@ const HwcDisplayConfig *HwcDisplay::GetCurrentConfig() const {
return &config_iter->second;
}
const HwcDisplayConfig *HwcDisplay::GetLastRequestedConfig() const {
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;
@ -112,6 +112,42 @@ const HwcDisplayConfig *HwcDisplay::GetLastRequestedConfig() const {
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();

View file

@ -41,6 +41,13 @@ inline constexpr uint32_t kPrimaryDisplay = 0;
// 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();
@ -60,12 +67,16 @@ class HwcDisplay {
}
// Get the config representing the mode that has been committed to KMS.
const HwcDisplayConfig *GetCurrentConfig() const;
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.
const HwcDisplayConfig *GetLastRequestedConfig() const;
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();

View file

@ -1051,13 +1051,14 @@ ndk::ScopedAStatus ComposerClient::registerCallback(
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(
@ -1071,23 +1072,24 @@ ndk::ScopedAStatus ComposerClient::setActiveConfigWithConstraints(
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*/,