hwc2: Clean-up asynchronous power mode set
* Avoid blocking wait when checking for secure session.
* Add power state to dummy display.
* Restore exact power mode on ending secure session.
Change-Id: I74fab8fadb8528a15e32aa96b0362ad386bd30cc
CRs-Fixed: 2449460
diff --git a/composer/hwc_display.cpp b/composer/hwc_display.cpp
index 10a9a75..366d5c6 100644
--- a/composer/hwc_display.cpp
+++ b/composer/hwc_display.cpp
@@ -2079,6 +2079,7 @@
if (active_secure_sessions_[kSecureDisplay] != secure_sessions[kSecureDisplay]) {
if (secure_sessions[kSecureDisplay]) {
+ pending_power_mode_ = current_power_mode_;
HWC2::Error error = SetPowerMode(HWC2::PowerMode::Off, true /* teardown */);
if (error != HWC2::Error::None) {
DLOGE("SetPowerMode failed. Error = %d", error);
@@ -2087,9 +2088,9 @@
*power_on_pending = true;
}
- DLOGI("SecureDisplay state changed from %d to %d for display %d",
+ DLOGI("SecureDisplay state changed from %d to %d for display %d-%d",
active_secure_sessions_.test(kSecureDisplay), secure_sessions.test(kSecureDisplay),
- type_);
+ id_, type_);
}
active_secure_sessions_ = secure_sessions;
return 0;
diff --git a/composer/hwc_display.h b/composer/hwc_display.h
index 4baa778..9a0f9e7 100644
--- a/composer/hwc_display.h
+++ b/composer/hwc_display.h
@@ -356,6 +356,12 @@
virtual void GetLayerStack(HWCLayerStack *stack);
virtual void SetLayerStack(HWCLayerStack *stack);
virtual void PostPowerMode();
+ virtual HWC2::PowerMode GetPendingPowerMode() {
+ return pending_power_mode_;
+ };
+ virtual void ClearPendingPowerMode() {
+ pending_power_mode_ = current_power_mode_;
+ };
protected:
static uint32_t throttling_refresh_rate_;
@@ -415,6 +421,7 @@
uint32_t dump_frame_index_ = 0;
bool dump_input_layers_ = false;
HWC2::PowerMode current_power_mode_ = HWC2::PowerMode::Off;
+ HWC2::PowerMode pending_power_mode_ = HWC2::PowerMode::Off;
bool swap_interval_zero_ = false;
bool display_paused_ = false;
uint32_t min_refresh_rate_ = 0;
diff --git a/composer/hwc_display_builtin.cpp b/composer/hwc_display_builtin.cpp
index 40a3ac3..d3e8785 100644
--- a/composer/hwc_display_builtin.cpp
+++ b/composer/hwc_display_builtin.cpp
@@ -127,6 +127,8 @@
DLOGI("Drop redundant drawcycles %d", id_);
}
+ is_primary_ = display_intf_->IsPrimaryDisplay();
+
return status;
}
@@ -136,7 +138,7 @@
DTRACE_SCOPED();
- if (display_paused_) {
+ if (display_paused_ || (!is_primary_ && active_secure_sessions_[kSecureDisplay])) {
MarkLayersForGPUBypass();
return status;
}
@@ -244,7 +246,10 @@
auto status = HWC2::Error::None;
DTRACE_SCOPED();
- if (display_paused_) {
+
+ if (!is_primary_ && active_secure_sessions_[kSecureDisplay]) {
+ return status;
+ } else if (display_paused_) {
DisplayError error = display_intf_->Flush(&layer_stack_);
validated_ = false;
if (error != kErrorNone) {
@@ -594,6 +599,10 @@
return -EINVAL;
}
+ if (!is_primary_) {
+ return HWCDisplay::HandleSecureSession(secure_sessions, power_on_pending);
+ }
+
if (current_power_mode_ != HWC2::PowerMode::On) {
return 0;
}
@@ -607,9 +616,9 @@
return err;
}
- DLOGI("SecureDisplay state changed from %d to %d for display %d",
+ DLOGI("SecureDisplay state changed from %d to %d for display %d-%d",
active_secure_sessions_.test(kSecureDisplay), secure_sessions.test(kSecureDisplay),
- type_);
+ id_, type_);
}
active_secure_sessions_ = secure_sessions;
*power_on_pending = false;
diff --git a/composer/hwc_display_builtin.h b/composer/hwc_display_builtin.h
index fa0b859..0047ae9 100644
--- a/composer/hwc_display_builtin.h
+++ b/composer/hwc_display_builtin.h
@@ -139,6 +139,7 @@
// Members for 1 frame capture in a client provided buffer
bool frame_capture_buffer_queued_ = false;
int frame_capture_status_ = -EAGAIN;
+ bool is_primary_ = false;
};
} // namespace sdm
diff --git a/composer/hwc_display_dummy.cpp b/composer/hwc_display_dummy.cpp
index fac6370..eff0ed6 100644
--- a/composer/hwc_display_dummy.cpp
+++ b/composer/hwc_display_dummy.cpp
@@ -82,4 +82,9 @@
return HWC2::Error::None;
}
+HWC2::Error HWCDisplayDummy::UpdatePowerMode(HWC2::PowerMode mode) {
+ current_power_mode_ = mode;
+ return HWC2::Error::None;
+}
+
} // namespace sdm
diff --git a/composer/hwc_display_dummy.h b/composer/hwc_display_dummy.h
index 29e04f4..bf28a03 100644
--- a/composer/hwc_display_dummy.h
+++ b/composer/hwc_display_dummy.h
@@ -45,6 +45,7 @@
virtual HWC2::Error Validate(uint32_t *out_num_types, uint32_t *out_num_requests);
virtual HWC2::Error Present(int32_t *out_retire_fence);
virtual HWC2::Error GetActiveConfig(hwc2_config_t *out_config);
+ virtual HWC2::Error UpdatePowerMode(HWC2::PowerMode mode);
private:
HWCDisplayDummy(CoreInterface *core_intf, BufferAllocator *buffer_allocator,
diff --git a/composer/hwc_session.cpp b/composer/hwc_session.cpp
index 6af6b16..b09a6e9 100644
--- a/composer/hwc_session.cpp
+++ b/composer/hwc_session.cpp
@@ -55,7 +55,7 @@
static HWCUEvent g_hwc_uevent_;
Locker HWCSession::locker_[HWCCallbacks::kNumDisplays];
-bool HWCSession::power_on_pending_[HWCCallbacks::kNumDisplays];
+bool HWCSession::pending_power_mode_[HWCCallbacks::kNumDisplays];
Locker HWCSession::power_state_[HWCCallbacks::kNumDisplays];
Locker HWCSession::display_config_locker_;
static const int kSolidFillDelay = 100 * 1000;
@@ -179,7 +179,7 @@
g_hwc_uevent_.Register(this);
}
- int value = 0;
+ int value = 1; // Default value when property is not present.
Debug::Get()->GetProperty(ENABLE_ASYNC_POWERMODE, &value);
async_powermode_ = (value == 1);
DLOGI("builtin_powermode_override: %d", async_powermode_);
@@ -621,18 +621,22 @@
}
HandleSecureSession();
+
+
+ hwc2_display_t target_display = display;
+
{
SCOPE_LOCK(power_state_[display]);
if (power_state_transition_[display]) {
// Route all interactions with client to dummy display.
- display = map_hwc_display_.find(display)->second;
+ target_display = map_hwc_display_.find(display)->second;
}
}
{
- SEQUENCE_EXIT_SCOPE_LOCK(locker_[display]);
- if (!hwc_display_[display]) {
- DLOGW("Removed Display : display = %" PRIu64, display);
+ SEQUENCE_EXIT_SCOPE_LOCK(locker_[target_display]);
+ if (!hwc_display_[target_display]) {
+ DLOGW("Removed Display : display = %" PRIu64, target_display);
return HWC2_ERROR_BAD_DISPLAY;
}
@@ -640,27 +644,27 @@
return HWC2_ERROR_BAD_PARAMETER;
}
- if (power_on_pending_[display]) {
+ if (pending_power_mode_[display]) {
status = HWC2::Error::None;
} else {
- status = PresentDisplayInternal(display, out_retire_fence);
+ status = PresentDisplayInternal(target_display, out_retire_fence);
if (status == HWC2::Error::None) {
// Check if hwc's refresh trigger is getting exercised.
if (callbacks_.NeedsRefresh(display)) {
- hwc_display_[display]->SetPendingRefresh();
+ hwc_display_[target_display]->SetPendingRefresh();
callbacks_.ResetRefresh(display);
}
- status = hwc_display_[display]->Present(out_retire_fence);
+ status = hwc_display_[target_display]->Present(out_retire_fence);
}
}
}
if (status != HWC2::Error::None && status != HWC2::Error::NotValidated) {
- SEQUENCE_CANCEL_SCOPE_LOCK(locker_[display]);
+ SEQUENCE_CANCEL_SCOPE_LOCK(locker_[target_display]);
}
- HandlePowerOnPending(display, *out_retire_fence);
- HandleHotplugPending(display, *out_retire_fence);
+ HandlePendingPowerMode(display, *out_retire_fence);
+ HandlePendingHotplug(display, *out_retire_fence);
HandlePendingRefresh();
cwb_.PresentDisplayDone(display);
display_ready_.set(UINT32(display));
@@ -707,7 +711,7 @@
int32_t err = HandlePluggableDisplays(false);
if (err) {
DLOGW("All displays could not be created. Error %d '%s'. Hotplug handling %s.", err,
- strerror(abs(err)), hotplug_pending_event_ == kHotPlugEvent ? "deferred" :
+ strerror(abs(err)), pending_hotplug_event_ == kHotPlugEvent ? "deferred" :
"dropped");
}
client_connected_ = true;
@@ -868,7 +872,7 @@
return HWC2_ERROR_BAD_PARAMETER;
}
- if (power_on_pending_[display]) {
+ if (pending_power_mode_[display]) {
DLOGW("Set power mode is not allowed during secure display session");
return HWC2_ERROR_UNSUPPORTED;
}
@@ -895,7 +899,7 @@
return INT32(error);
}
} else {
- SCOPE_LOCK(locker_[display]);
+ Locker::ScopeLock lock_disp(locker_[display]);
// Update hwc state for now. Actual poweron will handled through DisplayConfig.
hwc_display_[display]->UpdatePowerMode(mode);
}
@@ -959,11 +963,13 @@
return HWC2_ERROR_BAD_DISPLAY;
}
+ hwc2_display_t target_display = display;
+
{
SCOPE_LOCK(power_state_[display]);
if (power_state_transition_[display]) {
// Route all interactions with client to dummy display.
- display = map_hwc_display_.find(display)->second;
+ target_display = map_hwc_display_.find(display)->second;
}
}
DTRACE_SCOPED();
@@ -971,18 +977,23 @@
auto status = HWC2::Error::BadDisplay;
HandleSecureSession();
{
- SEQUENCE_ENTRY_SCOPE_LOCK(locker_[display]);
- if (power_on_pending_[display]) {
+ SEQUENCE_ENTRY_SCOPE_LOCK(locker_[target_display]);
+ if (pending_power_mode_[display]) {
status = HWC2::Error::None;
- } else if (hwc_display_[display]) {
- hwc_display_[display]->SetFastPathComposition(false);
- status = ValidateDisplayInternal(display, out_num_types, out_num_requests);
+ } else if (hwc_display_[target_display]) {
+ hwc_display_[target_display]->SetFastPathComposition(false);
+ status = ValidateDisplayInternal(target_display, out_num_types, out_num_requests);
}
}
// Sequence locking currently begins on Validate, so cancel the sequence lock on failures
if (status != HWC2::Error::None && status != HWC2::Error::HasChanges) {
- SEQUENCE_CANCEL_SCOPE_LOCK(locker_[display]);
+ SEQUENCE_CANCEL_SCOPE_LOCK(locker_[target_display]);
+ }
+
+ if (display != target_display) {
+ // Validate done on a dummy display. Assume present is complete.
+ SEQUENCE_EXIT_SCOPE_LOCK(locker_[target_display]);
}
return INT32(status);
@@ -2125,13 +2136,13 @@
// Defer hotplug handling.
SCOPE_LOCK(pluggable_handler_lock_);
DLOGI("Marking hotplug pending...");
- hotplug_pending_event_ = kHotPlugEvent;
+ pending_hotplug_event_ = kHotPlugEvent;
} else {
// Handle hotplug.
int32_t err = HandlePluggableDisplays(true);
if (err) {
DLOGW("Hotplug handling failed. Error %d '%s'. Hotplug handling %s.", err,
- strerror(abs(err)), (hotplug_pending_event_ == kHotPlugEvent) ?
+ strerror(abs(err)), (pending_hotplug_event_ == kHotPlugEvent) ?
"deferred" : "dropped");
}
}
@@ -2373,20 +2384,20 @@
case -EAGAIN:
case -ENODEV:
// Errors like device removal or deferral for which we want to try another hotplug handling.
- hotplug_pending_event_ = kHotPlugEvent;
+ pending_hotplug_event_ = kHotPlugEvent;
status = 0;
break;
default:
// Real errors we want to flag and stop hotplug handling.
- hotplug_pending_event_ = kHotPlugNone;
+ pending_hotplug_event_ = kHotPlugNone;
DLOGE("All displays could not be connected. Error %d '%s'.", status, strerror(abs(status)));
}
- DLOGI("Handling hotplug... %s", (kHotPlugNone ==hotplug_pending_event_) ?
+ DLOGI("Handling hotplug... %s", (kHotPlugNone == pending_hotplug_event_) ?
"Stopped." : "Done. Hotplug events pending.");
return status;
}
- hotplug_pending_event_ = kHotPlugNone;
+ pending_hotplug_event_ = kHotPlugNone;
DLOGI("Handling hotplug... Done.");
return 0;
@@ -2758,44 +2769,63 @@
void HWCSession::HandleSecureSession() {
std::bitset<kSecureMax> secure_sessions = 0;
{
+ // TODO(user): Revisit if supporting secure display on non-primary.
hwc2_display_t active_builtin_disp_id = GetActiveBuiltinDisplay();
if (active_builtin_disp_id >= HWCCallbacks::kNumDisplays) {
return;
}
- Locker::ScopeLock lock_a(locker_[active_builtin_disp_id]);
+ Locker::ScopeLock lock_pwr(power_state_[active_builtin_disp_id]);
+ if (power_state_transition_[active_builtin_disp_id]) {
+ // Route all interactions with client to dummy display.
+ active_builtin_disp_id = map_hwc_display_.find(active_builtin_disp_id)->second;
+ }
+ Locker::ScopeLock lock_d(locker_[active_builtin_disp_id]);
hwc_display_[active_builtin_disp_id]->GetActiveSecureSession(&secure_sessions);
}
+ if (secure_sessions.any()) {
+ secure_session_active_ = true;
+ } else if (!secure_session_active_) {
+ // No secure session active. No secure session transition to handle. Skip remaining steps.
+ return;
+ }
+
// If it is called during primary prepare/commit, we need to pause any ongoing commit on
// external/virtual display.
for (hwc2_display_t display = HWC_DISPLAY_PRIMARY;
display < HWCCallbacks::kNumDisplays; display++) {
Locker::ScopeLock lock_d(locker_[display]);
if (hwc_display_[display]) {
- hwc_display_[display]->HandleSecureSession(secure_sessions, &power_on_pending_[display]);
+ hwc_display_[display]->HandleSecureSession(secure_sessions, &pending_power_mode_[display]);
}
}
}
-void HWCSession::HandlePowerOnPending(hwc2_display_t disp_id, int retire_fence) {
+void HWCSession::HandlePendingPowerMode(hwc2_display_t disp_id, int retire_fence) {
+ if (!secure_session_active_) {
+ // No secure session active. Skip remaining steps.
+ return;
+ }
+
hwc2_display_t active_builtin_disp_id = GetActiveBuiltinDisplay();
if (disp_id != active_builtin_disp_id) {
return;
}
- Locker::ScopeLock lock_a(locker_[active_builtin_disp_id]);
- bool power_on_pending = false;
- for (hwc2_display_t display = HWC_DISPLAY_PRIMARY;
+
+ Locker::ScopeLock lock_d(locker_[active_builtin_disp_id]);
+ bool pending_power_mode = false;
+ for (hwc2_display_t display = HWC_DISPLAY_PRIMARY + 1;
display < HWCCallbacks::kNumDisplays; display++) {
if (display != active_builtin_disp_id) {
Locker::ScopeLock lock_d(locker_[display]);
- if (power_on_pending_[display]) {
- power_on_pending = true;
+ if (pending_power_mode_[display]) {
+ pending_power_mode = true;
break;
}
}
}
- if (power_on_pending) {
+ if (pending_power_mode) {
// retire fence is set only after successful primary commit, So check for retire fence to know
// non secure commit went through to notify driver to change the CRTC mode to non secure.
// Otherwise any commit to non-primary display would fail.
@@ -2810,31 +2840,36 @@
return;
}
- for (hwc2_display_t display = HWC_DISPLAY_PRIMARY;
+ for (hwc2_display_t display = HWC_DISPLAY_PRIMARY + 1;
display < HWCCallbacks::kNumDisplays; display++) {
if (display != active_builtin_disp_id) {
Locker::ScopeLock lock_d(locker_[display]);
- if (power_on_pending_[display] && hwc_display_[display]) {
- HWC2::Error status =
- hwc_display_[display]->SetPowerMode(HWC2::PowerMode::On, false /* teardown */);
- if (status == HWC2::Error::None) {
- power_on_pending_[display] = false;
+ if (pending_power_mode_[display] && hwc_display_[display]) {
+ HWC2::Error error =
+ hwc_display_[display]->SetPowerMode(hwc_display_[display]->GetPendingPowerMode(), false);
+ if (HWC2::Error::None == error) {
+ pending_power_mode_[display] = false;
+ hwc_display_[display]->ClearPendingPowerMode();
+ pending_refresh_.set(UINT32(HWC_DISPLAY_PRIMARY));
+ } else {
+ DLOGE("SetDisplayStatus error = %d (%s)", error, to_string(error).c_str());
}
}
}
}
+ secure_session_active_ = false;
}
-void HWCSession::HandleHotplugPending(hwc2_display_t disp_id, int retire_fence) {
+void HWCSession::HandlePendingHotplug(hwc2_display_t disp_id, int retire_fence) {
hwc2_display_t active_builtin_disp_id = GetActiveBuiltinDisplay();
if (disp_id != active_builtin_disp_id ||
- (kHotPlugNone == hotplug_pending_event_ && !destroy_virtual_disp_pending_)) {
+ (kHotPlugNone == pending_hotplug_event_ && !destroy_virtual_disp_pending_)) {
return;
}
std :: bitset < kSecureMax > secure_sessions = 0;
if (active_builtin_disp_id < HWCCallbacks::kNumDisplays) {
- Locker::ScopeLock lock_a(locker_[active_builtin_disp_id]);
+ Locker::ScopeLock lock_d(locker_[active_builtin_disp_id]);
hwc_display_[active_builtin_disp_id]->GetActiveSecureSession(&secure_sessions);
}
@@ -2842,7 +2877,7 @@
return;
}
- if (destroy_virtual_disp_pending_ || kHotPlugEvent == hotplug_pending_event_) {
+ if (destroy_virtual_disp_pending_ || kHotPlugEvent == pending_hotplug_event_) {
if (retire_fence >= 0) {
int error = sync_wait(retire_fence, 1000);
if (error < 0) {
@@ -2858,7 +2893,7 @@
}
// Handle connect/disconnect hotplugs if secure session is not present.
hwc2_display_t virtual_display_idx = (hwc2_display_t)GetDisplayIndex(qdutils::DISPLAY_VIRTUAL);
- if (!hwc_display_[virtual_display_idx] && kHotPlugEvent == hotplug_pending_event_) {
+ if (!hwc_display_[virtual_display_idx] && kHotPlugEvent == pending_hotplug_event_) {
// Handle deferred hotplug event.
int32_t err = pluggable_handler_lock_.TryLock();
if (!err) {
@@ -3055,21 +3090,27 @@
}
hwc2_display_t HWCSession::GetActiveBuiltinDisplay() {
- hwc2_display_t disp_id = HWCCallbacks::kNumDisplays;
+ hwc2_display_t active_display = HWCCallbacks::kNumDisplays;
// Get first active display among primary and built-in displays.
std::vector<DisplayMapInfo> map_info = {map_info_primary_};
std::copy(map_info_builtin_.begin(), map_info_builtin_.end(), std::back_inserter(map_info));
for (auto &info : map_info) {
- SCOPE_LOCK(locker_[info.client_id]);
- auto &hwc_display = hwc_display_[info.client_id];
+ hwc2_display_t target_display = info.client_id;
+ SCOPE_LOCK(power_state_[target_display]);
+ if (power_state_transition_[target_display]) {
+ // Route all interactions with client to dummy display.
+ target_display = map_hwc_display_.find(target_display)->second;
+ }
+ Locker::ScopeLock lock_d(locker_[target_display]);
+ auto &hwc_display = hwc_display_[target_display];
if (hwc_display && hwc_display->GetCurrentPowerMode() != HWC2::PowerMode::Off) {
- disp_id = info.client_id;
+ active_display = info.client_id;
break;
}
}
- return disp_id;
+ return active_display;
}
int32_t HWCSession::SetDisplayBrightnessScale(const android::Parcel *input_parcel) {
diff --git a/composer/hwc_session.h b/composer/hwc_session.h
index de8d4cd..e5199d9 100644
--- a/composer/hwc_session.h
+++ b/composer/hwc_session.h
@@ -434,8 +434,8 @@
uint32_t *out_num_requests);
HWC2::Error PresentDisplayInternal(hwc2_display_t display, int32_t *out_retire_fence);
void HandleSecureSession();
- void HandlePowerOnPending(hwc2_display_t display, int retire_fence);
- void HandleHotplugPending(hwc2_display_t disp_id, int retire_fence);
+ void HandlePendingPowerMode(hwc2_display_t display, int retire_fence);
+ void HandlePendingHotplug(hwc2_display_t disp_id, int retire_fence);
bool IsPluggableDisplayConnected();
hwc2_display_t GetActiveBuiltinDisplay();
void HandlePendingRefresh();
@@ -467,9 +467,9 @@
std::mutex mutex_lum_;
int hpd_bpp_ = 0;
int hpd_pattern_ = 0;
- static bool power_on_pending_[HWCCallbacks::kNumDisplays];
+ static bool pending_power_mode_[HWCCallbacks::kNumDisplays];
static int null_display_mode_;
- HotPlugEvent hotplug_pending_event_ = kHotPlugNone;
+ HotPlugEvent pending_hotplug_event_ = kHotPlugNone;
Locker pluggable_handler_lock_;
bool destroy_virtual_disp_pending_ = false;
uint32_t idle_pc_ref_cnt_ = 0;
@@ -482,6 +482,7 @@
bool async_powermode_ = false;
bool power_state_transition_[HWCCallbacks::kNumDisplays] = {};
std::bitset<HWCCallbacks::kNumDisplays> display_ready_;
+ bool secure_session_active_ = false;
};
} // namespace sdm
diff --git a/composer/hwc_session_services.cpp b/composer/hwc_session_services.cpp
index 898316e..afd60db 100644
--- a/composer/hwc_session_services.cpp
+++ b/composer/hwc_session_services.cpp
@@ -659,6 +659,7 @@
hwc_display_[disp_id]->GetLayerStack(&stack);
// Update the same stack onto dummy display.
hwc_display_[dummy_disp_id]->SetLayerStack(&stack);
+ hwc_display_[dummy_disp_id]->UpdatePowerMode(hwc_display_[disp_id]->GetCurrentPowerMode());
}
{