blob: e6f644edc94db2fa60fe5cfddcc070ac0b7c597d [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:
fei.denga7618662024-10-30 14:24:48 +08001379 if (!isNew) {
1380 removeWaylandBuffer(buf);
1381 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001382 //delete waylandbuf
1383 delete waylandBuf;
1384 waylandBuf = NULL;
fei.dengb9a1a572023-09-13 01:33:57 +00001385 return ERROR_UNKNOWN;
fei.dengf7a0cd32023-08-29 09:36:37 +00001386}
1387
1388void WaylandDisplay::displayFrameBuffer(RenderBuffer * buf, int64_t realDisplayTime)
1389{
fei.deng19b48692024-08-13 14:17:55 +08001390 WaylandBuffer *waylandBuf = NULL;
1391 struct wl_buffer * wlbuffer = NULL;
1392 int ret;
1393
1394 if (!buf) {
1395 ERROR(mLogCategory,"Error input params, RenderBuffer is null");
1396 return;
1397 }
1398
1399 if (buf->flag & BUFFER_FLAG_DMA_BUFFER) {
1400 if (buf->dma.width <=0 || buf->dma.height <=0) {
1401 buf->dma.width = mVideoWidth;
1402 buf->dma.height = mVideoHeight;
1403 }
1404
1405 waylandBuf = findWaylandBuffer(buf);
1406 if (waylandBuf) {
1407 waylandBuf->setRenderRealTime(realDisplayTime);
1408 } else {
1409 ERROR(mLogCategory,"NOT found wayland buffer,please prepare buffer first");
1410 goto waylandbuf_fail;
1411 }
1412 }
1413
1414 //if no wl_output, drop this buffer
1415 if (mCurrentDisplayOutput->wlOutput == NULL) {
1416 TRACE(mLogCategory,"No wl_output");
1417 //insert this buffer to committed weston buffer manager
1418 std::pair<int64_t, WaylandBuffer *> item(realDisplayTime, waylandBuf);
1419 mCommittedBufferMap.insert(item);
1420 mWaylandPlugin->handleFrameDropped(buf);
1421 WaylandBuffer::bufferRelease(waylandBuf,NULL);
1422 return;
1423 }
1424
1425 //must commit areasurface first, because weston xdg surface maybe timeout
1426 //this cause video is not display,commit can resume xdg surface
1427 if (!mReCommitAreaSurface) {
1428 mReCommitAreaSurface = true;
1429 wl_surface_commit (mAreaSurface);
1430 }
1431
fei.deng6c425232024-07-19 16:15:31 +08001432 //set frame rate to weston,it lets weston to select suitable mode
1433 if (mFrameRateChanged && mAmlConfigAPIList.enableSetDisplayRate) {
1434 mFrameRateChanged = false;
1435 TRACE(mLogCategory,"set frame rate %d/%d to weston", mFrameRateFractionNum, mFrameRateFractionDenom);
1436 wl_surface_set_display_rate(mVideoSurfaceWrapper, mFrameRateFractionNum, mFrameRateFractionDenom);
1437 }
fei.denga4abbd52024-07-11 19:17:50 +08001438 //update video surface size
le.han692592c2024-10-12 06:24:44 +00001439 if (mUpdateVideoSurface && mVideoSurface) {
fei.denga4abbd52024-07-11 19:17:50 +08001440 mUpdateVideoSurface = false;
1441 //if had full screen, unset it and set window size
1442 if (mFullScreen) {
1443 mFullScreen = false;
1444 ensureFullscreen(mFullScreen);
1445 }
1446 resizeVideoSurface(true);
fei.dengda0cd9f2024-07-24 09:25:11 +08001447 /*clean wayland buffers those allocated
1448 before resolution changed and had release by weston */
1449 cleanWaylandBufferBeforeResChanged();
fei.denga4abbd52024-07-11 19:17:50 +08001450 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001451
fei.deng1c94a342024-08-05 19:33:28 +08001452 if (mVideoPlaneZorderChanged && mVideoSurfaceWrapper) {
1453 mVideoPlaneZorderChanged = false;
1454 wl_surface_set_zorder(mVideoSurfaceWrapper, mVideoPlaneZorder);
1455 }
1456
fei.dengdd910ef2024-06-07 10:25:30 +08001457 //TRACE(mLogCategory,"display renderBuffer:%p,PTS:%lld us,realtime:%lld",buf, buf->pts/1000, realDisplayTime);
fei.dengf7a0cd32023-08-29 09:36:37 +00001458
fei.dengf7a0cd32023-08-29 09:36:37 +00001459 if (waylandBuf) {
1460 wlbuffer = waylandBuf->getWlBuffer();
1461 }
fei.deng19b48692024-08-13 14:17:55 +08001462
fei.dengf7a0cd32023-08-29 09:36:37 +00001463 if (wlbuffer) {
fei.dengf3ee6912024-08-30 18:22:55 +08001464 auto cItem = mCommittedBufferMap.find(realDisplayTime);
1465 if (cItem != mCommittedBufferMap.end()) {
1466 TRACE(mLogCategory,"Error.release same display time buffer,pts:%lld us",buf->pts/1000);
1467 goto waylandbuf_fail;
1468 }
fei.dengb9a1a572023-09-13 01:33:57 +00001469 Tls::Mutex::Autolock _l(mRenderMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001470 ++mCommitCnt;
1471 uint32_t hiPts = realDisplayTime >> 32;
1472 uint32_t lowPts = realDisplayTime & 0xFFFFFFFF;
1473 //attach this wl_buffer to weston
fei.denga4abbd52024-07-11 19:17:50 +08001474 TRACE(mLogCategory,"++attach,renderbuf:%p,wl_buffer:%p(%d,%d,%d,%d),pts:%lld us,commitCnt:%d",
1475 buf,wlbuffer,mVideoRect.x,mVideoRect.y,mVideoRect.w,mVideoRect.h,buf->pts/1000,mCommitCnt);
fei.dengf7a0cd32023-08-29 09:36:37 +00001476 waylandBuf->attach(mVideoSurfaceWrapper);
1477
fei.deng640c3c92024-04-12 08:31:19 +00001478 if (mAmlConfigAPIList.enableSetPts) {
fei.dengb9a1a572023-09-13 01:33:57 +00001479 TRACE(mLogCategory,"display time:%lld,hiPts:%u,lowPts:%u",realDisplayTime, hiPts, lowPts);
fei.dengf7a0cd32023-08-29 09:36:37 +00001480 wl_surface_set_pts(mVideoSurfaceWrapper, hiPts, lowPts);
1481 }
1482
le.hane8c8fdd2024-09-19 09:28:50 +00001483 if (!mKeepFrameOnFlush && mFirstPtsAfterFlush == -1) {
1484 mFirstPtsAfterFlush = buf->pts;
1485 }
1486
fei.deng96aa7f72024-09-29 15:46:52 +08001487 //doing video rotate if needed
1488 if (mVideoRotateDegree >= 0) {
1489 /*weston accept degree map: transfer value->degree, 0->0, 1->90,2->180,3->270
1490 detail see: enum wl_output_transform or search WL_OUTPUT_TRANSFORM_xxx*/
1491 int transform = 0;
1492 switch (mVideoRotateDegree) {
1493 case 90: {
1494 transform = 1;
1495 } break;
1496 case 180: {
1497 transform = 2;
1498 } break;
1499 case 270: {
1500 transform = 3;
1501 } break;
1502 default:
1503 transform = 0;
1504 }
1505 wl_surface_set_buffer_transform(mVideoSurfaceWrapper, transform);
1506 }
1507
fei.dengf7a0cd32023-08-29 09:36:37 +00001508 wl_surface_damage (mVideoSurfaceWrapper, 0, 0, mVideoRect.w, mVideoRect.h);
1509 wl_surface_commit (mVideoSurfaceWrapper);
1510 //insert this buffer to committed weston buffer manager
fei.dengae8c90a2024-06-27 13:39:53 +08001511 std::pair<int64_t, WaylandBuffer *> item(realDisplayTime, waylandBuf);
fei.dengf7a0cd32023-08-29 09:36:37 +00001512 mCommittedBufferMap.insert(item);
1513 } else {
fei.dengb9a1a572023-09-13 01:33:57 +00001514 WARNING(mLogCategory,"wlbuffer is NULL");
fei.dengf7a0cd32023-08-29 09:36:37 +00001515 /* clear both video and parent surfaces */
fei.deng19b48692024-08-13 14:17:55 +08001516 //cleanSurface();
1517 goto waylandbuf_fail;
fei.dengf7a0cd32023-08-29 09:36:37 +00001518 }
1519
1520 wl_display_flush (mWlDisplay);
fei.deng4029e682024-06-26 17:06:31 +08001521 //set keep last frame or not when after send first buffer to weston,1 keep last frame, 0 not
1522 if (mToSendKeepLastFrame) {
1523 setKeepLastFrame(mKeepLastFrame);
1524 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001525
1526 return;
1527waylandbuf_fail:
1528 //notify dropped
1529 mWaylandPlugin->handleFrameDropped(buf);
1530 //notify app release this buf
1531 mWaylandPlugin->handleBufferRelease(buf);
fei.dengf3ee6912024-08-30 18:22:55 +08001532
fei.dengf7a0cd32023-08-29 09:36:37 +00001533 return;
1534}
1535
1536void WaylandDisplay::handleBufferReleaseCallback(WaylandBuffer *buf)
1537{
fei.denga4abbd52024-07-11 19:17:50 +08001538 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.dengf7a0cd32023-08-29 09:36:37 +00001539 {
fei.dengb9a1a572023-09-13 01:33:57 +00001540 Tls::Mutex::Autolock _l(mRenderMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001541 //remove buffer if this buffer is ready to release
fei.dengae8c90a2024-06-27 13:39:53 +08001542 auto item = mCommittedBufferMap.find(buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001543 if (item != mCommittedBufferMap.end()) {
fei.dengdd910ef2024-06-07 10:25:30 +08001544 --mCommitCnt;
fei.dengf7a0cd32023-08-29 09:36:37 +00001545 mCommittedBufferMap.erase(item);
1546 } else {
fei.denga4abbd52024-07-11 19:17:50 +08001547 TRACE(mLogCategory,"Error,Can't find WaylandBuffer pts:%lld us (%lld) in buffer map",
1548 renderBuffer->pts/1000,buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001549 return;
1550 }
1551 }
fei.denga4abbd52024-07-11 19:17:50 +08001552
1553 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 +00001554 mWaylandPlugin->handleBufferRelease(renderBuffer);
1555}
1556
1557void WaylandDisplay::handleFrameDisplayedCallback(WaylandBuffer *buf)
1558{
1559 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.denga4abbd52024-07-11 19:17:50 +08001560 TRACE(mLogCategory,"renderBuffer :%p,PTS:%lld us,realtime:%lld us",renderBuffer,renderBuffer->pts/1000,buf->getRenderRealTime());
fei.deng3287c082024-04-23 09:29:22 +00001561 if (!mSignalFirstFramePts) {
1562 mSignalFirstFramePts = true;
1563 mWaylandPlugin->handleMsgNotify(MSG_FIRST_FRAME, (void*)&renderBuffer->pts);
1564 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001565 mWaylandPlugin->handleFrameDisplayed(renderBuffer);
le.hane8c8fdd2024-09-19 09:28:50 +00001566 if (!mKeepFrameOnFlush && mFirstPtsAfterFlush == renderBuffer->pts) {
1567 mKeepFrameOnFlush = 1;
1568 mFirstPtsAfterFlush = -1;
1569 wl_surface_set_video_plane_mute(mVideoSurfaceWrapper, 0);
1570 INFO(mLogCategory,"unmute video plane");
1571 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001572}
1573
1574void WaylandDisplay::handleFrameDropedCallback(WaylandBuffer *buf)
1575{
1576 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.denga4abbd52024-07-11 19:17:50 +08001577 TRACE(mLogCategory,"renderBuffer :%p,PTS:%lld us,realtime:%lld us",renderBuffer,renderBuffer->pts/1000,buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001578 mWaylandPlugin->handleFrameDropped(renderBuffer);
1579}
1580
fei.deng649b0e22024-09-03 18:57:13 +08001581void WaylandDisplay::handleFrameTime(WaylandBuffer *buf,uint32_t sec, uint32_t usec)
1582{
1583 RenderBuffer *renderBuffer = buf->getRenderBuffer();
1584 int64_t frameDisplayTimeUs = int64_t(sec)*1000000LL + usec;
1585 if (mLastDisplayFramePts == -1) {
1586 mLastDisplayFramePts = renderBuffer->pts;
1587 mLastDisplayFrameTimeUs = frameDisplayTimeUs;
1588 } else { //calculate last frame displayed duration
1589 int64_t duration = frameDisplayTimeUs - mLastDisplayFrameTimeUs;
1590 TRACE(mLogCategory,"now pts:%lld us,time:%u us,pre pts:%lld us,dur:%lld us",
1591 renderBuffer->pts/1000,frameDisplayTimeUs,mLastDisplayFramePts/1000,duration);
1592 if (mFrameDurationUs > 0 && duration > FRAME_FREEZE_THRESHOLD(mFrameDurationUs)) {
1593 FrameDisplayInfo frameDisplayInfo = {-1, -1};
1594 frameDisplayInfo.pts = mLastDisplayFramePts;
1595 frameDisplayInfo.duration = duration;
1596 TRACE(mLogCategory,"report freeze frame,pts:%lld us,duration:%lld us",frameDisplayInfo.pts/1000,frameDisplayInfo.duration);
1597 mWaylandPlugin->handleMsgNotify(MSG_FRAME_FREEZE, &frameDisplayInfo);
1598 }
1599 mLastDisplayFramePts = renderBuffer->pts;
1600 mLastDisplayFrameTimeUs = frameDisplayTimeUs;
1601 }
1602}
1603
fei.dengf7a0cd32023-08-29 09:36:37 +00001604
1605void WaylandDisplay::readyToRun()
1606{
1607 mFd = wl_display_get_fd (mWlDisplay);
fei.dengb9a1a572023-09-13 01:33:57 +00001608 if (mPoll) {
1609 mPoll->addFd(mFd);
1610 mPoll->setFdReadable(mFd, true);
1611 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001612}
1613
fei.dengdd910ef2024-06-07 10:25:30 +08001614void WaylandDisplay::readyToExit()
1615{
1616 if (mPoll && mFd >= 0) {
1617 mPoll->removeFd(mFd);
1618 }
1619}
1620
fei.dengf7a0cd32023-08-29 09:36:37 +00001621bool WaylandDisplay::threadLoop()
1622{
1623 int ret;
fei.dengf7a0cd32023-08-29 09:36:37 +00001624
1625 while (wl_display_prepare_read_queue (mWlDisplay, mWlQueue) != 0) {
1626 wl_display_dispatch_queue_pending (mWlDisplay, mWlQueue);
1627 }
1628
1629 wl_display_flush (mWlDisplay);
1630
1631 /*poll timeout value must > 300 ms,otherwise zwp_linux_dmabuf will create failed,
1632 so do use -1 to wait for ever*/
fei.dengb9a1a572023-09-13 01:33:57 +00001633 ret = mPoll->wait(-1); //wait for ever
fei.dengf7a0cd32023-08-29 09:36:37 +00001634 if (ret < 0) { //poll error
fei.dengb9a1a572023-09-13 01:33:57 +00001635 WARNING(mLogCategory,"poll error");
fei.dengf7a0cd32023-08-29 09:36:37 +00001636 wl_display_cancel_read(mWlDisplay);
1637 return false;
1638 } else if (ret == 0) { //poll time out
1639 return true; //run loop
1640 }
1641
1642 if (wl_display_read_events (mWlDisplay) == -1) {
1643 goto tag_error;
1644 }
1645
1646 wl_display_dispatch_queue_pending (mWlDisplay, mWlQueue);
1647 return true;
1648tag_error:
fei.dengb9a1a572023-09-13 01:33:57 +00001649 ERROR(mLogCategory,"Error communicating with the wayland server");
fei.dengf7a0cd32023-08-29 09:36:37 +00001650 return false;
1651}
1652
1653void WaylandDisplay::videoCenterRect(Rectangle src, Rectangle dst, Rectangle *result, bool scaling)
1654{
1655 //if dst is a small window, we scale video to map window size,don't doing center
fei.dengda0cd9f2024-07-24 09:25:11 +08001656 // if (mRenderRect.w != dst.w && mRenderRect.h != dst.h) {
1657 // result->x = dst.x;
1658 // result->y = dst.y;
1659 // result->w = dst.w;
1660 // result->h = dst.h;
1661 // TRACE(mLogCategory,"small window source is %dx%d dest is %dx%d, result is %d,%d,%d,%d",
1662 // src.w, src.h, dst.w, dst.h, result->x, result->y, result->w, result->h);
1663 // return;
1664 // }
fei.dengf7a0cd32023-08-29 09:36:37 +00001665 if (!scaling) {
1666 result->w = MIN (src.w, dst.w);
1667 result->h = MIN (src.h, dst.h);
1668 result->x = dst.x + (dst.w - result->w) / 2;
1669 result->y = dst.y + (dst.h - result->h) / 2;
1670 } else {
1671 double src_ratio, dst_ratio;
1672
fei.denga4abbd52024-07-11 19:17:50 +08001673 src_ratio = (double) (src.w * mPixelAspectRatio) / src.h;
fei.dengf7a0cd32023-08-29 09:36:37 +00001674 dst_ratio = (double) dst.w / dst.h;
1675
1676 if (src_ratio > dst_ratio) {
1677 result->w = dst.w;
1678 result->h = dst.w / src_ratio;
1679 result->x = dst.x;
1680 result->y = dst.y + (dst.h - result->h) / 2;
1681 } else if (src_ratio < dst_ratio) {
1682 result->w = dst.h * src_ratio;
1683 result->h = dst.h;
1684 result->x = dst.x + (dst.w - result->w) / 2;
1685 result->y = dst.y;
1686 } else {
1687 result->x = dst.x;
1688 result->y = dst.y;
1689 result->w = dst.w;
1690 result->h = dst.h;
1691 }
1692 }
1693
fei.denga4abbd52024-07-11 19:17:50 +08001694 TRACE(mLogCategory,"source is %dx%d dest is %dx%d, result is %d,%d,%d,%d",
1695 src.w, src.h, dst.w, dst.h, result->x, result->y,result->w, result->h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001696}
1697
1698void WaylandDisplay::updateBorders()
1699{
1700 int width,height;
1701
1702 if (mNoBorderUpdate)
1703 return;
1704
1705 if (mViewporter) {
1706 width = height = 1;
1707 mNoBorderUpdate = true;
1708 } else {
1709 width = mRenderRect.w;
1710 height = mRenderRect.h;
1711 }
1712
1713 RenderVideoFormat format = VIDEO_FORMAT_BGRA;
fei.dengb9a1a572023-09-13 01:33:57 +00001714 mAreaShmBuffer = new WaylandShmBuffer(this, mLogCategory);
fei.dengf7a0cd32023-08-29 09:36:37 +00001715 struct wl_buffer *wlbuf = mAreaShmBuffer->constructWlBuffer(width, height, format);
1716 if (wlbuf == NULL) {
1717 delete mAreaShmBuffer;
1718 mAreaShmBuffer = NULL;
1719 }
1720
1721 wl_surface_attach(mAreaSurfaceWrapper, wlbuf, 0, 0);
1722}
1723
1724std::size_t WaylandDisplay::calculateDmaBufferHash(RenderDmaBuffer &dmabuf)
1725{
1726 std::string hashString("");
1727 for (int i = 0; i < dmabuf.planeCnt; i++) {
1728 char hashtmp[1024];
fei.dengda0cd9f2024-07-24 09:25:11 +08001729 snprintf (hashtmp, 1024, "%d%d%d%d%d%d%d",i,dmabuf.width,dmabuf.height,dmabuf.planeCnt,
fei.dengf7a0cd32023-08-29 09:36:37 +00001730 dmabuf.stride[i],dmabuf.offset[i],dmabuf.fd[i]);
1731 std::string tmp(hashtmp);
1732 hashString += tmp;
1733 }
1734
1735 std::size_t hashval = std::hash<std::string>()(hashString);
fei.dengb9a1a572023-09-13 01:33:57 +00001736 //TRACE(mLogCategory,"hashstr:%s,val:%zu",hashString.c_str(),hashval);
fei.dengf7a0cd32023-08-29 09:36:37 +00001737 return hashval;
1738}
1739
1740void WaylandDisplay::addWaylandBuffer(RenderBuffer * buf, WaylandBuffer *waylandbuf)
1741{
fei.deng19b48692024-08-13 14:17:55 +08001742 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001743 if (buf->flag & BUFFER_FLAG_DMA_BUFFER) {
1744 std::size_t hashval = calculateDmaBufferHash(buf->dma);
1745 std::pair<std::size_t, WaylandBuffer *> item(hashval, waylandbuf);
fei.dengb9a1a572023-09-13 01:33:57 +00001746 //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 +00001747 mWaylandBuffersMap.insert(item);
1748 }
fei.dengb9a1a572023-09-13 01:33:57 +00001749 TRACE(mLogCategory,"mWaylandBuffersMap size:%d",mWaylandBuffersMap.size());
fei.dengf7a0cd32023-08-29 09:36:37 +00001750}
1751
1752WaylandBuffer* WaylandDisplay::findWaylandBuffer(RenderBuffer * buf)
1753{
fei.deng19b48692024-08-13 14:17:55 +08001754 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001755 std::size_t hashval = calculateDmaBufferHash(buf->dma);
1756 auto item = mWaylandBuffersMap.find(hashval);
1757 if (item == mWaylandBuffersMap.end()) {
1758 return NULL;
1759 }
1760
1761 return (WaylandBuffer*) item->second;
1762}
1763
fei.denga7618662024-10-30 14:24:48 +08001764void WaylandDisplay::removeWaylandBuffer(RenderBuffer * buf)
1765{
1766 Tls::Mutex::Autolock _l(mBufferMutex);
1767 std::size_t hashval = calculateDmaBufferHash(buf->dma);
1768 auto item = mWaylandBuffersMap.find(hashval);
1769 if (item == mWaylandBuffersMap.end()) {
1770 return ;
1771 }
1772
1773 mWaylandBuffersMap.erase(item);
1774}
1775
fei.dengf7a0cd32023-08-29 09:36:37 +00001776void WaylandDisplay::cleanAllWaylandBuffer()
1777{
fei.deng19b48692024-08-13 14:17:55 +08001778 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001779 //free all obtain buff
1780 for (auto item = mWaylandBuffersMap.begin(); item != mWaylandBuffersMap.end(); ) {
1781 WaylandBuffer *waylandbuf = (WaylandBuffer*)item->second;
1782 mWaylandBuffersMap.erase(item++);
1783 delete waylandbuf;
1784 }
1785}
1786
fei.dengda0cd9f2024-07-24 09:25:11 +08001787
1788/**
1789 * @brief clean wayland buffers those malloc before resolution changed
1790 *
1791 */
1792void WaylandDisplay::cleanWaylandBufferBeforeResChanged()
1793{
fei.deng19b48692024-08-13 14:17:55 +08001794 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengda0cd9f2024-07-24 09:25:11 +08001795 for (auto item = mWaylandBuffersMap.begin(); item != mWaylandBuffersMap.end(); ) {
1796 WaylandBuffer *wlbuf = (WaylandBuffer*)item->second;
1797 if (wlbuf->isFree()) {
1798 mWaylandBuffersMap.erase(item++);
1799 delete wlbuf;
1800 } else {
1801 item++;
1802 }
1803 }
1804}
1805
fei.dengf7a0cd32023-08-29 09:36:37 +00001806void WaylandDisplay::flushBuffers()
1807{
fei.dengb9a1a572023-09-13 01:33:57 +00001808 INFO(mLogCategory,"flushBuffers");
1809 Tls::Mutex::Autolock _l(mRenderMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001810 for (auto item = mCommittedBufferMap.begin(); item != mCommittedBufferMap.end(); item++) {
1811 WaylandBuffer *waylandbuf = (WaylandBuffer*)item->second;
1812 waylandbuf->forceRedrawing();
1813 handleFrameDisplayedCallback(waylandbuf);
1814 }
1815}
1816
1817void WaylandDisplay::cleanSurface()
1818{
1819 /* clear both video and parent surfaces */
1820 wl_surface_attach (mVideoSurfaceWrapper, NULL, 0, 0);
1821 wl_surface_commit (mVideoSurfaceWrapper);
1822 wl_surface_attach (mAreaSurfaceWrapper, NULL, 0, 0);
1823 wl_surface_commit (mAreaSurfaceWrapper);
fei.deng640c3c92024-04-12 08:31:19 +00001824}
1825
1826void WaylandDisplay::setKeepLastFrame(int keep)
1827{
1828 mKeepLastFrame = keep;
1829 if (mVideoSurfaceWrapper && mAmlConfigAPIList.enableKeepLastFrame) {
1830 INFO(mLogCategory,"keep last frame:%d",keep);
1831 wl_surface_keep_last_frame(mVideoSurfaceWrapper, keep);
fei.deng4029e682024-06-26 17:06:31 +08001832 mToSendKeepLastFrame = false;
1833 return;
fei.deng640c3c92024-04-12 08:31:19 +00001834 }
fei.deng4029e682024-06-26 17:06:31 +08001835 mToSendKeepLastFrame = true;
fei.deng6c425232024-07-19 16:15:31 +08001836}
1837
le.hane8c8fdd2024-09-19 09:28:50 +00001838void WaylandDisplay::setKeepLastFrameOnFlush(int keepOnFlush)
1839{
1840 mKeepFrameOnFlush = keepOnFlush;
1841 INFO(mLogCategory,"keep last frame:%d",mKeepFrameOnFlush);
1842 if (mVideoSurfaceWrapper && !mKeepFrameOnFlush) {
1843 INFO(mLogCategory,"mute video plane");
1844 wl_surface_set_video_plane_mute(mVideoSurfaceWrapper, 1);
1845 }
1846}
1847
le.han15dacdd2024-09-18 05:46:09 +00001848void WaylandDisplay::setImmediatelyOutput(int enable)
1849{
1850 if (mVideoSurfaceWrapper) {
1851 wl_surface_enable_ll_mode(mVideoSurfaceWrapper, enable);
1852 }
1853 INFO(mLogCategory,"set immediately output:%d", enable);
1854}
1855
fei.deng6c425232024-07-19 16:15:31 +08001856void WaylandDisplay::setFrameRate(int frameRateNum, int frameRateDenom)
1857{
1858 mFrameRateFractionNum = frameRateNum;
1859 mFrameRateFractionDenom = frameRateDenom;
1860 if (mFrameRateFractionDenom == 0) {
1861 mFrameRateFractionDenom = 1;
1862 }
fei.deng649b0e22024-09-03 18:57:13 +08001863
1864 if (mFrameRateFractionNum > 0) {
1865 mFrameDurationUs = 1000000 * mFrameRateFractionDenom/mFrameRateFractionNum;
1866 mFrameRateChanged = true;
fei.deng6c425232024-07-19 16:15:31 +08001867 }
fei.deng649b0e22024-09-03 18:57:13 +08001868
1869 INFO(mLogCategory,"num:%d,denom:%d,frame dur:%lld us",
1870 mFrameRateFractionNum, mFrameRateFractionDenom,mFrameDurationUs);
fei.deng1c94a342024-08-05 19:33:28 +08001871}
1872
1873void WaylandDisplay::setVideoPlaneZorder(int zorder)
1874{
1875 mVideoPlaneZorder = zorder;
1876 mVideoPlaneZorderChanged = true;
1877 if (mVideoSurfaceWrapper) {
1878 mVideoPlaneZorderChanged = false;
1879 wl_surface_set_zorder(mVideoSurfaceWrapper, mVideoPlaneZorder);
1880 }
fei.deng649b0e22024-09-03 18:57:13 +08001881}
1882
1883void WaylandDisplay::pause()
1884{
1885 mLastDisplayFramePts = -1;
1886 mLastDisplayFrameTimeUs = -1;
1887}
1888void WaylandDisplay::resume()
1889{
1890
fei.dengf7a0cd32023-08-29 09:36:37 +00001891}