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,
|
||||
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();
|
||||
};
|
||||
|
||||
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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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*/,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue