• 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 <fcntl.h>
22 #include <sys/stat.h>
23 
24 #include <ctime>
25 #include <sstream>
26 
27 #include "bufferinfo/BufferInfoGetter.h"
28 #include "drm/DrmAtomicStateManager.h"
29 #include "drm/DrmDevice.h"
30 #include "drm/DrmDisplayPipeline.h"
31 #include "drm/DrmPlane.h"
32 #include "utils/log.h"
33 #include "utils/properties.h"
34 
35 namespace android {
36 
ResourceManager(PipelineToFrontendBindingInterface * p2f_bind_interface)37 ResourceManager::ResourceManager(
38     PipelineToFrontendBindingInterface *p2f_bind_interface)
39     : frontend_interface_(p2f_bind_interface) {
40   if (uevent_listener_.Init() != 0) {
41     ALOGE("Can't initialize event listener");
42   }
43 }
44 
~ResourceManager()45 ResourceManager::~ResourceManager() {
46   uevent_listener_.Exit();
47 }
48 
Init()49 void ResourceManager::Init() {
50   if (initialized_) {
51     ALOGE("Already initialized");
52     return;
53   }
54 
55   char path_pattern[PROPERTY_VALUE_MAX];
56   // Could be a valid path or it can have at the end of it the wildcard %
57   // which means that it will try open all devices until an error is met.
58   int path_len = property_get("vendor.hwc.drm.device", path_pattern,
59                               "/dev/dri/card%");
60   if (path_pattern[path_len - 1] != '%') {
61     AddDrmDevice(std::string(path_pattern));
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       if (DrmDevice::IsKMSDev(path.str().c_str())) {
73         AddDrmDevice(path.str());
74       }
75     }
76   }
77 
78   char scale_with_gpu[PROPERTY_VALUE_MAX];
79   property_get("vendor.hwc.drm.scale_with_gpu", scale_with_gpu, "0");
80   scale_with_gpu_ = bool(strncmp(scale_with_gpu, "0", 1));
81 
82   if (BufferInfoGetter::GetInstance() == nullptr) {
83     ALOGE("Failed to initialize BufferInfoGetter");
84     return;
85   }
86 
87   uevent_listener_.RegisterHotplugHandler([this] {
88     const std::lock_guard<std::mutex> lock(GetMainLock());
89     UpdateFrontendDisplays();
90   });
91 
92   UpdateFrontendDisplays();
93 
94   initialized_ = true;
95 }
96 
DeInit()97 void ResourceManager::DeInit() {
98   if (!initialized_) {
99     ALOGE("Not initialized");
100     return;
101   }
102 
103   uevent_listener_.RegisterHotplugHandler([] {});
104 
105   DetachAllFrontendDisplays();
106   drms_.clear();
107 
108   initialized_ = false;
109 }
110 
AddDrmDevice(const std::string & path)111 int ResourceManager::AddDrmDevice(const std::string &path) {
112   auto drm = std::make_unique<DrmDevice>();
113   int ret = drm->Init(path.c_str());
114   drms_.push_back(std::move(drm));
115   return ret;
116 }
117 
GetTimeMonotonicNs()118 auto ResourceManager::GetTimeMonotonicNs() -> int64_t {
119   struct timespec ts {};
120   clock_gettime(CLOCK_MONOTONIC, &ts);
121   constexpr int64_t kNsInSec = 1000000000LL;
122   return int64_t(ts.tv_sec) * kNsInSec + int64_t(ts.tv_nsec);
123 }
124 
UpdateFrontendDisplays()125 void ResourceManager::UpdateFrontendDisplays() {
126   auto ordered_connectors = GetOrderedConnectors();
127 
128   for (auto *conn : ordered_connectors) {
129     conn->UpdateModes();
130     bool connected = conn->IsConnected();
131     bool attached = attached_pipelines_.count(conn) != 0;
132 
133     if (connected != attached) {
134       ALOGI("%s connector %s", connected ? "Attaching" : "Detaching",
135             conn->GetName().c_str());
136 
137       if (connected) {
138         auto pipeline = DrmDisplayPipeline::CreatePipeline(*conn);
139         frontend_interface_->BindDisplay(pipeline.get());
140         attached_pipelines_[conn] = std::move(pipeline);
141       } else {
142         auto &pipeline = attached_pipelines_[conn];
143         frontend_interface_->UnbindDisplay(pipeline.get());
144         attached_pipelines_.erase(conn);
145       }
146     }
147   }
148   frontend_interface_->FinalizeDisplayBinding();
149 }
150 
DetachAllFrontendDisplays()151 void ResourceManager::DetachAllFrontendDisplays() {
152   for (auto &p : attached_pipelines_) {
153     frontend_interface_->UnbindDisplay(p.second.get());
154   }
155   attached_pipelines_.clear();
156   frontend_interface_->FinalizeDisplayBinding();
157 }
158 
GetOrderedConnectors()159 auto ResourceManager::GetOrderedConnectors() -> std::vector<DrmConnector *> {
160   /* Put internal displays first then external to
161    * ensure Internal will take Primary slot
162    */
163 
164   std::vector<DrmConnector *> ordered_connectors;
165 
166   for (auto &drm : drms_) {
167     for (const auto &conn : drm->GetConnectors()) {
168       if (conn->IsInternal()) {
169         ordered_connectors.emplace_back(conn.get());
170       }
171     }
172   }
173 
174   for (auto &drm : drms_) {
175     for (const auto &conn : drm->GetConnectors()) {
176       if (conn->IsExternal()) {
177         ordered_connectors.emplace_back(conn.get());
178       }
179     }
180   }
181 
182   return ordered_connectors;
183 }
184 }  // namespace android
185