blob: 18151df82c63f0e5bc66ab8655a50d09ceb440d4 [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 <string>
17#include "wayland_display.h"
fei.dengb9a1a572023-09-13 01:33:57 +000018#include "ErrorCode.h"
fei.dengf7a0cd32023-08-29 09:36:37 +000019#include "Logger.h"
20#include "wayland_plugin.h"
21#include "wayland_videoformat.h"
22#include "wayland_shm.h"
23#include "wayland_dma.h"
24#include "wayland_buffer.h"
25
26#ifndef MAX
27# define MAX(a,b) ((a) > (b)? (a) : (b))
28# define MIN(a,b) ((a) < (b)? (a) : (b))
29#endif
30
31#define UNUSED_PARAM(x) ((void)(x))
fei.deng26950832023-11-09 03:00:23 +000032#define INVALID_OUTPUT_INDEX (-1)
fei.dengf7a0cd32023-08-29 09:36:37 +000033
34#define TAG "rlib:wayland_display"
fei.deng649b0e22024-09-03 18:57:13 +080035#define FRAME_FREEZE_THRESHOLD(x) (x*1.67)
36#define DETECT_FRAMERATE_CNT (5)
fei.dengf7a0cd32023-08-29 09:36:37 +000037
38void WaylandDisplay::dmabuf_modifiers(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
39 uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo)
40{
41 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
fei.dengb9a1a572023-09-13 01:33:57 +000042 Tls::Mutex::Autolock _l(self->mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +000043 if (wl_dmabuf_format_to_video_format (format) != VIDEO_FORMAT_UNKNOWN) {
fei.dengb9a1a572023-09-13 01:33:57 +000044 TRACE(self->mLogCategory,"regist dmabuffer format:%d (%s) hi:%x,lo:%x",format,print_dmabuf_format_name(format),modifier_hi,modifier_lo);
fei.dengf7a0cd32023-08-29 09:36:37 +000045 uint64_t modifier = ((uint64_t)modifier_hi << 32) | modifier_lo;
46 auto item = self->mDmaBufferFormats.find(format);
47 if (item == self->mDmaBufferFormats.end()) {
48 std::pair<uint32_t ,uint64_t> item(format, modifier);
49 self->mDmaBufferFormats.insert(item);
50 } else { //found format
51 item->second = modifier;
52 }
53 }
54}
55
56void
57WaylandDisplay::dmaBufferFormat (void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
58 uint32_t format)
59{
60#if 0
61 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
62
63 if (wl_dmabuf_format_to_video_format (format) != VIDEO_FORMAT_UNKNOWN) {
64 TRACE(mLogCategory,"regist dmabuffer format:%d : %s",format);
65 //self->mDmaBufferFormats.push_back(format);
66 }
67#endif
68 /* XXX: deprecated */
69}
70
71static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
72 WaylandDisplay::dmaBufferFormat,
73 WaylandDisplay::dmabuf_modifiers
74};
75
76static void
77handle_xdg_wm_base_ping (void *user_data, struct xdg_wm_base *xdg_wm_base,
78 uint32_t serial)
79{
80 xdg_wm_base_pong (xdg_wm_base, serial);
81}
82
83static const struct xdg_wm_base_listener xdg_wm_base_listener = {
84 handle_xdg_wm_base_ping
85};
86
87void WaylandDisplay::shmFormat(void *data, struct wl_shm *wl_shm, uint32_t format)
88{
89 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
90 self->mShmFormats.push_back(format);
91}
92
93static const struct wl_shm_listener shm_listener = {
94 WaylandDisplay::shmFormat
95};
96
97void WaylandDisplay::outputHandleGeometry( void *data,
98 struct wl_output *output,
99 int x,
100 int y,
101 int physicalWidth,
102 int physicalHeight,
103 int subPixel,
104 const char *make,
105 const char *model,
106 int transform )
107{
108 UNUSED_PARAM(make);
109 UNUSED_PARAM(model);
110
111 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
fei.dengb9a1a572023-09-13 01:33:57 +0000112 DEBUG(self->mLogCategory,"wl_output %p x:%d,y:%d,physicalWidth:%d,physicalHeight:%d,subPixel:%d,trans:%d",
113 output,x, y,physicalWidth, physicalHeight,subPixel,transform);
114 Tls::Mutex::Autolock _l(self->mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000115 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
116 if (output == self->mOutput[i].wlOutput) {
117 self->mOutput[i].offsetX = x;
118 self->mOutput[i].offsetY = y;
119 }
120 }
121}
122
123void WaylandDisplay::outputHandleMode( void *data,
124 struct wl_output *output,
125 uint32_t flags,
126 int width,
127 int height,
128 int refreshRate )
129{
130 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
131
132 if ( flags & WL_OUTPUT_MODE_CURRENT ) {
fei.dengb9a1a572023-09-13 01:33:57 +0000133 Tls::Mutex::Autolock _l(self->mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000134 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
135 if (output == self->mOutput[i].wlOutput) {
136 self->mOutput[i].width = width;
137 self->mOutput[i].height = height;
138 self->mOutput[i].refreshRate = refreshRate;
139 }
140 }
fei.deng26950832023-11-09 03:00:23 +0000141
142 DEBUG(self->mLogCategory,"wl_output: %p (%dx%d) refreshrate:%d,select output index %d",output, width, height,refreshRate,self->mSelectOutputIndex);
143 if (self->mCurrentDisplayOutput->width > 0 &&
144 self->mCurrentDisplayOutput->height > 0) {
145 self->updateDisplayOutput();
fei.dengf7a0cd32023-08-29 09:36:37 +0000146 }
147 }
148}
149
150void WaylandDisplay::outputHandleDone( void *data,
151 struct wl_output *output )
152{
fei.dengf1f5fc32023-12-06 06:22:20 +0000153 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
154 DEBUG(self->mLogCategory,"wl_output: %p",output);
fei.dengf7a0cd32023-08-29 09:36:37 +0000155 UNUSED_PARAM(data);
156 UNUSED_PARAM(output);
157}
158
159void WaylandDisplay::outputHandleScale( void *data,
160 struct wl_output *output,
161 int32_t scale )
162{
fei.dengf1f5fc32023-12-06 06:22:20 +0000163 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
164 DEBUG(self->mLogCategory,"wl_output: %p scale %d",output, scale);
fei.dengf7a0cd32023-08-29 09:36:37 +0000165 UNUSED_PARAM(data);
166 UNUSED_PARAM(output);
167 UNUSED_PARAM(scale);
168}
169
fei.dengf1f5fc32023-12-06 06:22:20 +0000170void WaylandDisplay::outputHandleCrtcIndex( void *data,
171 struct wl_output *output,
172 int32_t index )
173{
174 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
175 DEBUG(self->mLogCategory,"wl_output: %p crtc index %d",output, index);
176 Tls::Mutex::Autolock _l(self->mMutex);
177 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
178 if (output == self->mOutput[i].wlOutput) {
179 self->mOutput[i].crtcIndex = index;
180 }
181 }
182}
183
fei.deng640c3c92024-04-12 08:31:19 +0000184//aml weston always add crtcIndex in callbacks.
fei.dengf7a0cd32023-08-29 09:36:37 +0000185static const struct wl_output_listener outputListener = {
186 WaylandDisplay::outputHandleGeometry,
187 WaylandDisplay::outputHandleMode,
188 WaylandDisplay::outputHandleDone,
fei.dengf1f5fc32023-12-06 06:22:20 +0000189 WaylandDisplay::outputHandleScale,
190 WaylandDisplay::outputHandleCrtcIndex,
fei.dengf7a0cd32023-08-29 09:36:37 +0000191};
192
193void WaylandDisplay::pointerHandleEnter(void *data, struct wl_pointer *pointer,
194 uint32_t serial, struct wl_surface *surface,
195 wl_fixed_t sx, wl_fixed_t sy)
196{
197 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
198
199 if (self->mFullScreen) {
200 wl_pointer_set_cursor(pointer, serial, NULL, 0, 0);
201 }
202}
203
204void WaylandDisplay::pointerHandleLeave(void *data, struct wl_pointer *pointer,
205 uint32_t serial, struct wl_surface *surface)
206{
207 UNUSED_PARAM(data);
208 UNUSED_PARAM(pointer);
209 UNUSED_PARAM(serial);
210 UNUSED_PARAM(surface);
211}
212
213void WaylandDisplay::pointerHandleMotion(void *data, struct wl_pointer *pointer,
214 uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
215{
216 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
217 int x = wl_fixed_to_int(sx);
218 int y = wl_fixed_to_int(sy);
fei.dengb9a1a572023-09-13 01:33:57 +0000219 DEBUG(self->mLogCategory,"pointer motion fixed[%d, %d] to-int: x[%d] y[%d]\n", sx, sy, x, y);
fei.dengf7a0cd32023-08-29 09:36:37 +0000220}
221
222void WaylandDisplay::pointerHandleButton(void *data, struct wl_pointer *wl_pointer,
223 uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
224{
225 UNUSED_PARAM(data);
226 UNUSED_PARAM(wl_pointer);
227 UNUSED_PARAM(time);
228 UNUSED_PARAM(serial);
229 UNUSED_PARAM(button);
230 UNUSED_PARAM(state);
231}
232
233void WaylandDisplay::pointerHandleAxis(void *data, struct wl_pointer *wl_pointer,
234 uint32_t time, uint32_t axis, wl_fixed_t value)
235{
236 UNUSED_PARAM(data);
237 UNUSED_PARAM(wl_pointer);
238 UNUSED_PARAM(time);
239 UNUSED_PARAM(axis);
240 UNUSED_PARAM(value);
241}
242
243static const struct wl_pointer_listener pointer_listener = {
244 WaylandDisplay::pointerHandleEnter,
245 WaylandDisplay::pointerHandleLeave,
246 WaylandDisplay::pointerHandleMotion,
247 WaylandDisplay::pointerHandleButton,
248 WaylandDisplay::pointerHandleAxis,
249};
250
251void WaylandDisplay::touchHandleDown(void *data, struct wl_touch *wl_touch,
252 uint32_t serial, uint32_t time, struct wl_surface *surface,
253 int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
254{
255 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
256}
257
258void WaylandDisplay::touchHandleUp(void *data, struct wl_touch *wl_touch,
259 uint32_t serial, uint32_t time, int32_t id)
260{
261 UNUSED_PARAM(data);
262 UNUSED_PARAM(wl_touch);
263 UNUSED_PARAM(serial);
264 UNUSED_PARAM(time);
265 UNUSED_PARAM(id);
266}
267
268void WaylandDisplay::touchHandleMotion(void *data, struct wl_touch *wl_touch,
269 uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
270{
271 UNUSED_PARAM(data);
272 UNUSED_PARAM(wl_touch);
273 UNUSED_PARAM(time);
274 UNUSED_PARAM(id);
275 UNUSED_PARAM(x_w);
276 UNUSED_PARAM(y_w);
277}
278
279void WaylandDisplay::touchHandleFrame(void *data, struct wl_touch *wl_touch)
280{
281 UNUSED_PARAM(data);
282 UNUSED_PARAM(wl_touch);
283}
284
285void WaylandDisplay::touchHandleCancel(void *data, struct wl_touch *wl_touch)
286{
287 UNUSED_PARAM(data);
288 UNUSED_PARAM(wl_touch);
289}
290
291static const struct wl_touch_listener touch_listener = {
292 WaylandDisplay::touchHandleDown,
293 WaylandDisplay::touchHandleUp,
294 WaylandDisplay::touchHandleMotion,
295 WaylandDisplay::touchHandleFrame,
296 WaylandDisplay::touchHandleCancel,
297};
298
299void WaylandDisplay::keyboardHandleKeymap(void *data, struct wl_keyboard *keyboard,
300 uint32_t format, int fd, uint32_t size)
301{
302 UNUSED_PARAM(data);
303 UNUSED_PARAM(keyboard);
304 UNUSED_PARAM(format);
305 UNUSED_PARAM(fd);
306 UNUSED_PARAM(size);
307}
308
309void WaylandDisplay::keyboardHandleEnter(void *data, struct wl_keyboard *keyboard,
310 uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
311{
312 UNUSED_PARAM(data);
313 UNUSED_PARAM(keyboard);
314 UNUSED_PARAM(serial);
315 UNUSED_PARAM(surface);
316 UNUSED_PARAM(keys);
317}
318
319void WaylandDisplay::keyboardHandleLeave(void *data, struct wl_keyboard *keyboard,
320 uint32_t serial, struct wl_surface *surface)
321{
322 UNUSED_PARAM(data);
323 UNUSED_PARAM(keyboard);
324 UNUSED_PARAM(serial);
325 UNUSED_PARAM(surface);
326}
327
328void WaylandDisplay::keyboardHandleKey(void *data, struct wl_keyboard *keyboard,
329 uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
330{
331 UNUSED_PARAM(data);
332 UNUSED_PARAM(keyboard);
333 UNUSED_PARAM(serial);
334 UNUSED_PARAM(time);
335 UNUSED_PARAM(key);
336 UNUSED_PARAM(state);
337}
338
339void WaylandDisplay::keyboardHandleModifiers(void *data, struct wl_keyboard *keyboard,
340 uint32_t serial, uint32_t mods_depressed,
341 uint32_t mods_latched, uint32_t mods_locked,
342 uint32_t group)
343{
344 UNUSED_PARAM(data);
345 UNUSED_PARAM(keyboard);
346 UNUSED_PARAM(serial);
347 UNUSED_PARAM(mods_depressed);
348 UNUSED_PARAM(mods_latched);
349 UNUSED_PARAM(mods_locked);
350 UNUSED_PARAM(group);
351}
352
353static const struct wl_keyboard_listener keyboard_listener = {
354 WaylandDisplay::keyboardHandleKeymap,
355 WaylandDisplay::keyboardHandleEnter,
356 WaylandDisplay::keyboardHandleLeave,
357 WaylandDisplay::keyboardHandleKey,
358 WaylandDisplay::keyboardHandleModifiers,
359};
360
361void WaylandDisplay::seatHandleCapabilities(void *data, struct wl_seat *seat,
362 uint32_t caps)
363{
364 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
365 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !self->mPointer) {
366 self->mPointer = wl_seat_get_pointer(seat);
367 wl_pointer_add_listener(self->mPointer, &pointer_listener, data);
368 } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && self->mPointer) {
369 wl_pointer_destroy(self->mPointer);
370 self->mPointer = NULL;
371 }
372
373 if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !self->mKeyboard) {
374 self->mKeyboard = wl_seat_get_keyboard(seat);
375 wl_keyboard_add_listener(self->mKeyboard, &keyboard_listener, data);
376 } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && self->mKeyboard) {
377 wl_keyboard_destroy(self->mKeyboard);
378 self->mKeyboard = NULL;
379 }
380
381 if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !self->mTouch) {
382 self->mTouch = wl_seat_get_touch(seat);
383 wl_touch_set_user_data(self->mTouch, data);
384 wl_touch_add_listener(self->mTouch, &touch_listener, data);
385 } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && self->mTouch) {
386 wl_touch_destroy(self->mTouch);
387 self->mTouch = NULL;
388 }
389}
390
391static const struct wl_seat_listener seat_listener = {
392 WaylandDisplay::seatHandleCapabilities,
393};
394
395
396void WaylandDisplay::handleXdgToplevelClose (void *data, struct xdg_toplevel *xdg_toplevel)
397{
398 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
399
fei.dengb9a1a572023-09-13 01:33:57 +0000400 INFO(self->mLogCategory,"XDG toplevel got a close event.");
fei.dengf7a0cd32023-08-29 09:36:37 +0000401}
402
403void WaylandDisplay::handleXdgToplevelConfigure (void *data, struct xdg_toplevel *xdg_toplevel,
404 int32_t width, int32_t height, struct wl_array *states)
405{
406 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
407 uint32_t *state;
408
fei.dengb9a1a572023-09-13 01:33:57 +0000409 INFO(self->mLogCategory, "XDG toplevel got a configure event, width:height [ %d, %d ].", width, height);
fei.dengf7a0cd32023-08-29 09:36:37 +0000410 /*
411 wl_array_for_each (state, states) {
412 switch (*state) {
413 case XDG_TOPLEVEL_STATE_FULLSCREEN:
414 case XDG_TOPLEVEL_STATE_MAXIMIZED:
415 case XDG_TOPLEVEL_STATE_RESIZING:
416 case XDG_TOPLEVEL_STATE_ACTIVATED:
417 break;
418 }
419 }
420 */
421
422 if (width <= 0 || height <= 0)
423 return;
424
fei.deng26950832023-11-09 03:00:23 +0000425 if (width == self->mCurrentDisplayOutput->width && height == self->mCurrentDisplayOutput->height && self->mUpdateRenderRectangle) {
426 self->mUpdateRenderRectangle = false;
427 self->setRenderRectangle(self->mCurrentDisplayOutput->offsetX,
428 self->mCurrentDisplayOutput->offsetY,
429 self->mCurrentDisplayOutput->width,
430 self->mCurrentDisplayOutput->height);
fei.dengf7a0cd32023-08-29 09:36:37 +0000431 } else{
432 self->setRenderRectangle(self->mRenderRect.x, self->mRenderRect.y, width, height);
433 }
434}
435
436static const struct xdg_toplevel_listener xdg_toplevel_listener = {
437 WaylandDisplay::handleXdgToplevelConfigure,
438 WaylandDisplay::handleXdgToplevelClose,
439};
440
441void WaylandDisplay::handleXdgSurfaceConfigure (void *data, struct xdg_surface *xdg_surface,
442 uint32_t serial)
443{
444 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
445 xdg_surface_ack_configure (xdg_surface, serial);
446
fei.dengb9a1a572023-09-13 01:33:57 +0000447 TRACE(self->mLogCategory,"handleXdgSurfaceConfigure");
448 Tls::Mutex::Autolock _l(self->mConfigureMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000449 self->mXdgSurfaceConfigured = true;
fei.deng26950832023-11-09 03:00:23 +0000450 self->updateDisplayOutput();
fei.dengf7a0cd32023-08-29 09:36:37 +0000451}
452
453static const struct xdg_surface_listener xdg_surface_listener = {
454 WaylandDisplay::handleXdgSurfaceConfigure,
455};
456
fei.dengd0da4e22024-07-04 11:29:13 +0800457void WaylandDisplay::handleSurfaceDestroy(void *data, struct wl_callback *callback, uint32_t time)
458{
459 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
460 INFO(self->mLogCategory,"handle video surface destroy");
461 Tls::Mutex::Autolock _l(self->mMutex);
462 self->mCondition.signal();
463 wl_callback_destroy (callback);
464}
465
466static const struct wl_callback_listener surface_destroy_listener = {
467 WaylandDisplay::handleSurfaceDestroy,
468};
469
fei.deng640c3c92024-04-12 08:31:19 +0000470void WaylandDisplay::amlConfigure(void *data, struct aml_config *config, const char *list) {
471 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
472 TRACE(self->mLogCategory,"aml_config:%s",list);
473 if (list && strlen(list) > 0) {
474 if (strstr(list, "set_video_plane")) {
475 TRACE(self->mLogCategory,"weston enable set_video_plane");
476 self->mAmlConfigAPIList.enableSetVideoPlane = true;
477 }
478 if (strstr(list, "set_pts")) {
479 TRACE(self->mLogCategory,"weston enable set_pts");
480 self->mAmlConfigAPIList.enableSetPts = true;
481 }
482 if (strstr(list, "drop")) {
483 TRACE(self->mLogCategory,"weston enable drop");
484 self->mAmlConfigAPIList.enableDropFrame = true;
485 }
486 if (strstr(list, "keep_last_frame")) {
487 TRACE(self->mLogCategory,"weston enable keep_last_frame");
488 self->mAmlConfigAPIList.enableKeepLastFrame = true;
489 }
fei.dengd0da4e22024-07-04 11:29:13 +0800490 if (strstr(list, "surface_destroy_cb")) {
491 TRACE(self->mLogCategory,"weston enable surface_destroy_cb");
492 self->mAmlConfigAPIList.enableSurfaceDestroyCallback = true;
493 }
fei.deng6c425232024-07-19 16:15:31 +0800494 if (strstr(list, "set_display_rate")) {
495 TRACE(self->mLogCategory,"weston enable set_display_rate");
496 self->mAmlConfigAPIList.enableSetDisplayRate = true;
497 }
fei.deng9bf724e2024-08-01 11:34:52 +0800498 if (strstr(list, "set_surface_invisible")) {
499 TRACE(self->mLogCategory,"weston enable set_surface_invisible");
500 self->mAmlConfigAPIList.enableSetSurfaceInvisible = true;
501 }
fei.deng649b0e22024-09-03 18:57:13 +0800502 if (strstr(list, "display_time")) {
503 TRACE(self->mLogCategory,"weston enable display_time");
504 self->mAmlConfigAPIList.enableDisplayTime = true;
505 }
fei.deng640c3c92024-04-12 08:31:19 +0000506 }
507}
508
509static const struct aml_config_listener aml_config_listener = {
510 WaylandDisplay::amlConfigure,
511};
512
fei.dengf7a0cd32023-08-29 09:36:37 +0000513void
514WaylandDisplay::registryHandleGlobal (void *data, struct wl_registry *registry,
fei.dengaf9b07d2023-10-10 07:38:40 +0000515 uint32_t name, const char *interface, uint32_t version)
fei.dengf7a0cd32023-08-29 09:36:37 +0000516{
517 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
fei.dengaf9b07d2023-10-10 07:38:40 +0000518 TRACE(self->mLogCategory,"registryHandleGlobal,name:%u,interface:%s,version:%d",name,interface,version);
fei.dengf7a0cd32023-08-29 09:36:37 +0000519
520 if (strcmp (interface, "wl_compositor") == 0) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000521 self->mCompositor = (struct wl_compositor *)wl_registry_bind (registry, name, &wl_compositor_interface, 1/*MIN (version, 3)*/);
fei.dengf7a0cd32023-08-29 09:36:37 +0000522 } else if (strcmp (interface, "wl_subcompositor") == 0) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000523 self->mSubCompositor = (struct wl_subcompositor *)wl_registry_bind (registry, name, &wl_subcompositor_interface, 1);
fei.dengf7a0cd32023-08-29 09:36:37 +0000524 } else if (strcmp (interface, "xdg_wm_base") == 0) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000525 self->mXdgWmBase = (struct xdg_wm_base *)wl_registry_bind (registry, name, &xdg_wm_base_interface, 1);
fei.dengf7a0cd32023-08-29 09:36:37 +0000526 xdg_wm_base_add_listener (self->mXdgWmBase, &xdg_wm_base_listener, (void *)self);
527 } else if (strcmp (interface, "wl_shm") == 0) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000528 self->mShm = (struct wl_shm *)wl_registry_bind (registry, name, &wl_shm_interface, 1);
fei.dengf7a0cd32023-08-29 09:36:37 +0000529 wl_shm_add_listener (self->mShm, &shm_listener, self);
530 } else if (strcmp (interface, "zwp_fullscreen_shell_v1") == 0) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000531 //self->mFullscreenShell = (struct zwp_fullscreen_shell_v1 *)wl_registry_bind (registry, name,
fei.dengf7a0cd32023-08-29 09:36:37 +0000532 // &zwp_fullscreen_shell_v1_interface, 1);
533 } else if (strcmp (interface, "wp_viewporter") == 0) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000534 self->mViewporter = (struct wp_viewporter *)wl_registry_bind (registry, name, &wp_viewporter_interface, 1);
fei.dengf7a0cd32023-08-29 09:36:37 +0000535 } else if (strcmp (interface, "zwp_linux_dmabuf_v1") == 0) {
536 if (version < 3)
537 return;
fei.dengaf9b07d2023-10-10 07:38:40 +0000538 self->mDmabuf = (struct zwp_linux_dmabuf_v1 *)wl_registry_bind (registry, name, &zwp_linux_dmabuf_v1_interface, 3);
fei.dengf7a0cd32023-08-29 09:36:37 +0000539 zwp_linux_dmabuf_v1_add_listener (self->mDmabuf, &dmabuf_listener, (void *)self);
540 } else if (strcmp (interface, "wl_output") == 0) {
fei.deng26950832023-11-09 03:00:23 +0000541 int i = 0;
542 uint32_t oriName = self->mCurrentDisplayOutput->name;
fei.dengaf9b07d2023-10-10 07:38:40 +0000543 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
544 if (self->mOutput[i].wlOutput == NULL) {
545 self->mOutput[i].name = name;
546 self->mOutput[i].wlOutput = (struct wl_output*)wl_registry_bind(registry, name, &wl_output_interface, version);
fei.deng26950832023-11-09 03:00:23 +0000547 TRACE(self->mLogCategory,"name:%u, wl_output:%p, select:%d",self->mOutput[i].name,self->mOutput[i].wlOutput,self->mSelectOutputIndex);
fei.dengaf9b07d2023-10-10 07:38:40 +0000548 wl_output_add_listener(self->mOutput[i].wlOutput, &outputListener, (void *)self);
549 if (i == 0) { //primary wl_output
550 self->mOutput[i].isPrimary = true;
551 }
fei.deng26950832023-11-09 03:00:23 +0000552 break;
fei.dengaf9b07d2023-10-10 07:38:40 +0000553 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000554 }
fei.deng26950832023-11-09 03:00:23 +0000555 if (i == DEFAULT_DISPLAY_OUTPUT_NUM) {
556 WARNING(self->mLogCategory,"Not enough free output");
557 }
558 //select current wl_output
559 if (self->mSelectOutputIndex != INVALID_OUTPUT_INDEX && !self->isRunning()) {
560 TRACE(self->mLogCategory,"select %d output",self->mSelectOutputIndex);
561 self->mCurrentDisplayOutput = &self->mOutput[self->mSelectOutputIndex];
562 }
563 //if user select a wrong output index, we using a suiteble wl_output
564 if (self->mCurrentDisplayOutput->wlOutput == NULL) {
565 WARNING(self->mLogCategory,"wl_output is null,we should find a suiteble output");
566 for (i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
567 if (self->mOutput[i].wlOutput) {
568 self->mCurrentDisplayOutput = &self->mOutput[i];
569 break;
570 }
571 }
572 }
573 //if current wl_output update, we should update render rectangle
574 if (self->mCurrentDisplayOutput->name != oriName) {
575 self->mUpdateRenderRectangle = true;
576 }
577 //if wl_output plugin,active sending frame
578 self->setRedrawingPending(false);
fei.dengf7a0cd32023-08-29 09:36:37 +0000579 } else if (strcmp(interface, "wl_seat") == 0) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000580 //self->mSeat = (struct wl_seat *)wl_registry_bind(registry, name, &wl_seat_interface, 1);
fei.dengf7a0cd32023-08-29 09:36:37 +0000581 //wl_seat_add_listener(self->mSeat, &seat_listener, (void *)self);
fei.deng31f93f12024-02-27 07:52:10 +0000582 } else if (strcmp(interface, "weston_direct_display_v1") == 0) {
583 self->mDirect_display = (struct weston_direct_display_v1 *)wl_registry_bind(registry,name, &weston_direct_display_v1_interface, 1);
fei.deng640c3c92024-04-12 08:31:19 +0000584 } else if (strcmp(interface, "aml_config") == 0) {
585 self->mAmlConfig = (struct aml_config*)wl_registry_bind(registry, name, &aml_config_interface, 1);
586 aml_config_add_listener(self->mAmlConfig, &aml_config_listener, (void *)self);
fei.dengf7a0cd32023-08-29 09:36:37 +0000587 }
588}
589
590void
591WaylandDisplay::registryHandleGlobalRemove (void *data, struct wl_registry *registry, uint32_t name)
592{
fei.deng26950832023-11-09 03:00:23 +0000593 int i;
fei.dengf7a0cd32023-08-29 09:36:37 +0000594 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
fei.dengaf9b07d2023-10-10 07:38:40 +0000595 /* check wl_output changed */
596 DEBUG(self->mLogCategory,"wayland display remove registry handle global,name:%u",name);
fei.deng26950832023-11-09 03:00:23 +0000597 //if user selected wl_output removed, reset selected output index
598 if (self->mSelectOutputIndex != INVALID_OUTPUT_INDEX &&
599 self->mOutput[self->mSelectOutputIndex].wlOutput &&
600 self->mOutput[self->mSelectOutputIndex].name == name) {
601 self->mSelectOutputIndex = INVALID_OUTPUT_INDEX;
602 }
603 for (i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000604 if (self->mOutput[i].name == name) {
fei.deng26950832023-11-09 03:00:23 +0000605 DEBUG(self->mLogCategory,"remove wl_output name:%u,wl_output:%p",name,self->mOutput[i].wlOutput);
fei.dengaf9b07d2023-10-10 07:38:40 +0000606 self->mOutput[i].name = 0;
607 self->mOutput[i].wlOutput = NULL;
fei.deng26950832023-11-09 03:00:23 +0000608 }
609 }
610 //if current output removed, select a suiteble output
611 if (self->mCurrentDisplayOutput->wlOutput == NULL) {
612 for (i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
613 if (self->mOutput[i].wlOutput) {
614 self->mCurrentDisplayOutput = &self->mOutput[i];
615 self->mUpdateRenderRectangle = true;
616 }
617 }
618 //set new output rectangle
619 if (self->mUpdateRenderRectangle) {
620 self->mUpdateRenderRectangle = false;
621 self->setRenderRectangle(self->mCurrentDisplayOutput->offsetX,
622 self->mCurrentDisplayOutput->offsetY,
623 self->mCurrentDisplayOutput->width,
624 self->mCurrentDisplayOutput->height);
fei.dengaf9b07d2023-10-10 07:38:40 +0000625 }
626 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000627}
628
629static const struct wl_registry_listener registry_listener = {
630 WaylandDisplay::registryHandleGlobal,
631 WaylandDisplay::registryHandleGlobalRemove
632};
633
fei.dengb9a1a572023-09-13 01:33:57 +0000634WaylandDisplay::WaylandDisplay(WaylandPlugin *plugin, int logCategory)
635 :mBufferMutex("bufferMutex"),
636 mWaylandPlugin(plugin),
637 mLogCategory(logCategory)
fei.dengf7a0cd32023-08-29 09:36:37 +0000638{
fei.dengb9a1a572023-09-13 01:33:57 +0000639 TRACE(mLogCategory,"construct WaylandDisplay");
fei.dengf7a0cd32023-08-29 09:36:37 +0000640 mWlDisplay = NULL;
641 mWlDisplayWrapper = NULL;
642 mWlQueue = NULL;
643 mRegistry = NULL;
644 mCompositor = NULL;
645 mXdgWmBase = NULL;
646 mViewporter = NULL;
647 mDmabuf = NULL;
648 mShm = NULL;
649 mSeat = NULL;
650 mPointer = NULL;
651 mTouch = NULL;
652 mKeyboard = NULL;
fei.deng31f93f12024-02-27 07:52:10 +0000653 mDirect_display = NULL;
fei.deng26950832023-11-09 03:00:23 +0000654 mSelectOutputIndex = INVALID_OUTPUT_INDEX;
fei.dengb9a1a572023-09-13 01:33:57 +0000655 mPoll = new Tls::Poll(true);
fei.dengf7a0cd32023-08-29 09:36:37 +0000656 //window
657 mVideoWidth = 0;
658 mVideoHeight = 0;
659 mVideoSurface = NULL;
660 mXdgSurface = NULL;
661 mXdgToplevel = NULL;
662 mAreaViewport = NULL;
663 mVideoViewport = NULL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000664 mAreaShmBuffer = NULL;
665 mCommitCnt = 0;
fei.dengf7a0cd32023-08-29 09:36:37 +0000666 mAreaSurface = NULL;
667 mAreaSurfaceWrapper = NULL;
668 mVideoSurfaceWrapper = NULL;
669 mVideoSubSurface = NULL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000670 mPip = 0;
fei.deng640c3c92024-04-12 08:31:19 +0000671 mKeepLastFrame = 0; //default is off keep last frame
fei.deng3287c082024-04-23 09:29:22 +0000672 mSignalFirstFramePts = false;
fei.deng4029e682024-06-26 17:06:31 +0800673 mToSendKeepLastFrame = false;
fei.deng1c94a342024-08-05 19:33:28 +0800674 mVideoPlaneZorder = -1;
675 mVideoPlaneZorderChanged = false;
fei.dengf7a0cd32023-08-29 09:36:37 +0000676}
677
678WaylandDisplay::~WaylandDisplay()
679{
fei.dengb9a1a572023-09-13 01:33:57 +0000680 TRACE(mLogCategory,"desconstruct WaylandDisplay");
681 if (mPoll) {
682 delete mPoll;
683 mPoll = NULL;
684 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000685}
686
687char *WaylandDisplay::require_xdg_runtime_dir()
688{
689 char *val = getenv("XDG_RUNTIME_DIR");
fei.dengb9a1a572023-09-13 01:33:57 +0000690 INFO(mLogCategory,"XDG_RUNTIME_DIR=%s",val);
fei.dengdd910ef2024-06-07 10:25:30 +0800691 //if not set XDG_RUNTIME_DIR,set default value
692 // if (!val) {
693 // val = const_cast<char *>("/run/user/0");
694 // setenv("XDG_RUNTIME_DIR",val,0);
695 // WARNING(mLogCategory,"XDG_RUNTIME_DIR is not set,set default %s",val);
696 // }
fei.dengf7a0cd32023-08-29 09:36:37 +0000697
698 return val;
699}
700
701int WaylandDisplay::openDisplay()
702{
fei.deng649b0e22024-09-03 18:57:13 +0800703 mLastDisplayFramePts = -1;
704 mLastDisplayFrameTimeUs = -1;
705 mFrameDurationUs = 0;
706 mPreFramePts = -1;
707 mFrameRateDetectCnt = 0;
708 mFrameRateDetectPeriod = 0;
fei.denga4abbd52024-07-11 19:17:50 +0800709 mPixelAspectRatio = 1.0;
710 mUpdateVideoSurface = false;
fei.dengdd910ef2024-06-07 10:25:30 +0800711 mNoBorderUpdate = false;
712 mReCommitAreaSurface = false;
713 mXdgSurfaceConfigured = false;
714 mUpdateRenderRectangle = false;
fei.deng6c425232024-07-19 16:15:31 +0800715 mFrameRateFractionNum = 0;
716 mFrameRateFractionDenom = 1;
717 mFrameRateChanged = false;
fei.deng1c94a342024-08-05 19:33:28 +0800718 mVideoPlaneZorder = -1;
719 mVideoPlaneZorderChanged = false;
fei.dengdd910ef2024-06-07 10:25:30 +0800720 memset(&mRenderRect, 0, sizeof(struct Rectangle));
721 memset(&mVideoRect, 0, sizeof(struct Rectangle));
722 memset(&mWindowRect, 0, sizeof(struct Rectangle));
723 mFullScreen = true; //default is full screen
724 mAmlConfig = NULL;
725 //weston config private api
726 mAmlConfigAPIList.enableDropFrame = false;
727 mAmlConfigAPIList.enableKeepLastFrame = false;
728 mAmlConfigAPIList.enableSetPts = false;
729 mAmlConfigAPIList.enableSetVideoPlane = false;
fei.dengd0da4e22024-07-04 11:29:13 +0800730 mAmlConfigAPIList.enableSurfaceDestroyCallback = false;
fei.deng6c425232024-07-19 16:15:31 +0800731 mAmlConfigAPIList.enableSetDisplayRate = false;
fei.deng9bf724e2024-08-01 11:34:52 +0800732 mAmlConfigAPIList.enableSetSurfaceInvisible = false;
fei.deng649b0e22024-09-03 18:57:13 +0800733 mAmlConfigAPIList.enableDisplayTime = false;
fei.dengdd910ef2024-06-07 10:25:30 +0800734 mCurrentDisplayOutput = &mOutput[0];
735 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
736 mOutput[i].wlOutput = NULL;
737 mOutput[i].offsetX = 0;
738 mOutput[i].offsetY = 0;
739 mOutput[i].width = 0;
740 mOutput[i].height = 0;
741 mOutput[i].refreshRate = 0;
742 mOutput[i].isPrimary = false;
743 mOutput[i].name = 0;
744 mOutput[i].crtcIndex = 0;
745 }
fei.deng4029e682024-06-26 17:06:31 +0800746 /*if mKeepLastFrame had set but mToSendKeepLastFrame is false,maybe
747 playback is doing FF/FW action,so we keep set it on new connection*/
748 if (!mToSendKeepLastFrame && mKeepLastFrame) {
749 mToSendKeepLastFrame = true;
750 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000751 char *name = require_xdg_runtime_dir();
752 //DEBUG(mLogCategory,"name:%s",name);
fei.dengb9a1a572023-09-13 01:33:57 +0000753 DEBUG(mLogCategory,"openDisplay in");
fei.dengf7a0cd32023-08-29 09:36:37 +0000754 mWlDisplay = wl_display_connect(NULL);
755 if (!mWlDisplay) {
fei.dengb9a1a572023-09-13 01:33:57 +0000756 ERROR(mLogCategory,"Failed to connect to the wayland display, XDG_RUNTIME_DIR='%s'",
fei.dengf7a0cd32023-08-29 09:36:37 +0000757 name ? name : "NULL");
fei.dengb9a1a572023-09-13 01:33:57 +0000758 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000759 }
760
761 mWlDisplayWrapper = (struct wl_display *)wl_proxy_create_wrapper ((void *)mWlDisplay);
762 mWlQueue = wl_display_create_queue (mWlDisplay);
763 wl_proxy_set_queue ((struct wl_proxy *)mWlDisplayWrapper, mWlQueue);
764
765 mRegistry = wl_display_get_registry (mWlDisplayWrapper);
766 wl_registry_add_listener (mRegistry, &registry_listener, (void *)this);
767
768 /* we need exactly 2 roundtrips to discover global objects and their state */
769 for (int i = 0; i < 2; i++) {
770 if (wl_display_roundtrip_queue (mWlDisplay, mWlQueue) < 0) {
fei.dengb9a1a572023-09-13 01:33:57 +0000771 ERROR(mLogCategory,"Error communicating with the wayland display");
772 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000773 }
774 }
775
776 if (!mCompositor) {
fei.dengb9a1a572023-09-13 01:33:57 +0000777 ERROR(mLogCategory,"Could not bind to wl_compositor. Either it is not implemented in " \
fei.dengf7a0cd32023-08-29 09:36:37 +0000778 "the compositor, or the implemented version doesn't match");
fei.dengb9a1a572023-09-13 01:33:57 +0000779 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000780 }
781
782 if (!mDmabuf) {
fei.dengb9a1a572023-09-13 01:33:57 +0000783 ERROR(mLogCategory,"Could not bind to zwp_linux_dmabuf_v1");
784 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000785 }
786
787 if (!mXdgWmBase) {
788 /* If wl_surface and wl_display are passed via GstContext
789 * wl_shell, xdg_shell and zwp_fullscreen_shell are not used.
790 * In this case is correct to continue.
791 */
fei.dengb9a1a572023-09-13 01:33:57 +0000792 ERROR(mLogCategory,"Could not bind to either wl_shell, xdg_wm_base or "
fei.dengf7a0cd32023-08-29 09:36:37 +0000793 "zwp_fullscreen_shell, video display may not work properly.");
fei.dengb9a1a572023-09-13 01:33:57 +0000794 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000795 }
796
797 //create window surface
798 createCommonWindowSurface();
799 createXdgShellWindowSurface();
800
801 //config weston video plane
fei.deng640c3c92024-04-12 08:31:19 +0000802 if (mAmlConfigAPIList.enableSetVideoPlane) {
fei.dengb9a1a572023-09-13 01:33:57 +0000803 INFO(mLogCategory,"set weston video plane:%d",mPip);
fei.dengf7a0cd32023-08-29 09:36:37 +0000804 wl_surface_set_video_plane(mVideoSurfaceWrapper, mPip);
805 }
806
807 //run wl display queue dispatch
fei.dengb9a1a572023-09-13 01:33:57 +0000808 DEBUG(mLogCategory,"To run wl display dispatch queue");
fei.dengdd910ef2024-06-07 10:25:30 +0800809 if (mPoll) {
810 mPoll->setFlushing(false);
811 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000812 run("display queue");
813 mRedrawingPending = false;
814
fei.dengb9a1a572023-09-13 01:33:57 +0000815 DEBUG(mLogCategory,"openDisplay out");
816 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000817}
818
819void WaylandDisplay::closeDisplay()
820{
fei.dengb9a1a572023-09-13 01:33:57 +0000821 DEBUG(mLogCategory,"closeDisplay in");
fei.dengf7a0cd32023-08-29 09:36:37 +0000822
fei.dengd0da4e22024-07-04 11:29:13 +0800823 //first destroy window surface
824 destroyWindowSurfaces();
fei.dengf7a0cd32023-08-29 09:36:37 +0000825
fei.deng4029e682024-06-26 17:06:31 +0800826 //flush pending event to weston
fei.dengdd910ef2024-06-07 10:25:30 +0800827 if (mWlDisplay) {
828 wl_display_flush (mWlDisplay);
829 }
830
fei.dengd0da4e22024-07-04 11:29:13 +0800831 //wait video surface destroyed or 50ms timeout
832 if (mAmlConfigAPIList.enableSurfaceDestroyCallback) {
833 INFO(mLogCategory,"waiting surface_destroy_cb from weston");
834 Tls::Mutex::Autolock _l(mMutex);
835 if (ERROR_TIMED_OUT == mCondition.waitRelative(mMutex, 50/*microsecond*/)) {
836 WARNING(mLogCategory,"waited surface_destroy_cb timeout");
837 }
838 }
839
840 //we should receive all event from weston before stopped dispatch queue
841 if (isRunning()) {
842 TRACE(mLogCategory,"try stop dispatch thread");
843 if (mPoll) {
844 mPoll->setFlushing(true);
845 }
846 requestExitAndWait();
847 }
848 //after destroyed surface,then destroy buffers,otherwise maybe crash
849 if (mAreaShmBuffer) {
850 delete mAreaShmBuffer;
851 mAreaShmBuffer = NULL;
852 }
853
854 //clean all wayland buffers
855 cleanAllWaylandBuffer();
fei.dengf7a0cd32023-08-29 09:36:37 +0000856
857 if (mViewporter) {
858 wp_viewporter_destroy (mViewporter);
859 mViewporter = NULL;
860 }
861
862 if (mDmabuf) {
863 zwp_linux_dmabuf_v1_destroy (mDmabuf);
864 mDmabuf = NULL;
865 }
866
867 if (mXdgWmBase) {
868 xdg_wm_base_destroy (mXdgWmBase);
869 mXdgWmBase = NULL;
870 }
871
872 if (mCompositor) {
873 wl_compositor_destroy (mCompositor);
874 mCompositor = NULL;
875 }
876
877 if (mSubCompositor) {
878 wl_subcompositor_destroy (mSubCompositor);
879 mSubCompositor = NULL;
880 }
881
882 if (mRegistry) {
883 wl_registry_destroy (mRegistry);
884 mRegistry= NULL;
885 }
886
887 if (mWlDisplayWrapper) {
888 wl_proxy_wrapper_destroy (mWlDisplayWrapper);
889 mWlDisplayWrapper = NULL;
890 }
891
fei.deng640c3c92024-04-12 08:31:19 +0000892 if (mAmlConfig) {
893 aml_config_destroy(mAmlConfig);
894 mAmlConfig = NULL;
895 }
896
fei.dengf7a0cd32023-08-29 09:36:37 +0000897 if (mWlQueue) {
898 wl_event_queue_destroy (mWlQueue);
899 mWlQueue = NULL;
900 }
901
902 if (mWlDisplay) {
903 wl_display_flush (mWlDisplay);
904 wl_display_disconnect (mWlDisplay);
905 mWlDisplay = NULL;
906 }
907
fei.dengb9a1a572023-09-13 01:33:57 +0000908 DEBUG(mLogCategory,"closeDisplay out");
fei.dengf7a0cd32023-08-29 09:36:37 +0000909}
910
911int WaylandDisplay::toDmaBufferFormat(RenderVideoFormat format, uint32_t *outDmaformat /*out param*/, uint64_t *outDmaformatModifiers /*out param*/)
912{
913 if (!outDmaformat || !outDmaformatModifiers) {
fei.dengb9a1a572023-09-13 01:33:57 +0000914 WARNING(mLogCategory,"NULL params");
915 return ERROR_PARAM_NULL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000916 }
917
918 *outDmaformat = 0;
919 *outDmaformatModifiers = 0;
920
921 uint32_t dmaformat = video_format_to_wl_dmabuf_format (format);
922 if (dmaformat == -1) {
fei.dengb9a1a572023-09-13 01:33:57 +0000923 ERROR(mLogCategory,"Error not found render video format:%d to wl dmabuf format",format);
924 return ERROR_NOT_FOUND;
fei.dengf7a0cd32023-08-29 09:36:37 +0000925 }
926
fei.dengb9a1a572023-09-13 01:33:57 +0000927 TRACE(mLogCategory,"render video format:%d -> dmabuf format:%d",format,dmaformat);
fei.dengf7a0cd32023-08-29 09:36:37 +0000928 *outDmaformat = (uint32_t)dmaformat;
929
930 /*get dmaformat and modifiers*/
931 auto item = mDmaBufferFormats.find(dmaformat);
932 if (item == mDmaBufferFormats.end()) { //not found
fei.dengb9a1a572023-09-13 01:33:57 +0000933 WARNING(mLogCategory,"Not found dmabuf for render video format :%d",format);
fei.dengf7a0cd32023-08-29 09:36:37 +0000934 *outDmaformatModifiers = 0;
fei.dengb9a1a572023-09-13 01:33:57 +0000935 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000936 }
937
938 *outDmaformatModifiers = (uint64_t)item->second;
939
fei.dengb9a1a572023-09-13 01:33:57 +0000940 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000941}
942
943int WaylandDisplay::toShmBufferFormat(RenderVideoFormat format, uint32_t *outformat)
944{
945 if (!outformat) {
fei.dengb9a1a572023-09-13 01:33:57 +0000946 WARNING(mLogCategory,"NULL params");
947 return ERROR_PARAM_NULL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000948 }
949
950 *outformat = 0;
951
952 int shmformat = (int)video_format_to_wl_shm_format(format);
953 if (shmformat < 0) {
fei.dengb9a1a572023-09-13 01:33:57 +0000954 ERROR(mLogCategory,"Error not found render video format:%d to wl shmbuf format",format);
955 return ERROR_NOT_FOUND;
fei.dengf7a0cd32023-08-29 09:36:37 +0000956 }
957
958 for (auto item = mShmFormats.begin(); item != mShmFormats.end(); ++item) {
959 uint32_t registFormat = (uint32_t)*item;
960 if (registFormat == (uint32_t)shmformat) {
961 *outformat = registFormat;
fei.dengb9a1a572023-09-13 01:33:57 +0000962 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000963 }
964 }
965
fei.dengb9a1a572023-09-13 01:33:57 +0000966 return ERROR_NOT_FOUND;
fei.dengf7a0cd32023-08-29 09:36:37 +0000967}
968
969void WaylandDisplay::setVideoBufferFormat(RenderVideoFormat format)
970{
fei.dengb9a1a572023-09-13 01:33:57 +0000971 TRACE(mLogCategory,"set video buffer format: %d",format);
fei.dengf7a0cd32023-08-29 09:36:37 +0000972 mBufferFormat = format;
973};
974
975void WaylandDisplay::setDisplayOutput(int output)
976{
fei.dengb9a1a572023-09-13 01:33:57 +0000977 TRACE(mLogCategory,"select display output: %d",output);
fei.dengf7a0cd32023-08-29 09:36:37 +0000978 if (output < 0 || output >= DEFAULT_DISPLAY_OUTPUT_NUM) {
fei.dengb9a1a572023-09-13 01:33:57 +0000979 ERROR(mLogCategory, "display output index error,please set 0:primary or 1:extend,now:%d",output);
fei.dengf7a0cd32023-08-29 09:36:37 +0000980 return;
981 }
fei.deng26950832023-11-09 03:00:23 +0000982 //only do select output before video playing
983 if (mSelectOutputIndex != output) {
984 mSelectOutputIndex = output;
985 // if (mOutput[output].wlOutput) {
986 // mCurrentDisplayOutput = &mOutput[output];
987 // setRenderRectangle(mOutput[output].offsetX, mOutput[output].offsetY,
988 // mOutput[output].width, mOutput[output].height);
989 // }
fei.dengf7a0cd32023-08-29 09:36:37 +0000990 }
991}
992
993int WaylandDisplay::getDisplayOutput()
994{
fei.deng26950832023-11-09 03:00:23 +0000995 return mSelectOutputIndex == INVALID_OUTPUT_INDEX? 0: mSelectOutputIndex;
fei.dengf7a0cd32023-08-29 09:36:37 +0000996}
997
998void WaylandDisplay::setPip(int pip)
999{
fei.dengb9a1a572023-09-13 01:33:57 +00001000 INFO(mLogCategory,"set pip:%d",pip);
fei.dengf7a0cd32023-08-29 09:36:37 +00001001 mPip = pip;
1002}
1003
fei.deng26950832023-11-09 03:00:23 +00001004void WaylandDisplay::updateDisplayOutput()
1005{
1006 if (!mCurrentDisplayOutput->wlOutput || !mXdgToplevel || !mXdgSurface)
1007 {
1008 return;
1009 }
1010 if (mUpdateRenderRectangle) {
1011 if (mFullScreen) {
1012 DEBUG(mLogCategory,"unset full screen");
1013 xdg_toplevel_unset_fullscreen (mXdgToplevel);
1014 }
1015
1016 if (mXdgSurface) {
1017 DEBUG(mLogCategory,"set geometry");
1018 xdg_surface_set_window_geometry(mXdgSurface,
1019 mCurrentDisplayOutput->offsetX,
1020 mCurrentDisplayOutput->offsetY,
1021 mCurrentDisplayOutput->width,
1022 mCurrentDisplayOutput->height);
1023 }
1024
1025 if (mFullScreen && mXdgToplevel) {
1026 DEBUG(mLogCategory,"set full screen");
1027 xdg_toplevel_set_fullscreen (mXdgToplevel, mCurrentDisplayOutput->wlOutput);
1028 }
1029 setRenderRectangle(mCurrentDisplayOutput->offsetX, mCurrentDisplayOutput->offsetY,
1030 mCurrentDisplayOutput->width, mCurrentDisplayOutput->height);
1031 mUpdateRenderRectangle = false;
1032 }
1033}
1034
fei.dengf7a0cd32023-08-29 09:36:37 +00001035void WaylandDisplay::createCommonWindowSurface()
1036{
1037 struct wl_region *region;
1038
1039 mAreaSurface = wl_compositor_create_surface (mCompositor);
1040 mVideoSurface = wl_compositor_create_surface (mCompositor);
1041 mAreaSurfaceWrapper = (struct wl_surface *)wl_proxy_create_wrapper (mAreaSurface);
1042 mVideoSurfaceWrapper = (struct wl_surface *)wl_proxy_create_wrapper (mVideoSurface);
1043
1044 wl_proxy_set_queue ((struct wl_proxy *) mAreaSurfaceWrapper, mWlQueue);
1045 wl_proxy_set_queue ((struct wl_proxy *) mVideoSurfaceWrapper, mWlQueue);
1046
1047 /* embed video_surface in area_surface */
1048 mVideoSubSurface = wl_subcompositor_get_subsurface (mSubCompositor, mVideoSurface, mAreaSurface);
1049 wl_subsurface_set_desync (mVideoSubSurface);
1050
fei.dengd0da4e22024-07-04 11:29:13 +08001051 //add video surface callback to weston if weston enable this feature
1052 if (mVideoSurface && mAmlConfigAPIList.enableSurfaceDestroyCallback) {
1053 struct wl_callback *surfaceDestroyCb = wl_surface_destroy_callback(mVideoSurface);
1054 wl_callback_add_listener(surfaceDestroyCb, &surface_destroy_listener, this);
1055 }
1056
fei.dengf7a0cd32023-08-29 09:36:37 +00001057 if (mViewporter) {
1058 mAreaViewport = wp_viewporter_get_viewport (mViewporter, mAreaSurface);
1059 mVideoViewport = wp_viewporter_get_viewport (mViewporter, mVideoSurface);
1060 }
1061
fei.deng9bf724e2024-08-01 11:34:52 +08001062 /*set area surface to invisible. prevent frame droped at start playback,
1063 wl_surface_set_invisible must called before mAreaSurface commit called*/
1064 if (mAmlConfigAPIList.enableSetSurfaceInvisible) {
1065 int invisible = 1;
1066 INFO(mLogCategory,"set surface invisible:%d",invisible);
1067 wl_surface_set_invisible(mAreaSurfaceWrapper, invisible);
1068 }
1069
fei.deng649b0e22024-09-03 18:57:13 +08001070 if (mAmlConfigAPIList.enableDisplayTime) {
1071 INFO(mLogCategory,"set enable display time");
1072 wl_surface_enable_display_time(mVideoSurface, 1);
1073 }
1074
fei.dengf7a0cd32023-08-29 09:36:37 +00001075 /* do not accept input */
1076 region = wl_compositor_create_region (mCompositor);
1077 wl_surface_set_input_region (mAreaSurface, region);
1078 wl_region_destroy (region);
1079
1080 region = wl_compositor_create_region (mCompositor);
1081 wl_surface_set_input_region (mVideoSurface, region);
1082 wl_region_destroy (region);
1083}
1084
1085void WaylandDisplay::createXdgShellWindowSurface()
1086{
1087 /* Check which protocol we will use (in order of preference) */
1088 if (mXdgWmBase) {
1089 /* First create the XDG surface */
1090 mXdgSurface= xdg_wm_base_get_xdg_surface (mXdgWmBase, mAreaSurface);
1091 if (!mXdgSurface) {
fei.dengb9a1a572023-09-13 01:33:57 +00001092 ERROR(mLogCategory,"Unable to get xdg_surface");
fei.dengf7a0cd32023-08-29 09:36:37 +00001093 return;
1094 }
1095 xdg_surface_add_listener (mXdgSurface, &xdg_surface_listener,(void *)this);
1096
1097 /* Then the toplevel */
1098 mXdgToplevel= xdg_surface_get_toplevel (mXdgSurface);
1099 if (!mXdgSurface) {
fei.dengb9a1a572023-09-13 01:33:57 +00001100 ERROR(mLogCategory,"Unable to get xdg_toplevel");
fei.dengf7a0cd32023-08-29 09:36:37 +00001101 return;
1102 }
1103 xdg_toplevel_add_listener (mXdgToplevel, &xdg_toplevel_listener, this);
1104
1105 /* Finally, commit the xdg_surface state as toplevel */
1106 mXdgSurfaceConfigured = false;
1107 wl_surface_commit (mAreaSurface);
1108 wl_display_flush (mWlDisplay);
1109 /* we need exactly 3 roundtrips to discover global objects and their state */
1110 for (int i = 0; i < 3; i++) {
1111 if (wl_display_roundtrip_queue(mWlDisplay, mWlQueue) < 0) {
fei.dengb9a1a572023-09-13 01:33:57 +00001112 ERROR(mLogCategory,"Error communicating with the wayland display");
fei.dengf7a0cd32023-08-29 09:36:37 +00001113 }
1114 }
1115
1116 if (mXdgSurfaceConfigured) {
fei.dengb9a1a572023-09-13 01:33:57 +00001117 INFO(mLogCategory,"xdg surface had configured");
fei.dengf7a0cd32023-08-29 09:36:37 +00001118 } else {
fei.dengb9a1a572023-09-13 01:33:57 +00001119 WARNING(mLogCategory,"xdg surface not configured");
fei.dengf7a0cd32023-08-29 09:36:37 +00001120 }
1121
1122 //full screen show
fei.deng26950832023-11-09 03:00:23 +00001123 // if (mFullScreen && mCurrentDisplayOutput->wlOutput) {
1124 // //ensureFullscreen(mFullScreen);
fei.dengf7a0cd32023-08-29 09:36:37 +00001125 // }
1126 } else {
fei.dengb9a1a572023-09-13 01:33:57 +00001127 ERROR(mLogCategory,"Unable to use xdg_wm_base ");
fei.dengf7a0cd32023-08-29 09:36:37 +00001128 return;
1129 }
1130}
1131
1132void WaylandDisplay::destroyWindowSurfaces()
1133{
fei.dengf7a0cd32023-08-29 09:36:37 +00001134 if (mXdgToplevel) {
1135 xdg_toplevel_destroy (mXdgToplevel);
1136 mXdgToplevel = NULL;
1137 }
1138
1139 if (mXdgSurface) {
1140 xdg_surface_destroy (mXdgSurface);
1141 mXdgSurface = NULL;
1142 }
1143
1144 if (mVideoSurfaceWrapper) {
1145 wl_proxy_wrapper_destroy (mVideoSurfaceWrapper);
1146 mVideoSurfaceWrapper = NULL;
1147 }
1148
1149 if (mVideoSubSurface) {
1150 wl_subsurface_destroy (mVideoSubSurface);
1151 mVideoSubSurface = NULL;
1152 }
1153
1154 if (mVideoSurface) {
1155 wl_surface_destroy (mVideoSurface);
1156 mVideoSurface = NULL;
1157 }
1158
1159 if (mAreaSurfaceWrapper) {
1160 wl_proxy_wrapper_destroy (mAreaSurfaceWrapper);
1161 mAreaSurfaceWrapper = NULL;
1162 }
1163
1164 if (mAreaSurface) {
1165 wl_surface_destroy (mAreaSurface);
1166 mAreaSurface = NULL;
1167 mReCommitAreaSurface = false;
1168 }
1169}
1170
1171void WaylandDisplay::ensureFullscreen(bool fullscreen)
1172{
1173 if (mXdgWmBase) {
fei.dengb9a1a572023-09-13 01:33:57 +00001174 DEBUG(mLogCategory,"full screen : %d",fullscreen);
fei.dengf7a0cd32023-08-29 09:36:37 +00001175 if (fullscreen) {
fei.deng26950832023-11-09 03:00:23 +00001176 xdg_toplevel_set_fullscreen (mXdgToplevel, mCurrentDisplayOutput->wlOutput);
fei.dengf7a0cd32023-08-29 09:36:37 +00001177 } else {
1178 xdg_toplevel_unset_fullscreen (mXdgToplevel);
1179 }
1180 }
1181}
1182
1183void WaylandDisplay::setRenderRectangle(int x, int y, int w, int h)
1184{
fei.dengb9a1a572023-09-13 01:33:57 +00001185 DEBUG(mLogCategory,"set render rect:x:%d,y:%d,w:%d,h:%d",x,y,w,h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001186
1187 if (w <= 0 || h <= 0) {
fei.dengb9a1a572023-09-13 01:33:57 +00001188 WARNING(mLogCategory, "wrong render width or height %dx%d",w,h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001189 return;
1190 }
1191
1192 mRenderRect.x = x;
1193 mRenderRect.y = y;
1194 mRenderRect.w = w;
1195 mRenderRect.h = h;
1196
1197 if (!mXdgSurfaceConfigured) {
fei.dengb9a1a572023-09-13 01:33:57 +00001198 WARNING(mLogCategory,"Not configured xdg");
fei.dengf7a0cd32023-08-29 09:36:37 +00001199 return;
1200 }
1201
1202 if (mAreaViewport) {
1203 wp_viewport_set_destination (mAreaViewport, w, h);
1204 }
1205
1206 updateBorders();
1207
1208 if (mVideoWidth != 0 && mVideoSurface) {
1209 wl_subsurface_set_sync (mVideoSubSurface);
1210 resizeVideoSurface(true);
1211 }
1212
1213 wl_surface_damage (mAreaSurfaceWrapper, 0, 0, w, h);
1214 wl_surface_commit (mAreaSurfaceWrapper);
1215
1216 if (mVideoWidth != 0) {
1217 wl_subsurface_set_desync (mVideoSubSurface);
1218 }
1219}
1220
fei.dengf7a0cd32023-08-29 09:36:37 +00001221void WaylandDisplay::setFrameSize(int w, int h)
1222{
1223 mVideoWidth = w;
1224 mVideoHeight = h;
fei.denga4abbd52024-07-11 19:17:50 +08001225 mUpdateVideoSurface = true;
fei.dengb9a1a572023-09-13 01:33:57 +00001226 TRACE(mLogCategory,"frame w:%d,h:%d",mVideoWidth,mVideoHeight);
fei.dengf7a0cd32023-08-29 09:36:37 +00001227}
1228
1229void WaylandDisplay::setWindowSize(int x, int y, int w, int h)
1230{
1231 mWindowRect.x = x;
1232 mWindowRect.y = y;
1233 mWindowRect.w = w;
1234 mWindowRect.h = h;
fei.denga4abbd52024-07-11 19:17:50 +08001235 mUpdateVideoSurface = true;
fei.dengb9a1a572023-09-13 01:33:57 +00001236 TRACE(mLogCategory,"window size:x:%d,y:%d,w:%d,h:%d",mWindowRect.x,mWindowRect.y,mWindowRect.w,mWindowRect.h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001237}
1238
fei.denga4abbd52024-07-11 19:17:50 +08001239void WaylandDisplay::setPixelAspectRatio(double ratio)
1240{
1241 mPixelAspectRatio = ratio;
1242 mUpdateVideoSurface = true;
1243}
fei.dengf7a0cd32023-08-29 09:36:37 +00001244
1245void WaylandDisplay::resizeVideoSurface(bool commit)
1246{
1247 Rectangle src = {0,};
1248 Rectangle dst = {0,};
1249 Rectangle res;
1250
1251 /* center the video_subsurface inside area_subsurface */
1252 src.w = mVideoWidth;
1253 src.h = mVideoHeight;
1254 /*if had set the window size, we will scall
1255 video surface to this window size*/
1256 if (mWindowRect.w > 0 && mWindowRect.h > 0) {
1257 dst.x = mWindowRect.x;
1258 dst.y = mWindowRect.y;
1259 dst.w = mWindowRect.w;
1260 dst.h = mWindowRect.h;
1261 if (mWindowRect.w > mRenderRect.w && mWindowRect.h > mRenderRect.h) {
fei.dengb9a1a572023-09-13 01:33:57 +00001262 WARNING(mLogCategory,"Error window size:%dx%d, but render size:%dx%d,reset to render size",
fei.dengf7a0cd32023-08-29 09:36:37 +00001263 mWindowRect.w,mWindowRect.h,mRenderRect.w,mRenderRect.h);
1264 dst.x = mRenderRect.x;
1265 dst.y = mRenderRect.y;
1266 dst.w = mRenderRect.w;
1267 dst.h = mRenderRect.h;
1268 }
1269 //to do,we need set geometry?
1270 //if (mXdgSurface) {
1271 // xdg_surface_set_window_geometry(mXdgSurface, mWindowRect.x, mWindowRect.y, mWindowRect.w, mWindowRect.h);
1272 //}
1273 } else { //scal video to full screen
1274 dst.w = mRenderRect.w;
1275 dst.h = mRenderRect.h;
1276 }
1277
1278 if (mViewporter) {
1279 videoCenterRect(src, dst, &res, true);
1280 } else {
1281 videoCenterRect(src, dst, &res, false);
1282 }
1283
1284 wl_subsurface_set_position (mVideoSubSurface, res.x, res.y);
1285
1286 if (commit) {
1287 wl_surface_damage (mVideoSurfaceWrapper, 0, 0, res.w, res.h);
1288 wl_surface_commit (mVideoSurfaceWrapper);
1289 }
1290
1291 //top level setting
1292 if (mXdgToplevel) {
1293 struct wl_region *region;
1294
1295 region = wl_compositor_create_region (mCompositor);
1296 wl_region_add (region, 0, 0, mRenderRect.w, mRenderRect.h);
1297 wl_surface_set_input_region (mAreaSurface, region);
1298 wl_region_destroy (region);
1299 }
1300
1301 /* this is saved for use in wl_surface_damage */
1302 mVideoRect.x = res.x;
1303 mVideoRect.y = res.y;
1304 mVideoRect.w = res.w;
1305 mVideoRect.h = res.h;
1306
fei.denga4abbd52024-07-11 19:17:50 +08001307 //to scale video surface
fei.dengf7a0cd32023-08-29 09:36:37 +00001308 wp_viewport_set_destination(mVideoViewport, res.w, res.h);
fei.denga4abbd52024-07-11 19:17:50 +08001309 wl_display_flush (mWlDisplay);
fei.dengb9a1a572023-09-13 01:33:57 +00001310 TRACE(mLogCategory,"video rectangle,x:%d,y:%d,w:%d,h:%d",mVideoRect.x, mVideoRect.y, mVideoRect.w, mVideoRect.h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001311}
1312
1313void WaylandDisplay::setOpaque()
1314{
1315 struct wl_region *region;
1316
1317 /* Set area opaque */
1318 region = wl_compositor_create_region (mCompositor);
1319 wl_region_add (region, 0, 0, mRenderRect.w, mRenderRect.h);
1320 wl_surface_set_opaque_region (mAreaSurface, region);
1321 wl_region_destroy (region);
1322}
1323
1324int WaylandDisplay::prepareFrameBuffer(RenderBuffer * buf)
1325{
1326 WaylandBuffer *waylandBuf = NULL;
1327 int ret;
fei.dengda0cd9f2024-07-24 09:25:11 +08001328 bool isNew = false;
fei.dengf7a0cd32023-08-29 09:36:37 +00001329
fei.deng649b0e22024-09-03 18:57:13 +08001330 //detect frame rate and frame duration
1331 if (mFrameRateFractionNum == 0) {
1332 if (mPreFramePts == -1) {
1333 mPreFramePts = buf->pts; //ns
1334 } else {
1335 if (mFrameRateDetectCnt < DETECT_FRAMERATE_CNT) {
1336 mFrameRateDetectPeriod += (buf->pts - mPreFramePts);
1337 ++mFrameRateDetectCnt;
1338 }
1339 if (mFrameRateDetectCnt == DETECT_FRAMERATE_CNT) {
1340 int64_t mFrameDurationUs = (mFrameRateDetectPeriod/mFrameRateDetectCnt)/1000;
1341 double rate = 1000000.0/mFrameDurationUs;
1342 mFrameRateFractionNum = rate * 100;
1343 mFrameRateFractionDenom = 100;
1344 mFrameRateChanged = true;
1345 INFO(mLogCategory,"detect frame num:%d,denom:%d,dur:%lld us",
1346 mFrameRateFractionNum,mFrameRateFractionDenom,mFrameDurationUs);
1347 }
1348 }
1349 }
1350 mPreFramePts = buf->pts;
1351
fei.dengdd910ef2024-06-07 10:25:30 +08001352 if (!mDmabuf)
1353 {
1354 ERROR(mLogCategory,"Error zwp_linux_dmabuf_v1");
1355 return ERROR_UNKNOWN;
1356 }
1357
fei.dengf7a0cd32023-08-29 09:36:37 +00001358 waylandBuf = findWaylandBuffer(buf);
1359 if (waylandBuf == NULL) {
fei.dengb9a1a572023-09-13 01:33:57 +00001360 waylandBuf = new WaylandBuffer(this, mLogCategory);
fei.dengda0cd9f2024-07-24 09:25:11 +08001361 isNew = true;
1362 }
1363 waylandBuf->setBufferFormat(mBufferFormat);
1364 ret = waylandBuf->constructWlBuffer(buf);
1365 if (ret != NO_ERROR) {
1366 WARNING(mLogCategory,"dmabufConstructWlBuffer fail,release waylandbuf");
1367 //delete waylanBuf,WaylandBuffer object destruct will call release callback
1368 goto waylandbuf_fail;
1369 }
1370 if (isNew) {
1371 addWaylandBuffer(buf, waylandBuf);
fei.dengf7a0cd32023-08-29 09:36:37 +00001372 }
fei.dengb9a1a572023-09-13 01:33:57 +00001373 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +00001374waylandbuf_fail:
1375 //delete waylandbuf
1376 delete waylandBuf;
1377 waylandBuf = NULL;
fei.dengb9a1a572023-09-13 01:33:57 +00001378 return ERROR_UNKNOWN;
fei.dengf7a0cd32023-08-29 09:36:37 +00001379}
1380
1381void WaylandDisplay::displayFrameBuffer(RenderBuffer * buf, int64_t realDisplayTime)
1382{
fei.deng19b48692024-08-13 14:17:55 +08001383 WaylandBuffer *waylandBuf = NULL;
1384 struct wl_buffer * wlbuffer = NULL;
1385 int ret;
1386
1387 if (!buf) {
1388 ERROR(mLogCategory,"Error input params, RenderBuffer is null");
1389 return;
1390 }
1391
1392 if (buf->flag & BUFFER_FLAG_DMA_BUFFER) {
1393 if (buf->dma.width <=0 || buf->dma.height <=0) {
1394 buf->dma.width = mVideoWidth;
1395 buf->dma.height = mVideoHeight;
1396 }
1397
1398 waylandBuf = findWaylandBuffer(buf);
1399 if (waylandBuf) {
1400 waylandBuf->setRenderRealTime(realDisplayTime);
1401 } else {
1402 ERROR(mLogCategory,"NOT found wayland buffer,please prepare buffer first");
1403 goto waylandbuf_fail;
1404 }
1405 }
1406
1407 //if no wl_output, drop this buffer
1408 if (mCurrentDisplayOutput->wlOutput == NULL) {
1409 TRACE(mLogCategory,"No wl_output");
1410 //insert this buffer to committed weston buffer manager
1411 std::pair<int64_t, WaylandBuffer *> item(realDisplayTime, waylandBuf);
1412 mCommittedBufferMap.insert(item);
1413 mWaylandPlugin->handleFrameDropped(buf);
1414 WaylandBuffer::bufferRelease(waylandBuf,NULL);
1415 return;
1416 }
1417
1418 //must commit areasurface first, because weston xdg surface maybe timeout
1419 //this cause video is not display,commit can resume xdg surface
1420 if (!mReCommitAreaSurface) {
1421 mReCommitAreaSurface = true;
1422 wl_surface_commit (mAreaSurface);
1423 }
1424
fei.deng6c425232024-07-19 16:15:31 +08001425 //set frame rate to weston,it lets weston to select suitable mode
1426 if (mFrameRateChanged && mAmlConfigAPIList.enableSetDisplayRate) {
1427 mFrameRateChanged = false;
1428 TRACE(mLogCategory,"set frame rate %d/%d to weston", mFrameRateFractionNum, mFrameRateFractionDenom);
1429 wl_surface_set_display_rate(mVideoSurfaceWrapper, mFrameRateFractionNum, mFrameRateFractionDenom);
1430 }
fei.denga4abbd52024-07-11 19:17:50 +08001431 //update video surface size
1432 if (mUpdateVideoSurface && mVideoSurface &&
1433 buf->dma.width == mVideoWidth && buf->dma.height == mVideoHeight) {
1434 mUpdateVideoSurface = false;
1435 //if had full screen, unset it and set window size
1436 if (mFullScreen) {
1437 mFullScreen = false;
1438 ensureFullscreen(mFullScreen);
1439 }
1440 resizeVideoSurface(true);
fei.dengda0cd9f2024-07-24 09:25:11 +08001441 /*clean wayland buffers those allocated
1442 before resolution changed and had release by weston */
1443 cleanWaylandBufferBeforeResChanged();
fei.denga4abbd52024-07-11 19:17:50 +08001444 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001445
fei.deng1c94a342024-08-05 19:33:28 +08001446 if (mVideoPlaneZorderChanged && mVideoSurfaceWrapper) {
1447 mVideoPlaneZorderChanged = false;
1448 wl_surface_set_zorder(mVideoSurfaceWrapper, mVideoPlaneZorder);
1449 }
1450
fei.dengdd910ef2024-06-07 10:25:30 +08001451 //TRACE(mLogCategory,"display renderBuffer:%p,PTS:%lld us,realtime:%lld",buf, buf->pts/1000, realDisplayTime);
fei.dengf7a0cd32023-08-29 09:36:37 +00001452
fei.dengf7a0cd32023-08-29 09:36:37 +00001453 if (waylandBuf) {
1454 wlbuffer = waylandBuf->getWlBuffer();
1455 }
fei.deng19b48692024-08-13 14:17:55 +08001456
fei.dengf7a0cd32023-08-29 09:36:37 +00001457 if (wlbuffer) {
fei.dengf3ee6912024-08-30 18:22:55 +08001458 auto cItem = mCommittedBufferMap.find(realDisplayTime);
1459 if (cItem != mCommittedBufferMap.end()) {
1460 TRACE(mLogCategory,"Error.release same display time buffer,pts:%lld us",buf->pts/1000);
1461 goto waylandbuf_fail;
1462 }
fei.dengb9a1a572023-09-13 01:33:57 +00001463 Tls::Mutex::Autolock _l(mRenderMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001464 ++mCommitCnt;
1465 uint32_t hiPts = realDisplayTime >> 32;
1466 uint32_t lowPts = realDisplayTime & 0xFFFFFFFF;
1467 //attach this wl_buffer to weston
fei.denga4abbd52024-07-11 19:17:50 +08001468 TRACE(mLogCategory,"++attach,renderbuf:%p,wl_buffer:%p(%d,%d,%d,%d),pts:%lld us,commitCnt:%d",
1469 buf,wlbuffer,mVideoRect.x,mVideoRect.y,mVideoRect.w,mVideoRect.h,buf->pts/1000,mCommitCnt);
fei.dengf7a0cd32023-08-29 09:36:37 +00001470 waylandBuf->attach(mVideoSurfaceWrapper);
1471
fei.deng640c3c92024-04-12 08:31:19 +00001472 if (mAmlConfigAPIList.enableSetPts) {
fei.dengb9a1a572023-09-13 01:33:57 +00001473 TRACE(mLogCategory,"display time:%lld,hiPts:%u,lowPts:%u",realDisplayTime, hiPts, lowPts);
fei.dengf7a0cd32023-08-29 09:36:37 +00001474 wl_surface_set_pts(mVideoSurfaceWrapper, hiPts, lowPts);
1475 }
1476
1477 wl_surface_damage (mVideoSurfaceWrapper, 0, 0, mVideoRect.w, mVideoRect.h);
1478 wl_surface_commit (mVideoSurfaceWrapper);
1479 //insert this buffer to committed weston buffer manager
fei.dengae8c90a2024-06-27 13:39:53 +08001480 std::pair<int64_t, WaylandBuffer *> item(realDisplayTime, waylandBuf);
fei.dengf7a0cd32023-08-29 09:36:37 +00001481 mCommittedBufferMap.insert(item);
1482 } else {
fei.dengb9a1a572023-09-13 01:33:57 +00001483 WARNING(mLogCategory,"wlbuffer is NULL");
fei.dengf7a0cd32023-08-29 09:36:37 +00001484 /* clear both video and parent surfaces */
fei.deng19b48692024-08-13 14:17:55 +08001485 //cleanSurface();
1486 goto waylandbuf_fail;
fei.dengf7a0cd32023-08-29 09:36:37 +00001487 }
1488
1489 wl_display_flush (mWlDisplay);
fei.deng4029e682024-06-26 17:06:31 +08001490 //set keep last frame or not when after send first buffer to weston,1 keep last frame, 0 not
1491 if (mToSendKeepLastFrame) {
1492 setKeepLastFrame(mKeepLastFrame);
1493 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001494
1495 return;
1496waylandbuf_fail:
1497 //notify dropped
1498 mWaylandPlugin->handleFrameDropped(buf);
1499 //notify app release this buf
1500 mWaylandPlugin->handleBufferRelease(buf);
fei.dengf3ee6912024-08-30 18:22:55 +08001501
fei.dengf7a0cd32023-08-29 09:36:37 +00001502 return;
1503}
1504
1505void WaylandDisplay::handleBufferReleaseCallback(WaylandBuffer *buf)
1506{
fei.denga4abbd52024-07-11 19:17:50 +08001507 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.dengf7a0cd32023-08-29 09:36:37 +00001508 {
fei.dengb9a1a572023-09-13 01:33:57 +00001509 Tls::Mutex::Autolock _l(mRenderMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001510 //remove buffer if this buffer is ready to release
fei.dengae8c90a2024-06-27 13:39:53 +08001511 auto item = mCommittedBufferMap.find(buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001512 if (item != mCommittedBufferMap.end()) {
fei.dengdd910ef2024-06-07 10:25:30 +08001513 --mCommitCnt;
fei.dengf7a0cd32023-08-29 09:36:37 +00001514 mCommittedBufferMap.erase(item);
1515 } else {
fei.denga4abbd52024-07-11 19:17:50 +08001516 TRACE(mLogCategory,"Error,Can't find WaylandBuffer pts:%lld us (%lld) in buffer map",
1517 renderBuffer->pts/1000,buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001518 return;
1519 }
1520 }
fei.denga4abbd52024-07-11 19:17:50 +08001521
1522 TRACE(mLogCategory,"renderBuffer :%p,priv:%p,PTS:%lld us,realtime:%lld us,commitCnt:%d",renderBuffer,renderBuffer->priv,renderBuffer->pts/1000,buf->getRenderRealTime(),mCommitCnt);
fei.dengf7a0cd32023-08-29 09:36:37 +00001523 mWaylandPlugin->handleBufferRelease(renderBuffer);
1524}
1525
1526void WaylandDisplay::handleFrameDisplayedCallback(WaylandBuffer *buf)
1527{
1528 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.denga4abbd52024-07-11 19:17:50 +08001529 TRACE(mLogCategory,"renderBuffer :%p,PTS:%lld us,realtime:%lld us",renderBuffer,renderBuffer->pts/1000,buf->getRenderRealTime());
fei.deng3287c082024-04-23 09:29:22 +00001530 if (!mSignalFirstFramePts) {
1531 mSignalFirstFramePts = true;
1532 mWaylandPlugin->handleMsgNotify(MSG_FIRST_FRAME, (void*)&renderBuffer->pts);
1533 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001534 mWaylandPlugin->handleFrameDisplayed(renderBuffer);
1535}
1536
1537void WaylandDisplay::handleFrameDropedCallback(WaylandBuffer *buf)
1538{
1539 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.denga4abbd52024-07-11 19:17:50 +08001540 TRACE(mLogCategory,"renderBuffer :%p,PTS:%lld us,realtime:%lld us",renderBuffer,renderBuffer->pts/1000,buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001541 mWaylandPlugin->handleFrameDropped(renderBuffer);
1542}
1543
fei.deng649b0e22024-09-03 18:57:13 +08001544void WaylandDisplay::handleFrameTime(WaylandBuffer *buf,uint32_t sec, uint32_t usec)
1545{
1546 RenderBuffer *renderBuffer = buf->getRenderBuffer();
1547 int64_t frameDisplayTimeUs = int64_t(sec)*1000000LL + usec;
1548 if (mLastDisplayFramePts == -1) {
1549 mLastDisplayFramePts = renderBuffer->pts;
1550 mLastDisplayFrameTimeUs = frameDisplayTimeUs;
1551 } else { //calculate last frame displayed duration
1552 int64_t duration = frameDisplayTimeUs - mLastDisplayFrameTimeUs;
1553 TRACE(mLogCategory,"now pts:%lld us,time:%u us,pre pts:%lld us,dur:%lld us",
1554 renderBuffer->pts/1000,frameDisplayTimeUs,mLastDisplayFramePts/1000,duration);
1555 if (mFrameDurationUs > 0 && duration > FRAME_FREEZE_THRESHOLD(mFrameDurationUs)) {
1556 FrameDisplayInfo frameDisplayInfo = {-1, -1};
1557 frameDisplayInfo.pts = mLastDisplayFramePts;
1558 frameDisplayInfo.duration = duration;
1559 TRACE(mLogCategory,"report freeze frame,pts:%lld us,duration:%lld us",frameDisplayInfo.pts/1000,frameDisplayInfo.duration);
1560 mWaylandPlugin->handleMsgNotify(MSG_FRAME_FREEZE, &frameDisplayInfo);
1561 }
1562 mLastDisplayFramePts = renderBuffer->pts;
1563 mLastDisplayFrameTimeUs = frameDisplayTimeUs;
1564 }
1565}
1566
fei.dengf7a0cd32023-08-29 09:36:37 +00001567
1568void WaylandDisplay::readyToRun()
1569{
1570 mFd = wl_display_get_fd (mWlDisplay);
fei.dengb9a1a572023-09-13 01:33:57 +00001571 if (mPoll) {
1572 mPoll->addFd(mFd);
1573 mPoll->setFdReadable(mFd, true);
1574 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001575}
1576
fei.dengdd910ef2024-06-07 10:25:30 +08001577void WaylandDisplay::readyToExit()
1578{
1579 if (mPoll && mFd >= 0) {
1580 mPoll->removeFd(mFd);
1581 }
1582}
1583
fei.dengf7a0cd32023-08-29 09:36:37 +00001584bool WaylandDisplay::threadLoop()
1585{
1586 int ret;
fei.dengf7a0cd32023-08-29 09:36:37 +00001587
1588 while (wl_display_prepare_read_queue (mWlDisplay, mWlQueue) != 0) {
1589 wl_display_dispatch_queue_pending (mWlDisplay, mWlQueue);
1590 }
1591
1592 wl_display_flush (mWlDisplay);
1593
1594 /*poll timeout value must > 300 ms,otherwise zwp_linux_dmabuf will create failed,
1595 so do use -1 to wait for ever*/
fei.dengb9a1a572023-09-13 01:33:57 +00001596 ret = mPoll->wait(-1); //wait for ever
fei.dengf7a0cd32023-08-29 09:36:37 +00001597 if (ret < 0) { //poll error
fei.dengb9a1a572023-09-13 01:33:57 +00001598 WARNING(mLogCategory,"poll error");
fei.dengf7a0cd32023-08-29 09:36:37 +00001599 wl_display_cancel_read(mWlDisplay);
1600 return false;
1601 } else if (ret == 0) { //poll time out
1602 return true; //run loop
1603 }
1604
1605 if (wl_display_read_events (mWlDisplay) == -1) {
1606 goto tag_error;
1607 }
1608
1609 wl_display_dispatch_queue_pending (mWlDisplay, mWlQueue);
1610 return true;
1611tag_error:
fei.dengb9a1a572023-09-13 01:33:57 +00001612 ERROR(mLogCategory,"Error communicating with the wayland server");
fei.dengf7a0cd32023-08-29 09:36:37 +00001613 return false;
1614}
1615
1616void WaylandDisplay::videoCenterRect(Rectangle src, Rectangle dst, Rectangle *result, bool scaling)
1617{
1618 //if dst is a small window, we scale video to map window size,don't doing center
fei.dengda0cd9f2024-07-24 09:25:11 +08001619 // if (mRenderRect.w != dst.w && mRenderRect.h != dst.h) {
1620 // result->x = dst.x;
1621 // result->y = dst.y;
1622 // result->w = dst.w;
1623 // result->h = dst.h;
1624 // TRACE(mLogCategory,"small window source is %dx%d dest is %dx%d, result is %d,%d,%d,%d",
1625 // src.w, src.h, dst.w, dst.h, result->x, result->y, result->w, result->h);
1626 // return;
1627 // }
fei.dengf7a0cd32023-08-29 09:36:37 +00001628 if (!scaling) {
1629 result->w = MIN (src.w, dst.w);
1630 result->h = MIN (src.h, dst.h);
1631 result->x = dst.x + (dst.w - result->w) / 2;
1632 result->y = dst.y + (dst.h - result->h) / 2;
1633 } else {
1634 double src_ratio, dst_ratio;
1635
fei.denga4abbd52024-07-11 19:17:50 +08001636 src_ratio = (double) (src.w * mPixelAspectRatio) / src.h;
fei.dengf7a0cd32023-08-29 09:36:37 +00001637 dst_ratio = (double) dst.w / dst.h;
1638
1639 if (src_ratio > dst_ratio) {
1640 result->w = dst.w;
1641 result->h = dst.w / src_ratio;
1642 result->x = dst.x;
1643 result->y = dst.y + (dst.h - result->h) / 2;
1644 } else if (src_ratio < dst_ratio) {
1645 result->w = dst.h * src_ratio;
1646 result->h = dst.h;
1647 result->x = dst.x + (dst.w - result->w) / 2;
1648 result->y = dst.y;
1649 } else {
1650 result->x = dst.x;
1651 result->y = dst.y;
1652 result->w = dst.w;
1653 result->h = dst.h;
1654 }
1655 }
1656
fei.denga4abbd52024-07-11 19:17:50 +08001657 TRACE(mLogCategory,"source is %dx%d dest is %dx%d, result is %d,%d,%d,%d",
1658 src.w, src.h, dst.w, dst.h, result->x, result->y,result->w, result->h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001659}
1660
1661void WaylandDisplay::updateBorders()
1662{
1663 int width,height;
1664
1665 if (mNoBorderUpdate)
1666 return;
1667
1668 if (mViewporter) {
1669 width = height = 1;
1670 mNoBorderUpdate = true;
1671 } else {
1672 width = mRenderRect.w;
1673 height = mRenderRect.h;
1674 }
1675
1676 RenderVideoFormat format = VIDEO_FORMAT_BGRA;
fei.dengb9a1a572023-09-13 01:33:57 +00001677 mAreaShmBuffer = new WaylandShmBuffer(this, mLogCategory);
fei.dengf7a0cd32023-08-29 09:36:37 +00001678 struct wl_buffer *wlbuf = mAreaShmBuffer->constructWlBuffer(width, height, format);
1679 if (wlbuf == NULL) {
1680 delete mAreaShmBuffer;
1681 mAreaShmBuffer = NULL;
1682 }
1683
1684 wl_surface_attach(mAreaSurfaceWrapper, wlbuf, 0, 0);
1685}
1686
1687std::size_t WaylandDisplay::calculateDmaBufferHash(RenderDmaBuffer &dmabuf)
1688{
1689 std::string hashString("");
1690 for (int i = 0; i < dmabuf.planeCnt; i++) {
1691 char hashtmp[1024];
fei.dengda0cd9f2024-07-24 09:25:11 +08001692 snprintf (hashtmp, 1024, "%d%d%d%d%d%d%d",i,dmabuf.width,dmabuf.height,dmabuf.planeCnt,
fei.dengf7a0cd32023-08-29 09:36:37 +00001693 dmabuf.stride[i],dmabuf.offset[i],dmabuf.fd[i]);
1694 std::string tmp(hashtmp);
1695 hashString += tmp;
1696 }
1697
1698 std::size_t hashval = std::hash<std::string>()(hashString);
fei.dengb9a1a572023-09-13 01:33:57 +00001699 //TRACE(mLogCategory,"hashstr:%s,val:%zu",hashString.c_str(),hashval);
fei.dengf7a0cd32023-08-29 09:36:37 +00001700 return hashval;
1701}
1702
1703void WaylandDisplay::addWaylandBuffer(RenderBuffer * buf, WaylandBuffer *waylandbuf)
1704{
fei.deng19b48692024-08-13 14:17:55 +08001705 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001706 if (buf->flag & BUFFER_FLAG_DMA_BUFFER) {
1707 std::size_t hashval = calculateDmaBufferHash(buf->dma);
1708 std::pair<std::size_t, WaylandBuffer *> item(hashval, waylandbuf);
fei.dengb9a1a572023-09-13 01:33:57 +00001709 //TRACE(mLogCategory,"fd:%d,w:%d,h:%d,%p,hash:%zu",buf->dma.fd[0],buf->dma.width,buf->dma.height,waylandbuf,hashval);
fei.dengf7a0cd32023-08-29 09:36:37 +00001710 mWaylandBuffersMap.insert(item);
1711 }
fei.dengb9a1a572023-09-13 01:33:57 +00001712 TRACE(mLogCategory,"mWaylandBuffersMap size:%d",mWaylandBuffersMap.size());
fei.dengf7a0cd32023-08-29 09:36:37 +00001713}
1714
1715WaylandBuffer* WaylandDisplay::findWaylandBuffer(RenderBuffer * buf)
1716{
fei.deng19b48692024-08-13 14:17:55 +08001717 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001718 std::size_t hashval = calculateDmaBufferHash(buf->dma);
1719 auto item = mWaylandBuffersMap.find(hashval);
1720 if (item == mWaylandBuffersMap.end()) {
1721 return NULL;
1722 }
1723
1724 return (WaylandBuffer*) item->second;
1725}
1726
1727void WaylandDisplay::cleanAllWaylandBuffer()
1728{
fei.deng19b48692024-08-13 14:17:55 +08001729 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001730 //free all obtain buff
1731 for (auto item = mWaylandBuffersMap.begin(); item != mWaylandBuffersMap.end(); ) {
1732 WaylandBuffer *waylandbuf = (WaylandBuffer*)item->second;
1733 mWaylandBuffersMap.erase(item++);
1734 delete waylandbuf;
1735 }
1736}
1737
fei.dengda0cd9f2024-07-24 09:25:11 +08001738
1739/**
1740 * @brief clean wayland buffers those malloc before resolution changed
1741 *
1742 */
1743void WaylandDisplay::cleanWaylandBufferBeforeResChanged()
1744{
fei.deng19b48692024-08-13 14:17:55 +08001745 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengda0cd9f2024-07-24 09:25:11 +08001746 for (auto item = mWaylandBuffersMap.begin(); item != mWaylandBuffersMap.end(); ) {
1747 WaylandBuffer *wlbuf = (WaylandBuffer*)item->second;
1748 if (wlbuf->isFree()) {
1749 mWaylandBuffersMap.erase(item++);
1750 delete wlbuf;
1751 } else {
1752 item++;
1753 }
1754 }
1755}
1756
fei.dengf7a0cd32023-08-29 09:36:37 +00001757void WaylandDisplay::flushBuffers()
1758{
fei.dengb9a1a572023-09-13 01:33:57 +00001759 INFO(mLogCategory,"flushBuffers");
1760 Tls::Mutex::Autolock _l(mRenderMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001761 for (auto item = mCommittedBufferMap.begin(); item != mCommittedBufferMap.end(); item++) {
1762 WaylandBuffer *waylandbuf = (WaylandBuffer*)item->second;
1763 waylandbuf->forceRedrawing();
1764 handleFrameDisplayedCallback(waylandbuf);
1765 }
1766}
1767
1768void WaylandDisplay::cleanSurface()
1769{
1770 /* clear both video and parent surfaces */
1771 wl_surface_attach (mVideoSurfaceWrapper, NULL, 0, 0);
1772 wl_surface_commit (mVideoSurfaceWrapper);
1773 wl_surface_attach (mAreaSurfaceWrapper, NULL, 0, 0);
1774 wl_surface_commit (mAreaSurfaceWrapper);
fei.deng640c3c92024-04-12 08:31:19 +00001775}
1776
1777void WaylandDisplay::setKeepLastFrame(int keep)
1778{
1779 mKeepLastFrame = keep;
1780 if (mVideoSurfaceWrapper && mAmlConfigAPIList.enableKeepLastFrame) {
1781 INFO(mLogCategory,"keep last frame:%d",keep);
1782 wl_surface_keep_last_frame(mVideoSurfaceWrapper, keep);
fei.deng4029e682024-06-26 17:06:31 +08001783 mToSendKeepLastFrame = false;
1784 return;
fei.deng640c3c92024-04-12 08:31:19 +00001785 }
fei.deng4029e682024-06-26 17:06:31 +08001786 mToSendKeepLastFrame = true;
fei.deng6c425232024-07-19 16:15:31 +08001787}
1788
le.han15dacdd2024-09-18 05:46:09 +00001789void WaylandDisplay::setImmediatelyOutput(int enable)
1790{
1791 if (mVideoSurfaceWrapper) {
1792 wl_surface_enable_ll_mode(mVideoSurfaceWrapper, enable);
1793 }
1794 INFO(mLogCategory,"set immediately output:%d", enable);
1795}
1796
fei.deng6c425232024-07-19 16:15:31 +08001797void WaylandDisplay::setFrameRate(int frameRateNum, int frameRateDenom)
1798{
1799 mFrameRateFractionNum = frameRateNum;
1800 mFrameRateFractionDenom = frameRateDenom;
1801 if (mFrameRateFractionDenom == 0) {
1802 mFrameRateFractionDenom = 1;
1803 }
fei.deng649b0e22024-09-03 18:57:13 +08001804
1805 if (mFrameRateFractionNum > 0) {
1806 mFrameDurationUs = 1000000 * mFrameRateFractionDenom/mFrameRateFractionNum;
1807 mFrameRateChanged = true;
fei.deng6c425232024-07-19 16:15:31 +08001808 }
fei.deng649b0e22024-09-03 18:57:13 +08001809
1810 INFO(mLogCategory,"num:%d,denom:%d,frame dur:%lld us",
1811 mFrameRateFractionNum, mFrameRateFractionDenom,mFrameDurationUs);
fei.deng1c94a342024-08-05 19:33:28 +08001812}
1813
1814void WaylandDisplay::setVideoPlaneZorder(int zorder)
1815{
1816 mVideoPlaneZorder = zorder;
1817 mVideoPlaneZorderChanged = true;
1818 if (mVideoSurfaceWrapper) {
1819 mVideoPlaneZorderChanged = false;
1820 wl_surface_set_zorder(mVideoSurfaceWrapper, mVideoPlaneZorder);
1821 }
fei.deng649b0e22024-09-03 18:57:13 +08001822}
1823
1824void WaylandDisplay::pause()
1825{
1826 mLastDisplayFramePts = -1;
1827 mLastDisplayFrameTimeUs = -1;
1828}
1829void WaylandDisplay::resume()
1830{
1831
fei.dengf7a0cd32023-08-29 09:36:37 +00001832}