xref: /aosp_15_r20/external/drm_hwcomposer/drm/DrmDisplayPipeline.cpp (revision 0a9764fe0a15e71ebbeb85e87e10990c23aab47f)
1 /*
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 "drmhwc"
18 
19 #include "DrmDisplayPipeline.h"
20 
21 #include "DrmAtomicStateManager.h"
22 #include "DrmConnector.h"
23 #include "DrmCrtc.h"
24 #include "DrmDevice.h"
25 #include "DrmEncoder.h"
26 #include "DrmPlane.h"
27 #include "utils/log.h"
28 #include "utils/properties.h"
29 
30 namespace android {
31 
32 template <class O>
BindPipeline(DrmDisplayPipeline * pipeline,bool return_object_if_bound)33 auto 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 
46   owner_object_ = owner_object;
47   bound_pipeline_ = pipeline;
48   return owner_object;
49 }
50 
TryCreatePipeline(DrmDevice & dev,DrmConnector & connector,DrmEncoder & enc,DrmCrtc & crtc)51 static 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;
68   std::vector<DrmPlane *> overlay_planes;
69 
70   /* Attach necessary resources */
71   auto display_planes = std::vector<DrmPlane *>();
72   for (const auto &plane : dev.GetPlanes()) {
73     if (plane->IsCrtcSupported(crtc)) {
74       if (plane->GetType() == DRM_PLANE_TYPE_PRIMARY) {
75         primary_planes.emplace_back(plane.get());
76       } else if (plane->GetType() == DRM_PLANE_TYPE_OVERLAY) {
77         overlay_planes.emplace_back(plane.get());
78       } else {
79         ALOGI("Ignoring cursor plane %d", plane->GetId());
80       }
81     }
82   }
83 
84   if (primary_planes.empty()) {
85     ALOGE("Primary plane for CRTC %d not found", crtc.GetId());
86     return {};
87   }
88 
89   for (const auto &plane : primary_planes) {
90     pipe->primary_plane = plane->BindPipeline(pipe.get());
91     if (pipe->primary_plane) {
92       break;
93     }
94   }
95 
96   if (!pipe->primary_plane) {
97     ALOGE("Failed to bind primary plane");
98     return {};
99   }
100 
101   pipe->atomic_state_manager = DrmAtomicStateManager::CreateInstance(
102       pipe.get());
103 
104   return pipe;
105 }
106 
TryCreatePipelineUsingEncoder(DrmDevice & dev,DrmConnector & conn,DrmEncoder & enc)107 static auto TryCreatePipelineUsingEncoder(DrmDevice &dev, DrmConnector &conn,
108                                           DrmEncoder &enc)
109     -> std::unique_ptr<DrmDisplayPipeline> {
110   /* First try to use the currently-bound crtc */
111   auto *crtc = dev.FindCrtcById(enc.GetCurrentCrtcId());
112   if (crtc != nullptr) {
113     auto pipeline = TryCreatePipeline(dev, conn, enc, *crtc);
114     if (pipeline) {
115       return pipeline;
116     }
117   }
118 
119   /* Try to find a possible crtc which will work */
120   for (const auto &crtc : dev.GetCrtcs()) {
121     if (enc.SupportsCrtc(*crtc)) {
122       auto pipeline = TryCreatePipeline(dev, conn, enc, *crtc);
123       if (pipeline) {
124         return pipeline;
125       }
126     }
127   }
128 
129   /* We can't use this encoder, but nothing went wrong, try another one */
130   return {};
131 }
132 
CreatePipeline(DrmConnector & connector)133 auto DrmDisplayPipeline::CreatePipeline(DrmConnector &connector)
134     -> std::unique_ptr<DrmDisplayPipeline> {
135   auto &dev = connector.GetDev();
136   /* Try to use current setup first */
137   auto *encoder = dev.FindEncoderById(connector.GetCurrentEncoderId());
138 
139   if (encoder != nullptr) {
140     auto pipeline = TryCreatePipelineUsingEncoder(dev, connector, *encoder);
141     if (pipeline) {
142       return pipeline;
143     }
144   }
145 
146   for (const auto &enc : dev.GetEncoders()) {
147     if (connector.SupportsEncoder(*enc)) {
148       auto pipeline = TryCreatePipelineUsingEncoder(dev, connector, *enc);
149       if (pipeline) {
150         return pipeline;
151       }
152     }
153   }
154 
155   ALOGE("Could not find a suitable encoder/crtc for connector %s",
156         connector.GetName().c_str());
157 
158   return {};
159 }
160 
ReadUseOverlayProperty()161 static bool ReadUseOverlayProperty() {
162   char use_overlay_planes_prop[PROPERTY_VALUE_MAX];
163   property_get("vendor.hwc.drm.use_overlay_planes", use_overlay_planes_prop,
164                "1");
165   constexpr int kStrtolBase = 10;
166   return strtol(use_overlay_planes_prop, nullptr, kStrtolBase) != 0;
167 }
168 
GetUsablePlanes()169 auto DrmDisplayPipeline::GetUsablePlanes()
170     -> std::vector<std::shared_ptr<BindingOwner<DrmPlane>>> {
171   std::vector<std::shared_ptr<BindingOwner<DrmPlane>>> planes;
172   planes.emplace_back(primary_plane);
173 
174   const static bool kUseOverlayPlanes = ReadUseOverlayProperty();
175 
176   if (kUseOverlayPlanes) {
177     for (const auto &plane : device->GetPlanes()) {
178       if (plane->IsCrtcSupported(*crtc->Get())) {
179         if (plane->GetType() == DRM_PLANE_TYPE_OVERLAY) {
180           auto op = plane->BindPipeline(this, true);
181           if (op) {
182             planes.emplace_back(op);
183           }
184         }
185       }
186     }
187   }
188 
189   return planes;
190 }
191 
~DrmDisplayPipeline()192 DrmDisplayPipeline::~DrmDisplayPipeline() {
193   if (atomic_state_manager)
194     atomic_state_manager->StopThread();
195 }
196 
197 }  // namespace android
198