blob: df3eb56e39c6a8d7bd0843c34e2f6f064936ab36 [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"
25
26namespace android {
27
28DrmHwc::DrmHwc() : resource_manager_(this) {};
29
30/* Must be called after every display attach/detach cycle */
31void DrmHwc::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({});
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 time_for_sf_to_dispose_display_us = 200000;
62 usleep(time_for_sf_to_dispose_display_us);
63 mutex.lock();
64 for (auto handle : displays_for_removal_list_) {
65 displays_.erase(handle);
66 }
67}
68
69bool DrmHwc::BindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
70 if (display_handles_.count(pipeline) != 0) {
71 ALOGE("%s, pipeline is already used by another display, FIXME!!!: %p",
72 __func__, pipeline.get());
73 return false;
74 }
75
76 uint32_t disp_handle = kPrimaryDisplay;
77
78 if (displays_.count(kPrimaryDisplay) != 0 &&
79 !displays_[kPrimaryDisplay]->IsInHeadlessMode()) {
80 disp_handle = ++last_display_handle_;
81 }
82
83 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);
87 }
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
93 displays_[disp_handle]->SetPipeline(pipeline);
94 display_handles_[pipeline] = disp_handle;
95
96 return true;
97}
98
99bool DrmHwc::UnbindDisplay(std::shared_ptr<DrmDisplayPipeline> pipeline) {
100 if (display_handles_.count(pipeline) == 0) {
101 ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline.get());
102 return false;
103 }
104 auto handle = display_handles_[pipeline];
105 display_handles_.erase(pipeline);
106
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
111 if (displays_.count(handle) == 0) {
112 ALOGE("%s, can't find the display, handle: %" PRIu64, __func__, handle);
113 return false;
114 }
115 displays_[handle]->SetPipeline({});
116
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 }
124 return true;
125}
126
127HWC2::Error DrmHwc::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;
145}
146
147HWC2::Error DrmHwc::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 time_for_sf_to_dispose_display_us = 200000;
162 usleep(time_for_sf_to_dispose_display_us);
163 mutex.lock();
164
165 displays_.erase(display);
166
167 return HWC2::Error::None;
168}
169
170void DrmHwc::Dump(uint32_t *out_size, char *out_buffer) {
171 if (out_buffer != nullptr) {
172 auto copied_bytes = dump_string_.copy(out_buffer, *out_size);
173 *out_size = static_cast<uint32_t>(copied_bytes);
174 return;
175 }
176
177 std::stringstream output;
178
179 output << "-- drm_hwcomposer --\n\n";
180
181 for (auto &disp : displays_)
182 output << disp.second->Dump();
183
184 dump_string_ = output.str();
185 *out_size = static_cast<uint32_t>(dump_string_.size());
186}
187
188uint32_t DrmHwc::GetMaxVirtualDisplayCount() {
189 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;
194}
195
Drew Davenport1ac3b622024-09-05 10:59:16 -0600196void DrmHwc::DeinitDisplays() {
197 for (auto &pair : Displays()) {
198 pair.second->SetPipeline(nullptr);
199 }
200}
201
Drew Davenport93443182023-12-14 09:25:45 +0000202} // namespace android