blob: 69d28b3fc1cec6a04f269823680bd2e485e319d9 [file] [log] [blame]
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +02001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "hwc-drm-display-pipeline"
18
19#include "DrmDisplayPipeline.h"
20
21#include "DrmConnector.h"
22#include "DrmCrtc.h"
23#include "DrmDevice.h"
24#include "DrmEncoder.h"
25#include "DrmPlane.h"
26#include "compositor/DrmDisplayCompositor.h"
27#include "utils/log.h"
28
29namespace android {
30
31template <class O>
32auto PipelineBindable<O>::BindPipeline(DrmDisplayPipeline *pipeline,
33 bool return_object_if_bound)
34 -> std::shared_ptr<BindingOwner<O>> {
35 auto owner_object = owner_object_.lock();
36 if (owner_object) {
37 if (bound_pipeline_ == pipeline && return_object_if_bound) {
38 return owner_object;
39 }
40
41 return {};
42 }
43 owner_object = std::make_shared<BindingOwner<O>>(static_cast<O *>(this));
44
Roman Stratiienko33a71fa2022-02-02 12:53:14 +020045 owner_object_ = owner_object;
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +020046 bound_pipeline_ = pipeline;
47 return owner_object;
48}
49
50static auto TryCreatePipeline(DrmDevice &dev, DrmConnector &connector,
51 DrmEncoder &enc, DrmCrtc &crtc)
52 -> std::unique_ptr<DrmDisplayPipeline> {
53 /* Check if resources are available */
54
55 auto pipe = std::make_unique<DrmDisplayPipeline>();
56 pipe->device = &dev;
57
58 pipe->connector = connector.BindPipeline(pipe.get());
59 pipe->encoder = enc.BindPipeline(pipe.get());
60 pipe->crtc = crtc.BindPipeline(pipe.get());
61
62 if (!pipe->connector || !pipe->encoder || !pipe->crtc) {
63 return {};
64 }
65
66 std::vector<DrmPlane *> primary_planes;
67 std::vector<DrmPlane *> overlay_planes;
68
69 /* Attach necessary resources */
70 auto display_planes = std::vector<DrmPlane *>();
71 for (const auto &plane : dev.GetPlanes()) {
72 if (plane->IsCrtcSupported(crtc)) {
73 if (plane->GetType() == DRM_PLANE_TYPE_PRIMARY) {
74 primary_planes.emplace_back(plane.get());
75 } else if (plane->GetType() == DRM_PLANE_TYPE_OVERLAY) {
76 overlay_planes.emplace_back(plane.get());
77 } else {
78 ALOGI("Ignoring cursor plane %d", plane->GetId());
79 }
80 }
81 }
82
83 if (primary_planes.empty()) {
84 ALOGE("Primary plane for CRTC %d not found", crtc.GetId());
85 return {};
86 }
87
88 if (primary_planes.size() > 1) {
89 ALOGE("Found more than 1 primary plane for CRTC %d", crtc.GetId());
90 return {};
91 }
92
93 pipe->primary_plane = primary_planes[0]->BindPipeline(pipe.get());
94 if (!pipe->primary_plane) {
95 ALOGE("Primary plane %d is already owned. Internal error.",
96 primary_planes[0]->GetId());
97 return {};
98 }
99
100 bool use_overlay_planes = true; // TODO(rsglobal): restore
101 // strtol(use_overlay_planes_prop, nullptr,
102 // 10);
103 if (use_overlay_planes) {
104 for (auto *plane : overlay_planes) {
105 auto op = plane->BindPipeline(pipe.get());
106 if (op) {
107 pipe->overlay_planes.emplace_back(op);
108 }
109 }
110 }
111
112 return pipe;
113}
114
115static auto TryCreatePipelineUsingEncoder(DrmDevice &dev, DrmConnector &conn,
116 DrmEncoder &enc)
117 -> std::unique_ptr<DrmDisplayPipeline> {
118 /* First try to use the currently-bound crtc */
119 auto *crtc = dev.FindCrtcById(enc.GetCurrentCrtcId());
120 if (crtc != nullptr) {
121 auto pipeline = TryCreatePipeline(dev, conn, enc, *crtc);
122 if (pipeline) {
123 return pipeline;
124 }
125 }
126
127 /* Try to find a possible crtc which will work */
128 for (const auto &crtc : dev.GetCrtcs()) {
129 if (enc.SupportsCrtc(*crtc)) {
130 auto pipeline = TryCreatePipeline(dev, conn, enc, *crtc);
131 if (pipeline) {
132 return pipeline;
133 }
134 }
135 }
136
137 /* We can't use this encoder, but nothing went wrong, try another one */
138 return {};
139}
140
141auto DrmDisplayPipeline::CreatePipeline(DrmConnector &connector)
142 -> std::unique_ptr<DrmDisplayPipeline> {
143 auto &dev = connector.GetDev();
144 /* Try to use current setup first */
145 auto *encoder = dev.FindEncoderById(connector.GetCurrentEncoderId());
146
147 if (encoder != nullptr) {
148 auto pipeline = TryCreatePipelineUsingEncoder(dev, connector, *encoder);
149 if (pipeline) {
150 return pipeline;
151 }
152 }
153
154 for (const auto &enc : dev.GetEncoders()) {
155 if (connector.SupportsEncoder(*enc)) {
156 auto pipeline = TryCreatePipelineUsingEncoder(dev, connector, *enc);
157 if (pipeline) {
158 return pipeline;
159 }
160 }
161 }
162
163 ALOGE("Could not find a suitable encoder/crtc for connector %s",
164 connector.GetName().c_str());
165
166 return {};
167}
168
169} // namespace android