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