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