• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 "hwc-drm-two"
18 
19 #include "DrmHwcTwo.h"
20 
21 #include <cinttypes>
22 
23 #include "backend/Backend.h"
24 #include "utils/log.h"
25 
26 namespace android {
27 
DrmHwcTwo()28 DrmHwcTwo::DrmHwcTwo() : resource_manager_(this){};
29 
30 /* Must be called after every display attach/detach cycle */
FinalizeDisplayBinding()31 void DrmHwcTwo::FinalizeDisplayBinding() {
32   if (displays_.count(kPrimaryDisplay) == 0) {
33     /* Primary display MUST always exist */
34     ALOGI("No pipelines available. Creating null-display for headless mode");
35     displays_[kPrimaryDisplay] = std::make_unique<
36         HwcDisplay>(kPrimaryDisplay, HWC2::DisplayType::Physical, this);
37     /* Initializes null-display */
38     displays_[kPrimaryDisplay]->SetPipeline(nullptr);
39   }
40 
41   if (displays_[kPrimaryDisplay]->IsInHeadlessMode() &&
42       !display_handles_.empty()) {
43     /* Reattach first secondary display to take place of the primary */
44     auto *pipe = display_handles_.begin()->first;
45     ALOGI("Primary display was disconnected, reattaching '%s' as new primary",
46           pipe->connector->Get()->GetName().c_str());
47     UnbindDisplay(pipe);
48     BindDisplay(pipe);
49   }
50 
51   // Finally, send hotplug events to the client
52   for (auto &dhe : deferred_hotplug_events_) {
53     SendHotplugEventToClient(dhe.first, dhe.second);
54   }
55   deferred_hotplug_events_.clear();
56 
57   /* Wait 0.2s before removing the displays to flush pending HWC2 transactions
58    */
59   auto &mutex = GetResMan().GetMainLock();
60   mutex.unlock();
61   const int kTimeForSFToDisposeDisplayUs = 200000;
62   usleep(kTimeForSFToDisposeDisplayUs);
63   mutex.lock();
64   std::vector<std::unique_ptr<HwcDisplay>> for_disposal;
65   for (auto handle : displays_for_removal_list_) {
66     for_disposal.emplace_back(
67         std::unique_ptr<HwcDisplay>(displays_[handle].release()));
68     displays_.erase(handle);
69   }
70   /* Destroy HwcDisplays while unlocked to avoid vsyncworker deadlocks */
71   mutex.unlock();
72   for_disposal.clear();
73   mutex.lock();
74 }
75 
BindDisplay(DrmDisplayPipeline * pipeline)76 bool DrmHwcTwo::BindDisplay(DrmDisplayPipeline *pipeline) {
77   if (display_handles_.count(pipeline) != 0) {
78     ALOGE("%s, pipeline is already used by another display, FIXME!!!: %p",
79           __func__, pipeline);
80     return false;
81   }
82 
83   uint32_t disp_handle = kPrimaryDisplay;
84 
85   if (displays_.count(kPrimaryDisplay) != 0 &&
86       !displays_[kPrimaryDisplay]->IsInHeadlessMode()) {
87     disp_handle = ++last_display_handle_;
88   }
89 
90   if (displays_.count(disp_handle) == 0) {
91     auto disp = std::make_unique<HwcDisplay>(disp_handle,
92                                              HWC2::DisplayType::Physical, this);
93     displays_[disp_handle] = std::move(disp);
94   }
95 
96   ALOGI("Attaching pipeline '%s' to the display #%d%s",
97         pipeline->connector->Get()->GetName().c_str(), (int)disp_handle,
98         disp_handle == kPrimaryDisplay ? " (Primary)" : "");
99 
100   displays_[disp_handle]->SetPipeline(pipeline);
101   display_handles_[pipeline] = disp_handle;
102 
103   return true;
104 }
105 
UnbindDisplay(DrmDisplayPipeline * pipeline)106 bool DrmHwcTwo::UnbindDisplay(DrmDisplayPipeline *pipeline) {
107   if (display_handles_.count(pipeline) == 0) {
108     ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline);
109     return false;
110   }
111   auto handle = display_handles_[pipeline];
112   display_handles_.erase(pipeline);
113 
114   ALOGI("Detaching the pipeline '%s' from the display #%i%s",
115         pipeline->connector->Get()->GetName().c_str(), (int)handle,
116         handle == kPrimaryDisplay ? " (Primary)" : "");
117 
118   if (displays_.count(handle) == 0) {
119     ALOGE("%s, can't find the display, handle: %" PRIu64, __func__, handle);
120     return false;
121   }
122   displays_[handle]->SetPipeline(nullptr);
123 
124   /* We must defer display disposal and removal, since it may still have pending
125    * HWC_API calls scheduled and waiting until ueventlistener thread releases
126    * main lock, otherwise transaction may fail and SF may crash
127    */
128   if (handle != kPrimaryDisplay) {
129     displays_for_removal_list_.emplace_back(handle);
130   }
131   return true;
132 }
133 
CreateVirtualDisplay(uint32_t,uint32_t,int32_t *,hwc2_display_t *)134 HWC2::Error DrmHwcTwo::CreateVirtualDisplay(uint32_t /*width*/,
135                                             uint32_t /*height*/,
136                                             int32_t * /*format*/,
137                                             hwc2_display_t * /*display*/) {
138   // TODO(nobody): Implement virtual display
139   return HWC2::Error::Unsupported;
140 }
141 
DestroyVirtualDisplay(hwc2_display_t)142 HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t /*display*/) {
143   // TODO(nobody): Implement virtual display
144   return HWC2::Error::Unsupported;
145 }
146 
Dump(uint32_t * outSize,char * outBuffer)147 void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) {
148   if (outBuffer != nullptr) {
149     auto copied_bytes = mDumpString.copy(outBuffer, *outSize);
150     *outSize = static_cast<uint32_t>(copied_bytes);
151     return;
152   }
153 
154   std::stringstream output;
155 
156   output << "-- drm_hwcomposer --\n\n";
157 
158   for (auto &disp : displays_)
159     output << disp.second->Dump();
160 
161   mDumpString = output.str();
162   *outSize = static_cast<uint32_t>(mDumpString.size());
163 }
164 
GetMaxVirtualDisplayCount()165 uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() {
166   // TODO(nobody): Implement virtual display
167   return 0;
168 }
169 
RegisterCallback(int32_t descriptor,hwc2_callback_data_t data,hwc2_function_pointer_t function)170 HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
171                                         hwc2_callback_data_t data,
172                                         hwc2_function_pointer_t function) {
173   switch (static_cast<HWC2::Callback>(descriptor)) {
174     case HWC2::Callback::Hotplug: {
175       hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data);
176       if (function != nullptr) {
177         resource_manager_.Init();
178       } else {
179         resource_manager_.DeInit();
180         /* Headless display may still be here. Remove it! */
181         if (displays_.count(kPrimaryDisplay) != 0) {
182           displays_[kPrimaryDisplay]->Deinit();
183           auto &mutex = GetResMan().GetMainLock();
184           mutex.unlock();
185           displays_.erase(kPrimaryDisplay);
186           mutex.lock();
187         }
188       }
189       break;
190     }
191     case HWC2::Callback::Refresh: {
192       refresh_callback_ = std::make_pair(HWC2_PFN_REFRESH(function), data);
193       break;
194     }
195     case HWC2::Callback::Vsync: {
196       vsync_callback_ = std::make_pair(HWC2_PFN_VSYNC(function), data);
197       break;
198     }
199 #if PLATFORM_SDK_VERSION > 29
200     case HWC2::Callback::Vsync_2_4: {
201       vsync_2_4_callback_ = std::make_pair(HWC2_PFN_VSYNC_2_4(function), data);
202       break;
203     }
204     case HWC2::Callback::VsyncPeriodTimingChanged: {
205       period_timing_changed_callback_ = std::
206           make_pair(HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED(function), data);
207       break;
208     }
209 #endif
210     default:
211       break;
212   }
213   return HWC2::Error::None;
214 }
215 
SendHotplugEventToClient(hwc2_display_t displayid,bool connected)216 void DrmHwcTwo::SendHotplugEventToClient(hwc2_display_t displayid,
217                                          bool connected) {
218   auto &mutex = GetResMan().GetMainLock();
219   if (mutex.try_lock()) {
220     ALOGE("FIXME!!!: Main mutex must be locked in %s", __func__);
221     mutex.unlock();
222     return;
223   }
224 
225   auto hc = hotplug_callback_;
226   if (hc.first != nullptr && hc.second != nullptr) {
227     /* For some reason CLIENT will call HWC2 API in hotplug callback handler,
228      * which will cause deadlock . Unlock main mutex to prevent this.
229      */
230     mutex.unlock();
231     hc.first(hc.second, displayid,
232              connected == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
233                                              : HWC2_CONNECTION_DISCONNECTED);
234     mutex.lock();
235   }
236 }
237 
SendVsyncEventToClient(hwc2_display_t displayid,int64_t timestamp,uint32_t vsync_period) const238 void DrmHwcTwo::SendVsyncEventToClient(
239     hwc2_display_t displayid, int64_t timestamp,
240     [[maybe_unused]] uint32_t vsync_period) const {
241   /* vsync callback */
242 #if PLATFORM_SDK_VERSION > 29
243   if (vsync_2_4_callback_.first != nullptr &&
244       vsync_2_4_callback_.second != nullptr) {
245     vsync_2_4_callback_.first(vsync_2_4_callback_.second, displayid, timestamp,
246                               vsync_period);
247   } else
248 #endif
249       if (vsync_callback_.first != nullptr &&
250           vsync_callback_.second != nullptr) {
251     vsync_callback_.first(vsync_callback_.second, displayid, timestamp);
252   }
253 }
254 
SendVsyncPeriodTimingChangedEventToClient(hwc2_display_t displayid,int64_t timestamp) const255 void DrmHwcTwo::SendVsyncPeriodTimingChangedEventToClient(
256     [[maybe_unused]] hwc2_display_t displayid,
257     [[maybe_unused]] int64_t timestamp) const {
258 #if PLATFORM_SDK_VERSION > 29
259   hwc_vsync_period_change_timeline_t timeline = {
260       .newVsyncAppliedTimeNanos = timestamp,
261       .refreshRequired = false,
262       .refreshTimeNanos = 0,
263   };
264   if (period_timing_changed_callback_.first != nullptr &&
265       period_timing_changed_callback_.second != nullptr) {
266     period_timing_changed_callback_
267         .first(period_timing_changed_callback_.second, displayid, &timeline);
268   }
269 #endif
270 }
271 
272 }  // namespace android
273