blob: d47123c4a3d244a09029a232fd202698772212dc [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 "wayland_plugin.h"
17#include "wayland_display.h"
18#include "Logger.h"
19#include "Times.h"
fei.dengb9a1a572023-09-13 01:33:57 +000020#include "ErrorCode.h"
fei.dengf7a0cd32023-08-29 09:36:37 +000021
22#define TAG "rlib:wayland_plugin"
23
fei.dengb9a1a572023-09-13 01:33:57 +000024WaylandPlugin::WaylandPlugin(int logCatgory)
25 : mRenderLock("renderlock"),
26 mLogCategory(logCatgory)
fei.dengf7a0cd32023-08-29 09:36:37 +000027{
fei.dengb9a1a572023-09-13 01:33:57 +000028 mDisplay = new WaylandDisplay(this, logCatgory);
fei.dengf7a0cd32023-08-29 09:36:37 +000029 mQueue = new Tls::Queue();
30 mPaused = false;
31 mImmediatelyOutput = false;
32}
33
34WaylandPlugin::~WaylandPlugin()
35{
36 if (mDisplay) {
37 delete mDisplay;
38 }
39 if (mQueue) {
40 mQueue->flush();
41 delete mQueue;
42 mQueue = NULL;
43 }
fei.dengb9a1a572023-09-13 01:33:57 +000044 TRACE(mLogCategory,"desconstruct");
fei.dengf7a0cd32023-08-29 09:36:37 +000045}
46
47void WaylandPlugin::init()
48{
fei.dengb9a1a572023-09-13 01:33:57 +000049 INFO(mLogCategory,"\n--------------------------------\n"
fei.dengf7a0cd32023-08-29 09:36:37 +000050 "plugin : weston\n"
51 "ARCH : %s\n"
52 "branch name : %s\n"
53 "git version : %s\n"
54 "change id : %s \n"
55 "ID : %s \n"
56 "last changed: %s\n"
57 "build-time : %s\n"
58 "build-name : %s\n"
59 "--------------------------------\n",
60#if defined(__aarch64__)
61 "arm64",
62#else
63 "arm",
64#endif
65 BRANCH_NAME,
66 GIT_VERSION,
67 COMMIT_CHANGEID,
68 COMMIT_PD,
69 LAST_CHANGED,
70 BUILD_TIME,
71 BUILD_NAME
72 );
73}
74
75void WaylandPlugin::release()
76{
77}
78
79void WaylandPlugin::setCallback(void *userData, PluginCallback *callback)
80{
81 mUserData = userData;
82 mCallback = callback;
83}
84
85int WaylandPlugin::openDisplay()
86{
87 int ret;
88
fei.dengb9a1a572023-09-13 01:33:57 +000089 Tls::Mutex::Autolock _l(mRenderLock);
90 DEBUG(mLogCategory,"openDisplay");
fei.dengf7a0cd32023-08-29 09:36:37 +000091 ret = mDisplay->openDisplay();
fei.dengb9a1a572023-09-13 01:33:57 +000092 if (ret != NO_ERROR) {
93 ERROR(mLogCategory,"Error open display");
94 return ret;
fei.dengf7a0cd32023-08-29 09:36:37 +000095 }
fei.dengb9a1a572023-09-13 01:33:57 +000096 DEBUG(mLogCategory,"openDisplay end");
97 return ret;
fei.dengf7a0cd32023-08-29 09:36:37 +000098}
99
100int WaylandPlugin::openWindow()
101{
fei.dengb9a1a572023-09-13 01:33:57 +0000102 Tls::Mutex::Autolock _l(mRenderLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000103 /* if weston can't support pts feature,
104 * we should create a post buffer thread to
105 * send buffer by mono time
106 */
fei.deng640c3c92024-04-12 08:31:19 +0000107 WaylandDisplay::AmlConfigAPIList *amlconfig = mDisplay->getAmlConfigAPIList();
108 if (!amlconfig->enableSetPts) {
fei.dengb9a1a572023-09-13 01:33:57 +0000109 DEBUG(mLogCategory,"run frame post thread");
fei.dengf7a0cd32023-08-29 09:36:37 +0000110 setThreadPriority(50);
111 run("waylandPostThread");
112 }
fei.dengb9a1a572023-09-13 01:33:57 +0000113 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000114}
115
116int WaylandPlugin::prepareFrame(RenderBuffer *buffer)
117{
118 mDisplay->prepareFrameBuffer(buffer);
fei.dengb9a1a572023-09-13 01:33:57 +0000119 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000120}
121
122int WaylandPlugin::displayFrame(RenderBuffer *buffer, int64_t displayTime)
123{
124 /* if weston can't support pts feature,
125 * push buffer to queue, the buffer will send to
126 * weston in post thread
127 */
fei.deng640c3c92024-04-12 08:31:19 +0000128 WaylandDisplay::AmlConfigAPIList *amlconfig = mDisplay->getAmlConfigAPIList();
129 if (!amlconfig->enableSetPts) {
fei.dengf7a0cd32023-08-29 09:36:37 +0000130 buffer->time = displayTime;
131 mQueue->push(buffer);
fei.deng640c3c92024-04-12 08:31:19 +0000132 DEBUG(mLogCategory,"queue size:%d",mQueue->getCnt());
fei.dengf7a0cd32023-08-29 09:36:37 +0000133 } else {
134 mDisplay->displayFrameBuffer(buffer, displayTime);
135 }
fei.dengb9a1a572023-09-13 01:33:57 +0000136 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000137}
138
139void WaylandPlugin::queueFlushCallback(void *userdata,void *data)
140{
141 WaylandPlugin* plugin = static_cast<WaylandPlugin *>(userdata);
142 plugin->handleFrameDropped((RenderBuffer *)data);
143 plugin->handleBufferRelease((RenderBuffer *)data);
144}
145
146int WaylandPlugin::flush()
147{
148 RenderBuffer *entity;
149 mQueue->flushAndCallback(this, WaylandPlugin::queueFlushCallback);
150 mDisplay->flushBuffers();
fei.dengb9a1a572023-09-13 01:33:57 +0000151 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000152}
153
154int WaylandPlugin::pause()
155{
156 mPaused = true;
fei.dengb9a1a572023-09-13 01:33:57 +0000157 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000158}
159int WaylandPlugin::resume()
160{
161 mPaused = false;
fei.dengb9a1a572023-09-13 01:33:57 +0000162 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000163}
164
165int WaylandPlugin::closeDisplay()
166{
167 RenderBuffer *entity;
fei.dengb9a1a572023-09-13 01:33:57 +0000168 Tls::Mutex::Autolock _l(mRenderLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000169 mDisplay->closeDisplay();
170 while (mQueue->pop((void **)&entity) == Q_OK)
171 {
172 handleBufferRelease(entity);
173 }
174
fei.dengb9a1a572023-09-13 01:33:57 +0000175 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000176}
177
178int WaylandPlugin::closeWindow()
179{
fei.dengb9a1a572023-09-13 01:33:57 +0000180 Tls::Mutex::Autolock _l(mRenderLock);
fei.dengf7a0cd32023-08-29 09:36:37 +0000181 if (isRunning()) {
fei.dengb9a1a572023-09-13 01:33:57 +0000182 DEBUG(mLogCategory,"stop frame post thread");
fei.dengf7a0cd32023-08-29 09:36:37 +0000183 requestExitAndWait();
184 }
fei.dengb9a1a572023-09-13 01:33:57 +0000185 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000186}
187
188
189int WaylandPlugin::getValue(PluginKey key, void *value)
190{
191 switch (key) {
192 case PLUGIN_KEY_SELECT_DISPLAY_OUTPUT: {
193 *(int *)(value) = mDisplay->getDisplayOutput();
fei.dengb9a1a572023-09-13 01:33:57 +0000194 TRACE(mLogCategory,"get select display output:%d",*(int *)value);
fei.dengf7a0cd32023-08-29 09:36:37 +0000195 } break;
fei.dengf1f5fc32023-12-06 06:22:20 +0000196 case PLUGIN_KEY_CURRENT_OUTPUT: {
197 *(int *)(value) = mDisplay->getCurrentOutputCrtcIndex();
198 //DEBUG(mLogCategory,"get current crtc output index:%d",*(int *)value);
199 } break;
fei.dengf7a0cd32023-08-29 09:36:37 +0000200 }
fei.dengb9a1a572023-09-13 01:33:57 +0000201 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000202}
203
204int WaylandPlugin::setValue(PluginKey key, void *value)
205{
206 switch (key) {
207 case PLUGIN_KEY_WINDOW_SIZE: {
208 RenderRect* rect = static_cast<RenderRect*>(value);
209 if (mDisplay) {
210 mDisplay->setWindowSize(rect->x, rect->y, rect->w, rect->h);
211 }
212 } break;
213 case PLUGIN_KEY_FRAME_SIZE: {
214 RenderFrameSize * frameSize = static_cast<RenderFrameSize * >(value);
215 if (mDisplay) {
216 mDisplay->setFrameSize(frameSize->width, frameSize->height);
217 }
218 } break;
219 case PLUGIN_KEY_VIDEO_FORMAT: {
220 int videoFormat = *(int *)(value);
fei.dengb9a1a572023-09-13 01:33:57 +0000221 DEBUG(mLogCategory,"Set video format :%d",videoFormat);
fei.dengf7a0cd32023-08-29 09:36:37 +0000222 mDisplay->setVideoBufferFormat((RenderVideoFormat)videoFormat);
223 } break;
224 case PLUGIN_KEY_SELECT_DISPLAY_OUTPUT: {
225 int outputIndex = *(int *)(value);
fei.dengb9a1a572023-09-13 01:33:57 +0000226 DEBUG(mLogCategory,"Set select display output :%d",outputIndex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000227 mDisplay->setDisplayOutput(outputIndex);
228 } break;
229 case PLUGIN_KEY_VIDEO_PIP: {
230 int pip = *(int *) (value);
231 pip = pip > 0? 1: 0;
232 mDisplay->setPip(pip);
233 } break;
234 case PLUGIN_KEY_IMMEDIATELY_OUTPUT: {
235 bool mImmediatelyOutput = (*(int *)(value)) > 0? true: false;
fei.dengb9a1a572023-09-13 01:33:57 +0000236 DEBUG(mLogCategory, "Set immediately output:%d",mImmediatelyOutput);
fei.dengf7a0cd32023-08-29 09:36:37 +0000237 } break;
fei.deng640c3c92024-04-12 08:31:19 +0000238 case PLUGIN_KEY_KEEP_LAST_FRAME: {
239 int keep = *(int *) (value);
240 DEBUG(mLogCategory, "Set keep last frame:%d",keep);
241 mDisplay->setKeepLastFrame(keep);
242 } break;
fei.dengf7a0cd32023-08-29 09:36:37 +0000243 }
244 return 0;
245}
246
247void WaylandPlugin::handleBufferRelease(RenderBuffer *buffer)
248{
249 if (mCallback) {
250 mCallback->doBufferReleaseCallback(mUserData, (void *)buffer);
251 }
252}
253
254void WaylandPlugin::handleFrameDisplayed(RenderBuffer *buffer)
255{
256 if (mCallback) {
257 mCallback->doBufferDisplayedCallback(mUserData, (void *)buffer);
258 }
259}
260
261void WaylandPlugin::handleFrameDropped(RenderBuffer *buffer)
262{
263 if (mCallback) {
264 mCallback->doBufferDropedCallback(mUserData, (void *)buffer);
265 }
266}
267
fei.deng3287c082024-04-23 09:29:22 +0000268void WaylandPlugin::handleMsgNotify(int type, void *detail)
269{
270 if (mCallback) {
271 mCallback->doMsgCallback(mUserData, type, detail);
272 }
273}
274
fei.dengf7a0cd32023-08-29 09:36:37 +0000275void WaylandPlugin::readyToRun()
276{
277}
278
279bool WaylandPlugin::threadLoop()
280{
281 RenderBuffer *curFrameEntity = NULL;
282 RenderBuffer *expiredFrameEntity = NULL;
283 int64_t nowMonotime = Tls::Times::getSystemTimeUs();
284
285 //if queue is empty or paused, loop next
286 if (mQueue->isEmpty() || mPaused) {
287 goto tag_next;
288 }
289
fei.deng1cfb2752023-10-26 08:01:25 +0000290 //if weston has no wl_outout,it means weston can't display frames
291 //so we should display buffer to display to drop buffers
292 if (mDisplay->getWlOutput() == NULL) {
293 mQueue->pop((void **)&expiredFrameEntity);
294 goto tag_post;
295 }
296
fei.dengf7a0cd32023-08-29 09:36:37 +0000297 //if weston obtains a buffer rendering,we can't send buffer to weston
298 if (mDisplay->isRedrawingPending()) {
299 goto tag_next;
300 }
301
302 //we output video frame asap
303 if (mImmediatelyOutput) {
304 //pop the peeked frame
305 mQueue->pop((void **)&expiredFrameEntity);
306 goto tag_post;
307 }
308
309 while (mQueue->peek((void **)&curFrameEntity, 0) == Q_OK)
310 {
311 //no frame expired,loop next
312 if (nowMonotime < curFrameEntity->time) {
313 break;
314 }
315
316 //pop the peeked frame
317 mQueue->pop((void **)&curFrameEntity);
318
319 //drop last expired frame,got a new expired frame
320 if (expiredFrameEntity) {
fei.dengb9a1a572023-09-13 01:33:57 +0000321 WARNING(mLogCategory,"drop,now:%lld,display:%lld(pts:%lld ms),n-d:%lld ms",
fei.dengf7a0cd32023-08-29 09:36:37 +0000322 nowMonotime,expiredFrameEntity->time,expiredFrameEntity->pts/1000000,
323 (nowMonotime - expiredFrameEntity->time)/1000);
324 handleFrameDropped(expiredFrameEntity);
325 handleBufferRelease(expiredFrameEntity);
326 expiredFrameEntity = NULL;
327 }
328
329 expiredFrameEntity = curFrameEntity;
330 }
331
332tag_post:
333 if (!expiredFrameEntity) {
334 //TRACE(mLogCategory,"no frame expire");
335 goto tag_next;
336 }
337
338 if (mDisplay) {
fei.dengb9a1a572023-09-13 01:33:57 +0000339 TRACE(mLogCategory,"post,now:%lld,display:%lld(pts:%lld ms),n-d::%lld ms",
fei.dengf7a0cd32023-08-29 09:36:37 +0000340 nowMonotime,expiredFrameEntity->time,expiredFrameEntity->pts/1000000,
341 (nowMonotime - expiredFrameEntity->time)/1000);
342 mDisplay->displayFrameBuffer(expiredFrameEntity, expiredFrameEntity->time);
343 }
344
345tag_next:
346 usleep(4*1000);
347 return true;
348}
349
350void *makePluginInstance(int id)
351{
fei.dengb9a1a572023-09-13 01:33:57 +0000352 int category =Logger_init(id);
fei.dengc4677852023-10-09 07:21:04 +0000353 char *env = getenv("VIDEO_RENDER_PLUGIN_LOG_LEVEL");
fei.dengf7a0cd32023-08-29 09:36:37 +0000354 if (env) {
355 int level = atoi(env);
356 Logger_set_level(level);
fei.dengc4677852023-10-09 07:21:04 +0000357 INFO(category,"VIDEO_RENDER_PLUGIN_LOG_LEVEL=%d",level);
fei.dengf7a0cd32023-08-29 09:36:37 +0000358 }
fei.dengb9a1a572023-09-13 01:33:57 +0000359 WaylandPlugin *pluginInstance = new WaylandPlugin(category);
fei.dengf7a0cd32023-08-29 09:36:37 +0000360 return static_cast<void *>(pluginInstance);
361}
362
363void destroyPluginInstance(void * plugin)
364{
fei.dengb9a1a572023-09-13 01:33:57 +0000365 int category;
366
fei.dengf7a0cd32023-08-29 09:36:37 +0000367 WaylandPlugin *pluginInstance = static_cast<WaylandPlugin *>(plugin);
fei.dengb9a1a572023-09-13 01:33:57 +0000368 category = pluginInstance->getLogCategory();
fei.dengf7a0cd32023-08-29 09:36:37 +0000369 delete pluginInstance;
fei.dengb9a1a572023-09-13 01:33:57 +0000370 Logger_exit(category);
fei.dengf7a0cd32023-08-29 09:36:37 +0000371}