blob: f1a5490d61a0f52787ae178428c6379f62876dd8 [file] [log] [blame]
Sean Pauled2ec4b2016-03-10 15:35:40 -05001/*
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
Sean Pauled2ec4b2016-03-10 15:35:40 -050017#define LOG_TAG "hwc-drm-two"
18
Roman Stratiienko13cc3662020-08-29 21:35:39 +030019#include "DrmHwcTwo.h"
Sean Pauled2ec4b2016-03-10 15:35:40 -050020
Roman Stratiienko3dacd472022-01-11 19:18:34 +020021#include <cinttypes>
22
Roman Stratiienko3627beb2022-01-04 16:02:55 +020023#include "backend/Backend.h"
Roman Stratiienkod21071f2021-03-09 21:56:50 +020024#include "utils/log.h"
Roman Stratiienkoaa3cd542020-08-29 11:26:16 +030025
Sean Pauled2ec4b2016-03-10 15:35:40 -050026namespace android {
27
Roman Stratiienko3dacd472022-01-11 19:18:34 +020028DrmHwcTwo::DrmHwcTwo() : resource_manager_(this){};
Sean Pauled2ec4b2016-03-10 15:35:40 -050029
Roman Stratiienko3dacd472022-01-11 19:18:34 +020030/* Must be called after every display attach/detach cycle */
31void DrmHwcTwo::FinalizeDisplayBinding() {
32 if (displays_.count(kPrimaryDisplay) == 0) {
33 /* Create/update new headless display if no other displays exists
34 * or reattach different display to make it primary
35 */
Sean Paulac874152016-03-10 16:00:26 -050036
Roman Stratiienko3dacd472022-01-11 19:18:34 +020037 if (display_handles_.empty()) {
38 /* Enable headless mode */
39 ALOGI("No pipelines available. Creating null-display for headless mode");
40 displays_[kPrimaryDisplay] = std::make_unique<
41 HwcDisplay>(nullptr, kPrimaryDisplay, HWC2::DisplayType::Physical,
42 this);
43 } else {
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 if (displays_.count(kPrimaryDisplay) == 0) {
50 ALOGE("FIXME!!! Still no primary display after reattaching...");
51 }
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +030052 }
53 }
54
Roman Stratiienko3dacd472022-01-11 19:18:34 +020055 // Finally, send hotplug events to the client
56 for (auto &dhe : deferred_hotplug_events_) {
57 SendHotplugEventToClient(dhe.first, dhe.second);
58 }
59 deferred_hotplug_events_.clear();
60}
Roman Stratiienko74923582022-01-17 11:24:21 +020061
Roman Stratiienko3dacd472022-01-11 19:18:34 +020062bool DrmHwcTwo::BindDisplay(DrmDisplayPipeline *pipeline) {
63 if (display_handles_.count(pipeline) != 0) {
64 ALOGE("%s, pipeline is already used by another display, FIXME!!!: %p",
65 __func__, pipeline);
66 return false;
67 }
Roman Stratiienko1e053b42021-10-25 22:54:20 +030068
Roman Stratiienko3dacd472022-01-11 19:18:34 +020069 uint32_t disp_handle = kPrimaryDisplay;
70
71 if (displays_.count(kPrimaryDisplay) != 0 &&
72 !displays_[kPrimaryDisplay]->IsInHeadlessMode()) {
73 disp_handle = ++last_display_handle_;
74 }
75
76 auto disp = std::make_unique<HwcDisplay>(pipeline, disp_handle,
77 HWC2::DisplayType::Physical, this);
78
79 if (disp_handle == kPrimaryDisplay) {
80 displays_.erase(disp_handle);
81 }
82
83 ALOGI("Attaching pipeline '%s' to the display #%d%s",
84 pipeline->connector->Get()->GetName().c_str(), (int)disp_handle,
85 disp_handle == kPrimaryDisplay ? " (Primary)" : "");
86
87 displays_[disp_handle] = std::move(disp);
88 display_handles_[pipeline] = disp_handle;
89
90 return true;
91}
92
93bool DrmHwcTwo::UnbindDisplay(DrmDisplayPipeline *pipeline) {
94 if (display_handles_.count(pipeline) == 0) {
95 ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline);
96 return false;
97 }
98 auto handle = display_handles_[pipeline];
99
100 ALOGI("Detaching the pipeline '%s' from the display #%i%s",
101 pipeline->connector->Get()->GetName().c_str(), (int)handle,
102 handle == kPrimaryDisplay ? " (Primary)" : "");
103
104 display_handles_.erase(pipeline);
105 if (displays_.count(handle) == 0) {
106 ALOGE("%s, can't find the display, handle: %" PRIu64, __func__, handle);
107 return false;
108 }
109 displays_.erase(handle);
110 return true;
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +0300111}
112
Roman Stratiienko7f576ec2021-12-22 17:34:18 +0200113HWC2::Error DrmHwcTwo::CreateVirtualDisplay(uint32_t /*width*/,
114 uint32_t /*height*/,
115 int32_t * /*format*/,
116 hwc2_display_t * /*display*/) {
117 // TODO(nobody): Implement virtual display
Sean Pauled2ec4b2016-03-10 15:35:40 -0500118 return HWC2::Error::Unsupported;
119}
120
Roman Stratiienko7f576ec2021-12-22 17:34:18 +0200121HWC2::Error DrmHwcTwo::DestroyVirtualDisplay(hwc2_display_t /*display*/) {
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200122 // TODO(nobody): Implement virtual display
Roman Stratiienko7f576ec2021-12-22 17:34:18 +0200123 return HWC2::Error::Unsupported;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500124}
125
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200126void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) {
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200127 if (outBuffer != nullptr) {
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200128 auto copied_bytes = mDumpString.copy(outBuffer, *outSize);
129 *outSize = static_cast<uint32_t>(copied_bytes);
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200130 return;
131 }
132
133 std::stringstream output;
134
135 output << "-- drm_hwcomposer --\n\n";
136
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200137 for (auto &disp : displays_)
138 output << disp.second->Dump();
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200139
140 mDumpString = output.str();
141 *outSize = static_cast<uint32_t>(mDumpString.size());
Sean Pauled2ec4b2016-03-10 15:35:40 -0500142}
143
144uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() {
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200145 // TODO(nobody): Implement virtual display
Sean Pauled2ec4b2016-03-10 15:35:40 -0500146 return 0;
147}
148
149HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
Sean Paulac874152016-03-10 16:00:26 -0500150 hwc2_callback_data_t data,
151 hwc2_function_pointer_t function) {
Roman Stratiienko23701092020-09-26 02:08:41 +0300152 switch (static_cast<HWC2::Callback>(descriptor)) {
Sean Paulac874152016-03-10 16:00:26 -0500153 case HWC2::Callback::Hotplug: {
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300154 hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data);
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200155 if (function != nullptr) {
156 resource_manager_.Init();
157 } else {
158 resource_manager_.DeInit();
159 /* Headless display may still be here, remove it */
160 displays_.erase(kPrimaryDisplay);
161 }
Sean Paulac874152016-03-10 16:00:26 -0500162 break;
163 }
Roman Kovalivskyi8fae1562020-01-30 20:20:47 +0200164 case HWC2::Callback::Refresh: {
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300165 refresh_callback_ = std::make_pair(HWC2_PFN_REFRESH(function), data);
Roman Kovalivskyi8fae1562020-01-30 20:20:47 +0200166 break;
167 }
Sean Paulac874152016-03-10 16:00:26 -0500168 case HWC2::Callback::Vsync: {
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300169 vsync_callback_ = std::make_pair(HWC2_PFN_VSYNC(function), data);
Sean Paulac874152016-03-10 16:00:26 -0500170 break;
171 }
Roman Stratiienko11ef8c52021-09-29 13:01:39 +0300172#if PLATFORM_SDK_VERSION > 29
173 case HWC2::Callback::Vsync_2_4: {
174 vsync_2_4_callback_ = std::make_pair(HWC2_PFN_VSYNC_2_4(function), data);
175 break;
176 }
Roman Stratiienkod0c035b2022-01-21 15:12:56 +0200177 case HWC2::Callback::VsyncPeriodTimingChanged: {
178 period_timing_changed_callback_ = std::
179 make_pair(HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED(function), data);
180 break;
181 }
Roman Stratiienko11ef8c52021-09-29 13:01:39 +0300182#endif
Sean Paulac874152016-03-10 16:00:26 -0500183 default:
184 break;
185 }
186 return HWC2::Error::None;
187}
188
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200189void DrmHwcTwo::SendHotplugEventToClient(hwc2_display_t displayid,
190 bool connected) {
Roman Stratiienko74923582022-01-17 11:24:21 +0200191 auto &mutex = GetResMan().GetMainLock();
192 if (mutex.try_lock()) {
193 ALOGE("FIXME!!!: Main mutex must be locked in %s", __func__);
194 mutex.unlock();
195 return;
196 }
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +0300197
Roman Stratiienko74923582022-01-17 11:24:21 +0200198 auto hc = hotplug_callback_;
199 if (hc.first != nullptr && hc.second != nullptr) {
200 /* For some reason CLIENT will call HWC2 API in hotplug callback handler,
201 * which will cause deadlock . Unlock main mutex to prevent this.
202 */
203 mutex.unlock();
204 hc.first(hc.second, displayid,
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200205 connected == DRM_MODE_CONNECTED ? HWC2_CONNECTION_CONNECTED
206 : HWC2_CONNECTION_DISCONNECTED);
Roman Stratiienko74923582022-01-17 11:24:21 +0200207 mutex.lock();
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300208 }
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +0300209}
210
Roman Stratiienko099c3112022-01-20 11:50:54 +0200211void DrmHwcTwo::SendVsyncEventToClient(
212 hwc2_display_t displayid, int64_t timestamp,
213 [[maybe_unused]] uint32_t vsync_period) const {
214 /* vsync callback */
215#if PLATFORM_SDK_VERSION > 29
216 if (vsync_2_4_callback_.first != nullptr &&
217 vsync_2_4_callback_.second != nullptr) {
218 vsync_2_4_callback_.first(vsync_2_4_callback_.second, displayid, timestamp,
219 vsync_period);
220 } else
221#endif
222 if (vsync_callback_.first != nullptr &&
223 vsync_callback_.second != nullptr) {
224 vsync_callback_.first(vsync_callback_.second, displayid, timestamp);
225 }
226}
227
Roman Stratiienkod0c035b2022-01-21 15:12:56 +0200228void DrmHwcTwo::SendVsyncPeriodTimingChangedEventToClient(
229 [[maybe_unused]] hwc2_display_t displayid,
230 [[maybe_unused]] int64_t timestamp) const {
231#if PLATFORM_SDK_VERSION > 29
232 hwc_vsync_period_change_timeline_t timeline = {
233 .newVsyncAppliedTimeNanos = timestamp,
234 .refreshRequired = false,
235 .refreshTimeNanos = 0,
236 };
237 if (period_timing_changed_callback_.first != nullptr &&
238 period_timing_changed_callback_.second != nullptr) {
239 period_timing_changed_callback_
240 .first(period_timing_changed_callback_.second, displayid, &timeline);
241 }
242#endif
243}
244
Sean Paulf72cccd2018-08-27 13:59:08 -0400245} // namespace android