aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoman Stratiienko <roman.o.stratiienko@globallogic.com>2022-01-31 16:40:16 +0200
committerRoman Stratiienko <roman.o.stratiienko@globallogic.com>2022-01-31 21:48:40 +0200
commitcad8e0ca57c268d179730c8ef68edd31350a11d9 (patch)
tree04ae9a13759d8076c5ffbf54ed475485f0790726
parent7d89911c32c5ccc74e69349212713f02bfc95aef (diff)
downloaddrm_hwcomposer-cad8e0ca57c268d179730c8ef68edd31350a11d9.tar.gz
drm_hwcomposer: Introduce DrmDisplayPipeline class
Create systematic way of binding DRM objects (Crtc,Encoder,Planes...) to the pipeline using RAII. Use it to create the pipeline. + Allow pipeline creation to fail. Closes: https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/-/issues/14 Signed-off-by: Roman Stratiienko <roman.o.stratiienko@globallogic.com>
-rw-r--r--Android.bp1
-rw-r--r--drm/DrmConnector.h2
-rw-r--r--drm/DrmCrtc.h3
-rw-r--r--drm/DrmDevice.cpp124
-rw-r--r--drm/DrmDevice.h10
-rw-r--r--drm/DrmDisplayPipeline.cpp168
-rw-r--r--drm/DrmDisplayPipeline.h86
-rw-r--r--drm/DrmEncoder.h3
-rw-r--r--drm/DrmPlane.h2
9 files changed, 292 insertions, 107 deletions
diff --git a/Android.bp b/Android.bp
index b3bceaa..9236b3e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -91,6 +91,7 @@ filegroup {
"drm/DrmConnector.cpp",
"drm/DrmCrtc.cpp",
"drm/DrmDevice.cpp",
+ "drm/DrmDisplayPipeline.cpp",
"drm/DrmEncoder.cpp",
"drm/DrmFbImporter.cpp",
"drm/DrmMode.cpp",
diff --git a/drm/DrmConnector.h b/drm/DrmConnector.h
index 5f8ba88..629b3cc 100644
--- a/drm/DrmConnector.h
+++ b/drm/DrmConnector.h
@@ -32,7 +32,7 @@ namespace android {
class DrmDevice;
-class DrmConnector {
+class DrmConnector : public PipelineBindable<DrmConnector> {
public:
static auto CreateInstance(DrmDevice &dev, uint32_t connector_id,
uint32_t index) -> std::unique_ptr<DrmConnector>;
diff --git a/drm/DrmCrtc.h b/drm/DrmCrtc.h
index 42fc9f9..ebf0a97 100644
--- a/drm/DrmCrtc.h
+++ b/drm/DrmCrtc.h
@@ -21,6 +21,7 @@
#include <cstdint>
+#include "DrmDisplayPipeline.h"
#include "DrmMode.h"
#include "DrmProperty.h"
#include "DrmUnique.h"
@@ -29,7 +30,7 @@ namespace android {
class DrmDevice;
-class DrmCrtc {
+class DrmCrtc : public PipelineBindable<DrmCrtc> {
public:
static auto CreateInstance(DrmDevice &dev, uint32_t crtc_id, uint32_t index)
-> std::unique_ptr<DrmCrtc>;
diff --git a/drm/DrmDevice.cpp b/drm/DrmDevice.cpp
index 29dd95f..ece9437 100644
--- a/drm/DrmDevice.cpp
+++ b/drm/DrmDevice.cpp
@@ -66,7 +66,6 @@ std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
if (ret != 0) {
ALOGI("Failed to set writeback cap %d", ret);
- ret = 0;
}
#endif
@@ -125,14 +124,31 @@ std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
}
}
+ auto plane_res = MakeDrmModePlaneResUnique(GetFd());
+ if (!plane_res) {
+ ALOGE("Failed to get plane resources");
+ return std::make_tuple(-ENOENT, 0);
+ }
+
+ for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ auto plane = DrmPlane::CreateInstance(*this, plane_res->planes[i]);
+
+ if (plane) {
+ planes_.emplace_back(std::move(plane));
+ }
+ }
+
auto add_displays = [this, &num_displays](bool internal, bool connected) {
for (auto &conn : connectors_) {
bool is_connected = conn->IsConnected();
if ((internal ? conn->IsInternal() : conn->IsExternal()) &&
(connected ? is_connected : !is_connected)) {
- bound_connectors_[num_displays] = conn.get();
- connectors_to_display_id_[conn.get()] = num_displays;
- ++num_displays;
+ auto pipe = DrmDisplayPipeline::CreatePipeline(*conn);
+ if (pipe) {
+ pipelines_[num_displays] = std::move(pipe);
+ ++num_displays;
+ }
}
}
};
@@ -145,110 +161,28 @@ std::tuple<int, int> DrmDevice::Init(const char *path, int num_displays) {
add_displays(/*internal = */ true, /*connected = */ false);
add_displays(/*internal = */ false, /*connected = */ false);
- // Catch-all for the above loops
- if (ret != 0)
- return std::make_tuple(ret, 0);
-
- auto plane_res = MakeDrmModePlaneResUnique(GetFd());
- if (!plane_res) {
- ALOGE("Failed to get plane resources");
- return std::make_tuple(-ENOENT, 0);
- }
-
- for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- auto plane = DrmPlane::CreateInstance(*this, plane_res->planes[i]);
-
- if (plane) {
- planes_.emplace_back(std::move(plane));
- }
- }
-
- for (auto &conn : connectors_) {
- ret = CreateDisplayPipe(conn.get());
- if (ret != 0) {
- ALOGE("Failed CreateDisplayPipe %d with %d", conn->GetId(), ret);
- return std::make_tuple(ret, 0);
- }
- }
- return std::make_tuple(ret, bound_connectors_.size());
+ return std::make_tuple(0, pipelines_.size());
}
bool DrmDevice::HandlesDisplay(int display) const {
- return bound_connectors_.count(display) != 0;
+ return pipelines_.count(display) != 0;
}
DrmConnector *DrmDevice::GetConnectorForDisplay(int display) const {
- return bound_connectors_.at(display);
+ return pipelines_.at(display)->connector->Get();
}
DrmCrtc *DrmDevice::GetCrtcForDisplay(int display) const {
- return bound_crtcs_.at(display);
+ return pipelines_.at(display)->crtc->Get();
}
-int DrmDevice::TryEncoderForDisplay(int display, DrmEncoder *enc) {
- /* First try to use the currently-bound crtc */
- auto *crtc = FindCrtcById(enc->GetCurrentCrtcId());
- if (crtc != nullptr && bound_crtcs_.count(display) == 0) {
- bound_crtcs_[display] = crtc;
- bound_encoders_[crtc] = enc;
- return 0;
- }
-
- /* Try to find a possible crtc which will work */
- for (auto &crtc : crtcs_) {
- /* Crtc not supported or we've already tried this earlier */
- if (!enc->SupportsCrtc(*crtc) || crtc->GetId() == enc->GetCurrentCrtcId()) {
- continue;
- }
-
- if (bound_crtcs_.count(display) == 0) {
- bound_crtcs_[display] = crtc.get();
- bound_encoders_[crtc.get()] = enc;
- return 0;
- }
- }
-
- /* We can't use the encoder, but nothing went wrong, try another one */
- return -EAGAIN;
-}
-
-int DrmDevice::CreateDisplayPipe(DrmConnector *connector) {
- int display = connectors_to_display_id_.at(connector);
- /* Try to use current setup first */
- auto *enc0 = FindEncoderById(connector->GetCurrentEncoderId());
- if (enc0 != nullptr && encoders_to_display_id_.count(enc0) == 0) {
- int ret = TryEncoderForDisplay(display, enc0);
- if (ret == 0) {
- encoders_to_display_id_[enc0] = display;
- return 0;
- }
-
- if (ret != -EAGAIN) {
- ALOGE("Could not set mode %d/%d", display, ret);
- return ret;
- }
- }
-
- for (auto &enc : encoders_) {
- if (!connector->SupportsEncoder(*enc) ||
- encoders_to_display_id_.count(enc.get()) != 0) {
- continue;
- }
-
- int ret = TryEncoderForDisplay(display, enc.get());
- if (ret == 0) {
- encoders_to_display_id_[enc.get()] = display;
- return 0;
- }
-
- if (ret != -EAGAIN) {
- ALOGE("Could not set mode %d/%d", display, ret);
- return ret;
+auto DrmDevice::GetDisplayId(DrmConnector *conn) -> int {
+ for (auto &dpipe : pipelines_) {
+ if (dpipe.second->connector->Get() == conn) {
+ return dpipe.first;
}
}
- ALOGE("Could not find a suitable encoder/crtc for display %d", display);
- return -ENODEV;
+ return -1;
}
auto DrmDevice::RegisterUserPropertyBlob(void *data, size_t length) const
diff --git a/drm/DrmDevice.h b/drm/DrmDevice.h
index 6d792c2..8d9a34c 100644
--- a/drm/DrmDevice.h
+++ b/drm/DrmDevice.h
@@ -96,9 +96,7 @@ class DrmDevice {
return nullptr;
}
- auto GetDisplayId(DrmConnector *conn) {
- return connectors_to_display_id_.at(conn);
- }
+ auto GetDisplayId(DrmConnector *conn) -> int;
int GetProperty(uint32_t obj_id, uint32_t obj_type, const char *prop_name,
DrmProperty *property) const;
@@ -119,11 +117,7 @@ class DrmDevice {
std::pair<uint32_t, uint32_t> min_resolution_;
std::pair<uint32_t, uint32_t> max_resolution_;
- std::map<int /*display*/, DrmCrtc *> bound_crtcs_;
- std::map<int /*display*/, DrmConnector *> bound_connectors_;
- std::map<DrmConnector *, int /*display*/> connectors_to_display_id_;
- std::map<DrmEncoder *, int /*display*/> encoders_to_display_id_;
- std::map<DrmCrtc *, DrmEncoder *> bound_encoders_;
+ std::map<int /*display*/, std::unique_ptr<DrmDisplayPipeline>> pipelines_;
bool HasAddFb2ModifiersSupport_{};
diff --git a/drm/DrmDisplayPipeline.cpp b/drm/DrmDisplayPipeline.cpp
new file mode 100644
index 0000000..8a490f8
--- /dev/null
+++ b/drm/DrmDisplayPipeline.cpp
@@ -0,0 +1,168 @@
+/*
+ * 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 "DrmConnector.h"
+#include "DrmCrtc.h"
+#include "DrmDevice.h"
+#include "DrmEncoder.h"
+#include "DrmPlane.h"
+#include "compositor/DrmDisplayCompositor.h"
+#include "utils/log.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));
+
+ 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 {};
+ }
+
+ bool use_overlay_planes = true; // TODO(rsglobal): restore
+ // strtol(use_overlay_planes_prop, nullptr,
+ // 10);
+ if (use_overlay_planes) {
+ for (auto *plane : overlay_planes) {
+ auto op = plane->BindPipeline(pipe.get());
+ if (op) {
+ pipe->overlay_planes.emplace_back(op);
+ }
+ }
+ }
+
+ 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 {};
+}
+
+} // namespace android
diff --git a/drm/DrmDisplayPipeline.h b/drm/DrmDisplayPipeline.h
new file mode 100644
index 0000000..cb5b9e2
--- /dev/null
+++ b/drm/DrmDisplayPipeline.h
@@ -0,0 +1,86 @@
+/*
+ * 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 DrmDisplayCompositor;
+
+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>;
+
+ 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::vector<std::shared_ptr<BindingOwner<DrmPlane>>> overlay_planes;
+};
+
+} // namespace android
+
+#endif
diff --git a/drm/DrmEncoder.h b/drm/DrmEncoder.h
index e66d6f1..39a695c 100644
--- a/drm/DrmEncoder.h
+++ b/drm/DrmEncoder.h
@@ -24,10 +24,11 @@
#include <vector>
#include "DrmCrtc.h"
+#include "DrmDisplayPipeline.h"
namespace android {
-class DrmEncoder {
+class DrmEncoder : public PipelineBindable<DrmEncoder> {
public:
static auto CreateInstance(DrmDevice &dev, uint32_t encoder_id,
uint32_t index) -> std::unique_ptr<DrmEncoder>;
diff --git a/drm/DrmPlane.h b/drm/DrmPlane.h
index 9826f67..65f458f 100644
--- a/drm/DrmPlane.h
+++ b/drm/DrmPlane.h
@@ -31,7 +31,7 @@ namespace android {
class DrmDevice;
struct DrmHwcLayer;
-class DrmPlane {
+class DrmPlane : public PipelineBindable<DrmPlane> {
public:
DrmPlane(const DrmPlane &) = delete;
DrmPlane &operator=(const DrmPlane &) = delete;