aboutsummaryrefslogtreecommitdiff
path: root/drm
diff options
context:
space:
mode:
Diffstat (limited to 'drm')
-rw-r--r--drm/DrmAtomicStateManager.cpp191
-rw-r--r--drm/DrmAtomicStateManager.h89
-rw-r--r--drm/DrmConnector.cpp275
-rw-r--r--drm/DrmConnector.h119
-rw-r--r--drm/DrmCrtc.cpp72
-rw-r--r--drm/DrmCrtc.h45
-rw-r--r--drm/DrmDevice.cpp596
-rw-r--r--drm/DrmDevice.h103
-rw-r--r--drm/DrmDisplayPipeline.cpp192
-rw-r--r--drm/DrmDisplayPipeline.h90
-rw-r--r--drm/DrmEncoder.cpp47
-rw-r--r--drm/DrmEncoder.h45
-rw-r--r--drm/DrmEventListener.cpp138
-rw-r--r--drm/DrmFbImporter.cpp155
-rw-r--r--drm/DrmFbImporter.h91
-rw-r--r--drm/DrmGenericImporter.cpp137
-rw-r--r--drm/DrmGenericImporter.h73
-rw-r--r--drm/DrmMode.cpp83
-rw-r--r--drm/DrmMode.h63
-rw-r--r--drm/DrmPlane.cpp355
-rw-r--r--drm/DrmPlane.h66
-rw-r--r--drm/DrmProperty.cpp54
-rw-r--r--drm/DrmProperty.h41
-rw-r--r--drm/DrmUnique.h87
-rw-r--r--drm/ResourceManager.cpp187
-rw-r--r--drm/ResourceManager.h66
-rw-r--r--drm/UEventListener.cpp62
-rw-r--r--drm/UEventListener.h (renamed from drm/DrmEventListener.h)45
-rw-r--r--drm/VSyncWorker.cpp119
-rw-r--r--drm/VSyncWorker.h37
30 files changed, 2052 insertions, 1671 deletions
diff --git a/drm/DrmAtomicStateManager.cpp b/drm/DrmAtomicStateManager.cpp
new file mode 100644
index 0000000..65fb19e
--- /dev/null
+++ b/drm/DrmAtomicStateManager.cpp
@@ -0,0 +1,191 @@
+/*
+ * 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 ATRACE_TAG ATRACE_TAG_GRAPHICS
+#define LOG_TAG "hwc-drm-atomic-state-manager"
+
+#include "DrmAtomicStateManager.h"
+
+#include <drm/drm_mode.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sync/sync.h>
+#include <utils/Trace.h>
+
+#include <array>
+#include <cstdlib>
+#include <ctime>
+#include <sstream>
+#include <vector>
+
+#include "drm/DrmCrtc.h"
+#include "drm/DrmDevice.h"
+#include "drm/DrmPlane.h"
+#include "drm/DrmUnique.h"
+#include "utils/log.h"
+
+namespace android {
+
+// NOLINTNEXTLINE (readability-function-cognitive-complexity): Fixme
+auto DrmAtomicStateManager::CommitFrame(AtomicCommitArgs &args) -> int {
+ ATRACE_CALL();
+
+ if (args.active && *args.active == active_frame_state_.crtc_active_state) {
+ /* Don't set the same state twice */
+ args.active.reset();
+ }
+
+ if (!args.HasInputs()) {
+ /* nothing to do */
+ return 0;
+ }
+
+ if (!active_frame_state_.crtc_active_state) {
+ /* Force activate display */
+ args.active = true;
+ }
+
+ auto new_frame_state = NewFrameState();
+
+ auto *drm = pipe_->device;
+ auto *connector = pipe_->connector->Get();
+ auto *crtc = pipe_->crtc->Get();
+
+ auto pset = MakeDrmModeAtomicReqUnique();
+ if (!pset) {
+ ALOGE("Failed to allocate property set");
+ return -ENOMEM;
+ }
+
+ int64_t out_fence = -1;
+ if (crtc->GetOutFencePtrProperty() &&
+ !crtc->GetOutFencePtrProperty().AtomicSet(*pset, uint64_t(&out_fence))) {
+ return -EINVAL;
+ }
+
+ if (args.active) {
+ new_frame_state.crtc_active_state = *args.active;
+ if (!crtc->GetActiveProperty().AtomicSet(*pset, *args.active ? 1 : 0) ||
+ !connector->GetCrtcIdProperty().AtomicSet(*pset, crtc->GetId())) {
+ return -EINVAL;
+ }
+ }
+
+ if (args.display_mode) {
+ new_frame_state.mode_blob = args.display_mode.value().CreateModeBlob(*drm);
+
+ if (!new_frame_state.mode_blob) {
+ ALOGE("Failed to create mode_blob");
+ return -EINVAL;
+ }
+
+ if (!crtc->GetModeProperty().AtomicSet(*pset, *new_frame_state.mode_blob)) {
+ return -EINVAL;
+ }
+ }
+
+ auto unused_planes = new_frame_state.used_planes;
+
+ if (args.composition) {
+ new_frame_state.used_framebuffers.clear();
+ new_frame_state.used_planes.clear();
+
+ for (auto &joining : args.composition->plan) {
+ DrmPlane *plane = joining.plane->Get();
+ DrmHwcLayer &layer = joining.layer;
+
+ new_frame_state.used_framebuffers.emplace_back(layer.fb_id_handle);
+ new_frame_state.used_planes.emplace_back(joining.plane);
+
+ /* Remove from 'unused' list, since plane is re-used */
+ auto &v = unused_planes;
+ v.erase(std::remove(v.begin(), v.end(), joining.plane), v.end());
+
+ if (plane->AtomicSetState(*pset, layer, joining.z_pos, crtc->GetId()) !=
+ 0) {
+ return -EINVAL;
+ }
+ }
+ }
+
+ if (args.composition) {
+ for (auto &plane : unused_planes) {
+ if (plane->Get()->AtomicDisablePlane(*pset) != 0) {
+ return -EINVAL;
+ }
+ }
+ }
+
+ uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
+ if (args.test_only)
+ flags |= DRM_MODE_ATOMIC_TEST_ONLY;
+
+ int err = drmModeAtomicCommit(drm->GetFd(), pset.get(), flags, drm);
+ if (err != 0) {
+ if (!args.test_only)
+ ALOGE("Failed to commit pset ret=%d\n", err);
+ return err;
+ }
+
+ if (!args.test_only) {
+ if (args.display_mode) {
+ /* TODO(nobody): we still need this for synthetic vsync, remove after
+ * vsync reworked */
+ connector->SetActiveMode(*args.display_mode);
+ }
+
+ active_frame_state_ = std::move(new_frame_state);
+
+ if (crtc->GetOutFencePtrProperty()) {
+ args.out_fence = UniqueFd((int)out_fence);
+ }
+ }
+
+ return 0;
+}
+
+auto DrmAtomicStateManager::ExecuteAtomicCommit(AtomicCommitArgs &args) -> int {
+ int err = CommitFrame(args);
+
+ if (!args.test_only) {
+ if (err != 0) {
+ ALOGE("Composite failed for pipeline %s",
+ pipe_->connector->Get()->GetName().c_str());
+ // Disable the hw used by the last active composition. This allows us to
+ // signal the release fences from that composition to avoid hanging.
+ AtomicCommitArgs cl_args{};
+ cl_args.composition = std::make_shared<DrmKmsPlan>();
+ if (CommitFrame(cl_args) != 0) {
+ ALOGE("Failed to clean-up active composition for pipeline %s",
+ pipe_->connector->Get()->GetName().c_str());
+ }
+ return err;
+ }
+ }
+
+ return err;
+} // namespace android
+
+auto DrmAtomicStateManager::ActivateDisplayUsingDPMS() -> int {
+ return drmModeConnectorSetProperty(pipe_->device->GetFd(),
+ pipe_->connector->Get()->GetId(),
+ pipe_->connector->Get()
+ ->GetDpmsProperty()
+ .id(),
+ DRM_MODE_DPMS_ON);
+}
+
+} // namespace android
diff --git a/drm/DrmAtomicStateManager.h b/drm/DrmAtomicStateManager.h
new file mode 100644
index 0000000..08a1c13
--- /dev/null
+++ b/drm/DrmAtomicStateManager.h
@@ -0,0 +1,89 @@
+/*
+ * 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_ATOMIC_STATE_MANAGER_H_
+#define ANDROID_DRM_ATOMIC_STATE_MANAGER_H_
+
+#include <pthread.h>
+
+#include <functional>
+#include <memory>
+#include <optional>
+#include <sstream>
+#include <tuple>
+
+#include "compositor/DrmKmsPlan.h"
+#include "drm/DrmPlane.h"
+#include "drm/ResourceManager.h"
+#include "drm/VSyncWorker.h"
+#include "drmhwcomposer.h"
+
+namespace android {
+
+struct AtomicCommitArgs {
+ /* inputs. All fields are optional, but at least one has to be specified */
+ bool test_only = false;
+ std::optional<DrmMode> display_mode;
+ std::optional<bool> active;
+ std::shared_ptr<DrmKmsPlan> composition;
+
+ /* out */
+ UniqueFd out_fence;
+
+ /* helpers */
+ auto HasInputs() -> bool {
+ return display_mode || active || composition;
+ }
+};
+
+class DrmAtomicStateManager {
+ public:
+ explicit DrmAtomicStateManager(DrmDisplayPipeline *pipe) : pipe_(pipe){};
+ DrmAtomicStateManager(const DrmAtomicStateManager &) = delete;
+ ~DrmAtomicStateManager() = default;
+
+ auto ExecuteAtomicCommit(AtomicCommitArgs &args) -> int;
+ auto ActivateDisplayUsingDPMS() -> int;
+
+ private:
+ auto CommitFrame(AtomicCommitArgs &args) -> int;
+
+ struct KmsState {
+ /* Required to cleanup unused planes */
+ std::vector<std::shared_ptr<BindingOwner<DrmPlane>>> used_planes;
+ /* We have to hold a reference to framebuffer while displaying it ,
+ * otherwise picture will blink */
+ std::vector<std::shared_ptr<DrmFbIdHandle>> used_framebuffers;
+
+ DrmModeUserPropertyBlobUnique mode_blob;
+
+ /* To avoid setting the inactive state twice, which will fail the commit */
+ bool crtc_active_state{};
+ } active_frame_state_;
+
+ auto NewFrameState() -> KmsState {
+ return (KmsState){
+ .used_planes = active_frame_state_.used_planes,
+ .used_framebuffers = active_frame_state_.used_framebuffers,
+ .crtc_active_state = active_frame_state_.crtc_active_state,
+ };
+ }
+
+ DrmDisplayPipeline *const pipe_;
+};
+} // namespace android
+
+#endif // ANDROID_DRM_DISPLAY_COMPOSITOR_H_
diff --git a/drm/DrmConnector.cpp b/drm/DrmConnector.cpp
index f1b6c1b..4737316 100644
--- a/drm/DrmConnector.cpp
+++ b/drm/DrmConnector.cpp
@@ -18,237 +18,174 @@
#include "DrmConnector.h"
-#include <errno.h>
-#include <log/log.h>
-#include <stdint.h>
#include <xf86drmMode.h>
#include <array>
+#include <cerrno>
+#include <cstdint>
#include <sstream>
#include "DrmDevice.h"
+#include "utils/log.h"
+
+#ifndef DRM_MODE_CONNECTOR_SPI
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
+#define DRM_MODE_CONNECTOR_SPI 19
+#endif
+
+#ifndef DRM_MODE_CONNECTOR_USB
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
+#define DRM_MODE_CONNECTOR_USB 20
+#endif
namespace android {
-constexpr size_t TYPES_COUNT = 17;
-
-DrmConnector::DrmConnector(DrmDevice *drm, drmModeConnectorPtr c,
- DrmEncoder *current_encoder,
- std::vector<DrmEncoder *> &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) {
+constexpr size_t kTypesCount = 21;
+
+static bool GetOptionalConnectorProperty(const DrmDevice &dev,
+ const DrmConnector &connector,
+ const char *prop_name,
+ DrmProperty *property) {
+ return dev.GetProperty(connector.GetId(), DRM_MODE_OBJECT_CONNECTOR,
+ prop_name, property) == 0;
}
-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;
+static bool GetConnectorProperty(const DrmDevice &dev,
+ const DrmConnector &connector,
+ const char *prop_name, DrmProperty *property) {
+ if (!GetOptionalConnectorProperty(dev, connector, prop_name, property)) {
+ ALOGE("Could not get %s property\n", prop_name);
+ return false;
}
- ret = UpdateEdidProperty();
- 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;
+ return true;
}
-int DrmConnector::UpdateEdidProperty() {
- int ret = drm_->GetConnectorProperty(*this, "EDID", &edid_property_);
- if (ret) {
- ALOGW("Could not get EDID property\n");
+auto DrmConnector::CreateInstance(DrmDevice &dev, uint32_t connector_id,
+ uint32_t index)
+ -> std::unique_ptr<DrmConnector> {
+ auto conn = MakeDrmModeConnectorUnique(dev.GetFd(), connector_id);
+ if (!conn) {
+ ALOGE("Failed to get connector %d", connector_id);
+ return {};
}
- return ret;
-}
-int DrmConnector::GetEdidBlob(drmModePropertyBlobPtr &blob) {
- uint64_t blob_id;
- int ret = UpdateEdidProperty();
- if (ret) {
- return ret;
+ auto c = std::unique_ptr<DrmConnector>(
+ new DrmConnector(std::move(conn), &dev, index));
+
+ if (!GetConnectorProperty(dev, *c, "DPMS", &c->dpms_property_) ||
+ !GetConnectorProperty(dev, *c, "CRTC_ID", &c->crtc_id_property_)) {
+ return {};
}
- std::tie(ret, blob_id) = edid_property().value();
- if (ret) {
- return ret;
+ c->UpdateEdidProperty();
+
+ if (c->IsWriteback() &&
+ (!GetConnectorProperty(dev, *c, "WRITEBACK_PIXEL_FORMATS",
+ &c->writeback_pixel_formats_) ||
+ !GetConnectorProperty(dev, *c, "WRITEBACK_FB_ID",
+ &c->writeback_fb_id_) ||
+ !GetConnectorProperty(dev, *c, "WRITEBACK_OUT_FENCE_PTR",
+ &c->writeback_out_fence_))) {
+ return {};
}
- blob = drmModeGetPropertyBlob(drm_->fd(), blob_id);
- return !blob;
+ return c;
}
-uint32_t DrmConnector::id() const {
- return id_;
+int DrmConnector::UpdateEdidProperty() {
+ return GetOptionalConnectorProperty(*drm_, *this, "EDID", &edid_property_)
+ ? 0
+ : -EINVAL;
}
-int DrmConnector::display() const {
- return display_;
-}
+auto DrmConnector::GetEdidBlob() -> DrmModePropertyBlobUnique {
+ uint64_t blob_id = 0;
+ int ret = UpdateEdidProperty();
+ if (ret != 0) {
+ return {};
+ }
-void DrmConnector::set_display(int display) {
- display_ = display;
+ std::tie(ret, blob_id) = GetEdidProperty().value();
+ if (ret != 0) {
+ return {};
+ }
+
+ return MakeDrmModePropertyBlobUnique(drm_->GetFd(), blob_id);
}
-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::IsInternal() const {
+ auto type = connector_->connector_type;
+ 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 || type == DRM_MODE_CONNECTOR_SPI;
}
-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::IsExternal() const {
+ auto type = connector_->connector_type;
+ 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 || type == DRM_MODE_CONNECTOR_USB;
}
-bool DrmConnector::writeback() const {
+bool DrmConnector::IsWriteback() const {
#ifdef DRM_MODE_CONNECTOR_WRITEBACK
- return type_ == DRM_MODE_CONNECTOR_WRITEBACK;
+ return connector_->connector_type == DRM_MODE_CONNECTOR_WRITEBACK;
#else
return false;
#endif
}
-bool DrmConnector::valid_type() const {
- return internal() || external() || writeback();
+bool DrmConnector::IsValid() const {
+ return IsInternal() || IsExternal() || IsWriteback();
}
-std::string DrmConnector::name() const {
- constexpr std::array<const char *, TYPES_COUNT> names =
- {"None", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite",
- "SVIDEO", "LVDS", "Component", "DIN", "DP", "HDMI-A",
- "HDMI-B", "TV", "eDP", "Virtual", "DSI"};
+std::string DrmConnector::GetName() const {
+ constexpr std::array<const char *, kTypesCount> kNames =
+ {"None", "VGA", "DVI-I", "DVI-D", "DVI-A", "Composite",
+ "SVIDEO", "LVDS", "Component", "DIN", "DP", "HDMI-A",
+ "HDMI-B", "TV", "eDP", "Virtual", "DSI", "DPI",
+ "Writeback", "SPI", "USB"};
- if (type_ < TYPES_COUNT) {
+ if (connector_->connector_type < kTypesCount) {
std::ostringstream name_buf;
- name_buf << names[type_] << "-" << type_id_;
+ name_buf << kNames[connector_->connector_type] << "-"
+ << connector_->connector_type_id;
return name_buf.str();
- } else {
- ALOGE("Unknown type in connector %d, could not make his name", id_);
- return "None";
}
+
+ ALOGE("Unknown type in connector %d, could not make his name", GetId());
+ return "None";
}
int DrmConnector::UpdateModes() {
- int fd = drm_->fd();
-
- drmModeConnectorPtr c = drmModeGetConnector(fd, id_);
- if (!c) {
- ALOGE("Failed to get connector %d", id_);
+ auto conn = MakeDrmModeConnectorUnique(drm_->GetFd(), GetId());
+ if (!conn) {
+ ALOGE("Failed to get connector %d", GetId());
return -ENODEV;
}
+ connector_ = std::move(conn);
- state_ = c->connection;
-
- bool preferred_mode_found = false;
- std::vector<DrmMode> new_modes;
- for (int i = 0; i < c->count_modes; ++i) {
+ modes_.clear();
+ for (int i = 0; i < connector_->count_modes; ++i) {
bool exists = false;
for (const DrmMode &mode : modes_) {
- if (mode == c->modes[i]) {
- new_modes.push_back(mode);
+ if (mode == connector_->modes[i]) {
exists = true;
break;
}
}
+
if (!exists) {
- DrmMode m(&c->modes[i]);
- m.set_id(drm_->next_mode_id());
- new_modes.push_back(m);
+ modes_.emplace_back(DrmMode(&connector_->modes[i]));
}
- // 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_;
+ return 0;
}
-void DrmConnector::set_active_mode(const DrmMode &mode) {
+void DrmConnector::SetActiveMode(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
index 8533af8..629b3cc 100644
--- a/drm/DrmConnector.h
+++ b/drm/DrmConnector.h
@@ -17,87 +17,112 @@
#ifndef ANDROID_DRM_CONNECTOR_H_
#define ANDROID_DRM_CONNECTOR_H_
-#include <stdint.h>
#include <xf86drmMode.h>
+#include <cstdint>
#include <string>
#include <vector>
#include "DrmEncoder.h"
#include "DrmMode.h"
#include "DrmProperty.h"
+#include "DrmUnique.h"
namespace android {
class DrmDevice;
-class DrmConnector {
+class DrmConnector : public PipelineBindable<DrmConnector> {
public:
- DrmConnector(DrmDevice *drm, drmModeConnectorPtr c,
- DrmEncoder *current_encoder,
- std::vector<DrmEncoder *> &possible_encoders);
+ static auto CreateInstance(DrmDevice &dev, uint32_t connector_id,
+ uint32_t index) -> std::unique_ptr<DrmConnector>;
+
DrmConnector(const DrmProperty &) = delete;
DrmConnector &operator=(const DrmProperty &) = delete;
- int Init();
int UpdateEdidProperty();
- int GetEdidBlob(drmModePropertyBlobPtr &blob);
+ auto GetEdidBlob() -> DrmModePropertyBlobUnique;
+
+ auto GetDev() const -> DrmDevice & {
+ return *drm_;
+ }
- uint32_t id() const;
+ auto GetId() const {
+ return connector_->connector_id;
+ }
- int display() const;
- void set_display(int display);
+ auto GetIndexInResArray() const {
+ return index_in_res_array_;
+ }
- bool internal() const;
- bool external() const;
- bool writeback() const;
- bool valid_type() const;
+ auto GetCurrentEncoderId() const {
+ return connector_->encoder_id;
+ }
- std::string name() const;
+ auto SupportsEncoder(DrmEncoder &enc) const {
+ for (int i = 0; i < connector_->count_encoders; i++) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ if (connector_->encoders[i] == enc.GetId()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool IsInternal() const;
+ bool IsExternal() const;
+ bool IsWriteback() const;
+ bool IsValid() const;
+
+ std::string GetName() const;
int UpdateModes();
- const std::vector<DrmMode> &modes() const {
+ auto &GetModes() 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<DrmEncoder *> &possible_encoders() const {
- return possible_encoders_;
+
+ auto &GetActiveMode() const {
+ return active_mode_;
+ }
+
+ void SetActiveMode(DrmMode &mode);
+
+ auto &GetDpmsProperty() const {
+ return dpms_property_;
}
- DrmEncoder *encoder() const;
- void set_encoder(DrmEncoder *encoder);
- drmModeConnection state() const;
+ auto &GetCrtcIdProperty() const {
+ return crtc_id_property_;
+ }
- uint32_t mm_width() const;
- uint32_t mm_height() const;
+ auto &GetEdidProperty() const {
+ return edid_property_;
+ }
- uint32_t get_preferred_mode_id() const {
- return preferred_mode_id_;
+ auto IsConnected() const {
+ return connector_->connection == DRM_MODE_CONNECTED;
}
- private:
- DrmDevice *drm_;
+ auto GetMmWidth() const {
+ return connector_->mmWidth;
+ }
+
+ auto GetMmHeight() const {
+ return connector_->mmHeight;
+ };
- uint32_t id_;
- DrmEncoder *encoder_;
- int display_;
+ private:
+ DrmConnector(DrmModeConnectorUnique connector, DrmDevice *drm, uint32_t index)
+ : connector_(std::move(connector)),
+ drm_(drm),
+ index_in_res_array_(index){};
- uint32_t type_;
- uint32_t type_id_;
- drmModeConnection state_;
+ DrmModeConnectorUnique connector_;
+ DrmDevice *const drm_;
- uint32_t mm_width_;
- uint32_t mm_height_;
+ const uint32_t index_in_res_array_;
DrmMode active_mode_;
std::vector<DrmMode> modes_;
@@ -108,10 +133,6 @@ class DrmConnector {
DrmProperty writeback_pixel_formats_;
DrmProperty writeback_fb_id_;
DrmProperty writeback_out_fence_;
-
- std::vector<DrmEncoder *> possible_encoders_;
-
- uint32_t preferred_mode_id_;
};
} // namespace android
diff --git a/drm/DrmCrtc.cpp b/drm/DrmCrtc.cpp
index 4ce8cfc..b54f14b 100644
--- a/drm/DrmCrtc.cpp
+++ b/drm/DrmCrtc.cpp
@@ -18,68 +18,50 @@
#include "DrmCrtc.h"
-#include <log/log.h>
-#include <stdint.h>
+#include <utils/log.h>
#include <xf86drmMode.h>
+#include <cstdint>
+
#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) {
+static int GetCrtcProperty(const DrmDevice &dev, const DrmCrtc &crtc,
+ const char *prop_name, DrmProperty *property) {
+ return dev.GetProperty(crtc.GetId(), DRM_MODE_OBJECT_CRTC, prop_name,
+ property);
}
-int DrmCrtc::Init() {
- int ret = drm_->GetCrtcProperty(*this, "ACTIVE", &active_property_);
- if (ret) {
+auto DrmCrtc::CreateInstance(DrmDevice &dev, uint32_t crtc_id, uint32_t index)
+ -> std::unique_ptr<DrmCrtc> {
+ auto crtc = MakeDrmModeCrtcUnique(dev.GetFd(), crtc_id);
+ if (!crtc) {
+ ALOGE("Failed to get CRTC %d", crtc_id);
+ return {};
+ }
+
+ auto c = std::unique_ptr<DrmCrtc>(new DrmCrtc(std::move(crtc), index));
+
+ int ret = GetCrtcProperty(dev, *c, "ACTIVE", &c->active_property_);
+ if (ret != 0) {
ALOGE("Failed to get ACTIVE property");
- return ret;
+ return {};
}
- ret = drm_->GetCrtcProperty(*this, "MODE_ID", &mode_property_);
- if (ret) {
+ ret = GetCrtcProperty(dev, *c, "MODE_ID", &c->mode_property_);
+ if (ret != 0) {
ALOGE("Failed to get MODE_ID property");
- return ret;
+ return {};
}
- ret = drm_->GetCrtcProperty(*this, "OUT_FENCE_PTR", &out_fence_ptr_property_);
- if (ret) {
+ ret = GetCrtcProperty(dev, *c, "OUT_FENCE_PTR", &c->out_fence_ptr_property_);
+ if (ret != 0) {
ALOGE("Failed to get OUT_FENCE_PTR property");
- return ret;
+ return {};
}
- return 0;
-}
-
-uint32_t DrmCrtc::id() const {
- return id_;
-}
-
-unsigned DrmCrtc::pipe() const {
- return pipe_;
-}
-int DrmCrtc::display() const {
- return display_;
+ return c;
}
-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
index 7972bef..ebf0a97 100644
--- a/drm/DrmCrtc.h
+++ b/drm/DrmCrtc.h
@@ -17,44 +17,55 @@
#ifndef ANDROID_DRM_CRTC_H_
#define ANDROID_DRM_CRTC_H_
-#include <stdint.h>
#include <xf86drmMode.h>
+#include <cstdint>
+
+#include "DrmDisplayPipeline.h"
#include "DrmMode.h"
#include "DrmProperty.h"
+#include "DrmUnique.h"
namespace android {
class DrmDevice;
-class DrmCrtc {
+class DrmCrtc : public PipelineBindable<DrmCrtc> {
public:
- DrmCrtc(DrmDevice *drm, drmModeCrtcPtr c, unsigned pipe);
+ static auto CreateInstance(DrmDevice &dev, uint32_t crtc_id, uint32_t index)
+ -> std::unique_ptr<DrmCrtc>;
+
+ DrmCrtc() = delete;
DrmCrtc(const DrmCrtc &) = delete;
DrmCrtc &operator=(const DrmCrtc &) = delete;
- int Init();
+ auto GetId() const {
+ return crtc_->crtc_id;
+ }
- uint32_t id() const;
- unsigned pipe() const;
+ auto GetIndexInResArray() const {
+ return index_in_res_array_;
+ }
- int display() const;
- void set_display(int display);
+ auto &GetActiveProperty() const {
+ return active_property_;
+ }
- bool can_bind(int display) const;
+ auto &GetModeProperty() const {
+ return mode_property_;
+ }
- const DrmProperty &active_property() const;
- const DrmProperty &mode_property() const;
- const DrmProperty &out_fence_ptr_property() const;
+ auto &GetOutFencePtrProperty() const {
+ return out_fence_ptr_property_;
+ }
private:
- DrmDevice *drm_;
+ DrmCrtc(DrmModeCrtcUnique crtc, uint32_t index)
+ : crtc_(std::move(crtc)), index_in_res_array_(index){};
- uint32_t id_;
- unsigned pipe_;
- int display_;
+ DrmModeCrtcUnique crtc_;
- DrmMode mode_;
+ const uint32_t index_in_res_array_;
DrmProperty active_property_;
DrmProperty mode_property_;
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp
index bf1a5e2..fd4589e 100644
--- a/drm/DrmDevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -18,137 +18,70 @@
#include "DrmDevice.h"
-#include <cutils/properties.h>
-#include <errno.h>
#include <fcntl.h>
-#include <log/log.h>
-#include <stdint.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
-#include <algorithm>
-#include <array>
#include <cinttypes>
-#include <sstream>
+#include <cstdint>
#include <string>
-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);
-}
+#include "drm/DrmAtomicStateManager.h"
+#include "drm/DrmPlane.h"
+#include "utils/log.h"
+#include "utils/properties.h"
namespace android {
-static std::vector<std::string> read_primary_display_order_prop() {
- std::array<char, PROPERTY_VALUE_MAX> display_order_buf;
- property_get("vendor.hwc.drm.primary_display_order", display_order_buf.data(),
- "...");
-
- std::vector<std::string> 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<DrmConnector *> make_primary_display_candidates(
- std::vector<std::unique_ptr<DrmConnector>> &connectors) {
- std::vector<DrmConnector *> primary_candidates;
- std::transform(std::begin(connectors), std::end(connectors),
- std::back_inserter(primary_candidates),
- [](std::unique_ptr<DrmConnector> &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<std::string> 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();
+DrmDevice::DrmDevice() {
+ drm_fb_importer_ = std::make_unique<DrmFbImporter>(*this);
}
-std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
+auto DrmDevice::Init(const char *path) -> int {
/* TODO: Use drmOpenControl here instead */
- fd_.Set(open(path, O_RDWR));
- if (fd() < 0) {
+ fd_ = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
+ if (!fd_) {
+ // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme
ALOGE("Failed to open dri %s: %s", path, strerror(errno));
- return std::make_tuple(-ENODEV, 0);
+ return -ENODEV;
}
- int ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
- if (ret) {
+ int ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
+ if (ret != 0) {
ALOGE("Failed to set universal plane cap %d", ret);
- return std::make_tuple(ret, 0);
+ return ret;
}
- ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_ATOMIC, 1);
- if (ret) {
+ ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_ATOMIC, 1);
+ if (ret != 0) {
ALOGE("Failed to set atomic cap %d", ret);
- return std::make_tuple(ret, 0);
+ return ret;
}
#ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
- ret = drmSetClientCap(fd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
- if (ret) {
+ ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
+ if (ret != 0) {
ALOGI("Failed to set writeback cap %d", ret);
- ret = 0;
}
#endif
- drmModeResPtr res = drmModeGetResources(fd());
+ uint64_t cap_value = 0;
+ if (drmGetCap(GetFd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value) != 0) {
+ ALOGW("drmGetCap failed. Fallback to no modifier support.");
+ cap_value = 0;
+ }
+ HasAddFb2ModifiersSupport_ = cap_value != 0;
+
+ drmSetMaster(GetFd());
+ if (drmIsMaster(GetFd()) == 0) {
+ ALOGE("DRM/KMS master access required");
+ return -EACCES;
+ }
+
+ auto res = MakeDrmModeResUnique(GetFd());
if (!res) {
ALOGE("Failed to get DrmDevice resources");
- return std::make_tuple(-ENODEV, 0);
+ return -ENODEV;
}
min_resolution_ = std::pair<uint32_t, uint32_t>(res->min_width,
@@ -156,390 +89,100 @@ std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
max_resolution_ = std::pair<uint32_t, uint32_t>(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;
+ for (int i = 0; i < res->count_crtcs; ++i) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ auto crtc = DrmCrtc::CreateInstance(*this, res->crtcs[i], i);
+ if (crtc) {
+ crtcs_.emplace_back(std::move(crtc));
}
-
- std::unique_ptr<DrmCrtc> 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<int> 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<DrmCrtc *> 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();
+ for (int i = 0; i < res->count_encoders; ++i) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ auto enc = DrmEncoder::CreateInstance(*this, res->encoders[i], i);
+ if (enc) {
+ encoders_.emplace_back(std::move(enc));
}
-
- std::unique_ptr<DrmEncoder> 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<DrmEncoder *> 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();
- }
- }
+ for (int i = 0; i < res->count_connectors; ++i) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ auto conn = DrmConnector::CreateInstance(*this, res->connectors[i], i);
- std::unique_ptr<DrmConnector> 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) {
+ continue;
}
- if (conn->writeback())
+ if (conn->IsWriteback()) {
writeback_connectors_.emplace_back(std::move(conn));
- else
+ } 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<DrmConnector *>
- 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());
+ auto plane_res = MakeDrmModePlaneResUnique(GetFd());
if (!plane_res) {
ALOGE("Failed to get plane resources");
- return std::make_tuple(-ENOENT, 0);
+ return -ENOENT;
}
for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
- 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<DrmPlane> plane(new DrmPlane(this, p));
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ auto plane = DrmPlane::CreateInstance(*this, plane_res->planes[i]);
- drmModeFreePlane(p);
-
- ret = plane->Init();
- if (ret) {
- ALOGE("Init plane %d failed", plane_res->planes[i]);
- break;
+ if (plane) {
+ planes_.emplace_back(std::move(plane));
}
-
- 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<std::unique_ptr<DrmCrtc>> &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;
+ return 0;
}
-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));
+auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
+ -> DrmModeUserPropertyBlobUnique {
+ struct drm_mode_create_blob create_blob {};
create_blob.length = length;
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
create_blob.data = (__u64)data;
- int ret = drmIoctl(fd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
- if (ret) {
+ int ret = drmIoctl(GetFd(), DRM_IOCTL_MODE_CREATEPROPBLOB, &create_blob);
+ if (ret != 0) {
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_;
+ return {};
+ }
+
+ return DrmModeUserPropertyBlobUnique(
+ new uint32_t(create_blob.blob_id), [this](const uint32_t *it) {
+ struct drm_mode_destroy_blob destroy_blob {};
+ destroy_blob.blob_id = (__u32)*it;
+ int err = drmIoctl(GetFd(), DRM_IOCTL_MODE_DESTROYPROPBLOB,
+ &destroy_blob);
+ if (err != 0) {
+ ALOGE("Failed to destroy mode property blob %" PRIu32 "/%d", *it,
+ err);
+ }
+ // NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
+ delete it;
+ });
}
int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
- const char *prop_name, DrmProperty *property) {
- drmModeObjectPropertiesPtr props;
+ const char *prop_name, DrmProperty *property) const {
+ drmModeObjectPropertiesPtr props = nullptr;
- props = drmModeObjectGetProperties(fd(), obj_id, obj_type);
- if (!props) {
+ props = drmModeObjectGetProperties(GetFd(), obj_id, obj_type);
+ if (props == nullptr) {
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]);
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ drmModePropertyPtr p = drmModeGetProperty(GetFd(), props->props[i]);
+ if (strcmp(p->name, prop_name) == 0) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ property->Init(obj_id, p, props->prop_values[i]);
found = true;
}
drmModeFreeProperty(p);
@@ -549,32 +192,51 @@ int DrmDevice::GetProperty(uint32_t obj_id, uint32_t obj_type,
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);
+std::string DrmDevice::GetName() const {
+ auto *ver = drmGetVersion(GetFd());
+ if (ver == nullptr) {
+ ALOGW("Failed to get drm version for fd=%d", GetFd());
+ return "generic";
+ }
+
+ std::string name(ver->name);
+ drmFreeVersion(ver);
+ return name;
+}
+
+auto DrmDevice::IsKMSDev(const char *path) -> bool {
+ auto fd = UniqueFd(open(path, O_RDWR | O_CLOEXEC));
+ if (!fd) {
+ return false;
+ }
+
+ auto res = MakeDrmModeResUnique(fd.Get());
+ if (!res) {
+ return false;
+ }
+
+ bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 &&
+ res->count_encoders > 0;
+
+ return is_kms;
}
-int DrmDevice::GetCrtcProperty(const DrmCrtc &crtc, const char *prop_name,
- DrmProperty *property) {
- return GetProperty(crtc.id(), DRM_MODE_OBJECT_CRTC, prop_name, property);
+auto DrmDevice::GetConnectors()
+ -> const std::vector<std::unique_ptr<DrmConnector>> & {
+ return connectors_;
}
-int DrmDevice::GetConnectorProperty(const DrmConnector &connector,
- const char *prop_name,
- DrmProperty *property) {
- return GetProperty(connector.id(), DRM_MODE_OBJECT_CONNECTOR, prop_name,
- property);
+auto DrmDevice::GetPlanes() -> const std::vector<std::unique_ptr<DrmPlane>> & {
+ return planes_;
}
-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";
- }
+auto DrmDevice::GetCrtcs() -> const std::vector<std::unique_ptr<DrmCrtc>> & {
+ return crtcs_;
+}
- std::string name(ver->name);
- drmFreeVersion(ver);
- return name;
+auto DrmDevice::GetEncoders()
+ -> const std::vector<std::unique_ptr<DrmEncoder>> & {
+ return encoders_;
}
+
} // namespace android
diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h
index be68aa6..f2530ee 100644
--- a/drm/DrmDevice.h
+++ b/drm/DrmDevice.h
@@ -17,93 +17,98 @@
#ifndef ANDROID_DRM_H_
#define ANDROID_DRM_H_
-#include <stdint.h>
-
+#include <cstdint>
#include <map>
#include <tuple>
#include "DrmConnector.h"
#include "DrmCrtc.h"
#include "DrmEncoder.h"
-#include "DrmEventListener.h"
-#include "DrmPlane.h"
+#include "DrmFbImporter.h"
+#include "utils/UniqueFd.h"
namespace android {
+class DrmFbImporter;
+class DrmPlane;
+
class DrmDevice {
public:
DrmDevice();
- ~DrmDevice();
+ ~DrmDevice() = default;
- std::tuple<int, int> Init(const char *path, int num_displays);
+ auto Init(const char *path) -> int;
- int fd() const {
- return fd_.get();
+ auto GetFd() const {
+ return fd_.Get();
}
- const std::vector<std::unique_ptr<DrmConnector>> &connectors() const {
- return connectors_;
+ auto GetConnectors() -> const std::vector<std::unique_ptr<DrmConnector>> &;
+ auto GetPlanes() -> const std::vector<std::unique_ptr<DrmPlane>> &;
+ auto GetCrtcs() -> const std::vector<std::unique_ptr<DrmCrtc>> &;
+ auto GetEncoders() -> const std::vector<std::unique_ptr<DrmEncoder>> &;
+
+ auto GetMinResolution() const {
+ return min_resolution_;
}
- const std::vector<std::unique_ptr<DrmPlane>> &planes() const {
- return planes_;
+ auto GetMaxResolution() const {
+ return max_resolution_;
}
- std::pair<uint32_t, uint32_t> min_resolution() const {
- return min_resolution_;
+ std::string GetName() const;
+
+ auto RegisterUserPropertyBlob(void *data, size_t length) const
+ -> DrmModeUserPropertyBlobUnique;
+
+ auto HasAddFb2ModifiersSupport() const {
+ return HasAddFb2ModifiersSupport_;
}
- std::pair<uint32_t, uint32_t> max_resolution() const {
- return max_resolution_;
+ auto &GetDrmFbImporter() {
+ return *drm_fb_importer_;
}
- 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<std::unique_ptr<DrmCrtc>> &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);
+ static auto IsKMSDev(const char *path) -> bool;
+
+ auto FindCrtcById(uint32_t id) const -> DrmCrtc * {
+ for (const auto &crtc : crtcs_) {
+ if (crtc->GetId() == id) {
+ return crtc.get();
+ }
+ };
+
+ return nullptr;
}
- private:
- int TryEncoderForDisplay(int display, DrmEncoder *enc);
- int GetProperty(uint32_t obj_id, uint32_t obj_type, const char *prop_name,
- DrmProperty *property);
+ auto FindEncoderById(uint32_t id) const -> DrmEncoder * {
+ for (const auto &enc : encoders_) {
+ if (enc->GetId() == id) {
+ return enc.get();
+ }
+ };
- int CreateDisplayPipe(DrmConnector *connector);
- int AttachWriteback(DrmConnector *display_conn);
+ return nullptr;
+ }
+ int GetProperty(uint32_t obj_id, uint32_t obj_type, const char *prop_name,
+ DrmProperty *property) const;
+
+ private:
UniqueFd fd_;
- uint32_t mode_id_ = 0;
std::vector<std::unique_ptr<DrmConnector>> connectors_;
std::vector<std::unique_ptr<DrmConnector>> writeback_connectors_;
std::vector<std::unique_ptr<DrmEncoder>> encoders_;
std::vector<std::unique_ptr<DrmCrtc>> crtcs_;
std::vector<std::unique_ptr<DrmPlane>> planes_;
- DrmEventListener event_listener_;
std::pair<uint32_t, uint32_t> min_resolution_;
std::pair<uint32_t, uint32_t> max_resolution_;
- std::map<int, int> displays_;
+
+ bool HasAddFb2ModifiersSupport_{};
+
+ std::unique_ptr<DrmFbImporter> drm_fb_importer_;
};
} // namespace android
diff --git a/drm/DrmDisplayPipeline.cpp b/drm/DrmDisplayPipeline.cpp
new file mode 100644
index 0000000..f993d28
--- /dev/null
+++ b/drm/DrmDisplayPipeline.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2022 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-display-pipeline"
+
+#include "DrmDisplayPipeline.h"
+
+#include "DrmAtomicStateManager.h"
+#include "DrmConnector.h"
+#include "DrmCrtc.h"
+#include "DrmDevice.h"
+#include "DrmEncoder.h"
+#include "DrmPlane.h"
+#include "utils/log.h"
+#include "utils/properties.h"
+
+namespace android {
+
+template <class O>
+auto PipelineBindable<O>::BindPipeline(DrmDisplayPipeline *pipeline,
+ bool return_object_if_bound)
+ -> std::shared_ptr<BindingOwner<O>> {
+ auto owner_object = owner_object_.lock();
+ if (owner_object) {
+ if (bound_pipeline_ == pipeline && return_object_if_bound) {
+ return owner_object;
+ }
+
+ return {};
+ }
+ owner_object = std::make_shared<BindingOwner<O>>(static_cast<O *>(this));
+
+ owner_object_ = owner_object;
+ bound_pipeline_ = pipeline;
+ return owner_object;
+}
+
+static auto TryCreatePipeline(DrmDevice &dev, DrmConnector &connector,
+ DrmEncoder &enc, DrmCrtc &crtc)
+ -> std::unique_ptr<DrmDisplayPipeline> {
+ /* Check if resources are available */
+
+ auto pipe = std::make_unique<DrmDisplayPipeline>();
+ pipe->device = &dev;
+
+ pipe->connector = connector.BindPipeline(pipe.get());
+ pipe->encoder = enc.BindPipeline(pipe.get());
+ pipe->crtc = crtc.BindPipeline(pipe.get());
+
+ if (!pipe->connector || !pipe->encoder || !pipe->crtc) {
+ return {};
+ }
+
+ std::vector<DrmPlane *> primary_planes;
+ std::vector<DrmPlane *> overlay_planes;
+
+ /* Attach necessary resources */
+ auto display_planes = std::vector<DrmPlane *>();
+ for (const auto &plane : dev.GetPlanes()) {
+ if (plane->IsCrtcSupported(crtc)) {
+ if (plane->GetType() == DRM_PLANE_TYPE_PRIMARY) {
+ primary_planes.emplace_back(plane.get());
+ } else if (plane->GetType() == DRM_PLANE_TYPE_OVERLAY) {
+ overlay_planes.emplace_back(plane.get());
+ } else {
+ ALOGI("Ignoring cursor plane %d", plane->GetId());
+ }
+ }
+ }
+
+ if (primary_planes.empty()) {
+ ALOGE("Primary plane for CRTC %d not found", crtc.GetId());
+ return {};
+ }
+
+ if (primary_planes.size() > 1) {
+ ALOGE("Found more than 1 primary plane for CRTC %d", crtc.GetId());
+ return {};
+ }
+
+ pipe->primary_plane = primary_planes[0]->BindPipeline(pipe.get());
+ if (!pipe->primary_plane) {
+ ALOGE("Primary plane %d is already owned. Internal error.",
+ primary_planes[0]->GetId());
+ return {};
+ }
+
+ pipe->atomic_state_manager = std::make_unique<DrmAtomicStateManager>(
+ pipe.get());
+
+ return pipe;
+}
+
+static auto TryCreatePipelineUsingEncoder(DrmDevice &dev, DrmConnector &conn,
+ DrmEncoder &enc)
+ -> std::unique_ptr<DrmDisplayPipeline> {
+ /* First try to use the currently-bound crtc */
+ auto *crtc = dev.FindCrtcById(enc.GetCurrentCrtcId());
+ if (crtc != nullptr) {
+ auto pipeline = TryCreatePipeline(dev, conn, enc, *crtc);
+ if (pipeline) {
+ return pipeline;
+ }
+ }
+
+ /* Try to find a possible crtc which will work */
+ for (const auto &crtc : dev.GetCrtcs()) {
+ if (enc.SupportsCrtc(*crtc)) {
+ auto pipeline = TryCreatePipeline(dev, conn, enc, *crtc);
+ if (pipeline) {
+ return pipeline;
+ }
+ }
+ }
+
+ /* We can't use this encoder, but nothing went wrong, try another one */
+ return {};
+}
+
+auto DrmDisplayPipeline::CreatePipeline(DrmConnector &connector)
+ -> std::unique_ptr<DrmDisplayPipeline> {
+ auto &dev = connector.GetDev();
+ /* Try to use current setup first */
+ auto *encoder = dev.FindEncoderById(connector.GetCurrentEncoderId());
+
+ if (encoder != nullptr) {
+ auto pipeline = TryCreatePipelineUsingEncoder(dev, connector, *encoder);
+ if (pipeline) {
+ return pipeline;
+ }
+ }
+
+ for (const auto &enc : dev.GetEncoders()) {
+ if (connector.SupportsEncoder(*enc)) {
+ auto pipeline = TryCreatePipelineUsingEncoder(dev, connector, *enc);
+ if (pipeline) {
+ return pipeline;
+ }
+ }
+ }
+
+ ALOGE("Could not find a suitable encoder/crtc for connector %s",
+ connector.GetName().c_str());
+
+ return {};
+}
+
+static bool ReadUseOverlayProperty() {
+ char use_overlay_planes_prop[PROPERTY_VALUE_MAX];
+ property_get("vendor.hwc.drm.use_overlay_planes", use_overlay_planes_prop,
+ "1");
+ constexpr int kStrtolBase = 10;
+ return strtol(use_overlay_planes_prop, nullptr, kStrtolBase) != 0;
+}
+
+auto DrmDisplayPipeline::GetUsablePlanes()
+ -> std::vector<std::shared_ptr<BindingOwner<DrmPlane>>> {
+ std::vector<std::shared_ptr<BindingOwner<DrmPlane>>> planes;
+ planes.emplace_back(primary_plane);
+
+ static bool use_overlay_planes = ReadUseOverlayProperty();
+
+ if (use_overlay_planes) {
+ for (const auto &plane : device->GetPlanes()) {
+ if (plane->IsCrtcSupported(*crtc->Get())) {
+ if (plane->GetType() == DRM_PLANE_TYPE_OVERLAY) {
+ auto op = plane->BindPipeline(this, true);
+ if (op) {
+ planes.emplace_back(op);
+ }
+ }
+ }
+ }
+ }
+
+ return planes;
+}
+
+} // namespace android
diff --git a/drm/DrmDisplayPipeline.h b/drm/DrmDisplayPipeline.h
new file mode 100644
index 0000000..7ec619e
--- /dev/null
+++ b/drm/DrmDisplayPipeline.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 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_DRMDISPLAYPIPELINE_H_
+#define ANDROID_DRMDISPLAYPIPELINE_H_
+
+#include <memory>
+#include <vector>
+
+namespace android {
+
+class DrmConnector;
+class DrmDevice;
+class DrmPlane;
+class DrmCrtc;
+class DrmEncoder;
+class DrmAtomicStateManager;
+
+struct DrmDisplayPipeline;
+
+template <class O>
+class BindingOwner;
+
+template <class O>
+class PipelineBindable {
+ friend class BindingOwner<O>;
+
+ public:
+ auto *GetPipeline() {
+ return bound_pipeline_;
+ }
+
+ auto BindPipeline(DrmDisplayPipeline *pipeline,
+ bool return_object_if_bound = false)
+ -> std::shared_ptr<BindingOwner<O>>;
+
+ private:
+ DrmDisplayPipeline *bound_pipeline_;
+ std::weak_ptr<BindingOwner<O>> owner_object_;
+};
+
+template <class B>
+class BindingOwner {
+ public:
+ explicit BindingOwner(B *pb) : bindable_(pb){};
+ ~BindingOwner() {
+ bindable_->bound_pipeline_ = nullptr;
+ }
+
+ B *Get() {
+ return bindable_;
+ }
+
+ private:
+ B *const bindable_;
+};
+
+struct DrmDisplayPipeline {
+ static auto CreatePipeline(DrmConnector &connector)
+ -> std::unique_ptr<DrmDisplayPipeline>;
+
+ auto GetUsablePlanes()
+ -> std::vector<std::shared_ptr<BindingOwner<DrmPlane>>>;
+
+ DrmDevice *device;
+
+ std::shared_ptr<BindingOwner<DrmConnector>> connector;
+ std::shared_ptr<BindingOwner<DrmEncoder>> encoder;
+ std::shared_ptr<BindingOwner<DrmCrtc>> crtc;
+ std::shared_ptr<BindingOwner<DrmPlane>> primary_plane;
+
+ std::unique_ptr<DrmAtomicStateManager> atomic_state_manager;
+};
+
+} // namespace android
+
+#endif
diff --git a/drm/DrmEncoder.cpp b/drm/DrmEncoder.cpp
index bcf0926..eed5b5f 100644
--- a/drm/DrmEncoder.cpp
+++ b/drm/DrmEncoder.cpp
@@ -14,49 +14,28 @@
* limitations under the License.
*/
+#define LOG_TAG "hwc-drm-encoder"
+
#include "DrmEncoder.h"
-#include <stdint.h>
#include <xf86drmMode.h>
+#include <cstdint>
+
#include "DrmDevice.h"
+#include "utils/log.h"
namespace android {
-DrmEncoder::DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc,
- const std::vector<DrmCrtc *> &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);
-}
+auto DrmEncoder::CreateInstance(DrmDevice &dev, uint32_t encoder_id,
+ uint32_t index) -> std::unique_ptr<DrmEncoder> {
+ auto e = MakeDrmModeEncoderUnique(dev.GetFd(), encoder_id);
+ if (!e) {
+ ALOGE("Failed to get encoder %d", encoder_id);
+ return {};
+ }
-void DrmEncoder::set_crtc(DrmCrtc *crtc) {
- crtc_ = crtc;
- display_ = crtc->display();
+ return std::unique_ptr<DrmEncoder>(new DrmEncoder(std::move(e), index));
}
-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
index f4464d0..39a695c 100644
--- a/drm/DrmEncoder.h
+++ b/drm/DrmEncoder.h
@@ -17,43 +17,52 @@
#ifndef ANDROID_DRM_ENCODER_H_
#define ANDROID_DRM_ENCODER_H_
-#include <stdint.h>
#include <xf86drmMode.h>
+#include <cstdint>
#include <set>
#include <vector>
#include "DrmCrtc.h"
+#include "DrmDisplayPipeline.h"
namespace android {
-class DrmEncoder {
+class DrmEncoder : public PipelineBindable<DrmEncoder> {
public:
- DrmEncoder(drmModeEncoderPtr e, DrmCrtc *current_crtc,
- const std::vector<DrmCrtc *> &possible_crtcs);
+ static auto CreateInstance(DrmDevice &dev, uint32_t encoder_id,
+ uint32_t index) -> std::unique_ptr<DrmEncoder>;
+
DrmEncoder(const DrmEncoder &) = delete;
DrmEncoder &operator=(const DrmEncoder &) = delete;
- uint32_t id() const;
+ auto GetId() const {
+ return enc_->encoder_id;
+ };
+
+ auto GetIndexInResArray() const {
+ return index_in_res_array_;
+ }
- DrmCrtc *crtc() const;
- void set_crtc(DrmCrtc *crtc);
- bool can_bind(int display) const;
- int display() const;
+ auto CanClone(DrmEncoder &encoder) {
+ return (enc_->possible_clones & (1 << encoder.GetIndexInResArray())) != 0;
+ }
- const std::vector<DrmCrtc *> &possible_crtcs() const {
- return possible_crtcs_;
+ auto SupportsCrtc(DrmCrtc &crtc) {
+ return (enc_->possible_crtcs & (1 << crtc.GetIndexInResArray())) != 0;
+ }
+
+ auto GetCurrentCrtcId() {
+ return enc_->crtc_id;
}
- bool CanClone(DrmEncoder *encoder);
- void AddPossibleClone(DrmEncoder *possible_clone);
private:
- uint32_t id_;
- DrmCrtc *crtc_;
- int display_;
+ DrmEncoder(DrmModeEncoderUnique enc, uint32_t index)
+ : enc_(std::move(enc)), index_in_res_array_(index){};
+
+ DrmModeEncoderUnique enc_;
- std::vector<DrmCrtc *> possible_crtcs_;
- std::set<DrmEncoder *> possible_clones_;
+ const uint32_t index_in_res_array_;
};
} // namespace android
diff --git a/drm/DrmEventListener.cpp b/drm/DrmEventListener.cpp
deleted file mode 100644
index 3d95e28..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 <assert.h>
-#include <errno.h>
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-#include <linux/netlink.h>
-#include <log/log.h>
-#include <sys/socket.h>
-#include <xf86drm.h>
-
-#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/DrmFbImporter.cpp b/drm/DrmFbImporter.cpp
new file mode 100644
index 0000000..eeab076
--- /dev/null
+++ b/drm/DrmFbImporter.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
+#define LOG_TAG "hwc-platform-drm-generic"
+
+#include "DrmFbImporter.h"
+
+#include <hardware/gralloc.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <cinttypes>
+#include <system_error>
+
+#include "utils/log.h"
+#include "utils/properties.h"
+
+namespace android {
+
+auto DrmFbIdHandle::CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
+ DrmDevice &drm)
+ -> std::shared_ptr<DrmFbIdHandle> {
+ // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): priv. constructor usage
+ std::shared_ptr<DrmFbIdHandle> local(new DrmFbIdHandle(drm));
+
+ local->gem_handles_[0] = first_gem_handle;
+ int32_t err = 0;
+
+ /* Framebuffer object creation require gem handle for every used plane */
+ for (size_t i = 1; i < local->gem_handles_.size(); i++) {
+ if (bo->prime_fds[i] > 0) {
+ if (bo->prime_fds[i] != bo->prime_fds[0]) {
+ err = drmPrimeFDToHandle(drm.GetFd(), bo->prime_fds[i],
+ &local->gem_handles_.at(i));
+ if (err != 0) {
+ ALOGE("failed to import prime fd %d errno=%d", bo->prime_fds[i],
+ errno);
+ }
+ } else {
+ local->gem_handles_.at(i) = local->gem_handles_[0];
+ }
+ }
+ }
+
+ bool has_modifiers = bo->modifiers[0] != DRM_FORMAT_MOD_NONE &&
+ bo->modifiers[0] != DRM_FORMAT_MOD_INVALID;
+
+ if (!drm.HasAddFb2ModifiersSupport() && has_modifiers) {
+ ALOGE("No ADDFB2 with modifier support. Can't import modifier %" PRIu64,
+ bo->modifiers[0]);
+ local.reset();
+ return local;
+ }
+
+ /* Create framebuffer object */
+ if (!has_modifiers) {
+ err = drmModeAddFB2(drm.GetFd(), bo->width, bo->height, bo->format,
+ &local->gem_handles_[0], &bo->pitches[0],
+ &bo->offsets[0], &local->fb_id_, 0);
+ } else {
+ err = drmModeAddFB2WithModifiers(drm.GetFd(), bo->width, bo->height,
+ bo->format, &local->gem_handles_[0],
+ &bo->pitches[0], &bo->offsets[0],
+ &bo->modifiers[0], &local->fb_id_,
+ DRM_MODE_FB_MODIFIERS);
+ }
+ if (err != 0) {
+ ALOGE("could not create drm fb %d", err);
+ local.reset();
+ }
+
+ return local;
+}
+
+DrmFbIdHandle::~DrmFbIdHandle() {
+ /* Destroy framebuffer object */
+ if (drmModeRmFB(drm_->GetFd(), fb_id_) != 0) {
+ ALOGE("Failed to rm fb");
+ }
+
+ /* Close GEM handles.
+ *
+ * WARNING: TODO(nobody):
+ * From Linux side libweston relies on libgbm to get KMS handle and never
+ * closes it (handle is closed by libgbm on buffer destruction)
+ * Probably we should offer similar approach to users (at least on user
+ * request via system properties)
+ */
+ struct drm_gem_close gem_close {};
+ for (size_t i = 0; i < gem_handles_.size(); i++) {
+ /* Don't close invalid handle. Close handle only once in cases
+ * where several YUV planes located in the single buffer. */
+ if (gem_handles_[i] == 0 ||
+ (i != 0 && gem_handles_[i] == gem_handles_[0])) {
+ continue;
+ }
+ gem_close.handle = gem_handles_[i];
+ int32_t err = drmIoctl(drm_->GetFd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
+ if (err != 0) {
+ ALOGE("Failed to close gem handle %d, errno: %d", gem_handles_[i], errno);
+ }
+ }
+}
+
+auto DrmFbImporter::GetOrCreateFbId(hwc_drm_bo_t *bo)
+ -> std::shared_ptr<DrmFbIdHandle> {
+ /* Lookup DrmFbIdHandle in cache first. First handle serves as a cache key. */
+ GemHandle first_handle = 0;
+ int32_t err = drmPrimeFDToHandle(drm_->GetFd(), bo->prime_fds[0],
+ &first_handle);
+
+ if (err != 0) {
+ ALOGE("Failed to import prime fd %d ret=%d", bo->prime_fds[0], err);
+ return {};
+ }
+
+ auto drm_fb_id_cached = drm_fb_id_handle_cache_.find(first_handle);
+
+ if (drm_fb_id_cached != drm_fb_id_handle_cache_.end()) {
+ if (auto drm_fb_id_handle_shared = drm_fb_id_cached->second.lock()) {
+ return drm_fb_id_handle_shared;
+ }
+ drm_fb_id_handle_cache_.erase(drm_fb_id_cached);
+ }
+
+ /* Cleanup cached empty weak pointers */
+ const int minimal_cleanup_size = 128;
+ if (drm_fb_id_handle_cache_.size() > minimal_cleanup_size) {
+ CleanupEmptyCacheElements();
+ }
+
+ /* No DrmFbIdHandle found in cache, create framebuffer object */
+ auto fb_id_handle = DrmFbIdHandle::CreateInstance(bo, first_handle, *drm_);
+ if (fb_id_handle) {
+ drm_fb_id_handle_cache_[first_handle] = fb_id_handle;
+ }
+
+ return fb_id_handle;
+}
+
+} // namespace android
diff --git a/drm/DrmFbImporter.h b/drm/DrmFbImporter.h
new file mode 100644
index 0000000..7f17bbe
--- /dev/null
+++ b/drm/DrmFbImporter.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 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 DRM_DRMFBIMPORTER_H_
+#define DRM_DRMFBIMPORTER_H_
+
+#include <drm/drm_fourcc.h>
+#include <hardware/gralloc.h>
+
+#include <array>
+#include <map>
+
+#include "drm/DrmDevice.h"
+#include "drmhwcgralloc.h"
+
+#ifndef DRM_FORMAT_INVALID
+#define DRM_FORMAT_INVALID 0
+#endif
+
+using GemHandle = uint32_t;
+
+namespace android {
+
+class DrmFbIdHandle {
+ public:
+ static auto CreateInstance(hwc_drm_bo_t *bo, GemHandle first_gem_handle,
+ DrmDevice &drm) -> std::shared_ptr<DrmFbIdHandle>;
+
+ ~DrmFbIdHandle();
+ DrmFbIdHandle(DrmFbIdHandle &&) = delete;
+ DrmFbIdHandle(const DrmFbIdHandle &) = delete;
+ auto operator=(const DrmFbIdHandle &) = delete;
+ auto operator=(DrmFbIdHandle &&) = delete;
+
+ auto GetFbId [[nodiscard]] () const -> uint32_t {
+ return fb_id_;
+ }
+
+ private:
+ explicit DrmFbIdHandle(DrmDevice &drm) : drm_(&drm){};
+
+ DrmDevice *const drm_;
+
+ uint32_t fb_id_{};
+ std::array<GemHandle, kHwcDrmBoMaxPlanes> gem_handles_{};
+};
+
+class DrmFbImporter {
+ public:
+ explicit DrmFbImporter(DrmDevice &drm) : drm_(&drm){};
+ ~DrmFbImporter() = default;
+ DrmFbImporter(const DrmFbImporter &) = delete;
+ DrmFbImporter(DrmFbImporter &&) = delete;
+ auto operator=(const DrmFbImporter &) = delete;
+ auto operator=(DrmFbImporter &&) = delete;
+
+ auto GetOrCreateFbId(hwc_drm_bo_t *bo) -> std::shared_ptr<DrmFbIdHandle>;
+
+ private:
+ void CleanupEmptyCacheElements() {
+ for (auto it = drm_fb_id_handle_cache_.begin();
+ it != drm_fb_id_handle_cache_.end();) {
+ if (it->second.expired()) {
+ it = drm_fb_id_handle_cache_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+
+ DrmDevice *const drm_;
+
+ std::map<GemHandle, std::weak_ptr<DrmFbIdHandle>> drm_fb_id_handle_cache_;
+};
+
+} // namespace android
+
+#endif
diff --git a/drm/DrmGenericImporter.cpp b/drm/DrmGenericImporter.cpp
deleted file mode 100644
index 8ab4fe5..0000000
--- a/drm/DrmGenericImporter.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2020 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-platform-drm-generic"
-
-#include "DrmGenericImporter.h"
-
-#include <cutils/properties.h>
-#include <gralloc_handle.h>
-#include <hardware/gralloc.h>
-#include <inttypes.h>
-#include <log/log.h>
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-
-namespace android {
-
-DrmGenericImporter::DrmGenericImporter(DrmDevice *drm) : drm_(drm) {
- uint64_t cap_value = 0;
- if (drmGetCap(drm_->fd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value)) {
- ALOGE("drmGetCap failed. Fallback to no modifier support.");
- cap_value = 0;
- }
- has_modifier_support_ = cap_value;
-}
-
-DrmGenericImporter::~DrmGenericImporter() {
-}
-
-int DrmGenericImporter::ImportBuffer(hwc_drm_bo_t *bo) {
- int ret = drmPrimeFDToHandle(drm_->fd(), bo->prime_fds[0],
- &bo->gem_handles[0]);
- if (ret) {
- ALOGE("failed to import prime fd %d ret=%d", bo->prime_fds[0], ret);
- return ret;
- }
-
- for (int i = 1; i < HWC_DRM_BO_MAX_PLANES; i++) {
- int fd = bo->prime_fds[i];
- if (fd != 0) {
- if (fd != bo->prime_fds[0]) {
- ALOGE("Multiplanar FBs are not supported by this version of composer");
- return -ENOTSUP;
- }
- bo->gem_handles[i] = bo->gem_handles[0];
- }
- }
-
- if (!has_modifier_support_ && bo->modifiers[0]) {
- ALOGE("No ADDFB2 with modifier support. Can't import modifier %" PRIu64,
- bo->modifiers[0]);
- return -EINVAL;
- }
-
- if (!bo->with_modifiers)
- ret = drmModeAddFB2(drm_->fd(), bo->width, bo->height, bo->format,
- bo->gem_handles, bo->pitches, bo->offsets, &bo->fb_id,
- 0);
- else
- ret = drmModeAddFB2WithModifiers(drm_->fd(), bo->width, bo->height,
- bo->format, bo->gem_handles, bo->pitches,
- bo->offsets, bo->modifiers, &bo->fb_id,
- bo->modifiers[0] ? DRM_MODE_FB_MODIFIERS
- : 0);
-
- if (ret) {
- ALOGE("could not create drm fb %d", ret);
- return ret;
- }
-
- ImportHandle(bo->gem_handles[0]);
-
- return ret;
-}
-
-int DrmGenericImporter::ReleaseBuffer(hwc_drm_bo_t *bo) {
- if (bo->fb_id)
- if (drmModeRmFB(drm_->fd(), bo->fb_id))
- ALOGE("Failed to rm fb");
-
- for (int i = 0; i < HWC_DRM_BO_MAX_PLANES; i++) {
- if (!bo->gem_handles[i])
- continue;
-
- if (ReleaseHandle(bo->gem_handles[i])) {
- ALOGE("Failed to release gem handle %d", bo->gem_handles[i]);
- } else {
- for (int j = i + 1; j < HWC_DRM_BO_MAX_PLANES; j++)
- if (bo->gem_handles[j] == bo->gem_handles[i])
- bo->gem_handles[j] = 0;
- bo->gem_handles[i] = 0;
- }
- }
- return 0;
-}
-
-int DrmGenericImporter::ImportHandle(uint32_t gem_handle) {
- gem_refcount_[gem_handle]++;
-
- return 0;
-}
-
-int DrmGenericImporter::ReleaseHandle(uint32_t gem_handle) {
- if (--gem_refcount_[gem_handle])
- return 0;
-
- gem_refcount_.erase(gem_handle);
-
- return CloseHandle(gem_handle);
-}
-
-int DrmGenericImporter::CloseHandle(uint32_t gem_handle) {
- struct drm_gem_close gem_close;
-
- memset(&gem_close, 0, sizeof(gem_close));
-
- gem_close.handle = gem_handle;
- int ret = drmIoctl(drm_->fd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
- if (ret)
- ALOGE("Failed to close gem handle %d %d", gem_handle, ret);
-
- return ret;
-}
-} // namespace android
diff --git a/drm/DrmGenericImporter.h b/drm/DrmGenericImporter.h
deleted file mode 100644
index ca53762..0000000
--- a/drm/DrmGenericImporter.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2020 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_PLATFORM_DRM_GENERIC_H_
-#define ANDROID_PLATFORM_DRM_GENERIC_H_
-
-#include <drm/drm_fourcc.h>
-#include <hardware/gralloc.h>
-
-#include <map>
-
-#include "drm/DrmDevice.h"
-#include "drmhwcgralloc.h"
-
-#ifndef DRM_FORMAT_INVALID
-#define DRM_FORMAT_INVALID 0
-#endif
-
-namespace android {
-
-class Importer {
- public:
- virtual ~Importer() {
- }
-
- // Imports the buffer referred to by handle into bo.
- //
- // Note: This can be called from a different thread than ReleaseBuffer. The
- // implementation is responsible for ensuring thread safety.
- virtual int ImportBuffer(hwc_drm_bo_t *bo) = 0;
-
- // Releases the buffer object (ie: does the inverse of ImportBuffer)
- //
- // Note: This can be called from a different thread than ImportBuffer. The
- // implementation is responsible for ensuring thread safety.
- virtual int ReleaseBuffer(hwc_drm_bo_t *bo) = 0;
-};
-
-class DrmGenericImporter : public Importer {
- public:
- DrmGenericImporter(DrmDevice *drm);
- ~DrmGenericImporter() override;
-
- int ImportBuffer(hwc_drm_bo_t *bo) override;
- int ReleaseBuffer(hwc_drm_bo_t *bo) override;
- int ImportHandle(uint32_t gem_handle);
- int ReleaseHandle(uint32_t gem_handle);
-
- protected:
- DrmDevice *drm_;
-
- private:
- int CloseHandle(uint32_t gem_handle);
- std::map<uint32_t, int> gem_refcount_;
- bool has_modifier_support_;
-};
-
-} // namespace android
-
-#endif
diff --git a/drm/DrmMode.cpp b/drm/DrmMode.cpp
index 6de671a..010ea1b 100644
--- a/drm/DrmMode.cpp
+++ b/drm/DrmMode.cpp
@@ -16,13 +16,14 @@
#include "DrmMode.h"
+#include <cstring>
+
#include "DrmDevice.h"
namespace android {
DrmMode::DrmMode(drmModeModeInfoPtr m)
- : id_(0),
- clock_(m->clock),
+ : clock_(m->clock),
h_display_(m->hdisplay),
h_sync_start_(m->hsync_start),
h_sync_end_(m->hsync_end),
@@ -48,79 +49,56 @@ bool DrmMode::operator==(const drmModeModeInfo &m) const {
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 {
+uint16_t DrmMode::h_display() const {
return h_display_;
}
-uint32_t DrmMode::h_sync_start() const {
+uint16_t DrmMode::h_sync_start() const {
return h_sync_start_;
}
-uint32_t DrmMode::h_sync_end() const {
+uint16_t DrmMode::h_sync_end() const {
return h_sync_end_;
}
-uint32_t DrmMode::h_total() const {
+uint16_t DrmMode::h_total() const {
return h_total_;
}
-uint32_t DrmMode::h_skew() const {
+uint16_t DrmMode::h_skew() const {
return h_skew_;
}
-uint32_t DrmMode::v_display() const {
+uint16_t DrmMode::v_display() const {
return v_display_;
}
-uint32_t DrmMode::v_sync_start() const {
+uint16_t DrmMode::v_sync_start() const {
return v_sync_start_;
}
-uint32_t DrmMode::v_sync_end() const {
+uint16_t DrmMode::v_sync_end() const {
return v_sync_end_;
}
-uint32_t DrmMode::v_total() const {
+uint16_t DrmMode::v_total() const {
return v_total_;
}
-uint32_t DrmMode::v_scan() const {
+uint16_t DrmMode::v_scan() const {
return v_scan_;
}
float DrmMode::v_refresh() const {
+ if (clock_ == 0) {
+ return v_refresh_;
+ }
// Always recalculate refresh to report correct float rate
- return clock_ / (float)(v_total_ * h_total_) * 1000.0f;
+ return static_cast<float>(clock_) / (float)(v_total_ * h_total_) * 1000.0F;
}
uint32_t DrmMode::flags() const {
@@ -132,6 +110,31 @@ uint32_t DrmMode::type() const {
}
std::string DrmMode::name() const {
- return name_;
+ return name_ + "@" + std::to_string(v_refresh());
+}
+
+auto DrmMode::CreateModeBlob(const DrmDevice &drm)
+ -> DrmModeUserPropertyBlobUnique {
+ struct drm_mode_modeinfo drm_mode = {
+ .clock = clock_,
+ .hdisplay = h_display_,
+ .hsync_start = h_sync_start_,
+ .hsync_end = h_sync_end_,
+ .htotal = h_total_,
+ .hskew = h_skew_,
+ .vdisplay = v_display_,
+ .vsync_start = v_sync_start_,
+ .vsync_end = v_sync_end_,
+ .vtotal = v_total_,
+ .vscan = v_scan_,
+ .vrefresh = v_refresh_,
+ .flags = flags_,
+ .type = type_,
+ };
+ strncpy(drm_mode.name, name_.c_str(), DRM_DISPLAY_MODE_LEN);
+
+ return drm.RegisterUserPropertyBlob(&drm_mode,
+ sizeof(struct drm_mode_modeinfo));
}
+
} // namespace android
diff --git a/drm/DrmMode.h b/drm/DrmMode.h
index 313a8ea..20515f9 100644
--- a/drm/DrmMode.h
+++ b/drm/DrmMode.h
@@ -17,37 +17,38 @@
#ifndef ANDROID_DRM_MODE_H_
#define ANDROID_DRM_MODE_H_
-#include <stdint.h>
#include <xf86drmMode.h>
+#include <cstdint>
+#include <cstdio>
#include <string>
+#include "DrmUnique.h"
+
namespace android {
+class DrmDevice;
+
class DrmMode {
public:
DrmMode() = default;
- DrmMode(drmModeModeInfoPtr m);
+ explicit 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;
+ uint16_t h_display() const;
+ uint16_t h_sync_start() const;
+ uint16_t h_sync_end() const;
+ uint16_t h_total() const;
+ uint16_t h_skew() const;
+
+ uint16_t v_display() const;
+ uint16_t v_sync_start() const;
+ uint16_t v_sync_end() const;
+ uint16_t v_total() const;
+ uint16_t v_scan() const;
float v_refresh() const;
uint32_t flags() const;
@@ -55,23 +56,23 @@ class DrmMode {
std::string name() const;
- private:
- uint32_t id_ = 0;
+ auto CreateModeBlob(const DrmDevice &drm) -> DrmModeUserPropertyBlobUnique;
+ private:
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;
+ uint16_t h_display_ = 0;
+ uint16_t h_sync_start_ = 0;
+ uint16_t h_sync_end_ = 0;
+ uint16_t h_total_ = 0;
+ uint16_t h_skew_ = 0;
+
+ uint16_t v_display_ = 0;
+ uint16_t v_sync_start_ = 0;
+ uint16_t v_sync_end_ = 0;
+ uint16_t v_total_ = 0;
+ uint16_t v_scan_ = 0;
+ uint16_t v_refresh_ = 0;
uint32_t flags_ = 0;
uint32_t type_ = 0;
diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp
index f994252..28f48f3 100644
--- a/drm/DrmPlane.cpp
+++ b/drm/DrmPlane.cpp
@@ -18,35 +18,49 @@
#include "DrmPlane.h"
-#include <errno.h>
-#include <log/log.h>
-#include <stdint.h>
-
+#include <algorithm>
+#include <cerrno>
#include <cinttypes>
+#include <cstdint>
#include "DrmDevice.h"
+#include "bufferinfo/BufferInfoGetter.h"
+#include "utils/log.h"
namespace android {
-DrmPlane::DrmPlane(DrmDevice *drm, drmModePlanePtr p)
- : drm_(drm),
- id_(p->plane_id),
- possible_crtc_mask_(p->possible_crtcs),
- formats_(p->formats, p->formats + p->count_formats) {
+auto DrmPlane::CreateInstance(DrmDevice &dev, uint32_t plane_id)
+ -> std::unique_ptr<DrmPlane> {
+ auto p = MakeDrmModePlaneUnique(dev.GetFd(), plane_id);
+ if (!p) {
+ ALOGE("Failed to get plane %d", plane_id);
+ return {};
+ }
+
+ auto plane = std::unique_ptr<DrmPlane>(new DrmPlane(dev, std::move(p)));
+
+ if (plane->Init() != 0) {
+ ALOGE("Failed to init plane %d", plane_id);
+ return {};
+ }
+
+ return plane;
}
int DrmPlane::Init() {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ formats_ = {plane_->formats, plane_->formats + plane_->count_formats};
+
DrmProperty p;
- int ret = drm_->GetPlaneProperty(*this, "type", &p);
- if (ret) {
- ALOGE("Could not get plane type property");
- return ret;
+ if (!GetPlaneProperty("type", p)) {
+ return -ENOTSUP;
}
- uint64_t type;
+ int ret = 0;
+ uint64_t type = 0;
std::tie(ret, type) = p.value();
- if (ret) {
+ if (ret != 0) {
ALOGE("Failed to get plane type property value");
return ret;
}
@@ -61,99 +75,115 @@ int DrmPlane::Init() {
return -EINVAL;
}
- ret = drm_->GetPlaneProperty(*this, "CRTC_ID", &crtc_property_);
- if (ret) {
- ALOGE("Could not get CRTC_ID property");
- return ret;
+ if (!GetPlaneProperty("CRTC_ID", crtc_property_) ||
+ !GetPlaneProperty("FB_ID", fb_property_) ||
+ !GetPlaneProperty("CRTC_X", crtc_x_property_) ||
+ !GetPlaneProperty("CRTC_Y", crtc_y_property_) ||
+ !GetPlaneProperty("CRTC_W", crtc_w_property_) ||
+ !GetPlaneProperty("CRTC_H", crtc_h_property_) ||
+ !GetPlaneProperty("SRC_X", src_x_property_) ||
+ !GetPlaneProperty("SRC_Y", src_y_property_) ||
+ !GetPlaneProperty("SRC_W", src_w_property_) ||
+ !GetPlaneProperty("SRC_H", src_h_property_)) {
+ return -ENOTSUP;
}
- ret = drm_->GetPlaneProperty(*this, "FB_ID", &fb_property_);
- if (ret) {
- ALOGE("Could not get FB_ID property");
- return ret;
+ GetPlaneProperty("zpos", zpos_property_, Presence::kOptional);
+
+ if (GetPlaneProperty("rotation", rotation_property_, Presence::kOptional)) {
+ rotation_property_.AddEnumToMap("rotate-0", DrmHwcTransform::kIdentity,
+ transform_enum_map_);
+ rotation_property_.AddEnumToMap("rotate-90", DrmHwcTransform::kRotate90,
+ transform_enum_map_);
+ rotation_property_.AddEnumToMap("rotate-180", DrmHwcTransform::kRotate180,
+ transform_enum_map_);
+ rotation_property_.AddEnumToMap("rotate-270", DrmHwcTransform::kRotate270,
+ transform_enum_map_);
+ rotation_property_.AddEnumToMap("reflect-x", DrmHwcTransform::kFlipH,
+ transform_enum_map_);
+ rotation_property_.AddEnumToMap("reflect-y", DrmHwcTransform::kFlipV,
+ transform_enum_map_);
}
- ret = drm_->GetPlaneProperty(*this, "CRTC_X", &crtc_x_property_);
- if (ret) {
- ALOGE("Could not get CRTC_X property");
- return ret;
- }
+ GetPlaneProperty("alpha", alpha_property_, Presence::kOptional);
- ret = drm_->GetPlaneProperty(*this, "CRTC_Y", &crtc_y_property_);
- if (ret) {
- ALOGE("Could not get CRTC_Y property");
- return ret;
+ if (GetPlaneProperty("pixel blend mode", blend_property_,
+ Presence::kOptional)) {
+ blend_property_.AddEnumToMap("Pre-multiplied", DrmHwcBlending::kPreMult,
+ blending_enum_map_);
+ blend_property_.AddEnumToMap("Coverage", DrmHwcBlending::kCoverage,
+ blending_enum_map_);
+ blend_property_.AddEnumToMap("None", DrmHwcBlending::kNone,
+ blending_enum_map_);
}
- ret = drm_->GetPlaneProperty(*this, "CRTC_W", &crtc_w_property_);
- if (ret) {
- ALOGE("Could not get CRTC_W property");
- return ret;
+ GetPlaneProperty("IN_FENCE_FD", in_fence_fd_property_, Presence::kOptional);
+
+ if (HasNonRgbFormat()) {
+ if (GetPlaneProperty("COLOR_ENCODING", color_encoding_propery_,
+ Presence::kOptional)) {
+ color_encoding_propery_.AddEnumToMap("ITU-R BT.709 YCbCr",
+ DrmHwcColorSpace::kItuRec709,
+ color_encoding_enum_map_);
+ color_encoding_propery_.AddEnumToMap("ITU-R BT.601 YCbCr",
+ DrmHwcColorSpace::kItuRec601,
+ color_encoding_enum_map_);
+ color_encoding_propery_.AddEnumToMap("ITU-R BT.2020 YCbCr",
+ DrmHwcColorSpace::kItuRec2020,
+ color_encoding_enum_map_);
+ }
+
+ if (GetPlaneProperty("COLOR_RANGE", color_range_property_,
+ Presence::kOptional)) {
+ color_range_property_.AddEnumToMap("YCbCr full range",
+ DrmHwcSampleRange::kFullRange,
+ color_range_enum_map_);
+ color_range_property_.AddEnumToMap("YCbCr limited range",
+ DrmHwcSampleRange::kLimitedRange,
+ color_range_enum_map_);
+ }
}
- ret = drm_->GetPlaneProperty(*this, "CRTC_H", &crtc_h_property_);
- if (ret) {
- ALOGE("Could not get CRTC_H property");
- return ret;
- }
+ return 0;
+}
- ret = drm_->GetPlaneProperty(*this, "SRC_X", &src_x_property_);
- if (ret) {
- ALOGE("Could not get SRC_X property");
- return ret;
- }
+bool DrmPlane::IsCrtcSupported(const DrmCrtc &crtc) const {
+ return ((1 << crtc.GetIndexInResArray()) & plane_->possible_crtcs) != 0;
+}
- ret = drm_->GetPlaneProperty(*this, "SRC_Y", &src_y_property_);
- if (ret) {
- ALOGE("Could not get SRC_Y property");
- return ret;
+bool DrmPlane::IsValidForLayer(DrmHwcLayer *layer) {
+ if (!rotation_property_) {
+ if (layer->transform != DrmHwcTransform::kIdentity) {
+ ALOGV("No rotation property on plane %d", GetId());
+ return false;
+ }
+ } else {
+ if (transform_enum_map_.count(layer->transform) == 0) {
+ ALOGV("Transform is not supported on plane %d", GetId());
+ return false;
+ }
}
- ret = drm_->GetPlaneProperty(*this, "SRC_W", &src_w_property_);
- if (ret) {
- ALOGE("Could not get SRC_W property");
- return ret;
+ if (alpha_property_.id() == 0 && layer->alpha != UINT16_MAX) {
+ ALOGV("Alpha is not supported on plane %d", GetId());
+ return false;
}
- ret = drm_->GetPlaneProperty(*this, "SRC_H", &src_h_property_);
- if (ret) {
- ALOGE("Could not get SRC_H property");
- return ret;
+ if (blending_enum_map_.count(layer->blending) == 0 &&
+ layer->blending != DrmHwcBlending::kNone &&
+ layer->blending != DrmHwcBlending::kPreMult) {
+ ALOGV("Blending is not supported on plane %d", GetId());
+ return false;
}
- 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 format = layer->buffer_info.format;
+ if (!IsFormatSupported(format)) {
+ ALOGV("Plane %d does not supports %c%c%c%c format", GetId(), format,
+ format >> 8, format >> 16, format >> 24);
+ return false;
+ }
-uint32_t DrmPlane::type() const {
- return type_;
+ return true;
}
bool DrmPlane::IsFormatSupported(uint32_t format) const {
@@ -161,63 +191,130 @@ bool DrmPlane::IsFormatSupported(uint32_t format) const {
std::end(formats_);
}
-const DrmProperty &DrmPlane::crtc_property() const {
- return crtc_property_;
+bool DrmPlane::HasNonRgbFormat() const {
+ return std::find_if_not(std::begin(formats_), std::end(formats_),
+ [](uint32_t format) {
+ return BufferInfoGetter::IsDrmFormatRgb(format);
+ }) != std::end(formats_);
}
-const DrmProperty &DrmPlane::fb_property() const {
- return fb_property_;
+static uint64_t ToDrmRotation(DrmHwcTransform transform) {
+ uint64_t rotation = 0;
+ if ((transform & DrmHwcTransform::kFlipH) != 0)
+ rotation |= DRM_MODE_REFLECT_X;
+ if ((transform & DrmHwcTransform::kFlipV) != 0)
+ rotation |= DRM_MODE_REFLECT_Y;
+ if ((transform & DrmHwcTransform::kRotate90) != 0)
+ rotation |= DRM_MODE_ROTATE_90;
+ else if ((transform & DrmHwcTransform::kRotate180) != 0)
+ rotation |= DRM_MODE_ROTATE_180;
+ else if ((transform & DrmHwcTransform::kRotate270) != 0)
+ rotation |= DRM_MODE_ROTATE_270;
+ else
+ rotation |= DRM_MODE_ROTATE_0;
+
+ return rotation;
}
-const DrmProperty &DrmPlane::crtc_x_property() const {
- return crtc_x_property_;
+/* Convert float to 16.16 fixed point */
+static int To1616FixPt(float in) {
+ constexpr int kBitShift = 16;
+ return int(in * (1 << kBitShift));
}
-const DrmProperty &DrmPlane::crtc_y_property() const {
- return crtc_y_property_;
-}
+auto DrmPlane::AtomicSetState(drmModeAtomicReq &pset, DrmHwcLayer &layer,
+ uint32_t zpos, uint32_t crtc_id) -> int {
+ if (!layer.fb_id_handle) {
+ ALOGE("Expected a valid framebuffer for pset");
+ return -EINVAL;
+ }
-const DrmProperty &DrmPlane::crtc_w_property() const {
- return crtc_w_property_;
-}
+ if (zpos_property_ && !zpos_property_.is_immutable()) {
+ uint64_t min_zpos = 0;
-const DrmProperty &DrmPlane::crtc_h_property() const {
- return crtc_h_property_;
-}
+ // Ignore ret and use min_zpos as 0 by default
+ std::tie(std::ignore, min_zpos) = zpos_property_.range_min();
-const DrmProperty &DrmPlane::src_x_property() const {
- return src_x_property_;
-}
+ if (!zpos_property_.AtomicSet(pset, zpos + min_zpos)) {
+ return -EINVAL;
+ }
+ }
-const DrmProperty &DrmPlane::src_y_property() const {
- return src_y_property_;
-}
+ if (layer.acquire_fence &&
+ !in_fence_fd_property_.AtomicSet(pset, layer.acquire_fence.Get())) {
+ return -EINVAL;
+ }
-const DrmProperty &DrmPlane::src_w_property() const {
- return src_w_property_;
-}
+ if (!crtc_property_.AtomicSet(pset, crtc_id) ||
+ !fb_property_.AtomicSet(pset, layer.fb_id_handle->GetFbId()) ||
+ !crtc_x_property_.AtomicSet(pset, layer.display_frame.left) ||
+ !crtc_y_property_.AtomicSet(pset, layer.display_frame.top) ||
+ !crtc_w_property_.AtomicSet(pset, layer.display_frame.right -
+ layer.display_frame.left) ||
+ !crtc_h_property_.AtomicSet(pset, layer.display_frame.bottom -
+ layer.display_frame.top) ||
+ !src_x_property_.AtomicSet(pset, To1616FixPt(layer.source_crop.left)) ||
+ !src_y_property_.AtomicSet(pset, To1616FixPt(layer.source_crop.top)) ||
+ !src_w_property_.AtomicSet(pset, To1616FixPt(layer.source_crop.right -
+ layer.source_crop.left)) ||
+ !src_h_property_.AtomicSet(pset, To1616FixPt(layer.source_crop.bottom -
+ layer.source_crop.top))) {
+ return -EINVAL;
+ }
-const DrmProperty &DrmPlane::src_h_property() const {
- return src_h_property_;
-}
+ if (rotation_property_ &&
+ !rotation_property_.AtomicSet(pset, ToDrmRotation(layer.transform))) {
+ return -EINVAL;
+ }
-const DrmProperty &DrmPlane::zpos_property() const {
- return zpos_property_;
-}
+ if (alpha_property_ && !alpha_property_.AtomicSet(pset, layer.alpha)) {
+ return -EINVAL;
+ }
-const DrmProperty &DrmPlane::rotation_property() const {
- return rotation_property_;
-}
+ if (blending_enum_map_.count(layer.blending) != 0 &&
+ !blend_property_.AtomicSet(pset, blending_enum_map_[layer.blending])) {
+ return -EINVAL;
+ }
+
+ if (color_encoding_enum_map_.count(layer.color_space) != 0 &&
+ !color_encoding_propery_
+ .AtomicSet(pset, color_encoding_enum_map_[layer.color_space])) {
+ return -EINVAL;
+ }
+
+ if (color_range_enum_map_.count(layer.sample_range) != 0 &&
+ !color_range_property_
+ .AtomicSet(pset, color_range_enum_map_[layer.sample_range])) {
+ return -EINVAL;
+ }
-const DrmProperty &DrmPlane::alpha_property() const {
- return alpha_property_;
+ return 0;
}
-const DrmProperty &DrmPlane::blend_property() const {
- return blend_property_;
+auto DrmPlane::AtomicDisablePlane(drmModeAtomicReq &pset) -> int {
+ if (!crtc_property_.AtomicSet(pset, 0) || !fb_property_.AtomicSet(pset, 0)) {
+ return -EINVAL;
+ }
+
+ return 0;
}
-const DrmProperty &DrmPlane::in_fence_fd_property() const {
- return in_fence_fd_property_;
+auto DrmPlane::GetPlaneProperty(const char *prop_name, DrmProperty &property,
+ Presence presence) -> bool {
+ int err = drm_->GetProperty(GetId(), DRM_MODE_OBJECT_PLANE, prop_name,
+ &property);
+ if (err != 0) {
+ if (presence == Presence::kMandatory) {
+ ALOGE("Could not get mandatory property \"%s\" from plane %d", prop_name,
+ GetId());
+ } else {
+ ALOGV("Could not get optional property \"%s\" from plane %d", prop_name,
+ GetId());
+ }
+ return false;
+ }
+
+ return true;
}
+
} // namespace android
diff --git a/drm/DrmPlane.h b/drm/DrmPlane.h
index 16731a8..65f458f 100644
--- a/drm/DrmPlane.h
+++ b/drm/DrmPlane.h
@@ -17,57 +17,62 @@
#ifndef ANDROID_DRM_PLANE_H_
#define ANDROID_DRM_PLANE_H_
-#include <stdint.h>
#include <xf86drmMode.h>
+#include <cstdint>
#include <vector>
#include "DrmCrtc.h"
#include "DrmProperty.h"
+#include "drmhwcomposer.h"
namespace android {
class DrmDevice;
+struct DrmHwcLayer;
-class DrmPlane {
+class DrmPlane : public PipelineBindable<DrmPlane> {
public:
- DrmPlane(DrmDevice *drm, drmModePlanePtr p);
DrmPlane(const DrmPlane &) = delete;
DrmPlane &operator=(const DrmPlane &) = delete;
- int Init();
+ static auto CreateInstance(DrmDevice &dev, uint32_t plane_id)
+ -> std::unique_ptr<DrmPlane>;
- uint32_t id() const;
+ bool IsCrtcSupported(const DrmCrtc &crtc) const;
+ bool IsValidForLayer(DrmHwcLayer *layer);
- bool GetCrtcSupported(const DrmCrtc &crtc) const;
-
- uint32_t type() const;
+ auto GetType() const {
+ return type_;
+ }
bool IsFormatSupported(uint32_t format) const;
+ bool HasNonRgbFormat() const;
+
+ auto AtomicSetState(drmModeAtomicReq &pset, DrmHwcLayer &layer, uint32_t zpos,
+ uint32_t crtc_id) -> int;
+ auto AtomicDisablePlane(drmModeAtomicReq &pset) -> int;
+ auto &GetZPosProperty() const {
+ return zpos_property_;
+ }
- 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;
+ auto GetId() const {
+ return plane_->plane_id;
+ }
private:
- DrmDevice *drm_;
- uint32_t id_;
+ DrmPlane(DrmDevice &dev, DrmModePlaneUnique plane)
+ : drm_(&dev), plane_(std::move(plane)){};
+ DrmDevice *const drm_;
+ DrmModePlaneUnique plane_;
- uint32_t possible_crtc_mask_;
+ enum class Presence { kOptional, kMandatory };
- uint32_t type_;
+ auto Init() -> int;
+ auto GetPlaneProperty(const char *prop_name, DrmProperty &property,
+ Presence presence = Presence::kMandatory) -> bool;
+
+ uint32_t type_{};
std::vector<uint32_t> formats_;
@@ -86,6 +91,13 @@ class DrmPlane {
DrmProperty alpha_property_;
DrmProperty blend_property_;
DrmProperty in_fence_fd_property_;
+ DrmProperty color_encoding_propery_;
+ DrmProperty color_range_property_;
+
+ std::map<DrmHwcBlending, uint64_t> blending_enum_map_;
+ std::map<DrmHwcColorSpace, uint64_t> color_encoding_enum_map_;
+ std::map<DrmHwcSampleRange, uint64_t> color_range_enum_map_;
+ std::map<DrmHwcTransform, uint64_t> transform_enum_map_;
};
} // namespace android
diff --git a/drm/DrmProperty.cpp b/drm/DrmProperty.cpp
index b60a76e..32f1c62 100644
--- a/drm/DrmProperty.cpp
+++ b/drm/DrmProperty.cpp
@@ -14,15 +14,19 @@
* limitations under the License.
*/
+// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
+#define LOG_TAG "hwc-drm-property"
+
#include "DrmProperty.h"
-#include <errno.h>
-#include <stdint.h>
#include <xf86drmMode.h>
+#include <cerrno>
+#include <cstdint>
#include <string>
#include "DrmDevice.h"
+#include "utils/log.h"
namespace android {
@@ -30,28 +34,26 @@ 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);
+DrmProperty::DrmProperty(uint32_t obj_id, drmModePropertyPtr p,
+ uint64_t value) {
+ Init(obj_id, p, value);
}
-void DrmProperty::Init(drmModePropertyPtr p, uint64_t value) {
+void DrmProperty::Init(uint32_t obj_id, drmModePropertyPtr p, uint64_t value) {
+ obj_id_ = obj_id;
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]);
+ values_.emplace_back(p->values[i]);
for (int i = 0; i < p->count_enums; ++i)
- enums_.push_back(DrmPropertyEnum(&p->enums[i]));
+ enums_.emplace_back(DrmPropertyEnum(&p->enums[i]));
for (int i = 0; i < p->count_blobs; ++i)
- blob_ids_.push_back(p->blob_ids[i]);
+ blob_ids_.emplace_back(p->blob_ids[i]);
if (flags_ & DRM_MODE_PROP_RANGE)
type_ = DRM_PROPERTY_TYPE_INT;
@@ -61,6 +63,8 @@ void DrmProperty::Init(drmModePropertyPtr p, uint64_t value) {
type_ = DRM_PROPERTY_TYPE_OBJECT;
else if (flags_ & DRM_MODE_PROP_BLOB)
type_ = DRM_PROPERTY_TYPE_BLOB;
+ else if (flags_ & DRM_MODE_PROP_BITMASK)
+ type_ = DRM_PROPERTY_TYPE_BITMASK;
}
uint32_t DrmProperty::id() const {
@@ -75,7 +79,7 @@ std::tuple<int, uint64_t> DrmProperty::value() const {
if (type_ == DRM_PROPERTY_TYPE_BLOB)
return std::make_tuple(0, value_);
- if (values_.size() == 0)
+ if (values_.empty())
return std::make_tuple(-ENOENT, 0);
switch (type_) {
@@ -91,6 +95,7 @@ std::tuple<int, uint64_t> DrmProperty::value() const {
case DRM_PROPERTY_TYPE_OBJECT:
return std::make_tuple(0, value_);
+ case DRM_PROPERTY_TYPE_BITMASK:
default:
return std::make_tuple(-EINVAL, 0);
}
@@ -107,7 +112,7 @@ bool DrmProperty::is_range() const {
std::tuple<int, uint64_t> DrmProperty::range_min() const {
if (!is_range())
return std::make_tuple(-EINVAL, 0);
- if (values_.size() < 1)
+ if (values_.empty())
return std::make_tuple(-ENOENT, 0);
return std::make_tuple(0, values_[0]);
@@ -123,13 +128,28 @@ std::tuple<int, uint64_t> DrmProperty::range_max() const {
}
std::tuple<uint64_t, int> DrmProperty::GetEnumValueWithName(
- std::string name) const {
- for (auto it : enums_) {
- if (it.name_.compare(name) == 0) {
+ const std::string &name) const {
+ for (const auto &it : enums_) {
+ if (it.name_ == name) {
return std::make_tuple(it.value_, 0);
}
}
return std::make_tuple(UINT64_MAX, -EINVAL);
}
+
+auto DrmProperty::AtomicSet(drmModeAtomicReq &pset, uint64_t value) const
+ -> bool {
+ if (id_ == 0) {
+ ALOGE("AtomicSet() is called on non-initialized property!");
+ return false;
+ }
+ if (drmModeAtomicAddProperty(&pset, obj_id_, id_, value) < 0) {
+ ALOGE("Failed to add obj_id: %u, prop_id: %u (%s) to pset", obj_id_, id_,
+ name_.c_str());
+ return false;
+ }
+ return true;
+}
+
} // namespace android
diff --git a/drm/DrmProperty.h b/drm/DrmProperty.h
index d293da3..26a7c38 100644
--- a/drm/DrmProperty.h
+++ b/drm/DrmProperty.h
@@ -17,9 +17,10 @@
#ifndef ANDROID_DRM_PROPERTY_H_
#define ANDROID_DRM_PROPERTY_H_
-#include <stdint.h>
#include <xf86drmMode.h>
+#include <cstdint>
+#include <map>
#include <string>
#include <vector>
@@ -30,18 +31,19 @@ enum DrmPropertyType {
DRM_PROPERTY_TYPE_ENUM,
DRM_PROPERTY_TYPE_OBJECT,
DRM_PROPERTY_TYPE_BLOB,
+ DRM_PROPERTY_TYPE_BITMASK,
DRM_PROPERTY_TYPE_INVALID,
};
class DrmProperty {
public:
DrmProperty() = default;
- DrmProperty(drmModePropertyPtr p, uint64_t value);
+ DrmProperty(uint32_t obj_id, drmModePropertyPtr p, uint64_t value);
DrmProperty(const DrmProperty &) = delete;
DrmProperty &operator=(const DrmProperty &) = delete;
- void Init(drmModePropertyPtr p, uint64_t value);
- std::tuple<uint64_t, int> GetEnumValueWithName(std::string name) const;
+ auto Init(uint32_t obj_id, drmModePropertyPtr p, uint64_t value) -> void;
+ std::tuple<uint64_t, int> GetEnumValueWithName(const std::string &name) const;
uint32_t id() const;
std::string name() const;
@@ -53,16 +55,28 @@ class DrmProperty {
std::tuple<int, uint64_t> range_min() const;
std::tuple<int, uint64_t> range_max() const;
+ [[nodiscard]] auto AtomicSet(drmModeAtomicReq &pset, uint64_t value) const
+ -> bool;
+
+ template <class E>
+ auto AddEnumToMap(const std::string &name, E key, std::map<E, uint64_t> &map)
+ -> bool;
+
+ explicit operator bool() const {
+ return id_ != 0;
+ }
+
private:
class DrmPropertyEnum {
public:
- DrmPropertyEnum(drm_mode_property_enum *e);
- ~DrmPropertyEnum();
+ explicit DrmPropertyEnum(drm_mode_property_enum *e);
+ ~DrmPropertyEnum() = default;
uint64_t value_;
std::string name_;
};
+ uint32_t obj_id_ = 0;
uint32_t id_ = 0;
DrmPropertyType type_ = DRM_PROPERTY_TYPE_INVALID;
@@ -74,6 +88,21 @@ class DrmProperty {
std::vector<DrmPropertyEnum> enums_;
std::vector<uint32_t> blob_ids_;
};
+
+template <class E>
+auto DrmProperty::AddEnumToMap(const std::string &name, E key,
+ std::map<E, uint64_t> &map) -> bool {
+ uint64_t enum_value = UINT64_MAX;
+ int err = 0;
+ std::tie(enum_value, err) = GetEnumValueWithName(name);
+ if (err == 0) {
+ map[key] = enum_value;
+ return true;
+ }
+
+ return false;
+}
+
} // namespace android
#endif // ANDROID_DRM_PROPERTY_H_
diff --git a/drm/DrmUnique.h b/drm/DrmUnique.h
new file mode 100644
index 0000000..282528b
--- /dev/null
+++ b/drm/DrmUnique.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 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 DRM_UNIQUE_H_
+#define DRM_UNIQUE_H_
+
+#include <xf86drmMode.h>
+
+#include <functional>
+#include <memory>
+
+template <typename T>
+using DUniquePtr = std::unique_ptr<T, std::function<void(T *)>>;
+
+using DrmModeAtomicReqUnique = DUniquePtr<drmModeAtomicReq>;
+auto inline MakeDrmModeAtomicReqUnique() {
+ return DrmModeAtomicReqUnique(drmModeAtomicAlloc(), [](drmModeAtomicReq *it) {
+ drmModeAtomicFree(it);
+ });
+};
+
+using DrmModeConnectorUnique = DUniquePtr<drmModeConnector>;
+auto inline MakeDrmModeConnectorUnique(int fd, uint32_t connector_id) {
+ return DrmModeConnectorUnique(drmModeGetConnector(fd, connector_id),
+ [](drmModeConnector *it) {
+ drmModeFreeConnector(it);
+ });
+}
+
+using DrmModeCrtcUnique = DUniquePtr<drmModeCrtc>;
+auto inline MakeDrmModeCrtcUnique(int fd, uint32_t crtc_id) {
+ return DrmModeCrtcUnique(drmModeGetCrtc(fd, crtc_id),
+ [](drmModeCrtc *it) { drmModeFreeCrtc(it); });
+}
+
+using DrmModeEncoderUnique = DUniquePtr<drmModeEncoder>;
+auto inline MakeDrmModeEncoderUnique(int fd, uint32_t encoder_id) {
+ return DrmModeEncoderUnique(drmModeGetEncoder(fd, encoder_id),
+ [](drmModeEncoder *it) {
+ drmModeFreeEncoder(it);
+ });
+}
+
+using DrmModePlaneUnique = DUniquePtr<drmModePlane>;
+auto inline MakeDrmModePlaneUnique(int fd, uint32_t plane_id) {
+ return DrmModePlaneUnique(drmModeGetPlane(fd, plane_id),
+ [](drmModePlane *it) { drmModeFreePlane(it); });
+}
+
+using DrmModePlaneResUnique = DUniquePtr<drmModePlaneRes>;
+auto inline MakeDrmModePlaneResUnique(int fd) {
+ return DrmModePlaneResUnique(drmModeGetPlaneResources(fd),
+ [](drmModePlaneRes *it) {
+ drmModeFreePlaneResources(it);
+ });
+}
+
+using DrmModeUserPropertyBlobUnique = DUniquePtr<uint32_t /*id*/>;
+
+using DrmModePropertyBlobUnique = DUniquePtr<drmModePropertyBlobRes>;
+auto inline MakeDrmModePropertyBlobUnique(int fd, uint32_t blob_id) {
+ return DrmModePropertyBlobUnique(drmModeGetPropertyBlob(fd, blob_id),
+ [](drmModePropertyBlobRes *it) {
+ drmModeFreePropertyBlob(it);
+ });
+}
+
+using DrmModeResUnique = DUniquePtr<drmModeRes>;
+auto inline MakeDrmModeResUnique(int fd) {
+ return DrmModeResUnique(drmModeGetResources(fd),
+ [](drmModeRes *it) { drmModeFreeResources(it); });
+}
+
+#endif
diff --git a/drm/ResourceManager.cpp b/drm/ResourceManager.cpp
index fc24aea..c8235e9 100644
--- a/drm/ResourceManager.cpp
+++ b/drm/ResourceManager.cpp
@@ -18,134 +18,167 @@
#include "ResourceManager.h"
-#include <cutils/properties.h>
-#include <log/log.h>
+#include <fcntl.h>
#include <sys/stat.h>
+#include <ctime>
#include <sstream>
#include "bufferinfo/BufferInfoGetter.h"
+#include "drm/DrmAtomicStateManager.h"
+#include "drm/DrmDevice.h"
+#include "drm/DrmDisplayPipeline.h"
+#include "drm/DrmPlane.h"
+#include "utils/log.h"
+#include "utils/properties.h"
namespace android {
-ResourceManager::ResourceManager() : num_displays_(0), gralloc_(NULL) {
+ResourceManager::ResourceManager(
+ PipelineToFrontendBindingInterface *p2f_bind_interface)
+ : frontend_interface_(p2f_bind_interface) {
+ if (uevent_listener_.Init() != 0) {
+ ALOGE("Can't initialize event listener");
+ }
+}
+
+ResourceManager::~ResourceManager() {
+ uevent_listener_.Exit();
}
-int ResourceManager::Init() {
+void ResourceManager::Init() {
+ if (initialized_) {
+ ALOGE("Already initialized");
+ return;
+ }
+
char path_pattern[PROPERTY_VALUE_MAX];
// Could be a valid path or it can have at the end of it the wildcard %
// which means that it will try open all devices until an error is met.
int path_len = property_get("vendor.hwc.drm.device", path_pattern,
"/dev/dri/card%");
- int ret = 0;
if (path_pattern[path_len - 1] != '%') {
- ret = AddDrmDevice(std::string(path_pattern));
+ AddDrmDevice(std::string(path_pattern));
} else {
path_pattern[path_len - 1] = '\0';
- for (int idx = 0; !ret; ++idx) {
+ for (int idx = 0;; ++idx) {
std::ostringstream path;
path << path_pattern << idx;
- struct stat buf;
- if (stat(path.str().c_str(), &buf)) {
+ struct stat buf {};
+ if (stat(path.str().c_str(), &buf) != 0)
break;
- } else if (IsKMSDev(path.str().c_str())) {
- ret = AddDrmDevice(path.str());
+
+ if (DrmDevice::IsKMSDev(path.str().c_str())) {
+ 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));
- if (!BufferInfoGetter::GetInstance()) {
+ if (BufferInfoGetter::GetInstance() == nullptr) {
ALOGE("Failed to initialize BufferInfoGetter");
- return -EINVAL;
+ return;
}
- return hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
- (const hw_module_t **)&gralloc_);
+ uevent_listener_.RegisterHotplugHandler([this] {
+ const std::lock_guard<std::mutex> lock(GetMainLock());
+ UpdateFrontendDisplays();
+ });
+
+ UpdateFrontendDisplays();
+
+ initialized_ = true;
}
-int ResourceManager::AddDrmDevice(std::string path) {
- std::unique_ptr<DrmDevice> drm = std::make_unique<DrmDevice>();
- int displays_added, ret;
- std::tie(ret, displays_added) = drm->Init(path.c_str(), num_displays_);
- if (ret)
- return ret;
- std::shared_ptr<Importer> importer;
- importer.reset(new DrmGenericImporter(drm.get()));
- if (!importer) {
- ALOGE("Failed to create importer instance");
- return -ENODEV;
+void ResourceManager::DeInit() {
+ if (!initialized_) {
+ ALOGE("Not initialized");
+ return;
}
- importers_.push_back(importer);
+
+ uevent_listener_.RegisterHotplugHandler([] {});
+
+ DetachAllFrontendDisplays();
+ drms_.clear();
+
+ initialized_ = false;
+}
+
+int ResourceManager::AddDrmDevice(const std::string &path) {
+ auto drm = std::make_unique<DrmDevice>();
+ int ret = drm->Init(path.c_str());
drms_.push_back(std::move(drm));
- 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;
+auto ResourceManager::GetTimeMonotonicNs() -> int64_t {
+ struct timespec ts {};
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ constexpr int64_t kNsInSec = 1000000000LL;
+ return int64_t(ts.tv_sec) * kNsInSec + int64_t(ts.tv_nsec);
}
-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;
+void ResourceManager::UpdateFrontendDisplays() {
+ auto ordered_connectors = GetOrderedConnectors();
+
+ for (auto *conn : ordered_connectors) {
+ conn->UpdateModes();
+ bool connected = conn->IsConnected();
+ bool attached = attached_pipelines_.count(conn) != 0;
+
+ if (connected != attached) {
+ ALOGI("%s connector %s", connected ? "Attaching" : "Detaching",
+ conn->GetName().c_str());
+
+ if (connected) {
+ auto pipeline = DrmDisplayPipeline::CreatePipeline(*conn);
+ frontend_interface_->BindDisplay(pipeline.get());
+ attached_pipelines_[conn] = std::move(pipeline);
+ } else {
+ auto &pipeline = attached_pipelines_[conn];
+ frontend_interface_->UnbindDisplay(pipeline.get());
+ attached_pipelines_.erase(conn);
+ }
+ }
}
+ frontend_interface_->FinalizeDisplayBinding();
+}
- bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 &&
- res->count_encoders > 0;
+void ResourceManager::DetachAllFrontendDisplays() {
+ for (auto &p : attached_pipelines_) {
+ frontend_interface_->UnbindDisplay(p.second.get());
+ }
+ attached_pipelines_.clear();
+ frontend_interface_->FinalizeDisplayBinding();
+}
- drmModeFreeResources(res);
- close(fd);
+auto ResourceManager::GetOrderedConnectors() -> std::vector<DrmConnector *> {
+ /* Put internal displays first then external to
+ * ensure Internal will take Primary slot
+ */
- return is_kms;
-}
+ std::vector<DrmConnector *> ordered_connectors;
-DrmDevice *ResourceManager::GetDrmDevice(int display) {
for (auto &drm : drms_) {
- if (drm->HandlesDisplay(display))
- return drm.get();
+ for (const auto &conn : drm->GetConnectors()) {
+ if (conn->IsInternal()) {
+ ordered_connectors.emplace_back(conn.get());
+ }
+ }
}
- return NULL;
-}
-std::shared_ptr<Importer> ResourceManager::GetImporter(int display) {
- for (unsigned int i = 0; i < drms_.size(); i++) {
- if (drms_[i]->HandlesDisplay(display))
- return importers_[i];
+ for (auto &drm : drms_) {
+ for (const auto &conn : drm->GetConnectors()) {
+ if (conn->IsExternal()) {
+ ordered_connectors.emplace_back(conn.get());
+ }
+ }
}
- return NULL;
-}
-const gralloc_module_t *ResourceManager::gralloc() {
- return gralloc_;
+ return ordered_connectors;
}
} // namespace android
diff --git a/drm/ResourceManager.h b/drm/ResourceManager.h
index 7102cea..88ba878 100644
--- a/drm/ResourceManager.h
+++ b/drm/ResourceManager.h
@@ -17,43 +17,67 @@
#ifndef RESOURCEMANAGER_H
#define RESOURCEMANAGER_H
-#include <string.h>
+#include <cstring>
#include "DrmDevice.h"
-#include "DrmGenericImporter.h"
+#include "DrmDisplayPipeline.h"
+#include "DrmFbImporter.h"
+#include "UEventListener.h"
namespace android {
+class PipelineToFrontendBindingInterface {
+ public:
+ virtual ~PipelineToFrontendBindingInterface() = default;
+ virtual bool BindDisplay(DrmDisplayPipeline *);
+ virtual bool UnbindDisplay(DrmDisplayPipeline *);
+ virtual void FinalizeDisplayBinding();
+};
+
class ResourceManager {
public:
- ResourceManager();
+ explicit ResourceManager(
+ PipelineToFrontendBindingInterface *p2f_bind_interface);
ResourceManager(const ResourceManager &) = delete;
ResourceManager &operator=(const ResourceManager &) = delete;
- int Init();
- DrmDevice *GetDrmDevice(int display);
- std::shared_ptr<Importer> GetImporter(int display);
- const gralloc_module_t *gralloc();
- DrmConnector *AvailableWritebackConnector(int display);
- const std::vector<std::unique_ptr<DrmDevice>> &getDrmDevices() const {
- return drms_;
- }
- int getDisplayCount() const {
- return num_displays_;
- }
- bool ForcedScalingWithGpu() {
+ ResourceManager(const ResourceManager &&) = delete;
+ ResourceManager &&operator=(const ResourceManager &&) = delete;
+ ~ResourceManager();
+
+ void Init();
+
+ void DeInit();
+
+ bool ForcedScalingWithGpu() const {
return scale_with_gpu_;
}
+ auto &GetMainLock() {
+ return main_lock_;
+ }
+
+ static auto GetTimeMonotonicNs() -> int64_t;
+
private:
- int AddDrmDevice(std::string path);
- static bool IsKMSDev(const char *path);
+ auto AddDrmDevice(std::string const &path) -> int;
+ auto GetOrderedConnectors() -> std::vector<DrmConnector *>;
+ void UpdateFrontendDisplays();
+ void DetachAllFrontendDisplays();
- int num_displays_;
std::vector<std::unique_ptr<DrmDevice>> drms_;
- std::vector<std::shared_ptr<Importer>> importers_;
- const gralloc_module_t *gralloc_;
- bool scale_with_gpu_;
+ bool scale_with_gpu_{};
+
+ UEventListener uevent_listener_;
+
+ std::mutex main_lock_;
+
+ std::map<DrmConnector *, std::unique_ptr<DrmDisplayPipeline>>
+ attached_pipelines_;
+
+ PipelineToFrontendBindingInterface *const frontend_interface_;
+
+ bool initialized_{};
};
} // namespace android
diff --git a/drm/UEventListener.cpp b/drm/UEventListener.cpp
new file mode 100644
index 0000000..b56b8e1
--- /dev/null
+++ b/drm/UEventListener.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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-uevent-listener"
+
+#include "UEventListener.h"
+
+#include <cerrno>
+
+#include "utils/log.h"
+
+/* Originally defined in system/core/libsystem/include/system/graphics.h as
+ * #define HAL_PRIORITY_URGENT_DISPLAY (-8)*/
+constexpr int kHalPriorityUrgentDisplay = -8;
+
+namespace android {
+
+UEventListener::UEventListener()
+ : Worker("uevent-listener", kHalPriorityUrgentDisplay){};
+
+int UEventListener::Init() {
+ uevent_ = UEvent::CreateInstance();
+ if (!uevent_) {
+ return -ENODEV;
+ }
+
+ return InitWorker();
+}
+
+void UEventListener::Routine() {
+ while (true) {
+ auto uevent_str = uevent_->ReadNext();
+
+ if (!hotplug_handler_ || !uevent_str)
+ continue;
+
+ bool drm_event = uevent_str->find("DEVTYPE=drm_minor") != std::string::npos;
+ bool hotplug_event = uevent_str->find("HOTPLUG=1") != std::string::npos;
+
+ if (drm_event && hotplug_event) {
+ constexpr useconds_t kDelayAfterUeventUs = 200000;
+ /* We need some delay to ensure DrmConnector::UpdateModes() will query
+ * correct modes list, otherwise at least RPI4 board may report 0 modes */
+ usleep(kDelayAfterUeventUs);
+ hotplug_handler_();
+ }
+ }
+}
+} // namespace android
diff --git a/drm/DrmEventListener.h b/drm/UEventListener.h
index 9f9a4ba..c8b8582 100644
--- a/drm/DrmEventListener.h
+++ b/drm/UEventListener.h
@@ -14,51 +14,34 @@
* limitations under the License.
*/
-#ifndef ANDROID_DRM_EVENT_LISTENER_H_
-#define ANDROID_DRM_EVENT_LISTENER_H_
+#ifndef ANDROID_UEVENT_LISTENER_H_
+#define ANDROID_UEVENT_LISTENER_H_
-#include "autofd.h"
+#include <functional>
+
+#include "utils/UEvent.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 {
+class UEventListener : public Worker {
public:
- DrmEventListener(DrmDevice *drm);
- virtual ~DrmEventListener() {
- }
+ UEventListener();
+ ~UEventListener() override = default;
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);
+ void RegisterHotplugHandler(std::function<void()> hotplug_handler) {
+ hotplug_handler_ = std::move(hotplug_handler);
+ }
protected:
- virtual void Routine();
+ void Routine() override;
private:
- void UEventHandler();
-
- fd_set fds_;
- UniqueFd uevent_fd_;
- int max_fd_ = -1;
+ std::unique_ptr<UEvent> uevent_;
- DrmDevice *drm_;
- std::unique_ptr<DrmEventHandler> hotplug_handler_;
+ std::function<void()> hotplug_handler_;
};
} // namespace android
diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp
index b2f7e5f..ed41189 100644
--- a/drm/VSyncWorker.cpp
+++ b/drm/VSyncWorker.cpp
@@ -18,44 +18,26 @@
#include "VSyncWorker.h"
-#include <log/log.h>
-#include <stdlib.h>
-#include <time.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
-namespace android {
-
-VSyncWorker::VSyncWorker()
- : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY),
- drm_(NULL),
- display_(-1),
- enabled_(false),
- last_timestamp_(-1) {
-}
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
-VSyncWorker::~VSyncWorker() {
-}
+#include "utils/log.h"
-int VSyncWorker::Init(DrmDevice *drm, int display) {
- drm_ = drm;
- display_ = display;
+namespace android {
- return InitWorker();
-}
+VSyncWorker::VSyncWorker() : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY){};
-void VSyncWorker::RegisterCallback(std::shared_ptr<VsyncCallback> callback) {
- Lock();
- callback_ = callback;
- Unlock();
-}
+auto VSyncWorker::Init(DrmDisplayPipeline *pipe,
+ std::function<void(uint64_t /*timestamp*/)> callback)
+ -> int {
+ pipe_ = pipe;
+ callback_ = std::move(callback);
-void VSyncWorker::RegisterClientCallback(hwc2_callback_data_t data,
- hwc2_function_pointer_t hook) {
- Lock();
- vsync_callback_data_ = data;
- vsync_callback_hook_ = reinterpret_cast<HWC2_PFN_VSYNC>(hook);
- Unlock();
+ return InitWorker();
}
void VSyncWorker::VSyncControl(bool enabled) {
@@ -80,7 +62,7 @@ void VSyncWorker::VSyncControl(bool enabled) {
* 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) {
+int64_t VSyncWorker::GetPhasedVSync(int64_t frame_ns, int64_t current) const {
if (last_timestamp_ < 0)
return current + frame_ns;
@@ -88,28 +70,29 @@ int64_t VSyncWorker::GetPhasedVSync(int64_t frame_ns, int64_t current) {
last_timestamp_;
}
-static const int64_t kOneSecondNs = 1 * 1000 * 1000 * 1000;
+static const int64_t kOneSecondNs = 1LL * 1000 * 1000 * 1000;
int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) {
- struct timespec vsync;
+ struct timespec vsync {};
int ret = clock_gettime(CLOCK_MONOTONIC, &vsync);
+ if (ret)
+ return ret;
- 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);
+ float refresh = 60.0F; // Default to 60Hz refresh rate
+ if (pipe_ != nullptr &&
+ pipe_->connector->Get()->GetActiveMode().v_refresh() != 0.0F) {
+ refresh = pipe_->connector->Get()->GetActiveMode().v_refresh();
+ }
- int64_t phased_timestamp = GetPhasedVSync(kOneSecondNs / refresh,
+ int64_t phased_timestamp = GetPhasedVSync(kOneSecondNs /
+ static_cast<int>(refresh),
vsync.tv_sec * kOneSecondNs +
vsync.tv_nsec);
vsync.tv_sec = phased_timestamp / kOneSecondNs;
- vsync.tv_nsec = phased_timestamp - (vsync.tv_sec * kOneSecondNs);
+ vsync.tv_nsec = int(phased_timestamp - (vsync.tv_sec * kOneSecondNs));
do {
- ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &vsync, NULL);
- } while (ret == -1 && errno == EINTR);
+ ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &vsync, nullptr);
+ } while (ret == EINTR);
if (ret)
return ret;
@@ -118,7 +101,7 @@ int VSyncWorker::SyntheticWaitVBlank(int64_t *timestamp) {
}
void VSyncWorker::Routine() {
- int ret;
+ int ret = 0;
Lock();
if (!enabled_) {
@@ -129,28 +112,28 @@ void VSyncWorker::Routine() {
}
}
- int display = display_;
- std::shared_ptr<VsyncCallback> callback(callback_);
+ auto *pipe = pipe_;
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);
+ ret = -EAGAIN;
+ int64_t timestamp = 0;
+ drmVBlank vblank{};
- 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;
+ if (pipe != nullptr) {
+ uint32_t high_crtc = (pipe->crtc->Get()->GetIndexInResArray()
+ << DRM_VBLANK_HIGH_CRTC_SHIFT);
- int64_t timestamp;
- ret = drmWaitVBlank(drm_->fd(), &vblank);
- if (ret == -EINTR) {
- return;
- } else if (ret) {
+ vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE |
+ (high_crtc &
+ DRM_VBLANK_HIGH_CRTC_MASK));
+ vblank.request.sequence = 1;
+
+ ret = drmWaitVBlank(pipe->device->GetFd(), &vblank);
+ if (ret == -EINTR)
+ return;
+ }
+
+ if (ret) {
ret = SyntheticWaitVBlank(&timestamp);
if (ret)
return;
@@ -162,13 +145,9 @@ void VSyncWorker::Routine() {
if (!enabled_)
return;
- if (callback)
- callback->Callback(display, timestamp);
-
- Lock();
- if (enabled_ && vsync_callback_hook_ && vsync_callback_data_)
- vsync_callback_hook_(vsync_callback_data_, display, timestamp);
- Unlock();
+ if (callback_) {
+ callback_(timestamp);
+ }
last_timestamp_ = timestamp;
}
diff --git a/drm/VSyncWorker.h b/drm/VSyncWorker.h
index 7454b51..1e6d39f 100644
--- a/drm/VSyncWorker.h
+++ b/drm/VSyncWorker.h
@@ -20,8 +20,10 @@
#include <hardware/hardware.h>
#include <hardware/hwcomposer.h>
#include <hardware/hwcomposer2.h>
-#include <stdint.h>
+#include <atomic>
+#include <cstdint>
+#include <functional>
#include <map>
#include "DrmDevice.h"
@@ -29,22 +31,13 @@
namespace android {
-class VsyncCallback {
- public:
- virtual ~VsyncCallback() {
- }
- virtual void Callback(int display, int64_t timestamp) = 0;
-};
-
class VSyncWorker : public Worker {
public:
VSyncWorker();
- ~VSyncWorker() override;
+ ~VSyncWorker() override = default;
- int Init(DrmDevice *drm, int display);
- void RegisterCallback(std::shared_ptr<VsyncCallback> callback);
- void RegisterClientCallback(hwc2_callback_data_t data,
- hwc2_function_pointer_t hook);
+ auto Init(DrmDisplayPipeline *pipe,
+ std::function<void(uint64_t /*timestamp*/)> callback) -> int;
void VSyncControl(bool enabled);
@@ -52,22 +45,14 @@ class VSyncWorker : public Worker {
void Routine() override;
private:
- int64_t GetPhasedVSync(int64_t frame_ns, int64_t current);
+ int64_t GetPhasedVSync(int64_t frame_ns, int64_t current) const;
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<VsyncCallback> callback_ = NULL;
-
- int display_;
- std::atomic_bool enabled_;
- int64_t last_timestamp_;
+ std::function<void(uint64_t /*timestamp*/)> callback_;
- hwc2_callback_data_t vsync_callback_data_ = NULL;
- HWC2_PFN_VSYNC vsync_callback_hook_ = NULL;
+ DrmDisplayPipeline *pipe_ = nullptr;
+ std::atomic_bool enabled_ = false;
+ int64_t last_timestamp_ = -1;
};
} // namespace android