blob: f776b80f599c5b0ff6c9a1cfaddb94ab52ddb36c [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.deng96aa7f72024-09-29 15:46:52 +0800521 self->mCompositor = (struct wl_compositor *)wl_registry_bind (registry, name, &wl_compositor_interface, version);
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.deng96aa7f72024-09-29 15:46:52 +0800678 mVideoRotateDegree = -1;
fei.dengf7a0cd32023-08-29 09:36:37 +0000679}
680
681WaylandDisplay::~WaylandDisplay()
682{
fei.dengb9a1a572023-09-13 01:33:57 +0000683 TRACE(mLogCategory,"desconstruct WaylandDisplay");
684 if (mPoll) {
685 delete mPoll;
686 mPoll = NULL;
687 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000688}
689
690char *WaylandDisplay::require_xdg_runtime_dir()
691{
692 char *val = getenv("XDG_RUNTIME_DIR");
fei.dengb9a1a572023-09-13 01:33:57 +0000693 INFO(mLogCategory,"XDG_RUNTIME_DIR=%s",val);
fei.dengdd910ef2024-06-07 10:25:30 +0800694 //if not set XDG_RUNTIME_DIR,set default value
695 // if (!val) {
696 // val = const_cast<char *>("/run/user/0");
697 // setenv("XDG_RUNTIME_DIR",val,0);
698 // WARNING(mLogCategory,"XDG_RUNTIME_DIR is not set,set default %s",val);
699 // }
fei.dengf7a0cd32023-08-29 09:36:37 +0000700
701 return val;
702}
703
704int WaylandDisplay::openDisplay()
705{
fei.deng649b0e22024-09-03 18:57:13 +0800706 mLastDisplayFramePts = -1;
707 mLastDisplayFrameTimeUs = -1;
708 mFrameDurationUs = 0;
709 mPreFramePts = -1;
710 mFrameRateDetectCnt = 0;
711 mFrameRateDetectPeriod = 0;
fei.denga4abbd52024-07-11 19:17:50 +0800712 mPixelAspectRatio = 1.0;
713 mUpdateVideoSurface = false;
fei.dengdd910ef2024-06-07 10:25:30 +0800714 mNoBorderUpdate = false;
715 mReCommitAreaSurface = false;
716 mXdgSurfaceConfigured = false;
717 mUpdateRenderRectangle = false;
fei.deng6c425232024-07-19 16:15:31 +0800718 mFrameRateFractionNum = 0;
719 mFrameRateFractionDenom = 1;
720 mFrameRateChanged = false;
fei.deng1c94a342024-08-05 19:33:28 +0800721 mVideoPlaneZorder = -1;
722 mVideoPlaneZorderChanged = false;
fei.dengdd910ef2024-06-07 10:25:30 +0800723 memset(&mRenderRect, 0, sizeof(struct Rectangle));
724 memset(&mVideoRect, 0, sizeof(struct Rectangle));
725 memset(&mWindowRect, 0, sizeof(struct Rectangle));
726 mFullScreen = true; //default is full screen
727 mAmlConfig = NULL;
728 //weston config private api
729 mAmlConfigAPIList.enableDropFrame = false;
730 mAmlConfigAPIList.enableKeepLastFrame = false;
731 mAmlConfigAPIList.enableSetPts = false;
732 mAmlConfigAPIList.enableSetVideoPlane = false;
fei.dengd0da4e22024-07-04 11:29:13 +0800733 mAmlConfigAPIList.enableSurfaceDestroyCallback = false;
fei.deng6c425232024-07-19 16:15:31 +0800734 mAmlConfigAPIList.enableSetDisplayRate = false;
fei.deng9bf724e2024-08-01 11:34:52 +0800735 mAmlConfigAPIList.enableSetSurfaceInvisible = false;
fei.deng649b0e22024-09-03 18:57:13 +0800736 mAmlConfigAPIList.enableDisplayTime = false;
fei.dengdd910ef2024-06-07 10:25:30 +0800737 mCurrentDisplayOutput = &mOutput[0];
738 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
739 mOutput[i].wlOutput = NULL;
740 mOutput[i].offsetX = 0;
741 mOutput[i].offsetY = 0;
742 mOutput[i].width = 0;
743 mOutput[i].height = 0;
744 mOutput[i].refreshRate = 0;
745 mOutput[i].isPrimary = false;
746 mOutput[i].name = 0;
747 mOutput[i].crtcIndex = 0;
748 }
fei.deng4029e682024-06-26 17:06:31 +0800749 /*if mKeepLastFrame had set but mToSendKeepLastFrame is false,maybe
750 playback is doing FF/FW action,so we keep set it on new connection*/
751 if (!mToSendKeepLastFrame && mKeepLastFrame) {
752 mToSendKeepLastFrame = true;
753 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000754 char *name = require_xdg_runtime_dir();
755 //DEBUG(mLogCategory,"name:%s",name);
fei.dengb9a1a572023-09-13 01:33:57 +0000756 DEBUG(mLogCategory,"openDisplay in");
fei.dengf7a0cd32023-08-29 09:36:37 +0000757 mWlDisplay = wl_display_connect(NULL);
758 if (!mWlDisplay) {
fei.dengb9a1a572023-09-13 01:33:57 +0000759 ERROR(mLogCategory,"Failed to connect to the wayland display, XDG_RUNTIME_DIR='%s'",
fei.dengf7a0cd32023-08-29 09:36:37 +0000760 name ? name : "NULL");
fei.dengb9a1a572023-09-13 01:33:57 +0000761 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000762 }
763
764 mWlDisplayWrapper = (struct wl_display *)wl_proxy_create_wrapper ((void *)mWlDisplay);
765 mWlQueue = wl_display_create_queue (mWlDisplay);
766 wl_proxy_set_queue ((struct wl_proxy *)mWlDisplayWrapper, mWlQueue);
767
768 mRegistry = wl_display_get_registry (mWlDisplayWrapper);
769 wl_registry_add_listener (mRegistry, &registry_listener, (void *)this);
770
771 /* we need exactly 2 roundtrips to discover global objects and their state */
772 for (int i = 0; i < 2; i++) {
773 if (wl_display_roundtrip_queue (mWlDisplay, mWlQueue) < 0) {
fei.dengb9a1a572023-09-13 01:33:57 +0000774 ERROR(mLogCategory,"Error communicating with the wayland display");
775 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000776 }
777 }
778
779 if (!mCompositor) {
fei.dengb9a1a572023-09-13 01:33:57 +0000780 ERROR(mLogCategory,"Could not bind to wl_compositor. Either it is not implemented in " \
fei.dengf7a0cd32023-08-29 09:36:37 +0000781 "the compositor, or the implemented version doesn't match");
fei.dengb9a1a572023-09-13 01:33:57 +0000782 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000783 }
784
785 if (!mDmabuf) {
fei.dengb9a1a572023-09-13 01:33:57 +0000786 ERROR(mLogCategory,"Could not bind to zwp_linux_dmabuf_v1");
787 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000788 }
789
790 if (!mXdgWmBase) {
791 /* If wl_surface and wl_display are passed via GstContext
792 * wl_shell, xdg_shell and zwp_fullscreen_shell are not used.
793 * In this case is correct to continue.
794 */
fei.dengb9a1a572023-09-13 01:33:57 +0000795 ERROR(mLogCategory,"Could not bind to either wl_shell, xdg_wm_base or "
fei.dengf7a0cd32023-08-29 09:36:37 +0000796 "zwp_fullscreen_shell, video display may not work properly.");
fei.dengb9a1a572023-09-13 01:33:57 +0000797 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000798 }
799
800 //create window surface
801 createCommonWindowSurface();
802 createXdgShellWindowSurface();
803
804 //config weston video plane
fei.deng640c3c92024-04-12 08:31:19 +0000805 if (mAmlConfigAPIList.enableSetVideoPlane) {
fei.dengb9a1a572023-09-13 01:33:57 +0000806 INFO(mLogCategory,"set weston video plane:%d",mPip);
fei.dengf7a0cd32023-08-29 09:36:37 +0000807 wl_surface_set_video_plane(mVideoSurfaceWrapper, mPip);
808 }
809
810 //run wl display queue dispatch
fei.dengb9a1a572023-09-13 01:33:57 +0000811 DEBUG(mLogCategory,"To run wl display dispatch queue");
fei.dengdd910ef2024-06-07 10:25:30 +0800812 if (mPoll) {
813 mPoll->setFlushing(false);
814 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000815 run("display queue");
816 mRedrawingPending = false;
le.hane8c8fdd2024-09-19 09:28:50 +0000817 wl_surface_set_video_plane_mute(mVideoSurfaceWrapper, 0);
fei.dengf7a0cd32023-08-29 09:36:37 +0000818
fei.dengb9a1a572023-09-13 01:33:57 +0000819 DEBUG(mLogCategory,"openDisplay out");
820 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000821}
822
823void WaylandDisplay::closeDisplay()
824{
fei.dengb9a1a572023-09-13 01:33:57 +0000825 DEBUG(mLogCategory,"closeDisplay in");
fei.dengf7a0cd32023-08-29 09:36:37 +0000826
fei.dengd0da4e22024-07-04 11:29:13 +0800827 //first destroy window surface
828 destroyWindowSurfaces();
fei.dengf7a0cd32023-08-29 09:36:37 +0000829
fei.deng4029e682024-06-26 17:06:31 +0800830 //flush pending event to weston
fei.dengdd910ef2024-06-07 10:25:30 +0800831 if (mWlDisplay) {
832 wl_display_flush (mWlDisplay);
833 }
834
fei.dengd0da4e22024-07-04 11:29:13 +0800835 //wait video surface destroyed or 50ms timeout
836 if (mAmlConfigAPIList.enableSurfaceDestroyCallback) {
837 INFO(mLogCategory,"waiting surface_destroy_cb from weston");
838 Tls::Mutex::Autolock _l(mMutex);
839 if (ERROR_TIMED_OUT == mCondition.waitRelative(mMutex, 50/*microsecond*/)) {
840 WARNING(mLogCategory,"waited surface_destroy_cb timeout");
841 }
842 }
843
844 //we should receive all event from weston before stopped dispatch queue
845 if (isRunning()) {
846 TRACE(mLogCategory,"try stop dispatch thread");
847 if (mPoll) {
848 mPoll->setFlushing(true);
849 }
850 requestExitAndWait();
851 }
852 //after destroyed surface,then destroy buffers,otherwise maybe crash
853 if (mAreaShmBuffer) {
854 delete mAreaShmBuffer;
855 mAreaShmBuffer = NULL;
856 }
857
858 //clean all wayland buffers
859 cleanAllWaylandBuffer();
fei.dengf7a0cd32023-08-29 09:36:37 +0000860
861 if (mViewporter) {
862 wp_viewporter_destroy (mViewporter);
863 mViewporter = NULL;
864 }
865
866 if (mDmabuf) {
867 zwp_linux_dmabuf_v1_destroy (mDmabuf);
868 mDmabuf = NULL;
869 }
870
871 if (mXdgWmBase) {
872 xdg_wm_base_destroy (mXdgWmBase);
873 mXdgWmBase = NULL;
874 }
875
876 if (mCompositor) {
877 wl_compositor_destroy (mCompositor);
878 mCompositor = NULL;
879 }
880
881 if (mSubCompositor) {
882 wl_subcompositor_destroy (mSubCompositor);
883 mSubCompositor = NULL;
884 }
885
886 if (mRegistry) {
887 wl_registry_destroy (mRegistry);
888 mRegistry= NULL;
889 }
890
891 if (mWlDisplayWrapper) {
892 wl_proxy_wrapper_destroy (mWlDisplayWrapper);
893 mWlDisplayWrapper = NULL;
894 }
895
fei.deng640c3c92024-04-12 08:31:19 +0000896 if (mAmlConfig) {
897 aml_config_destroy(mAmlConfig);
898 mAmlConfig = NULL;
899 }
900
fei.dengf7a0cd32023-08-29 09:36:37 +0000901 if (mWlQueue) {
902 wl_event_queue_destroy (mWlQueue);
903 mWlQueue = NULL;
904 }
905
906 if (mWlDisplay) {
907 wl_display_flush (mWlDisplay);
908 wl_display_disconnect (mWlDisplay);
909 mWlDisplay = NULL;
910 }
911
fei.dengb9a1a572023-09-13 01:33:57 +0000912 DEBUG(mLogCategory,"closeDisplay out");
fei.dengf7a0cd32023-08-29 09:36:37 +0000913}
914
915int WaylandDisplay::toDmaBufferFormat(RenderVideoFormat format, uint32_t *outDmaformat /*out param*/, uint64_t *outDmaformatModifiers /*out param*/)
916{
917 if (!outDmaformat || !outDmaformatModifiers) {
fei.dengb9a1a572023-09-13 01:33:57 +0000918 WARNING(mLogCategory,"NULL params");
919 return ERROR_PARAM_NULL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000920 }
921
922 *outDmaformat = 0;
923 *outDmaformatModifiers = 0;
924
925 uint32_t dmaformat = video_format_to_wl_dmabuf_format (format);
926 if (dmaformat == -1) {
fei.dengb9a1a572023-09-13 01:33:57 +0000927 ERROR(mLogCategory,"Error not found render video format:%d to wl dmabuf format",format);
928 return ERROR_NOT_FOUND;
fei.dengf7a0cd32023-08-29 09:36:37 +0000929 }
930
fei.dengb9a1a572023-09-13 01:33:57 +0000931 TRACE(mLogCategory,"render video format:%d -> dmabuf format:%d",format,dmaformat);
fei.dengf7a0cd32023-08-29 09:36:37 +0000932 *outDmaformat = (uint32_t)dmaformat;
933
934 /*get dmaformat and modifiers*/
935 auto item = mDmaBufferFormats.find(dmaformat);
936 if (item == mDmaBufferFormats.end()) { //not found
fei.dengb9a1a572023-09-13 01:33:57 +0000937 WARNING(mLogCategory,"Not found dmabuf for render video format :%d",format);
fei.dengf7a0cd32023-08-29 09:36:37 +0000938 *outDmaformatModifiers = 0;
fei.dengb9a1a572023-09-13 01:33:57 +0000939 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000940 }
941
942 *outDmaformatModifiers = (uint64_t)item->second;
943
fei.dengb9a1a572023-09-13 01:33:57 +0000944 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000945}
946
947int WaylandDisplay::toShmBufferFormat(RenderVideoFormat format, uint32_t *outformat)
948{
949 if (!outformat) {
fei.dengb9a1a572023-09-13 01:33:57 +0000950 WARNING(mLogCategory,"NULL params");
951 return ERROR_PARAM_NULL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000952 }
953
954 *outformat = 0;
955
956 int shmformat = (int)video_format_to_wl_shm_format(format);
957 if (shmformat < 0) {
fei.dengb9a1a572023-09-13 01:33:57 +0000958 ERROR(mLogCategory,"Error not found render video format:%d to wl shmbuf format",format);
959 return ERROR_NOT_FOUND;
fei.dengf7a0cd32023-08-29 09:36:37 +0000960 }
961
962 for (auto item = mShmFormats.begin(); item != mShmFormats.end(); ++item) {
963 uint32_t registFormat = (uint32_t)*item;
964 if (registFormat == (uint32_t)shmformat) {
965 *outformat = registFormat;
fei.dengb9a1a572023-09-13 01:33:57 +0000966 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000967 }
968 }
969
fei.dengb9a1a572023-09-13 01:33:57 +0000970 return ERROR_NOT_FOUND;
fei.dengf7a0cd32023-08-29 09:36:37 +0000971}
972
973void WaylandDisplay::setVideoBufferFormat(RenderVideoFormat format)
974{
fei.dengb9a1a572023-09-13 01:33:57 +0000975 TRACE(mLogCategory,"set video buffer format: %d",format);
fei.dengf7a0cd32023-08-29 09:36:37 +0000976 mBufferFormat = format;
977};
978
979void WaylandDisplay::setDisplayOutput(int output)
980{
fei.dengb9a1a572023-09-13 01:33:57 +0000981 TRACE(mLogCategory,"select display output: %d",output);
fei.dengf7a0cd32023-08-29 09:36:37 +0000982 if (output < 0 || output >= DEFAULT_DISPLAY_OUTPUT_NUM) {
fei.dengb9a1a572023-09-13 01:33:57 +0000983 ERROR(mLogCategory, "display output index error,please set 0:primary or 1:extend,now:%d",output);
fei.dengf7a0cd32023-08-29 09:36:37 +0000984 return;
985 }
fei.deng26950832023-11-09 03:00:23 +0000986 //only do select output before video playing
987 if (mSelectOutputIndex != output) {
988 mSelectOutputIndex = output;
989 // if (mOutput[output].wlOutput) {
990 // mCurrentDisplayOutput = &mOutput[output];
991 // setRenderRectangle(mOutput[output].offsetX, mOutput[output].offsetY,
992 // mOutput[output].width, mOutput[output].height);
993 // }
fei.dengf7a0cd32023-08-29 09:36:37 +0000994 }
995}
996
997int WaylandDisplay::getDisplayOutput()
998{
fei.deng26950832023-11-09 03:00:23 +0000999 return mSelectOutputIndex == INVALID_OUTPUT_INDEX? 0: mSelectOutputIndex;
fei.dengf7a0cd32023-08-29 09:36:37 +00001000}
1001
1002void WaylandDisplay::setPip(int pip)
1003{
fei.dengb9a1a572023-09-13 01:33:57 +00001004 INFO(mLogCategory,"set pip:%d",pip);
fei.dengf7a0cd32023-08-29 09:36:37 +00001005 mPip = pip;
1006}
1007
fei.deng26950832023-11-09 03:00:23 +00001008void WaylandDisplay::updateDisplayOutput()
1009{
1010 if (!mCurrentDisplayOutput->wlOutput || !mXdgToplevel || !mXdgSurface)
1011 {
1012 return;
1013 }
1014 if (mUpdateRenderRectangle) {
1015 if (mFullScreen) {
1016 DEBUG(mLogCategory,"unset full screen");
1017 xdg_toplevel_unset_fullscreen (mXdgToplevel);
1018 }
1019
1020 if (mXdgSurface) {
1021 DEBUG(mLogCategory,"set geometry");
1022 xdg_surface_set_window_geometry(mXdgSurface,
1023 mCurrentDisplayOutput->offsetX,
1024 mCurrentDisplayOutput->offsetY,
1025 mCurrentDisplayOutput->width,
1026 mCurrentDisplayOutput->height);
1027 }
1028
1029 if (mFullScreen && mXdgToplevel) {
1030 DEBUG(mLogCategory,"set full screen");
1031 xdg_toplevel_set_fullscreen (mXdgToplevel, mCurrentDisplayOutput->wlOutput);
1032 }
1033 setRenderRectangle(mCurrentDisplayOutput->offsetX, mCurrentDisplayOutput->offsetY,
1034 mCurrentDisplayOutput->width, mCurrentDisplayOutput->height);
1035 mUpdateRenderRectangle = false;
1036 }
1037}
1038
fei.dengf7a0cd32023-08-29 09:36:37 +00001039void WaylandDisplay::createCommonWindowSurface()
1040{
1041 struct wl_region *region;
1042
1043 mAreaSurface = wl_compositor_create_surface (mCompositor);
1044 mVideoSurface = wl_compositor_create_surface (mCompositor);
1045 mAreaSurfaceWrapper = (struct wl_surface *)wl_proxy_create_wrapper (mAreaSurface);
1046 mVideoSurfaceWrapper = (struct wl_surface *)wl_proxy_create_wrapper (mVideoSurface);
1047
1048 wl_proxy_set_queue ((struct wl_proxy *) mAreaSurfaceWrapper, mWlQueue);
1049 wl_proxy_set_queue ((struct wl_proxy *) mVideoSurfaceWrapper, mWlQueue);
1050
1051 /* embed video_surface in area_surface */
1052 mVideoSubSurface = wl_subcompositor_get_subsurface (mSubCompositor, mVideoSurface, mAreaSurface);
1053 wl_subsurface_set_desync (mVideoSubSurface);
1054
fei.dengd0da4e22024-07-04 11:29:13 +08001055 //add video surface callback to weston if weston enable this feature
1056 if (mVideoSurface && mAmlConfigAPIList.enableSurfaceDestroyCallback) {
1057 struct wl_callback *surfaceDestroyCb = wl_surface_destroy_callback(mVideoSurface);
1058 wl_callback_add_listener(surfaceDestroyCb, &surface_destroy_listener, this);
1059 }
1060
fei.dengf7a0cd32023-08-29 09:36:37 +00001061 if (mViewporter) {
1062 mAreaViewport = wp_viewporter_get_viewport (mViewporter, mAreaSurface);
1063 mVideoViewport = wp_viewporter_get_viewport (mViewporter, mVideoSurface);
1064 }
1065
fei.deng9bf724e2024-08-01 11:34:52 +08001066 /*set area surface to invisible. prevent frame droped at start playback,
1067 wl_surface_set_invisible must called before mAreaSurface commit called*/
1068 if (mAmlConfigAPIList.enableSetSurfaceInvisible) {
1069 int invisible = 1;
1070 INFO(mLogCategory,"set surface invisible:%d",invisible);
1071 wl_surface_set_invisible(mAreaSurfaceWrapper, invisible);
1072 }
1073
fei.deng649b0e22024-09-03 18:57:13 +08001074 if (mAmlConfigAPIList.enableDisplayTime) {
1075 INFO(mLogCategory,"set enable display time");
1076 wl_surface_enable_display_time(mVideoSurface, 1);
1077 }
1078
fei.dengf7a0cd32023-08-29 09:36:37 +00001079 /* do not accept input */
1080 region = wl_compositor_create_region (mCompositor);
1081 wl_surface_set_input_region (mAreaSurface, region);
1082 wl_region_destroy (region);
1083
1084 region = wl_compositor_create_region (mCompositor);
1085 wl_surface_set_input_region (mVideoSurface, region);
1086 wl_region_destroy (region);
1087}
1088
1089void WaylandDisplay::createXdgShellWindowSurface()
1090{
1091 /* Check which protocol we will use (in order of preference) */
1092 if (mXdgWmBase) {
1093 /* First create the XDG surface */
1094 mXdgSurface= xdg_wm_base_get_xdg_surface (mXdgWmBase, mAreaSurface);
1095 if (!mXdgSurface) {
fei.dengb9a1a572023-09-13 01:33:57 +00001096 ERROR(mLogCategory,"Unable to get xdg_surface");
fei.dengf7a0cd32023-08-29 09:36:37 +00001097 return;
1098 }
1099 xdg_surface_add_listener (mXdgSurface, &xdg_surface_listener,(void *)this);
1100
1101 /* Then the toplevel */
1102 mXdgToplevel= xdg_surface_get_toplevel (mXdgSurface);
1103 if (!mXdgSurface) {
fei.dengb9a1a572023-09-13 01:33:57 +00001104 ERROR(mLogCategory,"Unable to get xdg_toplevel");
fei.dengf7a0cd32023-08-29 09:36:37 +00001105 return;
1106 }
1107 xdg_toplevel_add_listener (mXdgToplevel, &xdg_toplevel_listener, this);
1108
1109 /* Finally, commit the xdg_surface state as toplevel */
1110 mXdgSurfaceConfigured = false;
1111 wl_surface_commit (mAreaSurface);
1112 wl_display_flush (mWlDisplay);
1113 /* we need exactly 3 roundtrips to discover global objects and their state */
1114 for (int i = 0; i < 3; i++) {
1115 if (wl_display_roundtrip_queue(mWlDisplay, mWlQueue) < 0) {
fei.dengb9a1a572023-09-13 01:33:57 +00001116 ERROR(mLogCategory,"Error communicating with the wayland display");
fei.dengf7a0cd32023-08-29 09:36:37 +00001117 }
1118 }
1119
1120 if (mXdgSurfaceConfigured) {
fei.dengb9a1a572023-09-13 01:33:57 +00001121 INFO(mLogCategory,"xdg surface had configured");
fei.dengf7a0cd32023-08-29 09:36:37 +00001122 } else {
fei.dengb9a1a572023-09-13 01:33:57 +00001123 WARNING(mLogCategory,"xdg surface not configured");
fei.dengf7a0cd32023-08-29 09:36:37 +00001124 }
1125
1126 //full screen show
fei.deng26950832023-11-09 03:00:23 +00001127 // if (mFullScreen && mCurrentDisplayOutput->wlOutput) {
1128 // //ensureFullscreen(mFullScreen);
fei.dengf7a0cd32023-08-29 09:36:37 +00001129 // }
1130 } else {
fei.dengb9a1a572023-09-13 01:33:57 +00001131 ERROR(mLogCategory,"Unable to use xdg_wm_base ");
fei.dengf7a0cd32023-08-29 09:36:37 +00001132 return;
1133 }
1134}
1135
1136void WaylandDisplay::destroyWindowSurfaces()
1137{
fei.dengf7a0cd32023-08-29 09:36:37 +00001138 if (mXdgToplevel) {
1139 xdg_toplevel_destroy (mXdgToplevel);
1140 mXdgToplevel = NULL;
1141 }
1142
1143 if (mXdgSurface) {
1144 xdg_surface_destroy (mXdgSurface);
1145 mXdgSurface = NULL;
1146 }
1147
1148 if (mVideoSurfaceWrapper) {
1149 wl_proxy_wrapper_destroy (mVideoSurfaceWrapper);
1150 mVideoSurfaceWrapper = NULL;
1151 }
1152
1153 if (mVideoSubSurface) {
1154 wl_subsurface_destroy (mVideoSubSurface);
1155 mVideoSubSurface = NULL;
1156 }
1157
1158 if (mVideoSurface) {
1159 wl_surface_destroy (mVideoSurface);
1160 mVideoSurface = NULL;
1161 }
1162
1163 if (mAreaSurfaceWrapper) {
1164 wl_proxy_wrapper_destroy (mAreaSurfaceWrapper);
1165 mAreaSurfaceWrapper = NULL;
1166 }
1167
1168 if (mAreaSurface) {
1169 wl_surface_destroy (mAreaSurface);
1170 mAreaSurface = NULL;
1171 mReCommitAreaSurface = false;
1172 }
1173}
1174
1175void WaylandDisplay::ensureFullscreen(bool fullscreen)
1176{
1177 if (mXdgWmBase) {
fei.dengb9a1a572023-09-13 01:33:57 +00001178 DEBUG(mLogCategory,"full screen : %d",fullscreen);
fei.dengf7a0cd32023-08-29 09:36:37 +00001179 if (fullscreen) {
fei.deng26950832023-11-09 03:00:23 +00001180 xdg_toplevel_set_fullscreen (mXdgToplevel, mCurrentDisplayOutput->wlOutput);
fei.dengf7a0cd32023-08-29 09:36:37 +00001181 } else {
1182 xdg_toplevel_unset_fullscreen (mXdgToplevel);
1183 }
1184 }
1185}
1186
1187void WaylandDisplay::setRenderRectangle(int x, int y, int w, int h)
1188{
fei.dengb9a1a572023-09-13 01:33:57 +00001189 DEBUG(mLogCategory,"set render rect:x:%d,y:%d,w:%d,h:%d",x,y,w,h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001190
1191 if (w <= 0 || h <= 0) {
fei.dengb9a1a572023-09-13 01:33:57 +00001192 WARNING(mLogCategory, "wrong render width or height %dx%d",w,h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001193 return;
1194 }
1195
1196 mRenderRect.x = x;
1197 mRenderRect.y = y;
1198 mRenderRect.w = w;
1199 mRenderRect.h = h;
1200
1201 if (!mXdgSurfaceConfigured) {
fei.dengb9a1a572023-09-13 01:33:57 +00001202 WARNING(mLogCategory,"Not configured xdg");
fei.dengf7a0cd32023-08-29 09:36:37 +00001203 return;
1204 }
1205
1206 if (mAreaViewport) {
1207 wp_viewport_set_destination (mAreaViewport, w, h);
1208 }
1209
1210 updateBorders();
1211
1212 if (mVideoWidth != 0 && mVideoSurface) {
1213 wl_subsurface_set_sync (mVideoSubSurface);
1214 resizeVideoSurface(true);
1215 }
1216
1217 wl_surface_damage (mAreaSurfaceWrapper, 0, 0, w, h);
1218 wl_surface_commit (mAreaSurfaceWrapper);
1219
1220 if (mVideoWidth != 0) {
1221 wl_subsurface_set_desync (mVideoSubSurface);
1222 }
1223}
1224
fei.dengf7a0cd32023-08-29 09:36:37 +00001225void WaylandDisplay::setFrameSize(int w, int h)
1226{
1227 mVideoWidth = w;
1228 mVideoHeight = h;
fei.denga4abbd52024-07-11 19:17:50 +08001229 mUpdateVideoSurface = true;
fei.dengb9a1a572023-09-13 01:33:57 +00001230 TRACE(mLogCategory,"frame w:%d,h:%d",mVideoWidth,mVideoHeight);
fei.dengf7a0cd32023-08-29 09:36:37 +00001231}
1232
1233void WaylandDisplay::setWindowSize(int x, int y, int w, int h)
1234{
1235 mWindowRect.x = x;
1236 mWindowRect.y = y;
1237 mWindowRect.w = w;
1238 mWindowRect.h = h;
fei.denga4abbd52024-07-11 19:17:50 +08001239 mUpdateVideoSurface = true;
fei.dengb9a1a572023-09-13 01:33:57 +00001240 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 +00001241}
1242
fei.denga4abbd52024-07-11 19:17:50 +08001243void WaylandDisplay::setPixelAspectRatio(double ratio)
1244{
1245 mPixelAspectRatio = ratio;
1246 mUpdateVideoSurface = true;
1247}
fei.dengf7a0cd32023-08-29 09:36:37 +00001248
1249void WaylandDisplay::resizeVideoSurface(bool commit)
1250{
1251 Rectangle src = {0,};
1252 Rectangle dst = {0,};
1253 Rectangle res;
1254
1255 /* center the video_subsurface inside area_subsurface */
1256 src.w = mVideoWidth;
1257 src.h = mVideoHeight;
1258 /*if had set the window size, we will scall
1259 video surface to this window size*/
1260 if (mWindowRect.w > 0 && mWindowRect.h > 0) {
1261 dst.x = mWindowRect.x;
1262 dst.y = mWindowRect.y;
1263 dst.w = mWindowRect.w;
1264 dst.h = mWindowRect.h;
1265 if (mWindowRect.w > mRenderRect.w && mWindowRect.h > mRenderRect.h) {
fei.dengb9a1a572023-09-13 01:33:57 +00001266 WARNING(mLogCategory,"Error window size:%dx%d, but render size:%dx%d,reset to render size",
fei.dengf7a0cd32023-08-29 09:36:37 +00001267 mWindowRect.w,mWindowRect.h,mRenderRect.w,mRenderRect.h);
1268 dst.x = mRenderRect.x;
1269 dst.y = mRenderRect.y;
1270 dst.w = mRenderRect.w;
1271 dst.h = mRenderRect.h;
1272 }
1273 //to do,we need set geometry?
1274 //if (mXdgSurface) {
1275 // xdg_surface_set_window_geometry(mXdgSurface, mWindowRect.x, mWindowRect.y, mWindowRect.w, mWindowRect.h);
1276 //}
1277 } else { //scal video to full screen
1278 dst.w = mRenderRect.w;
1279 dst.h = mRenderRect.h;
1280 }
1281
1282 if (mViewporter) {
1283 videoCenterRect(src, dst, &res, true);
1284 } else {
1285 videoCenterRect(src, dst, &res, false);
1286 }
1287
1288 wl_subsurface_set_position (mVideoSubSurface, res.x, res.y);
1289
1290 if (commit) {
1291 wl_surface_damage (mVideoSurfaceWrapper, 0, 0, res.w, res.h);
1292 wl_surface_commit (mVideoSurfaceWrapper);
1293 }
1294
1295 //top level setting
1296 if (mXdgToplevel) {
1297 struct wl_region *region;
1298
1299 region = wl_compositor_create_region (mCompositor);
1300 wl_region_add (region, 0, 0, mRenderRect.w, mRenderRect.h);
1301 wl_surface_set_input_region (mAreaSurface, region);
1302 wl_region_destroy (region);
1303 }
1304
1305 /* this is saved for use in wl_surface_damage */
1306 mVideoRect.x = res.x;
1307 mVideoRect.y = res.y;
1308 mVideoRect.w = res.w;
1309 mVideoRect.h = res.h;
1310
fei.denga4abbd52024-07-11 19:17:50 +08001311 //to scale video surface
fei.dengf7a0cd32023-08-29 09:36:37 +00001312 wp_viewport_set_destination(mVideoViewport, res.w, res.h);
fei.denga4abbd52024-07-11 19:17:50 +08001313 wl_display_flush (mWlDisplay);
fei.dengb9a1a572023-09-13 01:33:57 +00001314 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 +00001315}
1316
1317void WaylandDisplay::setOpaque()
1318{
1319 struct wl_region *region;
1320
1321 /* Set area opaque */
1322 region = wl_compositor_create_region (mCompositor);
1323 wl_region_add (region, 0, 0, mRenderRect.w, mRenderRect.h);
1324 wl_surface_set_opaque_region (mAreaSurface, region);
1325 wl_region_destroy (region);
1326}
1327
1328int WaylandDisplay::prepareFrameBuffer(RenderBuffer * buf)
1329{
1330 WaylandBuffer *waylandBuf = NULL;
1331 int ret;
fei.dengda0cd9f2024-07-24 09:25:11 +08001332 bool isNew = false;
fei.dengf7a0cd32023-08-29 09:36:37 +00001333
fei.deng649b0e22024-09-03 18:57:13 +08001334 //detect frame rate and frame duration
1335 if (mFrameRateFractionNum == 0) {
1336 if (mPreFramePts == -1) {
1337 mPreFramePts = buf->pts; //ns
1338 } else {
1339 if (mFrameRateDetectCnt < DETECT_FRAMERATE_CNT) {
1340 mFrameRateDetectPeriod += (buf->pts - mPreFramePts);
1341 ++mFrameRateDetectCnt;
1342 }
1343 if (mFrameRateDetectCnt == DETECT_FRAMERATE_CNT) {
1344 int64_t mFrameDurationUs = (mFrameRateDetectPeriod/mFrameRateDetectCnt)/1000;
1345 double rate = 1000000.0/mFrameDurationUs;
1346 mFrameRateFractionNum = rate * 100;
1347 mFrameRateFractionDenom = 100;
1348 mFrameRateChanged = true;
1349 INFO(mLogCategory,"detect frame num:%d,denom:%d,dur:%lld us",
1350 mFrameRateFractionNum,mFrameRateFractionDenom,mFrameDurationUs);
1351 }
1352 }
1353 }
1354 mPreFramePts = buf->pts;
1355
fei.dengdd910ef2024-06-07 10:25:30 +08001356 if (!mDmabuf)
1357 {
1358 ERROR(mLogCategory,"Error zwp_linux_dmabuf_v1");
1359 return ERROR_UNKNOWN;
1360 }
1361
fei.dengf7a0cd32023-08-29 09:36:37 +00001362 waylandBuf = findWaylandBuffer(buf);
1363 if (waylandBuf == NULL) {
fei.dengb9a1a572023-09-13 01:33:57 +00001364 waylandBuf = new WaylandBuffer(this, mLogCategory);
fei.dengda0cd9f2024-07-24 09:25:11 +08001365 isNew = true;
1366 }
1367 waylandBuf->setBufferFormat(mBufferFormat);
1368 ret = waylandBuf->constructWlBuffer(buf);
1369 if (ret != NO_ERROR) {
1370 WARNING(mLogCategory,"dmabufConstructWlBuffer fail,release waylandbuf");
1371 //delete waylanBuf,WaylandBuffer object destruct will call release callback
1372 goto waylandbuf_fail;
1373 }
1374 if (isNew) {
1375 addWaylandBuffer(buf, waylandBuf);
fei.dengf7a0cd32023-08-29 09:36:37 +00001376 }
fei.dengb9a1a572023-09-13 01:33:57 +00001377 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +00001378waylandbuf_fail:
1379 //delete waylandbuf
1380 delete waylandBuf;
1381 waylandBuf = NULL;
fei.dengb9a1a572023-09-13 01:33:57 +00001382 return ERROR_UNKNOWN;
fei.dengf7a0cd32023-08-29 09:36:37 +00001383}
1384
1385void WaylandDisplay::displayFrameBuffer(RenderBuffer * buf, int64_t realDisplayTime)
1386{
fei.deng19b48692024-08-13 14:17:55 +08001387 WaylandBuffer *waylandBuf = NULL;
1388 struct wl_buffer * wlbuffer = NULL;
1389 int ret;
1390
1391 if (!buf) {
1392 ERROR(mLogCategory,"Error input params, RenderBuffer is null");
1393 return;
1394 }
1395
1396 if (buf->flag & BUFFER_FLAG_DMA_BUFFER) {
1397 if (buf->dma.width <=0 || buf->dma.height <=0) {
1398 buf->dma.width = mVideoWidth;
1399 buf->dma.height = mVideoHeight;
1400 }
1401
1402 waylandBuf = findWaylandBuffer(buf);
1403 if (waylandBuf) {
1404 waylandBuf->setRenderRealTime(realDisplayTime);
1405 } else {
1406 ERROR(mLogCategory,"NOT found wayland buffer,please prepare buffer first");
1407 goto waylandbuf_fail;
1408 }
1409 }
1410
1411 //if no wl_output, drop this buffer
1412 if (mCurrentDisplayOutput->wlOutput == NULL) {
1413 TRACE(mLogCategory,"No wl_output");
1414 //insert this buffer to committed weston buffer manager
1415 std::pair<int64_t, WaylandBuffer *> item(realDisplayTime, waylandBuf);
1416 mCommittedBufferMap.insert(item);
1417 mWaylandPlugin->handleFrameDropped(buf);
1418 WaylandBuffer::bufferRelease(waylandBuf,NULL);
1419 return;
1420 }
1421
1422 //must commit areasurface first, because weston xdg surface maybe timeout
1423 //this cause video is not display,commit can resume xdg surface
1424 if (!mReCommitAreaSurface) {
1425 mReCommitAreaSurface = true;
1426 wl_surface_commit (mAreaSurface);
1427 }
1428
fei.deng6c425232024-07-19 16:15:31 +08001429 //set frame rate to weston,it lets weston to select suitable mode
1430 if (mFrameRateChanged && mAmlConfigAPIList.enableSetDisplayRate) {
1431 mFrameRateChanged = false;
1432 TRACE(mLogCategory,"set frame rate %d/%d to weston", mFrameRateFractionNum, mFrameRateFractionDenom);
1433 wl_surface_set_display_rate(mVideoSurfaceWrapper, mFrameRateFractionNum, mFrameRateFractionDenom);
1434 }
fei.denga4abbd52024-07-11 19:17:50 +08001435 //update video surface size
le.han692592c2024-10-12 06:24:44 +00001436 if (mUpdateVideoSurface && mVideoSurface) {
fei.denga4abbd52024-07-11 19:17:50 +08001437 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.deng96aa7f72024-09-29 15:46:52 +08001484 //doing video rotate if needed
1485 if (mVideoRotateDegree >= 0) {
1486 /*weston accept degree map: transfer value->degree, 0->0, 1->90,2->180,3->270
1487 detail see: enum wl_output_transform or search WL_OUTPUT_TRANSFORM_xxx*/
1488 int transform = 0;
1489 switch (mVideoRotateDegree) {
1490 case 90: {
1491 transform = 1;
1492 } break;
1493 case 180: {
1494 transform = 2;
1495 } break;
1496 case 270: {
1497 transform = 3;
1498 } break;
1499 default:
1500 transform = 0;
1501 }
1502 wl_surface_set_buffer_transform(mVideoSurfaceWrapper, transform);
1503 }
1504
fei.dengf7a0cd32023-08-29 09:36:37 +00001505 wl_surface_damage (mVideoSurfaceWrapper, 0, 0, mVideoRect.w, mVideoRect.h);
1506 wl_surface_commit (mVideoSurfaceWrapper);
1507 //insert this buffer to committed weston buffer manager
fei.dengae8c90a2024-06-27 13:39:53 +08001508 std::pair<int64_t, WaylandBuffer *> item(realDisplayTime, waylandBuf);
fei.dengf7a0cd32023-08-29 09:36:37 +00001509 mCommittedBufferMap.insert(item);
1510 } else {
fei.dengb9a1a572023-09-13 01:33:57 +00001511 WARNING(mLogCategory,"wlbuffer is NULL");
fei.dengf7a0cd32023-08-29 09:36:37 +00001512 /* clear both video and parent surfaces */
fei.deng19b48692024-08-13 14:17:55 +08001513 //cleanSurface();
1514 goto waylandbuf_fail;
fei.dengf7a0cd32023-08-29 09:36:37 +00001515 }
1516
1517 wl_display_flush (mWlDisplay);
fei.deng4029e682024-06-26 17:06:31 +08001518 //set keep last frame or not when after send first buffer to weston,1 keep last frame, 0 not
1519 if (mToSendKeepLastFrame) {
1520 setKeepLastFrame(mKeepLastFrame);
1521 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001522
1523 return;
1524waylandbuf_fail:
1525 //notify dropped
1526 mWaylandPlugin->handleFrameDropped(buf);
1527 //notify app release this buf
1528 mWaylandPlugin->handleBufferRelease(buf);
fei.dengf3ee6912024-08-30 18:22:55 +08001529
fei.dengf7a0cd32023-08-29 09:36:37 +00001530 return;
1531}
1532
1533void WaylandDisplay::handleBufferReleaseCallback(WaylandBuffer *buf)
1534{
fei.denga4abbd52024-07-11 19:17:50 +08001535 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.dengf7a0cd32023-08-29 09:36:37 +00001536 {
fei.dengb9a1a572023-09-13 01:33:57 +00001537 Tls::Mutex::Autolock _l(mRenderMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001538 //remove buffer if this buffer is ready to release
fei.dengae8c90a2024-06-27 13:39:53 +08001539 auto item = mCommittedBufferMap.find(buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001540 if (item != mCommittedBufferMap.end()) {
fei.dengdd910ef2024-06-07 10:25:30 +08001541 --mCommitCnt;
fei.dengf7a0cd32023-08-29 09:36:37 +00001542 mCommittedBufferMap.erase(item);
1543 } else {
fei.denga4abbd52024-07-11 19:17:50 +08001544 TRACE(mLogCategory,"Error,Can't find WaylandBuffer pts:%lld us (%lld) in buffer map",
1545 renderBuffer->pts/1000,buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001546 return;
1547 }
1548 }
fei.denga4abbd52024-07-11 19:17:50 +08001549
1550 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 +00001551 mWaylandPlugin->handleBufferRelease(renderBuffer);
1552}
1553
1554void WaylandDisplay::handleFrameDisplayedCallback(WaylandBuffer *buf)
1555{
1556 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.denga4abbd52024-07-11 19:17:50 +08001557 TRACE(mLogCategory,"renderBuffer :%p,PTS:%lld us,realtime:%lld us",renderBuffer,renderBuffer->pts/1000,buf->getRenderRealTime());
fei.deng3287c082024-04-23 09:29:22 +00001558 if (!mSignalFirstFramePts) {
1559 mSignalFirstFramePts = true;
1560 mWaylandPlugin->handleMsgNotify(MSG_FIRST_FRAME, (void*)&renderBuffer->pts);
1561 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001562 mWaylandPlugin->handleFrameDisplayed(renderBuffer);
le.hane8c8fdd2024-09-19 09:28:50 +00001563 if (!mKeepFrameOnFlush && mFirstPtsAfterFlush == renderBuffer->pts) {
1564 mKeepFrameOnFlush = 1;
1565 mFirstPtsAfterFlush = -1;
1566 wl_surface_set_video_plane_mute(mVideoSurfaceWrapper, 0);
1567 INFO(mLogCategory,"unmute video plane");
1568 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001569}
1570
1571void WaylandDisplay::handleFrameDropedCallback(WaylandBuffer *buf)
1572{
1573 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.denga4abbd52024-07-11 19:17:50 +08001574 TRACE(mLogCategory,"renderBuffer :%p,PTS:%lld us,realtime:%lld us",renderBuffer,renderBuffer->pts/1000,buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001575 mWaylandPlugin->handleFrameDropped(renderBuffer);
1576}
1577
fei.deng649b0e22024-09-03 18:57:13 +08001578void WaylandDisplay::handleFrameTime(WaylandBuffer *buf,uint32_t sec, uint32_t usec)
1579{
1580 RenderBuffer *renderBuffer = buf->getRenderBuffer();
1581 int64_t frameDisplayTimeUs = int64_t(sec)*1000000LL + usec;
1582 if (mLastDisplayFramePts == -1) {
1583 mLastDisplayFramePts = renderBuffer->pts;
1584 mLastDisplayFrameTimeUs = frameDisplayTimeUs;
1585 } else { //calculate last frame displayed duration
1586 int64_t duration = frameDisplayTimeUs - mLastDisplayFrameTimeUs;
1587 TRACE(mLogCategory,"now pts:%lld us,time:%u us,pre pts:%lld us,dur:%lld us",
1588 renderBuffer->pts/1000,frameDisplayTimeUs,mLastDisplayFramePts/1000,duration);
1589 if (mFrameDurationUs > 0 && duration > FRAME_FREEZE_THRESHOLD(mFrameDurationUs)) {
1590 FrameDisplayInfo frameDisplayInfo = {-1, -1};
1591 frameDisplayInfo.pts = mLastDisplayFramePts;
1592 frameDisplayInfo.duration = duration;
1593 TRACE(mLogCategory,"report freeze frame,pts:%lld us,duration:%lld us",frameDisplayInfo.pts/1000,frameDisplayInfo.duration);
1594 mWaylandPlugin->handleMsgNotify(MSG_FRAME_FREEZE, &frameDisplayInfo);
1595 }
1596 mLastDisplayFramePts = renderBuffer->pts;
1597 mLastDisplayFrameTimeUs = frameDisplayTimeUs;
1598 }
1599}
1600
fei.dengf7a0cd32023-08-29 09:36:37 +00001601
1602void WaylandDisplay::readyToRun()
1603{
1604 mFd = wl_display_get_fd (mWlDisplay);
fei.dengb9a1a572023-09-13 01:33:57 +00001605 if (mPoll) {
1606 mPoll->addFd(mFd);
1607 mPoll->setFdReadable(mFd, true);
1608 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001609}
1610
fei.dengdd910ef2024-06-07 10:25:30 +08001611void WaylandDisplay::readyToExit()
1612{
1613 if (mPoll && mFd >= 0) {
1614 mPoll->removeFd(mFd);
1615 }
1616}
1617
fei.dengf7a0cd32023-08-29 09:36:37 +00001618bool WaylandDisplay::threadLoop()
1619{
1620 int ret;
fei.dengf7a0cd32023-08-29 09:36:37 +00001621
1622 while (wl_display_prepare_read_queue (mWlDisplay, mWlQueue) != 0) {
1623 wl_display_dispatch_queue_pending (mWlDisplay, mWlQueue);
1624 }
1625
1626 wl_display_flush (mWlDisplay);
1627
1628 /*poll timeout value must > 300 ms,otherwise zwp_linux_dmabuf will create failed,
1629 so do use -1 to wait for ever*/
fei.dengb9a1a572023-09-13 01:33:57 +00001630 ret = mPoll->wait(-1); //wait for ever
fei.dengf7a0cd32023-08-29 09:36:37 +00001631 if (ret < 0) { //poll error
fei.dengb9a1a572023-09-13 01:33:57 +00001632 WARNING(mLogCategory,"poll error");
fei.dengf7a0cd32023-08-29 09:36:37 +00001633 wl_display_cancel_read(mWlDisplay);
1634 return false;
1635 } else if (ret == 0) { //poll time out
1636 return true; //run loop
1637 }
1638
1639 if (wl_display_read_events (mWlDisplay) == -1) {
1640 goto tag_error;
1641 }
1642
1643 wl_display_dispatch_queue_pending (mWlDisplay, mWlQueue);
1644 return true;
1645tag_error:
fei.dengb9a1a572023-09-13 01:33:57 +00001646 ERROR(mLogCategory,"Error communicating with the wayland server");
fei.dengf7a0cd32023-08-29 09:36:37 +00001647 return false;
1648}
1649
1650void WaylandDisplay::videoCenterRect(Rectangle src, Rectangle dst, Rectangle *result, bool scaling)
1651{
1652 //if dst is a small window, we scale video to map window size,don't doing center
fei.dengda0cd9f2024-07-24 09:25:11 +08001653 // if (mRenderRect.w != dst.w && mRenderRect.h != dst.h) {
1654 // result->x = dst.x;
1655 // result->y = dst.y;
1656 // result->w = dst.w;
1657 // result->h = dst.h;
1658 // TRACE(mLogCategory,"small window source is %dx%d dest is %dx%d, result is %d,%d,%d,%d",
1659 // src.w, src.h, dst.w, dst.h, result->x, result->y, result->w, result->h);
1660 // return;
1661 // }
fei.dengf7a0cd32023-08-29 09:36:37 +00001662 if (!scaling) {
1663 result->w = MIN (src.w, dst.w);
1664 result->h = MIN (src.h, dst.h);
1665 result->x = dst.x + (dst.w - result->w) / 2;
1666 result->y = dst.y + (dst.h - result->h) / 2;
1667 } else {
1668 double src_ratio, dst_ratio;
1669
fei.denga4abbd52024-07-11 19:17:50 +08001670 src_ratio = (double) (src.w * mPixelAspectRatio) / src.h;
fei.dengf7a0cd32023-08-29 09:36:37 +00001671 dst_ratio = (double) dst.w / dst.h;
1672
1673 if (src_ratio > dst_ratio) {
1674 result->w = dst.w;
1675 result->h = dst.w / src_ratio;
1676 result->x = dst.x;
1677 result->y = dst.y + (dst.h - result->h) / 2;
1678 } else if (src_ratio < dst_ratio) {
1679 result->w = dst.h * src_ratio;
1680 result->h = dst.h;
1681 result->x = dst.x + (dst.w - result->w) / 2;
1682 result->y = dst.y;
1683 } else {
1684 result->x = dst.x;
1685 result->y = dst.y;
1686 result->w = dst.w;
1687 result->h = dst.h;
1688 }
1689 }
1690
fei.denga4abbd52024-07-11 19:17:50 +08001691 TRACE(mLogCategory,"source is %dx%d dest is %dx%d, result is %d,%d,%d,%d",
1692 src.w, src.h, dst.w, dst.h, result->x, result->y,result->w, result->h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001693}
1694
1695void WaylandDisplay::updateBorders()
1696{
1697 int width,height;
1698
1699 if (mNoBorderUpdate)
1700 return;
1701
1702 if (mViewporter) {
1703 width = height = 1;
1704 mNoBorderUpdate = true;
1705 } else {
1706 width = mRenderRect.w;
1707 height = mRenderRect.h;
1708 }
1709
1710 RenderVideoFormat format = VIDEO_FORMAT_BGRA;
fei.dengb9a1a572023-09-13 01:33:57 +00001711 mAreaShmBuffer = new WaylandShmBuffer(this, mLogCategory);
fei.dengf7a0cd32023-08-29 09:36:37 +00001712 struct wl_buffer *wlbuf = mAreaShmBuffer->constructWlBuffer(width, height, format);
1713 if (wlbuf == NULL) {
1714 delete mAreaShmBuffer;
1715 mAreaShmBuffer = NULL;
1716 }
1717
1718 wl_surface_attach(mAreaSurfaceWrapper, wlbuf, 0, 0);
1719}
1720
1721std::size_t WaylandDisplay::calculateDmaBufferHash(RenderDmaBuffer &dmabuf)
1722{
1723 std::string hashString("");
1724 for (int i = 0; i < dmabuf.planeCnt; i++) {
1725 char hashtmp[1024];
fei.dengda0cd9f2024-07-24 09:25:11 +08001726 snprintf (hashtmp, 1024, "%d%d%d%d%d%d%d",i,dmabuf.width,dmabuf.height,dmabuf.planeCnt,
fei.dengf7a0cd32023-08-29 09:36:37 +00001727 dmabuf.stride[i],dmabuf.offset[i],dmabuf.fd[i]);
1728 std::string tmp(hashtmp);
1729 hashString += tmp;
1730 }
1731
1732 std::size_t hashval = std::hash<std::string>()(hashString);
fei.dengb9a1a572023-09-13 01:33:57 +00001733 //TRACE(mLogCategory,"hashstr:%s,val:%zu",hashString.c_str(),hashval);
fei.dengf7a0cd32023-08-29 09:36:37 +00001734 return hashval;
1735}
1736
1737void WaylandDisplay::addWaylandBuffer(RenderBuffer * buf, WaylandBuffer *waylandbuf)
1738{
fei.deng19b48692024-08-13 14:17:55 +08001739 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001740 if (buf->flag & BUFFER_FLAG_DMA_BUFFER) {
1741 std::size_t hashval = calculateDmaBufferHash(buf->dma);
1742 std::pair<std::size_t, WaylandBuffer *> item(hashval, waylandbuf);
fei.dengb9a1a572023-09-13 01:33:57 +00001743 //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 +00001744 mWaylandBuffersMap.insert(item);
1745 }
fei.dengb9a1a572023-09-13 01:33:57 +00001746 TRACE(mLogCategory,"mWaylandBuffersMap size:%d",mWaylandBuffersMap.size());
fei.dengf7a0cd32023-08-29 09:36:37 +00001747}
1748
1749WaylandBuffer* WaylandDisplay::findWaylandBuffer(RenderBuffer * buf)
1750{
fei.deng19b48692024-08-13 14:17:55 +08001751 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001752 std::size_t hashval = calculateDmaBufferHash(buf->dma);
1753 auto item = mWaylandBuffersMap.find(hashval);
1754 if (item == mWaylandBuffersMap.end()) {
1755 return NULL;
1756 }
1757
1758 return (WaylandBuffer*) item->second;
1759}
1760
1761void WaylandDisplay::cleanAllWaylandBuffer()
1762{
fei.deng19b48692024-08-13 14:17:55 +08001763 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001764 //free all obtain buff
1765 for (auto item = mWaylandBuffersMap.begin(); item != mWaylandBuffersMap.end(); ) {
1766 WaylandBuffer *waylandbuf = (WaylandBuffer*)item->second;
1767 mWaylandBuffersMap.erase(item++);
1768 delete waylandbuf;
1769 }
1770}
1771
fei.dengda0cd9f2024-07-24 09:25:11 +08001772
1773/**
1774 * @brief clean wayland buffers those malloc before resolution changed
1775 *
1776 */
1777void WaylandDisplay::cleanWaylandBufferBeforeResChanged()
1778{
fei.deng19b48692024-08-13 14:17:55 +08001779 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengda0cd9f2024-07-24 09:25:11 +08001780 for (auto item = mWaylandBuffersMap.begin(); item != mWaylandBuffersMap.end(); ) {
1781 WaylandBuffer *wlbuf = (WaylandBuffer*)item->second;
1782 if (wlbuf->isFree()) {
1783 mWaylandBuffersMap.erase(item++);
1784 delete wlbuf;
1785 } else {
1786 item++;
1787 }
1788 }
1789}
1790
fei.dengf7a0cd32023-08-29 09:36:37 +00001791void WaylandDisplay::flushBuffers()
1792{
fei.dengb9a1a572023-09-13 01:33:57 +00001793 INFO(mLogCategory,"flushBuffers");
1794 Tls::Mutex::Autolock _l(mRenderMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001795 for (auto item = mCommittedBufferMap.begin(); item != mCommittedBufferMap.end(); item++) {
1796 WaylandBuffer *waylandbuf = (WaylandBuffer*)item->second;
1797 waylandbuf->forceRedrawing();
1798 handleFrameDisplayedCallback(waylandbuf);
1799 }
1800}
1801
1802void WaylandDisplay::cleanSurface()
1803{
1804 /* clear both video and parent surfaces */
1805 wl_surface_attach (mVideoSurfaceWrapper, NULL, 0, 0);
1806 wl_surface_commit (mVideoSurfaceWrapper);
1807 wl_surface_attach (mAreaSurfaceWrapper, NULL, 0, 0);
1808 wl_surface_commit (mAreaSurfaceWrapper);
fei.deng640c3c92024-04-12 08:31:19 +00001809}
1810
1811void WaylandDisplay::setKeepLastFrame(int keep)
1812{
1813 mKeepLastFrame = keep;
1814 if (mVideoSurfaceWrapper && mAmlConfigAPIList.enableKeepLastFrame) {
1815 INFO(mLogCategory,"keep last frame:%d",keep);
1816 wl_surface_keep_last_frame(mVideoSurfaceWrapper, keep);
fei.deng4029e682024-06-26 17:06:31 +08001817 mToSendKeepLastFrame = false;
1818 return;
fei.deng640c3c92024-04-12 08:31:19 +00001819 }
fei.deng4029e682024-06-26 17:06:31 +08001820 mToSendKeepLastFrame = true;
fei.deng6c425232024-07-19 16:15:31 +08001821}
1822
le.hane8c8fdd2024-09-19 09:28:50 +00001823void WaylandDisplay::setKeepLastFrameOnFlush(int keepOnFlush)
1824{
1825 mKeepFrameOnFlush = keepOnFlush;
1826 INFO(mLogCategory,"keep last frame:%d",mKeepFrameOnFlush);
1827 if (mVideoSurfaceWrapper && !mKeepFrameOnFlush) {
1828 INFO(mLogCategory,"mute video plane");
1829 wl_surface_set_video_plane_mute(mVideoSurfaceWrapper, 1);
1830 }
1831}
1832
le.han15dacdd2024-09-18 05:46:09 +00001833void WaylandDisplay::setImmediatelyOutput(int enable)
1834{
1835 if (mVideoSurfaceWrapper) {
1836 wl_surface_enable_ll_mode(mVideoSurfaceWrapper, enable);
1837 }
1838 INFO(mLogCategory,"set immediately output:%d", enable);
1839}
1840
fei.deng6c425232024-07-19 16:15:31 +08001841void WaylandDisplay::setFrameRate(int frameRateNum, int frameRateDenom)
1842{
1843 mFrameRateFractionNum = frameRateNum;
1844 mFrameRateFractionDenom = frameRateDenom;
1845 if (mFrameRateFractionDenom == 0) {
1846 mFrameRateFractionDenom = 1;
1847 }
fei.deng649b0e22024-09-03 18:57:13 +08001848
1849 if (mFrameRateFractionNum > 0) {
1850 mFrameDurationUs = 1000000 * mFrameRateFractionDenom/mFrameRateFractionNum;
1851 mFrameRateChanged = true;
fei.deng6c425232024-07-19 16:15:31 +08001852 }
fei.deng649b0e22024-09-03 18:57:13 +08001853
1854 INFO(mLogCategory,"num:%d,denom:%d,frame dur:%lld us",
1855 mFrameRateFractionNum, mFrameRateFractionDenom,mFrameDurationUs);
fei.deng1c94a342024-08-05 19:33:28 +08001856}
1857
1858void WaylandDisplay::setVideoPlaneZorder(int zorder)
1859{
1860 mVideoPlaneZorder = zorder;
1861 mVideoPlaneZorderChanged = true;
1862 if (mVideoSurfaceWrapper) {
1863 mVideoPlaneZorderChanged = false;
1864 wl_surface_set_zorder(mVideoSurfaceWrapper, mVideoPlaneZorder);
1865 }
fei.deng649b0e22024-09-03 18:57:13 +08001866}
1867
1868void WaylandDisplay::pause()
1869{
1870 mLastDisplayFramePts = -1;
1871 mLastDisplayFrameTimeUs = -1;
1872}
1873void WaylandDisplay::resume()
1874{
1875
fei.dengf7a0cd32023-08-29 09:36:37 +00001876}