1 /*
2 * Copyright (c) 2021 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 {
VideoAxisSet(const IRect & rect)23 static int VideoAxisSet(const IRect &rect)
24 {
25 const char *path = "/sys/class/video/axis";
26 int fd;
27 char bcmd[64];
28
29 fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
30 if (fd >= 0) {
31 snprintf(bcmd, sizeof(bcmd), "%d %d %d %d",
32 rect.x, rect.y, rect.x+rect.w, rect.y+rect.h);
33 DISPLAY_LOGI("Set %s=%s", path, bcmd);
34 write(fd, bcmd, strlen(bcmd));
35 close(fd);
36 return 0;
37 } else {
38 DISPLAY_LOGE("unable to open file %s,err: %s\n", path, strerror(errno));
39 }
40
41 return -1;
42 }
43
HdiDrmComposition(std::shared_ptr<DrmConnector> & connector,std::shared_ptr<DrmCrtc> & crtc,std::shared_ptr<DrmDevice> & drmDevice)44 HdiDrmComposition::HdiDrmComposition(std::shared_ptr<DrmConnector> &connector, std::shared_ptr<DrmCrtc> &crtc,
45 std::shared_ptr<DrmDevice> &drmDevice)
46 : mDrmDevice(drmDevice), mConnector(connector), mCrtc(crtc)
47 {
48 DISPLAY_LOGD();
49 }
50
Init()51 int32_t HdiDrmComposition::Init()
52 {
53 DISPLAY_LOGD();
54 mPrimPlanes.clear();
55 mOverlayPlanes.clear();
56 mPlanes.clear();
57 DISPLAY_CHK_RETURN((mCrtc == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("crtc is null"));
58 DISPLAY_CHK_RETURN((mConnector == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("connector is null"));
59 DISPLAY_CHK_RETURN((mDrmDevice == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("drmDevice is null"));
60 mPrimPlanes = mDrmDevice->GetDrmPlane(mCrtc->GetPipe(), DRM_PLANE_TYPE_PRIMARY);
61 mOverlayPlanes = mDrmDevice->GetDrmPlane(mCrtc->GetPipe(), DRM_PLANE_TYPE_OVERLAY);
62 DISPLAY_CHK_RETURN((mPrimPlanes.size() == 0), DISPLAY_FAILURE, DISPLAY_LOGE("has no primary plane"));
63 mPlanes.insert(mPlanes.end(), mPrimPlanes.begin(), mPrimPlanes.end());
64 mPlanes.insert(mPlanes.end(), mOverlayPlanes.begin(), mOverlayPlanes.end());
65 mVideoLayer = nullptr;
66 return DISPLAY_SUCCESS;
67 }
68
IsAmVideoLayer(HdiLayer & hdiLayer)69 bool HdiDrmComposition::IsAmVideoLayer(HdiLayer &hdiLayer)
70 {
71 HdiLayerBuffer *srcBuffer = hdiLayer.GetCurrentBuffer();
72
73 static std::set<PixelFormat> formats = {
74 PIXEL_FMT_YUV_422_I, /* *< YUV422 interleaved format */
75 PIXEL_FMT_YCBCR_422_SP, /* *< YCBCR422 semi-planar format */
76 PIXEL_FMT_YCRCB_422_SP, /* *< YCRCB422 semi-planar format */
77 PIXEL_FMT_YCBCR_420_SP, /* *< YCBCR420 semi-planar format */
78 PIXEL_FMT_YCRCB_420_SP, /* *< YCRCB420 semi-planar format */
79 PIXEL_FMT_YCBCR_422_P, /* *< YCBCR422 planar format */
80 PIXEL_FMT_YCRCB_422_P, /* *< YCRCB422 planar format */
81 PIXEL_FMT_YCBCR_420_P, /* *< YCBCR420 planar format */
82 PIXEL_FMT_YCRCB_420_P, /* *< YCRCB420 planar format */
83 PIXEL_FMT_YUYV_422_PKG, /* *< YUYV422 packed format */
84 PIXEL_FMT_UYVY_422_PKG, /* *< UYVY422 packed format */
85 PIXEL_FMT_YVYU_422_PKG, /* *< YVYU422 packed format */
86 PIXEL_FMT_VYUY_422_PKG, /* *< VYUY422 packed format */
87 };
88
89 if (srcBuffer == nullptr) {
90 return false;
91 }
92
93 if (formats.find(static_cast<PixelFormat>(hdiLayer.GetCurrentBuffer()->GetFormat())) == formats.end()) {
94 return false; // not found in formats table.
95 }
96
97 /* amplayer engine submit a layer buffer with size of [1,1] */
98 if (srcBuffer->GetHeight() != 1L || srcBuffer->GetWidth() != 1L) {
99 return false;
100 }
101
102 return true;
103 }
104
SetLayers(std::vector<HdiLayer * > & layers,HdiLayer & clientLayer)105 int32_t HdiDrmComposition::SetLayers(std::vector<HdiLayer *> &layers, HdiLayer &clientLayer)
106 {
107 // now we do not surpport present direct
108 DISPLAY_LOGD();
109 mCompLayers.clear();
110 mCompLayers.push_back(&clientLayer);
111
112 mVideoLayer = nullptr;
113 for (auto &layer : layers) {
114 if (IsAmVideoLayer(*layer)) {
115 layer->SetLayerCompositionType(COMPOSITION_VIDEO);
116 mVideoLayer = static_cast<HdiDrmLayer *>(layer);
117 break;
118 }
119 }
120
121 return DISPLAY_SUCCESS;
122 }
123
ApplyPlane(HdiDrmLayer & layer,DrmPlane & drmPlane,drmModeAtomicReqPtr pset)124 int32_t HdiDrmComposition::ApplyPlane(HdiDrmLayer &layer, DrmPlane &drmPlane, drmModeAtomicReqPtr pset)
125 {
126 // set fence in
127 int ret;
128 int fenceFd = layer.GetAcquireFenceFd();
129 int propId = drmPlane.GetPropFenceInId();
130 DISPLAY_LOGD();
131 if (propId != 0) {
132 DISPLAY_LOGD("set the fence in prop");
133 if (fenceFd >= 0) {
134 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), propId, fenceFd);
135 DISPLAY_LOGD("set the IfenceProp plane id %{public}d, propId %{public}d, fenceFd %{public}d",
136 drmPlane.GetId(), propId, fenceFd);
137 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set IN_FENCE_FD failed"));
138 }
139 }
140
141 // set fb id
142 DrmGemBuffer *gemBuffer = layer.GetGemBuffer();
143 DISPLAY_CHK_RETURN((gemBuffer == nullptr), DISPLAY_FAILURE, DISPLAY_LOGE("current gemBuffer is nullptr"));
144 DISPLAY_CHK_RETURN((!gemBuffer->IsValid()), DISPLAY_FAILURE, DISPLAY_LOGE("the DrmGemBuffer is invalid"));
145 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropFbId(), gemBuffer->GetFbId());
146 DISPLAY_LOGD("set the fb planeid %{public}d, propId %{public}d, fbId %{public}d", drmPlane.GetId(),
147 drmPlane.GetPropFbId(), gemBuffer->GetFbId());
148 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set fb id fialed errno : %{public}d", errno));
149
150 // set crtc id
151 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropCrtcId(), mCrtc->GetId());
152 DISPLAY_LOGD("set the crtc planeId %{public}d, propId %{public}d, crtcId %{public}d", drmPlane.GetId(),
153 drmPlane.GetPropCrtcId(), mCrtc->GetId());
154 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set crtc id fialed errno : %{public}d", errno));
155
156 // set src_w
157 HdiLayerBuffer *layerBuffer = layer.GetCurrentBuffer();
158 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropSrcWId(),
159 (uint32_t)layerBuffer->GetWidth() << 16U);
160 DISPLAY_LOGD("set the src_w planeId %{public}d, propId %{public}d, src_w %{public}d", drmPlane.GetId(),
161 drmPlane.GetPropSrcWId(), layerBuffer->GetWidth());
162 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set src_w fialed errno : %{public}d", errno));
163
164 // set src_h
165 ret = drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.GetPropSrcHId(),
166 (uint32_t)layerBuffer->GetHeight() << 16U);
167 DISPLAY_LOGD("set the src_h planeId %{public}d, propId %{public}d, src_h %{public}d", drmPlane.GetId(),
168 drmPlane.GetPropSrcHId(), layerBuffer->GetHeight());
169 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set src_h fialed errno : %{public}d", errno));
170
171 return DISPLAY_SUCCESS;
172 }
173
UpdateMode(std::unique_ptr<DrmModeBlock> & modeBlock,drmModeAtomicReq & pset)174 int32_t HdiDrmComposition::UpdateMode(std::unique_ptr<DrmModeBlock> &modeBlock, drmModeAtomicReq &pset)
175 {
176 // set the mode
177 int ret;
178 DISPLAY_LOGD();
179 if (mCrtc->NeedModeSet()) {
180 modeBlock = mConnector->GetModeBlockFromId(mCrtc->GetActiveModeId());
181 if ((modeBlock != nullptr) && (modeBlock->GetBlockId() != 0xFFFFFFFF)) {
182 // set to active
183 DISPLAY_LOGD("set crtc to active");
184 ret = drmModeAtomicAddProperty(&pset, mCrtc->GetId(), mCrtc->GetActivePropId(), 1);
185 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
186 DISPLAY_LOGE("can not add the active prop errno %{public}d", errno));
187
188 // set the mode id
189 DISPLAY_LOGD("set the mode");
190 ret = drmModeAtomicAddProperty(&pset, mCrtc->GetId(), mCrtc->GetModePropId(), modeBlock->GetBlockId());
191 DISPLAY_LOGD("set the mode planeId %{public}d, propId %{public}d, GetBlockId: %{public}d", mCrtc->GetId(),
192 mCrtc->GetModePropId(), modeBlock->GetBlockId());
193 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
194 DISPLAY_LOGE("can not add the mode prop errno %{public}d", errno));
195 ret = drmModeAtomicAddProperty(&pset, mConnector->GetId(), mConnector->GetPropCrtcId(), mCrtc->GetId());
196 DISPLAY_LOGD("set the connector id: %{public}d, propId %{public}d, crtcId %{public}d", mConnector->GetId(),
197 mConnector->GetPropCrtcId(), mCrtc->GetId());
198 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE,
199 DISPLAY_LOGE("can not add the crtc id prop %{public}d", errno));
200 }
201 }
202 return DISPLAY_SUCCESS;
203 }
204
UpdateVideoRect(HdiDrmLayer & videoLayer,HdiDrmLayer & clientLayer)205 int32_t HdiDrmComposition::UpdateVideoRect(HdiDrmLayer &videoLayer, HdiDrmLayer &clientLayer)
206 {
207 DrmMode mode;
208 int32_t ret = mConnector->GetModeFromId(mCrtc->GetActiveModeId(), mode);
209 DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE,
210 DISPLAY_LOGE("can not get the mode from id %{public}d", mCrtc->GetActiveModeId()));
211
212 int32_t dstWidth = mode.GetModeInfoPtr()->hdisplay;
213 int32_t dstHeight = mode.GetModeInfoPtr()->vdisplay;
214 HdiLayerBuffer *dstBuffer = clientLayer.GetCurrentBuffer();
215 int32_t srcWidth = dstBuffer->GetWidth();
216 int32_t srcHeight = dstBuffer->GetHeight();
217 IRect rect = videoLayer.GetLayerDisplayRect();
218
219 rect.x = rect.x * dstWidth / srcWidth;
220 rect.y = rect.y * dstHeight / srcHeight;
221 rect.w = rect.w * dstWidth / srcWidth;
222 rect.h = rect.h * dstHeight / srcHeight;
223
224 return VideoAxisSet(rect);
225 }
226
Apply(bool modeSet)227 int32_t HdiDrmComposition::Apply(bool modeSet)
228 {
229 uint64_t crtcOutFence = -1;
230 int ret;
231 std::unique_ptr<DrmModeBlock> modeBlock;
232 int drmFd = mDrmDevice->GetDrmFd();
233 DISPLAY_LOGD();
234 DISPLAY_CHK_RETURN((mPlanes.size() < mCompLayers.size()), DISPLAY_FAILURE, DISPLAY_LOGE("plane not enough"));
235 drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
236 DISPLAY_CHK_RETURN((pset == nullptr), DISPLAY_NULL_PTR,
237 DISPLAY_LOGE("drm atomic alloc failed errno %{public}d", errno));
238 AtomicReqPtr atomicReqPtr = AtomicReqPtr(pset);
239
240 // set the outFence property
241 ret = drmModeAtomicAddProperty(atomicReqPtr.Get(), mCrtc->GetId(), mCrtc->GetOutFencePropId(),
242 (uint64_t)&crtcOutFence);
243
244 DISPLAY_LOGD("Apply Set OutFence crtc id: %{public}d, fencePropId %{public}d", mCrtc->GetId(),
245 mCrtc->GetOutFencePropId());
246 DISPLAY_CHK_RETURN((ret < 0), DISPLAY_FAILURE, DISPLAY_LOGE("set the outfence property of crtc failed "));
247
248 // set the plane info.
249 DISPLAY_LOGD("mCompLayers size %{public}zd", mCompLayers.size());
250 for (uint32_t i = 0; i < mCompLayers.size(); i++) {
251 HdiDrmLayer *layer = static_cast<HdiDrmLayer *>(mCompLayers[i]);
252 auto &drmPlane = mPlanes[i];
253 ret = ApplyPlane(*layer, *drmPlane, atomicReqPtr.Get());
254 if (ret != DISPLAY_SUCCESS) {
255 DISPLAY_LOGE("apply plane failed");
256 break;
257 }
258 }
259
260 if (mCompLayers.size() > 0 && mVideoLayer != nullptr) {
261 HdiDrmLayer *clientLayer = static_cast<HdiDrmLayer *>(mCompLayers[0]);
262 UpdateVideoRect(*mVideoLayer, *clientLayer);
263 mVideoLayer = nullptr;
264 }
265
266 ret = UpdateMode(modeBlock, *(atomicReqPtr.Get()));
267 DISPLAY_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_LOGE("update mode failed"));
268 uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
269
270 ret = drmModeAtomicCommit(drmFd, atomicReqPtr.Get(), flags, nullptr);
271 DISPLAY_CHK_RETURN((ret != 0), DISPLAY_FAILURE,
272 DISPLAY_LOGE("drmModeAtomicCommit failed %{public}d errno %{public}d, %{public}s",
273 ret, errno, strerror(errno)));
274 // set the release fence
275 for (auto layer : mCompLayers) {
276 layer->SetReleaseFence(dup(static_cast<int32_t>(crtcOutFence)));
277 }
278 close(static_cast<int32_t>(crtcOutFence));
279 crtcOutFence = -1;
280 return DISPLAY_SUCCESS;
281 }
282 } // OHOS
283 } // HDI
284 } // DISPLAY
285