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