1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "hdi_drm_composition.h"
17 #include <cerrno>
18 #include "hdi_drm_layer.h"
19 
20 namespace OHOS {
21     namespace HDI {
22         namespace DISPLAY {
HdiDrmComposition(const std::shared_ptr<DrmConnector> &connector, const std::shared_ptr<DrmCrtc> &crtc, const std::shared_ptr<DrmDevice> &drmDevice)23             HdiDrmComposition::HdiDrmComposition(const std::shared_ptr<DrmConnector> &connector,
24                                                  const std::shared_ptr<DrmCrtc> &crtc,
25                                                  const std::shared_ptr<DrmDevice> &drmDevice)
26                 : mDrmDevice(drmDevice), mConnector(connector), mCrtc(crtc)
27             {
28                 DISPLAY_DEBUGLOG();
29             }
30 
Init()31             int32_t HdiDrmComposition::Init()
32             {
33                 DISPLAY_DEBUGLOG();
34                 mPrimPlanes.clear();
35                 mOverlayPlanes.clear();
36                 mPlanes.clear();
37                 DISPLAY_CHK_RETURN((mCrtc == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("crtc is null"));
38                 DISPLAY_CHK_RETURN((mConnector == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("connector is null"));
39                 DISPLAY_CHK_RETURN((mDrmDevice == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("drmDevice is null"));
40                 mPrimPlanes = mDrmDevice->GetDrmPlane(mCrtc->GetPipe(), DRM_PLANE_TYPE_PRIMARY);
41                 mOverlayPlanes = mDrmDevice->GetDrmPlane(mCrtc->GetPipe(), DRM_PLANE_TYPE_OVERLAY);
42                 mPlanes.insert(mPlanes.end(), mPrimPlanes.begin(), mPrimPlanes.end());
43                 mPlanes.insert(mPlanes.end(), mOverlayPlanes.begin(), mOverlayPlanes.end());
44                 return DISPLAY_SUCCESS;
45             }
46 
SetLayers(std::vector<HdiLayer *> &layers, HdiLayer &clientLayer)47             int32_t HdiDrmComposition::SetLayers(std::vector<HdiLayer *> &layers, HdiLayer &clientLayer)
48             {
49                 // now we do not surpport present direct
50                 DISPLAY_DEBUGLOG();
51                 mCompLayers.clear();
52                 mCompLayers.push_back(&clientLayer);
53                 return DISPLAY_SUCCESS;
54             }
55 
SetCrtcProperty(DrmPlane &drmPlane, drmModeAtomicReqPtr pset, int32_t bufferW, int32_t bufferH)56             int32_t HdiDrmComposition::SetCrtcProperty(DrmPlane &drmPlane, drmModeAtomicReqPtr pset, int32_t bufferW,
57                                                        int32_t bufferH)
58             {
59                 int ret;
60 
61                 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropCrtc_xId(), 0);
62                 DISPLAY_DEBUGLOG("set the fb planeid %{public}d, GetPropCrtc_xId %{public}d, crop.x %{public}d",
63                                  drmPlane.GetId(), drmPlane.GetPropCrtc_xId(), 0);
64                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
65                                    DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
66 
67                 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropCrtc_yId(), 0);
68                 DISPLAY_DEBUGLOG("set the fb planeid %{public}d, GetPropCrtc_yId %{public}d, crop.y %{public}d",
69                                  drmPlane.GetId(), drmPlane.GetPropCrtc_yId(), 0);
70                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
71                                    DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
72 
73                 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropCrtc_wId(), bufferW);
74                 DISPLAY_DEBUGLOG("set the fb planeid %{public}d, GetPropCrtc_wId %{public}d, crop.w %{public}d",
75                                  drmPlane.GetId(), drmPlane.GetPropCrtc_wId(), bufferW);
76                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
77                                    DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
78 
79                 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropCrtc_hId(), bufferH);
80                 DISPLAY_DEBUGLOG("set the fb planeid %{public}d, GetPropCrtc_hId %{public}d, crop.h %{public}d",
81                                  drmPlane.GetId(), drmPlane.GetPropCrtc_xId(), bufferH);
82                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
83                                    DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
84 
85                 return DISPLAY_SUCCESS;
86             }
87 
SetSrcProperty(DrmPlane &drmPlane, drmModeAtomicReqPtr pset, int32_t bufferW, int32_t bufferH)88             int32_t HdiDrmComposition::SetSrcProperty(DrmPlane &drmPlane, drmModeAtomicReqPtr pset, int32_t bufferW,
89                                                       int32_t bufferH)
90             {
91                 int ret;
92 
93                 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropSrc_xId(),
94                                                0 << 16); // 16:shift left 16 bits
95                 DISPLAY_DEBUGLOG("set the fb planeid %{public}d, GetPropSrc_xId %{public}d, displayRect.x %{public}d",
96                                  drmPlane.GetId(), drmPlane.GetPropSrc_xId(), 0);
97                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
98                                    DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
99 
100                 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropSrc_yId(),
101                                                0 << 16); // 16:shift left 16 bits
102                 DISPLAY_DEBUGLOG("set the fb planeid %{public}d, GetPropSrc_yId %{public}d, displayRect.y %{public}d",
103                                  drmPlane.GetId(), drmPlane.GetPropSrc_yId(), 0);
104                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
105                                    DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
106 
107                 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropSrc_wId(),
108                                                bufferW << 16); // 16:shift left 16 bits
109                 DISPLAY_DEBUGLOG("set the fb planeid %{public}d, GetPropCrtc_wId %{public}d, displayRect.w %{public}d",
110                                  drmPlane.GetId(), drmPlane.GetPropSrc_wId(), bufferW);
111                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
112                                    DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
113 
114                 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropSrc_hId(),
115                                                bufferH << 16); // 16:shift left 16 bits
116                 DISPLAY_DEBUGLOG("set the fb planeid %{public}d, GetPropSrc_hId %{public}d, displayRect.h %{public}d",
117                                  drmPlane.GetId(), drmPlane.GetPropSrc_hId(), bufferH);
118                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
119                                    DISPLAY_LOGE("set the fb planeid fialed errno : %{public}d", errno));
120 
121                 return DISPLAY_SUCCESS;
122             }
123 
ApplyPlane(HdiDrmLayer &layer, HdiLayer &hlayer, DrmPlane &drmPlane, drmModeAtomicReqPtr pset)124             int32_t HdiDrmComposition::ApplyPlane(HdiDrmLayer &layer, HdiLayer &hlayer, DrmPlane &drmPlane,
125                                                   drmModeAtomicReqPtr pset)
126             {
127                 int ret;
128                 int fenceFd = layer.GetAcquireFenceFd();
129                 int propId = drmPlane.GetPropFenceInId();
130                 HdiLayerBuffer *layerBuffer = hlayer.GetCurrentBuffer();
131                 int32_t bufferW = layerBuffer->GetWight();
132                 int32_t bufferH = layerBuffer->GetHeight();
133 
134                 DISPLAY_DEBUGLOG();
135                 if (propId != 0) {
136                     DISPLAY_DEBUGLOG("set the fence in prop");
137                     if (fenceFd >= 0) {
138                         ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), propId, fenceFd);
139                         DISPLAY_DEBUGLOG(
140                             "set the IfenceProp plane id %{public}d, propId %{public}d, fenceFd %{public}d",
141                             drmPlane.GetId(), propId, fenceFd);
142                         DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set IN_FENCE_FD failed"));
143                     }
144                 }
145 
146                 ret = SetCrtcProperty(drmPlane, pset, bufferW, bufferH);
147                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
148                                    DISPLAY_LOGE("set Crtc fialed errno : %{public}d", errno));
149 
150                 ret = SetSrcProperty(drmPlane, pset, bufferW, bufferH);
151                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
152                                    DISPLAY_LOGE("set Src fialed errno : %{public}d", errno));
153 
154                 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropZposId(), layer.GetZorder());
155                 DISPLAY_DEBUGLOG("set the fb planeid %{public}d, GetPropZposId %{public}d, zpos %{public}d",
156                                  drmPlane.GetId(), drmPlane.GetPropZposId(), layer.GetZorder());
157                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
158                                    DISPLAY_LOGE("set the zpos fialed errno : %{public}d", errno));
159 
160                 // set fb id
161                 DrmGemBuffer *gemBuffer = layer.GetGemBuffer();
162                 DISPLAY_CHK_RETURN((gemBuffer == nullptr), DISPLAY_FAILURE,
163                                    DISPLAY_LOGE("current gemBuffer is nullptr"));
164                 DISPLAY_CHK_RETURN((!gemBuffer->IsValid()), DISPLAY_FAILURE,
165                                    DISPLAY_LOGE("the DrmGemBuffer is invalid"));
166                 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropFbId(), gemBuffer->GetFbId());
167                 DISPLAY_DEBUGLOG("set the fb planeid %{public}d, propId %{public}d, fbId %{public}d", drmPlane.GetId(),
168                                  drmPlane.GetPropFbId(), gemBuffer->GetFbId());
169                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
170                                    DISPLAY_LOGE("set fb id fialed errno : %{public}d", errno));
171 
172                 // set crtc id
173                 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropCrtcId(), mCrtc->GetId());
174                 DISPLAY_DEBUGLOG("set the crtc planeId %{public}d, propId %{public}d, crtcId %{public}d",
175                                  drmPlane.GetId(), drmPlane.GetPropCrtcId(), mCrtc->GetId());
176                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
177                                    DISPLAY_LOGE("set crtc id fialed errno : %{public}d", errno));
178                 return DISPLAY_SUCCESS;
179             }
180 
UpdateMode(std::unique_ptr<DrmModeBlock> &modeBlock)181             int32_t HdiDrmComposition::UpdateMode(std::unique_ptr<DrmModeBlock> &modeBlock)
182             {
183                 // set the mode
184                 DISPLAY_DEBUGLOG();
185                 if (mCrtc->NeedModeSet()) {
186                     int drmFd = mDrmDevice->GetDrmFd();
187                     drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
188                     modeBlock = mConnector->GetModeBlockFromId(mCrtc->GetActiveModeId());
189                     if ((modeBlock != nullptr) && (modeBlock->GetBlockId() != DRM_INVALID_ID)) {
190                         // set to active
191                         DISPLAY_DEBUGLOG("set crtc to active");
192                         int ret = drmModeAtomicAddProperty(pset, mCrtc->GetId(), mCrtc->GetActivePropId(), 1);
193                         DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
194                                            DISPLAY_LOGE("can not add the active prop errno %{public}d", errno));
195 
196                         // set the mode id
197                         DISPLAY_DEBUGLOG("set the mode");
198                         ret = drmModeAtomicAddProperty(pset, mCrtc->GetId(), mCrtc->GetModePropId(),
199                                                        modeBlock->GetBlockId());
200                         DISPLAY_DEBUGLOG("set the mode planeId %{public}d, propId %{public}d, GetBlockId: %{public}d",
201                                          mCrtc->GetId(), mCrtc->GetModePropId(), modeBlock->GetBlockId());
202                         DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
203                                            DISPLAY_LOGE("can not add the mode prop errno %{public}d", errno));
204                         ret = drmModeAtomicAddProperty(pset, mConnector->GetId(), mConnector->GetPropCrtcId(),
205                                                        mCrtc->GetId());
206                         DISPLAY_DEBUGLOG("set the connector id: %{public}d, propId %{public}d, crtcId %{public}d",
207                                          mConnector->GetId(), mConnector->GetPropCrtcId(), mCrtc->GetId());
208                         DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
209                                            DISPLAY_LOGE("can not add the crtc id prop %{public}d", errno));
210 
211                         uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
212                         ret = drmModeAtomicCommit(drmFd, pset, flags, nullptr);
213                         DISPLAY_CHK_RETURN(
214                             (ret != 0), DISPLAY_FAILURE,
215                             DISPLAY_LOGE("drmModeAtomicCommit failed %{public}d errno %{public}d", ret, errno));
216                         mCrtc->ClearModeSet();
217                     }
218                 }
219                 return DISPLAY_SUCCESS;
220             }
221 
RemoveUnusePlane(drmModeAtomicReqPtr pset)222             int32_t HdiDrmComposition::RemoveUnusePlane(drmModeAtomicReqPtr pset)
223             {
224                 int ret = 0;
225                 /* Remove useless planes from the drm */
226                 for (uint32_t j = 0; j < mPlanes.size(); j++) {
227                     auto &drmPlane = mPlanes[j];
228                     if ((static_cast<int>(drmPlane->GetWinType()) & mCrtc->GetPlaneMask()) &&
229                         drmPlane->GetPipe() == 0) {
230                         DISPLAY_DEBUGLOG("no used plane %{public}s id %{public}d", drmPlane->GetName().c_str(),
231                                          drmPlane->GetId());
232                         ret = drmModeAtomicAddProperty(pset, drmPlane->GetId(), drmPlane->GetPropFbId(), 0);
233                         ret = drmModeAtomicAddProperty(pset, drmPlane->GetId(), drmPlane->GetPropFbId(), 0);
234                         drmPlane->UnBindPipe();
235                     }
236                 }
237                 return DISPLAY_SUCCESS;
238             }
239 
FindPlaneAndApply(drmModeAtomicReqPtr pset)240             int32_t HdiDrmComposition::FindPlaneAndApply(drmModeAtomicReqPtr pset)
241             {
242                 int32_t ret = 0;
243                 for (uint32_t i = 0; i < mCompLayers.size(); i++) {
244                     HdiDrmLayer *layer = static_cast<HdiDrmLayer *>(mCompLayers[i]);
245                     HdiLayer *hlayer = mCompLayers[i];
246                     for (uint32_t j = 0; j < mPlanes.size(); j++) {
247                         auto &drmPlane = mPlanes[j];
248                         if (drmPlane->GetPipe() != 0 && drmPlane->GetPipe() != (1 << mCrtc->GetPipe())) {
249                             DISPLAY_DEBUGLOG("plane %{public}d used pipe %{public}d crtc pipe %{public}d",
250                                              drmPlane->GetId(), drmPlane->GetPipe(), mCrtc->GetPipe());
251                             continue;
252                         }
253                         /* Check whether the plane belond to the crtc */
254                         if (!(static_cast<int>(drmPlane->GetWinType()) & mCrtc->GetPlaneMask())) {
255                             continue;
256                         }
257                         DISPLAY_DEBUGLOG("use plane %{public}d WinType %{public}x crtc %{public}d PlaneMask %{public}x",
258                                          drmPlane->GetId(), drmPlane->GetWinType(), mCrtc->GetId(),
259                                          mCrtc->GetPlaneMask());
260 
261                         if (drmPlane->GetCrtcId() == mCrtc->GetId() || drmPlane->GetCrtcId() == 0) {
262                             ret = ApplyPlane(*layer, *hlayer, *drmPlane, pset);
263                             if (ret != DISPLAY_SUCCESS) {
264                                 DISPLAY_LOGE("apply plane failed");
265                                 break;
266                             }
267                             /* mark the plane is used by crtc */
268                             drmPlane->BindToPipe(1 << mCrtc->GetPipe());
269                             break;
270                         }
271                     }
272                 }
273                 return DISPLAY_SUCCESS;
274             }
275 
Apply(bool modeSet)276             int32_t HdiDrmComposition::Apply(bool modeSet)
277             {
278                 uint64_t crtcOutFence = -1;
279                 int ret = 0;
280                 std::unique_ptr<DrmModeBlock> modeBlock;
281                 int drmFd = mDrmDevice->GetDrmFd();
282 
283                 ret = UpdateMode(modeBlock);
284                 DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_LOGE("update mode failed"));
285 
286                 DISPLAY_DEBUGLOG("mPlane size: %{public}zd mCompLayers size: %{public}zd", mPlanes.size(),
287                                  mCompLayers.size());
288                 DISPLAY_CHK_RETURN((mPlanes.size() < mCompLayers.size()), DISPLAY_FAILURE,
289                                    DISPLAY_LOGE("plane not enough"));
290                 drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
291                 DISPLAY_CHK_RETURN((pset == nullptr), DISPLAY_NULL_PTR,
292                                    DISPLAY_LOGE("drm atomic alloc failed errno %{public}d", errno));
293                 AtomicReqPtr atomicReqPtr = AtomicReqPtr(pset);
294 
295                 // set the outFence property
296                 ret = drmModeAtomicAddProperty(atomicReqPtr.Get(), mCrtc->GetId(), mCrtc->GetOutFencePropId(),
297                                                (uint64_t)&crtcOutFence);
298 
299                 DISPLAY_DEBUGLOG("Apply Set OutFence crtc id: %{public}d, fencePropId %{public}d", mCrtc->GetId(),
300                                  mCrtc->GetOutFencePropId());
301                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
302                                    DISPLAY_LOGE("set the outfence property of crtc failed "));
303 
304                 // set the plane info.
305                 DISPLAY_DEBUGLOG("mCompLayers size %{public}zd", mCompLayers.size());
306                 DISPLAY_DEBUGLOG("crtc id %{public}d connect id %{public}d encoder id %{public}d", mCrtc->GetId(),
307                                  mConnector->GetId(), mConnector->GetEncoderId());
308 
309                 /*  Bind the plane not used by other crtcs to the crtc. */
310                 FindPlaneAndApply(atomicReqPtr.Get());
311                 /* Remove useless planes from the drm */
312                 RemoveUnusePlane(atomicReqPtr.Get());
313 
314                 ret = drmModeAtomicAddProperty(pset, mConnector->GetId(), mConnector->GetPropCrtcId(), mCrtc->GetId());
315                 DISPLAY_LOGI("set the connector id: %{public}d, propId %{public}d, crtcId %{public}d",
316                              mConnector->GetId(), mConnector->GetPropCrtcId(), mCrtc->GetId());
317                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
318                                    DISPLAY_LOGE("can not add the crtc id prop %{public}d", errno));
319 
320                 // set to active
321                 DISPLAY_DEBUGLOG("set crtc to active");
322                 ret = drmModeAtomicAddProperty(pset, mCrtc->GetId(), mCrtc->GetActivePropId(), 1);
323                 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
324                                    DISPLAY_LOGE("can not add the active prop errno %{public}d", errno));
325 
326                 uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK;
327 
328                 ret = drmModeAtomicCommit(drmFd, atomicReqPtr.Get(), flags, nullptr);
329                 DISPLAY_CHK_RETURN((ret != 0), DISPLAY_FAILURE,
330                                    DISPLAY_LOGE("drmModeAtomicCommit failed %{public}d errno %{public}d", ret, errno));
331                 // set the release fence
332                 for (auto layer : mCompLayers) {
333                     layer->SetReleaseFence(static_cast<int>(crtcOutFence));
334                 }
335 
336                 return DISPLAY_SUCCESS;
337             }
338         } // OHOS
339     }     // HDI
340 } // DISPLAY
341