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