drm_hwcomposer: Fixes for display hotplug / headless mode
Further testing showed that several issues is still present:
1. Boot without display doesn't work.
2. Unplug/plug primary display has some flaws due to incomplete
HwcDisplay disposal.
3. In case creation of the pipeline fails, hwcomposer crashes.
This commit aims to address them.
Fixes: bb594baa1c68 ("drm_hwcomposer: Rework HwcDisplay disposal to avoid races")
Signed-off-by: Roman Stratiienko <roman.o.stratiienko@globallogic.com>
diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp
index c8235e9..ddf59dd 100644
--- a/drm/ResourceManager.cpp
+++ b/drm/ResourceManager.cpp
@@ -136,8 +136,10 @@
if (connected) {
auto pipeline = DrmDisplayPipeline::CreatePipeline(*conn);
- frontend_interface_->BindDisplay(pipeline.get());
- attached_pipelines_[conn] = std::move(pipeline);
+ if (pipeline) {
+ frontend_interface_->BindDisplay(pipeline.get());
+ attached_pipelines_[conn] = std::move(pipeline);
+ }
} else {
auto &pipeline = attached_pipelines_[conn];
frontend_interface_->UnbindDisplay(pipeline.get());
diff --git a/hwc2_device/DrmHwcTwo.cpp b/hwc2_device/DrmHwcTwo.cpp
index e689419..4accb07 100644
--- a/hwc2_device/DrmHwcTwo.cpp
+++ b/hwc2_device/DrmHwcTwo.cpp
@@ -177,8 +177,14 @@
resource_manager_.Init();
} else {
resource_manager_.DeInit();
- /* Headless display may still be here, remove it */
- displays_.erase(kPrimaryDisplay);
+ /* Headless display may still be here. Remove it! */
+ if (displays_.count(kPrimaryDisplay) != 0) {
+ displays_[kPrimaryDisplay]->Deinit();
+ auto &mutex = GetResMan().GetMainLock();
+ mutex.unlock();
+ displays_.erase(kPrimaryDisplay);
+ mutex.lock();
+ }
}
break;
}
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index cedac19..0f957a7 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -102,24 +102,36 @@
HwcDisplay::~HwcDisplay() = default;
void HwcDisplay::SetPipeline(DrmDisplayPipeline *pipeline) {
+ Deinit();
+
pipeline_ = pipeline;
- if (pipeline != nullptr) {
- ChosePreferredConfig();
+ if (pipeline != nullptr || handle_ == kPrimaryDisplay) {
Init();
-
hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ true);
} else {
- backend_.reset();
- vsync_worker_.Init(nullptr, [](int64_t) {});
- SetClientTarget(nullptr, -1, 0, {});
- if (handle_ != kPrimaryDisplay) {
- hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ false);
- }
+ hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ false);
}
}
+void HwcDisplay::Deinit() {
+ if (pipeline_ != nullptr) {
+ AtomicCommitArgs a_args{};
+ a_args.active = false;
+ a_args.composition = std::make_shared<DrmKmsPlan>();
+ GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
+
+ vsync_worker_.Init(nullptr, [](int64_t) {});
+ current_plan_.reset();
+ backend_.reset();
+ }
+
+ SetClientTarget(nullptr, -1, 0, {});
+}
+
HWC2::Error HwcDisplay::Init() {
+ ChosePreferredConfig();
+
int ret = vsync_worker_.Init(pipeline_, [this](int64_t timestamp) {
const std::lock_guard<std::mutex> lock(hwc2_->GetResMan().GetMainLock());
if (vsync_event_en_) {
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index 98d8e9b..8ff9a92 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -180,6 +180,8 @@
return !pipeline_;
}
+ void Deinit();
+
private:
enum ClientFlattenningState : int32_t {
Disabled = -3,