blob: aaba5062dcc14904d4110da6da121dbb596103c6 [file] [log] [blame]
Drew Davenport93443182023-12-14 09:25:45 +00001/*
2 * Copyright (C) 2024 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 "drmhwc"
18
19#include "DrmHwc.h"
20
21#include <cinttypes>
22
23#include "backend/Backend.h"
24#include "utils/log.h"
Paz Zcharya9c41b682024-11-05 19:07:31 +000025#include "utils/properties.h"
Drew Davenport93443182023-12-14 09:25:45 +000026
27namespace android {
28
29DrmHwc::DrmHwc() : resource_manager_(this) {};
30
31/* Must be called after every display attach/detach cycle */
32void DrmHwc::FinalizeDisplayBinding() {
33 if (displays_.count(kPrimaryDisplay) == 0) {
34 /* Primary display MUST always exist */
35 ALOGI("No pipelines available. Creating null-display for headless mode");
36 displays_[kPrimaryDisplay] = std::make_unique<
37 HwcDisplay>(kPrimaryDisplay, HWC2::DisplayType::Physical, this);
38 /* Initializes null-display */
39 displays_[kPrimaryDisplay]->SetPipeline({});
40 }
41
42 if (displays_[kPrimaryDisplay]->IsInHeadlessMode() &&
43 !display_handles_.empty()) {
44 /* Reattach first secondary display to take place of the primary */
45 auto pipe = display_handles_.begin()->first;
46 ALOGI("Primary display was disconnected, reattaching '%s' as new primary",
47 pipe->connector->Get()->GetName().c_str());
48 UnbindDisplay(pipe);
49 BindDisplay(pipe);
50 }
51
52 // Finally, send hotplug events to the client
53 for (auto &dhe : deferred_hotplug_events_) {
54 SendHotplugEventToClient(dhe.first, dhe.second);
55 }
56 deferred_hotplug_events_.clear();
57
58 /* Wait 0.2s before removing the displays to flush pending HWC2 transactions
59 */
60 auto &mutex = GetResMan().GetMainLock();
61 mutex.unlock();
62 const int time_for_sf_to_dispose_display_us = 200000;
63 usleep(time_for_sf_to_dispose_display_us);
64 mutex.lock();
65 for (auto handle : displays_for_removal_list_) {
66 displays_.erase(handle);
67 }
68}
69
70bool DrmHwc::BindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
71 if (display_handles_.count(pipeline) != 0) {
72 ALOGE("%s, pipeline is already used by another display, FIXME!!!: %p",
73 __func__, pipeline.get());
74 return false;
75 }
76
77 uint32_t disp_handle = kPrimaryDisplay;
78
79 if (displays_.count(kPrimaryDisplay) != 0 &&
80 !displays_[kPrimaryDisplay]->IsInHeadlessMode()) {
81 disp_handle = ++last_display_handle_;
82 }
83
84 if (displays_.count(disp_handle) == 0) {
85 auto disp = std::make_unique<HwcDisplay>(disp_handle,
86 HWC2::DisplayType::Physical, this);
87 displays_[disp_handle] = std::move(disp);
88 }
89
90 ALOGI("Attaching pipeline '%s' to the display #%d%s",
91 pipeline->connector->Get()->GetName().c_str(), (int)disp_handle,
92 disp_handle == kPrimaryDisplay ? " (Primary)" : "");
93
94 displays_[disp_handle]->SetPipeline(pipeline);
95 display_handles_[pipeline] = disp_handle;
96
97 return true;
98}
99
100bool DrmHwc::UnbindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
101 if (display_handles_.count(pipeline) == 0) {
102 ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline.get());
103 return false;
104 }
105 auto handle = display_handles_[pipeline];
106 display_handles_.erase(pipeline);
107
108 ALOGI("Detaching the pipeline '%s' from the display #%i%s",
109 pipeline->connector->Get()->GetName().c_str(), (int)handle,
110 handle == kPrimaryDisplay ? " (Primary)" : "");
111
112 if (displays_.count(handle) == 0) {
113 ALOGE("%s, can't find the display, handle: %" PRIu64, __func__, handle);
114 return false;
115 }
116 displays_[handle]->SetPipeline({});
117
118 /* We must defer display disposal and removal, since it may still have pending
119 * HWC_API calls scheduled and waiting until ueventlistener thread releases
120 * main lock, otherwise transaction may fail and SF may crash
121 */
122 if (handle != kPrimaryDisplay) {
123 displays_for_removal_list_.emplace_back(handle);
124 }
125 return true;
126}
127
Manasi Navare3f0c01a2024-10-04 18:01:55 +0000128void DrmHwc::NotifyDisplayLinkStatus(
129 std::shared_ptr<DrmDisplayPipeline> pipeline) {
130 if (display_handles_.count(pipeline) == 0) {
131 ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline.get());
132 return;
133 }
134 ScheduleHotplugEvent(display_handles_[pipeline],
135 DisplayStatus::kLinkTrainingFailed);
136}
137
Drew Davenport93443182023-12-14 09:25:45 +0000138HWC2::Error DrmHwc::CreateVirtualDisplay(
139 uint32_t width, uint32_t height,
140 int32_t *format, // NOLINT(readability-non-const-parameter)
141 hwc2_display_t *display) {
142 ALOGI("Creating virtual display %dx%d format %d", width, height, *format);
143
144 auto virtual_pipeline = resource_manager_.GetVirtualDisplayPipeline();
145 if (!virtual_pipeline)
146 return HWC2::Error::Unsupported;
147
148 *display = ++last_display_handle_;
149 auto disp = std::make_unique<HwcDisplay>(*display, HWC2::DisplayType::Virtual,
150 this);
151
152 disp->SetVirtualDisplayResolution(width, height);
153 disp->SetPipeline(virtual_pipeline);
154 displays_[*display] = std::move(disp);
155 return HWC2::Error::None;
156}
157
158HWC2::Error DrmHwc::DestroyVirtualDisplay(hwc2_display_t display) {
159 ALOGI("Destroying virtual display %" PRIu64, display);
160
161 if (displays_.count(display) == 0) {
162 ALOGE("Trying to destroy non-existent display %" PRIu64, display);
163 return HWC2::Error::BadDisplay;
164 }
165
166 displays_[display]->SetPipeline({});
167
168 /* Wait 0.2s before removing the displays to flush pending HWC2 transactions
169 */
170 auto &mutex = GetResMan().GetMainLock();
171 mutex.unlock();
172 const int time_for_sf_to_dispose_display_us = 200000;
173 usleep(time_for_sf_to_dispose_display_us);
174 mutex.lock();
175
176 displays_.erase(display);
177
178 return HWC2::Error::None;
179}
180
181void DrmHwc::Dump(uint32_t *out_size, char *out_buffer) {
182 if (out_buffer != nullptr) {
183 auto copied_bytes = dump_string_.copy(out_buffer, *out_size);
184 *out_size = static_cast<uint32_t>(copied_bytes);
185 return;
186 }
187
188 std::stringstream output;
189
190 output << "-- drm_hwcomposer --\n\n";
191
192 for (auto &disp : displays_)
193 output << disp.second->Dump();
194
195 dump_string_ = output.str();
196 *out_size = static_cast<uint32_t>(dump_string_.size());
197}
198
199uint32_t DrmHwc::GetMaxVirtualDisplayCount() {
Paz Zcharyae11f7232024-10-26 21:11:29 +0000200 /* Virtual display is an experimental feature.
201 * Unless explicitly set to true, return 0 for no support.
202 */
Paz Zcharya9c41b682024-11-05 19:07:31 +0000203 if (0 == property_get_bool("vendor.hwc.drm.enable_virtual_display", 0)) {
Paz Zcharyae11f7232024-10-26 21:11:29 +0000204 return 0;
205 }
206
Drew Davenport93443182023-12-14 09:25:45 +0000207 auto writeback_count = resource_manager_.GetWritebackConnectorsCount();
208 writeback_count = std::min(writeback_count, 1U);
209 /* Currently, only 1 virtual display is supported. Other cases need testing */
210 ALOGI("Max virtual display count: %d", writeback_count);
211 return writeback_count;
212}
213
Drew Davenport1ac3b622024-09-05 10:59:16 -0600214void DrmHwc::DeinitDisplays() {
215 for (auto &pair : Displays()) {
216 pair.second->SetPipeline(nullptr);
217 }
218}
219
Drew Davenport93443182023-12-14 09:25:45 +0000220} // namespace android