blob: 529e2c5307c6996a53ab1c9863151d7dc2c66df1 [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
le.hane8c8fdd2024-09-19 09:28:50 +0000672 mKeepFrameOnFlush = 1;
673 mFirstPtsAfterFlush = -1;
fei.deng3287c082024-04-23 09:29:22 +0000674 mSignalFirstFramePts = false;
fei.deng4029e682024-06-26 17:06:31 +0800675 mToSendKeepLastFrame = false;
fei.deng1c94a342024-08-05 19:33:28 +0800676 mVideoPlaneZorder = -1;
677 mVideoPlaneZorderChanged = false;
fei.dengf7a0cd32023-08-29 09:36:37 +0000678}
679
680WaylandDisplay::~WaylandDisplay()
681{
fei.dengb9a1a572023-09-13 01:33:57 +0000682 TRACE(mLogCategory,"desconstruct WaylandDisplay");
683 if (mPoll) {
684 delete mPoll;
685 mPoll = NULL;
686 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000687}
688
689char *WaylandDisplay::require_xdg_runtime_dir()
690{
691 char *val = getenv("XDG_RUNTIME_DIR");
fei.dengb9a1a572023-09-13 01:33:57 +0000692 INFO(mLogCategory,"XDG_RUNTIME_DIR=%s",val);
fei.dengdd910ef2024-06-07 10:25:30 +0800693 //if not set XDG_RUNTIME_DIR,set default value
694 // if (!val) {
695 // val = const_cast<char *>("/run/user/0");
696 // setenv("XDG_RUNTIME_DIR",val,0);
697 // WARNING(mLogCategory,"XDG_RUNTIME_DIR is not set,set default %s",val);
698 // }
fei.dengf7a0cd32023-08-29 09:36:37 +0000699
700 return val;
701}
702
703int WaylandDisplay::openDisplay()
704{
fei.deng649b0e22024-09-03 18:57:13 +0800705 mLastDisplayFramePts = -1;
706 mLastDisplayFrameTimeUs = -1;
707 mFrameDurationUs = 0;
708 mPreFramePts = -1;
709 mFrameRateDetectCnt = 0;
710 mFrameRateDetectPeriod = 0;
fei.denga4abbd52024-07-11 19:17:50 +0800711 mPixelAspectRatio = 1.0;
712 mUpdateVideoSurface = false;
fei.dengdd910ef2024-06-07 10:25:30 +0800713 mNoBorderUpdate = false;
714 mReCommitAreaSurface = false;
715 mXdgSurfaceConfigured = false;
716 mUpdateRenderRectangle = false;
fei.deng6c425232024-07-19 16:15:31 +0800717 mFrameRateFractionNum = 0;
718 mFrameRateFractionDenom = 1;
719 mFrameRateChanged = false;
fei.deng1c94a342024-08-05 19:33:28 +0800720 mVideoPlaneZorder = -1;
721 mVideoPlaneZorderChanged = false;
fei.dengdd910ef2024-06-07 10:25:30 +0800722 memset(&mRenderRect, 0, sizeof(struct Rectangle));
723 memset(&mVideoRect, 0, sizeof(struct Rectangle));
724 memset(&mWindowRect, 0, sizeof(struct Rectangle));
725 mFullScreen = true; //default is full screen
726 mAmlConfig = NULL;
727 //weston config private api
728 mAmlConfigAPIList.enableDropFrame = false;
729 mAmlConfigAPIList.enableKeepLastFrame = false;
730 mAmlConfigAPIList.enableSetPts = false;
731 mAmlConfigAPIList.enableSetVideoPlane = false;
fei.dengd0da4e22024-07-04 11:29:13 +0800732 mAmlConfigAPIList.enableSurfaceDestroyCallback = false;
fei.deng6c425232024-07-19 16:15:31 +0800733 mAmlConfigAPIList.enableSetDisplayRate = false;
fei.deng9bf724e2024-08-01 11:34:52 +0800734 mAmlConfigAPIList.enableSetSurfaceInvisible = false;
fei.deng649b0e22024-09-03 18:57:13 +0800735 mAmlConfigAPIList.enableDisplayTime = false;
fei.dengdd910ef2024-06-07 10:25:30 +0800736 mCurrentDisplayOutput = &mOutput[0];
737 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
738 mOutput[i].wlOutput = NULL;
739 mOutput[i].offsetX = 0;
740 mOutput[i].offsetY = 0;
741 mOutput[i].width = 0;
742 mOutput[i].height = 0;
743 mOutput[i].refreshRate = 0;
744 mOutput[i].isPrimary = false;
745 mOutput[i].name = 0;
746 mOutput[i].crtcIndex = 0;
747 }
fei.deng4029e682024-06-26 17:06:31 +0800748 /*if mKeepLastFrame had set but mToSendKeepLastFrame is false,maybe
749 playback is doing FF/FW action,so we keep set it on new connection*/
750 if (!mToSendKeepLastFrame && mKeepLastFrame) {
751 mToSendKeepLastFrame = true;
752 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000753 char *name = require_xdg_runtime_dir();
754 //DEBUG(mLogCategory,"name:%s",name);
fei.dengb9a1a572023-09-13 01:33:57 +0000755 DEBUG(mLogCategory,"openDisplay in");
fei.dengf7a0cd32023-08-29 09:36:37 +0000756 mWlDisplay = wl_display_connect(NULL);
757 if (!mWlDisplay) {
fei.dengb9a1a572023-09-13 01:33:57 +0000758 ERROR(mLogCategory,"Failed to connect to the wayland display, XDG_RUNTIME_DIR='%s'",
fei.dengf7a0cd32023-08-29 09:36:37 +0000759 name ? name : "NULL");
fei.dengb9a1a572023-09-13 01:33:57 +0000760 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000761 }
762
763 mWlDisplayWrapper = (struct wl_display *)wl_proxy_create_wrapper ((void *)mWlDisplay);
764 mWlQueue = wl_display_create_queue (mWlDisplay);
765 wl_proxy_set_queue ((struct wl_proxy *)mWlDisplayWrapper, mWlQueue);
766
767 mRegistry = wl_display_get_registry (mWlDisplayWrapper);
768 wl_registry_add_listener (mRegistry, &registry_listener, (void *)this);
769
770 /* we need exactly 2 roundtrips to discover global objects and their state */
771 for (int i = 0; i < 2; i++) {
772 if (wl_display_roundtrip_queue (mWlDisplay, mWlQueue) < 0) {
fei.dengb9a1a572023-09-13 01:33:57 +0000773 ERROR(mLogCategory,"Error communicating with the wayland display");
774 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000775 }
776 }
777
778 if (!mCompositor) {
fei.dengb9a1a572023-09-13 01:33:57 +0000779 ERROR(mLogCategory,"Could not bind to wl_compositor. Either it is not implemented in " \
fei.dengf7a0cd32023-08-29 09:36:37 +0000780 "the compositor, or the implemented version doesn't match");
fei.dengb9a1a572023-09-13 01:33:57 +0000781 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000782 }
783
784 if (!mDmabuf) {
fei.dengb9a1a572023-09-13 01:33:57 +0000785 ERROR(mLogCategory,"Could not bind to zwp_linux_dmabuf_v1");
786 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000787 }
788
789 if (!mXdgWmBase) {
790 /* If wl_surface and wl_display are passed via GstContext
791 * wl_shell, xdg_shell and zwp_fullscreen_shell are not used.
792 * In this case is correct to continue.
793 */
fei.dengb9a1a572023-09-13 01:33:57 +0000794 ERROR(mLogCategory,"Could not bind to either wl_shell, xdg_wm_base or "
fei.dengf7a0cd32023-08-29 09:36:37 +0000795 "zwp_fullscreen_shell, video display may not work properly.");
fei.dengb9a1a572023-09-13 01:33:57 +0000796 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000797 }
798
799 //create window surface
800 createCommonWindowSurface();
801 createXdgShellWindowSurface();
802
803 //config weston video plane
fei.deng640c3c92024-04-12 08:31:19 +0000804 if (mAmlConfigAPIList.enableSetVideoPlane) {
fei.dengb9a1a572023-09-13 01:33:57 +0000805 INFO(mLogCategory,"set weston video plane:%d",mPip);
fei.dengf7a0cd32023-08-29 09:36:37 +0000806 wl_surface_set_video_plane(mVideoSurfaceWrapper, mPip);
807 }
808
809 //run wl display queue dispatch
fei.dengb9a1a572023-09-13 01:33:57 +0000810 DEBUG(mLogCategory,"To run wl display dispatch queue");
fei.dengdd910ef2024-06-07 10:25:30 +0800811 if (mPoll) {
812 mPoll->setFlushing(false);
813 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000814 run("display queue");
815 mRedrawingPending = false;
le.hane8c8fdd2024-09-19 09:28:50 +0000816 wl_surface_set_video_plane_mute(mVideoSurfaceWrapper, 0);
fei.dengf7a0cd32023-08-29 09:36:37 +0000817
fei.dengb9a1a572023-09-13 01:33:57 +0000818 DEBUG(mLogCategory,"openDisplay out");
819 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000820}
821
822void WaylandDisplay::closeDisplay()
823{
fei.dengb9a1a572023-09-13 01:33:57 +0000824 DEBUG(mLogCategory,"closeDisplay in");
fei.dengf7a0cd32023-08-29 09:36:37 +0000825
fei.dengd0da4e22024-07-04 11:29:13 +0800826 //first destroy window surface
827 destroyWindowSurfaces();
fei.dengf7a0cd32023-08-29 09:36:37 +0000828
fei.deng4029e682024-06-26 17:06:31 +0800829 //flush pending event to weston
fei.dengdd910ef2024-06-07 10:25:30 +0800830 if (mWlDisplay) {
831 wl_display_flush (mWlDisplay);
832 }
833
fei.dengd0da4e22024-07-04 11:29:13 +0800834 //wait video surface destroyed or 50ms timeout
835 if (mAmlConfigAPIList.enableSurfaceDestroyCallback) {
836 INFO(mLogCategory,"waiting surface_destroy_cb from weston");
837 Tls::Mutex::Autolock _l(mMutex);
838 if (ERROR_TIMED_OUT == mCondition.waitRelative(mMutex, 50/*microsecond*/)) {
839 WARNING(mLogCategory,"waited surface_destroy_cb timeout");
840 }
841 }
842
843 //we should receive all event from weston before stopped dispatch queue
844 if (isRunning()) {
845 TRACE(mLogCategory,"try stop dispatch thread");
846 if (mPoll) {
847 mPoll->setFlushing(true);
848 }
849 requestExitAndWait();
850 }
851 //after destroyed surface,then destroy buffers,otherwise maybe crash
852 if (mAreaShmBuffer) {
853 delete mAreaShmBuffer;
854 mAreaShmBuffer = NULL;
855 }
856
857 //clean all wayland buffers
858 cleanAllWaylandBuffer();
fei.dengf7a0cd32023-08-29 09:36:37 +0000859
860 if (mViewporter) {
861 wp_viewporter_destroy (mViewporter);
862 mViewporter = NULL;
863 }
864
865 if (mDmabuf) {
866 zwp_linux_dmabuf_v1_destroy (mDmabuf);
867 mDmabuf = NULL;
868 }
869
870 if (mXdgWmBase) {
871 xdg_wm_base_destroy (mXdgWmBase);
872 mXdgWmBase = NULL;
873 }
874
875 if (mCompositor) {
876 wl_compositor_destroy (mCompositor);
877 mCompositor = NULL;
878 }
879
880 if (mSubCompositor) {
881 wl_subcompositor_destroy (mSubCompositor);
882 mSubCompositor = NULL;
883 }
884
885 if (mRegistry) {
886 wl_registry_destroy (mRegistry);
887 mRegistry= NULL;
888 }
889
890 if (mWlDisplayWrapper) {
891 wl_proxy_wrapper_destroy (mWlDisplayWrapper);
892 mWlDisplayWrapper = NULL;
893 }
894
fei.deng640c3c92024-04-12 08:31:19 +0000895 if (mAmlConfig) {
896 aml_config_destroy(mAmlConfig);
897 mAmlConfig = NULL;
898 }
899
fei.dengf7a0cd32023-08-29 09:36:37 +0000900 if (mWlQueue) {
901 wl_event_queue_destroy (mWlQueue);
902 mWlQueue = NULL;
903 }
904
905 if (mWlDisplay) {
906 wl_display_flush (mWlDisplay);
907 wl_display_disconnect (mWlDisplay);
908 mWlDisplay = NULL;
909 }
910
fei.dengb9a1a572023-09-13 01:33:57 +0000911 DEBUG(mLogCategory,"closeDisplay out");
fei.dengf7a0cd32023-08-29 09:36:37 +0000912}
913
914int WaylandDisplay::toDmaBufferFormat(RenderVideoFormat format, uint32_t *outDmaformat /*out param*/, uint64_t *outDmaformatModifiers /*out param*/)
915{
916 if (!outDmaformat || !outDmaformatModifiers) {
fei.dengb9a1a572023-09-13 01:33:57 +0000917 WARNING(mLogCategory,"NULL params");
918 return ERROR_PARAM_NULL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000919 }
920
921 *outDmaformat = 0;
922 *outDmaformatModifiers = 0;
923
924 uint32_t dmaformat = video_format_to_wl_dmabuf_format (format);
925 if (dmaformat == -1) {
fei.dengb9a1a572023-09-13 01:33:57 +0000926 ERROR(mLogCategory,"Error not found render video format:%d to wl dmabuf format",format);
927 return ERROR_NOT_FOUND;
fei.dengf7a0cd32023-08-29 09:36:37 +0000928 }
929
fei.dengb9a1a572023-09-13 01:33:57 +0000930 TRACE(mLogCategory,"render video format:%d -> dmabuf format:%d",format,dmaformat);
fei.dengf7a0cd32023-08-29 09:36:37 +0000931 *outDmaformat = (uint32_t)dmaformat;
932
933 /*get dmaformat and modifiers*/
934 auto item = mDmaBufferFormats.find(dmaformat);
935 if (item == mDmaBufferFormats.end()) { //not found
fei.dengb9a1a572023-09-13 01:33:57 +0000936 WARNING(mLogCategory,"Not found dmabuf for render video format :%d",format);
fei.dengf7a0cd32023-08-29 09:36:37 +0000937 *outDmaformatModifiers = 0;
fei.dengb9a1a572023-09-13 01:33:57 +0000938 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000939 }
940
941 *outDmaformatModifiers = (uint64_t)item->second;
942
fei.dengb9a1a572023-09-13 01:33:57 +0000943 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000944}
945
946int WaylandDisplay::toShmBufferFormat(RenderVideoFormat format, uint32_t *outformat)
947{
948 if (!outformat) {
fei.dengb9a1a572023-09-13 01:33:57 +0000949 WARNING(mLogCategory,"NULL params");
950 return ERROR_PARAM_NULL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000951 }
952
953 *outformat = 0;
954
955 int shmformat = (int)video_format_to_wl_shm_format(format);
956 if (shmformat < 0) {
fei.dengb9a1a572023-09-13 01:33:57 +0000957 ERROR(mLogCategory,"Error not found render video format:%d to wl shmbuf format",format);
958 return ERROR_NOT_FOUND;
fei.dengf7a0cd32023-08-29 09:36:37 +0000959 }
960
961 for (auto item = mShmFormats.begin(); item != mShmFormats.end(); ++item) {
962 uint32_t registFormat = (uint32_t)*item;
963 if (registFormat == (uint32_t)shmformat) {
964 *outformat = registFormat;
fei.dengb9a1a572023-09-13 01:33:57 +0000965 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000966 }
967 }
968
fei.dengb9a1a572023-09-13 01:33:57 +0000969 return ERROR_NOT_FOUND;
fei.dengf7a0cd32023-08-29 09:36:37 +0000970}
971
972void WaylandDisplay::setVideoBufferFormat(RenderVideoFormat format)
973{
fei.dengb9a1a572023-09-13 01:33:57 +0000974 TRACE(mLogCategory,"set video buffer format: %d",format);
fei.dengf7a0cd32023-08-29 09:36:37 +0000975 mBufferFormat = format;
976};
977
978void WaylandDisplay::setDisplayOutput(int output)
979{
fei.dengb9a1a572023-09-13 01:33:57 +0000980 TRACE(mLogCategory,"select display output: %d",output);
fei.dengf7a0cd32023-08-29 09:36:37 +0000981 if (output < 0 || output >= DEFAULT_DISPLAY_OUTPUT_NUM) {
fei.dengb9a1a572023-09-13 01:33:57 +0000982 ERROR(mLogCategory, "display output index error,please set 0:primary or 1:extend,now:%d",output);
fei.dengf7a0cd32023-08-29 09:36:37 +0000983 return;
984 }
fei.deng26950832023-11-09 03:00:23 +0000985 //only do select output before video playing
986 if (mSelectOutputIndex != output) {
987 mSelectOutputIndex = output;
988 // if (mOutput[output].wlOutput) {
989 // mCurrentDisplayOutput = &mOutput[output];
990 // setRenderRectangle(mOutput[output].offsetX, mOutput[output].offsetY,
991 // mOutput[output].width, mOutput[output].height);
992 // }
fei.dengf7a0cd32023-08-29 09:36:37 +0000993 }
994}
995
996int WaylandDisplay::getDisplayOutput()
997{
fei.deng26950832023-11-09 03:00:23 +0000998 return mSelectOutputIndex == INVALID_OUTPUT_INDEX? 0: mSelectOutputIndex;
fei.dengf7a0cd32023-08-29 09:36:37 +0000999}
1000
1001void WaylandDisplay::setPip(int pip)
1002{
fei.dengb9a1a572023-09-13 01:33:57 +00001003 INFO(mLogCategory,"set pip:%d",pip);
fei.dengf7a0cd32023-08-29 09:36:37 +00001004 mPip = pip;
1005}
1006
fei.deng26950832023-11-09 03:00:23 +00001007void WaylandDisplay::updateDisplayOutput()
1008{
1009 if (!mCurrentDisplayOutput->wlOutput || !mXdgToplevel || !mXdgSurface)
1010 {
1011 return;
1012 }
1013 if (mUpdateRenderRectangle) {
1014 if (mFullScreen) {
1015 DEBUG(mLogCategory,"unset full screen");
1016 xdg_toplevel_unset_fullscreen (mXdgToplevel);
1017 }
1018
1019 if (mXdgSurface) {
1020 DEBUG(mLogCategory,"set geometry");
1021 xdg_surface_set_window_geometry(mXdgSurface,
1022 mCurrentDisplayOutput->offsetX,
1023 mCurrentDisplayOutput->offsetY,
1024 mCurrentDisplayOutput->width,
1025 mCurrentDisplayOutput->height);
1026 }
1027
1028 if (mFullScreen && mXdgToplevel) {
1029 DEBUG(mLogCategory,"set full screen");
1030 xdg_toplevel_set_fullscreen (mXdgToplevel, mCurrentDisplayOutput->wlOutput);
1031 }
1032 setRenderRectangle(mCurrentDisplayOutput->offsetX, mCurrentDisplayOutput->offsetY,
1033 mCurrentDisplayOutput->width, mCurrentDisplayOutput->height);
1034 mUpdateRenderRectangle = false;
1035 }
1036}
1037
fei.dengf7a0cd32023-08-29 09:36:37 +00001038void WaylandDisplay::createCommonWindowSurface()
1039{
1040 struct wl_region *region;
1041
1042 mAreaSurface = wl_compositor_create_surface (mCompositor);
1043 mVideoSurface = wl_compositor_create_surface (mCompositor);
1044 mAreaSurfaceWrapper = (struct wl_surface *)wl_proxy_create_wrapper (mAreaSurface);
1045 mVideoSurfaceWrapper = (struct wl_surface *)wl_proxy_create_wrapper (mVideoSurface);
1046
1047 wl_proxy_set_queue ((struct wl_proxy *) mAreaSurfaceWrapper, mWlQueue);
1048 wl_proxy_set_queue ((struct wl_proxy *) mVideoSurfaceWrapper, mWlQueue);
1049
1050 /* embed video_surface in area_surface */
1051 mVideoSubSurface = wl_subcompositor_get_subsurface (mSubCompositor, mVideoSurface, mAreaSurface);
1052 wl_subsurface_set_desync (mVideoSubSurface);
1053
fei.dengd0da4e22024-07-04 11:29:13 +08001054 //add video surface callback to weston if weston enable this feature
1055 if (mVideoSurface && mAmlConfigAPIList.enableSurfaceDestroyCallback) {
1056 struct wl_callback *surfaceDestroyCb = wl_surface_destroy_callback(mVideoSurface);
1057 wl_callback_add_listener(surfaceDestroyCb, &surface_destroy_listener, this);
1058 }
1059
fei.dengf7a0cd32023-08-29 09:36:37 +00001060 if (mViewporter) {
1061 mAreaViewport = wp_viewporter_get_viewport (mViewporter, mAreaSurface);
1062 mVideoViewport = wp_viewporter_get_viewport (mViewporter, mVideoSurface);
1063 }
1064
fei.deng9bf724e2024-08-01 11:34:52 +08001065 /*set area surface to invisible. prevent frame droped at start playback,
1066 wl_surface_set_invisible must called before mAreaSurface commit called*/
1067 if (mAmlConfigAPIList.enableSetSurfaceInvisible) {
1068 int invisible = 1;
1069 INFO(mLogCategory,"set surface invisible:%d",invisible);
1070 wl_surface_set_invisible(mAreaSurfaceWrapper, invisible);
1071 }
1072
fei.deng649b0e22024-09-03 18:57:13 +08001073 if (mAmlConfigAPIList.enableDisplayTime) {
1074 INFO(mLogCategory,"set enable display time");
1075 wl_surface_enable_display_time(mVideoSurface, 1);
1076 }
1077
fei.dengf7a0cd32023-08-29 09:36:37 +00001078 /* do not accept input */
1079 region = wl_compositor_create_region (mCompositor);
1080 wl_surface_set_input_region (mAreaSurface, region);
1081 wl_region_destroy (region);
1082
1083 region = wl_compositor_create_region (mCompositor);
1084 wl_surface_set_input_region (mVideoSurface, region);
1085 wl_region_destroy (region);
1086}
1087
1088void WaylandDisplay::createXdgShellWindowSurface()
1089{
1090 /* Check which protocol we will use (in order of preference) */
1091 if (mXdgWmBase) {
1092 /* First create the XDG surface */
1093 mXdgSurface= xdg_wm_base_get_xdg_surface (mXdgWmBase, mAreaSurface);
1094 if (!mXdgSurface) {
fei.dengb9a1a572023-09-13 01:33:57 +00001095 ERROR(mLogCategory,"Unable to get xdg_surface");
fei.dengf7a0cd32023-08-29 09:36:37 +00001096 return;
1097 }
1098 xdg_surface_add_listener (mXdgSurface, &xdg_surface_listener,(void *)this);
1099
1100 /* Then the toplevel */
1101 mXdgToplevel= xdg_surface_get_toplevel (mXdgSurface);
1102 if (!mXdgSurface) {
fei.dengb9a1a572023-09-13 01:33:57 +00001103 ERROR(mLogCategory,"Unable to get xdg_toplevel");
fei.dengf7a0cd32023-08-29 09:36:37 +00001104 return;
1105 }
1106 xdg_toplevel_add_listener (mXdgToplevel, &xdg_toplevel_listener, this);
1107
1108 /* Finally, commit the xdg_surface state as toplevel */
1109 mXdgSurfaceConfigured = false;
1110 wl_surface_commit (mAreaSurface);
1111 wl_display_flush (mWlDisplay);
1112 /* we need exactly 3 roundtrips to discover global objects and their state */
1113 for (int i = 0; i < 3; i++) {
1114 if (wl_display_roundtrip_queue(mWlDisplay, mWlQueue) < 0) {
fei.dengb9a1a572023-09-13 01:33:57 +00001115 ERROR(mLogCategory,"Error communicating with the wayland display");
fei.dengf7a0cd32023-08-29 09:36:37 +00001116 }
1117 }
1118
1119 if (mXdgSurfaceConfigured) {
fei.dengb9a1a572023-09-13 01:33:57 +00001120 INFO(mLogCategory,"xdg surface had configured");
fei.dengf7a0cd32023-08-29 09:36:37 +00001121 } else {
fei.dengb9a1a572023-09-13 01:33:57 +00001122 WARNING(mLogCategory,"xdg surface not configured");
fei.dengf7a0cd32023-08-29 09:36:37 +00001123 }
1124
1125 //full screen show
fei.deng26950832023-11-09 03:00:23 +00001126 // if (mFullScreen && mCurrentDisplayOutput->wlOutput) {
1127 // //ensureFullscreen(mFullScreen);
fei.dengf7a0cd32023-08-29 09:36:37 +00001128 // }
1129 } else {
fei.dengb9a1a572023-09-13 01:33:57 +00001130 ERROR(mLogCategory,"Unable to use xdg_wm_base ");
fei.dengf7a0cd32023-08-29 09:36:37 +00001131 return;
1132 }
1133}
1134
1135void WaylandDisplay::destroyWindowSurfaces()
1136{
fei.dengf7a0cd32023-08-29 09:36:37 +00001137 if (mXdgToplevel) {
1138 xdg_toplevel_destroy (mXdgToplevel);
1139 mXdgToplevel = NULL;
1140 }
1141
1142 if (mXdgSurface) {
1143 xdg_surface_destroy (mXdgSurface);
1144 mXdgSurface = NULL;
1145 }
1146
1147 if (mVideoSurfaceWrapper) {
1148 wl_proxy_wrapper_destroy (mVideoSurfaceWrapper);
1149 mVideoSurfaceWrapper = NULL;
1150 }
1151
1152 if (mVideoSubSurface) {
1153 wl_subsurface_destroy (mVideoSubSurface);
1154 mVideoSubSurface = NULL;
1155 }
1156
1157 if (mVideoSurface) {
1158 wl_surface_destroy (mVideoSurface);
1159 mVideoSurface = NULL;
1160 }
1161
1162 if (mAreaSurfaceWrapper) {
1163 wl_proxy_wrapper_destroy (mAreaSurfaceWrapper);
1164 mAreaSurfaceWrapper = NULL;
1165 }
1166
1167 if (mAreaSurface) {
1168 wl_surface_destroy (mAreaSurface);
1169 mAreaSurface = NULL;
1170 mReCommitAreaSurface = false;
1171 }
1172}
1173
1174void WaylandDisplay::ensureFullscreen(bool fullscreen)
1175{
1176 if (mXdgWmBase) {
fei.dengb9a1a572023-09-13 01:33:57 +00001177 DEBUG(mLogCategory,"full screen : %d",fullscreen);
fei.dengf7a0cd32023-08-29 09:36:37 +00001178 if (fullscreen) {
fei.deng26950832023-11-09 03:00:23 +00001179 xdg_toplevel_set_fullscreen (mXdgToplevel, mCurrentDisplayOutput->wlOutput);
fei.dengf7a0cd32023-08-29 09:36:37 +00001180 } else {
1181 xdg_toplevel_unset_fullscreen (mXdgToplevel);
1182 }
1183 }
1184}
1185
1186void WaylandDisplay::setRenderRectangle(int x, int y, int w, int h)
1187{
fei.dengb9a1a572023-09-13 01:33:57 +00001188 DEBUG(mLogCategory,"set render rect:x:%d,y:%d,w:%d,h:%d",x,y,w,h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001189
1190 if (w <= 0 || h <= 0) {
fei.dengb9a1a572023-09-13 01:33:57 +00001191 WARNING(mLogCategory, "wrong render width or height %dx%d",w,h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001192 return;
1193 }
1194
1195 mRenderRect.x = x;
1196 mRenderRect.y = y;
1197 mRenderRect.w = w;
1198 mRenderRect.h = h;
1199
1200 if (!mXdgSurfaceConfigured) {
fei.dengb9a1a572023-09-13 01:33:57 +00001201 WARNING(mLogCategory,"Not configured xdg");
fei.dengf7a0cd32023-08-29 09:36:37 +00001202 return;
1203 }
1204
1205 if (mAreaViewport) {
1206 wp_viewport_set_destination (mAreaViewport, w, h);
1207 }
1208
1209 updateBorders();
1210
1211 if (mVideoWidth != 0 && mVideoSurface) {
1212 wl_subsurface_set_sync (mVideoSubSurface);
1213 resizeVideoSurface(true);
1214 }
1215
1216 wl_surface_damage (mAreaSurfaceWrapper, 0, 0, w, h);
1217 wl_surface_commit (mAreaSurfaceWrapper);
1218
1219 if (mVideoWidth != 0) {
1220 wl_subsurface_set_desync (mVideoSubSurface);
1221 }
1222}
1223
fei.dengf7a0cd32023-08-29 09:36:37 +00001224void WaylandDisplay::setFrameSize(int w, int h)
1225{
1226 mVideoWidth = w;
1227 mVideoHeight = h;
fei.denga4abbd52024-07-11 19:17:50 +08001228 mUpdateVideoSurface = true;
fei.dengb9a1a572023-09-13 01:33:57 +00001229 TRACE(mLogCategory,"frame w:%d,h:%d",mVideoWidth,mVideoHeight);
fei.dengf7a0cd32023-08-29 09:36:37 +00001230}
1231
1232void WaylandDisplay::setWindowSize(int x, int y, int w, int h)
1233{
1234 mWindowRect.x = x;
1235 mWindowRect.y = y;
1236 mWindowRect.w = w;
1237 mWindowRect.h = h;
fei.denga4abbd52024-07-11 19:17:50 +08001238 mUpdateVideoSurface = true;
fei.dengb9a1a572023-09-13 01:33:57 +00001239 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 +00001240}
1241
fei.denga4abbd52024-07-11 19:17:50 +08001242void WaylandDisplay::setPixelAspectRatio(double ratio)
1243{
1244 mPixelAspectRatio = ratio;
1245 mUpdateVideoSurface = true;
1246}
fei.dengf7a0cd32023-08-29 09:36:37 +00001247
1248void WaylandDisplay::resizeVideoSurface(bool commit)
1249{
1250 Rectangle src = {0,};
1251 Rectangle dst = {0,};
1252 Rectangle res;
1253
1254 /* center the video_subsurface inside area_subsurface */
1255 src.w = mVideoWidth;
1256 src.h = mVideoHeight;
1257 /*if had set the window size, we will scall
1258 video surface to this window size*/
1259 if (mWindowRect.w > 0 && mWindowRect.h > 0) {
1260 dst.x = mWindowRect.x;
1261 dst.y = mWindowRect.y;
1262 dst.w = mWindowRect.w;
1263 dst.h = mWindowRect.h;
1264 if (mWindowRect.w > mRenderRect.w && mWindowRect.h > mRenderRect.h) {
fei.dengb9a1a572023-09-13 01:33:57 +00001265 WARNING(mLogCategory,"Error window size:%dx%d, but render size:%dx%d,reset to render size",
fei.dengf7a0cd32023-08-29 09:36:37 +00001266 mWindowRect.w,mWindowRect.h,mRenderRect.w,mRenderRect.h);
1267 dst.x = mRenderRect.x;
1268 dst.y = mRenderRect.y;
1269 dst.w = mRenderRect.w;
1270 dst.h = mRenderRect.h;
1271 }
1272 //to do,we need set geometry?
1273 //if (mXdgSurface) {
1274 // xdg_surface_set_window_geometry(mXdgSurface, mWindowRect.x, mWindowRect.y, mWindowRect.w, mWindowRect.h);
1275 //}
1276 } else { //scal video to full screen
1277 dst.w = mRenderRect.w;
1278 dst.h = mRenderRect.h;
1279 }
1280
1281 if (mViewporter) {
1282 videoCenterRect(src, dst, &res, true);
1283 } else {
1284 videoCenterRect(src, dst, &res, false);
1285 }
1286
1287 wl_subsurface_set_position (mVideoSubSurface, res.x, res.y);
1288
1289 if (commit) {
1290 wl_surface_damage (mVideoSurfaceWrapper, 0, 0, res.w, res.h);
1291 wl_surface_commit (mVideoSurfaceWrapper);
1292 }
1293
1294 //top level setting
1295 if (mXdgToplevel) {
1296 struct wl_region *region;
1297
1298 region = wl_compositor_create_region (mCompositor);
1299 wl_region_add (region, 0, 0, mRenderRect.w, mRenderRect.h);
1300 wl_surface_set_input_region (mAreaSurface, region);
1301 wl_region_destroy (region);
1302 }
1303
1304 /* this is saved for use in wl_surface_damage */
1305 mVideoRect.x = res.x;
1306 mVideoRect.y = res.y;
1307 mVideoRect.w = res.w;
1308 mVideoRect.h = res.h;
1309
fei.denga4abbd52024-07-11 19:17:50 +08001310 //to scale video surface
fei.dengf7a0cd32023-08-29 09:36:37 +00001311 wp_viewport_set_destination(mVideoViewport, res.w, res.h);
fei.denga4abbd52024-07-11 19:17:50 +08001312 wl_display_flush (mWlDisplay);
fei.dengb9a1a572023-09-13 01:33:57 +00001313 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 +00001314}
1315
1316void WaylandDisplay::setOpaque()
1317{
1318 struct wl_region *region;
1319
1320 /* Set area opaque */
1321 region = wl_compositor_create_region (mCompositor);
1322 wl_region_add (region, 0, 0, mRenderRect.w, mRenderRect.h);
1323 wl_surface_set_opaque_region (mAreaSurface, region);
1324 wl_region_destroy (region);
1325}
1326
1327int WaylandDisplay::prepareFrameBuffer(RenderBuffer * buf)
1328{
1329 WaylandBuffer *waylandBuf = NULL;
1330 int ret;
fei.dengda0cd9f2024-07-24 09:25:11 +08001331 bool isNew = false;
fei.dengf7a0cd32023-08-29 09:36:37 +00001332
fei.deng649b0e22024-09-03 18:57:13 +08001333 //detect frame rate and frame duration
1334 if (mFrameRateFractionNum == 0) {
1335 if (mPreFramePts == -1) {
1336 mPreFramePts = buf->pts; //ns
1337 } else {
1338 if (mFrameRateDetectCnt < DETECT_FRAMERATE_CNT) {
1339 mFrameRateDetectPeriod += (buf->pts - mPreFramePts);
1340 ++mFrameRateDetectCnt;
1341 }
1342 if (mFrameRateDetectCnt == DETECT_FRAMERATE_CNT) {
1343 int64_t mFrameDurationUs = (mFrameRateDetectPeriod/mFrameRateDetectCnt)/1000;
1344 double rate = 1000000.0/mFrameDurationUs;
1345 mFrameRateFractionNum = rate * 100;
1346 mFrameRateFractionDenom = 100;
1347 mFrameRateChanged = true;
1348 INFO(mLogCategory,"detect frame num:%d,denom:%d,dur:%lld us",
1349 mFrameRateFractionNum,mFrameRateFractionDenom,mFrameDurationUs);
1350 }
1351 }
1352 }
1353 mPreFramePts = buf->pts;
1354
fei.dengdd910ef2024-06-07 10:25:30 +08001355 if (!mDmabuf)
1356 {
1357 ERROR(mLogCategory,"Error zwp_linux_dmabuf_v1");
1358 return ERROR_UNKNOWN;
1359 }
1360
fei.dengf7a0cd32023-08-29 09:36:37 +00001361 waylandBuf = findWaylandBuffer(buf);
1362 if (waylandBuf == NULL) {
fei.dengb9a1a572023-09-13 01:33:57 +00001363 waylandBuf = new WaylandBuffer(this, mLogCategory);
fei.dengda0cd9f2024-07-24 09:25:11 +08001364 isNew = true;
1365 }
1366 waylandBuf->setBufferFormat(mBufferFormat);
1367 ret = waylandBuf->constructWlBuffer(buf);
1368 if (ret != NO_ERROR) {
1369 WARNING(mLogCategory,"dmabufConstructWlBuffer fail,release waylandbuf");
1370 //delete waylanBuf,WaylandBuffer object destruct will call release callback
1371 goto waylandbuf_fail;
1372 }
1373 if (isNew) {
1374 addWaylandBuffer(buf, waylandBuf);
fei.dengf7a0cd32023-08-29 09:36:37 +00001375 }
fei.dengb9a1a572023-09-13 01:33:57 +00001376 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +00001377waylandbuf_fail:
1378 //delete waylandbuf
1379 delete waylandBuf;
1380 waylandBuf = NULL;
fei.dengb9a1a572023-09-13 01:33:57 +00001381 return ERROR_UNKNOWN;
fei.dengf7a0cd32023-08-29 09:36:37 +00001382}
1383
1384void WaylandDisplay::displayFrameBuffer(RenderBuffer * buf, int64_t realDisplayTime)
1385{
fei.deng19b48692024-08-13 14:17:55 +08001386 WaylandBuffer *waylandBuf = NULL;
1387 struct wl_buffer * wlbuffer = NULL;
1388 int ret;
1389
1390 if (!buf) {
1391 ERROR(mLogCategory,"Error input params, RenderBuffer is null");
1392 return;
1393 }
1394
1395 if (buf->flag & BUFFER_FLAG_DMA_BUFFER) {
1396 if (buf->dma.width <=0 || buf->dma.height <=0) {
1397 buf->dma.width = mVideoWidth;
1398 buf->dma.height = mVideoHeight;
1399 }
1400
1401 waylandBuf = findWaylandBuffer(buf);
1402 if (waylandBuf) {
1403 waylandBuf->setRenderRealTime(realDisplayTime);
1404 } else {
1405 ERROR(mLogCategory,"NOT found wayland buffer,please prepare buffer first");
1406 goto waylandbuf_fail;
1407 }
1408 }
1409
1410 //if no wl_output, drop this buffer
1411 if (mCurrentDisplayOutput->wlOutput == NULL) {
1412 TRACE(mLogCategory,"No wl_output");
1413 //insert this buffer to committed weston buffer manager
1414 std::pair<int64_t, WaylandBuffer *> item(realDisplayTime, waylandBuf);
1415 mCommittedBufferMap.insert(item);
1416 mWaylandPlugin->handleFrameDropped(buf);
1417 WaylandBuffer::bufferRelease(waylandBuf,NULL);
1418 return;
1419 }
1420
1421 //must commit areasurface first, because weston xdg surface maybe timeout
1422 //this cause video is not display,commit can resume xdg surface
1423 if (!mReCommitAreaSurface) {
1424 mReCommitAreaSurface = true;
1425 wl_surface_commit (mAreaSurface);
1426 }
1427
fei.deng6c425232024-07-19 16:15:31 +08001428 //set frame rate to weston,it lets weston to select suitable mode
1429 if (mFrameRateChanged && mAmlConfigAPIList.enableSetDisplayRate) {
1430 mFrameRateChanged = false;
1431 TRACE(mLogCategory,"set frame rate %d/%d to weston", mFrameRateFractionNum, mFrameRateFractionDenom);
1432 wl_surface_set_display_rate(mVideoSurfaceWrapper, mFrameRateFractionNum, mFrameRateFractionDenom);
1433 }
fei.denga4abbd52024-07-11 19:17:50 +08001434 //update video surface size
1435 if (mUpdateVideoSurface && mVideoSurface &&
1436 buf->dma.width == mVideoWidth && buf->dma.height == mVideoHeight) {
1437 mUpdateVideoSurface = false;
1438 //if had full screen, unset it and set window size
1439 if (mFullScreen) {
1440 mFullScreen = false;
1441 ensureFullscreen(mFullScreen);
1442 }
1443 resizeVideoSurface(true);
fei.dengda0cd9f2024-07-24 09:25:11 +08001444 /*clean wayland buffers those allocated
1445 before resolution changed and had release by weston */
1446 cleanWaylandBufferBeforeResChanged();
fei.denga4abbd52024-07-11 19:17:50 +08001447 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001448
fei.deng1c94a342024-08-05 19:33:28 +08001449 if (mVideoPlaneZorderChanged && mVideoSurfaceWrapper) {
1450 mVideoPlaneZorderChanged = false;
1451 wl_surface_set_zorder(mVideoSurfaceWrapper, mVideoPlaneZorder);
1452 }
1453
fei.dengdd910ef2024-06-07 10:25:30 +08001454 //TRACE(mLogCategory,"display renderBuffer:%p,PTS:%lld us,realtime:%lld",buf, buf->pts/1000, realDisplayTime);
fei.dengf7a0cd32023-08-29 09:36:37 +00001455
fei.dengf7a0cd32023-08-29 09:36:37 +00001456 if (waylandBuf) {
1457 wlbuffer = waylandBuf->getWlBuffer();
1458 }
fei.deng19b48692024-08-13 14:17:55 +08001459
fei.dengf7a0cd32023-08-29 09:36:37 +00001460 if (wlbuffer) {
fei.dengf3ee6912024-08-30 18:22:55 +08001461 auto cItem = mCommittedBufferMap.find(realDisplayTime);
1462 if (cItem != mCommittedBufferMap.end()) {
1463 TRACE(mLogCategory,"Error.release same display time buffer,pts:%lld us",buf->pts/1000);
1464 goto waylandbuf_fail;
1465 }
fei.dengb9a1a572023-09-13 01:33:57 +00001466 Tls::Mutex::Autolock _l(mRenderMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001467 ++mCommitCnt;
1468 uint32_t hiPts = realDisplayTime >> 32;
1469 uint32_t lowPts = realDisplayTime & 0xFFFFFFFF;
1470 //attach this wl_buffer to weston
fei.denga4abbd52024-07-11 19:17:50 +08001471 TRACE(mLogCategory,"++attach,renderbuf:%p,wl_buffer:%p(%d,%d,%d,%d),pts:%lld us,commitCnt:%d",
1472 buf,wlbuffer,mVideoRect.x,mVideoRect.y,mVideoRect.w,mVideoRect.h,buf->pts/1000,mCommitCnt);
fei.dengf7a0cd32023-08-29 09:36:37 +00001473 waylandBuf->attach(mVideoSurfaceWrapper);
1474
fei.deng640c3c92024-04-12 08:31:19 +00001475 if (mAmlConfigAPIList.enableSetPts) {
fei.dengb9a1a572023-09-13 01:33:57 +00001476 TRACE(mLogCategory,"display time:%lld,hiPts:%u,lowPts:%u",realDisplayTime, hiPts, lowPts);
fei.dengf7a0cd32023-08-29 09:36:37 +00001477 wl_surface_set_pts(mVideoSurfaceWrapper, hiPts, lowPts);
1478 }
1479
le.hane8c8fdd2024-09-19 09:28:50 +00001480 if (!mKeepFrameOnFlush && mFirstPtsAfterFlush == -1) {
1481 mFirstPtsAfterFlush = buf->pts;
1482 }
1483
fei.dengf7a0cd32023-08-29 09:36:37 +00001484 wl_surface_damage (mVideoSurfaceWrapper, 0, 0, mVideoRect.w, mVideoRect.h);
1485 wl_surface_commit (mVideoSurfaceWrapper);
1486 //insert this buffer to committed weston buffer manager
fei.dengae8c90a2024-06-27 13:39:53 +08001487 std::pair<int64_t, WaylandBuffer *> item(realDisplayTime, waylandBuf);
fei.dengf7a0cd32023-08-29 09:36:37 +00001488 mCommittedBufferMap.insert(item);
1489 } else {
fei.dengb9a1a572023-09-13 01:33:57 +00001490 WARNING(mLogCategory,"wlbuffer is NULL");
fei.dengf7a0cd32023-08-29 09:36:37 +00001491 /* clear both video and parent surfaces */
fei.deng19b48692024-08-13 14:17:55 +08001492 //cleanSurface();
1493 goto waylandbuf_fail;
fei.dengf7a0cd32023-08-29 09:36:37 +00001494 }
1495
1496 wl_display_flush (mWlDisplay);
fei.deng4029e682024-06-26 17:06:31 +08001497 //set keep last frame or not when after send first buffer to weston,1 keep last frame, 0 not
1498 if (mToSendKeepLastFrame) {
1499 setKeepLastFrame(mKeepLastFrame);
1500 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001501
1502 return;
1503waylandbuf_fail:
1504 //notify dropped
1505 mWaylandPlugin->handleFrameDropped(buf);
1506 //notify app release this buf
1507 mWaylandPlugin->handleBufferRelease(buf);
fei.dengf3ee6912024-08-30 18:22:55 +08001508
fei.dengf7a0cd32023-08-29 09:36:37 +00001509 return;
1510}
1511
1512void WaylandDisplay::handleBufferReleaseCallback(WaylandBuffer *buf)
1513{
fei.denga4abbd52024-07-11 19:17:50 +08001514 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.dengf7a0cd32023-08-29 09:36:37 +00001515 {
fei.dengb9a1a572023-09-13 01:33:57 +00001516 Tls::Mutex::Autolock _l(mRenderMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001517 //remove buffer if this buffer is ready to release
fei.dengae8c90a2024-06-27 13:39:53 +08001518 auto item = mCommittedBufferMap.find(buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001519 if (item != mCommittedBufferMap.end()) {
fei.dengdd910ef2024-06-07 10:25:30 +08001520 --mCommitCnt;
fei.dengf7a0cd32023-08-29 09:36:37 +00001521 mCommittedBufferMap.erase(item);
1522 } else {
fei.denga4abbd52024-07-11 19:17:50 +08001523 TRACE(mLogCategory,"Error,Can't find WaylandBuffer pts:%lld us (%lld) in buffer map",
1524 renderBuffer->pts/1000,buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001525 return;
1526 }
1527 }
fei.denga4abbd52024-07-11 19:17:50 +08001528
1529 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 +00001530 mWaylandPlugin->handleBufferRelease(renderBuffer);
1531}
1532
1533void WaylandDisplay::handleFrameDisplayedCallback(WaylandBuffer *buf)
1534{
1535 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.denga4abbd52024-07-11 19:17:50 +08001536 TRACE(mLogCategory,"renderBuffer :%p,PTS:%lld us,realtime:%lld us",renderBuffer,renderBuffer->pts/1000,buf->getRenderRealTime());
fei.deng3287c082024-04-23 09:29:22 +00001537 if (!mSignalFirstFramePts) {
1538 mSignalFirstFramePts = true;
1539 mWaylandPlugin->handleMsgNotify(MSG_FIRST_FRAME, (void*)&renderBuffer->pts);
1540 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001541 mWaylandPlugin->handleFrameDisplayed(renderBuffer);
le.hane8c8fdd2024-09-19 09:28:50 +00001542 if (!mKeepFrameOnFlush && mFirstPtsAfterFlush == renderBuffer->pts) {
1543 mKeepFrameOnFlush = 1;
1544 mFirstPtsAfterFlush = -1;
1545 wl_surface_set_video_plane_mute(mVideoSurfaceWrapper, 0);
1546 INFO(mLogCategory,"unmute video plane");
1547 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001548}
1549
1550void WaylandDisplay::handleFrameDropedCallback(WaylandBuffer *buf)
1551{
1552 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.denga4abbd52024-07-11 19:17:50 +08001553 TRACE(mLogCategory,"renderBuffer :%p,PTS:%lld us,realtime:%lld us",renderBuffer,renderBuffer->pts/1000,buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001554 mWaylandPlugin->handleFrameDropped(renderBuffer);
1555}
1556
fei.deng649b0e22024-09-03 18:57:13 +08001557void WaylandDisplay::handleFrameTime(WaylandBuffer *buf,uint32_t sec, uint32_t usec)
1558{
1559 RenderBuffer *renderBuffer = buf->getRenderBuffer();
1560 int64_t frameDisplayTimeUs = int64_t(sec)*1000000LL + usec;
1561 if (mLastDisplayFramePts == -1) {
1562 mLastDisplayFramePts = renderBuffer->pts;
1563 mLastDisplayFrameTimeUs = frameDisplayTimeUs;
1564 } else { //calculate last frame displayed duration
1565 int64_t duration = frameDisplayTimeUs - mLastDisplayFrameTimeUs;
1566 TRACE(mLogCategory,"now pts:%lld us,time:%u us,pre pts:%lld us,dur:%lld us",
1567 renderBuffer->pts/1000,frameDisplayTimeUs,mLastDisplayFramePts/1000,duration);
1568 if (mFrameDurationUs > 0 && duration > FRAME_FREEZE_THRESHOLD(mFrameDurationUs)) {
1569 FrameDisplayInfo frameDisplayInfo = {-1, -1};
1570 frameDisplayInfo.pts = mLastDisplayFramePts;
1571 frameDisplayInfo.duration = duration;
1572 TRACE(mLogCategory,"report freeze frame,pts:%lld us,duration:%lld us",frameDisplayInfo.pts/1000,frameDisplayInfo.duration);
1573 mWaylandPlugin->handleMsgNotify(MSG_FRAME_FREEZE, &frameDisplayInfo);
1574 }
1575 mLastDisplayFramePts = renderBuffer->pts;
1576 mLastDisplayFrameTimeUs = frameDisplayTimeUs;
1577 }
1578}
1579
fei.dengf7a0cd32023-08-29 09:36:37 +00001580
1581void WaylandDisplay::readyToRun()
1582{
1583 mFd = wl_display_get_fd (mWlDisplay);
fei.dengb9a1a572023-09-13 01:33:57 +00001584 if (mPoll) {
1585 mPoll->addFd(mFd);
1586 mPoll->setFdReadable(mFd, true);
1587 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001588}
1589
fei.dengdd910ef2024-06-07 10:25:30 +08001590void WaylandDisplay::readyToExit()
1591{
1592 if (mPoll && mFd >= 0) {
1593 mPoll->removeFd(mFd);
1594 }
1595}
1596
fei.dengf7a0cd32023-08-29 09:36:37 +00001597bool WaylandDisplay::threadLoop()
1598{
1599 int ret;
fei.dengf7a0cd32023-08-29 09:36:37 +00001600
1601 while (wl_display_prepare_read_queue (mWlDisplay, mWlQueue) != 0) {
1602 wl_display_dispatch_queue_pending (mWlDisplay, mWlQueue);
1603 }
1604
1605 wl_display_flush (mWlDisplay);
1606
1607 /*poll timeout value must > 300 ms,otherwise zwp_linux_dmabuf will create failed,
1608 so do use -1 to wait for ever*/
fei.dengb9a1a572023-09-13 01:33:57 +00001609 ret = mPoll->wait(-1); //wait for ever
fei.dengf7a0cd32023-08-29 09:36:37 +00001610 if (ret < 0) { //poll error
fei.dengb9a1a572023-09-13 01:33:57 +00001611 WARNING(mLogCategory,"poll error");
fei.dengf7a0cd32023-08-29 09:36:37 +00001612 wl_display_cancel_read(mWlDisplay);
1613 return false;
1614 } else if (ret == 0) { //poll time out
1615 return true; //run loop
1616 }
1617
1618 if (wl_display_read_events (mWlDisplay) == -1) {
1619 goto tag_error;
1620 }
1621
1622 wl_display_dispatch_queue_pending (mWlDisplay, mWlQueue);
1623 return true;
1624tag_error:
fei.dengb9a1a572023-09-13 01:33:57 +00001625 ERROR(mLogCategory,"Error communicating with the wayland server");
fei.dengf7a0cd32023-08-29 09:36:37 +00001626 return false;
1627}
1628
1629void WaylandDisplay::videoCenterRect(Rectangle src, Rectangle dst, Rectangle *result, bool scaling)
1630{
1631 //if dst is a small window, we scale video to map window size,don't doing center
fei.dengda0cd9f2024-07-24 09:25:11 +08001632 // if (mRenderRect.w != dst.w && mRenderRect.h != dst.h) {
1633 // result->x = dst.x;
1634 // result->y = dst.y;
1635 // result->w = dst.w;
1636 // result->h = dst.h;
1637 // TRACE(mLogCategory,"small window source is %dx%d dest is %dx%d, result is %d,%d,%d,%d",
1638 // src.w, src.h, dst.w, dst.h, result->x, result->y, result->w, result->h);
1639 // return;
1640 // }
fei.dengf7a0cd32023-08-29 09:36:37 +00001641 if (!scaling) {
1642 result->w = MIN (src.w, dst.w);
1643 result->h = MIN (src.h, dst.h);
1644 result->x = dst.x + (dst.w - result->w) / 2;
1645 result->y = dst.y + (dst.h - result->h) / 2;
1646 } else {
1647 double src_ratio, dst_ratio;
1648
fei.denga4abbd52024-07-11 19:17:50 +08001649 src_ratio = (double) (src.w * mPixelAspectRatio) / src.h;
fei.dengf7a0cd32023-08-29 09:36:37 +00001650 dst_ratio = (double) dst.w / dst.h;
1651
1652 if (src_ratio > dst_ratio) {
1653 result->w = dst.w;
1654 result->h = dst.w / src_ratio;
1655 result->x = dst.x;
1656 result->y = dst.y + (dst.h - result->h) / 2;
1657 } else if (src_ratio < dst_ratio) {
1658 result->w = dst.h * src_ratio;
1659 result->h = dst.h;
1660 result->x = dst.x + (dst.w - result->w) / 2;
1661 result->y = dst.y;
1662 } else {
1663 result->x = dst.x;
1664 result->y = dst.y;
1665 result->w = dst.w;
1666 result->h = dst.h;
1667 }
1668 }
1669
fei.denga4abbd52024-07-11 19:17:50 +08001670 TRACE(mLogCategory,"source is %dx%d dest is %dx%d, result is %d,%d,%d,%d",
1671 src.w, src.h, dst.w, dst.h, result->x, result->y,result->w, result->h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001672}
1673
1674void WaylandDisplay::updateBorders()
1675{
1676 int width,height;
1677
1678 if (mNoBorderUpdate)
1679 return;
1680
1681 if (mViewporter) {
1682 width = height = 1;
1683 mNoBorderUpdate = true;
1684 } else {
1685 width = mRenderRect.w;
1686 height = mRenderRect.h;
1687 }
1688
1689 RenderVideoFormat format = VIDEO_FORMAT_BGRA;
fei.dengb9a1a572023-09-13 01:33:57 +00001690 mAreaShmBuffer = new WaylandShmBuffer(this, mLogCategory);
fei.dengf7a0cd32023-08-29 09:36:37 +00001691 struct wl_buffer *wlbuf = mAreaShmBuffer->constructWlBuffer(width, height, format);
1692 if (wlbuf == NULL) {
1693 delete mAreaShmBuffer;
1694 mAreaShmBuffer = NULL;
1695 }
1696
1697 wl_surface_attach(mAreaSurfaceWrapper, wlbuf, 0, 0);
1698}
1699
1700std::size_t WaylandDisplay::calculateDmaBufferHash(RenderDmaBuffer &dmabuf)
1701{
1702 std::string hashString("");
1703 for (int i = 0; i < dmabuf.planeCnt; i++) {
1704 char hashtmp[1024];
fei.dengda0cd9f2024-07-24 09:25:11 +08001705 snprintf (hashtmp, 1024, "%d%d%d%d%d%d%d",i,dmabuf.width,dmabuf.height,dmabuf.planeCnt,
fei.dengf7a0cd32023-08-29 09:36:37 +00001706 dmabuf.stride[i],dmabuf.offset[i],dmabuf.fd[i]);
1707 std::string tmp(hashtmp);
1708 hashString += tmp;
1709 }
1710
1711 std::size_t hashval = std::hash<std::string>()(hashString);
fei.dengb9a1a572023-09-13 01:33:57 +00001712 //TRACE(mLogCategory,"hashstr:%s,val:%zu",hashString.c_str(),hashval);
fei.dengf7a0cd32023-08-29 09:36:37 +00001713 return hashval;
1714}
1715
1716void WaylandDisplay::addWaylandBuffer(RenderBuffer * buf, WaylandBuffer *waylandbuf)
1717{
fei.deng19b48692024-08-13 14:17:55 +08001718 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001719 if (buf->flag & BUFFER_FLAG_DMA_BUFFER) {
1720 std::size_t hashval = calculateDmaBufferHash(buf->dma);
1721 std::pair<std::size_t, WaylandBuffer *> item(hashval, waylandbuf);
fei.dengb9a1a572023-09-13 01:33:57 +00001722 //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 +00001723 mWaylandBuffersMap.insert(item);
1724 }
fei.dengb9a1a572023-09-13 01:33:57 +00001725 TRACE(mLogCategory,"mWaylandBuffersMap size:%d",mWaylandBuffersMap.size());
fei.dengf7a0cd32023-08-29 09:36:37 +00001726}
1727
1728WaylandBuffer* WaylandDisplay::findWaylandBuffer(RenderBuffer * buf)
1729{
fei.deng19b48692024-08-13 14:17:55 +08001730 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001731 std::size_t hashval = calculateDmaBufferHash(buf->dma);
1732 auto item = mWaylandBuffersMap.find(hashval);
1733 if (item == mWaylandBuffersMap.end()) {
1734 return NULL;
1735 }
1736
1737 return (WaylandBuffer*) item->second;
1738}
1739
1740void WaylandDisplay::cleanAllWaylandBuffer()
1741{
fei.deng19b48692024-08-13 14:17:55 +08001742 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001743 //free all obtain buff
1744 for (auto item = mWaylandBuffersMap.begin(); item != mWaylandBuffersMap.end(); ) {
1745 WaylandBuffer *waylandbuf = (WaylandBuffer*)item->second;
1746 mWaylandBuffersMap.erase(item++);
1747 delete waylandbuf;
1748 }
1749}
1750
fei.dengda0cd9f2024-07-24 09:25:11 +08001751
1752/**
1753 * @brief clean wayland buffers those malloc before resolution changed
1754 *
1755 */
1756void WaylandDisplay::cleanWaylandBufferBeforeResChanged()
1757{
fei.deng19b48692024-08-13 14:17:55 +08001758 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengda0cd9f2024-07-24 09:25:11 +08001759 for (auto item = mWaylandBuffersMap.begin(); item != mWaylandBuffersMap.end(); ) {
1760 WaylandBuffer *wlbuf = (WaylandBuffer*)item->second;
1761 if (wlbuf->isFree()) {
1762 mWaylandBuffersMap.erase(item++);
1763 delete wlbuf;
1764 } else {
1765 item++;
1766 }
1767 }
1768}
1769
fei.dengf7a0cd32023-08-29 09:36:37 +00001770void WaylandDisplay::flushBuffers()
1771{
fei.dengb9a1a572023-09-13 01:33:57 +00001772 INFO(mLogCategory,"flushBuffers");
1773 Tls::Mutex::Autolock _l(mRenderMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001774 for (auto item = mCommittedBufferMap.begin(); item != mCommittedBufferMap.end(); item++) {
1775 WaylandBuffer *waylandbuf = (WaylandBuffer*)item->second;
1776 waylandbuf->forceRedrawing();
1777 handleFrameDisplayedCallback(waylandbuf);
1778 }
1779}
1780
1781void WaylandDisplay::cleanSurface()
1782{
1783 /* clear both video and parent surfaces */
1784 wl_surface_attach (mVideoSurfaceWrapper, NULL, 0, 0);
1785 wl_surface_commit (mVideoSurfaceWrapper);
1786 wl_surface_attach (mAreaSurfaceWrapper, NULL, 0, 0);
1787 wl_surface_commit (mAreaSurfaceWrapper);
fei.deng640c3c92024-04-12 08:31:19 +00001788}
1789
1790void WaylandDisplay::setKeepLastFrame(int keep)
1791{
1792 mKeepLastFrame = keep;
1793 if (mVideoSurfaceWrapper && mAmlConfigAPIList.enableKeepLastFrame) {
1794 INFO(mLogCategory,"keep last frame:%d",keep);
1795 wl_surface_keep_last_frame(mVideoSurfaceWrapper, keep);
fei.deng4029e682024-06-26 17:06:31 +08001796 mToSendKeepLastFrame = false;
1797 return;
fei.deng640c3c92024-04-12 08:31:19 +00001798 }
fei.deng4029e682024-06-26 17:06:31 +08001799 mToSendKeepLastFrame = true;
fei.deng6c425232024-07-19 16:15:31 +08001800}
1801
le.hane8c8fdd2024-09-19 09:28:50 +00001802void WaylandDisplay::setKeepLastFrameOnFlush(int keepOnFlush)
1803{
1804 mKeepFrameOnFlush = keepOnFlush;
1805 INFO(mLogCategory,"keep last frame:%d",mKeepFrameOnFlush);
1806 if (mVideoSurfaceWrapper && !mKeepFrameOnFlush) {
1807 INFO(mLogCategory,"mute video plane");
1808 wl_surface_set_video_plane_mute(mVideoSurfaceWrapper, 1);
1809 }
1810}
1811
le.han15dacdd2024-09-18 05:46:09 +00001812void WaylandDisplay::setImmediatelyOutput(int enable)
1813{
1814 if (mVideoSurfaceWrapper) {
1815 wl_surface_enable_ll_mode(mVideoSurfaceWrapper, enable);
1816 }
1817 INFO(mLogCategory,"set immediately output:%d", enable);
1818}
1819
fei.deng6c425232024-07-19 16:15:31 +08001820void WaylandDisplay::setFrameRate(int frameRateNum, int frameRateDenom)
1821{
1822 mFrameRateFractionNum = frameRateNum;
1823 mFrameRateFractionDenom = frameRateDenom;
1824 if (mFrameRateFractionDenom == 0) {
1825 mFrameRateFractionDenom = 1;
1826 }
fei.deng649b0e22024-09-03 18:57:13 +08001827
1828 if (mFrameRateFractionNum > 0) {
1829 mFrameDurationUs = 1000000 * mFrameRateFractionDenom/mFrameRateFractionNum;
1830 mFrameRateChanged = true;
fei.deng6c425232024-07-19 16:15:31 +08001831 }
fei.deng649b0e22024-09-03 18:57:13 +08001832
1833 INFO(mLogCategory,"num:%d,denom:%d,frame dur:%lld us",
1834 mFrameRateFractionNum, mFrameRateFractionDenom,mFrameDurationUs);
fei.deng1c94a342024-08-05 19:33:28 +08001835}
1836
1837void WaylandDisplay::setVideoPlaneZorder(int zorder)
1838{
1839 mVideoPlaneZorder = zorder;
1840 mVideoPlaneZorderChanged = true;
1841 if (mVideoSurfaceWrapper) {
1842 mVideoPlaneZorderChanged = false;
1843 wl_surface_set_zorder(mVideoSurfaceWrapper, mVideoPlaneZorder);
1844 }
fei.deng649b0e22024-09-03 18:57:13 +08001845}
1846
1847void WaylandDisplay::pause()
1848{
1849 mLastDisplayFramePts = -1;
1850 mLastDisplayFrameTimeUs = -1;
1851}
1852void WaylandDisplay::resume()
1853{
1854
fei.dengf7a0cd32023-08-29 09:36:37 +00001855}