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