xref: /aosp_15_r20/external/drm_hwcomposer/drm/DrmHwc.cpp (revision 0a9764fe0a15e71ebbeb85e87e10990c23aab47f)
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "drmhwc"
18 
19 #include "DrmHwc.h"
20 
21 #include <cinttypes>
22 
23 #include "backend/Backend.h"
24 #include "utils/log.h"
25 #include "utils/properties.h"
26 
27 namespace android {
28 
DrmHwc()29 DrmHwc::DrmHwc() : resource_manager_(this) {};
30 
31 /* Must be called after every display attach/detach cycle */
FinalizeDisplayBinding()32 void DrmHwc::FinalizeDisplayBinding() {
33   if (displays_.count(kPrimaryDisplay) == 0) {
34     /* Primary display MUST always exist */
35     ALOGI("No pipelines available. Creating null-display for headless mode");
36     displays_[kPrimaryDisplay] = std::make_unique<
37         HwcDisplay>(kPrimaryDisplay, HWC2::DisplayType::Physical, this);
38     /* Initializes null-display */
39     displays_[kPrimaryDisplay]->SetPipeline({});
40   }
41 
42   if (displays_[kPrimaryDisplay]->IsInHeadlessMode() &&
43       !display_handles_.empty()) {
44     /* Reattach first secondary display to take place of the primary */
45     auto pipe = display_handles_.begin()->first;
46     ALOGI("Primary display was disconnected, reattaching '%s' as new primary",
47           pipe->connector->Get()->GetName().c_str());
48     UnbindDisplay(pipe);
49     BindDisplay(pipe);
50   }
51 
52   // Finally, send hotplug events to the client
53   for (auto &dhe : deferred_hotplug_events_) {
54     SendHotplugEventToClient(dhe.first, dhe.second);
55   }
56   deferred_hotplug_events_.clear();
57 
58   /* Wait 0.2s before removing the displays to flush pending HWC2 transactions
59    */
60   auto &mutex = GetResMan().GetMainLock();
61   mutex.unlock();
62   const int time_for_sf_to_dispose_display_us = 200000;
63   usleep(time_for_sf_to_dispose_display_us);
64   mutex.lock();
65   for (auto handle : displays_for_removal_list_) {
66     displays_.erase(handle);
67   }
68 }
69 
BindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline)70 bool DrmHwc::BindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
71   if (display_handles_.count(pipeline) != 0) {
72     ALOGE("%s, pipeline is already used by another display, FIXME!!!: %p",
73           __func__, pipeline.get());
74     return false;
75   }
76 
77   uint32_t disp_handle = kPrimaryDisplay;
78 
79   if (displays_.count(kPrimaryDisplay) != 0 &&
80       !displays_[kPrimaryDisplay]->IsInHeadlessMode()) {
81     disp_handle = ++last_display_handle_;
82   }
83 
84   if (displays_.count(disp_handle) == 0) {
85     auto disp = std::make_unique<HwcDisplay>(disp_handle,
86                                              HWC2::DisplayType::Physical, this);
87     displays_[disp_handle] = std::move(disp);
88   }
89 
90   ALOGI("Attaching pipeline '%s' to the display #%d%s",
91         pipeline->connector->Get()->GetName().c_str(), (int)disp_handle,
92         disp_handle == kPrimaryDisplay ? " (Primary)" : "");
93 
94   displays_[disp_handle]->SetPipeline(pipeline);
95   display_handles_[pipeline] = disp_handle;
96 
97   return true;
98 }
99 
UnbindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline)100 bool DrmHwc::UnbindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
101   if (display_handles_.count(pipeline) == 0) {
102     ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline.get());
103     return false;
104   }
105   auto handle = display_handles_[pipeline];
106   display_handles_.erase(pipeline);
107 
108   ALOGI("Detaching the pipeline '%s' from the display #%i%s",
109         pipeline->connector->Get()->GetName().c_str(), (int)handle,
110         handle == kPrimaryDisplay ? " (Primary)" : "");
111 
112   if (displays_.count(handle) == 0) {
113     ALOGE("%s, can't find the display, handle: %" PRIu64, __func__, handle);
114     return false;
115   }
116   displays_[handle]->SetPipeline({});
117 
118   /* We must defer display disposal and removal, since it may still have pending
119    * HWC_API calls scheduled and waiting until ueventlistener thread releases
120    * main lock, otherwise transaction may fail and SF may crash
121    */
122   if (handle != kPrimaryDisplay) {
123     displays_for_removal_list_.emplace_back(handle);
124   }
125   return true;
126 }
127 
NotifyDisplayLinkStatus(std::shared_ptr<DrmDisplayPipeline> pipeline)128 void DrmHwc::NotifyDisplayLinkStatus(
129     std::shared_ptr<DrmDisplayPipeline> pipeline) {
130   if (display_handles_.count(pipeline) == 0) {
131     ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline.get());
132     return;
133   }
134   ScheduleHotplugEvent(display_handles_[pipeline],
135                        DisplayStatus::kLinkTrainingFailed);
136 }
137 
CreateVirtualDisplay(uint32_t width,uint32_t height,int32_t * format,hwc2_display_t * display)138 HWC2::Error DrmHwc::CreateVirtualDisplay(
139     uint32_t width, uint32_t height,
140     int32_t *format,  // NOLINT(readability-non-const-parameter)
141     hwc2_display_t *display) {
142   ALOGI("Creating virtual display %dx%d format %d", width, height, *format);
143 
144   auto virtual_pipeline = resource_manager_.GetVirtualDisplayPipeline();
145   if (!virtual_pipeline)
146     return HWC2::Error::Unsupported;
147 
148   *display = ++last_display_handle_;
149   auto disp = std::make_unique<HwcDisplay>(*display, HWC2::DisplayType::Virtual,
150                                            this);
151 
152   disp->SetVirtualDisplayResolution(width, height);
153   disp->SetPipeline(virtual_pipeline);
154   displays_[*display] = std::move(disp);
155   return HWC2::Error::None;
156 }
157 
DestroyVirtualDisplay(hwc2_display_t display)158 HWC2::Error DrmHwc::DestroyVirtualDisplay(hwc2_display_t display) {
159   ALOGI("Destroying virtual display %" PRIu64, display);
160 
161   if (displays_.count(display) == 0) {
162     ALOGE("Trying to destroy non-existent display %" PRIu64, display);
163     return HWC2::Error::BadDisplay;
164   }
165 
166   displays_[display]->SetPipeline({});
167 
168   /* Wait 0.2s before removing the displays to flush pending HWC2 transactions
169    */
170   auto &mutex = GetResMan().GetMainLock();
171   mutex.unlock();
172   const int time_for_sf_to_dispose_display_us = 200000;
173   usleep(time_for_sf_to_dispose_display_us);
174   mutex.lock();
175 
176   displays_.erase(display);
177 
178   return HWC2::Error::None;
179 }
180 
Dump(uint32_t * out_size,char * out_buffer)181 void DrmHwc::Dump(uint32_t *out_size, char *out_buffer) {
182   if (out_buffer != nullptr) {
183     auto copied_bytes = dump_string_.copy(out_buffer, *out_size);
184     *out_size = static_cast<uint32_t>(copied_bytes);
185     return;
186   }
187 
188   std::stringstream output;
189 
190   output << "-- drm_hwcomposer --\n\n";
191 
192   for (auto &disp : displays_)
193     output << disp.second->Dump();
194 
195   dump_string_ = output.str();
196   *out_size = static_cast<uint32_t>(dump_string_.size());
197 }
198 
GetMaxVirtualDisplayCount()199 uint32_t DrmHwc::GetMaxVirtualDisplayCount() {
200   /* Virtual display is an experimental feature.
201    * Unless explicitly set to true, return 0 for no support.
202    */
203   if (0 == property_get_bool("vendor.hwc.drm.enable_virtual_display", 0)) {
204     return 0;
205   }
206 
207   auto writeback_count = resource_manager_.GetWritebackConnectorsCount();
208   writeback_count = std::min(writeback_count, 1U);
209   /* Currently, only 1 virtual display is supported. Other cases need testing */
210   ALOGI("Max virtual display count: %d", writeback_count);
211   return writeback_count;
212 }
213 
DeinitDisplays()214 void DrmHwc::DeinitDisplays() {
215   for (auto &pair : Displays()) {
216     pair.second->SetPipeline(nullptr);
217   }
218 }
219 
220 }  // namespace android