1
0
Fork 0
android_external_drm_hwcomp.../drm/ResourceManager.cpp
Roman Stratiienko 4e994055a3 drm_hwcomposer: Rename DrmDisplayCompositor->DrmAtomicStateManager
Primary responsibilities of this class are:

1. Send composition/mode/active state over DRM atomic commit IOCTL
   to the kernel
2. Track commit state and keep planes owned by the Pipeline while they
   are either displayed or staged for displaying.
3. Keep framebuffers alive while they are in use or staged.

Not much related to composition itself, therefore rename it to
DrmAtomicStateManager and move it to drm folder.

Bump clang-tidy level of DrmAtomicStateManager.c to normal by fixing
minor clang-tidy findings.

Signed-off-by: Roman Stratiienko <roman.o.stratiienko@globallogic.com>
2022-02-09 17:40:35 +02:00

184 lines
4.9 KiB
C++

/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "hwc-resource-manager"
#include "ResourceManager.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <ctime>
#include <sstream>
#include "bufferinfo/BufferInfoGetter.h"
#include "drm/DrmAtomicStateManager.h"
#include "drm/DrmDevice.h"
#include "drm/DrmDisplayPipeline.h"
#include "drm/DrmPlane.h"
#include "utils/log.h"
#include "utils/properties.h"
namespace android {
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();
}
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%");
if (path_pattern[path_len - 1] != '%') {
AddDrmDevice(std::string(path_pattern));
} else {
path_pattern[path_len - 1] = '\0';
for (int idx = 0;; ++idx) {
std::ostringstream path;
path << path_pattern << idx;
struct stat buf {};
if (stat(path.str().c_str(), &buf) != 0)
break;
if (DrmDevice::IsKMSDev(path.str().c_str())) {
AddDrmDevice(path.str());
}
}
}
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;
}
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;
}
uevent_listener_.RegisterHotplugHandler([] {});
DetachAllFrontendDisplays();
drms_.clear();
initialized_ = false;
}
int ResourceManager::AddDrmDevice(const std::string &path) {
auto drm = std::make_unique<DrmDevice>();
int ret = drm->Init(path.c_str());
drms_.push_back(std::move(drm));
return ret;
}
auto ResourceManager::GetTimeMonotonicNs() -> int64_t {
struct timespec ts {};
clock_gettime(CLOCK_MONOTONIC, &ts);
constexpr int64_t kNsInSec = 1000000000LL;
return int64_t(ts.tv_sec) * kNsInSec + int64_t(ts.tv_nsec);
}
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_) {
for (const auto &conn : drm->GetConnectors()) {
if (conn->IsExternal()) {
ordered_connectors.emplace_back(conn.get());
}
}
}
return ordered_connectors;
}
} // namespace android