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:
parent
85be25d045
commit
8998f8b04a
4 changed files with 83 additions and 25 deletions
|
|
@ -46,3 +46,12 @@ enum PanelOrientation {
|
||||||
kModePanelOrientationLeftUp,
|
kModePanelOrientationLeftUp,
|
||||||
kModePanelOrientationRightUp
|
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;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ HwcDisplay::~HwcDisplay() {
|
||||||
Deinit();
|
Deinit();
|
||||||
};
|
};
|
||||||
|
|
||||||
const HwcDisplayConfig *HwcDisplay::GetCurrentConfig() const {
|
auto HwcDisplay::GetCurrentConfig() const -> const HwcDisplayConfig * {
|
||||||
auto config_iter = configs_.hwc_configs.find(configs_.active_config_id);
|
auto config_iter = configs_.hwc_configs.find(configs_.active_config_id);
|
||||||
if (config_iter == configs_.hwc_configs.end()) {
|
if (config_iter == configs_.hwc_configs.end()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -104,7 +104,7 @@ const HwcDisplayConfig *HwcDisplay::GetCurrentConfig() const {
|
||||||
return &config_iter->second;
|
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_);
|
auto config_iter = configs_.hwc_configs.find(staged_mode_config_id_);
|
||||||
if (config_iter == configs_.hwc_configs.end()) {
|
if (config_iter == configs_.hwc_configs.end()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -112,6 +112,42 @@ const HwcDisplayConfig *HwcDisplay::GetLastRequestedConfig() const {
|
||||||
return &config_iter->second;
|
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) {
|
void HwcDisplay::SetPipeline(std::shared_ptr<DrmDisplayPipeline> pipeline) {
|
||||||
Deinit();
|
Deinit();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,13 @@ inline constexpr uint32_t kPrimaryDisplay = 0;
|
||||||
// NOLINTNEXTLINE
|
// NOLINTNEXTLINE
|
||||||
class HwcDisplay {
|
class HwcDisplay {
|
||||||
public:
|
public:
|
||||||
|
enum ConfigError {
|
||||||
|
kNone,
|
||||||
|
kBadConfig,
|
||||||
|
kSeamlessNotAllowed,
|
||||||
|
kSeamlessNotPossible
|
||||||
|
};
|
||||||
|
|
||||||
HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type, DrmHwc *hwc);
|
HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type, DrmHwc *hwc);
|
||||||
HwcDisplay(const HwcDisplay &) = delete;
|
HwcDisplay(const HwcDisplay &) = delete;
|
||||||
~HwcDisplay();
|
~HwcDisplay();
|
||||||
|
|
@ -60,12 +67,16 @@ class HwcDisplay {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the config representing the mode that has been committed to KMS.
|
// 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
|
// Get the config that was last requested through SetActiveConfig and similar
|
||||||
// functions. This may differ from the GetCurrentConfig if the config change
|
// functions. This may differ from the GetCurrentConfig if the config change
|
||||||
// is queued up to take effect in the future.
|
// 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 Hooks - these should not be used outside of the hwc2 device.
|
||||||
HWC2::Error AcceptDisplayChanges();
|
HWC2::Error AcceptDisplayChanges();
|
||||||
|
|
|
||||||
|
|
@ -1051,13 +1051,14 @@ ndk::ScopedAStatus ComposerClient::registerCallback(
|
||||||
ndk::ScopedAStatus ComposerClient::setActiveConfig(int64_t display_id,
|
ndk::ScopedAStatus ComposerClient::setActiveConfig(int64_t display_id,
|
||||||
int32_t config) {
|
int32_t config) {
|
||||||
DEBUG_FUNC();
|
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(
|
ndk::ScopedAStatus ComposerClient::setActiveConfigWithConstraints(
|
||||||
|
|
@ -1071,23 +1072,24 @@ ndk::ScopedAStatus ComposerClient::setActiveConfigWithConstraints(
|
||||||
return ToBinderStatus(hwc3::Error::kBadDisplay);
|
return ToBinderStatus(hwc3::Error::kBadDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
hwc_vsync_period_change_constraints_t hwc2_constraints;
|
::QueuedConfigTiming timing{};
|
||||||
hwc2_constraints.desiredTimeNanos = constraints.desiredTimeNanos;
|
HwcDisplay::ConfigError
|
||||||
hwc2_constraints.seamlessRequired = static_cast<uint8_t>(
|
result = display->QueueConfig(config, constraints.desiredTimeNanos,
|
||||||
constraints.seamlessRequired);
|
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{};
|
switch (result) {
|
||||||
auto error = Hwc2toHwc3Error(
|
case HwcDisplay::ConfigError::kBadConfig:
|
||||||
display->SetActiveConfigWithConstraints(config, &hwc2_constraints,
|
return ToBinderStatus(hwc3::Error::kBadConfig);
|
||||||
&hwc2_timeline));
|
case HwcDisplay::ConfigError::kSeamlessNotAllowed:
|
||||||
if (error != hwc3::Error::kNone) {
|
return ToBinderStatus(hwc3::Error::kSeamlessNotAllowed);
|
||||||
return ToBinderStatus(error);
|
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*/,
|
ndk::ScopedAStatus ComposerClient::setBootDisplayConfig(int64_t /*display_id*/,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue