blob: 8062b2c2811112db344feb2fd43e0a6115cdaee4 [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
Sean Paul468a7542024-07-16 19:50:58 +000017#define LOG_TAG "drmhwc"
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +020018
19#include "DrmDisplayPipeline.h"
20
Roman Stratiienko4e994052022-02-09 17:40:35 +020021#include "DrmAtomicStateManager.h"
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +020022#include "DrmConnector.h"
23#include "DrmCrtc.h"
24#include "DrmDevice.h"
25#include "DrmEncoder.h"
26#include "DrmPlane.h"
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +020027#include "utils/log.h"
Roman Stratiienko19c162f2022-02-01 09:35:08 +020028#include "utils/properties.h"
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +020029
30namespace android {
31
32template <class O>
33auto PipelineBindable<O>::BindPipeline(DrmDisplayPipeline *pipeline,
34 bool return_object_if_bound)
35 -> std::shared_ptr<BindingOwner<O>> {
36 auto owner_object = owner_object_.lock();
37 if (owner_object) {
38 if (bound_pipeline_ == pipeline && return_object_if_bound) {
39 return owner_object;
40 }
41
42 return {};
43 }
44 owner_object = std::make_shared<BindingOwner<O>>(static_cast<O *>(this));
45
Roman Stratiienko33a71fa2022-02-02 12:53:14 +020046 owner_object_ = owner_object;
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +020047 bound_pipeline_ = pipeline;
48 return owner_object;
49}
50
51static auto TryCreatePipeline(DrmDevice &dev, DrmConnector &connector,
52 DrmEncoder &enc, DrmCrtc &crtc)
53 -> std::unique_ptr<DrmDisplayPipeline> {
54 /* Check if resources are available */
55
56 auto pipe = std::make_unique<DrmDisplayPipeline>();
57 pipe->device = &dev;
58
59 pipe->connector = connector.BindPipeline(pipe.get());
60 pipe->encoder = enc.BindPipeline(pipe.get());
61 pipe->crtc = crtc.BindPipeline(pipe.get());
62
63 if (!pipe->connector || !pipe->encoder || !pipe->crtc) {
64 return {};
65 }
66
67 std::vector<DrmPlane *> primary_planes;
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +020068
69 /* Attach necessary resources */
70 auto display_planes = std::vector<DrmPlane *>();
71 for (const auto &plane : dev.GetPlanes()) {
72 if (plane->IsCrtcSupported(crtc)) {
Andrew Wolfers7979d2a2025-02-27 14:44:41 +000073 switch (plane->GetType()) {
74 case DRM_PLANE_TYPE_PRIMARY:
75 primary_planes.emplace_back(plane.get());
76 break;
77 case DRM_PLANE_TYPE_OVERLAY:
78 case DRM_PLANE_TYPE_CURSOR:
79 break;
80 default:
81 ALOGE("Unknown type for plane %d", plane->GetId());
82 break;
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +020083 }
84 }
85 }
86
87 if (primary_planes.empty()) {
88 ALOGE("Primary plane for CRTC %d not found", crtc.GetId());
89 return {};
90 }
91
Roman Stratiienkoce2ce752022-09-29 19:55:01 +030092 for (const auto &plane : primary_planes) {
93 pipe->primary_plane = plane->BindPipeline(pipe.get());
94 if (pipe->primary_plane) {
95 break;
96 }
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +020097 }
98
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +020099 if (!pipe->primary_plane) {
Roman Stratiienkoce2ce752022-09-29 19:55:01 +0300100 ALOGE("Failed to bind primary plane");
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +0200101 return {};
102 }
103
Roman Stratiienkof818d4c2022-12-28 20:12:19 +0200104 pipe->atomic_state_manager = DrmAtomicStateManager::CreateInstance(
Roman Stratiienko4e994052022-02-09 17:40:35 +0200105 pipe.get());
Roman Stratiienko19c162f2022-02-01 09:35:08 +0200106
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +0200107 return pipe;
108}
109
110static auto TryCreatePipelineUsingEncoder(DrmDevice &dev, DrmConnector &conn,
111 DrmEncoder &enc)
112 -> std::unique_ptr<DrmDisplayPipeline> {
113 /* First try to use the currently-bound crtc */
114 auto *crtc = dev.FindCrtcById(enc.GetCurrentCrtcId());
115 if (crtc != nullptr) {
116 auto pipeline = TryCreatePipeline(dev, conn, enc, *crtc);
117 if (pipeline) {
118 return pipeline;
119 }
120 }
121
122 /* Try to find a possible crtc which will work */
123 for (const auto &crtc : dev.GetCrtcs()) {
124 if (enc.SupportsCrtc(*crtc)) {
125 auto pipeline = TryCreatePipeline(dev, conn, enc, *crtc);
126 if (pipeline) {
127 return pipeline;
128 }
129 }
130 }
131
132 /* We can't use this encoder, but nothing went wrong, try another one */
133 return {};
134}
135
136auto DrmDisplayPipeline::CreatePipeline(DrmConnector &connector)
137 -> std::unique_ptr<DrmDisplayPipeline> {
138 auto &dev = connector.GetDev();
139 /* Try to use current setup first */
140 auto *encoder = dev.FindEncoderById(connector.GetCurrentEncoderId());
141
142 if (encoder != nullptr) {
143 auto pipeline = TryCreatePipelineUsingEncoder(dev, connector, *encoder);
144 if (pipeline) {
145 return pipeline;
146 }
147 }
148
149 for (const auto &enc : dev.GetEncoders()) {
150 if (connector.SupportsEncoder(*enc)) {
151 auto pipeline = TryCreatePipelineUsingEncoder(dev, connector, *enc);
152 if (pipeline) {
153 return pipeline;
154 }
155 }
156 }
157
158 ALOGE("Could not find a suitable encoder/crtc for connector %s",
159 connector.GetName().c_str());
160
161 return {};
162}
163
Andrew Wolfers7979d2a2025-02-27 14:44:41 +0000164auto DrmDisplayPipeline::GetUsablePlanes() -> UsablePlanes {
165 UsablePlanes pair;
166 auto &[planes, cursor] = pair;
167
Roman Stratiienko9362cef2022-02-02 09:53:50 +0200168 planes.emplace_back(primary_plane);
169
Andrew Wolfers7979d2a2025-02-27 14:44:41 +0000170 for (const auto &plane : device->GetPlanes()) {
171 if (plane->IsCrtcSupported(*crtc->Get())) {
172 if (Properties::UseOverlayPlanes() &&
173 plane->GetType() == DRM_PLANE_TYPE_OVERLAY) {
174 auto op = plane->BindPipeline(this, true);
175 if (op) {
176 planes.emplace_back(op);
177 }
178 } else if (plane->GetType() == DRM_PLANE_TYPE_CURSOR) {
179 if (cursor) {
180 ALOGW(
181 "Encountered multiple cursor planes for CRTC %d. Ignoring "
182 "plane %d",
183 crtc->Get()->GetId(), plane->GetId());
184 } else {
185 cursor = plane->BindPipeline(this, true);
Roman Stratiienko9362cef2022-02-02 09:53:50 +0200186 }
187 }
188 }
189 }
190
Andrew Wolfers7979d2a2025-02-27 14:44:41 +0000191 return pair;
Roman Stratiienko9362cef2022-02-02 09:53:50 +0200192}
193
Roman Stratiienkof818d4c2022-12-28 20:12:19 +0200194DrmDisplayPipeline::~DrmDisplayPipeline() {
195 if (atomic_state_manager)
196 atomic_state_manager->StopThread();
197}
198
Roman Stratiienkocad8e0c2022-01-31 16:40:16 +0200199} // namespace android