• 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({});
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   for (auto handle : displays_for_removal_list_) {
65     displays_.erase(handle);
66   }
67 }
68 
BindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline)69 bool DrmHwcTwo::BindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
70   if (display_handles_.count(pipeline) != 0) {
71     ALOGE("%s, pipeline is already used by another display, FIXME!!!: %p",
72           __func__, pipeline.get());
73     return false;
74   }
75 
76   uint32_t disp_handle = kPrimaryDisplay;
77 
78   if (displays_.count(kPrimaryDisplay) != 0 &&
79       !displays_[kPrimaryDisplay]->IsInHeadlessMode()) {
80     disp_handle = ++last_display_handle_;
81   }
82 
83   if (displays_.count(disp_handle) == 0) {
84     auto disp = std::make_unique<HwcDisplay>(disp_handle,
85                                              HWC2::DisplayType::Physical, this);
86     displays_[disp_handle] = std::move(disp);
87   }
88 
89   ALOGI("Attaching pipeline '%s' to the display #%d%s",
90         pipeline->connector->Get()->GetName().c_str(), (int)disp_handle,
91         disp_handle == kPrimaryDisplay ? " (Primary)" : "");
92 
93   displays_[disp_handle]->SetPipeline(pipeline);
94   display_handles_[pipeline] = disp_handle;
95 
96   return true;
97 }
98 
UnbindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline)99 bool DrmHwcTwo::UnbindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
100   if (display_handles_.count(pipeline) == 0) {
101     ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline.get());
102     return false;
103   }
104   auto handle = display_handles_[pipeline];
105   display_handles_.erase(pipeline);
106 
107   ALOGI("Detaching the pipeline '%s' from the display #%i%s",
108         pipeline->connector->Get()->GetName().c_str(), (int)handle,
109         handle == kPrimaryDisplay ? " (Primary)" : "");
110 
111   if (displays_.count(handle) == 0) {
112     ALOGE("%s, can't find the display, handle: %" PRIu64, __func__, handle);
113     return false;
114   }
115   displays_[handle]->SetPipeline({});
116 
117   /* We must defer display disposal and removal, since it may still have pending
118    * HWC_API calls scheduled and waiting until ueventlistener thread releases
119    * main lock, otherwise transaction may fail and SF may crash
120    */
121   if (handle != kPrimaryDisplay) {
122     displays_for_removal_list_.emplace_back(handle);
123   }
124   return true;
125 }
126 
CreateVirtualDisplay(uint32_t width,uint32_t height,int32_t * format,hwc2_display_t * display)127 HWC2::Error DrmHwcTwo::CreateVirtualDisplay(
128     uint32_t width, uint32_t height,
129     int32_t *format,  // NOLINT(readability-non-const-parameter)
130     hwc2_display_t *display) {
131   ALOGI("Creating virtual display %dx%d format %d", width, height, *format);
132 
133   auto virtual_pipeline = resource_manager_.GetVirtualDisplayPipeline();
134   if (!virtual_pipeline)
135     return HWC2::Error::Unsupported;
136 
137   *display = ++last_display_handle_;
138   auto disp = std::make_unique<HwcDisplay>(*display, HWC2::DisplayType::Virtual,
139                                            this);
140 
141   disp->SetVirtualDisplayResolution(width, height);
142   disp->SetPipeline(virtual_pipeline);
143   displays_[*display] = std::move(disp);
144   return HWC2::Error::None;
145 }
146 
DestroyVirtualDisplay(hwc2_display_t display)147 HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t display) {
148   ALOGI("Destroying virtual display %" PRIu64, display);
149 
150   if (displays_.count(display) == 0) {
151     ALOGE("Trying to destroy non-existent display %" PRIu64, display);
152     return HWC2::Error::BadDisplay;
153   }
154 
155   displays_[display]->SetPipeline({});
156 
157   /* Wait 0.2s before removing the displays to flush pending HWC2 transactions
158    */
159   auto &mutex = GetResMan().GetMainLock();
160   mutex.unlock();
161   const int kTimeForSFToDisposeDisplayUs = 200000;
162   usleep(kTimeForSFToDisposeDisplayUs);
163   mutex.lock();
164 
165   displays_.erase(display);
166 
167   return HWC2::Error::None;
168 }
169 
Dump(uint32_t * outSize,char * outBuffer)170 void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) {
171   if (outBuffer != nullptr) {
172     auto copied_bytes = mDumpString.copy(outBuffer, *outSize);
173     *outSize = static_cast<uint32_t>(copied_bytes);
174     return;
175   }
176 
177   std::stringstream output;
178 
179   output << "-- drm_hwcomposer --\n\n";
180 
181   for (auto &disp : displays_)
182     output << disp.second->Dump();
183 
184   mDumpString = output.str();
185   *outSize = static_cast<uint32_t>(mDumpString.size());
186 }
187 
GetMaxVirtualDisplayCount()188 uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() {
189   auto writeback_count = resource_manager_.GetWritebackConnectorsCount();
190   writeback_count = std::min(writeback_count, 1U);
191   /* Currently, only 1 virtual display is supported. Other cases need testing */
192   ALOGI("Max virtual display count: %d", writeback_count);
193   return writeback_count;
194 }
195 
RegisterCallback(int32_t descriptor,hwc2_callback_data_t data,hwc2_function_pointer_t function)196 HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
197                                         hwc2_callback_data_t data,
198                                         hwc2_function_pointer_t function) {
199   switch (static_cast<HWC2::Callback>(descriptor)) {
200     case HWC2::Callback::Hotplug: {
201       hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data);
202       if (function != nullptr) {
203         resource_manager_.Init();
204       } else {
205         resource_manager_.DeInit();
206         /* Headless display may still be here. Remove it! */
207         if (displays_.count(kPrimaryDisplay) != 0) {
208           displays_[kPrimaryDisplay]->Deinit();
209           displays_.erase(kPrimaryDisplay);
210         }
211       }
212       break;
213     }
214     case HWC2::Callback::Refresh: {
215       refresh_callback_ = std::make_pair(HWC2_PFN_REFRESH(function), data);
216       break;
217     }
218     case HWC2::Callback::Vsync: {
219       vsync_callback_ = std::make_pair(HWC2_PFN_VSYNC(function), data);
220       break;
221     }
222 #if __ANDROID_API__ > 29
223     case HWC2::Callback::Vsync_2_4: {
224       vsync_2_4_callback_ = std::make_pair(HWC2_PFN_VSYNC_2_4(function), data);
225       break;
226     }
227     case HWC2::Callback::VsyncPeriodTimingChanged: {
228       period_timing_changed_callback_ = std::
229           make_pair(HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED(function), data);
230       break;
231     }
232 #endif
233     default:
234       break;
235   }
236   return HWC2::Error::None;
237 }
238 
SendHotplugEventToClient(hwc2_display_t displayid,bool connected) const239 void DrmHwcTwo::SendHotplugEventToClient(hwc2_display_t displayid,
240                                          bool connected) const {
241   auto hc = hotplug_callback_;
242   if (hc.first != nullptr && hc.second != nullptr) {
243     /* For some reason HWC Service will call HWC2 API in hotplug callback
244      * handler. This is the reason we're using recursive mutex.
245      */
246     hc.first(hc.second, displayid,
247              connected == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
248                                              : HWC2_CONNECTION_DISCONNECTED);
249   }
250 }
251 
SendVsyncEventToClient(hwc2_display_t displayid,int64_t timestamp,uint32_t vsync_period) const252 void DrmHwcTwo::SendVsyncEventToClient(
253     hwc2_display_t displayid, int64_t timestamp,
254     [[maybe_unused]] uint32_t vsync_period) const {
255   /* vsync callback */
256 #if __ANDROID_API__ > 29
257   if (vsync_2_4_callback_.first != nullptr &&
258       vsync_2_4_callback_.second != nullptr) {
259     vsync_2_4_callback_.first(vsync_2_4_callback_.second, displayid, timestamp,
260                               vsync_period);
261   } else
262 #endif
263       if (vsync_callback_.first != nullptr &&
264           vsync_callback_.second != nullptr) {
265     vsync_callback_.first(vsync_callback_.second, displayid, timestamp);
266   }
267 }
268 
SendVsyncPeriodTimingChangedEventToClient(hwc2_display_t displayid,int64_t timestamp) const269 void DrmHwcTwo::SendVsyncPeriodTimingChangedEventToClient(
270     [[maybe_unused]] hwc2_display_t displayid,
271     [[maybe_unused]] int64_t timestamp) const {
272 #if __ANDROID_API__ > 29
273   hwc_vsync_period_change_timeline_t timeline = {
274       .newVsyncAppliedTimeNanos = timestamp,
275       .refreshRequired = false,
276       .refreshTimeNanos = 0,
277   };
278   if (period_timing_changed_callback_.first != nullptr &&
279       period_timing_changed_callback_.second != nullptr) {
280     period_timing_changed_callback_
281         .first(period_timing_changed_callback_.second, displayid, &timeline);
282   }
283 #endif
284 }
285 
286 }  // namespace android
287