diff options
Diffstat (limited to 'drm')
-rw-r--r-- | drm/DrmDevice.cpp | 56 | ||||
-rw-r--r-- | drm/DrmDevice.h | 15 | ||||
-rw-r--r-- | drm/ResourceManager.cpp | 121 | ||||
-rw-r--r-- | drm/ResourceManager.h | 43 |
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 |