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