blob: 5d9abee499e001eb1fec3d24dad360f5c32f3c3c [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;
55 mIsDropFrames = false;
56 mKeepLastFrame = false;
fei.dengb9a1a572023-09-13 01:33:57 +000057 mDrmMesonLib = drmMesonLoadLib(logcategory);
fei.dengf7a0cd32023-08-29 09:36:37 +000058}
59
60DrmDisplay::~DrmDisplay()
61{
62 if (mDrmHandle) {
63 if (mDrmMesonLib) {
64 mDrmMesonLib->libDrmDisplayDestroy(mDrmHandle);
65 mDrmHandle = NULL;
66 }
67 }
68 //free dlopen resources
69 if (mDrmMesonLib) {
fei.dengb9a1a572023-09-13 01:33:57 +000070 drmMesonUnloadLib(mLogCategory, mDrmMesonLib);
fei.dengf7a0cd32023-08-29 09:36:37 +000071 mDrmMesonLib = NULL;
72 }
73}
74
75bool DrmDisplay::start(bool pip)
76{
77 mIsPip = pip;
78
fei.dengb9a1a572023-09-13 01:33:57 +000079 DEBUG(mLogCategory, "start pip:%d",pip);
fei.dengf7a0cd32023-08-29 09:36:37 +000080 if (mDrmMesonLib) {
81 mDrmHandle = mDrmMesonLib->libDrmDisplayInit();
82 }
83
84 if (!mDrmHandle) {
fei.dengb9a1a572023-09-13 01:33:57 +000085 ERROR(mLogCategory, "drm display init failed");
fei.dengf7a0cd32023-08-29 09:36:37 +000086 return false;
87 }
88#ifdef SUPPORT_DRM_FREEZEN
89 //set keep last frame if needed;
90 if (mKeepLastFrame) {
91 mDrmHandle->freeze = 1;
92 } else {
93 mDrmHandle->freeze = 0;
94 }
fei.dengb9a1a572023-09-13 01:33:57 +000095 INFO(mLogCategory, "set keep last frame %d", mDrmHandle->freeze);
fei.dengf7a0cd32023-08-29 09:36:37 +000096#endif
97
98 if (!mDrmFramePost) {
fei.dengb9a1a572023-09-13 01:33:57 +000099 mDrmFramePost = new DrmFramePost(this, mLogCategory);
fei.dengf7a0cd32023-08-29 09:36:37 +0000100 mDrmFramePost->start();
101 /*if window size set, we set to frame post,this needed
102 when yts resize case,window size must effect when post
103 buffer to drm
104 */
105 if (mWinRect.w > 0 && mWinRect.h > 0) {
106 mDrmFramePost->setWindowSize(mWinRect.x, mWinRect.y, mWinRect.w, mWinRect.h);
107 }
108 }
109
110 if (!mDrmFrameRecycle) {
fei.dengb9a1a572023-09-13 01:33:57 +0000111 mDrmFrameRecycle = new DrmFrameRecycle(this,mLogCategory);
fei.dengf7a0cd32023-08-29 09:36:37 +0000112 mDrmFrameRecycle->start();
113 }
114 return true;
115}
116
117bool DrmDisplay::stop()
118{
119 if (mDrmFramePost) {
fei.dengb9a1a572023-09-13 01:33:57 +0000120 DEBUG(mLogCategory, "stop frame post thread");
fei.dengf7a0cd32023-08-29 09:36:37 +0000121 mDrmFramePost->stop();
122 delete mDrmFramePost;
123 mDrmFramePost = NULL;
124 }
125 if (mDrmFrameRecycle) {
fei.dengb9a1a572023-09-13 01:33:57 +0000126 DEBUG(mLogCategory, "stop frame recycle thread");
fei.dengf7a0cd32023-08-29 09:36:37 +0000127 mDrmFrameRecycle->stop();
128 delete mDrmFrameRecycle;
129 mDrmFrameRecycle = NULL;
130 }
131 if (mBlackFrameAddr) {
132 munmap (mBlackFrameAddr, mBlackFrame->width * mBlackFrame->height * 2);
133 mBlackFrameAddr = NULL;
134 }
135 if (mBlackFrame) {
136 if (mDrmMesonLib) {
137 mDrmMesonLib->libDrmFreeBuf(mBlackFrame);
138 }
139 mBlackFrame = NULL;
140 }
141 if (mDrmHandle) {
142 if (mDrmMesonLib) {
143 mDrmMesonLib->libDrmDisplayDestroy(mDrmHandle);
144 mDrmHandle = NULL;
145 }
146 }
147 return true;
148}
149
150bool DrmDisplay::displayFrame(RenderBuffer *buf, int64_t displayTime)
151{
152 int ret;
153
154 FrameEntity *frameEntity = createFrameEntity(buf, displayTime);
155 if (frameEntity) {
156 if (mDrmFramePost) {
157 //if hided video and commit hide frame to drm,drop all frame
158 if (mIsDropFrames) {
159 handleDropedFrameEntity(frameEntity);
160 handleReleaseFrameEntity(frameEntity);
161 } else {
162 mDrmFramePost->readyPostFrame(frameEntity);
163 }
164 if (mHideVideo) {
165 mIsDropFrames = true;
166 }
167 } else {
fei.dengb9a1a572023-09-13 01:33:57 +0000168 WARNING(mLogCategory,"no frame post service");
fei.dengf7a0cd32023-08-29 09:36:37 +0000169 handleDropedFrameEntity(frameEntity);
170 handleReleaseFrameEntity(frameEntity);
171 }
172 } else { //drop and release render buffer
173 if (mPlugin) {
174 mPlugin->handleFrameDropped(buf);
175 mPlugin->handleBufferRelease(buf);
176 }
177 }
178
179 return true;
180}
181
182void DrmDisplay::flush()
183{
fei.dengb9a1a572023-09-13 01:33:57 +0000184 DEBUG(mLogCategory,"flush");
185 Tls::Mutex::Autolock _l(mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000186 if (mDrmFramePost) {
187 mDrmFramePost->flush();
188 }
189}
190
191void DrmDisplay::pause()
192{
193 mDrmFramePost->pause();
194}
195
196void DrmDisplay::resume()
197{
198 mDrmFramePost->resume();
199}
200
201void DrmDisplay::setVideoFormat(RenderVideoFormat videoFormat)
202{
203 mVideoFormat = videoFormat;
fei.dengb9a1a572023-09-13 01:33:57 +0000204 DEBUG(mLogCategory,"video format:%d",mVideoFormat);
fei.dengf7a0cd32023-08-29 09:36:37 +0000205}
206
207void DrmDisplay::setWindowSize(int x, int y, int w, int h)
208{
209 mWinRect.x = x;
210 mWinRect.y = y;
211 mWinRect.w = w;
212 mWinRect.h = h;
fei.dengb9a1a572023-09-13 01:33:57 +0000213 DEBUG(mLogCategory,"window size:(%dx%dx%dx%d)",x, y,w,h);
fei.dengf7a0cd32023-08-29 09:36:37 +0000214 if (mDrmFramePost) {
215 mDrmFramePost->setWindowSize(x, y, w, h);
216 }
217}
218
219void DrmDisplay::setFrameSize(int width, int height)
220{
221 mFrameWidth = width;
222 mFrameHeight = height;
fei.dengb9a1a572023-09-13 01:33:57 +0000223 DEBUG(mLogCategory,"frame size:%dx%d",width, height);
fei.dengf7a0cd32023-08-29 09:36:37 +0000224}
225
226void DrmDisplay::showBlackFrame()
227{
228 int rc;
229 struct drm_buf_metadata info;
230
fei.dengb9a1a572023-09-13 01:33:57 +0000231 if (mBlackFrame) {
232 return;
233 }
234
fei.dengf7a0cd32023-08-29 09:36:37 +0000235 memset(&info, 0 , sizeof(struct drm_buf_metadata));
236
237 /* use single planar for black frame */
238 info.width = BLACK_FRAME_WIDTH;
239 info.height = BLACK_FRAME_HEIGHT;
240 info.flags = 0;
241 info.fourcc = DRM_FORMAT_YUYV;
242
243 if (!mIsPip)
244 info.flags |= MESON_USE_VD1;
245 else
246 info.flags |= MESON_USE_VD2;
247
248 if (mDrmHandle && mDrmMesonLib) {
249 mBlackFrame = mDrmMesonLib->libDrmAllocBuf(mDrmHandle, &info);
250 }
251
252 if (!mBlackFrame) {
fei.dengb9a1a572023-09-13 01:33:57 +0000253 ERROR(mLogCategory,"Unable to alloc drm buf");
fei.dengf7a0cd32023-08-29 09:36:37 +0000254 goto tag_error;
255 }
256
257 mBlackFrameAddr = mmap (NULL, info.width * info.height * 2, PROT_WRITE,
258 MAP_SHARED, mBlackFrame->fd[0], mBlackFrame->offsets[0]);
259 if (mBlackFrameAddr == MAP_FAILED) {
fei.dengb9a1a572023-09-13 01:33:57 +0000260 ERROR(mLogCategory,"mmap fail %d", errno);
fei.dengf7a0cd32023-08-29 09:36:37 +0000261 mBlackFrameAddr = NULL;
262 }
263
264 /* full screen black frame */
265 memset (mBlackFrameAddr, 0, info.width * info.height * 2);
266 mBlackFrame->crtc_x = 0;
267 mBlackFrame->crtc_y = 0;
268 mBlackFrame->crtc_w = -1;
269 mBlackFrame->crtc_h = -1;
270
fei.dengb9a1a572023-09-13 01:33:57 +0000271 //disable plane
272 mBlackFrame->disable_plane = 1;
273
fei.dengf7a0cd32023-08-29 09:36:37 +0000274 //post black frame buf to drm
275 if (mDrmHandle && mDrmMesonLib) {
276 rc = mDrmMesonLib->libDrmPostBuf(mDrmHandle, mBlackFrame);
277 }
278 if (rc) {
fei.dengb9a1a572023-09-13 01:33:57 +0000279 ERROR(mLogCategory, "post black frame to drm failed");
fei.dengf7a0cd32023-08-29 09:36:37 +0000280 goto tag_error;
281 }
282
283 return;
284tag_error:
285 if (mBlackFrameAddr) {
286 munmap (mBlackFrameAddr, mBlackFrame->width * mBlackFrame->height * 2);
287 mBlackFrameAddr = NULL;
288 }
289 if (mBlackFrame) {
290 if (mDrmMesonLib) {
291 mDrmMesonLib->libDrmFreeBuf(mBlackFrame);
292 }
293
294 mBlackFrame = NULL;
295 }
296 return;
297}
298
299void DrmDisplay::setImmediatelyOutout(bool on)
300{
301 if (mDrmFramePost) {
302 mDrmFramePost->setImmediatelyOutout(on);
303 }
304}
305
306void DrmDisplay::setHideVideo(bool hide) {
fei.dengb9a1a572023-09-13 01:33:57 +0000307 INFO(mLogCategory,"hide video:%d",hide);
fei.dengf7a0cd32023-08-29 09:36:37 +0000308 mHideVideo = hide;
309 mIsDropFrames = false;
310}
311
312void DrmDisplay::setKeepLastFrame(bool keep)
313{
314 int kp = keep? 1: 0;
315 mKeepLastFrame = keep;
316
317#ifdef SUPPORT_DRM_FREEZEN
318 if (mDrmHandle) {
319 mDrmHandle->freeze = kp;
320 }
fei.dengb9a1a572023-09-13 01:33:57 +0000321 INFO(mLogCategory, "set keep last frame %d(%d)", keep,mDrmHandle->freeze);
322 if (!kp) {
323 INFO(mLogCategory, "set keep last frame %d, show black frame to drm", kp);
324 showBlackFrame();
325 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000326#endif
327}
328
329FrameEntity *DrmDisplay::createFrameEntity(RenderBuffer *buf, int64_t displayTime)
330{
331 struct drm_buf_import info;
332 FrameEntity* frame = NULL;
333 struct drm_buf * drmBuf = NULL;
334
335 frame = (FrameEntity*)calloc(1, sizeof(FrameEntity));
336 if (!frame) {
fei.dengb9a1a572023-09-13 01:33:57 +0000337 ERROR(mLogCategory,"oom calloc FrameEntity mem failed");
fei.dengf7a0cd32023-08-29 09:36:37 +0000338 goto tag_error;
339 }
340
341 frame->displayTime = displayTime;
342 frame->renderBuf = buf;
343
344 memset(&info, 0 , sizeof(struct drm_buf_import));
345
346 info.width = buf->dma.width;
347 info.height = buf->dma.height;
348 info.flags = 0;
349 switch (mVideoFormat)
350 {
351 case VIDEO_FORMAT_NV21: {
352 info.fourcc = DRM_FORMAT_NV21;
353 } break;
354 case VIDEO_FORMAT_NV12: {
355 info.fourcc = DRM_FORMAT_NV12;
356 } break;
357
358 default: {
359 info.fourcc = DRM_FORMAT_YUYV;
fei.dengb9a1a572023-09-13 01:33:57 +0000360 WARNING(mLogCategory,"unknown video format, set to default YUYV format");
fei.dengf7a0cd32023-08-29 09:36:37 +0000361 }
362 }
363
364 if (!mIsPip) {
365 info.flags |= MESON_USE_VD1;
366 } else {
367 info.flags |= MESON_USE_VD2;
368 }
369
370 /*warning: must dup fd, because drm_free_buf will close buf fd
371 if not dup buf fd, fd will be double free*/
372 for (int i = 0; i < buf->dma.planeCnt; i++) {
373 info.fd[i] = dup(buf->dma.fd[i]);
fei.dengb9a1a572023-09-13 01:33:57 +0000374 TRACE(mLogCategory,"dup fd[%d]:%d->%d",i,buf->dma.fd[i],info.fd[i]);
fei.dengf7a0cd32023-08-29 09:36:37 +0000375 }
376
377 if (mDrmHandle && mDrmMesonLib) {
378 drmBuf = mDrmMesonLib->libDrmImportBuf(mDrmHandle, &info);
379 }
380
381 if (!drmBuf) {
fei.dengb9a1a572023-09-13 01:33:57 +0000382 ERROR(mLogCategory, "unable drm_import_buf");
fei.dengf7a0cd32023-08-29 09:36:37 +0000383 goto tag_error;
384 }
385
386 //set source content's size
387 drmBuf->src_x = 0;
388 drmBuf->src_y = 0;
389 drmBuf->src_w = buf->dma.width;
390 drmBuf->src_h = buf->dma.height;
391
392 /*default set window size to full screen
393 *if window size set,the crtc size will be reset
394 *before post drm buffer
395 */
396 drmBuf->crtc_x = 0;
397 drmBuf->crtc_y = 0;
398 drmBuf->crtc_w = mDrmHandle->width;
399 drmBuf->crtc_h = mDrmHandle->height;
400#ifdef SUPPORT_DRM_FREEZEN
401 if (mHideVideo) {
402 drmBuf->disable_plane = 1;
403 } else {
404 drmBuf->disable_plane = 0;
405 }
406#endif
407
408 frame->drmBuf = drmBuf;
fei.dengb9a1a572023-09-13 01:33:57 +0000409 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 +0000410 drmBuf->src_x,drmBuf->src_y,drmBuf->src_w,drmBuf->src_h);
411
412 return frame;
413tag_error:
414 for (int i = 0; i < buf->dma.planeCnt; i++) {
415 if (info.fd[i] > 0) {
416 close(info.fd[i]);
417 info.fd[i] = -1;
418 }
419 }
420 if (frame) {
421 free(frame);
422 }
423 return NULL;
424}
425
426void DrmDisplay::destroyFrameEntity(FrameEntity * frameEntity)
427{
428 int rc;
429
430 if (!frameEntity) {
431 return;
432 }
433 if (frameEntity->drmBuf) {
434 if (mDrmMesonLib) {
435 rc = mDrmMesonLib->libDrmFreeBuf(frameEntity->drmBuf);
436 }
437
438 if (rc) {
fei.dengb9a1a572023-09-13 01:33:57 +0000439 WARNING(mLogCategory, "drm_free_buf free %p failed",frameEntity->drmBuf);
fei.dengf7a0cd32023-08-29 09:36:37 +0000440 }
fei.dengb9a1a572023-09-13 01:33:57 +0000441 TRACE(mLogCategory,"drm_free_buf displaytime:%lld(pts:%lld ms)",frameEntity->displayTime,frameEntity->renderBuf->pts/1000000);
fei.dengf7a0cd32023-08-29 09:36:37 +0000442 }
443 free(frameEntity);
444}
445
446void DrmDisplay::handlePostedFrameEntity(FrameEntity * frameEntity)
447{
448 if (mDrmFrameRecycle) {
449 mDrmFrameRecycle->recycleFrame(frameEntity);
450 }
451}
452
453void DrmDisplay::handleDropedFrameEntity(FrameEntity * frameEntity)
454{
455 if (mPlugin) {
456 mPlugin->handleFrameDropped(frameEntity->renderBuf);
457 }
458}
459
460void DrmDisplay::handleDisplayedFrameEntity(FrameEntity * frameEntity)
461{
462 if (mPlugin) {
463 mPlugin->handleFrameDisplayed(frameEntity->renderBuf);
464 }
465}
466
467void DrmDisplay::handleReleaseFrameEntity(FrameEntity * frameEntity)
468{
469 if (mPlugin) {
470 mPlugin->handleBufferRelease(frameEntity->renderBuf);
471 }
472 destroyFrameEntity(frameEntity);
473}
474
475void DrmDisplay::handleMsg(int type, void *detail)
476{
477 if (mPlugin) {
478 mPlugin->handleMsgNotify(type, detail);
479 }
480}