blob: 2ea6c77bdb9afa3492f7c6d2163ce7f5c550d6ae [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 Paul468a7542024-07-16 19:50:58 +000017#define LOG_TAG "drmhwc"
Sean Pauled2ec4b2016-03-10 15:35:40 -050018
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) {
Roman Stratiienkobb594ba2022-02-18 16:52:03 +020033 /* 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 */
Roman Stratiienko63762a92023-09-18 22:33:45 +030038 displays_[kPrimaryDisplay]->SetPipeline({});
Roman Stratiienkobb594ba2022-02-18 16:52:03 +020039 }
Sean Paulac874152016-03-10 16:00:26 -050040
Roman Stratiienkobb594ba2022-02-18 16:52:03 +020041 if (displays_[kPrimaryDisplay]->IsInHeadlessMode() &&
42 !display_handles_.empty()) {
43 /* Reattach first secondary display to take place of the primary */
Roman Stratiienko63762a92023-09-18 22:33:45 +030044 auto pipe = display_handles_.begin()->first;
Roman Stratiienkobb594ba2022-02-18 16:52:03 +020045 ALOGI("Primary display was disconnected, reattaching '%s' as new primary",
46 pipe->connector->Get()->GetName().c_str());
47 UnbindDisplay(pipe);
48 BindDisplay(pipe);
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +030049 }
50
Roman Stratiienko3dacd472022-01-11 19:18:34 +020051 // 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();
Roman Stratiienkobb594ba2022-02-18 16:52:03 +020056
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();
Roman Stratiienkobb594ba2022-02-18 16:52:03 +020064 for (auto handle : displays_for_removal_list_) {
Roman Stratiienkobb594ba2022-02-18 16:52:03 +020065 displays_.erase(handle);
66 }
Roman Stratiienko3dacd472022-01-11 19:18:34 +020067}
Roman Stratiienko74923582022-01-17 11:24:21 +020068
Roman Stratiienko63762a92023-09-18 22:33:45 +030069bool DrmHwcTwo::BindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
Roman Stratiienko3dacd472022-01-11 19:18:34 +020070 if (display_handles_.count(pipeline) != 0) {
71 ALOGE("%s, pipeline is already used by another display, FIXME!!!: %p",
Roman Stratiienko63762a92023-09-18 22:33:45 +030072 __func__, pipeline.get());
Roman Stratiienko3dacd472022-01-11 19:18:34 +020073 return false;
74 }
Roman Stratiienko1e053b42021-10-25 22:54:20 +030075
Roman Stratiienko3dacd472022-01-11 19:18:34 +020076 uint32_t disp_handle = kPrimaryDisplay;
77
78 if (displays_.count(kPrimaryDisplay) != 0 &&
79 !displays_[kPrimaryDisplay]->IsInHeadlessMode()) {
80 disp_handle = ++last_display_handle_;
81 }
82
Roman Stratiienkobb594ba2022-02-18 16:52:03 +020083 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);
Roman Stratiienko3dacd472022-01-11 19:18:34 +020087 }
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
Roman Stratiienkobb594ba2022-02-18 16:52:03 +020093 displays_[disp_handle]->SetPipeline(pipeline);
Roman Stratiienko3dacd472022-01-11 19:18:34 +020094 display_handles_[pipeline] = disp_handle;
95
96 return true;
97}
98
Roman Stratiienko63762a92023-09-18 22:33:45 +030099bool DrmHwcTwo::UnbindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200100 if (display_handles_.count(pipeline) == 0) {
Roman Stratiienko63762a92023-09-18 22:33:45 +0300101 ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline.get());
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200102 return false;
103 }
104 auto handle = display_handles_[pipeline];
Roman Stratiienkobb594ba2022-02-18 16:52:03 +0200105 display_handles_.erase(pipeline);
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200106
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
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200111 if (displays_.count(handle) == 0) {
112 ALOGE("%s, can't find the display, handle: %" PRIu64, __func__, handle);
113 return false;
114 }
Roman Stratiienko63762a92023-09-18 22:33:45 +0300115 displays_[handle]->SetPipeline({});
Roman Stratiienkobb594ba2022-02-18 16:52:03 +0200116
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 }
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200124 return true;
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +0300125}
126
Roman Stratiienkof2c060f2023-09-18 22:46:08 +0300127HWC2::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;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500145}
146
Roman Stratiienkof2c060f2023-09-18 22:46:08 +0300147HWC2::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;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500168}
169
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200170void DrmHwcTwo::Dump(uint32_t *outSize, char *outBuffer) {
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200171 if (outBuffer != nullptr) {
Roman Stratiienkoe2f2c922021-02-13 10:57:47 +0200172 auto copied_bytes = mDumpString.copy(outBuffer, *outSize);
173 *outSize = static_cast<uint32_t>(copied_bytes);
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200174 return;
175 }
176
177 std::stringstream output;
178
179 output << "-- drm_hwcomposer --\n\n";
180
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200181 for (auto &disp : displays_)
182 output << disp.second->Dump();
Roman Stratiienko0d1a2cd2019-11-28 17:51:16 +0200183
184 mDumpString = output.str();
185 *outSize = static_cast<uint32_t>(mDumpString.size());
Sean Pauled2ec4b2016-03-10 15:35:40 -0500186}
187
188uint32_t DrmHwcTwo::GetMaxVirtualDisplayCount() {
Roman Stratiienkof2c060f2023-09-18 22:46:08 +0300189 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;
Sean Pauled2ec4b2016-03-10 15:35:40 -0500194}
195
196HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
Sean Paulac874152016-03-10 16:00:26 -0500197 hwc2_callback_data_t data,
198 hwc2_function_pointer_t function) {
Roman Stratiienko23701092020-09-26 02:08:41 +0300199 switch (static_cast<HWC2::Callback>(descriptor)) {
Sean Paulac874152016-03-10 16:00:26 -0500200 case HWC2::Callback::Hotplug: {
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300201 hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data);
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200202 if (function != nullptr) {
203 resource_manager_.Init();
204 } else {
205 resource_manager_.DeInit();
Roman Stratiienkod0494d92022-03-15 18:02:04 +0200206 /* Headless display may still be here. Remove it! */
207 if (displays_.count(kPrimaryDisplay) != 0) {
208 displays_[kPrimaryDisplay]->Deinit();
Roman Stratiienkod0494d92022-03-15 18:02:04 +0200209 displays_.erase(kPrimaryDisplay);
Roman Stratiienkod0494d92022-03-15 18:02:04 +0200210 }
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200211 }
Sean Paulac874152016-03-10 16:00:26 -0500212 break;
213 }
Roman Kovalivskyi8fae1562020-01-30 20:20:47 +0200214 case HWC2::Callback::Refresh: {
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300215 refresh_callback_ = std::make_pair(HWC2_PFN_REFRESH(function), data);
Roman Kovalivskyi8fae1562020-01-30 20:20:47 +0200216 break;
217 }
Sean Paulac874152016-03-10 16:00:26 -0500218 case HWC2::Callback::Vsync: {
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300219 vsync_callback_ = std::make_pair(HWC2_PFN_VSYNC(function), data);
Sean Paulac874152016-03-10 16:00:26 -0500220 break;
221 }
Roman Stratiienko6b405052022-12-10 19:09:10 +0200222#if __ANDROID_API__ > 29
Roman Stratiienko11ef8c52021-09-29 13:01:39 +0300223 case HWC2::Callback::Vsync_2_4: {
224 vsync_2_4_callback_ = std::make_pair(HWC2_PFN_VSYNC_2_4(function), data);
225 break;
226 }
Roman Stratiienkod0c035b2022-01-21 15:12:56 +0200227 case HWC2::Callback::VsyncPeriodTimingChanged: {
228 period_timing_changed_callback_ = std::
229 make_pair(HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED(function), data);
230 break;
231 }
Roman Stratiienko11ef8c52021-09-29 13:01:39 +0300232#endif
Sean Paulac874152016-03-10 16:00:26 -0500233 default:
234 break;
235 }
236 return HWC2::Error::None;
237}
238
Roman Stratiienko3dacd472022-01-11 19:18:34 +0200239void DrmHwcTwo::SendHotplugEventToClient(hwc2_display_t displayid,
Roman Stratiienko9e2a2cd2022-12-28 20:47:29 +0200240 bool connected) const {
Roman Stratiienko74923582022-01-17 11:24:21 +0200241 auto hc = hotplug_callback_;
242 if (hc.first != nullptr && hc.second != nullptr) {
Roman Stratiienko9e2a2cd2022-12-28 20:47:29 +0200243 /* For some reason HWC Service will call HWC2 API in hotplug callback
244 * handler. This is the reason we're using recursive mutex.
Roman Stratiienko74923582022-01-17 11:24:21 +0200245 */
Roman Stratiienko74923582022-01-17 11:24:21 +0200246 hc.first(hc.second, displayid,
Drew Davenport4520df12024-07-15 12:19:55 -0600247 connected ? HWC2_CONNECTION_CONNECTED
248 : HWC2_CONNECTION_DISCONNECTED);
Roman Stratiienko863a3c22021-09-29 13:00:29 +0300249 }
Andrii Chepurnyi495e4cc2018-08-01 17:42:56 +0300250}
251
Roman Stratiienko099c3112022-01-20 11:50:54 +0200252void DrmHwcTwo::SendVsyncEventToClient(
253 hwc2_display_t displayid, int64_t timestamp,
254 [[maybe_unused]] uint32_t vsync_period) const {
255 /* vsync callback */
Roman Stratiienko6b405052022-12-10 19:09:10 +0200256#if __ANDROID_API__ > 29
Roman Stratiienko099c3112022-01-20 11:50:54 +0200257 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
Roman Stratiienkod0c035b2022-01-21 15:12:56 +0200269void DrmHwcTwo::SendVsyncPeriodTimingChangedEventToClient(
270 [[maybe_unused]] hwc2_display_t displayid,
271 [[maybe_unused]] int64_t timestamp) const {
Roman Stratiienko6b405052022-12-10 19:09:10 +0200272#if __ANDROID_API__ > 29
Roman Stratiienkod0c035b2022-01-21 15:12:56 +0200273 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
Sean Paulf72cccd2018-08-27 13:59:08 -0400286} // namespace android