From 13cc3666c63010a4fc12568d645703bf365ccfc7 Mon Sep 17 00:00:00 2001 From: Roman Stratiienko Date: Sat, 29 Aug 2020 21:35:39 +0300 Subject: drm_hwcomposer: use CamelCase in source/header files related to class Main goal is to increase readability of file names. AOSP uses camelcase for files in many projects. Lets do the same for drm_hwcomposer. Keep platform/ directory as is, since class names is different from file names. Signed-off-by: Roman Stratiienko Change-Id: I7e992357851c2a86711f4da1241c4d507359e56b --- drm/DrmConnector.cpp | 233 +++++++++++++++++++ drm/DrmConnector.h | 116 ++++++++++ drm/DrmCrtc.cpp | 85 +++++++ drm/DrmCrtc.h | 65 ++++++ drm/DrmDevice.cpp | 579 ++++++++++++++++++++++++++++++++++++++++++++++ drm/DrmDevice.h | 110 +++++++++ drm/DrmEncoder.cpp | 62 +++++ drm/DrmEncoder.h | 60 +++++ drm/DrmEventListener.cpp | 138 +++++++++++ drm/DrmEventListener.h | 65 ++++++ drm/DrmMode.cpp | 137 +++++++++++ drm/DrmMode.h | 83 +++++++ drm/DrmPlane.cpp | 215 ++++++++++++++++++ drm/DrmPlane.h | 88 +++++++ drm/DrmProperty.cpp | 135 +++++++++++ drm/DrmProperty.h | 79 +++++++ drm/ResourceManager.cpp | 144 ++++++++++++ drm/ResourceManager.h | 60 +++++ drm/VSyncWorker.cpp | 187 +++++++++++++++ drm/VSyncWorker.h | 68 ++++++ drm/drmconnector.cpp | 233 ------------------- drm/drmconnector.h | 116 ---------- drm/drmcrtc.cpp | 85 ------- drm/drmcrtc.h | 65 ------ drm/drmdevice.cpp | 580 ----------------------------------------------- drm/drmdevice.h | 110 --------- drm/drmencoder.cpp | 61 ----- drm/drmencoder.h | 60 ----- drm/drmeventlistener.cpp | 138 ----------- drm/drmeventlistener.h | 65 ------ drm/drmmode.cpp | 136 ----------- drm/drmmode.h | 83 ------- drm/drmplane.cpp | 214 ----------------- drm/drmplane.h | 88 ------- drm/drmproperty.cpp | 134 ----------- drm/drmproperty.h | 79 ------- drm/resourcemanager.cpp | 143 ------------ drm/resourcemanager.h | 60 ----- drm/vsyncworker.cpp | 188 --------------- drm/vsyncworker.h | 68 ------ 40 files changed, 2709 insertions(+), 2706 deletions(-) create mode 100644 drm/DrmConnector.cpp create mode 100644 drm/DrmConnector.h create mode 100644 drm/DrmCrtc.cpp create mode 100644 drm/DrmCrtc.h create mode 100644 drm/DrmDevice.cpp create mode 100644 drm/DrmDevice.h create mode 100644 drm/DrmEncoder.cpp create mode 100644 drm/DrmEncoder.h create mode 100644 drm/DrmEventListener.cpp create mode 100644 drm/DrmEventListener.h create mode 100644 drm/DrmMode.cpp create mode 100644 drm/DrmMode.h create mode 100644 drm/DrmPlane.cpp create mode 100644 drm/DrmPlane.h create mode 100644 drm/DrmProperty.cpp create mode 100644 drm/DrmProperty.h create mode 100644 drm/ResourceManager.cpp create mode 100644 drm/ResourceManager.h create mode 100644 drm/VSyncWorker.cpp create mode 100644 drm/VSyncWorker.h delete mode 100644 drm/drmconnector.cpp delete mode 100644 drm/drmconnector.h delete mode 100644 drm/drmcrtc.cpp delete mode 100644 drm/drmcrtc.h delete mode 100644 drm/drmdevice.cpp delete mode 100644 drm/drmdevice.h delete mode 100644 drm/drmencoder.cpp delete mode 100644 drm/drmencoder.h delete mode 100644 drm/drmeventlistener.cpp delete mode 100644 drm/drmeventlistener.h delete mode 100644 drm/drmmode.cpp delete mode 100644 drm/drmmode.h delete mode 100644 drm/drmplane.cpp delete mode 100644 drm/drmplane.h delete mode 100644 drm/drmproperty.cpp delete mode 100644 drm/drmproperty.h delete mode 100644 drm/resourcemanager.cpp delete mode 100644 drm/resourcemanager.h delete mode 100644 drm/vsyncworker.cpp delete mode 100644 drm/vsyncworker.h (limited to 'drm') diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp new file mode 100644 index 0000000..8fa47f5 --- /dev/null +++ b/drm/DrmConnector.cpp @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2015 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-drm-connector" + +#include "DrmConnector.h" + +#include +#include +#include +#include + +#include +#include + +#include "DrmDevice.h" + +namespace android { + +constexpr size_t TYPES_COUNT = 17; + +DrmConnector::DrmConnector(DrmDevice *drm, drmModeConnectorPtr c, + DrmEncoder *current_encoder, + std::vector &possible_encoders) + : drm_(drm), + id_(c->connector_id), + encoder_(current_encoder), + display_(-1), + type_(c->connector_type), + type_id_(c->connector_type_id), + state_(c->connection), + mm_width_(c->mmWidth), + mm_height_(c->mmHeight), + possible_encoders_(possible_encoders) { +} + +int DrmConnector::Init() { + int ret = drm_->GetConnectorProperty(*this, "DPMS", &dpms_property_); + if (ret) { + ALOGE("Could not get DPMS property\n"); + return ret; + } + ret = drm_->GetConnectorProperty(*this, "CRTC_ID", &crtc_id_property_); + if (ret) { + ALOGE("Could not get CRTC_ID property\n"); + return ret; + } + ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_); + if (ret) { + ALOGW("Could not get EDID property\n"); + } + if (writeback()) { + ret = drm_->GetConnectorProperty(*this, "WRITEBACK_PIXEL_FORMATS", + &writeback_pixel_formats_); + if (ret) { + ALOGE("Could not get WRITEBACK_PIXEL_FORMATS connector_id = %d\n", id_); + return ret; + } + ret = drm_->GetConnectorProperty(*this, "WRITEBACK_FB_ID", + &writeback_fb_id_); + if (ret) { + ALOGE("Could not get WRITEBACK_FB_ID connector_id = %d\n", id_); + return ret; + } + ret = drm_->GetConnectorProperty(*this, "WRITEBACK_OUT_FENCE_PTR", + &writeback_out_fence_); + if (ret) { + ALOGE("Could not get WRITEBACK_OUT_FENCE_PTR connector_id = %d\n", id_); + return ret; + } + } + return 0; +} + +uint32_t DrmConnector::id() const { + return id_; +} + +int DrmConnector::display() const { + return display_; +} + +void DrmConnector::set_display(int display) { + display_ = display; +} + +bool DrmConnector::internal() const { + return type_ == DRM_MODE_CONNECTOR_LVDS || type_ == DRM_MODE_CONNECTOR_eDP || + type_ == DRM_MODE_CONNECTOR_DSI || + type_ == DRM_MODE_CONNECTOR_VIRTUAL || type_ == DRM_MODE_CONNECTOR_DPI; +} + +bool DrmConnector::external() const { + return type_ == DRM_MODE_CONNECTOR_HDMIA || + type_ == DRM_MODE_CONNECTOR_DisplayPort || + type_ == DRM_MODE_CONNECTOR_DVID || type_ == DRM_MODE_CONNECTOR_DVII || + type_ == DRM_MODE_CONNECTOR_VGA; +} + +bool DrmConnector::writeback() const { +#ifdef DRM_MODE_CONNECTOR_WRITEBACK + return type_ == DRM_MODE_CONNECTOR_WRITEBACK; +#else + return false; +#endif +} + +bool DrmConnector::valid_type() const { + return internal() || external() || writeback(); +} + +std::string DrmConnector::name() const { + constexpr std::array names = + {"None", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite", + "SVIDEO", "LVDS", "Component", "DIN", "DP", "HDMI-A", + "HDMI-B", "TV", "eDP", "Virtual", "DSI"}; + + if (type_ < TYPES_COUNT) { + std::ostringstream name_buf; + name_buf << names[type_] << "-" << type_id_; + return name_buf.str(); + } else { + ALOGE("Unknown type in connector %d, could not make his name", id_); + return "None"; + } +} + +int DrmConnector::UpdateModes() { + int fd = drm_->fd(); + + drmModeConnectorPtr c = drmModeGetConnector(fd, id_); + if (!c) { + ALOGE("Failed to get connector %d", id_); + return -ENODEV; + } + + state_ = c->connection; + + bool preferred_mode_found = false; + std::vector new_modes; + for (int i = 0; i < c->count_modes; ++i) { + bool exists = false; + for (const DrmMode &mode : modes_) { + if (mode == c->modes[i]) { + new_modes.push_back(mode); + exists = true; + break; + } + } + if (!exists) { + DrmMode m(&c->modes[i]); + m.set_id(drm_->next_mode_id()); + new_modes.push_back(m); + } + // Use only the first DRM_MODE_TYPE_PREFERRED mode found + if (!preferred_mode_found && + (new_modes.back().type() & DRM_MODE_TYPE_PREFERRED)) { + preferred_mode_id_ = new_modes.back().id(); + preferred_mode_found = true; + } + } + modes_.swap(new_modes); + if (!preferred_mode_found && modes_.size() != 0) { + preferred_mode_id_ = modes_[0].id(); + } + return 0; +} + +const DrmMode &DrmConnector::active_mode() const { + return active_mode_; +} + +void DrmConnector::set_active_mode(const DrmMode &mode) { + active_mode_ = mode; +} + +const DrmProperty &DrmConnector::dpms_property() const { + return dpms_property_; +} + +const DrmProperty &DrmConnector::crtc_id_property() const { + return crtc_id_property_; +} + +const DrmProperty &DrmConnector::edid_property() const { + return edid_property_; +} + +const DrmProperty &DrmConnector::writeback_pixel_formats() const { + return writeback_pixel_formats_; +} + +const DrmProperty &DrmConnector::writeback_fb_id() const { + return writeback_fb_id_; +} + +const DrmProperty &DrmConnector::writeback_out_fence() const { + return writeback_out_fence_; +} + +DrmEncoder *DrmConnector::encoder() const { + return encoder_; +} + +void DrmConnector::set_encoder(DrmEncoder *encoder) { + encoder_ = encoder; +} + +drmModeConnection DrmConnector::state() const { + return state_; +} + +uint32_t DrmConnector::mm_width() const { + return mm_width_; +} + +uint32_t DrmConnector::mm_height() const { + return mm_height_; +} +} // namespace android diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h new file mode 100644 index 0000000..3fdf146 --- /dev/null +++ b/drm/DrmConnector.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2015 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 ANDROID_DRM_CONNECTOR_H_ +#define ANDROID_DRM_CONNECTOR_H_ + +#include +#include + +#include +#include + +#include "DrmEncoder.h" +#include "DrmMode.h" +#include "DrmProperty.h" + +namespace android { + +class DrmDevice; + +class DrmConnector { + public: + DrmConnector(DrmDevice *drm, drmModeConnectorPtr c, + DrmEncoder *current_encoder, + std::vector &possible_encoders); + DrmConnector(const DrmProperty &) = delete; + DrmConnector &operator=(const DrmProperty &) = delete; + + int Init(); + + uint32_t id() const; + + int display() const; + void set_display(int display); + + bool internal() const; + bool external() const; + bool writeback() const; + bool valid_type() const; + + std::string name() const; + + int UpdateModes(); + + const std::vector &modes() const { + return modes_; + } + const DrmMode &active_mode() const; + void set_active_mode(const DrmMode &mode); + + const DrmProperty &dpms_property() const; + const DrmProperty &crtc_id_property() const; + const DrmProperty &edid_property() const; + const DrmProperty &writeback_pixel_formats() const; + const DrmProperty &writeback_fb_id() const; + const DrmProperty &writeback_out_fence() const; + + const std::vector &possible_encoders() const { + return possible_encoders_; + } + DrmEncoder *encoder() const; + void set_encoder(DrmEncoder *encoder); + + drmModeConnection state() const; + + uint32_t mm_width() const; + uint32_t mm_height() const; + + uint32_t get_preferred_mode_id() const { + return preferred_mode_id_; + } + + private: + DrmDevice *drm_; + + uint32_t id_; + DrmEncoder *encoder_; + int display_; + + uint32_t type_; + uint32_t type_id_; + drmModeConnection state_; + + uint32_t mm_width_; + uint32_t mm_height_; + + DrmMode active_mode_; + std::vector modes_; + + DrmProperty dpms_property_; + DrmProperty crtc_id_property_; + DrmProperty edid_property_; + DrmProperty writeback_pixel_formats_; + DrmProperty writeback_fb_id_; + DrmProperty writeback_out_fence_; + + std::vector possible_encoders_; + + uint32_t preferred_mode_id_; +}; +} // namespace android + +#endif // ANDROID_DRM_PLANE_H_ diff --git a/drm/DrmCrtc.cpp b/drm/DrmCrtc.cpp new file mode 100644 index 0000000..4ce8cfc --- /dev/null +++ b/drm/DrmCrtc.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2015 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-drm-crtc" + +#include "DrmCrtc.h" + +#include +#include +#include + +#include "DrmDevice.h" + +namespace android { + +DrmCrtc::DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe) + : drm_(drm), id_(c->crtc_id), pipe_(pipe), display_(-1), mode_(&c->mode) { +} + +int DrmCrtc::Init() { + int ret = drm_->GetCrtcProperty(*this, "ACTIVE", &active_property_); + if (ret) { + ALOGE("Failed to get ACTIVE property"); + return ret; + } + + ret = drm_->GetCrtcProperty(*this, "MODE_ID", &mode_property_); + if (ret) { + ALOGE("Failed to get MODE_ID property"); + return ret; + } + + ret = drm_->GetCrtcProperty(*this, "OUT_FENCE_PTR", &out_fence_ptr_property_); + if (ret) { + ALOGE("Failed to get OUT_FENCE_PTR property"); + return ret; + } + return 0; +} + +uint32_t DrmCrtc::id() const { + return id_; +} + +unsigned DrmCrtc::pipe() const { + return pipe_; +} + +int DrmCrtc::display() const { + return display_; +} + +void DrmCrtc::set_display(int display) { + display_ = display; +} + +bool DrmCrtc::can_bind(int display) const { + return display_ == -1 || display_ == display; +} + +const DrmProperty &DrmCrtc::active_property() const { + return active_property_; +} + +const DrmProperty &DrmCrtc::mode_property() const { + return mode_property_; +} + +const DrmProperty &DrmCrtc::out_fence_ptr_property() const { + return out_fence_ptr_property_; +} +} // namespace android diff --git a/drm/DrmCrtc.h b/drm/DrmCrtc.h new file mode 100644 index 0000000..7972bef --- /dev/null +++ b/drm/DrmCrtc.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 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 ANDROID_DRM_CRTC_H_ +#define ANDROID_DRM_CRTC_H_ + +#include +#include + +#include "DrmMode.h" +#include "DrmProperty.h" + +namespace android { + +class DrmDevice; + +class DrmCrtc { + public: + DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe); + DrmCrtc(const DrmCrtc &) = delete; + DrmCrtc &operator=(const DrmCrtc &) = delete; + + int Init(); + + uint32_t id() const; + unsigned pipe() const; + + int display() const; + void set_display(int display); + + bool can_bind(int display) const; + + const DrmProperty &active_property() const; + const DrmProperty &mode_property() const; + const DrmProperty &out_fence_ptr_property() const; + + private: + DrmDevice *drm_; + + uint32_t id_; + unsigned pipe_; + int display_; + + DrmMode mode_; + + DrmProperty active_property_; + DrmProperty mode_property_; + DrmProperty out_fence_ptr_property_; +}; +} // namespace android + +#endif // ANDROID_DRM_CRTC_H_ diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp new file mode 100644 index 0000000..28ecfda --- /dev/null +++ b/drm/DrmDevice.cpp @@ -0,0 +1,579 @@ +/* + * Copyright (C) 2015 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-drm-device" + +#include "DrmDevice.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static void trim_left(std::string &str) { + str.erase(std::begin(str), + std::find_if(std::begin(str), std::end(str), + [](int ch) { return !std::isspace(ch); })); +} + +static void trim_right(std::string &str) { + str.erase(std::find_if(std::rbegin(str), std::rend(str), + [](int ch) { return !std::isspace(ch); }) + .base(), + std::end(str)); +} + +static void trim(std::string &str) { + trim_left(str); + trim_right(str); +} + +namespace android { + +static std::vector read_primary_display_order_prop() { + std::array display_order_buf; + property_get("vendor.hwc.drm.primary_display_order", display_order_buf.data(), + "..."); + + std::vector display_order; + std::istringstream str(display_order_buf.data()); + for (std::string conn_name = ""; std::getline(str, conn_name, ',');) { + trim(conn_name); + display_order.push_back(std::move(conn_name)); + } + return display_order; +} + +static std::vector make_primary_display_candidates( + std::vector> &connectors) { + std::vector primary_candidates; + std::transform(std::begin(connectors), std::end(connectors), + std::back_inserter(primary_candidates), + [](std::unique_ptr &conn) { + return conn.get(); + }); + primary_candidates.erase(std::remove_if(std::begin(primary_candidates), + std::end(primary_candidates), + [](const DrmConnector *conn) { + return conn->state() != + DRM_MODE_CONNECTED; + }), + std::end(primary_candidates)); + + std::vector display_order = read_primary_display_order_prop(); + bool use_other = display_order.back() == "..."; + + // putting connectors from primary_display_order first + auto curr_connector = std::begin(primary_candidates); + for (const std::string &display_name : display_order) { + auto it = std::find_if(std::begin(primary_candidates), + std::end(primary_candidates), + [&display_name](const DrmConnector *conn) { + return conn->name() == display_name; + }); + if (it != std::end(primary_candidates)) { + std::iter_swap(it, curr_connector); + ++curr_connector; + } + } + + if (use_other) { + // then putting internal connectors second, everything else afterwards + std::partition(curr_connector, std::end(primary_candidates), + [](const DrmConnector *conn) { return conn->internal(); }); + } else { + primary_candidates.erase(curr_connector, std::end(primary_candidates)); + } + + return primary_candidates; +} + +DrmDevice::DrmDevice() : event_listener_(this) { +} + +DrmDevice::~DrmDevice() { + event_listener_.Exit(); +} + +std::tuple 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: %s", path, strerror(errno)); + 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 std::make_tuple(ret, 0); + } + + ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_ATOMIC, 1); + if (ret) { + ALOGE("Failed to set atomic cap %d", ret); + return std::make_tuple(ret, 0); + } + +#ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS + ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1); + if (ret) { + ALOGI("Failed to set writeback cap %d", ret); + ret = 0; + } +#endif + + drmModeResPtr res = drmModeGetResources(fd()); + if (!res) { + ALOGE("Failed to get DrmDevice resources"); + return std::make_tuple(-ENODEV, 0); + } + + min_resolution_ = std::pair(res->min_width, + res->min_height); + max_resolution_ = std::pair(res->max_width, + res->max_height); + + // 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]); + if (!c) { + ALOGE("Failed to get crtc %d", res->crtcs[i]); + ret = -ENODEV; + break; + } + + std::unique_ptr crtc(new DrmCrtc(this, c, i)); + drmModeFreeCrtc(c); + + ret = crtc->Init(); + if (ret) { + ALOGE("Failed to initialize crtc %d", res->crtcs[i]); + break; + } + crtcs_.emplace_back(std::move(crtc)); + } + + std::vector possible_clones; + for (int i = 0; !ret && i < res->count_encoders; ++i) { + drmModeEncoderPtr e = drmModeGetEncoder(fd(), res->encoders[i]); + if (!e) { + ALOGE("Failed to get encoder %d", res->encoders[i]); + ret = -ENODEV; + break; + } + + std::vector possible_crtcs; + DrmCrtc *current_crtc = NULL; + for (auto &crtc : crtcs_) { + if ((1 << crtc->pipe()) & e->possible_crtcs) + possible_crtcs.push_back(crtc.get()); + + if (crtc->id() == e->crtc_id) + current_crtc = crtc.get(); + } + + std::unique_ptr enc( + new DrmEncoder(e, current_crtc, possible_crtcs)); + possible_clones.push_back(e->possible_clones); + drmModeFreeEncoder(e); + + encoders_.emplace_back(std::move(enc)); + } + + for (unsigned int i = 0; i < encoders_.size(); i++) { + for (unsigned int j = 0; j < encoders_.size(); j++) + if (possible_clones[i] & (1 << j)) + encoders_[i]->AddPossibleClone(encoders_[j].get()); + } + + for (int i = 0; !ret && i < res->count_connectors; ++i) { + drmModeConnectorPtr c = drmModeGetConnector(fd(), res->connectors[i]); + if (!c) { + ALOGE("Failed to get connector %d", res->connectors[i]); + ret = -ENODEV; + break; + } + + std::vector possible_encoders; + DrmEncoder *current_encoder = NULL; + for (int j = 0; j < c->count_encoders; ++j) { + for (auto &encoder : encoders_) { + if (encoder->id() == c->encoders[j]) + possible_encoders.push_back(encoder.get()); + if (encoder->id() == c->encoder_id) + current_encoder = encoder.get(); + } + } + + std::unique_ptr conn( + new DrmConnector(this, c, current_encoder, possible_encoders)); + + drmModeFreeConnector(c); + + ret = conn->Init(); + if (ret) { + ALOGE("Init connector %d failed", res->connectors[i]); + break; + } + + if (conn->writeback()) + writeback_connectors_.emplace_back(std::move(conn)); + else + connectors_.emplace_back(std::move(conn)); + } + + // Primary display priority: + // 1) vendor.hwc.drm.primary_display_order property + // 2) internal connectors + // 3) anything else + std::vector + primary_candidates = make_primary_display_candidates(connectors_); + if (!primary_candidates.empty() && !found_primary) { + DrmConnector &conn = **std::begin(primary_candidates); + conn.set_display(num_displays); + displays_[num_displays] = num_displays; + ++num_displays; + found_primary = true; + } else { + ALOGE( + "Failed to find primary display from " + "\"vendor.hwc.drm.primary_display_order\" property"); + } + + // If no priority display were found then pick first available as primary and + // for the others assign consecutive display_numbers. + for (auto &conn : connectors_) { + 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; + } + } + } + + if (res) + drmModeFreeResources(res); + + // Catch-all for the above loops + if (ret) + return std::make_tuple(ret, 0); + + drmModePlaneResPtr plane_res = drmModeGetPlaneResources(fd()); + if (!plane_res) { + ALOGE("Failed to get plane resources"); + return std::make_tuple(-ENOENT, 0); + } + + for (uint32_t i = 0; i < plane_res->count_planes; ++i) { + drmModePlanePtr p = drmModeGetPlane(fd(), plane_res->planes[i]); + if (!p) { + ALOGE("Failed to get plane %d", plane_res->planes[i]); + ret = -ENODEV; + break; + } + + std::unique_ptr plane(new DrmPlane(this, p)); + + drmModeFreePlane(p); + + ret = plane->Init(); + if (ret) { + ALOGE("Init plane %d failed", plane_res->planes[i]); + break; + } + + planes_.emplace_back(std::move(plane)); + } + drmModeFreePlaneResources(plane_res); + if (ret) + return std::make_tuple(ret, 0); + + ret = event_listener_.Init(); + if (ret) { + ALOGE("Can't initialize event listener %d", 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 std::make_tuple(ret, 0); + } + if (!AttachWriteback(conn.get())) { + ALOGI("Display %d has writeback attach to it", conn->display()); + } + } + 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 { + for (auto &conn : connectors_) { + if (conn->display() == display) + return conn.get(); + } + return NULL; +} + +DrmConnector *DrmDevice::GetWritebackConnectorForDisplay(int display) const { + for (auto &conn : writeback_connectors_) { + if (conn->display() == display) + return conn.get(); + } + return NULL; +} + +// TODO what happens when hotplugging +DrmConnector *DrmDevice::AvailableWritebackConnector(int display) const { + DrmConnector *writeback_conn = GetWritebackConnectorForDisplay(display); + DrmConnector *display_conn = GetConnectorForDisplay(display); + // If we have a writeback already attached to the same CRTC just use that, + // if possible. + if (display_conn && writeback_conn && + writeback_conn->encoder()->CanClone(display_conn->encoder())) + return writeback_conn; + + // Use another CRTC if available and doesn't have any connector + for (auto &crtc : crtcs_) { + if (crtc->display() == display) + continue; + display_conn = GetConnectorForDisplay(crtc->display()); + // If we have a display connected don't use it for writeback + if (display_conn && display_conn->state() == DRM_MODE_CONNECTED) + continue; + writeback_conn = GetWritebackConnectorForDisplay(crtc->display()); + if (writeback_conn) + return writeback_conn; + } + return NULL; +} + +DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const { + for (auto &crtc : crtcs_) { + if (crtc->display() == display) + return crtc.get(); + } + return NULL; +} + +DrmPlane *DrmDevice::GetPlane(uint32_t id) const { + for (auto &plane : planes_) { + if (plane->id() == id) + return plane.get(); + } + return NULL; +} + +const std::vector> &DrmDevice::crtcs() const { + return crtcs_; +} + +uint32_t DrmDevice::next_mode_id() { + return ++mode_id_; +} + +int DrmDevice::TryEncoderForDisplay(int display, DrmEncoder *enc) { + /* First try to use the currently-bound crtc */ + DrmCrtc *crtc = enc->crtc(); + if (crtc && crtc->can_bind(display)) { + crtc->set_display(display); + enc->set_crtc(crtc); + return 0; + } + + /* Try to find a possible crtc which will work */ + for (DrmCrtc *crtc : enc->possible_crtcs()) { + /* We've already tried this earlier */ + if (crtc == enc->crtc()) + continue; + + if (crtc->can_bind(display)) { + crtc->set_display(display); + enc->set_crtc(crtc); + return 0; + } + } + + /* We can't use the encoder, but nothing went wrong, try another one */ + return -EAGAIN; +} + +int DrmDevice::CreateDisplayPipe(DrmConnector *connector) { + int display = connector->display(); + /* Try to use current setup first */ + if (connector->encoder()) { + int ret = TryEncoderForDisplay(display, connector->encoder()); + if (!ret) { + return 0; + } else if (ret != -EAGAIN) { + ALOGE("Could not set mode %d/%d", display, ret); + return ret; + } + } + + for (DrmEncoder *enc : connector->possible_encoders()) { + int ret = TryEncoderForDisplay(display, enc); + if (!ret) { + connector->set_encoder(enc); + return 0; + } else if (ret != -EAGAIN) { + ALOGE("Could not set mode %d/%d", display, ret); + return ret; + } + } + ALOGE("Could not find a suitable encoder/crtc for display %d", + connector->display()); + return -ENODEV; +} + +// Attach writeback connector to the CRTC linked to the display_conn +int DrmDevice::AttachWriteback(DrmConnector *display_conn) { + DrmCrtc *display_crtc = display_conn->encoder()->crtc(); + if (GetWritebackConnectorForDisplay(display_crtc->display()) != NULL) { + ALOGE("Display already has writeback attach to it"); + return -EINVAL; + } + for (auto &writeback_conn : writeback_connectors_) { + if (writeback_conn->display() >= 0) + continue; + for (DrmEncoder *writeback_enc : writeback_conn->possible_encoders()) { + for (DrmCrtc *possible_crtc : writeback_enc->possible_crtcs()) { + if (possible_crtc != display_crtc) + continue; + // Use just encoders which had not been bound already + if (writeback_enc->can_bind(display_crtc->display())) { + writeback_enc->set_crtc(display_crtc); + writeback_conn->set_encoder(writeback_enc); + writeback_conn->set_display(display_crtc->display()); + writeback_conn->UpdateModes(); + return 0; + } + } + } + } + return -EINVAL; +} + +int DrmDevice::CreatePropertyBlob(void *data, size_t length, + uint32_t *blob_id) { + struct drm_mode_create_blob create_blob; + memset(&create_blob, 0, sizeof(create_blob)); + create_blob.length = length; + create_blob.data = (__u64)data; + + int ret = drmIoctl(fd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob); + if (ret) { + ALOGE("Failed to create mode property blob %d", ret); + return ret; + } + *blob_id = create_blob.blob_id; + return 0; +} + +int DrmDevice::DestroyPropertyBlob(uint32_t blob_id) { + if (!blob_id) + return 0; + + struct drm_mode_destroy_blob destroy_blob; + memset(&destroy_blob, 0, sizeof(destroy_blob)); + destroy_blob.blob_id = (__u32)blob_id; + int ret = drmIoctl(fd(), DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy_blob); + if (ret) { + ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", blob_id, ret); + return ret; + } + return 0; +} + +DrmEventListener *DrmDevice::event_listener() { + return &event_listener_; +} + +int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type, + const char *prop_name, DrmProperty *property) { + drmModeObjectPropertiesPtr props; + + props = drmModeObjectGetProperties(fd(), obj_id, obj_type); + if (!props) { + ALOGE("Failed to get properties for %d/%x", obj_id, obj_type); + return -ENODEV; + } + + bool found = false; + for (int i = 0; !found && (size_t)i < props->count_props; ++i) { + drmModePropertyPtr p = drmModeGetProperty(fd(), props->props[i]); + if (!strcmp(p->name, prop_name)) { + property->Init(p, props->prop_values[i]); + found = true; + } + drmModeFreeProperty(p); + } + + drmModeFreeObjectProperties(props); + return found ? 0 : -ENOENT; +} + +int DrmDevice::GetPlaneProperty(const DrmPlane &plane, const char *prop_name, + DrmProperty *property) { + return GetProperty(plane.id(), DRM_MODE_OBJECT_PLANE, prop_name, property); +} + +int DrmDevice::GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name, + DrmProperty *property) { + return GetProperty(crtc.id(), DRM_MODE_OBJECT_CRTC, prop_name, property); +} + +int DrmDevice::GetConnectorProperty(const DrmConnector &connector, + const char *prop_name, + DrmProperty *property) { + return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name, + property); +} + +const std::string DrmDevice::GetName() const { + auto ver = drmGetVersion(fd_.get()); + if (!ver) { + ALOGW("Failed to get drm version for fd=%d", fd_.get()); + return "generic"; + } + + std::string name(ver->name); + drmFreeVersion(ver); + return name; +} +} // namespace android diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h new file mode 100644 index 0000000..d7ea359 --- /dev/null +++ b/drm/DrmDevice.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2015 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 ANDROID_DRM_H_ +#define ANDROID_DRM_H_ + +#include + +#include + +#include "DrmConnector.h" +#include "DrmCrtc.h" +#include "DrmEncoder.h" +#include "DrmEventListener.h" +#include "DrmPlane.h" +#include "platform/platform.h" + +namespace android { + +class DrmDevice { + public: + DrmDevice(); + ~DrmDevice(); + + std::tuple Init(const char *path, int num_displays); + + int fd() const { + return fd_.get(); + } + + const std::vector> &connectors() const { + return connectors_; + } + + const std::vector> &planes() const { + return planes_; + } + + std::pair min_resolution() const { + return min_resolution_; + } + + std::pair max_resolution() const { + return max_resolution_; + } + + DrmConnector *GetConnectorForDisplay(int display) const; + DrmConnector *GetWritebackConnectorForDisplay(int display) const; + DrmConnector *AvailableWritebackConnector(int display) const; + DrmCrtc *GetCrtcForDisplay(int display) const; + DrmPlane *GetPlane(uint32_t id) const; + DrmEventListener *event_listener(); + + int GetPlaneProperty(const DrmPlane &plane, const char *prop_name, + DrmProperty *property); + int GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name, + DrmProperty *property); + int GetConnectorProperty(const DrmConnector &connector, const char *prop_name, + DrmProperty *property); + + const std::string GetName() const; + + const std::vector> &crtcs() const; + uint32_t next_mode_id(); + + int CreatePropertyBlob(void *data, size_t length, uint32_t *blob_id); + int DestroyPropertyBlob(uint32_t blob_id); + bool HandlesDisplay(int display) const; + void RegisterHotplugHandler(DrmEventHandler *handler) { + event_listener_.RegisterHotplugHandler(handler); + } + + private: + int TryEncoderForDisplay(int display, DrmEncoder *enc); + int GetProperty(uint32_t obj_id, uint32_t obj_type, const char *prop_name, + DrmProperty *property); + + int CreateDisplayPipe(DrmConnector *connector); + int AttachWriteback(DrmConnector *display_conn); + + UniqueFd fd_; + uint32_t mode_id_ = 0; + + std::vector> connectors_; + std::vector> writeback_connectors_; + std::vector> encoders_; + std::vector> crtcs_; + std::vector> planes_; + DrmEventListener event_listener_; + + std::pair min_resolution_; + std::pair max_resolution_; + std::map displays_; +}; +} // namespace android + +#endif // ANDROID_DRM_H_ diff --git a/drm/DrmEncoder.cpp b/drm/DrmEncoder.cpp new file mode 100644 index 0000000..bcf0926 --- /dev/null +++ b/drm/DrmEncoder.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 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. + */ + +#include "DrmEncoder.h" + +#include +#include + +#include "DrmDevice.h" + +namespace android { + +DrmEncoder::DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc, + const std::vector &possible_crtcs) + : id_(e->encoder_id), + crtc_(current_crtc), + display_(-1), + possible_crtcs_(possible_crtcs) { +} + +uint32_t DrmEncoder::id() const { + return id_; +} + +DrmCrtc *DrmEncoder::crtc() const { + return crtc_; +} + +bool DrmEncoder::CanClone(DrmEncoder *possible_clone) { + return possible_clones_.find(possible_clone) != possible_clones_.end(); +} + +void DrmEncoder::AddPossibleClone(DrmEncoder *possible_clone) { + possible_clones_.insert(possible_clone); +} + +void DrmEncoder::set_crtc(DrmCrtc *crtc) { + crtc_ = crtc; + display_ = crtc->display(); +} + +int DrmEncoder::display() const { + return display_; +} + +bool DrmEncoder::can_bind(int display) const { + return display_ == -1 || display_ == display; +} +} // namespace android diff --git a/drm/DrmEncoder.h b/drm/DrmEncoder.h new file mode 100644 index 0000000..f4464d0 --- /dev/null +++ b/drm/DrmEncoder.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 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 ANDROID_DRM_ENCODER_H_ +#define ANDROID_DRM_ENCODER_H_ + +#include +#include + +#include +#include + +#include "DrmCrtc.h" + +namespace android { + +class DrmEncoder { + public: + DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc, + const std::vector &possible_crtcs); + DrmEncoder(const DrmEncoder &) = delete; + DrmEncoder &operator=(const DrmEncoder &) = delete; + + uint32_t id() const; + + DrmCrtc *crtc() const; + void set_crtc(DrmCrtc *crtc); + bool can_bind(int display) const; + int display() const; + + const std::vector &possible_crtcs() const { + return possible_crtcs_; + } + bool CanClone(DrmEncoder *encoder); + void AddPossibleClone(DrmEncoder *possible_clone); + + private: + uint32_t id_; + DrmCrtc *crtc_; + int display_; + + std::vector possible_crtcs_; + std::set possible_clones_; +}; +} // namespace android + +#endif // ANDROID_DRM_ENCODER_H_ diff --git a/drm/DrmEventListener.cpp b/drm/DrmEventListener.cpp new file mode 100644 index 0000000..3d95e28 --- /dev/null +++ b/drm/DrmEventListener.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2016 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-drm-event-listener" + +#include "DrmEventListener.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DrmDevice.h" + +namespace android { + +DrmEventListener::DrmEventListener(DrmDevice *drm) + : Worker("drm-event-listener", HAL_PRIORITY_URGENT_DISPLAY), drm_(drm) { +} + +int DrmEventListener::Init() { + uevent_fd_.Set(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)); + if (uevent_fd_.get() < 0) { + ALOGE("Failed to open uevent socket: %s", strerror(errno)); + return uevent_fd_.get(); + } + + struct sockaddr_nl addr; + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + addr.nl_pid = 0; + addr.nl_groups = 0xFFFFFFFF; + + int ret = bind(uevent_fd_.get(), (struct sockaddr *)&addr, sizeof(addr)); + if (ret) { + ALOGE("Failed to bind uevent socket: %s", strerror(errno)); + return -errno; + } + + FD_ZERO(&fds_); + FD_SET(drm_->fd(), &fds_); + FD_SET(uevent_fd_.get(), &fds_); + max_fd_ = std::max(drm_->fd(), uevent_fd_.get()); + + return InitWorker(); +} + +void DrmEventListener::RegisterHotplugHandler(DrmEventHandler *handler) { + assert(!hotplug_handler_); + hotplug_handler_.reset(handler); +} + +void DrmEventListener::FlipHandler(int /* fd */, unsigned int /* sequence */, + unsigned int tv_sec, unsigned int tv_usec, + void *user_data) { + DrmEventHandler *handler = (DrmEventHandler *)user_data; + if (!handler) + return; + + handler->HandleEvent((uint64_t)tv_sec * 1000 * 1000 + tv_usec); + delete handler; +} + +void DrmEventListener::UEventHandler() { + char buffer[1024]; + int ret; + + struct timespec ts; + uint64_t timestamp = 0; + ret = clock_gettime(CLOCK_MONOTONIC, &ts); + if (!ret) + timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; + else + ALOGE("Failed to get monotonic clock on hotplug %d", ret); + + while (true) { + ret = read(uevent_fd_.get(), &buffer, sizeof(buffer)); + if (ret == 0) { + return; + } else if (ret < 0) { + ALOGE("Got error reading uevent %d", ret); + return; + } + + if (!hotplug_handler_) + continue; + + bool drm_event = false, hotplug_event = false; + for (int i = 0; i < ret;) { + char *event = buffer + i; + if (strcmp(event, "DEVTYPE=drm_minor")) + drm_event = true; + else if (strcmp(event, "HOTPLUG=1")) + hotplug_event = true; + + i += strlen(event) + 1; + } + + if (drm_event && hotplug_event) + hotplug_handler_->HandleEvent(timestamp); + } +} + +void DrmEventListener::Routine() { + int ret; + do { + ret = select(max_fd_ + 1, &fds_, NULL, NULL, NULL); + } while (ret == -1 && errno == EINTR); + + if (FD_ISSET(drm_->fd(), &fds_)) { + drmEventContext event_context = + {.version = 2, + .vblank_handler = NULL, + .page_flip_handler = DrmEventListener::FlipHandler}; + drmHandleEvent(drm_->fd(), &event_context); + } + + if (FD_ISSET(uevent_fd_.get(), &fds_)) + UEventHandler(); +} +} // namespace android diff --git a/drm/DrmEventListener.h b/drm/DrmEventListener.h new file mode 100644 index 0000000..9f9a4ba --- /dev/null +++ b/drm/DrmEventListener.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2016 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 ANDROID_DRM_EVENT_LISTENER_H_ +#define ANDROID_DRM_EVENT_LISTENER_H_ + +#include "autofd.h" +#include "utils/Worker.h" + +namespace android { + +class DrmDevice; + +class DrmEventHandler { + public: + DrmEventHandler() { + } + virtual ~DrmEventHandler() { + } + + virtual void HandleEvent(uint64_t timestamp_us) = 0; +}; + +class DrmEventListener : public Worker { + public: + DrmEventListener(DrmDevice *drm); + virtual ~DrmEventListener() { + } + + int Init(); + + void RegisterHotplugHandler(DrmEventHandler *handler); + + static void FlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, + unsigned int tv_usec, void *user_data); + + protected: + virtual void Routine(); + + private: + void UEventHandler(); + + fd_set fds_; + UniqueFd uevent_fd_; + int max_fd_ = -1; + + DrmDevice *drm_; + std::unique_ptr hotplug_handler_; +}; +} // namespace android + +#endif diff --git a/drm/DrmMode.cpp b/drm/DrmMode.cpp new file mode 100644 index 0000000..6de671a --- /dev/null +++ b/drm/DrmMode.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2015 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. + */ + +#include "DrmMode.h" + +#include "DrmDevice.h" + +namespace android { + +DrmMode::DrmMode(drmModeModeInfoPtr m) + : id_(0), + clock_(m->clock), + h_display_(m->hdisplay), + h_sync_start_(m->hsync_start), + h_sync_end_(m->hsync_end), + h_total_(m->htotal), + h_skew_(m->hskew), + v_display_(m->vdisplay), + v_sync_start_(m->vsync_start), + v_sync_end_(m->vsync_end), + v_total_(m->vtotal), + v_scan_(m->vscan), + v_refresh_(m->vrefresh), + flags_(m->flags), + type_(m->type), + name_(m->name) { +} + +bool DrmMode::operator==(const drmModeModeInfo &m) const { + return clock_ == m.clock && h_display_ == m.hdisplay && + h_sync_start_ == m.hsync_start && h_sync_end_ == m.hsync_end && + h_total_ == m.htotal && h_skew_ == m.hskew && + v_display_ == m.vdisplay && v_sync_start_ == m.vsync_start && + v_sync_end_ == m.vsync_end && v_total_ == m.vtotal && + v_scan_ == m.vscan && flags_ == m.flags && type_ == m.type; +} + +void DrmMode::ToDrmModeModeInfo(drm_mode_modeinfo *m) const { + m->clock = clock_; + m->hdisplay = h_display_; + m->hsync_start = h_sync_start_; + m->hsync_end = h_sync_end_; + m->htotal = h_total_; + m->hskew = h_skew_; + m->vdisplay = v_display_; + m->vsync_start = v_sync_start_; + m->vsync_end = v_sync_end_; + m->vtotal = v_total_; + m->vscan = v_scan_; + m->vrefresh = v_refresh_; + m->flags = flags_; + m->type = type_; + strncpy(m->name, name_.c_str(), DRM_DISPLAY_MODE_LEN); +} + +uint32_t DrmMode::id() const { + return id_; +} + +void DrmMode::set_id(uint32_t id) { + id_ = id; +} + +uint32_t DrmMode::clock() const { + return clock_; +} + +uint32_t DrmMode::h_display() const { + return h_display_; +} + +uint32_t DrmMode::h_sync_start() const { + return h_sync_start_; +} + +uint32_t DrmMode::h_sync_end() const { + return h_sync_end_; +} + +uint32_t DrmMode::h_total() const { + return h_total_; +} + +uint32_t DrmMode::h_skew() const { + return h_skew_; +} + +uint32_t DrmMode::v_display() const { + return v_display_; +} + +uint32_t DrmMode::v_sync_start() const { + return v_sync_start_; +} + +uint32_t DrmMode::v_sync_end() const { + return v_sync_end_; +} + +uint32_t DrmMode::v_total() const { + return v_total_; +} + +uint32_t DrmMode::v_scan() const { + return v_scan_; +} + +float DrmMode::v_refresh() const { + // Always recalculate refresh to report correct float rate + return clock_ / (float)(v_total_ * h_total_) * 1000.0f; +} + +uint32_t DrmMode::flags() const { + return flags_; +} + +uint32_t DrmMode::type() const { + return type_; +} + +std::string DrmMode::name() const { + return name_; +} +} // namespace android diff --git a/drm/DrmMode.h b/drm/DrmMode.h new file mode 100644 index 0000000..313a8ea --- /dev/null +++ b/drm/DrmMode.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2015 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 ANDROID_DRM_MODE_H_ +#define ANDROID_DRM_MODE_H_ + +#include +#include + +#include + +namespace android { + +class DrmMode { + public: + DrmMode() = default; + DrmMode(drmModeModeInfoPtr m); + + bool operator==(const drmModeModeInfo &m) const; + void ToDrmModeModeInfo(drm_mode_modeinfo *m) const; + + uint32_t id() const; + void set_id(uint32_t id); + + uint32_t clock() const; + + uint32_t h_display() const; + uint32_t h_sync_start() const; + uint32_t h_sync_end() const; + uint32_t h_total() const; + uint32_t h_skew() const; + + uint32_t v_display() const; + uint32_t v_sync_start() const; + uint32_t v_sync_end() const; + uint32_t v_total() const; + uint32_t v_scan() const; + float v_refresh() const; + + uint32_t flags() const; + uint32_t type() const; + + std::string name() const; + + private: + uint32_t id_ = 0; + + uint32_t clock_ = 0; + + uint32_t h_display_ = 0; + uint32_t h_sync_start_ = 0; + uint32_t h_sync_end_ = 0; + uint32_t h_total_ = 0; + uint32_t h_skew_ = 0; + + uint32_t v_display_ = 0; + uint32_t v_sync_start_ = 0; + uint32_t v_sync_end_ = 0; + uint32_t v_total_ = 0; + uint32_t v_scan_ = 0; + uint32_t v_refresh_ = 0; + + uint32_t flags_ = 0; + uint32_t type_ = 0; + + std::string name_; +}; +} // namespace android + +#endif // ANDROID_DRM_MODE_H_ diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp new file mode 100644 index 0000000..1fb1316 --- /dev/null +++ b/drm/DrmPlane.cpp @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2015 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-drm-plane" + +#include "DrmPlane.h" + +#include +#include +#include + +#include + +#include "DrmDevice.h" + +namespace android { + +DrmPlane::DrmPlane(DrmDevice *drm, drmModePlanePtr p) + : drm_(drm), id_(p->plane_id), possible_crtc_mask_(p->possible_crtcs) { +} + +int DrmPlane::Init() { + DrmProperty p; + + int ret = drm_->GetPlaneProperty(*this, "type", &p); + if (ret) { + ALOGE("Could not get plane type property"); + return ret; + } + + uint64_t type; + std::tie(ret, type) = p.value(); + if (ret) { + ALOGE("Failed to get plane type property value"); + return ret; + } + switch (type) { + case DRM_PLANE_TYPE_OVERLAY: + case DRM_PLANE_TYPE_PRIMARY: + case DRM_PLANE_TYPE_CURSOR: + type_ = (uint32_t)type; + break; + default: + ALOGE("Invalid plane type %" PRIu64, type); + return -EINVAL; + } + + ret = drm_->GetPlaneProperty(*this, "CRTC_ID", &crtc_property_); + if (ret) { + ALOGE("Could not get CRTC_ID property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "FB_ID", &fb_property_); + if (ret) { + ALOGE("Could not get FB_ID property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "CRTC_X", &crtc_x_property_); + if (ret) { + ALOGE("Could not get CRTC_X property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "CRTC_Y", &crtc_y_property_); + if (ret) { + ALOGE("Could not get CRTC_Y property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "CRTC_W", &crtc_w_property_); + if (ret) { + ALOGE("Could not get CRTC_W property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "CRTC_H", &crtc_h_property_); + if (ret) { + ALOGE("Could not get CRTC_H property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "SRC_X", &src_x_property_); + if (ret) { + ALOGE("Could not get SRC_X property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "SRC_Y", &src_y_property_); + if (ret) { + ALOGE("Could not get SRC_Y property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "SRC_W", &src_w_property_); + if (ret) { + ALOGE("Could not get SRC_W property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "SRC_H", &src_h_property_); + if (ret) { + ALOGE("Could not get SRC_H property"); + return ret; + } + + ret = drm_->GetPlaneProperty(*this, "zpos", &zpos_property_); + if (ret) + ALOGE("Could not get zpos property for plane %u", id()); + + ret = drm_->GetPlaneProperty(*this, "rotation", &rotation_property_); + if (ret) + ALOGE("Could not get rotation property"); + + ret = drm_->GetPlaneProperty(*this, "alpha", &alpha_property_); + if (ret) + ALOGI("Could not get alpha property"); + + ret = drm_->GetPlaneProperty(*this, "pixel blend mode", &blend_property_); + if (ret) + ALOGI("Could not get pixel blend mode property"); + + ret = drm_->GetPlaneProperty(*this, "IN_FENCE_FD", &in_fence_fd_property_); + if (ret) + ALOGI("Could not get IN_FENCE_FD property"); + + return 0; +} + +uint32_t DrmPlane::id() const { + return id_; +} + +bool DrmPlane::GetCrtcSupported(const DrmCrtc &crtc) const { + return !!((1 << crtc.pipe()) & possible_crtc_mask_); +} + +uint32_t DrmPlane::type() const { + return type_; +} + +const DrmProperty &DrmPlane::crtc_property() const { + return crtc_property_; +} + +const DrmProperty &DrmPlane::fb_property() const { + return fb_property_; +} + +const DrmProperty &DrmPlane::crtc_x_property() const { + return crtc_x_property_; +} + +const DrmProperty &DrmPlane::crtc_y_property() const { + return crtc_y_property_; +} + +const DrmProperty &DrmPlane::crtc_w_property() const { + return crtc_w_property_; +} + +const DrmProperty &DrmPlane::crtc_h_property() const { + return crtc_h_property_; +} + +const DrmProperty &DrmPlane::src_x_property() const { + return src_x_property_; +} + +const DrmProperty &DrmPlane::src_y_property() const { + return src_y_property_; +} + +const DrmProperty &DrmPlane::src_w_property() const { + return src_w_property_; +} + +const DrmProperty &DrmPlane::src_h_property() const { + return src_h_property_; +} + +const DrmProperty &DrmPlane::zpos_property() const { + return zpos_property_; +} + +const DrmProperty &DrmPlane::rotation_property() const { + return rotation_property_; +} + +const DrmProperty &DrmPlane::alpha_property() const { + return alpha_property_; +} + +const DrmProperty &DrmPlane::blend_property() const { + return blend_property_; +} + +const DrmProperty &DrmPlane::in_fence_fd_property() const { + return in_fence_fd_property_; +} +} // namespace android diff --git a/drm/DrmPlane.h b/drm/DrmPlane.h new file mode 100644 index 0000000..d2f0601 --- /dev/null +++ b/drm/DrmPlane.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015 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 ANDROID_DRM_PLANE_H_ +#define ANDROID_DRM_PLANE_H_ + +#include +#include + +#include + +#include "DrmCrtc.h" +#include "DrmProperty.h" + +namespace android { + +class DrmDevice; + +class DrmPlane { + public: + DrmPlane(DrmDevice *drm, drmModePlanePtr p); + DrmPlane(const DrmPlane &) = delete; + DrmPlane &operator=(const DrmPlane &) = delete; + + int Init(); + + uint32_t id() const; + + bool GetCrtcSupported(const DrmCrtc &crtc) const; + + uint32_t type() const; + + const DrmProperty &crtc_property() const; + const DrmProperty &fb_property() const; + const DrmProperty &crtc_x_property() const; + const DrmProperty &crtc_y_property() const; + const DrmProperty &crtc_w_property() const; + const DrmProperty &crtc_h_property() const; + const DrmProperty &src_x_property() const; + const DrmProperty &src_y_property() const; + const DrmProperty &src_w_property() const; + const DrmProperty &src_h_property() const; + const DrmProperty &zpos_property() const; + const DrmProperty &rotation_property() const; + const DrmProperty &alpha_property() const; + const DrmProperty &blend_property() const; + const DrmProperty &in_fence_fd_property() const; + + private: + DrmDevice *drm_; + uint32_t id_; + + uint32_t possible_crtc_mask_; + + uint32_t type_; + + DrmProperty crtc_property_; + DrmProperty fb_property_; + DrmProperty crtc_x_property_; + DrmProperty crtc_y_property_; + DrmProperty crtc_w_property_; + DrmProperty crtc_h_property_; + DrmProperty src_x_property_; + DrmProperty src_y_property_; + DrmProperty src_w_property_; + DrmProperty src_h_property_; + DrmProperty zpos_property_; + DrmProperty rotation_property_; + DrmProperty alpha_property_; + DrmProperty blend_property_; + DrmProperty in_fence_fd_property_; +}; +} // namespace android + +#endif // ANDROID_DRM_PLANE_H_ diff --git a/drm/DrmProperty.cpp b/drm/DrmProperty.cpp new file mode 100644 index 0000000..b60a76e --- /dev/null +++ b/drm/DrmProperty.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2015 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. + */ + +#include "DrmProperty.h" + +#include +#include +#include + +#include + +#include "DrmDevice.h" + +namespace android { + +DrmProperty::DrmPropertyEnum::DrmPropertyEnum(drm_mode_property_enum *e) + : value_(e->value), name_(e->name) { +} + +DrmProperty::DrmPropertyEnum::~DrmPropertyEnum() { +} + +DrmProperty::DrmProperty(drmModePropertyPtr p, uint64_t value) + : id_(0), type_(DRM_PROPERTY_TYPE_INVALID), flags_(0), name_("") { + Init(p, value); +} + +void DrmProperty::Init(drmModePropertyPtr p, uint64_t value) { + id_ = p->prop_id; + flags_ = p->flags; + name_ = p->name; + value_ = value; + + for (int i = 0; i < p->count_values; ++i) + values_.push_back(p->values[i]); + + for (int i = 0; i < p->count_enums; ++i) + enums_.push_back(DrmPropertyEnum(&p->enums[i])); + + for (int i = 0; i < p->count_blobs; ++i) + blob_ids_.push_back(p->blob_ids[i]); + + if (flags_ & DRM_MODE_PROP_RANGE) + type_ = DRM_PROPERTY_TYPE_INT; + else if (flags_ & DRM_MODE_PROP_ENUM) + type_ = DRM_PROPERTY_TYPE_ENUM; + else if (flags_ & DRM_MODE_PROP_OBJECT) + type_ = DRM_PROPERTY_TYPE_OBJECT; + else if (flags_ & DRM_MODE_PROP_BLOB) + type_ = DRM_PROPERTY_TYPE_BLOB; +} + +uint32_t DrmProperty::id() const { + return id_; +} + +std::string DrmProperty::name() const { + return name_; +} + +std::tuple DrmProperty::value() const { + if (type_ == DRM_PROPERTY_TYPE_BLOB) + return std::make_tuple(0, value_); + + if (values_.size() == 0) + return std::make_tuple(-ENOENT, 0); + + switch (type_) { + case DRM_PROPERTY_TYPE_INT: + return std::make_tuple(0, value_); + + case DRM_PROPERTY_TYPE_ENUM: + if (value_ >= enums_.size()) + return std::make_tuple(-ENOENT, 0); + + return std::make_tuple(0, enums_[value_].value_); + + case DRM_PROPERTY_TYPE_OBJECT: + return std::make_tuple(0, value_); + + default: + return std::make_tuple(-EINVAL, 0); + } +} + +bool DrmProperty::is_immutable() const { + return id_ && (flags_ & DRM_MODE_PROP_IMMUTABLE); +} + +bool DrmProperty::is_range() const { + return id_ && (flags_ & DRM_MODE_PROP_RANGE); +} + +std::tuple DrmProperty::range_min() const { + if (!is_range()) + return std::make_tuple(-EINVAL, 0); + if (values_.size() < 1) + return std::make_tuple(-ENOENT, 0); + + return std::make_tuple(0, values_[0]); +} + +std::tuple DrmProperty::range_max() const { + if (!is_range()) + return std::make_tuple(-EINVAL, 0); + if (values_.size() < 2) + return std::make_tuple(-ENOENT, 0); + + return std::make_tuple(0, values_[1]); +} + +std::tuple DrmProperty::GetEnumValueWithName( + std::string name) const { + for (auto it : enums_) { + if (it.name_.compare(name) == 0) { + return std::make_tuple(it.value_, 0); + } + } + + return std::make_tuple(UINT64_MAX, -EINVAL); +} +} // namespace android diff --git a/drm/DrmProperty.h b/drm/DrmProperty.h new file mode 100644 index 0000000..d293da3 --- /dev/null +++ b/drm/DrmProperty.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 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 ANDROID_DRM_PROPERTY_H_ +#define ANDROID_DRM_PROPERTY_H_ + +#include +#include + +#include +#include + +namespace android { + +enum DrmPropertyType { + DRM_PROPERTY_TYPE_INT, + DRM_PROPERTY_TYPE_ENUM, + DRM_PROPERTY_TYPE_OBJECT, + DRM_PROPERTY_TYPE_BLOB, + DRM_PROPERTY_TYPE_INVALID, +}; + +class DrmProperty { + public: + DrmProperty() = default; + DrmProperty(drmModePropertyPtr p, uint64_t value); + DrmProperty(const DrmProperty &) = delete; + DrmProperty &operator=(const DrmProperty &) = delete; + + void Init(drmModePropertyPtr p, uint64_t value); + std::tuple GetEnumValueWithName(std::string name) const; + + uint32_t id() const; + std::string name() const; + + std::tuple value() const; + bool is_immutable() const; + + bool is_range() const; + std::tuple range_min() const; + std::tuple range_max() const; + + private: + class DrmPropertyEnum { + public: + DrmPropertyEnum(drm_mode_property_enum *e); + ~DrmPropertyEnum(); + + uint64_t value_; + std::string name_; + }; + + uint32_t id_ = 0; + + DrmPropertyType type_ = DRM_PROPERTY_TYPE_INVALID; + uint32_t flags_ = 0; + std::string name_; + uint64_t value_ = 0; + + std::vector values_; + std::vector enums_; + std::vector blob_ids_; +}; +} // namespace android + +#endif // ANDROID_DRM_PROPERTY_H_ diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp new file mode 100644 index 0000000..67ef7f8 --- /dev/null +++ b/drm/ResourceManager.cpp @@ -0,0 +1,144 @@ +/* + * 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 +#include +#include + +#include + +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("vendor.hwc.drm.device", path_pattern, + "/dev/dri/card%"); + 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; + + struct stat buf; + if (stat(path.str().c_str(), &buf)) { + break; + } else if (IsKMSDev(path.str().c_str())) { + ret = AddDrmDevice(path.str()); + } + } + } + + if (!num_displays_) { + ALOGE("Failed to initialize any displays"); + return ret ? -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)); + + return hw_get_module(GRALLOC_HARDWARE_MODULE_ID, + (const hw_module_t **)&gralloc_); +} + +int ResourceManager::AddDrmDevice(std::string path) { + std::unique_ptr drm = std::make_unique(); + 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.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; +} + +DrmConnector *ResourceManager::AvailableWritebackConnector(int display) { + DrmDevice *drm_device = GetDrmDevice(display); + DrmConnector *writeback_conn = NULL; + if (drm_device) { + writeback_conn = drm_device->AvailableWritebackConnector(display); + if (writeback_conn) + return writeback_conn; + } + for (auto &drm : drms_) { + if (drm.get() == drm_device) + continue; + writeback_conn = drm->AvailableWritebackConnector(display); + if (writeback_conn) + return writeback_conn; + } + return writeback_conn; +} + +bool ResourceManager::IsKMSDev(const char *path) { + int fd = open(path, O_RDWR | O_CLOEXEC); + if (fd < 0) + return false; + + auto res = drmModeGetResources(fd); + if (!res) { + close(fd); + return false; + } + + bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 && + res->count_encoders > 0; + + drmModeFreeResources(res); + close(fd); + + return is_kms; +} + +DrmDevice *ResourceManager::GetDrmDevice(int display) { + for (auto &drm : drms_) { + if (drm->HandlesDisplay(display)) + return drm.get(); + } + return NULL; +} + +std::shared_ptr 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_; +} +} // namespace android diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h new file mode 100644 index 0000000..94ba43e --- /dev/null +++ b/drm/ResourceManager.h @@ -0,0 +1,60 @@ +/* + * 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 + +#include "DrmDevice.h" +#include "platform/platform.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 GetImporter(int display); + const gralloc_module_t *gralloc(); + DrmConnector *AvailableWritebackConnector(int display); + const std::vector> &getDrmDevices() const { + return drms_; + } + int getDisplayCount() const { + return num_displays_; + } + bool ForcedScalingWithGpu() { + return scale_with_gpu_; + } + + private: + int AddDrmDevice(std::string path); + static bool IsKMSDev(const char *path); + + int num_displays_; + std::vector> drms_; + std::vector> importers_; + const gralloc_module_t *gralloc_; + + bool scale_with_gpu_; +}; +} // namespace android + +#endif // RESOURCEMANAGER_H diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp new file mode 100644 index 0000000..dfbf8ce --- /dev/null +++ b/drm/VSyncWorker.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2015 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-vsync-worker" + +#include "VSyncWorker.h" + +#include +#include +#include +#include +#include + +namespace android { + +VSyncWorker::VSyncWorker() + : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY), + drm_(NULL), + display_(-1), + enabled_(false), + last_timestamp_(-1) { +} + +VSyncWorker::~VSyncWorker() { +} + +int VSyncWorker::Init(DrmDevice *drm, int display) { + drm_ = drm; + display_ = display; + + return InitWorker(); +} + +void VSyncWorker::RegisterCallback(std::shared_ptr callback) { + Lock(); + callback_ = callback; + Unlock(); +} + +void VSyncWorker::VSyncControl(bool enabled) { + Lock(); + enabled_ = enabled; + last_timestamp_ = -1; + Unlock(); + + Signal(); +} + +/* + * Returns the timestamp of the next vsync in phase with last_timestamp_. + * For example: + * last_timestamp_ = 137 + * frame_ns = 50 + * current = 683 + * + * ret = (50 * ((683 - 137)/50 + 1)) + 137 + * ret = 687 + * + * Thus, we must sleep until timestamp 687 to maintain phase with the last + * timestamp. + */ +int64_t VSyncWorker::GetPhasedVSync(int64_t frame_ns, int64_t current) { + if (last_timestamp_ < 0) + return current + frame_ns; + + return frame_ns * ((current - last_timestamp_) / frame_ns + 1) + + last_timestamp_; +} + +static const int64_t kOneSecondNs = 1 * 1000 * 1000 * 1000; + +int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) { + struct timespec vsync; + int ret = clock_gettime(CLOCK_MONOTONIC, &vsync); + + float refresh = 60.0f; // Default to 60Hz refresh rate + DrmConnector *conn = drm_->GetConnectorForDisplay(display_); + if (conn && conn->active_mode().v_refresh() != 0.0f) + refresh = conn->active_mode().v_refresh(); + else + ALOGW("Vsync worker active with conn=%p refresh=%f\n", conn, + conn ? conn->active_mode().v_refresh() : 0.0f); + + int64_t phased_timestamp = GetPhasedVSync(kOneSecondNs / refresh, + vsync.tv_sec * kOneSecondNs + + vsync.tv_nsec); + vsync.tv_sec = phased_timestamp / kOneSecondNs; + vsync.tv_nsec = phased_timestamp - (vsync.tv_sec * kOneSecondNs); + do { + ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &vsync, NULL); + } while (ret == -1 && errno == EINTR); + if (ret) + return ret; + + *timestamp = (int64_t)vsync.tv_sec * kOneSecondNs + (int64_t)vsync.tv_nsec; + return 0; +} + +void VSyncWorker::Routine() { + int ret; + + Lock(); + if (!enabled_) { + ret = WaitForSignalOrExitLocked(); + if (ret == -EINTR) { + Unlock(); + return; + } + } + + int display = display_; + std::shared_ptr callback(callback_); + Unlock(); + + DrmCrtc *crtc = drm_->GetCrtcForDisplay(display); + if (!crtc) { + ALOGE("Failed to get crtc for display"); + return; + } + uint32_t high_crtc = (crtc->pipe() << DRM_VBLANK_HIGH_CRTC_SHIFT); + + drmVBlank vblank; + memset(&vblank, 0, sizeof(vblank)); + vblank.request.type = (drmVBlankSeqType)( + DRM_VBLANK_RELATIVE | (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK)); + vblank.request.sequence = 1; + + int64_t timestamp; + ret = drmWaitVBlank(drm_->fd(), &vblank); + if (ret == -EINTR) { + return; + } else if (ret) { + ret = SyntheticWaitVBlank(×tamp); + if (ret) + return; + } else { + timestamp = (int64_t)vblank.reply.tval_sec * kOneSecondNs + + (int64_t)vblank.reply.tval_usec * 1000; + } + + /* + * VSync could be disabled during routine execution so it could potentially + * lead to crash since callback's inner hook could be invalid anymore. We have + * no control over lifetime of this hook, therefore we can't rely that it'll + * be valid after vsync disabling. + * + * Blocking VSyncControl to wait until routine + * will finish execution is logically correct way to fix this issue, but it + * creates visible lags and stutters, so we have to resort to other ways of + * mitigating this issue. + * + * Doing check before attempt to invoke callback drastically shortens the + * window when such situation could happen and that allows us to practically + * avoid this issue. + * + * Please note that issue described below is different one and it is related + * to RegisterCallback, not to disabling vsync via VSyncControl. + */ + if (!enabled_) + return; + /* + * There's a race here where a change in callback_ will not take effect until + * the next subsequent requested vsync. This is unavoidable since we can't + * call the vsync hook while holding the thread lock. + * + * We could shorten the race window by caching callback_ right before calling + * the hook. However, in practice, callback_ is only updated once, so it's not + * worth the overhead. + */ + if (callback) + callback->Callback(display, timestamp); + last_timestamp_ = timestamp; +} +} // namespace android diff --git a/drm/VSyncWorker.h b/drm/VSyncWorker.h new file mode 100644 index 0000000..0121a6c --- /dev/null +++ b/drm/VSyncWorker.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 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 ANDROID_EVENT_WORKER_H_ +#define ANDROID_EVENT_WORKER_H_ + +#include +#include +#include + +#include + +#include "DrmDevice.h" +#include "utils/Worker.h" + +namespace android { + +class VsyncCallback { + public: + virtual ~VsyncCallback() { + } + virtual void Callback(int display, int64_t timestamp) = 0; +}; + +class VSyncWorker : public Worker { + public: + VSyncWorker(); + ~VSyncWorker() override; + + int Init(DrmDevice *drm, int display); + void RegisterCallback(std::shared_ptr callback); + + void VSyncControl(bool enabled); + + protected: + void Routine() override; + + private: + int64_t GetPhasedVSync(int64_t frame_ns, int64_t current); + int SyntheticWaitVBlank(int64_t *timestamp); + + DrmDevice *drm_; + + // shared_ptr since we need to use this outside of the thread lock (to + // actually call the hook) and we don't want the memory freed until we're + // done + std::shared_ptr callback_ = NULL; + + int display_; + std::atomic_bool enabled_; + int64_t last_timestamp_; +}; +} // namespace android + +#endif diff --git a/drm/drmconnector.cpp b/drm/drmconnector.cpp deleted file mode 100644 index 81c2b98..0000000 --- a/drm/drmconnector.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2015 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-drm-connector" - -#include "drmconnector.h" -#include "drmdevice.h" - -#include -#include - -#include -#include - -#include -#include - -namespace android { - -constexpr size_t TYPES_COUNT = 17; - -DrmConnector::DrmConnector(DrmDevice *drm, drmModeConnectorPtr c, - DrmEncoder *current_encoder, - std::vector &possible_encoders) - : drm_(drm), - id_(c->connector_id), - encoder_(current_encoder), - display_(-1), - type_(c->connector_type), - type_id_(c->connector_type_id), - state_(c->connection), - mm_width_(c->mmWidth), - mm_height_(c->mmHeight), - possible_encoders_(possible_encoders) { -} - -int DrmConnector::Init() { - int ret = drm_->GetConnectorProperty(*this, "DPMS", &dpms_property_); - if (ret) { - ALOGE("Could not get DPMS property\n"); - return ret; - } - ret = drm_->GetConnectorProperty(*this, "CRTC_ID", &crtc_id_property_); - if (ret) { - ALOGE("Could not get CRTC_ID property\n"); - return ret; - } - ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_); - if (ret) { - ALOGW("Could not get EDID property\n"); - } - if (writeback()) { - ret = drm_->GetConnectorProperty(*this, "WRITEBACK_PIXEL_FORMATS", - &writeback_pixel_formats_); - if (ret) { - ALOGE("Could not get WRITEBACK_PIXEL_FORMATS connector_id = %d\n", id_); - return ret; - } - ret = drm_->GetConnectorProperty(*this, "WRITEBACK_FB_ID", - &writeback_fb_id_); - if (ret) { - ALOGE("Could not get WRITEBACK_FB_ID connector_id = %d\n", id_); - return ret; - } - ret = drm_->GetConnectorProperty(*this, "WRITEBACK_OUT_FENCE_PTR", - &writeback_out_fence_); - if (ret) { - ALOGE("Could not get WRITEBACK_OUT_FENCE_PTR connector_id = %d\n", id_); - return ret; - } - } - return 0; -} - -uint32_t DrmConnector::id() const { - return id_; -} - -int DrmConnector::display() const { - return display_; -} - -void DrmConnector::set_display(int display) { - display_ = display; -} - -bool DrmConnector::internal() const { - return type_ == DRM_MODE_CONNECTOR_LVDS || type_ == DRM_MODE_CONNECTOR_eDP || - type_ == DRM_MODE_CONNECTOR_DSI || - type_ == DRM_MODE_CONNECTOR_VIRTUAL || type_ == DRM_MODE_CONNECTOR_DPI; -} - -bool DrmConnector::external() const { - return type_ == DRM_MODE_CONNECTOR_HDMIA || - type_ == DRM_MODE_CONNECTOR_DisplayPort || - type_ == DRM_MODE_CONNECTOR_DVID || type_ == DRM_MODE_CONNECTOR_DVII || - type_ == DRM_MODE_CONNECTOR_VGA; -} - -bool DrmConnector::writeback() const { -#ifdef DRM_MODE_CONNECTOR_WRITEBACK - return type_ == DRM_MODE_CONNECTOR_WRITEBACK; -#else - return false; -#endif -} - -bool DrmConnector::valid_type() const { - return internal() || external() || writeback(); -} - -std::string DrmConnector::name() const { - constexpr std::array names = - {"None", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite", - "SVIDEO", "LVDS", "Component", "DIN", "DP", "HDMI-A", - "HDMI-B", "TV", "eDP", "Virtual", "DSI"}; - - if (type_ < TYPES_COUNT) { - std::ostringstream name_buf; - name_buf << names[type_] << "-" << type_id_; - return name_buf.str(); - } else { - ALOGE("Unknown type in connector %d, could not make his name", id_); - return "None"; - } -} - -int DrmConnector::UpdateModes() { - int fd = drm_->fd(); - - drmModeConnectorPtr c = drmModeGetConnector(fd, id_); - if (!c) { - ALOGE("Failed to get connector %d", id_); - return -ENODEV; - } - - state_ = c->connection; - - bool preferred_mode_found = false; - std::vector new_modes; - for (int i = 0; i < c->count_modes; ++i) { - bool exists = false; - for (const DrmMode &mode : modes_) { - if (mode == c->modes[i]) { - new_modes.push_back(mode); - exists = true; - break; - } - } - if (!exists) { - DrmMode m(&c->modes[i]); - m.set_id(drm_->next_mode_id()); - new_modes.push_back(m); - } - // Use only the first DRM_MODE_TYPE_PREFERRED mode found - if (!preferred_mode_found && - (new_modes.back().type() & DRM_MODE_TYPE_PREFERRED)) { - preferred_mode_id_ = new_modes.back().id(); - preferred_mode_found = true; - } - } - modes_.swap(new_modes); - if (!preferred_mode_found && modes_.size() != 0) { - preferred_mode_id_ = modes_[0].id(); - } - return 0; -} - -const DrmMode &DrmConnector::active_mode() const { - return active_mode_; -} - -void DrmConnector::set_active_mode(const DrmMode &mode) { - active_mode_ = mode; -} - -const DrmProperty &DrmConnector::dpms_property() const { - return dpms_property_; -} - -const DrmProperty &DrmConnector::crtc_id_property() const { - return crtc_id_property_; -} - -const DrmProperty &DrmConnector::edid_property() const { - return edid_property_; -} - -const DrmProperty &DrmConnector::writeback_pixel_formats() const { - return writeback_pixel_formats_; -} - -const DrmProperty &DrmConnector::writeback_fb_id() const { - return writeback_fb_id_; -} - -const DrmProperty &DrmConnector::writeback_out_fence() const { - return writeback_out_fence_; -} - -DrmEncoder *DrmConnector::encoder() const { - return encoder_; -} - -void DrmConnector::set_encoder(DrmEncoder *encoder) { - encoder_ = encoder; -} - -drmModeConnection DrmConnector::state() const { - return state_; -} - -uint32_t DrmConnector::mm_width() const { - return mm_width_; -} - -uint32_t DrmConnector::mm_height() const { - return mm_height_; -} -} // namespace android diff --git a/drm/drmconnector.h b/drm/drmconnector.h deleted file mode 100644 index 0c19c55..0000000 --- a/drm/drmconnector.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2015 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 ANDROID_DRM_CONNECTOR_H_ -#define ANDROID_DRM_CONNECTOR_H_ - -#include -#include - -#include -#include - -#include "drmencoder.h" -#include "drmmode.h" -#include "drmproperty.h" - -namespace android { - -class DrmDevice; - -class DrmConnector { - public: - DrmConnector(DrmDevice *drm, drmModeConnectorPtr c, - DrmEncoder *current_encoder, - std::vector &possible_encoders); - DrmConnector(const DrmProperty &) = delete; - DrmConnector &operator=(const DrmProperty &) = delete; - - int Init(); - - uint32_t id() const; - - int display() const; - void set_display(int display); - - bool internal() const; - bool external() const; - bool writeback() const; - bool valid_type() const; - - std::string name() const; - - int UpdateModes(); - - const std::vector &modes() const { - return modes_; - } - const DrmMode &active_mode() const; - void set_active_mode(const DrmMode &mode); - - const DrmProperty &dpms_property() const; - const DrmProperty &crtc_id_property() const; - const DrmProperty &edid_property() const; - const DrmProperty &writeback_pixel_formats() const; - const DrmProperty &writeback_fb_id() const; - const DrmProperty &writeback_out_fence() const; - - const std::vector &possible_encoders() const { - return possible_encoders_; - } - DrmEncoder *encoder() const; - void set_encoder(DrmEncoder *encoder); - - drmModeConnection state() const; - - uint32_t mm_width() const; - uint32_t mm_height() const; - - uint32_t get_preferred_mode_id() const { - return preferred_mode_id_; - } - - private: - DrmDevice *drm_; - - uint32_t id_; - DrmEncoder *encoder_; - int display_; - - uint32_t type_; - uint32_t type_id_; - drmModeConnection state_; - - uint32_t mm_width_; - uint32_t mm_height_; - - DrmMode active_mode_; - std::vector modes_; - - DrmProperty dpms_property_; - DrmProperty crtc_id_property_; - DrmProperty edid_property_; - DrmProperty writeback_pixel_formats_; - DrmProperty writeback_fb_id_; - DrmProperty writeback_out_fence_; - - std::vector possible_encoders_; - - uint32_t preferred_mode_id_; -}; -} // namespace android - -#endif // ANDROID_DRM_PLANE_H_ diff --git a/drm/drmcrtc.cpp b/drm/drmcrtc.cpp deleted file mode 100644 index b627291..0000000 --- a/drm/drmcrtc.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2015 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-drm-crtc" - -#include "drmcrtc.h" -#include "drmdevice.h" - -#include -#include - -#include - -namespace android { - -DrmCrtc::DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe) - : drm_(drm), id_(c->crtc_id), pipe_(pipe), display_(-1), mode_(&c->mode) { -} - -int DrmCrtc::Init() { - int ret = drm_->GetCrtcProperty(*this, "ACTIVE", &active_property_); - if (ret) { - ALOGE("Failed to get ACTIVE property"); - return ret; - } - - ret = drm_->GetCrtcProperty(*this, "MODE_ID", &mode_property_); - if (ret) { - ALOGE("Failed to get MODE_ID property"); - return ret; - } - - ret = drm_->GetCrtcProperty(*this, "OUT_FENCE_PTR", &out_fence_ptr_property_); - if (ret) { - ALOGE("Failed to get OUT_FENCE_PTR property"); - return ret; - } - return 0; -} - -uint32_t DrmCrtc::id() const { - return id_; -} - -unsigned DrmCrtc::pipe() const { - return pipe_; -} - -int DrmCrtc::display() const { - return display_; -} - -void DrmCrtc::set_display(int display) { - display_ = display; -} - -bool DrmCrtc::can_bind(int display) const { - return display_ == -1 || display_ == display; -} - -const DrmProperty &DrmCrtc::active_property() const { - return active_property_; -} - -const DrmProperty &DrmCrtc::mode_property() const { - return mode_property_; -} - -const DrmProperty &DrmCrtc::out_fence_ptr_property() const { - return out_fence_ptr_property_; -} -} // namespace android diff --git a/drm/drmcrtc.h b/drm/drmcrtc.h deleted file mode 100644 index 132c2d3..0000000 --- a/drm/drmcrtc.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2015 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 ANDROID_DRM_CRTC_H_ -#define ANDROID_DRM_CRTC_H_ - -#include -#include - -#include "drmmode.h" -#include "drmproperty.h" - -namespace android { - -class DrmDevice; - -class DrmCrtc { - public: - DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe); - DrmCrtc(const DrmCrtc &) = delete; - DrmCrtc &operator=(const DrmCrtc &) = delete; - - int Init(); - - uint32_t id() const; - unsigned pipe() const; - - int display() const; - void set_display(int display); - - bool can_bind(int display) const; - - const DrmProperty &active_property() const; - const DrmProperty &mode_property() const; - const DrmProperty &out_fence_ptr_property() const; - - private: - DrmDevice *drm_; - - uint32_t id_; - unsigned pipe_; - int display_; - - DrmMode mode_; - - DrmProperty active_property_; - DrmProperty mode_property_; - DrmProperty out_fence_ptr_property_; -}; -} // namespace android - -#endif // ANDROID_DRM_CRTC_H_ diff --git a/drm/drmdevice.cpp b/drm/drmdevice.cpp deleted file mode 100644 index 18b5b62..0000000 --- a/drm/drmdevice.cpp +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Copyright (C) 2015 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-drm-device" - -#include "drmdevice.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -static void trim_left(std::string &str) { - str.erase(std::begin(str), - std::find_if(std::begin(str), std::end(str), - [](int ch) { return !std::isspace(ch); })); -} - -static void trim_right(std::string &str) { - str.erase(std::find_if(std::rbegin(str), std::rend(str), - [](int ch) { return !std::isspace(ch); }) - .base(), - std::end(str)); -} - -static void trim(std::string &str) { - trim_left(str); - trim_right(str); -} - -namespace android { - -static std::vector read_primary_display_order_prop() { - std::array display_order_buf; - property_get("vendor.hwc.drm.primary_display_order", display_order_buf.data(), - "..."); - - std::vector display_order; - std::istringstream str(display_order_buf.data()); - for (std::string conn_name = ""; std::getline(str, conn_name, ',');) { - trim(conn_name); - display_order.push_back(std::move(conn_name)); - } - return display_order; -} - -static std::vector make_primary_display_candidates( - std::vector> &connectors) { - std::vector primary_candidates; - std::transform(std::begin(connectors), std::end(connectors), - std::back_inserter(primary_candidates), - [](std::unique_ptr &conn) { - return conn.get(); - }); - primary_candidates.erase(std::remove_if(std::begin(primary_candidates), - std::end(primary_candidates), - [](const DrmConnector *conn) { - return conn->state() != - DRM_MODE_CONNECTED; - }), - std::end(primary_candidates)); - - std::vector display_order = read_primary_display_order_prop(); - bool use_other = display_order.back() == "..."; - - // putting connectors from primary_display_order first - auto curr_connector = std::begin(primary_candidates); - for (const std::string &display_name : display_order) { - auto it = std::find_if(std::begin(primary_candidates), - std::end(primary_candidates), - [&display_name](const DrmConnector *conn) { - return conn->name() == display_name; - }); - if (it != std::end(primary_candidates)) { - std::iter_swap(it, curr_connector); - ++curr_connector; - } - } - - if (use_other) { - // then putting internal connectors second, everything else afterwards - std::partition(curr_connector, std::end(primary_candidates), - [](const DrmConnector *conn) { return conn->internal(); }); - } else { - primary_candidates.erase(curr_connector, std::end(primary_candidates)); - } - - return primary_candidates; -} - -DrmDevice::DrmDevice() : event_listener_(this) { -} - -DrmDevice::~DrmDevice() { - event_listener_.Exit(); -} - -std::tuple 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: %s", path, strerror(errno)); - 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 std::make_tuple(ret, 0); - } - - ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_ATOMIC, 1); - if (ret) { - ALOGE("Failed to set atomic cap %d", ret); - return std::make_tuple(ret, 0); - } - -#ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS - ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1); - if (ret) { - ALOGI("Failed to set writeback cap %d", ret); - ret = 0; - } -#endif - - drmModeResPtr res = drmModeGetResources(fd()); - if (!res) { - ALOGE("Failed to get DrmDevice resources"); - return std::make_tuple(-ENODEV, 0); - } - - min_resolution_ = std::pair(res->min_width, - res->min_height); - max_resolution_ = std::pair(res->max_width, - res->max_height); - - // 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]); - if (!c) { - ALOGE("Failed to get crtc %d", res->crtcs[i]); - ret = -ENODEV; - break; - } - - std::unique_ptr crtc(new DrmCrtc(this, c, i)); - drmModeFreeCrtc(c); - - ret = crtc->Init(); - if (ret) { - ALOGE("Failed to initialize crtc %d", res->crtcs[i]); - break; - } - crtcs_.emplace_back(std::move(crtc)); - } - - std::vector possible_clones; - for (int i = 0; !ret && i < res->count_encoders; ++i) { - drmModeEncoderPtr e = drmModeGetEncoder(fd(), res->encoders[i]); - if (!e) { - ALOGE("Failed to get encoder %d", res->encoders[i]); - ret = -ENODEV; - break; - } - - std::vector possible_crtcs; - DrmCrtc *current_crtc = NULL; - for (auto &crtc : crtcs_) { - if ((1 << crtc->pipe()) & e->possible_crtcs) - possible_crtcs.push_back(crtc.get()); - - if (crtc->id() == e->crtc_id) - current_crtc = crtc.get(); - } - - std::unique_ptr enc( - new DrmEncoder(e, current_crtc, possible_crtcs)); - possible_clones.push_back(e->possible_clones); - drmModeFreeEncoder(e); - - encoders_.emplace_back(std::move(enc)); - } - - for (unsigned int i = 0; i < encoders_.size(); i++) { - for (unsigned int j = 0; j < encoders_.size(); j++) - if (possible_clones[i] & (1 << j)) - encoders_[i]->AddPossibleClone(encoders_[j].get()); - } - - for (int i = 0; !ret && i < res->count_connectors; ++i) { - drmModeConnectorPtr c = drmModeGetConnector(fd(), res->connectors[i]); - if (!c) { - ALOGE("Failed to get connector %d", res->connectors[i]); - ret = -ENODEV; - break; - } - - std::vector possible_encoders; - DrmEncoder *current_encoder = NULL; - for (int j = 0; j < c->count_encoders; ++j) { - for (auto &encoder : encoders_) { - if (encoder->id() == c->encoders[j]) - possible_encoders.push_back(encoder.get()); - if (encoder->id() == c->encoder_id) - current_encoder = encoder.get(); - } - } - - std::unique_ptr conn( - new DrmConnector(this, c, current_encoder, possible_encoders)); - - drmModeFreeConnector(c); - - ret = conn->Init(); - if (ret) { - ALOGE("Init connector %d failed", res->connectors[i]); - break; - } - - if (conn->writeback()) - writeback_connectors_.emplace_back(std::move(conn)); - else - connectors_.emplace_back(std::move(conn)); - } - - // Primary display priority: - // 1) vendor.hwc.drm.primary_display_order property - // 2) internal connectors - // 3) anything else - std::vector - primary_candidates = make_primary_display_candidates(connectors_); - if (!primary_candidates.empty() && !found_primary) { - DrmConnector &conn = **std::begin(primary_candidates); - conn.set_display(num_displays); - displays_[num_displays] = num_displays; - ++num_displays; - found_primary = true; - } else { - ALOGE( - "Failed to find primary display from " - "\"vendor.hwc.drm.primary_display_order\" property"); - } - - // If no priority display were found then pick first available as primary and - // for the others assign consecutive display_numbers. - for (auto &conn : connectors_) { - 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; - } - } - } - - if (res) - drmModeFreeResources(res); - - // Catch-all for the above loops - if (ret) - return std::make_tuple(ret, 0); - - drmModePlaneResPtr plane_res = drmModeGetPlaneResources(fd()); - if (!plane_res) { - ALOGE("Failed to get plane resources"); - return std::make_tuple(-ENOENT, 0); - } - - for (uint32_t i = 0; i < plane_res->count_planes; ++i) { - drmModePlanePtr p = drmModeGetPlane(fd(), plane_res->planes[i]); - if (!p) { - ALOGE("Failed to get plane %d", plane_res->planes[i]); - ret = -ENODEV; - break; - } - - std::unique_ptr plane(new DrmPlane(this, p)); - - drmModeFreePlane(p); - - ret = plane->Init(); - if (ret) { - ALOGE("Init plane %d failed", plane_res->planes[i]); - break; - } - - planes_.emplace_back(std::move(plane)); - } - drmModeFreePlaneResources(plane_res); - if (ret) - return std::make_tuple(ret, 0); - - ret = event_listener_.Init(); - if (ret) { - ALOGE("Can't initialize event listener %d", 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 std::make_tuple(ret, 0); - } - if (!AttachWriteback(conn.get())) { - ALOGI("Display %d has writeback attach to it", conn->display()); - } - } - 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 { - for (auto &conn : connectors_) { - if (conn->display() == display) - return conn.get(); - } - return NULL; -} - -DrmConnector *DrmDevice::GetWritebackConnectorForDisplay(int display) const { - for (auto &conn : writeback_connectors_) { - if (conn->display() == display) - return conn.get(); - } - return NULL; -} - -// TODO what happens when hotplugging -DrmConnector *DrmDevice::AvailableWritebackConnector(int display) const { - DrmConnector *writeback_conn = GetWritebackConnectorForDisplay(display); - DrmConnector *display_conn = GetConnectorForDisplay(display); - // If we have a writeback already attached to the same CRTC just use that, - // if possible. - if (display_conn && writeback_conn && - writeback_conn->encoder()->CanClone(display_conn->encoder())) - return writeback_conn; - - // Use another CRTC if available and doesn't have any connector - for (auto &crtc : crtcs_) { - if (crtc->display() == display) - continue; - display_conn = GetConnectorForDisplay(crtc->display()); - // If we have a display connected don't use it for writeback - if (display_conn && display_conn->state() == DRM_MODE_CONNECTED) - continue; - writeback_conn = GetWritebackConnectorForDisplay(crtc->display()); - if (writeback_conn) - return writeback_conn; - } - return NULL; -} - -DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const { - for (auto &crtc : crtcs_) { - if (crtc->display() == display) - return crtc.get(); - } - return NULL; -} - -DrmPlane *DrmDevice::GetPlane(uint32_t id) const { - for (auto &plane : planes_) { - if (plane->id() == id) - return plane.get(); - } - return NULL; -} - -const std::vector> &DrmDevice::crtcs() const { - return crtcs_; -} - -uint32_t DrmDevice::next_mode_id() { - return ++mode_id_; -} - -int DrmDevice::TryEncoderForDisplay(int display, DrmEncoder *enc) { - /* First try to use the currently-bound crtc */ - DrmCrtc *crtc = enc->crtc(); - if (crtc && crtc->can_bind(display)) { - crtc->set_display(display); - enc->set_crtc(crtc); - return 0; - } - - /* Try to find a possible crtc which will work */ - for (DrmCrtc *crtc : enc->possible_crtcs()) { - /* We've already tried this earlier */ - if (crtc == enc->crtc()) - continue; - - if (crtc->can_bind(display)) { - crtc->set_display(display); - enc->set_crtc(crtc); - return 0; - } - } - - /* We can't use the encoder, but nothing went wrong, try another one */ - return -EAGAIN; -} - -int DrmDevice::CreateDisplayPipe(DrmConnector *connector) { - int display = connector->display(); - /* Try to use current setup first */ - if (connector->encoder()) { - int ret = TryEncoderForDisplay(display, connector->encoder()); - if (!ret) { - return 0; - } else if (ret != -EAGAIN) { - ALOGE("Could not set mode %d/%d", display, ret); - return ret; - } - } - - for (DrmEncoder *enc : connector->possible_encoders()) { - int ret = TryEncoderForDisplay(display, enc); - if (!ret) { - connector->set_encoder(enc); - return 0; - } else if (ret != -EAGAIN) { - ALOGE("Could not set mode %d/%d", display, ret); - return ret; - } - } - ALOGE("Could not find a suitable encoder/crtc for display %d", - connector->display()); - return -ENODEV; -} - -// Attach writeback connector to the CRTC linked to the display_conn -int DrmDevice::AttachWriteback(DrmConnector *display_conn) { - DrmCrtc *display_crtc = display_conn->encoder()->crtc(); - if (GetWritebackConnectorForDisplay(display_crtc->display()) != NULL) { - ALOGE("Display already has writeback attach to it"); - return -EINVAL; - } - for (auto &writeback_conn : writeback_connectors_) { - if (writeback_conn->display() >= 0) - continue; - for (DrmEncoder *writeback_enc : writeback_conn->possible_encoders()) { - for (DrmCrtc *possible_crtc : writeback_enc->possible_crtcs()) { - if (possible_crtc != display_crtc) - continue; - // Use just encoders which had not been bound already - if (writeback_enc->can_bind(display_crtc->display())) { - writeback_enc->set_crtc(display_crtc); - writeback_conn->set_encoder(writeback_enc); - writeback_conn->set_display(display_crtc->display()); - writeback_conn->UpdateModes(); - return 0; - } - } - } - } - return -EINVAL; -} - -int DrmDevice::CreatePropertyBlob(void *data, size_t length, - uint32_t *blob_id) { - struct drm_mode_create_blob create_blob; - memset(&create_blob, 0, sizeof(create_blob)); - create_blob.length = length; - create_blob.data = (__u64)data; - - int ret = drmIoctl(fd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob); - if (ret) { - ALOGE("Failed to create mode property blob %d", ret); - return ret; - } - *blob_id = create_blob.blob_id; - return 0; -} - -int DrmDevice::DestroyPropertyBlob(uint32_t blob_id) { - if (!blob_id) - return 0; - - struct drm_mode_destroy_blob destroy_blob; - memset(&destroy_blob, 0, sizeof(destroy_blob)); - destroy_blob.blob_id = (__u32)blob_id; - int ret = drmIoctl(fd(), DRM_IOCTL_MODE_DESTROYPROPBLOB, &destroy_blob); - if (ret) { - ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", blob_id, ret); - return ret; - } - return 0; -} - -DrmEventListener *DrmDevice::event_listener() { - return &event_listener_; -} - -int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type, - const char *prop_name, DrmProperty *property) { - drmModeObjectPropertiesPtr props; - - props = drmModeObjectGetProperties(fd(), obj_id, obj_type); - if (!props) { - ALOGE("Failed to get properties for %d/%x", obj_id, obj_type); - return -ENODEV; - } - - bool found = false; - for (int i = 0; !found && (size_t)i < props->count_props; ++i) { - drmModePropertyPtr p = drmModeGetProperty(fd(), props->props[i]); - if (!strcmp(p->name, prop_name)) { - property->Init(p, props->prop_values[i]); - found = true; - } - drmModeFreeProperty(p); - } - - drmModeFreeObjectProperties(props); - return found ? 0 : -ENOENT; -} - -int DrmDevice::GetPlaneProperty(const DrmPlane &plane, const char *prop_name, - DrmProperty *property) { - return GetProperty(plane.id(), DRM_MODE_OBJECT_PLANE, prop_name, property); -} - -int DrmDevice::GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name, - DrmProperty *property) { - return GetProperty(crtc.id(), DRM_MODE_OBJECT_CRTC, prop_name, property); -} - -int DrmDevice::GetConnectorProperty(const DrmConnector &connector, - const char *prop_name, - DrmProperty *property) { - return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name, - property); -} - -const std::string DrmDevice::GetName() const { - auto ver = drmGetVersion(fd_.get()); - if (!ver) { - ALOGW("Failed to get drm version for fd=%d", fd_.get()); - return "generic"; - } - - std::string name(ver->name); - drmFreeVersion(ver); - return name; -} -} // namespace android diff --git a/drm/drmdevice.h b/drm/drmdevice.h deleted file mode 100644 index 6a8de47..0000000 --- a/drm/drmdevice.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2015 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 ANDROID_DRM_H_ -#define ANDROID_DRM_H_ - -#include - -#include - -#include "drmconnector.h" -#include "drmcrtc.h" -#include "drmencoder.h" -#include "drmeventlistener.h" -#include "drmplane.h" -#include "platform/platform.h" - -namespace android { - -class DrmDevice { - public: - DrmDevice(); - ~DrmDevice(); - - std::tuple Init(const char *path, int num_displays); - - int fd() const { - return fd_.get(); - } - - const std::vector> &connectors() const { - return connectors_; - } - - const std::vector> &planes() const { - return planes_; - } - - std::pair min_resolution() const { - return min_resolution_; - } - - std::pair max_resolution() const { - return max_resolution_; - } - - DrmConnector *GetConnectorForDisplay(int display) const; - DrmConnector *GetWritebackConnectorForDisplay(int display) const; - DrmConnector *AvailableWritebackConnector(int display) const; - DrmCrtc *GetCrtcForDisplay(int display) const; - DrmPlane *GetPlane(uint32_t id) const; - DrmEventListener *event_listener(); - - int GetPlaneProperty(const DrmPlane &plane, const char *prop_name, - DrmProperty *property); - int GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name, - DrmProperty *property); - int GetConnectorProperty(const DrmConnector &connector, const char *prop_name, - DrmProperty *property); - - const std::string GetName() const; - - const std::vector> &crtcs() const; - uint32_t next_mode_id(); - - int CreatePropertyBlob(void *data, size_t length, uint32_t *blob_id); - int DestroyPropertyBlob(uint32_t blob_id); - bool HandlesDisplay(int display) const; - void RegisterHotplugHandler(DrmEventHandler *handler) { - event_listener_.RegisterHotplugHandler(handler); - } - - private: - int TryEncoderForDisplay(int display, DrmEncoder *enc); - int GetProperty(uint32_t obj_id, uint32_t obj_type, const char *prop_name, - DrmProperty *property); - - int CreateDisplayPipe(DrmConnector *connector); - int AttachWriteback(DrmConnector *display_conn); - - UniqueFd fd_; - uint32_t mode_id_ = 0; - - std::vector> connectors_; - std::vector> writeback_connectors_; - std::vector> encoders_; - std::vector> crtcs_; - std::vector> planes_; - DrmEventListener event_listener_; - - std::pair min_resolution_; - std::pair max_resolution_; - std::map displays_; -}; -} // namespace android - -#endif // ANDROID_DRM_H_ diff --git a/drm/drmencoder.cpp b/drm/drmencoder.cpp deleted file mode 100644 index 9aa6805..0000000 --- a/drm/drmencoder.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#include "drmencoder.h" -#include "drmdevice.h" - -#include -#include - -namespace android { - -DrmEncoder::DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc, - const std::vector &possible_crtcs) - : id_(e->encoder_id), - crtc_(current_crtc), - display_(-1), - possible_crtcs_(possible_crtcs) { -} - -uint32_t DrmEncoder::id() const { - return id_; -} - -DrmCrtc *DrmEncoder::crtc() const { - return crtc_; -} - -bool DrmEncoder::CanClone(DrmEncoder *possible_clone) { - return possible_clones_.find(possible_clone) != possible_clones_.end(); -} - -void DrmEncoder::AddPossibleClone(DrmEncoder *possible_clone) { - possible_clones_.insert(possible_clone); -} - -void DrmEncoder::set_crtc(DrmCrtc *crtc) { - crtc_ = crtc; - display_ = crtc->display(); -} - -int DrmEncoder::display() const { - return display_; -} - -bool DrmEncoder::can_bind(int display) const { - return display_ == -1 || display_ == display; -} -} // namespace android diff --git a/drm/drmencoder.h b/drm/drmencoder.h deleted file mode 100644 index 4403d9f..0000000 --- a/drm/drmencoder.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2015 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 ANDROID_DRM_ENCODER_H_ -#define ANDROID_DRM_ENCODER_H_ - -#include -#include - -#include -#include - -#include "drmcrtc.h" - -namespace android { - -class DrmEncoder { - public: - DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc, - const std::vector &possible_crtcs); - DrmEncoder(const DrmEncoder &) = delete; - DrmEncoder &operator=(const DrmEncoder &) = delete; - - uint32_t id() const; - - DrmCrtc *crtc() const; - void set_crtc(DrmCrtc *crtc); - bool can_bind(int display) const; - int display() const; - - const std::vector &possible_crtcs() const { - return possible_crtcs_; - } - bool CanClone(DrmEncoder *encoder); - void AddPossibleClone(DrmEncoder *possible_clone); - - private: - uint32_t id_; - DrmCrtc *crtc_; - int display_; - - std::vector possible_crtcs_; - std::set possible_clones_; -}; -} // namespace android - -#endif // ANDROID_DRM_ENCODER_H_ diff --git a/drm/drmeventlistener.cpp b/drm/drmeventlistener.cpp deleted file mode 100644 index ccee0d6..0000000 --- a/drm/drmeventlistener.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2016 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-drm-event-listener" - -#include "drmeventlistener.h" -#include "drmdevice.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -namespace android { - -DrmEventListener::DrmEventListener(DrmDevice *drm) - : Worker("drm-event-listener", HAL_PRIORITY_URGENT_DISPLAY), drm_(drm) { -} - -int DrmEventListener::Init() { - uevent_fd_.Set(socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)); - if (uevent_fd_.get() < 0) { - ALOGE("Failed to open uevent socket: %s", strerror(errno)); - return uevent_fd_.get(); - } - - struct sockaddr_nl addr; - memset(&addr, 0, sizeof(addr)); - addr.nl_family = AF_NETLINK; - addr.nl_pid = 0; - addr.nl_groups = 0xFFFFFFFF; - - int ret = bind(uevent_fd_.get(), (struct sockaddr *)&addr, sizeof(addr)); - if (ret) { - ALOGE("Failed to bind uevent socket: %s", strerror(errno)); - return -errno; - } - - FD_ZERO(&fds_); - FD_SET(drm_->fd(), &fds_); - FD_SET(uevent_fd_.get(), &fds_); - max_fd_ = std::max(drm_->fd(), uevent_fd_.get()); - - return InitWorker(); -} - -void DrmEventListener::RegisterHotplugHandler(DrmEventHandler *handler) { - assert(!hotplug_handler_); - hotplug_handler_.reset(handler); -} - -void DrmEventListener::FlipHandler(int /* fd */, unsigned int /* sequence */, - unsigned int tv_sec, unsigned int tv_usec, - void *user_data) { - DrmEventHandler *handler = (DrmEventHandler *)user_data; - if (!handler) - return; - - handler->HandleEvent((uint64_t)tv_sec * 1000 * 1000 + tv_usec); - delete handler; -} - -void DrmEventListener::UEventHandler() { - char buffer[1024]; - int ret; - - struct timespec ts; - uint64_t timestamp = 0; - ret = clock_gettime(CLOCK_MONOTONIC, &ts); - if (!ret) - timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec; - else - ALOGE("Failed to get monotonic clock on hotplug %d", ret); - - while (true) { - ret = read(uevent_fd_.get(), &buffer, sizeof(buffer)); - if (ret == 0) { - return; - } else if (ret < 0) { - ALOGE("Got error reading uevent %d", ret); - return; - } - - if (!hotplug_handler_) - continue; - - bool drm_event = false, hotplug_event = false; - for (int i = 0; i < ret;) { - char *event = buffer + i; - if (strcmp(event, "DEVTYPE=drm_minor")) - drm_event = true; - else if (strcmp(event, "HOTPLUG=1")) - hotplug_event = true; - - i += strlen(event) + 1; - } - - if (drm_event && hotplug_event) - hotplug_handler_->HandleEvent(timestamp); - } -} - -void DrmEventListener::Routine() { - int ret; - do { - ret = select(max_fd_ + 1, &fds_, NULL, NULL, NULL); - } while (ret == -1 && errno == EINTR); - - if (FD_ISSET(drm_->fd(), &fds_)) { - drmEventContext event_context = - {.version = 2, - .vblank_handler = NULL, - .page_flip_handler = DrmEventListener::FlipHandler}; - drmHandleEvent(drm_->fd(), &event_context); - } - - if (FD_ISSET(uevent_fd_.get(), &fds_)) - UEventHandler(); -} -} // namespace android diff --git a/drm/drmeventlistener.h b/drm/drmeventlistener.h deleted file mode 100644 index ff3b8e5..0000000 --- a/drm/drmeventlistener.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2016 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 ANDROID_DRM_EVENT_LISTENER_H_ -#define ANDROID_DRM_EVENT_LISTENER_H_ - -#include "autofd.h" -#include "utils/worker.h" - -namespace android { - -class DrmDevice; - -class DrmEventHandler { - public: - DrmEventHandler() { - } - virtual ~DrmEventHandler() { - } - - virtual void HandleEvent(uint64_t timestamp_us) = 0; -}; - -class DrmEventListener : public Worker { - public: - DrmEventListener(DrmDevice *drm); - virtual ~DrmEventListener() { - } - - int Init(); - - void RegisterHotplugHandler(DrmEventHandler *handler); - - static void FlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, - unsigned int tv_usec, void *user_data); - - protected: - virtual void Routine(); - - private: - void UEventHandler(); - - fd_set fds_; - UniqueFd uevent_fd_; - int max_fd_ = -1; - - DrmDevice *drm_; - std::unique_ptr hotplug_handler_; -}; -} // namespace android - -#endif diff --git a/drm/drmmode.cpp b/drm/drmmode.cpp deleted file mode 100644 index c1398ef..0000000 --- a/drm/drmmode.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#include "drmmode.h" -#include "drmdevice.h" - -namespace android { - -DrmMode::DrmMode(drmModeModeInfoPtr m) - : id_(0), - clock_(m->clock), - h_display_(m->hdisplay), - h_sync_start_(m->hsync_start), - h_sync_end_(m->hsync_end), - h_total_(m->htotal), - h_skew_(m->hskew), - v_display_(m->vdisplay), - v_sync_start_(m->vsync_start), - v_sync_end_(m->vsync_end), - v_total_(m->vtotal), - v_scan_(m->vscan), - v_refresh_(m->vrefresh), - flags_(m->flags), - type_(m->type), - name_(m->name) { -} - -bool DrmMode::operator==(const drmModeModeInfo &m) const { - return clock_ == m.clock && h_display_ == m.hdisplay && - h_sync_start_ == m.hsync_start && h_sync_end_ == m.hsync_end && - h_total_ == m.htotal && h_skew_ == m.hskew && - v_display_ == m.vdisplay && v_sync_start_ == m.vsync_start && - v_sync_end_ == m.vsync_end && v_total_ == m.vtotal && - v_scan_ == m.vscan && flags_ == m.flags && type_ == m.type; -} - -void DrmMode::ToDrmModeModeInfo(drm_mode_modeinfo *m) const { - m->clock = clock_; - m->hdisplay = h_display_; - m->hsync_start = h_sync_start_; - m->hsync_end = h_sync_end_; - m->htotal = h_total_; - m->hskew = h_skew_; - m->vdisplay = v_display_; - m->vsync_start = v_sync_start_; - m->vsync_end = v_sync_end_; - m->vtotal = v_total_; - m->vscan = v_scan_; - m->vrefresh = v_refresh_; - m->flags = flags_; - m->type = type_; - strncpy(m->name, name_.c_str(), DRM_DISPLAY_MODE_LEN); -} - -uint32_t DrmMode::id() const { - return id_; -} - -void DrmMode::set_id(uint32_t id) { - id_ = id; -} - -uint32_t DrmMode::clock() const { - return clock_; -} - -uint32_t DrmMode::h_display() const { - return h_display_; -} - -uint32_t DrmMode::h_sync_start() const { - return h_sync_start_; -} - -uint32_t DrmMode::h_sync_end() const { - return h_sync_end_; -} - -uint32_t DrmMode::h_total() const { - return h_total_; -} - -uint32_t DrmMode::h_skew() const { - return h_skew_; -} - -uint32_t DrmMode::v_display() const { - return v_display_; -} - -uint32_t DrmMode::v_sync_start() const { - return v_sync_start_; -} - -uint32_t DrmMode::v_sync_end() const { - return v_sync_end_; -} - -uint32_t DrmMode::v_total() const { - return v_total_; -} - -uint32_t DrmMode::v_scan() const { - return v_scan_; -} - -float DrmMode::v_refresh() const { - // Always recalculate refresh to report correct float rate - return clock_ / (float)(v_total_ * h_total_) * 1000.0f; -} - -uint32_t DrmMode::flags() const { - return flags_; -} - -uint32_t DrmMode::type() const { - return type_; -} - -std::string DrmMode::name() const { - return name_; -} -} // namespace android diff --git a/drm/drmmode.h b/drm/drmmode.h deleted file mode 100644 index 313a8ea..0000000 --- a/drm/drmmode.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2015 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 ANDROID_DRM_MODE_H_ -#define ANDROID_DRM_MODE_H_ - -#include -#include - -#include - -namespace android { - -class DrmMode { - public: - DrmMode() = default; - DrmMode(drmModeModeInfoPtr m); - - bool operator==(const drmModeModeInfo &m) const; - void ToDrmModeModeInfo(drm_mode_modeinfo *m) const; - - uint32_t id() const; - void set_id(uint32_t id); - - uint32_t clock() const; - - uint32_t h_display() const; - uint32_t h_sync_start() const; - uint32_t h_sync_end() const; - uint32_t h_total() const; - uint32_t h_skew() const; - - uint32_t v_display() const; - uint32_t v_sync_start() const; - uint32_t v_sync_end() const; - uint32_t v_total() const; - uint32_t v_scan() const; - float v_refresh() const; - - uint32_t flags() const; - uint32_t type() const; - - std::string name() const; - - private: - uint32_t id_ = 0; - - uint32_t clock_ = 0; - - uint32_t h_display_ = 0; - uint32_t h_sync_start_ = 0; - uint32_t h_sync_end_ = 0; - uint32_t h_total_ = 0; - uint32_t h_skew_ = 0; - - uint32_t v_display_ = 0; - uint32_t v_sync_start_ = 0; - uint32_t v_sync_end_ = 0; - uint32_t v_total_ = 0; - uint32_t v_scan_ = 0; - uint32_t v_refresh_ = 0; - - uint32_t flags_ = 0; - uint32_t type_ = 0; - - std::string name_; -}; -} // namespace android - -#endif // ANDROID_DRM_MODE_H_ diff --git a/drm/drmplane.cpp b/drm/drmplane.cpp deleted file mode 100644 index f0c7559..0000000 --- a/drm/drmplane.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2015 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-drm-plane" - -#include "drmplane.h" -#include "drmdevice.h" - -#include -#include -#include - -#include - -namespace android { - -DrmPlane::DrmPlane(DrmDevice *drm, drmModePlanePtr p) - : drm_(drm), id_(p->plane_id), possible_crtc_mask_(p->possible_crtcs) { -} - -int DrmPlane::Init() { - DrmProperty p; - - int ret = drm_->GetPlaneProperty(*this, "type", &p); - if (ret) { - ALOGE("Could not get plane type property"); - return ret; - } - - uint64_t type; - std::tie(ret, type) = p.value(); - if (ret) { - ALOGE("Failed to get plane type property value"); - return ret; - } - switch (type) { - case DRM_PLANE_TYPE_OVERLAY: - case DRM_PLANE_TYPE_PRIMARY: - case DRM_PLANE_TYPE_CURSOR: - type_ = (uint32_t)type; - break; - default: - ALOGE("Invalid plane type %" PRIu64, type); - return -EINVAL; - } - - ret = drm_->GetPlaneProperty(*this, "CRTC_ID", &crtc_property_); - if (ret) { - ALOGE("Could not get CRTC_ID property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "FB_ID", &fb_property_); - if (ret) { - ALOGE("Could not get FB_ID property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "CRTC_X", &crtc_x_property_); - if (ret) { - ALOGE("Could not get CRTC_X property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "CRTC_Y", &crtc_y_property_); - if (ret) { - ALOGE("Could not get CRTC_Y property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "CRTC_W", &crtc_w_property_); - if (ret) { - ALOGE("Could not get CRTC_W property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "CRTC_H", &crtc_h_property_); - if (ret) { - ALOGE("Could not get CRTC_H property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "SRC_X", &src_x_property_); - if (ret) { - ALOGE("Could not get SRC_X property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "SRC_Y", &src_y_property_); - if (ret) { - ALOGE("Could not get SRC_Y property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "SRC_W", &src_w_property_); - if (ret) { - ALOGE("Could not get SRC_W property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "SRC_H", &src_h_property_); - if (ret) { - ALOGE("Could not get SRC_H property"); - return ret; - } - - ret = drm_->GetPlaneProperty(*this, "zpos", &zpos_property_); - if (ret) - ALOGE("Could not get zpos property for plane %u", id()); - - ret = drm_->GetPlaneProperty(*this, "rotation", &rotation_property_); - if (ret) - ALOGE("Could not get rotation property"); - - ret = drm_->GetPlaneProperty(*this, "alpha", &alpha_property_); - if (ret) - ALOGI("Could not get alpha property"); - - ret = drm_->GetPlaneProperty(*this, "pixel blend mode", &blend_property_); - if (ret) - ALOGI("Could not get pixel blend mode property"); - - ret = drm_->GetPlaneProperty(*this, "IN_FENCE_FD", &in_fence_fd_property_); - if (ret) - ALOGI("Could not get IN_FENCE_FD property"); - - return 0; -} - -uint32_t DrmPlane::id() const { - return id_; -} - -bool DrmPlane::GetCrtcSupported(const DrmCrtc &crtc) const { - return !!((1 << crtc.pipe()) & possible_crtc_mask_); -} - -uint32_t DrmPlane::type() const { - return type_; -} - -const DrmProperty &DrmPlane::crtc_property() const { - return crtc_property_; -} - -const DrmProperty &DrmPlane::fb_property() const { - return fb_property_; -} - -const DrmProperty &DrmPlane::crtc_x_property() const { - return crtc_x_property_; -} - -const DrmProperty &DrmPlane::crtc_y_property() const { - return crtc_y_property_; -} - -const DrmProperty &DrmPlane::crtc_w_property() const { - return crtc_w_property_; -} - -const DrmProperty &DrmPlane::crtc_h_property() const { - return crtc_h_property_; -} - -const DrmProperty &DrmPlane::src_x_property() const { - return src_x_property_; -} - -const DrmProperty &DrmPlane::src_y_property() const { - return src_y_property_; -} - -const DrmProperty &DrmPlane::src_w_property() const { - return src_w_property_; -} - -const DrmProperty &DrmPlane::src_h_property() const { - return src_h_property_; -} - -const DrmProperty &DrmPlane::zpos_property() const { - return zpos_property_; -} - -const DrmProperty &DrmPlane::rotation_property() const { - return rotation_property_; -} - -const DrmProperty &DrmPlane::alpha_property() const { - return alpha_property_; -} - -const DrmProperty &DrmPlane::blend_property() const { - return blend_property_; -} - -const DrmProperty &DrmPlane::in_fence_fd_property() const { - return in_fence_fd_property_; -} -} // namespace android diff --git a/drm/drmplane.h b/drm/drmplane.h deleted file mode 100644 index 1a4dc91..0000000 --- a/drm/drmplane.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2015 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 ANDROID_DRM_PLANE_H_ -#define ANDROID_DRM_PLANE_H_ - -#include -#include - -#include - -#include "drmcrtc.h" -#include "drmproperty.h" - -namespace android { - -class DrmDevice; - -class DrmPlane { - public: - DrmPlane(DrmDevice *drm, drmModePlanePtr p); - DrmPlane(const DrmPlane &) = delete; - DrmPlane &operator=(const DrmPlane &) = delete; - - int Init(); - - uint32_t id() const; - - bool GetCrtcSupported(const DrmCrtc &crtc) const; - - uint32_t type() const; - - const DrmProperty &crtc_property() const; - const DrmProperty &fb_property() const; - const DrmProperty &crtc_x_property() const; - const DrmProperty &crtc_y_property() const; - const DrmProperty &crtc_w_property() const; - const DrmProperty &crtc_h_property() const; - const DrmProperty &src_x_property() const; - const DrmProperty &src_y_property() const; - const DrmProperty &src_w_property() const; - const DrmProperty &src_h_property() const; - const DrmProperty &zpos_property() const; - const DrmProperty &rotation_property() const; - const DrmProperty &alpha_property() const; - const DrmProperty &blend_property() const; - const DrmProperty &in_fence_fd_property() const; - - private: - DrmDevice *drm_; - uint32_t id_; - - uint32_t possible_crtc_mask_; - - uint32_t type_; - - DrmProperty crtc_property_; - DrmProperty fb_property_; - DrmProperty crtc_x_property_; - DrmProperty crtc_y_property_; - DrmProperty crtc_w_property_; - DrmProperty crtc_h_property_; - DrmProperty src_x_property_; - DrmProperty src_y_property_; - DrmProperty src_w_property_; - DrmProperty src_h_property_; - DrmProperty zpos_property_; - DrmProperty rotation_property_; - DrmProperty alpha_property_; - DrmProperty blend_property_; - DrmProperty in_fence_fd_property_; -}; -} // namespace android - -#endif // ANDROID_DRM_PLANE_H_ diff --git a/drm/drmproperty.cpp b/drm/drmproperty.cpp deleted file mode 100644 index 3aeed13..0000000 --- a/drm/drmproperty.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#include "drmproperty.h" -#include "drmdevice.h" - -#include -#include -#include - -#include - -namespace android { - -DrmProperty::DrmPropertyEnum::DrmPropertyEnum(drm_mode_property_enum *e) - : value_(e->value), name_(e->name) { -} - -DrmProperty::DrmPropertyEnum::~DrmPropertyEnum() { -} - -DrmProperty::DrmProperty(drmModePropertyPtr p, uint64_t value) - : id_(0), type_(DRM_PROPERTY_TYPE_INVALID), flags_(0), name_("") { - Init(p, value); -} - -void DrmProperty::Init(drmModePropertyPtr p, uint64_t value) { - id_ = p->prop_id; - flags_ = p->flags; - name_ = p->name; - value_ = value; - - for (int i = 0; i < p->count_values; ++i) - values_.push_back(p->values[i]); - - for (int i = 0; i < p->count_enums; ++i) - enums_.push_back(DrmPropertyEnum(&p->enums[i])); - - for (int i = 0; i < p->count_blobs; ++i) - blob_ids_.push_back(p->blob_ids[i]); - - if (flags_ & DRM_MODE_PROP_RANGE) - type_ = DRM_PROPERTY_TYPE_INT; - else if (flags_ & DRM_MODE_PROP_ENUM) - type_ = DRM_PROPERTY_TYPE_ENUM; - else if (flags_ & DRM_MODE_PROP_OBJECT) - type_ = DRM_PROPERTY_TYPE_OBJECT; - else if (flags_ & DRM_MODE_PROP_BLOB) - type_ = DRM_PROPERTY_TYPE_BLOB; -} - -uint32_t DrmProperty::id() const { - return id_; -} - -std::string DrmProperty::name() const { - return name_; -} - -std::tuple DrmProperty::value() const { - if (type_ == DRM_PROPERTY_TYPE_BLOB) - return std::make_tuple(0, value_); - - if (values_.size() == 0) - return std::make_tuple(-ENOENT, 0); - - switch (type_) { - case DRM_PROPERTY_TYPE_INT: - return std::make_tuple(0, value_); - - case DRM_PROPERTY_TYPE_ENUM: - if (value_ >= enums_.size()) - return std::make_tuple(-ENOENT, 0); - - return std::make_tuple(0, enums_[value_].value_); - - case DRM_PROPERTY_TYPE_OBJECT: - return std::make_tuple(0, value_); - - default: - return std::make_tuple(-EINVAL, 0); - } -} - -bool DrmProperty::is_immutable() const { - return id_ && (flags_ & DRM_MODE_PROP_IMMUTABLE); -} - -bool DrmProperty::is_range() const { - return id_ && (flags_ & DRM_MODE_PROP_RANGE); -} - -std::tuple DrmProperty::range_min() const { - if (!is_range()) - return std::make_tuple(-EINVAL, 0); - if (values_.size() < 1) - return std::make_tuple(-ENOENT, 0); - - return std::make_tuple(0, values_[0]); -} - -std::tuple DrmProperty::range_max() const { - if (!is_range()) - return std::make_tuple(-EINVAL, 0); - if (values_.size() < 2) - return std::make_tuple(-ENOENT, 0); - - return std::make_tuple(0, values_[1]); -} - -std::tuple DrmProperty::GetEnumValueWithName( - std::string name) const { - for (auto it : enums_) { - if (it.name_.compare(name) == 0) { - return std::make_tuple(it.value_, 0); - } - } - - return std::make_tuple(UINT64_MAX, -EINVAL); -} -} // namespace android diff --git a/drm/drmproperty.h b/drm/drmproperty.h deleted file mode 100644 index d293da3..0000000 --- a/drm/drmproperty.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2015 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 ANDROID_DRM_PROPERTY_H_ -#define ANDROID_DRM_PROPERTY_H_ - -#include -#include - -#include -#include - -namespace android { - -enum DrmPropertyType { - DRM_PROPERTY_TYPE_INT, - DRM_PROPERTY_TYPE_ENUM, - DRM_PROPERTY_TYPE_OBJECT, - DRM_PROPERTY_TYPE_BLOB, - DRM_PROPERTY_TYPE_INVALID, -}; - -class DrmProperty { - public: - DrmProperty() = default; - DrmProperty(drmModePropertyPtr p, uint64_t value); - DrmProperty(const DrmProperty &) = delete; - DrmProperty &operator=(const DrmProperty &) = delete; - - void Init(drmModePropertyPtr p, uint64_t value); - std::tuple GetEnumValueWithName(std::string name) const; - - uint32_t id() const; - std::string name() const; - - std::tuple value() const; - bool is_immutable() const; - - bool is_range() const; - std::tuple range_min() const; - std::tuple range_max() const; - - private: - class DrmPropertyEnum { - public: - DrmPropertyEnum(drm_mode_property_enum *e); - ~DrmPropertyEnum(); - - uint64_t value_; - std::string name_; - }; - - uint32_t id_ = 0; - - DrmPropertyType type_ = DRM_PROPERTY_TYPE_INVALID; - uint32_t flags_ = 0; - std::string name_; - uint64_t value_ = 0; - - std::vector values_; - std::vector enums_; - std::vector blob_ids_; -}; -} // namespace android - -#endif // ANDROID_DRM_PROPERTY_H_ diff --git a/drm/resourcemanager.cpp b/drm/resourcemanager.cpp deleted file mode 100644 index 45fa818..0000000 --- a/drm/resourcemanager.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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 -#include -#include -#include - -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("vendor.hwc.drm.device", path_pattern, - "/dev/dri/card%"); - 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; - - struct stat buf; - if (stat(path.str().c_str(), &buf)) { - break; - } else if (IsKMSDev(path.str().c_str())) { - ret = AddDrmDevice(path.str()); - } - } - } - - if (!num_displays_) { - ALOGE("Failed to initialize any displays"); - return ret ? -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)); - - return hw_get_module(GRALLOC_HARDWARE_MODULE_ID, - (const hw_module_t **)&gralloc_); -} - -int ResourceManager::AddDrmDevice(std::string path) { - std::unique_ptr drm = std::make_unique(); - 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.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; -} - -DrmConnector *ResourceManager::AvailableWritebackConnector(int display) { - DrmDevice *drm_device = GetDrmDevice(display); - DrmConnector *writeback_conn = NULL; - if (drm_device) { - writeback_conn = drm_device->AvailableWritebackConnector(display); - if (writeback_conn) - return writeback_conn; - } - for (auto &drm : drms_) { - if (drm.get() == drm_device) - continue; - writeback_conn = drm->AvailableWritebackConnector(display); - if (writeback_conn) - return writeback_conn; - } - return writeback_conn; -} - -bool ResourceManager::IsKMSDev(const char *path) { - int fd = open(path, O_RDWR | O_CLOEXEC); - if (fd < 0) - return false; - - auto res = drmModeGetResources(fd); - if (!res) { - close(fd); - return false; - } - - bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 && - res->count_encoders > 0; - - drmModeFreeResources(res); - close(fd); - - return is_kms; -} - -DrmDevice *ResourceManager::GetDrmDevice(int display) { - for (auto &drm : drms_) { - if (drm->HandlesDisplay(display)) - return drm.get(); - } - return NULL; -} - -std::shared_ptr 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_; -} -} // namespace android diff --git a/drm/resourcemanager.h b/drm/resourcemanager.h deleted file mode 100644 index 4afa842..0000000 --- a/drm/resourcemanager.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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 - -#include "drmdevice.h" -#include "platform/platform.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 GetImporter(int display); - const gralloc_module_t *gralloc(); - DrmConnector *AvailableWritebackConnector(int display); - const std::vector> &getDrmDevices() const { - return drms_; - } - int getDisplayCount() const { - return num_displays_; - } - bool ForcedScalingWithGpu() { - return scale_with_gpu_; - } - - private: - int AddDrmDevice(std::string path); - static bool IsKMSDev(const char *path); - - int num_displays_; - std::vector> drms_; - std::vector> importers_; - const gralloc_module_t *gralloc_; - - bool scale_with_gpu_; -}; -} // namespace android - -#endif // RESOURCEMANAGER_H diff --git a/drm/vsyncworker.cpp b/drm/vsyncworker.cpp deleted file mode 100644 index 55dbd26..0000000 --- a/drm/vsyncworker.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2015 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-vsync-worker" - -#include "vsyncworker.h" - -#include -#include -#include -#include - -#include - -namespace android { - -VSyncWorker::VSyncWorker() - : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY), - drm_(NULL), - display_(-1), - enabled_(false), - last_timestamp_(-1) { -} - -VSyncWorker::~VSyncWorker() { -} - -int VSyncWorker::Init(DrmDevice *drm, int display) { - drm_ = drm; - display_ = display; - - return InitWorker(); -} - -void VSyncWorker::RegisterCallback(std::shared_ptr callback) { - Lock(); - callback_ = callback; - Unlock(); -} - -void VSyncWorker::VSyncControl(bool enabled) { - Lock(); - enabled_ = enabled; - last_timestamp_ = -1; - Unlock(); - - Signal(); -} - -/* - * Returns the timestamp of the next vsync in phase with last_timestamp_. - * For example: - * last_timestamp_ = 137 - * frame_ns = 50 - * current = 683 - * - * ret = (50 * ((683 - 137)/50 + 1)) + 137 - * ret = 687 - * - * Thus, we must sleep until timestamp 687 to maintain phase with the last - * timestamp. - */ -int64_t VSyncWorker::GetPhasedVSync(int64_t frame_ns, int64_t current) { - if (last_timestamp_ < 0) - return current + frame_ns; - - return frame_ns * ((current - last_timestamp_) / frame_ns + 1) + - last_timestamp_; -} - -static const int64_t kOneSecondNs = 1 * 1000 * 1000 * 1000; - -int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) { - struct timespec vsync; - int ret = clock_gettime(CLOCK_MONOTONIC, &vsync); - - float refresh = 60.0f; // Default to 60Hz refresh rate - DrmConnector *conn = drm_->GetConnectorForDisplay(display_); - if (conn && conn->active_mode().v_refresh() != 0.0f) - refresh = conn->active_mode().v_refresh(); - else - ALOGW("Vsync worker active with conn=%p refresh=%f\n", conn, - conn ? conn->active_mode().v_refresh() : 0.0f); - - int64_t phased_timestamp = GetPhasedVSync(kOneSecondNs / refresh, - vsync.tv_sec * kOneSecondNs + - vsync.tv_nsec); - vsync.tv_sec = phased_timestamp / kOneSecondNs; - vsync.tv_nsec = phased_timestamp - (vsync.tv_sec * kOneSecondNs); - do { - ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &vsync, NULL); - } while (ret == -1 && errno == EINTR); - if (ret) - return ret; - - *timestamp = (int64_t)vsync.tv_sec * kOneSecondNs + (int64_t)vsync.tv_nsec; - return 0; -} - -void VSyncWorker::Routine() { - int ret; - - Lock(); - if (!enabled_) { - ret = WaitForSignalOrExitLocked(); - if (ret == -EINTR) { - Unlock(); - return; - } - } - - int display = display_; - std::shared_ptr callback(callback_); - Unlock(); - - DrmCrtc *crtc = drm_->GetCrtcForDisplay(display); - if (!crtc) { - ALOGE("Failed to get crtc for display"); - return; - } - uint32_t high_crtc = (crtc->pipe() << DRM_VBLANK_HIGH_CRTC_SHIFT); - - drmVBlank vblank; - memset(&vblank, 0, sizeof(vblank)); - vblank.request.type = (drmVBlankSeqType)( - DRM_VBLANK_RELATIVE | (high_crtc & DRM_VBLANK_HIGH_CRTC_MASK)); - vblank.request.sequence = 1; - - int64_t timestamp; - ret = drmWaitVBlank(drm_->fd(), &vblank); - if (ret == -EINTR) { - return; - } else if (ret) { - ret = SyntheticWaitVBlank(×tamp); - if (ret) - return; - } else { - timestamp = (int64_t)vblank.reply.tval_sec * kOneSecondNs + - (int64_t)vblank.reply.tval_usec * 1000; - } - - /* - * VSync could be disabled during routine execution so it could potentially - * lead to crash since callback's inner hook could be invalid anymore. We have - * no control over lifetime of this hook, therefore we can't rely that it'll - * be valid after vsync disabling. - * - * Blocking VSyncControl to wait until routine - * will finish execution is logically correct way to fix this issue, but it - * creates visible lags and stutters, so we have to resort to other ways of - * mitigating this issue. - * - * Doing check before attempt to invoke callback drastically shortens the - * window when such situation could happen and that allows us to practically - * avoid this issue. - * - * Please note that issue described below is different one and it is related - * to RegisterCallback, not to disabling vsync via VSyncControl. - */ - if (!enabled_) - return; - /* - * There's a race here where a change in callback_ will not take effect until - * the next subsequent requested vsync. This is unavoidable since we can't - * call the vsync hook while holding the thread lock. - * - * We could shorten the race window by caching callback_ right before calling - * the hook. However, in practice, callback_ is only updated once, so it's not - * worth the overhead. - */ - if (callback) - callback->Callback(display, timestamp); - last_timestamp_ = timestamp; -} -} // namespace android diff --git a/drm/vsyncworker.h b/drm/vsyncworker.h deleted file mode 100644 index cbf4ffa..0000000 --- a/drm/vsyncworker.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2015 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 ANDROID_EVENT_WORKER_H_ -#define ANDROID_EVENT_WORKER_H_ - -#include -#include -#include - -#include - -#include "drmdevice.h" -#include "utils/worker.h" - -namespace android { - -class VsyncCallback { - public: - virtual ~VsyncCallback() { - } - virtual void Callback(int display, int64_t timestamp) = 0; -}; - -class VSyncWorker : public Worker { - public: - VSyncWorker(); - ~VSyncWorker() override; - - int Init(DrmDevice *drm, int display); - void RegisterCallback(std::shared_ptr callback); - - void VSyncControl(bool enabled); - - protected: - void Routine() override; - - private: - int64_t GetPhasedVSync(int64_t frame_ns, int64_t current); - int SyntheticWaitVBlank(int64_t *timestamp); - - DrmDevice *drm_; - - // shared_ptr since we need to use this outside of the thread lock (to - // actually call the hook) and we don't want the memory freed until we're - // done - std::shared_ptr callback_ = NULL; - - int display_; - std::atomic_bool enabled_; - int64_t last_timestamp_; -}; -} // namespace android - -#endif -- cgit v1.2.3