• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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