blob: be4bc04da8e34e83f7b6320145a08c9b8e80a2c4 [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"
21
22using namespace Tls;
23
24#define TAG "rlib:drm_framepost"
25
26DrmFramePost::DrmFramePost(DrmDisplay *drmDisplay)
27{
28 mDrmDisplay = drmDisplay;
29 mPaused = false;
30 mStop = false;
31 mImmediatelyOutput = false;
32 mQueue = new Tls::Queue();
33 mWinRect.x = 0;
34 mWinRect.y = 0;
35 mWinRect.w = 0;
36 mWinRect.h = 0;
37}
38
39DrmFramePost::~DrmFramePost()
40{
41 if (isRunning()) {
42 mStop = true;
43 DEBUG("stop frame post thread");
44 requestExitAndWait();
45 }
46
47 if (mQueue) {
48 mQueue->flush();
49 delete mQueue;
50 mQueue = NULL;
51 }
52}
53
54bool DrmFramePost::start()
55{
56 DEBUG("start frame post thread");
57 run("frame post thread");
58 return true;
59}
60
61bool DrmFramePost::stop()
62{
63 DEBUG("stop frame post thread");
64 if (isRunning()) {
65 mStop = true;
66 DEBUG("stop frame post thread");
67 requestExitAndWait();
68 }
69 flush();
70 return true;
71}
72
73bool DrmFramePost::readyPostFrame(FrameEntity * frameEntity)
74{
75 std::lock_guard<std::mutex> lck(mMutex);
76 mQueue->push(frameEntity);
77 TRACE("queue cnt:%d",mQueue->getCnt());
78 return true;
79}
80
81void DrmFramePost::flush()
82{
83 FrameEntity *entity;
84 std::lock_guard<std::mutex> lck(mMutex);
85 while (mQueue->pop((void **)&entity) == Q_OK)
86 {
87 mDrmDisplay->handleDropedFrameEntity(entity);
88 mDrmDisplay->handleReleaseFrameEntity(entity);
89 }
90}
91
92void DrmFramePost::pause()
93{
94 mPaused = true;
95}
96
97void DrmFramePost::resume()
98{
99 mPaused = false;
100}
101
102void DrmFramePost::setImmediatelyOutout(bool on)
103{
104 mImmediatelyOutput = on;
105 DEBUG("set immediately output:%d",on);
106}
107
108void DrmFramePost::setWindowSize(int x, int y, int w, int h)
109{
110 mWinRect.x = x;
111 mWinRect.y = y;
112 mWinRect.w = w;
113 mWinRect.h = h;
114}
115
116void DrmFramePost::readyToRun()
117{
118}
119
120bool DrmFramePost::threadLoop()
121{
122 int rc;
123 drmVBlank vbl;
124 int64_t vBlankTime;
125 FrameEntity *curFrameEntity = NULL;
126 FrameEntity *expiredFrameEntity = NULL;
127 long long refreshInterval= 0LL;
128 struct drm_display *drmHandle = mDrmDisplay->getDrmHandle();
129 DrmMesonLib *drmMesonLib = mDrmDisplay->getDrmMesonLib();
130
131 //stop thread
132 if (mStop) {
133 return false;
134 }
135
136 if (!drmHandle) {
137 ERROR("drm handle is NULL");
138 return false;
139 }
140
141 memset(&vbl, 0, sizeof(drmVBlank));
142
143 vbl.request.type = DRM_VBLANK_RELATIVE;
144 vbl.request.sequence = 1;
145 vbl.request.signal = 0;
146
147 //drmWaitBland need link libdrm.so
148 rc = drmWaitVBlank(drmHandle->drm_fd, &vbl);
149 if (rc) {
150 ERROR("drmWaitVBlank error %d", rc);
151 usleep(4000);
152 return true;
153 }
154
155 if (drmHandle->vrefresh)
156 {
157 refreshInterval= (1000000LL+(drmHandle->vrefresh/2))/drmHandle->vrefresh;
158 }
159
160 vBlankTime = vbl.reply.tval_sec*1000000LL + vbl.reply.tval_usec;
161 vBlankTime += refreshInterval; //check next blank time
162
163 std::lock_guard<std::mutex> lck(mMutex);
164 //if queue is empty or paused, loop next
165 if (mQueue->isEmpty() || mPaused) {
166 //TRACE(mLogCategory,"empty or paused");
167 goto tag_next;
168 }
169
170 //we output video frame asap
171 if (mImmediatelyOutput) {
172 //pop the peeked frame
173 mQueue->pop((void **)&expiredFrameEntity);
174 goto tag_post;
175 }
176
177 while (mQueue->peek((void **)&curFrameEntity, 0) == Q_OK)
178 {
179 TRACE("vBlankTime:%lld,frame time:%lld(pts:%lld ms),refreshInterval:%lld",vBlankTime,curFrameEntity->displayTime,curFrameEntity->renderBuf->pts/1000000,refreshInterval);
180 //no frame expired,loop next
181 if (vBlankTime < curFrameEntity->displayTime) {
182 break;
183 }
184
185 //pop the peeked frame
186 mQueue->pop((void **)&curFrameEntity);
187
188 //drop last expired frame,got a new expired frame
189 if (expiredFrameEntity) {
190 DEBUG("drop frame,vBlankTime:%lld,frame time:%lld(pts:%lld ms)",vBlankTime,expiredFrameEntity->displayTime,expiredFrameEntity->renderBuf->pts/1000000);
191 mDrmDisplay->handleDropedFrameEntity(expiredFrameEntity);
192 mDrmDisplay->handleReleaseFrameEntity(expiredFrameEntity);
193 expiredFrameEntity = NULL;
194 }
195
196 expiredFrameEntity = curFrameEntity;
197 TRACE("expire,frame time:%lld(pts:%lld ms)",expiredFrameEntity->displayTime,expiredFrameEntity->renderBuf->pts/1000000);
198 }
199
200tag_post:
201 //no frame will be posted to drm display
202 if (!expiredFrameEntity) {
203 TRACE("no frame expire");
204 goto tag_next;
205 }
206
207 //double check window size before post drm buffer
208 if (mWinRect.w > 0 && mWinRect.h > 0) {
209 struct drm_buf * drmBuf = expiredFrameEntity->drmBuf;
210 drmBuf->crtc_x = mWinRect.x;
211 drmBuf->crtc_y = mWinRect.y;
212 drmBuf->crtc_w = mWinRect.w;
213 drmBuf->crtc_h = mWinRect.h;
214 TRACE("postBuf crtc(%d,%d,%d,%d),src(%d,%d,%d,%d)",drmBuf->crtc_x,drmBuf->crtc_y,drmBuf->crtc_w,drmBuf->crtc_h,
215 drmBuf->src_x,drmBuf->src_y,drmBuf->src_w,drmBuf->src_h);
216 }
217
218 if (drmHandle && drmMesonLib) {
219 rc = drmMesonLib->libDrmPostBuf(drmHandle, expiredFrameEntity->drmBuf);
220 }
221
222 if (rc) {
223 ERROR("drm_post_buf error %d", rc);
224 mDrmDisplay->handleDropedFrameEntity(expiredFrameEntity);
225 mDrmDisplay->handleReleaseFrameEntity(expiredFrameEntity);
226 goto tag_next;
227 }
228
229 TRACE("drm_post_buf,frame time:%lld(pts:%lld ms)",expiredFrameEntity->displayTime,expiredFrameEntity->renderBuf->pts/1000000);
230 mDrmDisplay->handlePostedFrameEntity(expiredFrameEntity);
231 mDrmDisplay->handleDisplayedFrameEntity(expiredFrameEntity);
232tag_next:
233 return true;
234}