diff options
Diffstat (limited to 'drm')
-rw-r--r-- | drm/DrmConnector.h | 2 | ||||
-rw-r--r-- | drm/DrmCrtc.h | 3 | ||||
-rw-r--r-- | drm/DrmDevice.cpp | 124 | ||||
-rw-r--r-- | drm/DrmDevice.h | 10 | ||||
-rw-r--r-- | drm/DrmDisplayPipeline.cpp | 168 | ||||
-rw-r--r-- | drm/DrmDisplayPipeline.h | 86 | ||||
-rw-r--r-- | drm/DrmEncoder.h | 3 | ||||
-rw-r--r-- | drm/DrmPlane.h | 2 |
8 files changed, 291 insertions, 107 deletions
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; |