aboutsummaryrefslogtreecommitdiff
path: root/drm
diff options
context:
space:
mode:
Diffstat (limited to 'drm')
-rw-r--r--drm/DrmDevice.cpp56
-rw-r--r--drm/DrmDevice.h15
-rw-r--r--drm/ResourceManager.cpp121
-rw-r--r--drm/ResourceManager.h43
4 files changed, 132 insertions, 103 deletions
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp
index d1ae7c9..e5f41e8 100644
--- a/drm/DrmDevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -22,12 +22,8 @@
#include <xf86drm.h>
#include <xf86drmMode.h>
-#include <algorithm>
-#include <array>
-#include <cerrno>
#include <cinttypes>
#include <cstdint>
-#include <sstream>
#include <string>
#include "compositor/DrmDisplayCompositor.h"
@@ -41,26 +37,25 @@ DrmDevice::DrmDevice() {
drm_fb_importer_ = std::make_unique<DrmFbImporter>(*this);
}
-// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
-std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
+auto DrmDevice::Init(const char *path) -> int {
/* TODO: Use drmOpenControl here instead */
fd_ = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
if (!fd_) {
// NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme
ALOGE("Failed to open dri %s: %s", path, strerror(errno));
- return std::make_tuple(-ENODEV, 0);
+ return -ENODEV;
}
int ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
if (ret != 0) {
ALOGE("Failed to set universal plane cap %d", ret);
- return std::make_tuple(ret, 0);
+ return ret;
}
ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_ATOMIC, 1);
if (ret != 0) {
ALOGE("Failed to set atomic cap %d", ret);
- return std::make_tuple(ret, 0);
+ return ret;
}
#ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
@@ -80,13 +75,13 @@ std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
drmSetMaster(GetFd());
if (drmIsMaster(GetFd()) == 0) {
ALOGE("DRM/KMS master access required");
- return std::make_tuple(-EACCES, 0);
+ return -EACCES;
}
auto res = MakeDrmModeResUnique(GetFd());
if (!res) {
ALOGE("Failed to get DrmDevice resources");
- return std::make_tuple(-ENODEV, 0);
+ return -ENODEV;
}
min_resolution_ = std::pair<uint32_t, uint32_t>(res->min_width,
@@ -128,7 +123,7 @@ std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
auto plane_res = MakeDrmModePlaneResUnique(GetFd());
if (!plane_res) {
ALOGE("Failed to get plane resources");
- return std::make_tuple(-ENOENT, 0);
+ return -ENOENT;
}
for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
@@ -140,42 +135,7 @@ std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
}
}
- auto add_displays = [this, &num_displays](bool internal, bool connected) {
- for (auto &conn : connectors_) {
- bool is_connected = conn->IsConnected();
- if ((internal ? conn->IsInternal() : conn->IsExternal()) &&
- (connected ? is_connected : !is_connected)) {
- auto pipe = DrmDisplayPipeline::CreatePipeline(*conn);
- if (pipe) {
- pipelines_[num_displays] = std::move(pipe);
- ++num_displays;
- }
- }
- }
- };
-
- /* Put internal first to ensure Primary display will be internal
- * in case at least 1 internal is available
- */
- add_displays(/*internal = */ true, /*connected = */ true);
- add_displays(/*internal = */ false, /*connected = */ true);
- add_displays(/*internal = */ true, /*connected = */ false);
- add_displays(/*internal = */ false, /*connected = */ false);
-
- return std::make_tuple(0, pipelines_.size());
-}
-
-bool DrmDevice::HandlesDisplay(int display) const {
- return pipelines_.count(display) != 0;
-}
-
-auto DrmDevice::GetDisplayId(DrmConnector *conn) -> int {
- for (auto &dpipe : pipelines_) {
- if (dpipe.second->connector->Get() == conn) {
- return dpipe.first;
- }
- }
- return -1;
+ return 0;
}
auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h
index 5220760..f2530ee 100644
--- a/drm/DrmDevice.h
+++ b/drm/DrmDevice.h
@@ -37,7 +37,7 @@ class DrmDevice {
DrmDevice();
~DrmDevice() = default;
- std::tuple<int, int> Init(const char *path, int num_displays);
+ auto Init(const char *path) -> int;
auto GetFd() const {
return fd_.Get();
@@ -56,19 +56,12 @@ class DrmDevice {
return max_resolution_;
}
- auto *GetPipelineForDisplay(int display) {
- return pipelines_.count(display) != 0 ? pipelines_.at(display).get()
- : nullptr;
- }
-
std::string GetName() const;
auto RegisterUserPropertyBlob(void *data, size_t length) const
-> DrmModeUserPropertyBlobUnique;
- bool HandlesDisplay(int display) const;
-
- bool HasAddFb2ModifiersSupport() const {
+ auto HasAddFb2ModifiersSupport() const {
return HasAddFb2ModifiersSupport_;
}
@@ -98,8 +91,6 @@ class DrmDevice {
return nullptr;
}
- auto GetDisplayId(DrmConnector *conn) -> int;
-
int GetProperty(uint32_t obj_id, uint32_t obj_type, const char *prop_name,
DrmProperty *property) const;
@@ -115,8 +106,6 @@ class DrmDevice {
std::pair<uint32_t, uint32_t> min_resolution_;
std::pair<uint32_t, uint32_t> max_resolution_;
- std::map<int /*display*/, std::unique_ptr<DrmDisplayPipeline>> pipelines_;
-
bool HasAddFb2ModifiersSupport_{};
std::unique_ptr<DrmFbImporter> drm_fb_importer_;
diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp
index a7d99ee..789eca3 100644
--- a/drm/ResourceManager.cpp
+++ b/drm/ResourceManager.cpp
@@ -33,25 +33,34 @@
namespace android {
-ResourceManager::ResourceManager() : num_displays_(0) {
+ResourceManager::ResourceManager(
+ PipelineToFrontendBindingInterface *p2f_bind_interface)
+ : frontend_interface_(p2f_bind_interface) {
+ if (uevent_listener_.Init() != 0) {
+ ALOGE("Can't initialize event listener");
+ }
}
ResourceManager::~ResourceManager() {
uevent_listener_.Exit();
}
-int ResourceManager::Init() {
+void ResourceManager::Init() {
+ if (initialized_) {
+ ALOGE("Already initialized");
+ return;
+ }
+
char path_pattern[PROPERTY_VALUE_MAX];
// Could be a valid path or it can have at the end of it the wildcard %
// which means that it will try open all devices until an error is met.
int path_len = property_get("vendor.hwc.drm.device", path_pattern,
"/dev/dri/card%");
- int ret = 0;
if (path_pattern[path_len - 1] != '%') {
- ret = AddDrmDevice(std::string(path_pattern));
+ AddDrmDevice(std::string(path_pattern));
} else {
path_pattern[path_len - 1] = '\0';
- for (int idx = 0; ret == 0; ++idx) {
+ for (int idx = 0;; ++idx) {
std::ostringstream path;
path << path_pattern << idx;
@@ -59,51 +68,109 @@ int ResourceManager::Init() {
if (stat(path.str().c_str(), &buf) != 0)
break;
- if (DrmDevice::IsKMSDev(path.str().c_str()))
- ret = AddDrmDevice(path.str());
+ if (DrmDevice::IsKMSDev(path.str().c_str())) {
+ AddDrmDevice(path.str());
+ }
}
}
- if (num_displays_ == 0) {
- ALOGE("Failed to initialize any displays");
- return ret != 0 ? -EINVAL : ret;
- }
-
char scale_with_gpu[PROPERTY_VALUE_MAX];
property_get("vendor.hwc.drm.scale_with_gpu", scale_with_gpu, "0");
scale_with_gpu_ = bool(strncmp(scale_with_gpu, "0", 1));
if (BufferInfoGetter::GetInstance() == nullptr) {
ALOGE("Failed to initialize BufferInfoGetter");
- return -EINVAL;
+ return;
}
- ret = uevent_listener_.Init();
- if (ret != 0) {
- ALOGE("Can't initialize event listener %d", ret);
- return ret;
+ uevent_listener_.RegisterHotplugHandler([this] {
+ const std::lock_guard<std::mutex> lock(GetMainLock());
+ UpdateFrontendDisplays();
+ });
+
+ UpdateFrontendDisplays();
+
+ initialized_ = true;
+}
+
+void ResourceManager::DeInit() {
+ if (!initialized_) {
+ ALOGE("Not initialized");
+ return;
}
- return 0;
+ uevent_listener_.RegisterHotplugHandler([] {});
+
+ DetachAllFrontendDisplays();
+ drms_.clear();
+
+ initialized_ = false;
}
int ResourceManager::AddDrmDevice(const std::string &path) {
auto drm = std::make_unique<DrmDevice>();
- int displays_added = 0;
- int ret = 0;
- std::tie(ret, displays_added) = drm->Init(path.c_str(), num_displays_);
+ int ret = drm->Init(path.c_str());
drms_.push_back(std::move(drm));
- num_displays_ += displays_added;
return ret;
}
-DrmDisplayPipeline *ResourceManager::GetPipeline(int display) {
+void ResourceManager::UpdateFrontendDisplays() {
+ auto ordered_connectors = GetOrderedConnectors();
+
+ for (auto *conn : ordered_connectors) {
+ conn->UpdateModes();
+ bool connected = conn->IsConnected();
+ bool attached = attached_pipelines_.count(conn) != 0;
+
+ if (connected != attached) {
+ ALOGI("%s connector %s", connected ? "Attaching" : "Detaching",
+ conn->GetName().c_str());
+
+ if (connected) {
+ auto pipeline = DrmDisplayPipeline::CreatePipeline(*conn);
+ frontend_interface_->BindDisplay(pipeline.get());
+ attached_pipelines_[conn] = std::move(pipeline);
+ } else {
+ auto &pipeline = attached_pipelines_[conn];
+ frontend_interface_->UnbindDisplay(pipeline.get());
+ attached_pipelines_.erase(conn);
+ }
+ }
+ }
+ frontend_interface_->FinalizeDisplayBinding();
+}
+
+void ResourceManager::DetachAllFrontendDisplays() {
+ for (auto &p : attached_pipelines_) {
+ frontend_interface_->UnbindDisplay(p.second.get());
+ }
+ attached_pipelines_.clear();
+ frontend_interface_->FinalizeDisplayBinding();
+}
+
+auto ResourceManager::GetOrderedConnectors() -> std::vector<DrmConnector *> {
+ /* Put internal displays first then external to
+ * ensure Internal will take Primary slot
+ */
+
+ std::vector<DrmConnector *> ordered_connectors;
+
+ for (auto &drm : drms_) {
+ for (const auto &conn : drm->GetConnectors()) {
+ if (conn->IsInternal()) {
+ ordered_connectors.emplace_back(conn.get());
+ }
+ }
+ }
+
for (auto &drm : drms_) {
- auto *pipe = drm->GetPipelineForDisplay(display);
- if (pipe != nullptr) {
- return pipe;
+ for (const auto &conn : drm->GetConnectors()) {
+ if (conn->IsExternal()) {
+ ordered_connectors.emplace_back(conn.get());
+ }
}
}
- return nullptr;
+
+ return ordered_connectors;
}
} // namespace android
diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h
index caeb098..c4c3edd 100644
--- a/drm/ResourceManager.h
+++ b/drm/ResourceManager.h
@@ -20,42 +20,48 @@
#include <cstring>
#include "DrmDevice.h"
+#include "DrmDisplayPipeline.h"
#include "DrmFbImporter.h"
#include "UEventListener.h"
namespace android {
+class PipelineToFrontendBindingInterface {
+ public:
+ virtual ~PipelineToFrontendBindingInterface() = default;
+ virtual bool BindDisplay(DrmDisplayPipeline *);
+ virtual bool UnbindDisplay(DrmDisplayPipeline *);
+ virtual void FinalizeDisplayBinding();
+};
+
class ResourceManager {
public:
- ResourceManager();
+ explicit ResourceManager(
+ PipelineToFrontendBindingInterface *p2f_bind_interface);
ResourceManager(const ResourceManager &) = delete;
ResourceManager &operator=(const ResourceManager &) = delete;
+ ResourceManager(const ResourceManager &&) = delete;
+ ResourceManager &&operator=(const ResourceManager &&) = delete;
~ResourceManager();
- int Init();
- auto GetPipeline(int display) -> DrmDisplayPipeline *;
- auto &GetDrmDevices() const {
- return drms_;
- }
- int GetDisplayCount() const {
- return num_displays_;
- }
+ void Init();
+
+ void DeInit();
+
bool ForcedScalingWithGpu() const {
return scale_with_gpu_;
}
- UEventListener *GetUEventListener() {
- return &uevent_listener_;
- }
-
auto &GetMainLock() {
return main_lock_;
}
private:
- int AddDrmDevice(std::string const &path);
+ auto AddDrmDevice(std::string const &path) -> int;
+ auto GetOrderedConnectors() -> std::vector<DrmConnector *>;
+ void UpdateFrontendDisplays();
+ void DetachAllFrontendDisplays();
- int num_displays_;
std::vector<std::unique_ptr<DrmDevice>> drms_;
bool scale_with_gpu_{};
@@ -63,6 +69,13 @@ class ResourceManager {
UEventListener uevent_listener_;
std::mutex main_lock_;
+
+ std::map<DrmConnector *, std::unique_ptr<DrmDisplayPipeline>>
+ attached_pipelines_;
+
+ PipelineToFrontendBindingInterface *const frontend_interface_;
+
+ bool initialized_{};
};
} // namespace android