blob: 32ad486d83c07491c4aeb94d2383367b7916f6c6 [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 "Logger.h"
19#include "drm_display.h"
20#include "drm_framepost.h"
fei.dengb9a1a572023-09-13 01:33:57 +000021#include "ErrorCode.h"
fei.dengf7a0cd32023-08-29 09:36:37 +000022
23using namespace Tls;
24
25#define TAG "rlib:drm_framepost"
26
fei.dengb9a1a572023-09-13 01:33:57 +000027DrmFramePost::DrmFramePost(DrmDisplay *drmDisplay,int logCategory)
fei.dengf7a0cd32023-08-29 09:36:37 +000028{
29 mDrmDisplay = drmDisplay;
fei.dengb9a1a572023-09-13 01:33:57 +000030 mLogCategory = logCategory;
fei.dengf7a0cd32023-08-29 09:36:37 +000031 mPaused = false;
32 mStop = false;
33 mImmediatelyOutput = false;
34 mQueue = new Tls::Queue();
35 mWinRect.x = 0;
36 mWinRect.y = 0;
37 mWinRect.w = 0;
38 mWinRect.h = 0;
39}
40
41DrmFramePost::~DrmFramePost()
42{
43 if (isRunning()) {
44 mStop = true;
fei.dengb9a1a572023-09-13 01:33:57 +000045 DEBUG(mLogCategory,"stop frame post thread");
fei.dengf7a0cd32023-08-29 09:36:37 +000046 requestExitAndWait();
47 }
48
49 if (mQueue) {
50 mQueue->flush();
51 delete mQueue;
52 mQueue = NULL;
53 }
54}
55
56bool DrmFramePost::start()
57{
fei.dengb9a1a572023-09-13 01:33:57 +000058 DEBUG(mLogCategory,"start frame post thread");
fei.dengf7a0cd32023-08-29 09:36:37 +000059 run("frame post thread");
60 return true;
61}
62
63bool DrmFramePost::stop()
64{
fei.dengb9a1a572023-09-13 01:33:57 +000065 DEBUG(mLogCategory,"stop frame post thread");
fei.dengf7a0cd32023-08-29 09:36:37 +000066 if (isRunning()) {
67 mStop = true;
fei.dengb9a1a572023-09-13 01:33:57 +000068 DEBUG(mLogCategory,"stop frame post thread");
fei.dengf7a0cd32023-08-29 09:36:37 +000069 requestExitAndWait();
70 }
71 flush();
72 return true;
73}
74
75bool DrmFramePost::readyPostFrame(FrameEntity * frameEntity)
76{
fei.dengb9a1a572023-09-13 01:33:57 +000077 Tls::Mutex::Autolock _l(mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +000078 mQueue->push(frameEntity);
fei.dengb9a1a572023-09-13 01:33:57 +000079 TRACE(mLogCategory,"queue cnt:%d",mQueue->getCnt());
fei.dengf7a0cd32023-08-29 09:36:37 +000080 return true;
81}
82
83void DrmFramePost::flush()
84{
85 FrameEntity *entity;
fei.dengb9a1a572023-09-13 01:33:57 +000086 Tls::Mutex::Autolock _l(mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +000087 while (mQueue->pop((void **)&entity) == Q_OK)
88 {
89 mDrmDisplay->handleDropedFrameEntity(entity);
90 mDrmDisplay->handleReleaseFrameEntity(entity);
91 }
92}
93
94void DrmFramePost::pause()
95{
96 mPaused = true;
97}
98
99void DrmFramePost::resume()
100{
101 mPaused = false;
102}
103
104void DrmFramePost::setImmediatelyOutout(bool on)
105{
106 mImmediatelyOutput = on;
fei.dengb9a1a572023-09-13 01:33:57 +0000107 DEBUG(mLogCategory,"set immediately output:%d",on);
fei.dengf7a0cd32023-08-29 09:36:37 +0000108}
109
110void DrmFramePost::setWindowSize(int x, int y, int w, int h)
111{
112 mWinRect.x = x;
113 mWinRect.y = y;
114 mWinRect.w = w;
115 mWinRect.h = h;
116}
117
118void DrmFramePost::readyToRun()
119{
120}
121
122bool DrmFramePost::threadLoop()
123{
124 int rc;
125 drmVBlank vbl;
126 int64_t vBlankTime;
127 FrameEntity *curFrameEntity = NULL;
128 FrameEntity *expiredFrameEntity = NULL;
129 long long refreshInterval= 0LL;
130 struct drm_display *drmHandle = mDrmDisplay->getDrmHandle();
131 DrmMesonLib *drmMesonLib = mDrmDisplay->getDrmMesonLib();
132
133 //stop thread
134 if (mStop) {
135 return false;
136 }
137
138 if (!drmHandle) {
fei.dengb9a1a572023-09-13 01:33:57 +0000139 ERROR(mLogCategory,"drm handle is NULL");
fei.dengf7a0cd32023-08-29 09:36:37 +0000140 return false;
141 }
142
143 memset(&vbl, 0, sizeof(drmVBlank));
144
145 vbl.request.type = DRM_VBLANK_RELATIVE;
146 vbl.request.sequence = 1;
147 vbl.request.signal = 0;
148
149 //drmWaitBland need link libdrm.so
150 rc = drmWaitVBlank(drmHandle->drm_fd, &vbl);
151 if (rc) {
fei.dengb9a1a572023-09-13 01:33:57 +0000152 ERROR(mLogCategory,"drmWaitVBlank error %d", rc);
fei.dengf7a0cd32023-08-29 09:36:37 +0000153 usleep(4000);
154 return true;
155 }
156
157 if (drmHandle->vrefresh)
158 {
159 refreshInterval= (1000000LL+(drmHandle->vrefresh/2))/drmHandle->vrefresh;
160 }
161
162 vBlankTime = vbl.reply.tval_sec*1000000LL + vbl.reply.tval_usec;
163 vBlankTime += refreshInterval; //check next blank time
164
fei.dengb9a1a572023-09-13 01:33:57 +0000165 Tls::Mutex::Autolock _l(mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000166 //if queue is empty or paused, loop next
167 if (mQueue->isEmpty() || mPaused) {
168 //TRACE(mLogCategory,"empty or paused");
169 goto tag_next;
170 }
171
172 //we output video frame asap
173 if (mImmediatelyOutput) {
174 //pop the peeked frame
175 mQueue->pop((void **)&expiredFrameEntity);
176 goto tag_post;
177 }
178
179 while (mQueue->peek((void **)&curFrameEntity, 0) == Q_OK)
180 {
fei.dengb9a1a572023-09-13 01:33:57 +0000181 TRACE(mLogCategory,"vBlankTime:%lld,frame time:%lld(pts:%lld ms),refreshInterval:%lld",vBlankTime,curFrameEntity->displayTime,curFrameEntity->renderBuf->pts/1000000,refreshInterval);
fei.dengf7a0cd32023-08-29 09:36:37 +0000182 //no frame expired,loop next
183 if (vBlankTime < curFrameEntity->displayTime) {
184 break;
185 }
186
187 //pop the peeked frame
188 mQueue->pop((void **)&curFrameEntity);
189
190 //drop last expired frame,got a new expired frame
191 if (expiredFrameEntity) {
fei.dengb9a1a572023-09-13 01:33:57 +0000192 DEBUG(mLogCategory,"drop frame,vBlankTime:%lld,frame time:%lld(pts:%lld ms)",vBlankTime,expiredFrameEntity->displayTime,expiredFrameEntity->renderBuf->pts/1000000);
fei.dengf7a0cd32023-08-29 09:36:37 +0000193 mDrmDisplay->handleDropedFrameEntity(expiredFrameEntity);
194 mDrmDisplay->handleReleaseFrameEntity(expiredFrameEntity);
195 expiredFrameEntity = NULL;
196 }
197
198 expiredFrameEntity = curFrameEntity;
fei.dengb9a1a572023-09-13 01:33:57 +0000199 TRACE(mLogCategory,"expire,frame time:%lld(pts:%lld ms)",expiredFrameEntity->displayTime,expiredFrameEntity->renderBuf->pts/1000000);
fei.dengf7a0cd32023-08-29 09:36:37 +0000200 }
201
202tag_post:
203 //no frame will be posted to drm display
204 if (!expiredFrameEntity) {
fei.dengb9a1a572023-09-13 01:33:57 +0000205 TRACE(mLogCategory,"no frame expire");
fei.dengf7a0cd32023-08-29 09:36:37 +0000206 goto tag_next;
207 }
208
209 //double check window size before post drm buffer
210 if (mWinRect.w > 0 && mWinRect.h > 0) {
211 struct drm_buf * drmBuf = expiredFrameEntity->drmBuf;
212 drmBuf->crtc_x = mWinRect.x;
213 drmBuf->crtc_y = mWinRect.y;
214 drmBuf->crtc_w = mWinRect.w;
215 drmBuf->crtc_h = mWinRect.h;
fei.dengb9a1a572023-09-13 01:33:57 +0000216 TRACE(mLogCategory,"postBuf 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 +0000217 drmBuf->src_x,drmBuf->src_y,drmBuf->src_w,drmBuf->src_h);
218 }
219
220 if (drmHandle && drmMesonLib) {
221 rc = drmMesonLib->libDrmPostBuf(drmHandle, expiredFrameEntity->drmBuf);
222 }
223
224 if (rc) {
fei.dengb9a1a572023-09-13 01:33:57 +0000225 ERROR(mLogCategory, "drm_post_buf error %d", rc);
fei.dengf7a0cd32023-08-29 09:36:37 +0000226 mDrmDisplay->handleDropedFrameEntity(expiredFrameEntity);
227 mDrmDisplay->handleReleaseFrameEntity(expiredFrameEntity);
228 goto tag_next;
229 }
230
fei.dengb9a1a572023-09-13 01:33:57 +0000231 TRACE(mLogCategory,"drm_post_buf,frame time:%lld(pts:%lld ms)",expiredFrameEntity->displayTime,expiredFrameEntity->renderBuf->pts/1000000);
fei.dengf7a0cd32023-08-29 09:36:37 +0000232 mDrmDisplay->handlePostedFrameEntity(expiredFrameEntity);
233 mDrmDisplay->handleDisplayedFrameEntity(expiredFrameEntity);
234tag_next:
235 return true;
236}