Commit c5463587 authored by Alexandru Gheorghe's avatar Alexandru Gheorghe
Browse files

drm_hwcomposer: Add resource manager support



Add a resource manager class that is responsible for detecting all
kms devices and allocates unique display numbers for every detected
display.

This is controlled by the value of hwc.drm.device property, if it ends
with a %, it will try to open minor devices until an error is detected.
E.g: /dev/dri/card%

Additionally, this will be used for finding an available writeback
connector that will be used for the flattening of the currently
displayed scene.

Signed-off-by: default avatarAlexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com>
parent 0f5abd79
......@@ -56,6 +56,7 @@ LOCAL_C_INCLUDES := \
LOCAL_SRC_FILES := \
autolock.cpp \
resourcemanager.cpp \
drmdevice.cpp \
drmconnector.cpp \
drmcrtc.cpp \
......
......@@ -42,33 +42,30 @@ DrmDevice::~DrmDevice() {
event_listener_.Exit();
}
int DrmDevice::Init() {
char path[PROPERTY_VALUE_MAX];
property_get("hwc.drm.device", path, "/dev/dri/card0");
std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
/* TODO: Use drmOpenControl here instead */
fd_.Set(open(path, O_RDWR));
if (fd() < 0) {
ALOGE("Failed to open dri- %s", strerror(-errno));
return -ENODEV;
return std::make_tuple(-ENODEV, 0);
}
int ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
if (ret) {
ALOGE("Failed to set universal plane cap %d", ret);
return ret;
return std::make_tuple(ret, 0);
}
ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_ATOMIC, 1);
if (ret) {
ALOGE("Failed to set atomic cap %d", ret);
return ret;
return std::make_tuple(ret, 0);
}
drmModeResPtr res = drmModeGetResources(fd());
if (!res) {
ALOGE("Failed to get DrmDevice resources");
return -ENODEV;
return std::make_tuple(-ENODEV, 0);
}
min_resolution_ =
......@@ -76,8 +73,9 @@ int DrmDevice::Init() {
max_resolution_ =
std::pair<uint32_t, uint32_t>(res->max_width, res->max_height);
bool found_primary = false;
int display_num = 1;
// Assumes that the primary display will always be in the first
// drm_device opened.
bool found_primary = num_displays != 0;
for (int i = 0; !ret && i < res->count_crtcs; ++i) {
drmModeCrtcPtr c = drmModeGetCrtc(fd(), res->crtcs[i]);
......@@ -160,19 +158,28 @@ int DrmDevice::Init() {
// First look for primary amongst internal connectors
for (auto &conn : connectors_) {
if (conn->internal() && !found_primary) {
conn->set_display(0);
conn->set_display(num_displays);
displays_[num_displays] = num_displays;
++num_displays;
found_primary = true;
} else {
conn->set_display(display_num);
++display_num;
break;
}
}
// Then look for primary amongst external connectors
// Then pick first available as primary and for the others assign
// consecutive display_numbers.
for (auto &conn : connectors_) {
if (conn->external() && !found_primary) {
conn->set_display(0);
found_primary = true;
if (conn->external() || conn->internal()) {
if (!found_primary) {
conn->set_display(num_displays);
displays_[num_displays] = num_displays;
found_primary = true;
++num_displays;
} else if (conn->display() < 0) {
conn->set_display(num_displays);
displays_[num_displays] = num_displays;
++num_displays;
}
}
}
......@@ -181,12 +188,12 @@ int DrmDevice::Init() {
// Catch-all for the above loops
if (ret)
return ret;
return std::make_tuple(ret, 0);
drmModePlaneResPtr plane_res = drmModeGetPlaneResources(fd());
if (!plane_res) {
ALOGE("Failed to get plane resources");
return -ENOENT;
return std::make_tuple(-ENOENT, 0);
}
for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
......@@ -211,22 +218,26 @@ int DrmDevice::Init() {
}
drmModeFreePlaneResources(plane_res);
if (ret)
return ret;
return std::make_tuple(ret, 0);
ret = event_listener_.Init();
if (ret) {
ALOGE("Can't initialize event listener %d", ret);
return ret;
return std::make_tuple(ret, 0);
}
for (auto &conn : connectors_) {
ret = CreateDisplayPipe(conn.get());
if (ret) {
ALOGE("Failed CreateDisplayPipe %d with %d", conn->id(), ret);
return ret;
return std::make_tuple(ret, 0);
}
}
return 0;
return std::make_tuple(ret, displays_.size());
}
bool DrmDevice::HandlesDisplay(int display) const {
return displays_.find(display) != displays_.end();
}
DrmConnector *DrmDevice::GetConnectorForDisplay(int display) const {
......
......@@ -22,8 +22,10 @@
#include "drmencoder.h"
#include "drmeventlistener.h"
#include "drmplane.h"
#include "platform.h"
#include <stdint.h>
#include <tuple>
namespace android {
......@@ -32,7 +34,7 @@ class DrmDevice {
DrmDevice();
~DrmDevice();
int Init();
std::tuple<int, int> Init(const char *path, int num_displays);
int fd() const {
return fd_.get();
......@@ -71,6 +73,7 @@ class DrmDevice {
int CreatePropertyBlob(void *data, size_t length, uint32_t *blob_id);
int DestroyPropertyBlob(uint32_t blob_id);
bool HandlesDisplay(int display) const;
private:
int TryEncoderForDisplay(int display, DrmEncoder *enc);
......@@ -90,6 +93,7 @@ class DrmDevice {
std::pair<uint32_t, uint32_t> min_resolution_;
std::pair<uint32_t, uint32_t> max_resolution_;
std::map<int, int> displays_;
};
}
......
......@@ -58,24 +58,26 @@ DrmHwcTwo::DrmHwcTwo() {
}
HWC2::Error DrmHwcTwo::Init() {
int ret = drm_.Init();
int ret = resource_manager_.Init();
if (ret) {
ALOGE("Can't initialize drm object %d", ret);
ALOGE("Can't initialize the resource manager %d", ret);
return HWC2::Error::NoResources;
}
importer_.reset(Importer::CreateInstance(&drm_));
if (!importer_) {
ALOGE("Failed to create importer instance");
DrmDevice *drm = resource_manager_.GetDrmDevice(HWC_DISPLAY_PRIMARY);
std::shared_ptr<Importer> importer =
resource_manager_.GetImporter(HWC_DISPLAY_PRIMARY);
if (!drm || !importer) {
ALOGE("Failed to get a valid drmresource and importer");
return HWC2::Error::NoResources;
}
displays_.emplace(std::piecewise_construct,
std::forward_as_tuple(HWC_DISPLAY_PRIMARY),
std::forward_as_tuple(&drm_, importer_, HWC_DISPLAY_PRIMARY,
std::forward_as_tuple(drm, importer, HWC_DISPLAY_PRIMARY,
HWC2::DisplayType::Physical));
DrmCrtc *crtc = drm_.GetCrtcForDisplay(static_cast<int>(HWC_DISPLAY_PRIMARY));
DrmCrtc *crtc = drm->GetCrtcForDisplay(static_cast<int>(HWC_DISPLAY_PRIMARY));
if (!crtc) {
ALOGE("Failed to get crtc for display %d",
static_cast<int>(HWC_DISPLAY_PRIMARY));
......@@ -83,7 +85,7 @@ HWC2::Error DrmHwcTwo::Init() {
}
std::vector<DrmPlane *> display_planes;
for (auto &plane : drm_.planes()) {
for (auto &plane : drm->planes()) {
if (plane->GetCrtcSupported(*crtc))
display_planes.push_back(plane.get());
}
......
......@@ -16,8 +16,8 @@
#include "drmdisplaycompositor.h"
#include "drmhwcomposer.h"
#include "drmdevice.h"
#include "platform.h"
#include "resourcemanager.h"
#include "vsyncworker.h"
#include <hardware/hwcomposer2.h>
......@@ -261,8 +261,7 @@ class DrmHwcTwo : public hwc2_device_t {
HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data,
hwc2_function_pointer_t function);
DrmDevice drm_;
std::shared_ptr<Importer> importer_; // Shared with HwcDisplay
ResourceManager resource_manager_;
std::map<hwc2_display_t, HwcDisplay> displays_;
std::map<HWC2::Callback, HwcCallback> callbacks_;
};
......
/*
* 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 <cutils/properties.h>
#include <log/log.h>
#include <sstream>
#include <string>
namespace android {
ResourceManager::ResourceManager() : num_displays_(0), gralloc_(NULL) {
}
int ResourceManager::Init() {
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("hwc.drm.device", path_pattern, "/dev/dri/card0");
int ret = 0;
if (path_pattern[path_len - 1] != '%') {
ret = AddDrmDevice(std::string(path_pattern));
} else {
path_pattern[path_len - 1] = '\0';
for (int idx = 0; !ret; ++idx) {
std::ostringstream path;
path << path_pattern << idx;
ret = AddDrmDevice(path.str());
}
}
if (!num_displays_) {
ALOGE("Failed to initialize any displays");
return ret ? -EINVAL : ret;
}
return hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
(const hw_module_t **)&gralloc_);
}
int ResourceManager::AddDrmDevice(std::string path) {
std::unique_ptr<DrmDevice> drm = std::make_unique<DrmDevice>();
int displays_added, ret;
std::tie(ret, displays_added) = drm->Init(path.c_str(), num_displays_);
if (ret)
return ret;
std::shared_ptr<Importer> importer;
importer.reset(Importer::CreateInstance(drm.get()));
if (!importer) {
ALOGE("Failed to create importer instance");
return -ENODEV;
}
importers_.push_back(importer);
drms_.push_back(std::move(drm));
num_displays_ += displays_added;
return ret;
}
DrmDevice *ResourceManager::GetDrmDevice(int display) {
for (auto &drm : drms_) {
if (drm->HandlesDisplay(display))
return drm.get();
}
return NULL;
}
std::shared_ptr<Importer> ResourceManager::GetImporter(int display) {
for (unsigned int i = 0; i < drms_.size(); i++) {
if (drms_[i]->HandlesDisplay(display))
return importers_[i];
}
return NULL;
}
const gralloc_module_t *ResourceManager::gralloc() {
return gralloc_;
}
}
/*
* 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.
*/
#ifndef RESOURCEMANAGER_H
#define RESOURCEMANAGER_H
#include "drmdevice.h"
#include "platform.h"
#include <string.h>
namespace android {
class ResourceManager {
public:
ResourceManager();
ResourceManager(const ResourceManager &) = delete;
ResourceManager &operator=(const ResourceManager &) = delete;
int Init();
DrmDevice *GetDrmDevice(int display);
std::shared_ptr<Importer> GetImporter(int display);
const gralloc_module_t *gralloc();
private:
int AddDrmDevice(std::string path);
int num_displays_;
std::vector<std::unique_ptr<DrmDevice>> drms_;
std::vector<std::shared_ptr<Importer>> importers_;
const gralloc_module_t *gralloc_;
};
}
#endif // RESOURCEMANAGER_H
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment