1*0a9764feSAndroid Build Coastguard Worker /*
2*0a9764feSAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
3*0a9764feSAndroid Build Coastguard Worker *
4*0a9764feSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*0a9764feSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*0a9764feSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*0a9764feSAndroid Build Coastguard Worker *
8*0a9764feSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*0a9764feSAndroid Build Coastguard Worker *
10*0a9764feSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*0a9764feSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*0a9764feSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*0a9764feSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*0a9764feSAndroid Build Coastguard Worker * limitations under the License.
15*0a9764feSAndroid Build Coastguard Worker */
16*0a9764feSAndroid Build Coastguard Worker
17*0a9764feSAndroid Build Coastguard Worker #define LOG_TAG "drmhwc"
18*0a9764feSAndroid Build Coastguard Worker
19*0a9764feSAndroid Build Coastguard Worker #include "ResourceManager.h"
20*0a9764feSAndroid Build Coastguard Worker
21*0a9764feSAndroid Build Coastguard Worker #include <sys/stat.h>
22*0a9764feSAndroid Build Coastguard Worker
23*0a9764feSAndroid Build Coastguard Worker #include <ctime>
24*0a9764feSAndroid Build Coastguard Worker #include <sstream>
25*0a9764feSAndroid Build Coastguard Worker
26*0a9764feSAndroid Build Coastguard Worker #include "bufferinfo/BufferInfoGetter.h"
27*0a9764feSAndroid Build Coastguard Worker #include "drm/DrmAtomicStateManager.h"
28*0a9764feSAndroid Build Coastguard Worker #include "drm/DrmDevice.h"
29*0a9764feSAndroid Build Coastguard Worker #include "drm/DrmDisplayPipeline.h"
30*0a9764feSAndroid Build Coastguard Worker #include "drm/DrmPlane.h"
31*0a9764feSAndroid Build Coastguard Worker #include "utils/log.h"
32*0a9764feSAndroid Build Coastguard Worker #include "utils/properties.h"
33*0a9764feSAndroid Build Coastguard Worker
34*0a9764feSAndroid Build Coastguard Worker namespace android {
35*0a9764feSAndroid Build Coastguard Worker
ResourceManager(PipelineToFrontendBindingInterface * p2f_bind_interface)36*0a9764feSAndroid Build Coastguard Worker ResourceManager::ResourceManager(
37*0a9764feSAndroid Build Coastguard Worker PipelineToFrontendBindingInterface *p2f_bind_interface)
38*0a9764feSAndroid Build Coastguard Worker : frontend_interface_(p2f_bind_interface) {
39*0a9764feSAndroid Build Coastguard Worker uevent_listener_ = UEventListener::CreateInstance();
40*0a9764feSAndroid Build Coastguard Worker }
41*0a9764feSAndroid Build Coastguard Worker
~ResourceManager()42*0a9764feSAndroid Build Coastguard Worker ResourceManager::~ResourceManager() {
43*0a9764feSAndroid Build Coastguard Worker uevent_listener_->StopThread();
44*0a9764feSAndroid Build Coastguard Worker }
45*0a9764feSAndroid Build Coastguard Worker
Init()46*0a9764feSAndroid Build Coastguard Worker void ResourceManager::Init() {
47*0a9764feSAndroid Build Coastguard Worker if (initialized_) {
48*0a9764feSAndroid Build Coastguard Worker ALOGE("Already initialized");
49*0a9764feSAndroid Build Coastguard Worker return;
50*0a9764feSAndroid Build Coastguard Worker }
51*0a9764feSAndroid Build Coastguard Worker
52*0a9764feSAndroid Build Coastguard Worker char path_pattern[PROPERTY_VALUE_MAX];
53*0a9764feSAndroid Build Coastguard Worker // Could be a valid path or it can have at the end of it the wildcard %
54*0a9764feSAndroid Build Coastguard Worker // which means that it will try open all devices until an error is met.
55*0a9764feSAndroid Build Coastguard Worker auto path_len = property_get("vendor.hwc.drm.device", path_pattern,
56*0a9764feSAndroid Build Coastguard Worker "/dev/dri/card%");
57*0a9764feSAndroid Build Coastguard Worker if (path_pattern[path_len - 1] != '%') {
58*0a9764feSAndroid Build Coastguard Worker auto dev = DrmDevice::CreateInstance(path_pattern, this);
59*0a9764feSAndroid Build Coastguard Worker if (dev) {
60*0a9764feSAndroid Build Coastguard Worker drms_.emplace_back(std::move(dev));
61*0a9764feSAndroid Build Coastguard Worker }
62*0a9764feSAndroid Build Coastguard Worker } else {
63*0a9764feSAndroid Build Coastguard Worker path_pattern[path_len - 1] = '\0';
64*0a9764feSAndroid Build Coastguard Worker for (int idx = 0;; ++idx) {
65*0a9764feSAndroid Build Coastguard Worker std::ostringstream path;
66*0a9764feSAndroid Build Coastguard Worker path << path_pattern << idx;
67*0a9764feSAndroid Build Coastguard Worker
68*0a9764feSAndroid Build Coastguard Worker struct stat buf {};
69*0a9764feSAndroid Build Coastguard Worker if (stat(path.str().c_str(), &buf) != 0)
70*0a9764feSAndroid Build Coastguard Worker break;
71*0a9764feSAndroid Build Coastguard Worker
72*0a9764feSAndroid Build Coastguard Worker auto dev = DrmDevice::CreateInstance(path.str(), this);
73*0a9764feSAndroid Build Coastguard Worker if (dev) {
74*0a9764feSAndroid Build Coastguard Worker drms_.emplace_back(std::move(dev));
75*0a9764feSAndroid Build Coastguard Worker }
76*0a9764feSAndroid Build Coastguard Worker }
77*0a9764feSAndroid Build Coastguard Worker }
78*0a9764feSAndroid Build Coastguard Worker
79*0a9764feSAndroid Build Coastguard Worker char proptext[PROPERTY_VALUE_MAX];
80*0a9764feSAndroid Build Coastguard Worker property_get("vendor.hwc.drm.scale_with_gpu", proptext, "0");
81*0a9764feSAndroid Build Coastguard Worker scale_with_gpu_ = bool(strncmp(proptext, "0", 1));
82*0a9764feSAndroid Build Coastguard Worker
83*0a9764feSAndroid Build Coastguard Worker constexpr char kDrmOrGpu[] = "DRM_OR_GPU";
84*0a9764feSAndroid Build Coastguard Worker constexpr char kDrmOrIgnore[] = "DRM_OR_IGNORE";
85*0a9764feSAndroid Build Coastguard Worker property_get("vendor.hwc.drm.ctm", proptext, kDrmOrGpu);
86*0a9764feSAndroid Build Coastguard Worker if (strncmp(proptext, kDrmOrGpu, sizeof(kDrmOrGpu)) == 0) {
87*0a9764feSAndroid Build Coastguard Worker ctm_handling_ = CtmHandling::kDrmOrGpu;
88*0a9764feSAndroid Build Coastguard Worker } else if (strncmp(proptext, kDrmOrIgnore, sizeof(kDrmOrIgnore)) == 0) {
89*0a9764feSAndroid Build Coastguard Worker ctm_handling_ = CtmHandling::kDrmOrIgnore;
90*0a9764feSAndroid Build Coastguard Worker } else {
91*0a9764feSAndroid Build Coastguard Worker ALOGE("Invalid value for vendor.hwc.drm.ctm: %s", proptext);
92*0a9764feSAndroid Build Coastguard Worker ctm_handling_ = CtmHandling::kDrmOrGpu;
93*0a9764feSAndroid Build Coastguard Worker }
94*0a9764feSAndroid Build Coastguard Worker
95*0a9764feSAndroid Build Coastguard Worker if (BufferInfoGetter::GetInstance() == nullptr) {
96*0a9764feSAndroid Build Coastguard Worker ALOGE("Failed to initialize BufferInfoGetter");
97*0a9764feSAndroid Build Coastguard Worker return;
98*0a9764feSAndroid Build Coastguard Worker }
99*0a9764feSAndroid Build Coastguard Worker
100*0a9764feSAndroid Build Coastguard Worker uevent_listener_->RegisterHotplugHandler([this] {
101*0a9764feSAndroid Build Coastguard Worker const std::unique_lock lock(GetMainLock());
102*0a9764feSAndroid Build Coastguard Worker UpdateFrontendDisplays();
103*0a9764feSAndroid Build Coastguard Worker });
104*0a9764feSAndroid Build Coastguard Worker
105*0a9764feSAndroid Build Coastguard Worker UpdateFrontendDisplays();
106*0a9764feSAndroid Build Coastguard Worker
107*0a9764feSAndroid Build Coastguard Worker initialized_ = true;
108*0a9764feSAndroid Build Coastguard Worker }
109*0a9764feSAndroid Build Coastguard Worker
DeInit()110*0a9764feSAndroid Build Coastguard Worker void ResourceManager::DeInit() {
111*0a9764feSAndroid Build Coastguard Worker if (!initialized_) {
112*0a9764feSAndroid Build Coastguard Worker ALOGE("Not initialized");
113*0a9764feSAndroid Build Coastguard Worker return;
114*0a9764feSAndroid Build Coastguard Worker }
115*0a9764feSAndroid Build Coastguard Worker
116*0a9764feSAndroid Build Coastguard Worker uevent_listener_->RegisterHotplugHandler({});
117*0a9764feSAndroid Build Coastguard Worker
118*0a9764feSAndroid Build Coastguard Worker DetachAllFrontendDisplays();
119*0a9764feSAndroid Build Coastguard Worker drms_.clear();
120*0a9764feSAndroid Build Coastguard Worker
121*0a9764feSAndroid Build Coastguard Worker initialized_ = false;
122*0a9764feSAndroid Build Coastguard Worker }
123*0a9764feSAndroid Build Coastguard Worker
GetTimeMonotonicNs()124*0a9764feSAndroid Build Coastguard Worker auto ResourceManager::GetTimeMonotonicNs() -> int64_t {
125*0a9764feSAndroid Build Coastguard Worker struct timespec ts {};
126*0a9764feSAndroid Build Coastguard Worker clock_gettime(CLOCK_MONOTONIC, &ts);
127*0a9764feSAndroid Build Coastguard Worker constexpr int64_t kNsInSec = 1000000000LL;
128*0a9764feSAndroid Build Coastguard Worker return int64_t(ts.tv_sec) * kNsInSec + int64_t(ts.tv_nsec);
129*0a9764feSAndroid Build Coastguard Worker }
130*0a9764feSAndroid Build Coastguard Worker
UpdateFrontendDisplays()131*0a9764feSAndroid Build Coastguard Worker void ResourceManager::UpdateFrontendDisplays() {
132*0a9764feSAndroid Build Coastguard Worker auto ordered_connectors = GetOrderedConnectors();
133*0a9764feSAndroid Build Coastguard Worker
134*0a9764feSAndroid Build Coastguard Worker for (auto *conn : ordered_connectors) {
135*0a9764feSAndroid Build Coastguard Worker conn->UpdateModes();
136*0a9764feSAndroid Build Coastguard Worker auto connected = conn->IsConnected();
137*0a9764feSAndroid Build Coastguard Worker auto attached = attached_pipelines_.count(conn) != 0;
138*0a9764feSAndroid Build Coastguard Worker
139*0a9764feSAndroid Build Coastguard Worker if (connected != attached) {
140*0a9764feSAndroid Build Coastguard Worker ALOGI("%s connector %s", connected ? "Attaching" : "Detaching",
141*0a9764feSAndroid Build Coastguard Worker conn->GetName().c_str());
142*0a9764feSAndroid Build Coastguard Worker
143*0a9764feSAndroid Build Coastguard Worker if (connected) {
144*0a9764feSAndroid Build Coastguard Worker std::shared_ptr<DrmDisplayPipeline>
145*0a9764feSAndroid Build Coastguard Worker pipeline = DrmDisplayPipeline::CreatePipeline(*conn);
146*0a9764feSAndroid Build Coastguard Worker
147*0a9764feSAndroid Build Coastguard Worker if (pipeline) {
148*0a9764feSAndroid Build Coastguard Worker frontend_interface_->BindDisplay(pipeline);
149*0a9764feSAndroid Build Coastguard Worker attached_pipelines_[conn] = std::move(pipeline);
150*0a9764feSAndroid Build Coastguard Worker }
151*0a9764feSAndroid Build Coastguard Worker } else {
152*0a9764feSAndroid Build Coastguard Worker auto &pipeline = attached_pipelines_[conn];
153*0a9764feSAndroid Build Coastguard Worker frontend_interface_->UnbindDisplay(pipeline);
154*0a9764feSAndroid Build Coastguard Worker attached_pipelines_.erase(conn);
155*0a9764feSAndroid Build Coastguard Worker }
156*0a9764feSAndroid Build Coastguard Worker }
157*0a9764feSAndroid Build Coastguard Worker if (connected) {
158*0a9764feSAndroid Build Coastguard Worker if (!conn->IsLinkStatusGood())
159*0a9764feSAndroid Build Coastguard Worker frontend_interface_->NotifyDisplayLinkStatus(attached_pipelines_[conn]);
160*0a9764feSAndroid Build Coastguard Worker }
161*0a9764feSAndroid Build Coastguard Worker }
162*0a9764feSAndroid Build Coastguard Worker frontend_interface_->FinalizeDisplayBinding();
163*0a9764feSAndroid Build Coastguard Worker }
164*0a9764feSAndroid Build Coastguard Worker
DetachAllFrontendDisplays()165*0a9764feSAndroid Build Coastguard Worker void ResourceManager::DetachAllFrontendDisplays() {
166*0a9764feSAndroid Build Coastguard Worker for (auto &p : attached_pipelines_) {
167*0a9764feSAndroid Build Coastguard Worker frontend_interface_->UnbindDisplay(p.second);
168*0a9764feSAndroid Build Coastguard Worker }
169*0a9764feSAndroid Build Coastguard Worker attached_pipelines_.clear();
170*0a9764feSAndroid Build Coastguard Worker frontend_interface_->FinalizeDisplayBinding();
171*0a9764feSAndroid Build Coastguard Worker }
172*0a9764feSAndroid Build Coastguard Worker
GetOrderedConnectors()173*0a9764feSAndroid Build Coastguard Worker auto ResourceManager::GetOrderedConnectors() -> std::vector<DrmConnector *> {
174*0a9764feSAndroid Build Coastguard Worker /* Put internal displays first then external to
175*0a9764feSAndroid Build Coastguard Worker * ensure Internal will take Primary slot
176*0a9764feSAndroid Build Coastguard Worker */
177*0a9764feSAndroid Build Coastguard Worker
178*0a9764feSAndroid Build Coastguard Worker std::vector<DrmConnector *> ordered_connectors;
179*0a9764feSAndroid Build Coastguard Worker
180*0a9764feSAndroid Build Coastguard Worker for (auto &drm : drms_) {
181*0a9764feSAndroid Build Coastguard Worker for (const auto &conn : drm->GetConnectors()) {
182*0a9764feSAndroid Build Coastguard Worker if (conn->IsInternal()) {
183*0a9764feSAndroid Build Coastguard Worker ordered_connectors.emplace_back(conn.get());
184*0a9764feSAndroid Build Coastguard Worker }
185*0a9764feSAndroid Build Coastguard Worker }
186*0a9764feSAndroid Build Coastguard Worker }
187*0a9764feSAndroid Build Coastguard Worker
188*0a9764feSAndroid Build Coastguard Worker for (auto &drm : drms_) {
189*0a9764feSAndroid Build Coastguard Worker for (const auto &conn : drm->GetConnectors()) {
190*0a9764feSAndroid Build Coastguard Worker if (conn->IsExternal()) {
191*0a9764feSAndroid Build Coastguard Worker ordered_connectors.emplace_back(conn.get());
192*0a9764feSAndroid Build Coastguard Worker }
193*0a9764feSAndroid Build Coastguard Worker }
194*0a9764feSAndroid Build Coastguard Worker }
195*0a9764feSAndroid Build Coastguard Worker
196*0a9764feSAndroid Build Coastguard Worker return ordered_connectors;
197*0a9764feSAndroid Build Coastguard Worker }
198*0a9764feSAndroid Build Coastguard Worker
GetVirtualDisplayPipeline()199*0a9764feSAndroid Build Coastguard Worker auto ResourceManager::GetVirtualDisplayPipeline()
200*0a9764feSAndroid Build Coastguard Worker -> std::shared_ptr<DrmDisplayPipeline> {
201*0a9764feSAndroid Build Coastguard Worker for (auto &drm : drms_) {
202*0a9764feSAndroid Build Coastguard Worker for (const auto &conn : drm->GetWritebackConnectors()) {
203*0a9764feSAndroid Build Coastguard Worker auto pipeline = DrmDisplayPipeline::CreatePipeline(*conn);
204*0a9764feSAndroid Build Coastguard Worker if (!pipeline) {
205*0a9764feSAndroid Build Coastguard Worker ALOGE("Failed to create pipeline for writeback connector %s",
206*0a9764feSAndroid Build Coastguard Worker conn->GetName().c_str());
207*0a9764feSAndroid Build Coastguard Worker }
208*0a9764feSAndroid Build Coastguard Worker if (pipeline) {
209*0a9764feSAndroid Build Coastguard Worker return pipeline;
210*0a9764feSAndroid Build Coastguard Worker }
211*0a9764feSAndroid Build Coastguard Worker }
212*0a9764feSAndroid Build Coastguard Worker }
213*0a9764feSAndroid Build Coastguard Worker return {};
214*0a9764feSAndroid Build Coastguard Worker }
215*0a9764feSAndroid Build Coastguard Worker
GetWritebackConnectorsCount()216*0a9764feSAndroid Build Coastguard Worker auto ResourceManager::GetWritebackConnectorsCount() -> uint32_t {
217*0a9764feSAndroid Build Coastguard Worker uint32_t count = 0;
218*0a9764feSAndroid Build Coastguard Worker for (auto &drm : drms_) {
219*0a9764feSAndroid Build Coastguard Worker count += drm->GetWritebackConnectors().size();
220*0a9764feSAndroid Build Coastguard Worker }
221*0a9764feSAndroid Build Coastguard Worker return count;
222*0a9764feSAndroid Build Coastguard Worker }
223*0a9764feSAndroid Build Coastguard Worker
224*0a9764feSAndroid Build Coastguard Worker } // namespace android
225