blob: 363e4cbf85e5da1b97fb57d5209851145528e395 [file] [log] [blame]
fei.dengf7a0cd32023-08-29 09:36:37 +00001/*
2 * Copyright (C) 2021 Amlogic Corporation.
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#include <errno.h>
17#include <sys/mman.h>
18#include <xf86drm.h>
19#include <xf86drmMode.h>
20#include <drm_fourcc.h>
21#include <linux/videodev2.h>
22#include <meson_drm.h>
23#include "drm_display.h"
24#include "Logger.h"
25#include "drm_framepost.h"
26#include "drm_framerecycle.h"
fei.dengb9a1a572023-09-13 01:33:57 +000027#include "ErrorCode.h"
fei.dengf7a0cd32023-08-29 09:36:37 +000028
29using namespace Tls;
30
31#define TAG "rlib:drm_display"
32
33#define BLACK_FRAME_WIDTH 64
34#define BLACK_FRAME_HEIGHT 64
35
fei.dengb9a1a572023-09-13 01:33:57 +000036DrmDisplay::DrmDisplay(DrmPlugin *plugin, int logcategory)
37 : mPlugin(plugin),
38 mLogCategory(logcategory)
fei.dengf7a0cd32023-08-29 09:36:37 +000039{
40 mDrmHandle = NULL;
41 mBlackFrame = 0;
42 mIsPip = false;
43 mDrmFramePost = NULL;
44 mDrmFrameRecycle = NULL;
45 mVideoFormat = VIDEO_FORMAT_UNKNOWN;
46 mWinRect.x = 0;
47 mWinRect.y = 0;
48 mWinRect.w = 0;
49 mWinRect.h = 0;
50 mFrameWidth = 0;
51 mFrameHeight = 0;
52 mBlackFrame = NULL;
53 mBlackFrameAddr = NULL;
54 mHideVideo = false;
fei.dengf7a0cd32023-08-29 09:36:37 +000055 mKeepLastFrame = false;
fei.dengb9a1a572023-09-13 01:33:57 +000056 mDrmMesonLib = drmMesonLoadLib(logcategory);
fei.dengf7a0cd32023-08-29 09:36:37 +000057}
58
59DrmDisplay::~DrmDisplay()
60{
61 if (mDrmHandle) {
62 if (mDrmMesonLib) {
63 mDrmMesonLib->libDrmDisplayDestroy(mDrmHandle);
64 mDrmHandle = NULL;
65 }
66 }
67 //free dlopen resources
68 if (mDrmMesonLib) {
fei.dengb9a1a572023-09-13 01:33:57 +000069 drmMesonUnloadLib(mLogCategory, mDrmMesonLib);
fei.dengf7a0cd32023-08-29 09:36:37 +000070 mDrmMesonLib = NULL;
71 }
72}
73
74bool DrmDisplay::start(bool pip)
75{
76 mIsPip = pip;
77
fei.dengb9a1a572023-09-13 01:33:57 +000078 DEBUG(mLogCategory, "start pip:%d",pip);
fei.dengf7a0cd32023-08-29 09:36:37 +000079 if (mDrmMesonLib) {
80 mDrmHandle = mDrmMesonLib->libDrmDisplayInit();
81 }
82
83 if (!mDrmHandle) {
fei.dengb9a1a572023-09-13 01:33:57 +000084 ERROR(mLogCategory, "drm display init failed");
fei.dengf7a0cd32023-08-29 09:36:37 +000085 return false;
86 }
87#ifdef SUPPORT_DRM_FREEZEN
88 //set keep last frame if needed;
89 if (mKeepLastFrame) {
90 mDrmHandle->freeze = 1;
91 } else {
92 mDrmHandle->freeze = 0;
93 }
fei.dengb9a1a572023-09-13 01:33:57 +000094 INFO(mLogCategory, "set keep last frame %d", mDrmHandle->freeze);
fei.dengf7a0cd32023-08-29 09:36:37 +000095#endif
96
97 if (!mDrmFramePost) {
fei.dengb9a1a572023-09-13 01:33:57 +000098 mDrmFramePost = new DrmFramePost(this, mLogCategory);
fei.dengf7a0cd32023-08-29 09:36:37 +000099 mDrmFramePost->start();
100 /*if window size set, we set to frame post,this needed
101 when yts resize case,window size must effect when post
102 buffer to drm
103 */
104 if (mWinRect.w > 0 && mWinRect.h > 0) {
105 mDrmFramePost->setWindowSize(mWinRect.x, mWinRect.y, mWinRect.w, mWinRect.h);
106 }
107 }
108
109 if (!mDrmFrameRecycle) {
fei.dengb9a1a572023-09-13 01:33:57 +0000110 mDrmFrameRecycle = new DrmFrameRecycle(this,mLogCategory);
fei.dengf7a0cd32023-08-29 09:36:37 +0000111 mDrmFrameRecycle->start();
112 }
113 return true;
114}
115
116bool DrmDisplay::stop()
117{
118 if (mDrmFramePost) {
fei.dengb9a1a572023-09-13 01:33:57 +0000119 DEBUG(mLogCategory, "stop frame post thread");
fei.dengf7a0cd32023-08-29 09:36:37 +0000120 mDrmFramePost->stop();
121 delete mDrmFramePost;
122 mDrmFramePost = NULL;
123 }
124 if (mDrmFrameRecycle) {
fei.dengb9a1a572023-09-13 01:33:57 +0000125 DEBUG(mLogCategory, "stop frame recycle thread");
fei.dengf7a0cd32023-08-29 09:36:37 +0000126 mDrmFrameRecycle->stop();
127 delete mDrmFrameRecycle;
128 mDrmFrameRecycle = NULL;
129 }
130 if (mBlackFrameAddr) {
131 munmap (mBlackFrameAddr, mBlackFrame->width * mBlackFrame->height * 2);
132 mBlackFrameAddr = NULL;
133 }
134 if (mBlackFrame) {
135 if (mDrmMesonLib) {
136 mDrmMesonLib->libDrmFreeBuf(mBlackFrame);
137 }
138 mBlackFrame = NULL;
139 }
fei.deng22cad1e2023-10-26 07:21:02 +0000140 //if video plane hided,we should unhide here,otherwise next playback will no video showed
141 if (mHideVideo) {
142 setHideVideo(false);
143 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000144 if (mDrmHandle) {
145 if (mDrmMesonLib) {
146 mDrmMesonLib->libDrmDisplayDestroy(mDrmHandle);
147 mDrmHandle = NULL;
148 }
149 }
150 return true;
151}
152
153bool DrmDisplay::displayFrame(RenderBuffer *buf, int64_t displayTime)
154{
155 int ret;
156
157 FrameEntity *frameEntity = createFrameEntity(buf, displayTime);
158 if (frameEntity) {
159 if (mDrmFramePost) {
fei.deng22cad1e2023-10-26 07:21:02 +0000160 mDrmFramePost->readyPostFrame(frameEntity);
fei.dengf7a0cd32023-08-29 09:36:37 +0000161 } else {
fei.dengb9a1a572023-09-13 01:33:57 +0000162 WARNING(mLogCategory,"no frame post service");
fei.dengf7a0cd32023-08-29 09:36:37 +0000163 handleDropedFrameEntity(frameEntity);
164 handleReleaseFrameEntity(frameEntity);
165 }
166 } else { //drop and release render buffer
167 if (mPlugin) {
168 mPlugin->handleFrameDropped(buf);
169 mPlugin->handleBufferRelease(buf);
170 }
171 }
172
173 return true;
174}
175
176void DrmDisplay::flush()
177{
fei.dengb9a1a572023-09-13 01:33:57 +0000178 DEBUG(mLogCategory,"flush");
179 Tls::Mutex::Autolock _l(mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000180 if (mDrmFramePost) {
181 mDrmFramePost->flush();
182 }
183}
184
185void DrmDisplay::pause()
186{
187 mDrmFramePost->pause();
188}
189
190void DrmDisplay::resume()
191{
192 mDrmFramePost->resume();
193}
194
195void DrmDisplay::setVideoFormat(RenderVideoFormat videoFormat)
196{
197 mVideoFormat = videoFormat;
fei.dengb9a1a572023-09-13 01:33:57 +0000198 DEBUG(mLogCategory,"video format:%d",mVideoFormat);
fei.dengf7a0cd32023-08-29 09:36:37 +0000199}
200
201void DrmDisplay::setWindowSize(int x, int y, int w, int h)
202{
203 mWinRect.x = x;
204 mWinRect.y = y;
205 mWinRect.w = w;
206 mWinRect.h = h;
fei.dengb9a1a572023-09-13 01:33:57 +0000207 DEBUG(mLogCategory,"window size:(%dx%dx%dx%d)",x, y,w,h);
fei.dengf7a0cd32023-08-29 09:36:37 +0000208 if (mDrmFramePost) {
209 mDrmFramePost->setWindowSize(x, y, w, h);
210 }
211}
212
213void DrmDisplay::setFrameSize(int width, int height)
214{
215 mFrameWidth = width;
216 mFrameHeight = height;
fei.dengb9a1a572023-09-13 01:33:57 +0000217 DEBUG(mLogCategory,"frame size:%dx%d",width, height);
fei.dengf7a0cd32023-08-29 09:36:37 +0000218}
219
220void DrmDisplay::showBlackFrame()
221{
222 int rc;
223 struct drm_buf_metadata info;
224
225 memset(&info, 0 , sizeof(struct drm_buf_metadata));
226
227 /* use single planar for black frame */
228 info.width = BLACK_FRAME_WIDTH;
229 info.height = BLACK_FRAME_HEIGHT;
230 info.flags = 0;
231 info.fourcc = DRM_FORMAT_YUYV;
232
233 if (!mIsPip)
234 info.flags |= MESON_USE_VD1;
235 else
236 info.flags |= MESON_USE_VD2;
237
fei.deng942dff62023-10-18 04:21:10 +0000238 if (mDrmHandle && mDrmMesonLib && !mBlackFrame) {
fei.dengf7a0cd32023-08-29 09:36:37 +0000239 mBlackFrame = mDrmMesonLib->libDrmAllocBuf(mDrmHandle, &info);
240 }
241
242 if (!mBlackFrame) {
fei.dengb9a1a572023-09-13 01:33:57 +0000243 ERROR(mLogCategory,"Unable to alloc drm buf");
fei.dengf7a0cd32023-08-29 09:36:37 +0000244 goto tag_error;
245 }
246
fei.deng942dff62023-10-18 04:21:10 +0000247 if (!mBlackFrameAddr) {
248 mBlackFrameAddr = mmap (NULL, info.width * info.height * 2, PROT_WRITE,
249 MAP_SHARED, mBlackFrame->fd[0], mBlackFrame->offsets[0]);
250 if (mBlackFrameAddr == MAP_FAILED) {
251 ERROR(mLogCategory,"mmap fail %d", errno);
252 mBlackFrameAddr = NULL;
253 goto tag_error;
254 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000255 }
256
257 /* full screen black frame */
258 memset (mBlackFrameAddr, 0, info.width * info.height * 2);
259 mBlackFrame->crtc_x = 0;
260 mBlackFrame->crtc_y = 0;
261 mBlackFrame->crtc_w = -1;
262 mBlackFrame->crtc_h = -1;
263
fei.deng942dff62023-10-18 04:21:10 +0000264 //disable plane,only this flag can take effect for black screen
fei.dengb9a1a572023-09-13 01:33:57 +0000265 mBlackFrame->disable_plane = 1;
266
fei.dengf7a0cd32023-08-29 09:36:37 +0000267 //post black frame buf to drm
268 if (mDrmHandle && mDrmMesonLib) {
269 rc = mDrmMesonLib->libDrmPostBuf(mDrmHandle, mBlackFrame);
270 }
271 if (rc) {
fei.dengb9a1a572023-09-13 01:33:57 +0000272 ERROR(mLogCategory, "post black frame to drm failed");
fei.dengf7a0cd32023-08-29 09:36:37 +0000273 goto tag_error;
274 }
275
276 return;
277tag_error:
278 if (mBlackFrameAddr) {
279 munmap (mBlackFrameAddr, mBlackFrame->width * mBlackFrame->height * 2);
280 mBlackFrameAddr = NULL;
281 }
282 if (mBlackFrame) {
283 if (mDrmMesonLib) {
284 mDrmMesonLib->libDrmFreeBuf(mBlackFrame);
285 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000286 mBlackFrame = NULL;
287 }
288 return;
289}
290
291void DrmDisplay::setImmediatelyOutout(bool on)
292{
293 if (mDrmFramePost) {
294 mDrmFramePost->setImmediatelyOutout(on);
295 }
296}
297
298void DrmDisplay::setHideVideo(bool hide) {
fei.dengb9a1a572023-09-13 01:33:57 +0000299 INFO(mLogCategory,"hide video:%d",hide);
fei.dengf7a0cd32023-08-29 09:36:37 +0000300 mHideVideo = hide;
fei.deng22cad1e2023-10-26 07:21:02 +0000301 if (mDrmHandle && mDrmMesonLib && mDrmMesonLib->libDrmMutePlane) {
302 unsigned int planeType = 1; //0:osd plane,1:video plane
303 unsigned int planeMute; //0: unmute,1:mute
304 if (hide) {
305 planeMute = 1; //1:mute
306 INFO(mLogCategory,"mute video");
307 } else {
308 planeMute = 0; //0: unmute
309 INFO(mLogCategory,"unmute video");
310 }
311 mDrmMesonLib->libDrmMutePlane(mDrmHandle->drm_fd, planeType, planeMute);
312 } else {
313 ERROR(mLogCategory, "Error dlsym drm_mute_plane");
fei.deng942dff62023-10-18 04:21:10 +0000314 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000315}
316
317void DrmDisplay::setKeepLastFrame(bool keep)
318{
319 int kp = keep? 1: 0;
320 mKeepLastFrame = keep;
321
322#ifdef SUPPORT_DRM_FREEZEN
323 if (mDrmHandle) {
324 mDrmHandle->freeze = kp;
325 }
fei.dengb9a1a572023-09-13 01:33:57 +0000326 INFO(mLogCategory, "set keep last frame %d(%d)", keep,mDrmHandle->freeze);
327 if (!kp) {
328 INFO(mLogCategory, "set keep last frame %d, show black frame to drm", kp);
329 showBlackFrame();
330 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000331#endif
332}
333
334FrameEntity *DrmDisplay::createFrameEntity(RenderBuffer *buf, int64_t displayTime)
335{
336 struct drm_buf_import info;
337 FrameEntity* frame = NULL;
338 struct drm_buf * drmBuf = NULL;
fei.deng942dff62023-10-18 04:21:10 +0000339 int displayWidth = 0, displayHeight = 0;
fei.dengf7a0cd32023-08-29 09:36:37 +0000340
341 frame = (FrameEntity*)calloc(1, sizeof(FrameEntity));
342 if (!frame) {
fei.dengb9a1a572023-09-13 01:33:57 +0000343 ERROR(mLogCategory,"oom calloc FrameEntity mem failed");
fei.dengf7a0cd32023-08-29 09:36:37 +0000344 goto tag_error;
345 }
346
347 frame->displayTime = displayTime;
348 frame->renderBuf = buf;
349
350 memset(&info, 0 , sizeof(struct drm_buf_import));
351
352 info.width = buf->dma.width;
353 info.height = buf->dma.height;
354 info.flags = 0;
355 switch (mVideoFormat)
356 {
357 case VIDEO_FORMAT_NV21: {
358 info.fourcc = DRM_FORMAT_NV21;
359 } break;
360 case VIDEO_FORMAT_NV12: {
361 info.fourcc = DRM_FORMAT_NV12;
362 } break;
363
364 default: {
365 info.fourcc = DRM_FORMAT_YUYV;
fei.dengb9a1a572023-09-13 01:33:57 +0000366 WARNING(mLogCategory,"unknown video format, set to default YUYV format");
fei.dengf7a0cd32023-08-29 09:36:37 +0000367 }
368 }
369
370 if (!mIsPip) {
371 info.flags |= MESON_USE_VD1;
372 } else {
373 info.flags |= MESON_USE_VD2;
374 }
375
376 /*warning: must dup fd, because drm_free_buf will close buf fd
377 if not dup buf fd, fd will be double free*/
378 for (int i = 0; i < buf->dma.planeCnt; i++) {
379 info.fd[i] = dup(buf->dma.fd[i]);
fei.dengb9a1a572023-09-13 01:33:57 +0000380 TRACE(mLogCategory,"dup fd[%d]:%d->%d",i,buf->dma.fd[i],info.fd[i]);
fei.dengf7a0cd32023-08-29 09:36:37 +0000381 }
382
383 if (mDrmHandle && mDrmMesonLib) {
384 drmBuf = mDrmMesonLib->libDrmImportBuf(mDrmHandle, &info);
385 }
386
387 if (!drmBuf) {
fei.dengb9a1a572023-09-13 01:33:57 +0000388 ERROR(mLogCategory, "unable drm_import_buf");
fei.dengf7a0cd32023-08-29 09:36:37 +0000389 goto tag_error;
390 }
391
392 //set source content's size
393 drmBuf->src_x = 0;
394 drmBuf->src_y = 0;
395 drmBuf->src_w = buf->dma.width;
396 drmBuf->src_h = buf->dma.height;
397
398 /*default set window size to full screen
399 *if window size set,the crtc size will be reset
400 *before post drm buffer
401 */
fei.deng942dff62023-10-18 04:21:10 +0000402 //get current display mode
403 if (mDrmHandle && mDrmMesonLib) {
404 DisplayMode displayMode;
405 mDrmMesonLib->libDrmGetModeInfo(mDrmHandle->drm_fd, MESON_CONNECTOR_RESERVED, &displayMode);
406 displayWidth = displayMode.w;
407 displayHeight = displayMode.h;
408 ERROR(mLogCategory, "displayWidth:%d,displayHeight:%d",displayWidth,displayHeight);
409 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000410 drmBuf->crtc_x = 0;
411 drmBuf->crtc_y = 0;
fei.deng942dff62023-10-18 04:21:10 +0000412 if (displayWidth > 0 && displayHeight > 0) {
413 drmBuf->crtc_w = displayWidth;
414 drmBuf->crtc_h = displayHeight;
415 } else {
416 drmBuf->crtc_w = mDrmHandle->width;
417 drmBuf->crtc_h = mDrmHandle->height;
418 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000419
420 frame->drmBuf = drmBuf;
fei.dengb9a1a572023-09-13 01:33:57 +0000421 TRACE(mLogCategory,"crtc(%d,%d,%d,%d),src(%d,%d,%d,%d)",drmBuf->crtc_x,drmBuf->crtc_y,drmBuf->crtc_w,drmBuf->crtc_h,
fei.dengf7a0cd32023-08-29 09:36:37 +0000422 drmBuf->src_x,drmBuf->src_y,drmBuf->src_w,drmBuf->src_h);
423
424 return frame;
425tag_error:
426 for (int i = 0; i < buf->dma.planeCnt; i++) {
427 if (info.fd[i] > 0) {
428 close(info.fd[i]);
429 info.fd[i] = -1;
430 }
431 }
432 if (frame) {
433 free(frame);
434 }
435 return NULL;
436}
437
438void DrmDisplay::destroyFrameEntity(FrameEntity * frameEntity)
439{
440 int rc;
441
442 if (!frameEntity) {
443 return;
444 }
445 if (frameEntity->drmBuf) {
446 if (mDrmMesonLib) {
447 rc = mDrmMesonLib->libDrmFreeBuf(frameEntity->drmBuf);
448 }
449
450 if (rc) {
fei.dengb9a1a572023-09-13 01:33:57 +0000451 WARNING(mLogCategory, "drm_free_buf free %p failed",frameEntity->drmBuf);
fei.dengf7a0cd32023-08-29 09:36:37 +0000452 }
fei.dengb9a1a572023-09-13 01:33:57 +0000453 TRACE(mLogCategory,"drm_free_buf displaytime:%lld(pts:%lld ms)",frameEntity->displayTime,frameEntity->renderBuf->pts/1000000);
fei.dengf7a0cd32023-08-29 09:36:37 +0000454 }
455 free(frameEntity);
456}
457
458void DrmDisplay::handlePostedFrameEntity(FrameEntity * frameEntity)
459{
460 if (mDrmFrameRecycle) {
461 mDrmFrameRecycle->recycleFrame(frameEntity);
462 }
463}
464
465void DrmDisplay::handleDropedFrameEntity(FrameEntity * frameEntity)
466{
467 if (mPlugin) {
468 mPlugin->handleFrameDropped(frameEntity->renderBuf);
469 }
470}
471
472void DrmDisplay::handleDisplayedFrameEntity(FrameEntity * frameEntity)
473{
474 if (mPlugin) {
475 mPlugin->handleFrameDisplayed(frameEntity->renderBuf);
476 }
477}
478
479void DrmDisplay::handleReleaseFrameEntity(FrameEntity * frameEntity)
480{
481 if (mPlugin) {
482 mPlugin->handleBufferRelease(frameEntity->renderBuf);
483 }
484 destroyFrameEntity(frameEntity);
485}
486
487void DrmDisplay::handleMsg(int type, void *detail)
488{
489 if (mPlugin) {
490 mPlugin->handleMsgNotify(type, detail);
491 }
492}