blob: d11f5171211e6eb03b84d604ee849856392d4d31 [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"
35
36void WaylandDisplay::dmabuf_modifiers(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
37 uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo)
38{
39 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
fei.dengb9a1a572023-09-13 01:33:57 +000040 Tls::Mutex::Autolock _l(self->mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +000041 if (wl_dmabuf_format_to_video_format (format) != VIDEO_FORMAT_UNKNOWN) {
fei.dengb9a1a572023-09-13 01:33:57 +000042 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 +000043 uint64_t modifier = ((uint64_t)modifier_hi << 32) | modifier_lo;
44 auto item = self->mDmaBufferFormats.find(format);
45 if (item == self->mDmaBufferFormats.end()) {
46 std::pair<uint32_t ,uint64_t> item(format, modifier);
47 self->mDmaBufferFormats.insert(item);
48 } else { //found format
49 item->second = modifier;
50 }
51 }
52}
53
54void
55WaylandDisplay::dmaBufferFormat (void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
56 uint32_t format)
57{
58#if 0
59 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
60
61 if (wl_dmabuf_format_to_video_format (format) != VIDEO_FORMAT_UNKNOWN) {
62 TRACE(mLogCategory,"regist dmabuffer format:%d : %s",format);
63 //self->mDmaBufferFormats.push_back(format);
64 }
65#endif
66 /* XXX: deprecated */
67}
68
69static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
70 WaylandDisplay::dmaBufferFormat,
71 WaylandDisplay::dmabuf_modifiers
72};
73
74static void
75handle_xdg_wm_base_ping (void *user_data, struct xdg_wm_base *xdg_wm_base,
76 uint32_t serial)
77{
78 xdg_wm_base_pong (xdg_wm_base, serial);
79}
80
81static const struct xdg_wm_base_listener xdg_wm_base_listener = {
82 handle_xdg_wm_base_ping
83};
84
85void WaylandDisplay::shmFormat(void *data, struct wl_shm *wl_shm, uint32_t format)
86{
87 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
88 self->mShmFormats.push_back(format);
89}
90
91static const struct wl_shm_listener shm_listener = {
92 WaylandDisplay::shmFormat
93};
94
95void WaylandDisplay::outputHandleGeometry( void *data,
96 struct wl_output *output,
97 int x,
98 int y,
99 int physicalWidth,
100 int physicalHeight,
101 int subPixel,
102 const char *make,
103 const char *model,
104 int transform )
105{
106 UNUSED_PARAM(make);
107 UNUSED_PARAM(model);
108
109 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
fei.dengb9a1a572023-09-13 01:33:57 +0000110 DEBUG(self->mLogCategory,"wl_output %p x:%d,y:%d,physicalWidth:%d,physicalHeight:%d,subPixel:%d,trans:%d",
111 output,x, y,physicalWidth, physicalHeight,subPixel,transform);
112 Tls::Mutex::Autolock _l(self->mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000113 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
114 if (output == self->mOutput[i].wlOutput) {
115 self->mOutput[i].offsetX = x;
116 self->mOutput[i].offsetY = y;
117 }
118 }
119}
120
121void WaylandDisplay::outputHandleMode( void *data,
122 struct wl_output *output,
123 uint32_t flags,
124 int width,
125 int height,
126 int refreshRate )
127{
128 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
129
130 if ( flags & WL_OUTPUT_MODE_CURRENT ) {
fei.dengb9a1a572023-09-13 01:33:57 +0000131 Tls::Mutex::Autolock _l(self->mMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000132 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
133 if (output == self->mOutput[i].wlOutput) {
134 self->mOutput[i].width = width;
135 self->mOutput[i].height = height;
136 self->mOutput[i].refreshRate = refreshRate;
137 }
138 }
fei.deng26950832023-11-09 03:00:23 +0000139
140 DEBUG(self->mLogCategory,"wl_output: %p (%dx%d) refreshrate:%d,select output index %d",output, width, height,refreshRate,self->mSelectOutputIndex);
141 if (self->mCurrentDisplayOutput->width > 0 &&
142 self->mCurrentDisplayOutput->height > 0) {
143 self->updateDisplayOutput();
fei.dengf7a0cd32023-08-29 09:36:37 +0000144 }
145 }
146}
147
148void WaylandDisplay::outputHandleDone( void *data,
149 struct wl_output *output )
150{
fei.dengf1f5fc32023-12-06 06:22:20 +0000151 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
152 DEBUG(self->mLogCategory,"wl_output: %p",output);
fei.dengf7a0cd32023-08-29 09:36:37 +0000153 UNUSED_PARAM(data);
154 UNUSED_PARAM(output);
155}
156
157void WaylandDisplay::outputHandleScale( void *data,
158 struct wl_output *output,
159 int32_t scale )
160{
fei.dengf1f5fc32023-12-06 06:22:20 +0000161 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
162 DEBUG(self->mLogCategory,"wl_output: %p scale %d",output, scale);
fei.dengf7a0cd32023-08-29 09:36:37 +0000163 UNUSED_PARAM(data);
164 UNUSED_PARAM(output);
165 UNUSED_PARAM(scale);
166}
167
fei.dengf1f5fc32023-12-06 06:22:20 +0000168void WaylandDisplay::outputHandleCrtcIndex( void *data,
169 struct wl_output *output,
170 int32_t index )
171{
172 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
173 DEBUG(self->mLogCategory,"wl_output: %p crtc index %d",output, index);
174 Tls::Mutex::Autolock _l(self->mMutex);
175 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
176 if (output == self->mOutput[i].wlOutput) {
177 self->mOutput[i].crtcIndex = index;
178 }
179 }
180}
181
fei.deng640c3c92024-04-12 08:31:19 +0000182//aml weston always add crtcIndex in callbacks.
fei.dengf7a0cd32023-08-29 09:36:37 +0000183static const struct wl_output_listener outputListener = {
184 WaylandDisplay::outputHandleGeometry,
185 WaylandDisplay::outputHandleMode,
186 WaylandDisplay::outputHandleDone,
fei.dengf1f5fc32023-12-06 06:22:20 +0000187 WaylandDisplay::outputHandleScale,
188 WaylandDisplay::outputHandleCrtcIndex,
fei.dengf7a0cd32023-08-29 09:36:37 +0000189};
190
191void WaylandDisplay::pointerHandleEnter(void *data, struct wl_pointer *pointer,
192 uint32_t serial, struct wl_surface *surface,
193 wl_fixed_t sx, wl_fixed_t sy)
194{
195 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
196
197 if (self->mFullScreen) {
198 wl_pointer_set_cursor(pointer, serial, NULL, 0, 0);
199 }
200}
201
202void WaylandDisplay::pointerHandleLeave(void *data, struct wl_pointer *pointer,
203 uint32_t serial, struct wl_surface *surface)
204{
205 UNUSED_PARAM(data);
206 UNUSED_PARAM(pointer);
207 UNUSED_PARAM(serial);
208 UNUSED_PARAM(surface);
209}
210
211void WaylandDisplay::pointerHandleMotion(void *data, struct wl_pointer *pointer,
212 uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
213{
214 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
215 int x = wl_fixed_to_int(sx);
216 int y = wl_fixed_to_int(sy);
fei.dengb9a1a572023-09-13 01:33:57 +0000217 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 +0000218}
219
220void WaylandDisplay::pointerHandleButton(void *data, struct wl_pointer *wl_pointer,
221 uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
222{
223 UNUSED_PARAM(data);
224 UNUSED_PARAM(wl_pointer);
225 UNUSED_PARAM(time);
226 UNUSED_PARAM(serial);
227 UNUSED_PARAM(button);
228 UNUSED_PARAM(state);
229}
230
231void WaylandDisplay::pointerHandleAxis(void *data, struct wl_pointer *wl_pointer,
232 uint32_t time, uint32_t axis, wl_fixed_t value)
233{
234 UNUSED_PARAM(data);
235 UNUSED_PARAM(wl_pointer);
236 UNUSED_PARAM(time);
237 UNUSED_PARAM(axis);
238 UNUSED_PARAM(value);
239}
240
241static const struct wl_pointer_listener pointer_listener = {
242 WaylandDisplay::pointerHandleEnter,
243 WaylandDisplay::pointerHandleLeave,
244 WaylandDisplay::pointerHandleMotion,
245 WaylandDisplay::pointerHandleButton,
246 WaylandDisplay::pointerHandleAxis,
247};
248
249void WaylandDisplay::touchHandleDown(void *data, struct wl_touch *wl_touch,
250 uint32_t serial, uint32_t time, struct wl_surface *surface,
251 int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
252{
253 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
254}
255
256void WaylandDisplay::touchHandleUp(void *data, struct wl_touch *wl_touch,
257 uint32_t serial, uint32_t time, int32_t id)
258{
259 UNUSED_PARAM(data);
260 UNUSED_PARAM(wl_touch);
261 UNUSED_PARAM(serial);
262 UNUSED_PARAM(time);
263 UNUSED_PARAM(id);
264}
265
266void WaylandDisplay::touchHandleMotion(void *data, struct wl_touch *wl_touch,
267 uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
268{
269 UNUSED_PARAM(data);
270 UNUSED_PARAM(wl_touch);
271 UNUSED_PARAM(time);
272 UNUSED_PARAM(id);
273 UNUSED_PARAM(x_w);
274 UNUSED_PARAM(y_w);
275}
276
277void WaylandDisplay::touchHandleFrame(void *data, struct wl_touch *wl_touch)
278{
279 UNUSED_PARAM(data);
280 UNUSED_PARAM(wl_touch);
281}
282
283void WaylandDisplay::touchHandleCancel(void *data, struct wl_touch *wl_touch)
284{
285 UNUSED_PARAM(data);
286 UNUSED_PARAM(wl_touch);
287}
288
289static const struct wl_touch_listener touch_listener = {
290 WaylandDisplay::touchHandleDown,
291 WaylandDisplay::touchHandleUp,
292 WaylandDisplay::touchHandleMotion,
293 WaylandDisplay::touchHandleFrame,
294 WaylandDisplay::touchHandleCancel,
295};
296
297void WaylandDisplay::keyboardHandleKeymap(void *data, struct wl_keyboard *keyboard,
298 uint32_t format, int fd, uint32_t size)
299{
300 UNUSED_PARAM(data);
301 UNUSED_PARAM(keyboard);
302 UNUSED_PARAM(format);
303 UNUSED_PARAM(fd);
304 UNUSED_PARAM(size);
305}
306
307void WaylandDisplay::keyboardHandleEnter(void *data, struct wl_keyboard *keyboard,
308 uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
309{
310 UNUSED_PARAM(data);
311 UNUSED_PARAM(keyboard);
312 UNUSED_PARAM(serial);
313 UNUSED_PARAM(surface);
314 UNUSED_PARAM(keys);
315}
316
317void WaylandDisplay::keyboardHandleLeave(void *data, struct wl_keyboard *keyboard,
318 uint32_t serial, struct wl_surface *surface)
319{
320 UNUSED_PARAM(data);
321 UNUSED_PARAM(keyboard);
322 UNUSED_PARAM(serial);
323 UNUSED_PARAM(surface);
324}
325
326void WaylandDisplay::keyboardHandleKey(void *data, struct wl_keyboard *keyboard,
327 uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
328{
329 UNUSED_PARAM(data);
330 UNUSED_PARAM(keyboard);
331 UNUSED_PARAM(serial);
332 UNUSED_PARAM(time);
333 UNUSED_PARAM(key);
334 UNUSED_PARAM(state);
335}
336
337void WaylandDisplay::keyboardHandleModifiers(void *data, struct wl_keyboard *keyboard,
338 uint32_t serial, uint32_t mods_depressed,
339 uint32_t mods_latched, uint32_t mods_locked,
340 uint32_t group)
341{
342 UNUSED_PARAM(data);
343 UNUSED_PARAM(keyboard);
344 UNUSED_PARAM(serial);
345 UNUSED_PARAM(mods_depressed);
346 UNUSED_PARAM(mods_latched);
347 UNUSED_PARAM(mods_locked);
348 UNUSED_PARAM(group);
349}
350
351static const struct wl_keyboard_listener keyboard_listener = {
352 WaylandDisplay::keyboardHandleKeymap,
353 WaylandDisplay::keyboardHandleEnter,
354 WaylandDisplay::keyboardHandleLeave,
355 WaylandDisplay::keyboardHandleKey,
356 WaylandDisplay::keyboardHandleModifiers,
357};
358
359void WaylandDisplay::seatHandleCapabilities(void *data, struct wl_seat *seat,
360 uint32_t caps)
361{
362 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
363 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !self->mPointer) {
364 self->mPointer = wl_seat_get_pointer(seat);
365 wl_pointer_add_listener(self->mPointer, &pointer_listener, data);
366 } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && self->mPointer) {
367 wl_pointer_destroy(self->mPointer);
368 self->mPointer = NULL;
369 }
370
371 if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !self->mKeyboard) {
372 self->mKeyboard = wl_seat_get_keyboard(seat);
373 wl_keyboard_add_listener(self->mKeyboard, &keyboard_listener, data);
374 } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && self->mKeyboard) {
375 wl_keyboard_destroy(self->mKeyboard);
376 self->mKeyboard = NULL;
377 }
378
379 if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !self->mTouch) {
380 self->mTouch = wl_seat_get_touch(seat);
381 wl_touch_set_user_data(self->mTouch, data);
382 wl_touch_add_listener(self->mTouch, &touch_listener, data);
383 } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && self->mTouch) {
384 wl_touch_destroy(self->mTouch);
385 self->mTouch = NULL;
386 }
387}
388
389static const struct wl_seat_listener seat_listener = {
390 WaylandDisplay::seatHandleCapabilities,
391};
392
393
394void WaylandDisplay::handleXdgToplevelClose (void *data, struct xdg_toplevel *xdg_toplevel)
395{
396 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
397
fei.dengb9a1a572023-09-13 01:33:57 +0000398 INFO(self->mLogCategory,"XDG toplevel got a close event.");
fei.dengf7a0cd32023-08-29 09:36:37 +0000399}
400
401void WaylandDisplay::handleXdgToplevelConfigure (void *data, struct xdg_toplevel *xdg_toplevel,
402 int32_t width, int32_t height, struct wl_array *states)
403{
404 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
405 uint32_t *state;
406
fei.dengb9a1a572023-09-13 01:33:57 +0000407 INFO(self->mLogCategory, "XDG toplevel got a configure event, width:height [ %d, %d ].", width, height);
fei.dengf7a0cd32023-08-29 09:36:37 +0000408 /*
409 wl_array_for_each (state, states) {
410 switch (*state) {
411 case XDG_TOPLEVEL_STATE_FULLSCREEN:
412 case XDG_TOPLEVEL_STATE_MAXIMIZED:
413 case XDG_TOPLEVEL_STATE_RESIZING:
414 case XDG_TOPLEVEL_STATE_ACTIVATED:
415 break;
416 }
417 }
418 */
419
420 if (width <= 0 || height <= 0)
421 return;
422
fei.deng26950832023-11-09 03:00:23 +0000423 if (width == self->mCurrentDisplayOutput->width && height == self->mCurrentDisplayOutput->height && self->mUpdateRenderRectangle) {
424 self->mUpdateRenderRectangle = false;
425 self->setRenderRectangle(self->mCurrentDisplayOutput->offsetX,
426 self->mCurrentDisplayOutput->offsetY,
427 self->mCurrentDisplayOutput->width,
428 self->mCurrentDisplayOutput->height);
fei.dengf7a0cd32023-08-29 09:36:37 +0000429 } else{
430 self->setRenderRectangle(self->mRenderRect.x, self->mRenderRect.y, width, height);
431 }
432}
433
434static const struct xdg_toplevel_listener xdg_toplevel_listener = {
435 WaylandDisplay::handleXdgToplevelConfigure,
436 WaylandDisplay::handleXdgToplevelClose,
437};
438
439void WaylandDisplay::handleXdgSurfaceConfigure (void *data, struct xdg_surface *xdg_surface,
440 uint32_t serial)
441{
442 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
443 xdg_surface_ack_configure (xdg_surface, serial);
444
fei.dengb9a1a572023-09-13 01:33:57 +0000445 TRACE(self->mLogCategory,"handleXdgSurfaceConfigure");
446 Tls::Mutex::Autolock _l(self->mConfigureMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +0000447 self->mXdgSurfaceConfigured = true;
fei.deng26950832023-11-09 03:00:23 +0000448 self->updateDisplayOutput();
fei.dengf7a0cd32023-08-29 09:36:37 +0000449}
450
451static const struct xdg_surface_listener xdg_surface_listener = {
452 WaylandDisplay::handleXdgSurfaceConfigure,
453};
454
fei.dengd0da4e22024-07-04 11:29:13 +0800455void WaylandDisplay::handleSurfaceDestroy(void *data, struct wl_callback *callback, uint32_t time)
456{
457 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
458 INFO(self->mLogCategory,"handle video surface destroy");
459 Tls::Mutex::Autolock _l(self->mMutex);
460 self->mCondition.signal();
461 wl_callback_destroy (callback);
462}
463
464static const struct wl_callback_listener surface_destroy_listener = {
465 WaylandDisplay::handleSurfaceDestroy,
466};
467
fei.deng640c3c92024-04-12 08:31:19 +0000468void WaylandDisplay::amlConfigure(void *data, struct aml_config *config, const char *list) {
469 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
470 TRACE(self->mLogCategory,"aml_config:%s",list);
471 if (list && strlen(list) > 0) {
472 if (strstr(list, "set_video_plane")) {
473 TRACE(self->mLogCategory,"weston enable set_video_plane");
474 self->mAmlConfigAPIList.enableSetVideoPlane = true;
475 }
476 if (strstr(list, "set_pts")) {
477 TRACE(self->mLogCategory,"weston enable set_pts");
478 self->mAmlConfigAPIList.enableSetPts = true;
479 }
480 if (strstr(list, "drop")) {
481 TRACE(self->mLogCategory,"weston enable drop");
482 self->mAmlConfigAPIList.enableDropFrame = true;
483 }
484 if (strstr(list, "keep_last_frame")) {
485 TRACE(self->mLogCategory,"weston enable keep_last_frame");
486 self->mAmlConfigAPIList.enableKeepLastFrame = true;
487 }
fei.dengd0da4e22024-07-04 11:29:13 +0800488 if (strstr(list, "surface_destroy_cb")) {
489 TRACE(self->mLogCategory,"weston enable surface_destroy_cb");
490 self->mAmlConfigAPIList.enableSurfaceDestroyCallback = true;
491 }
fei.deng6c425232024-07-19 16:15:31 +0800492 if (strstr(list, "set_display_rate")) {
493 TRACE(self->mLogCategory,"weston enable set_display_rate");
494 self->mAmlConfigAPIList.enableSetDisplayRate = true;
495 }
fei.deng9bf724e2024-08-01 11:34:52 +0800496 if (strstr(list, "set_surface_invisible")) {
497 TRACE(self->mLogCategory,"weston enable set_surface_invisible");
498 self->mAmlConfigAPIList.enableSetSurfaceInvisible = true;
499 }
fei.deng640c3c92024-04-12 08:31:19 +0000500 }
501}
502
503static const struct aml_config_listener aml_config_listener = {
504 WaylandDisplay::amlConfigure,
505};
506
fei.dengf7a0cd32023-08-29 09:36:37 +0000507void
508WaylandDisplay::registryHandleGlobal (void *data, struct wl_registry *registry,
fei.dengaf9b07d2023-10-10 07:38:40 +0000509 uint32_t name, const char *interface, uint32_t version)
fei.dengf7a0cd32023-08-29 09:36:37 +0000510{
511 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
fei.dengaf9b07d2023-10-10 07:38:40 +0000512 TRACE(self->mLogCategory,"registryHandleGlobal,name:%u,interface:%s,version:%d",name,interface,version);
fei.dengf7a0cd32023-08-29 09:36:37 +0000513
514 if (strcmp (interface, "wl_compositor") == 0) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000515 self->mCompositor = (struct wl_compositor *)wl_registry_bind (registry, name, &wl_compositor_interface, 1/*MIN (version, 3)*/);
fei.dengf7a0cd32023-08-29 09:36:37 +0000516 } else if (strcmp (interface, "wl_subcompositor") == 0) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000517 self->mSubCompositor = (struct wl_subcompositor *)wl_registry_bind (registry, name, &wl_subcompositor_interface, 1);
fei.dengf7a0cd32023-08-29 09:36:37 +0000518 } else if (strcmp (interface, "xdg_wm_base") == 0) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000519 self->mXdgWmBase = (struct xdg_wm_base *)wl_registry_bind (registry, name, &xdg_wm_base_interface, 1);
fei.dengf7a0cd32023-08-29 09:36:37 +0000520 xdg_wm_base_add_listener (self->mXdgWmBase, &xdg_wm_base_listener, (void *)self);
521 } else if (strcmp (interface, "wl_shm") == 0) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000522 self->mShm = (struct wl_shm *)wl_registry_bind (registry, name, &wl_shm_interface, 1);
fei.dengf7a0cd32023-08-29 09:36:37 +0000523 wl_shm_add_listener (self->mShm, &shm_listener, self);
524 } else if (strcmp (interface, "zwp_fullscreen_shell_v1") == 0) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000525 //self->mFullscreenShell = (struct zwp_fullscreen_shell_v1 *)wl_registry_bind (registry, name,
fei.dengf7a0cd32023-08-29 09:36:37 +0000526 // &zwp_fullscreen_shell_v1_interface, 1);
527 } else if (strcmp (interface, "wp_viewporter") == 0) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000528 self->mViewporter = (struct wp_viewporter *)wl_registry_bind (registry, name, &wp_viewporter_interface, 1);
fei.dengf7a0cd32023-08-29 09:36:37 +0000529 } else if (strcmp (interface, "zwp_linux_dmabuf_v1") == 0) {
530 if (version < 3)
531 return;
fei.dengaf9b07d2023-10-10 07:38:40 +0000532 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 +0000533 zwp_linux_dmabuf_v1_add_listener (self->mDmabuf, &dmabuf_listener, (void *)self);
534 } else if (strcmp (interface, "wl_output") == 0) {
fei.deng26950832023-11-09 03:00:23 +0000535 int i = 0;
536 uint32_t oriName = self->mCurrentDisplayOutput->name;
fei.dengaf9b07d2023-10-10 07:38:40 +0000537 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
538 if (self->mOutput[i].wlOutput == NULL) {
539 self->mOutput[i].name = name;
540 self->mOutput[i].wlOutput = (struct wl_output*)wl_registry_bind(registry, name, &wl_output_interface, version);
fei.deng26950832023-11-09 03:00:23 +0000541 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 +0000542 wl_output_add_listener(self->mOutput[i].wlOutput, &outputListener, (void *)self);
543 if (i == 0) { //primary wl_output
544 self->mOutput[i].isPrimary = true;
545 }
fei.deng26950832023-11-09 03:00:23 +0000546 break;
fei.dengaf9b07d2023-10-10 07:38:40 +0000547 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000548 }
fei.deng26950832023-11-09 03:00:23 +0000549 if (i == DEFAULT_DISPLAY_OUTPUT_NUM) {
550 WARNING(self->mLogCategory,"Not enough free output");
551 }
552 //select current wl_output
553 if (self->mSelectOutputIndex != INVALID_OUTPUT_INDEX && !self->isRunning()) {
554 TRACE(self->mLogCategory,"select %d output",self->mSelectOutputIndex);
555 self->mCurrentDisplayOutput = &self->mOutput[self->mSelectOutputIndex];
556 }
557 //if user select a wrong output index, we using a suiteble wl_output
558 if (self->mCurrentDisplayOutput->wlOutput == NULL) {
559 WARNING(self->mLogCategory,"wl_output is null,we should find a suiteble output");
560 for (i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
561 if (self->mOutput[i].wlOutput) {
562 self->mCurrentDisplayOutput = &self->mOutput[i];
563 break;
564 }
565 }
566 }
567 //if current wl_output update, we should update render rectangle
568 if (self->mCurrentDisplayOutput->name != oriName) {
569 self->mUpdateRenderRectangle = true;
570 }
571 //if wl_output plugin,active sending frame
572 self->setRedrawingPending(false);
fei.dengf7a0cd32023-08-29 09:36:37 +0000573 } else if (strcmp(interface, "wl_seat") == 0) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000574 //self->mSeat = (struct wl_seat *)wl_registry_bind(registry, name, &wl_seat_interface, 1);
fei.dengf7a0cd32023-08-29 09:36:37 +0000575 //wl_seat_add_listener(self->mSeat, &seat_listener, (void *)self);
fei.deng31f93f12024-02-27 07:52:10 +0000576 } else if (strcmp(interface, "weston_direct_display_v1") == 0) {
577 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 +0000578 } else if (strcmp(interface, "aml_config") == 0) {
579 self->mAmlConfig = (struct aml_config*)wl_registry_bind(registry, name, &aml_config_interface, 1);
580 aml_config_add_listener(self->mAmlConfig, &aml_config_listener, (void *)self);
fei.dengf7a0cd32023-08-29 09:36:37 +0000581 }
582}
583
584void
585WaylandDisplay::registryHandleGlobalRemove (void *data, struct wl_registry *registry, uint32_t name)
586{
fei.deng26950832023-11-09 03:00:23 +0000587 int i;
fei.dengf7a0cd32023-08-29 09:36:37 +0000588 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
fei.dengaf9b07d2023-10-10 07:38:40 +0000589 /* check wl_output changed */
590 DEBUG(self->mLogCategory,"wayland display remove registry handle global,name:%u",name);
fei.deng26950832023-11-09 03:00:23 +0000591 //if user selected wl_output removed, reset selected output index
592 if (self->mSelectOutputIndex != INVALID_OUTPUT_INDEX &&
593 self->mOutput[self->mSelectOutputIndex].wlOutput &&
594 self->mOutput[self->mSelectOutputIndex].name == name) {
595 self->mSelectOutputIndex = INVALID_OUTPUT_INDEX;
596 }
597 for (i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
fei.dengaf9b07d2023-10-10 07:38:40 +0000598 if (self->mOutput[i].name == name) {
fei.deng26950832023-11-09 03:00:23 +0000599 DEBUG(self->mLogCategory,"remove wl_output name:%u,wl_output:%p",name,self->mOutput[i].wlOutput);
fei.dengaf9b07d2023-10-10 07:38:40 +0000600 self->mOutput[i].name = 0;
601 self->mOutput[i].wlOutput = NULL;
fei.deng26950832023-11-09 03:00:23 +0000602 }
603 }
604 //if current output removed, select a suiteble output
605 if (self->mCurrentDisplayOutput->wlOutput == NULL) {
606 for (i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
607 if (self->mOutput[i].wlOutput) {
608 self->mCurrentDisplayOutput = &self->mOutput[i];
609 self->mUpdateRenderRectangle = true;
610 }
611 }
612 //set new output rectangle
613 if (self->mUpdateRenderRectangle) {
614 self->mUpdateRenderRectangle = false;
615 self->setRenderRectangle(self->mCurrentDisplayOutput->offsetX,
616 self->mCurrentDisplayOutput->offsetY,
617 self->mCurrentDisplayOutput->width,
618 self->mCurrentDisplayOutput->height);
fei.dengaf9b07d2023-10-10 07:38:40 +0000619 }
620 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000621}
622
623static const struct wl_registry_listener registry_listener = {
624 WaylandDisplay::registryHandleGlobal,
625 WaylandDisplay::registryHandleGlobalRemove
626};
627
fei.dengb9a1a572023-09-13 01:33:57 +0000628WaylandDisplay::WaylandDisplay(WaylandPlugin *plugin, int logCategory)
629 :mBufferMutex("bufferMutex"),
630 mWaylandPlugin(plugin),
631 mLogCategory(logCategory)
fei.dengf7a0cd32023-08-29 09:36:37 +0000632{
fei.dengb9a1a572023-09-13 01:33:57 +0000633 TRACE(mLogCategory,"construct WaylandDisplay");
fei.dengf7a0cd32023-08-29 09:36:37 +0000634 mWlDisplay = NULL;
635 mWlDisplayWrapper = NULL;
636 mWlQueue = NULL;
637 mRegistry = NULL;
638 mCompositor = NULL;
639 mXdgWmBase = NULL;
640 mViewporter = NULL;
641 mDmabuf = NULL;
642 mShm = NULL;
643 mSeat = NULL;
644 mPointer = NULL;
645 mTouch = NULL;
646 mKeyboard = NULL;
fei.deng31f93f12024-02-27 07:52:10 +0000647 mDirect_display = NULL;
fei.deng26950832023-11-09 03:00:23 +0000648 mSelectOutputIndex = INVALID_OUTPUT_INDEX;
fei.dengb9a1a572023-09-13 01:33:57 +0000649 mPoll = new Tls::Poll(true);
fei.dengf7a0cd32023-08-29 09:36:37 +0000650 //window
651 mVideoWidth = 0;
652 mVideoHeight = 0;
653 mVideoSurface = NULL;
654 mXdgSurface = NULL;
655 mXdgToplevel = NULL;
656 mAreaViewport = NULL;
657 mVideoViewport = NULL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000658 mAreaShmBuffer = NULL;
659 mCommitCnt = 0;
fei.dengf7a0cd32023-08-29 09:36:37 +0000660 mAreaSurface = NULL;
661 mAreaSurfaceWrapper = NULL;
662 mVideoSurfaceWrapper = NULL;
663 mVideoSubSurface = NULL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000664 mPip = 0;
fei.deng640c3c92024-04-12 08:31:19 +0000665 mKeepLastFrame = 0; //default is off keep last frame
fei.deng3287c082024-04-23 09:29:22 +0000666 mSignalFirstFramePts = false;
fei.deng4029e682024-06-26 17:06:31 +0800667 mToSendKeepLastFrame = false;
fei.deng1c94a342024-08-05 19:33:28 +0800668 mVideoPlaneZorder = -1;
669 mVideoPlaneZorderChanged = false;
fei.dengf7a0cd32023-08-29 09:36:37 +0000670}
671
672WaylandDisplay::~WaylandDisplay()
673{
fei.dengb9a1a572023-09-13 01:33:57 +0000674 TRACE(mLogCategory,"desconstruct WaylandDisplay");
675 if (mPoll) {
676 delete mPoll;
677 mPoll = NULL;
678 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000679}
680
681char *WaylandDisplay::require_xdg_runtime_dir()
682{
683 char *val = getenv("XDG_RUNTIME_DIR");
fei.dengb9a1a572023-09-13 01:33:57 +0000684 INFO(mLogCategory,"XDG_RUNTIME_DIR=%s",val);
fei.dengdd910ef2024-06-07 10:25:30 +0800685 //if not set XDG_RUNTIME_DIR,set default value
686 // if (!val) {
687 // val = const_cast<char *>("/run/user/0");
688 // setenv("XDG_RUNTIME_DIR",val,0);
689 // WARNING(mLogCategory,"XDG_RUNTIME_DIR is not set,set default %s",val);
690 // }
fei.dengf7a0cd32023-08-29 09:36:37 +0000691
692 return val;
693}
694
695int WaylandDisplay::openDisplay()
696{
fei.denga4abbd52024-07-11 19:17:50 +0800697 mPixelAspectRatio = 1.0;
698 mUpdateVideoSurface = false;
fei.dengdd910ef2024-06-07 10:25:30 +0800699 mNoBorderUpdate = false;
700 mReCommitAreaSurface = false;
701 mXdgSurfaceConfigured = false;
702 mUpdateRenderRectangle = false;
fei.deng6c425232024-07-19 16:15:31 +0800703 mFrameRateFractionNum = 0;
704 mFrameRateFractionDenom = 1;
705 mFrameRateChanged = false;
fei.deng1c94a342024-08-05 19:33:28 +0800706 mVideoPlaneZorder = -1;
707 mVideoPlaneZorderChanged = false;
fei.dengdd910ef2024-06-07 10:25:30 +0800708 memset(&mRenderRect, 0, sizeof(struct Rectangle));
709 memset(&mVideoRect, 0, sizeof(struct Rectangle));
710 memset(&mWindowRect, 0, sizeof(struct Rectangle));
711 mFullScreen = true; //default is full screen
712 mAmlConfig = NULL;
713 //weston config private api
714 mAmlConfigAPIList.enableDropFrame = false;
715 mAmlConfigAPIList.enableKeepLastFrame = false;
716 mAmlConfigAPIList.enableSetPts = false;
717 mAmlConfigAPIList.enableSetVideoPlane = false;
fei.dengd0da4e22024-07-04 11:29:13 +0800718 mAmlConfigAPIList.enableSurfaceDestroyCallback = false;
fei.deng6c425232024-07-19 16:15:31 +0800719 mAmlConfigAPIList.enableSetDisplayRate = false;
fei.deng9bf724e2024-08-01 11:34:52 +0800720 mAmlConfigAPIList.enableSetSurfaceInvisible = false;
fei.dengdd910ef2024-06-07 10:25:30 +0800721 mCurrentDisplayOutput = &mOutput[0];
722 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
723 mOutput[i].wlOutput = NULL;
724 mOutput[i].offsetX = 0;
725 mOutput[i].offsetY = 0;
726 mOutput[i].width = 0;
727 mOutput[i].height = 0;
728 mOutput[i].refreshRate = 0;
729 mOutput[i].isPrimary = false;
730 mOutput[i].name = 0;
731 mOutput[i].crtcIndex = 0;
732 }
fei.deng4029e682024-06-26 17:06:31 +0800733 /*if mKeepLastFrame had set but mToSendKeepLastFrame is false,maybe
734 playback is doing FF/FW action,so we keep set it on new connection*/
735 if (!mToSendKeepLastFrame && mKeepLastFrame) {
736 mToSendKeepLastFrame = true;
737 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000738 char *name = require_xdg_runtime_dir();
739 //DEBUG(mLogCategory,"name:%s",name);
fei.dengb9a1a572023-09-13 01:33:57 +0000740 DEBUG(mLogCategory,"openDisplay in");
fei.dengf7a0cd32023-08-29 09:36:37 +0000741 mWlDisplay = wl_display_connect(NULL);
742 if (!mWlDisplay) {
fei.dengb9a1a572023-09-13 01:33:57 +0000743 ERROR(mLogCategory,"Failed to connect to the wayland display, XDG_RUNTIME_DIR='%s'",
fei.dengf7a0cd32023-08-29 09:36:37 +0000744 name ? name : "NULL");
fei.dengb9a1a572023-09-13 01:33:57 +0000745 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000746 }
747
748 mWlDisplayWrapper = (struct wl_display *)wl_proxy_create_wrapper ((void *)mWlDisplay);
749 mWlQueue = wl_display_create_queue (mWlDisplay);
750 wl_proxy_set_queue ((struct wl_proxy *)mWlDisplayWrapper, mWlQueue);
751
752 mRegistry = wl_display_get_registry (mWlDisplayWrapper);
753 wl_registry_add_listener (mRegistry, &registry_listener, (void *)this);
754
755 /* we need exactly 2 roundtrips to discover global objects and their state */
756 for (int i = 0; i < 2; i++) {
757 if (wl_display_roundtrip_queue (mWlDisplay, mWlQueue) < 0) {
fei.dengb9a1a572023-09-13 01:33:57 +0000758 ERROR(mLogCategory,"Error communicating with the wayland display");
759 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000760 }
761 }
762
763 if (!mCompositor) {
fei.dengb9a1a572023-09-13 01:33:57 +0000764 ERROR(mLogCategory,"Could not bind to wl_compositor. Either it is not implemented in " \
fei.dengf7a0cd32023-08-29 09:36:37 +0000765 "the compositor, or the implemented version doesn't match");
fei.dengb9a1a572023-09-13 01:33:57 +0000766 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000767 }
768
769 if (!mDmabuf) {
fei.dengb9a1a572023-09-13 01:33:57 +0000770 ERROR(mLogCategory,"Could not bind to zwp_linux_dmabuf_v1");
771 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000772 }
773
774 if (!mXdgWmBase) {
775 /* If wl_surface and wl_display are passed via GstContext
776 * wl_shell, xdg_shell and zwp_fullscreen_shell are not used.
777 * In this case is correct to continue.
778 */
fei.dengb9a1a572023-09-13 01:33:57 +0000779 ERROR(mLogCategory,"Could not bind to either wl_shell, xdg_wm_base or "
fei.dengf7a0cd32023-08-29 09:36:37 +0000780 "zwp_fullscreen_shell, video display may not work properly.");
fei.dengb9a1a572023-09-13 01:33:57 +0000781 return ERROR_OPEN_FAIL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000782 }
783
784 //create window surface
785 createCommonWindowSurface();
786 createXdgShellWindowSurface();
787
788 //config weston video plane
fei.deng640c3c92024-04-12 08:31:19 +0000789 if (mAmlConfigAPIList.enableSetVideoPlane) {
fei.dengb9a1a572023-09-13 01:33:57 +0000790 INFO(mLogCategory,"set weston video plane:%d",mPip);
fei.dengf7a0cd32023-08-29 09:36:37 +0000791 wl_surface_set_video_plane(mVideoSurfaceWrapper, mPip);
792 }
793
794 //run wl display queue dispatch
fei.dengb9a1a572023-09-13 01:33:57 +0000795 DEBUG(mLogCategory,"To run wl display dispatch queue");
fei.dengdd910ef2024-06-07 10:25:30 +0800796 if (mPoll) {
797 mPoll->setFlushing(false);
798 }
fei.dengf7a0cd32023-08-29 09:36:37 +0000799 run("display queue");
800 mRedrawingPending = false;
801
fei.dengb9a1a572023-09-13 01:33:57 +0000802 DEBUG(mLogCategory,"openDisplay out");
803 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000804}
805
806void WaylandDisplay::closeDisplay()
807{
fei.dengb9a1a572023-09-13 01:33:57 +0000808 DEBUG(mLogCategory,"closeDisplay in");
fei.dengf7a0cd32023-08-29 09:36:37 +0000809
fei.dengd0da4e22024-07-04 11:29:13 +0800810 //first destroy window surface
811 destroyWindowSurfaces();
fei.dengf7a0cd32023-08-29 09:36:37 +0000812
fei.deng4029e682024-06-26 17:06:31 +0800813 //flush pending event to weston
fei.dengdd910ef2024-06-07 10:25:30 +0800814 if (mWlDisplay) {
815 wl_display_flush (mWlDisplay);
816 }
817
fei.dengd0da4e22024-07-04 11:29:13 +0800818 //wait video surface destroyed or 50ms timeout
819 if (mAmlConfigAPIList.enableSurfaceDestroyCallback) {
820 INFO(mLogCategory,"waiting surface_destroy_cb from weston");
821 Tls::Mutex::Autolock _l(mMutex);
822 if (ERROR_TIMED_OUT == mCondition.waitRelative(mMutex, 50/*microsecond*/)) {
823 WARNING(mLogCategory,"waited surface_destroy_cb timeout");
824 }
825 }
826
827 //we should receive all event from weston before stopped dispatch queue
828 if (isRunning()) {
829 TRACE(mLogCategory,"try stop dispatch thread");
830 if (mPoll) {
831 mPoll->setFlushing(true);
832 }
833 requestExitAndWait();
834 }
835 //after destroyed surface,then destroy buffers,otherwise maybe crash
836 if (mAreaShmBuffer) {
837 delete mAreaShmBuffer;
838 mAreaShmBuffer = NULL;
839 }
840
841 //clean all wayland buffers
842 cleanAllWaylandBuffer();
fei.dengf7a0cd32023-08-29 09:36:37 +0000843
844 if (mViewporter) {
845 wp_viewporter_destroy (mViewporter);
846 mViewporter = NULL;
847 }
848
849 if (mDmabuf) {
850 zwp_linux_dmabuf_v1_destroy (mDmabuf);
851 mDmabuf = NULL;
852 }
853
854 if (mXdgWmBase) {
855 xdg_wm_base_destroy (mXdgWmBase);
856 mXdgWmBase = NULL;
857 }
858
859 if (mCompositor) {
860 wl_compositor_destroy (mCompositor);
861 mCompositor = NULL;
862 }
863
864 if (mSubCompositor) {
865 wl_subcompositor_destroy (mSubCompositor);
866 mSubCompositor = NULL;
867 }
868
869 if (mRegistry) {
870 wl_registry_destroy (mRegistry);
871 mRegistry= NULL;
872 }
873
874 if (mWlDisplayWrapper) {
875 wl_proxy_wrapper_destroy (mWlDisplayWrapper);
876 mWlDisplayWrapper = NULL;
877 }
878
fei.deng640c3c92024-04-12 08:31:19 +0000879 if (mAmlConfig) {
880 aml_config_destroy(mAmlConfig);
881 mAmlConfig = NULL;
882 }
883
fei.dengf7a0cd32023-08-29 09:36:37 +0000884 if (mWlQueue) {
885 wl_event_queue_destroy (mWlQueue);
886 mWlQueue = NULL;
887 }
888
889 if (mWlDisplay) {
890 wl_display_flush (mWlDisplay);
891 wl_display_disconnect (mWlDisplay);
892 mWlDisplay = NULL;
893 }
894
fei.dengb9a1a572023-09-13 01:33:57 +0000895 DEBUG(mLogCategory,"closeDisplay out");
fei.dengf7a0cd32023-08-29 09:36:37 +0000896}
897
898int WaylandDisplay::toDmaBufferFormat(RenderVideoFormat format, uint32_t *outDmaformat /*out param*/, uint64_t *outDmaformatModifiers /*out param*/)
899{
900 if (!outDmaformat || !outDmaformatModifiers) {
fei.dengb9a1a572023-09-13 01:33:57 +0000901 WARNING(mLogCategory,"NULL params");
902 return ERROR_PARAM_NULL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000903 }
904
905 *outDmaformat = 0;
906 *outDmaformatModifiers = 0;
907
908 uint32_t dmaformat = video_format_to_wl_dmabuf_format (format);
909 if (dmaformat == -1) {
fei.dengb9a1a572023-09-13 01:33:57 +0000910 ERROR(mLogCategory,"Error not found render video format:%d to wl dmabuf format",format);
911 return ERROR_NOT_FOUND;
fei.dengf7a0cd32023-08-29 09:36:37 +0000912 }
913
fei.dengb9a1a572023-09-13 01:33:57 +0000914 TRACE(mLogCategory,"render video format:%d -> dmabuf format:%d",format,dmaformat);
fei.dengf7a0cd32023-08-29 09:36:37 +0000915 *outDmaformat = (uint32_t)dmaformat;
916
917 /*get dmaformat and modifiers*/
918 auto item = mDmaBufferFormats.find(dmaformat);
919 if (item == mDmaBufferFormats.end()) { //not found
fei.dengb9a1a572023-09-13 01:33:57 +0000920 WARNING(mLogCategory,"Not found dmabuf for render video format :%d",format);
fei.dengf7a0cd32023-08-29 09:36:37 +0000921 *outDmaformatModifiers = 0;
fei.dengb9a1a572023-09-13 01:33:57 +0000922 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000923 }
924
925 *outDmaformatModifiers = (uint64_t)item->second;
926
fei.dengb9a1a572023-09-13 01:33:57 +0000927 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000928}
929
930int WaylandDisplay::toShmBufferFormat(RenderVideoFormat format, uint32_t *outformat)
931{
932 if (!outformat) {
fei.dengb9a1a572023-09-13 01:33:57 +0000933 WARNING(mLogCategory,"NULL params");
934 return ERROR_PARAM_NULL;
fei.dengf7a0cd32023-08-29 09:36:37 +0000935 }
936
937 *outformat = 0;
938
939 int shmformat = (int)video_format_to_wl_shm_format(format);
940 if (shmformat < 0) {
fei.dengb9a1a572023-09-13 01:33:57 +0000941 ERROR(mLogCategory,"Error not found render video format:%d to wl shmbuf format",format);
942 return ERROR_NOT_FOUND;
fei.dengf7a0cd32023-08-29 09:36:37 +0000943 }
944
945 for (auto item = mShmFormats.begin(); item != mShmFormats.end(); ++item) {
946 uint32_t registFormat = (uint32_t)*item;
947 if (registFormat == (uint32_t)shmformat) {
948 *outformat = registFormat;
fei.dengb9a1a572023-09-13 01:33:57 +0000949 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +0000950 }
951 }
952
fei.dengb9a1a572023-09-13 01:33:57 +0000953 return ERROR_NOT_FOUND;
fei.dengf7a0cd32023-08-29 09:36:37 +0000954}
955
956void WaylandDisplay::setVideoBufferFormat(RenderVideoFormat format)
957{
fei.dengb9a1a572023-09-13 01:33:57 +0000958 TRACE(mLogCategory,"set video buffer format: %d",format);
fei.dengf7a0cd32023-08-29 09:36:37 +0000959 mBufferFormat = format;
960};
961
962void WaylandDisplay::setDisplayOutput(int output)
963{
fei.dengb9a1a572023-09-13 01:33:57 +0000964 TRACE(mLogCategory,"select display output: %d",output);
fei.dengf7a0cd32023-08-29 09:36:37 +0000965 if (output < 0 || output >= DEFAULT_DISPLAY_OUTPUT_NUM) {
fei.dengb9a1a572023-09-13 01:33:57 +0000966 ERROR(mLogCategory, "display output index error,please set 0:primary or 1:extend,now:%d",output);
fei.dengf7a0cd32023-08-29 09:36:37 +0000967 return;
968 }
fei.deng26950832023-11-09 03:00:23 +0000969 //only do select output before video playing
970 if (mSelectOutputIndex != output) {
971 mSelectOutputIndex = output;
972 // if (mOutput[output].wlOutput) {
973 // mCurrentDisplayOutput = &mOutput[output];
974 // setRenderRectangle(mOutput[output].offsetX, mOutput[output].offsetY,
975 // mOutput[output].width, mOutput[output].height);
976 // }
fei.dengf7a0cd32023-08-29 09:36:37 +0000977 }
978}
979
980int WaylandDisplay::getDisplayOutput()
981{
fei.deng26950832023-11-09 03:00:23 +0000982 return mSelectOutputIndex == INVALID_OUTPUT_INDEX? 0: mSelectOutputIndex;
fei.dengf7a0cd32023-08-29 09:36:37 +0000983}
984
985void WaylandDisplay::setPip(int pip)
986{
fei.dengb9a1a572023-09-13 01:33:57 +0000987 INFO(mLogCategory,"set pip:%d",pip);
fei.dengf7a0cd32023-08-29 09:36:37 +0000988 mPip = pip;
989}
990
fei.deng26950832023-11-09 03:00:23 +0000991void WaylandDisplay::updateDisplayOutput()
992{
993 if (!mCurrentDisplayOutput->wlOutput || !mXdgToplevel || !mXdgSurface)
994 {
995 return;
996 }
997 if (mUpdateRenderRectangle) {
998 if (mFullScreen) {
999 DEBUG(mLogCategory,"unset full screen");
1000 xdg_toplevel_unset_fullscreen (mXdgToplevel);
1001 }
1002
1003 if (mXdgSurface) {
1004 DEBUG(mLogCategory,"set geometry");
1005 xdg_surface_set_window_geometry(mXdgSurface,
1006 mCurrentDisplayOutput->offsetX,
1007 mCurrentDisplayOutput->offsetY,
1008 mCurrentDisplayOutput->width,
1009 mCurrentDisplayOutput->height);
1010 }
1011
1012 if (mFullScreen && mXdgToplevel) {
1013 DEBUG(mLogCategory,"set full screen");
1014 xdg_toplevel_set_fullscreen (mXdgToplevel, mCurrentDisplayOutput->wlOutput);
1015 }
1016 setRenderRectangle(mCurrentDisplayOutput->offsetX, mCurrentDisplayOutput->offsetY,
1017 mCurrentDisplayOutput->width, mCurrentDisplayOutput->height);
1018 mUpdateRenderRectangle = false;
1019 }
1020}
1021
fei.dengf7a0cd32023-08-29 09:36:37 +00001022void WaylandDisplay::createCommonWindowSurface()
1023{
1024 struct wl_region *region;
1025
1026 mAreaSurface = wl_compositor_create_surface (mCompositor);
1027 mVideoSurface = wl_compositor_create_surface (mCompositor);
1028 mAreaSurfaceWrapper = (struct wl_surface *)wl_proxy_create_wrapper (mAreaSurface);
1029 mVideoSurfaceWrapper = (struct wl_surface *)wl_proxy_create_wrapper (mVideoSurface);
1030
1031 wl_proxy_set_queue ((struct wl_proxy *) mAreaSurfaceWrapper, mWlQueue);
1032 wl_proxy_set_queue ((struct wl_proxy *) mVideoSurfaceWrapper, mWlQueue);
1033
1034 /* embed video_surface in area_surface */
1035 mVideoSubSurface = wl_subcompositor_get_subsurface (mSubCompositor, mVideoSurface, mAreaSurface);
1036 wl_subsurface_set_desync (mVideoSubSurface);
1037
fei.dengd0da4e22024-07-04 11:29:13 +08001038 //add video surface callback to weston if weston enable this feature
1039 if (mVideoSurface && mAmlConfigAPIList.enableSurfaceDestroyCallback) {
1040 struct wl_callback *surfaceDestroyCb = wl_surface_destroy_callback(mVideoSurface);
1041 wl_callback_add_listener(surfaceDestroyCb, &surface_destroy_listener, this);
1042 }
1043
fei.dengf7a0cd32023-08-29 09:36:37 +00001044 if (mViewporter) {
1045 mAreaViewport = wp_viewporter_get_viewport (mViewporter, mAreaSurface);
1046 mVideoViewport = wp_viewporter_get_viewport (mViewporter, mVideoSurface);
1047 }
1048
fei.deng9bf724e2024-08-01 11:34:52 +08001049 /*set area surface to invisible. prevent frame droped at start playback,
1050 wl_surface_set_invisible must called before mAreaSurface commit called*/
1051 if (mAmlConfigAPIList.enableSetSurfaceInvisible) {
1052 int invisible = 1;
1053 INFO(mLogCategory,"set surface invisible:%d",invisible);
1054 wl_surface_set_invisible(mAreaSurfaceWrapper, invisible);
1055 }
1056
fei.dengf7a0cd32023-08-29 09:36:37 +00001057 /* do not accept input */
1058 region = wl_compositor_create_region (mCompositor);
1059 wl_surface_set_input_region (mAreaSurface, region);
1060 wl_region_destroy (region);
1061
1062 region = wl_compositor_create_region (mCompositor);
1063 wl_surface_set_input_region (mVideoSurface, region);
1064 wl_region_destroy (region);
1065}
1066
1067void WaylandDisplay::createXdgShellWindowSurface()
1068{
1069 /* Check which protocol we will use (in order of preference) */
1070 if (mXdgWmBase) {
1071 /* First create the XDG surface */
1072 mXdgSurface= xdg_wm_base_get_xdg_surface (mXdgWmBase, mAreaSurface);
1073 if (!mXdgSurface) {
fei.dengb9a1a572023-09-13 01:33:57 +00001074 ERROR(mLogCategory,"Unable to get xdg_surface");
fei.dengf7a0cd32023-08-29 09:36:37 +00001075 return;
1076 }
1077 xdg_surface_add_listener (mXdgSurface, &xdg_surface_listener,(void *)this);
1078
1079 /* Then the toplevel */
1080 mXdgToplevel= xdg_surface_get_toplevel (mXdgSurface);
1081 if (!mXdgSurface) {
fei.dengb9a1a572023-09-13 01:33:57 +00001082 ERROR(mLogCategory,"Unable to get xdg_toplevel");
fei.dengf7a0cd32023-08-29 09:36:37 +00001083 return;
1084 }
1085 xdg_toplevel_add_listener (mXdgToplevel, &xdg_toplevel_listener, this);
1086
1087 /* Finally, commit the xdg_surface state as toplevel */
1088 mXdgSurfaceConfigured = false;
1089 wl_surface_commit (mAreaSurface);
1090 wl_display_flush (mWlDisplay);
1091 /* we need exactly 3 roundtrips to discover global objects and their state */
1092 for (int i = 0; i < 3; i++) {
1093 if (wl_display_roundtrip_queue(mWlDisplay, mWlQueue) < 0) {
fei.dengb9a1a572023-09-13 01:33:57 +00001094 ERROR(mLogCategory,"Error communicating with the wayland display");
fei.dengf7a0cd32023-08-29 09:36:37 +00001095 }
1096 }
1097
1098 if (mXdgSurfaceConfigured) {
fei.dengb9a1a572023-09-13 01:33:57 +00001099 INFO(mLogCategory,"xdg surface had configured");
fei.dengf7a0cd32023-08-29 09:36:37 +00001100 } else {
fei.dengb9a1a572023-09-13 01:33:57 +00001101 WARNING(mLogCategory,"xdg surface not configured");
fei.dengf7a0cd32023-08-29 09:36:37 +00001102 }
1103
1104 //full screen show
fei.deng26950832023-11-09 03:00:23 +00001105 // if (mFullScreen && mCurrentDisplayOutput->wlOutput) {
1106 // //ensureFullscreen(mFullScreen);
fei.dengf7a0cd32023-08-29 09:36:37 +00001107 // }
1108 } else {
fei.dengb9a1a572023-09-13 01:33:57 +00001109 ERROR(mLogCategory,"Unable to use xdg_wm_base ");
fei.dengf7a0cd32023-08-29 09:36:37 +00001110 return;
1111 }
1112}
1113
1114void WaylandDisplay::destroyWindowSurfaces()
1115{
fei.dengf7a0cd32023-08-29 09:36:37 +00001116 if (mXdgToplevel) {
1117 xdg_toplevel_destroy (mXdgToplevel);
1118 mXdgToplevel = NULL;
1119 }
1120
1121 if (mXdgSurface) {
1122 xdg_surface_destroy (mXdgSurface);
1123 mXdgSurface = NULL;
1124 }
1125
1126 if (mVideoSurfaceWrapper) {
1127 wl_proxy_wrapper_destroy (mVideoSurfaceWrapper);
1128 mVideoSurfaceWrapper = NULL;
1129 }
1130
1131 if (mVideoSubSurface) {
1132 wl_subsurface_destroy (mVideoSubSurface);
1133 mVideoSubSurface = NULL;
1134 }
1135
1136 if (mVideoSurface) {
1137 wl_surface_destroy (mVideoSurface);
1138 mVideoSurface = NULL;
1139 }
1140
1141 if (mAreaSurfaceWrapper) {
1142 wl_proxy_wrapper_destroy (mAreaSurfaceWrapper);
1143 mAreaSurfaceWrapper = NULL;
1144 }
1145
1146 if (mAreaSurface) {
1147 wl_surface_destroy (mAreaSurface);
1148 mAreaSurface = NULL;
1149 mReCommitAreaSurface = false;
1150 }
1151}
1152
1153void WaylandDisplay::ensureFullscreen(bool fullscreen)
1154{
1155 if (mXdgWmBase) {
fei.dengb9a1a572023-09-13 01:33:57 +00001156 DEBUG(mLogCategory,"full screen : %d",fullscreen);
fei.dengf7a0cd32023-08-29 09:36:37 +00001157 if (fullscreen) {
fei.deng26950832023-11-09 03:00:23 +00001158 xdg_toplevel_set_fullscreen (mXdgToplevel, mCurrentDisplayOutput->wlOutput);
fei.dengf7a0cd32023-08-29 09:36:37 +00001159 } else {
1160 xdg_toplevel_unset_fullscreen (mXdgToplevel);
1161 }
1162 }
1163}
1164
1165void WaylandDisplay::setRenderRectangle(int x, int y, int w, int h)
1166{
fei.dengb9a1a572023-09-13 01:33:57 +00001167 DEBUG(mLogCategory,"set render rect:x:%d,y:%d,w:%d,h:%d",x,y,w,h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001168
1169 if (w <= 0 || h <= 0) {
fei.dengb9a1a572023-09-13 01:33:57 +00001170 WARNING(mLogCategory, "wrong render width or height %dx%d",w,h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001171 return;
1172 }
1173
1174 mRenderRect.x = x;
1175 mRenderRect.y = y;
1176 mRenderRect.w = w;
1177 mRenderRect.h = h;
1178
1179 if (!mXdgSurfaceConfigured) {
fei.dengb9a1a572023-09-13 01:33:57 +00001180 WARNING(mLogCategory,"Not configured xdg");
fei.dengf7a0cd32023-08-29 09:36:37 +00001181 return;
1182 }
1183
1184 if (mAreaViewport) {
1185 wp_viewport_set_destination (mAreaViewport, w, h);
1186 }
1187
1188 updateBorders();
1189
1190 if (mVideoWidth != 0 && mVideoSurface) {
1191 wl_subsurface_set_sync (mVideoSubSurface);
1192 resizeVideoSurface(true);
1193 }
1194
1195 wl_surface_damage (mAreaSurfaceWrapper, 0, 0, w, h);
1196 wl_surface_commit (mAreaSurfaceWrapper);
1197
1198 if (mVideoWidth != 0) {
1199 wl_subsurface_set_desync (mVideoSubSurface);
1200 }
1201}
1202
fei.dengf7a0cd32023-08-29 09:36:37 +00001203void WaylandDisplay::setFrameSize(int w, int h)
1204{
1205 mVideoWidth = w;
1206 mVideoHeight = h;
fei.denga4abbd52024-07-11 19:17:50 +08001207 mUpdateVideoSurface = true;
fei.dengb9a1a572023-09-13 01:33:57 +00001208 TRACE(mLogCategory,"frame w:%d,h:%d",mVideoWidth,mVideoHeight);
fei.dengf7a0cd32023-08-29 09:36:37 +00001209}
1210
1211void WaylandDisplay::setWindowSize(int x, int y, int w, int h)
1212{
1213 mWindowRect.x = x;
1214 mWindowRect.y = y;
1215 mWindowRect.w = w;
1216 mWindowRect.h = h;
fei.denga4abbd52024-07-11 19:17:50 +08001217 mUpdateVideoSurface = true;
fei.dengb9a1a572023-09-13 01:33:57 +00001218 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 +00001219}
1220
fei.denga4abbd52024-07-11 19:17:50 +08001221void WaylandDisplay::setPixelAspectRatio(double ratio)
1222{
1223 mPixelAspectRatio = ratio;
1224 mUpdateVideoSurface = true;
1225}
fei.dengf7a0cd32023-08-29 09:36:37 +00001226
1227void WaylandDisplay::resizeVideoSurface(bool commit)
1228{
1229 Rectangle src = {0,};
1230 Rectangle dst = {0,};
1231 Rectangle res;
1232
1233 /* center the video_subsurface inside area_subsurface */
1234 src.w = mVideoWidth;
1235 src.h = mVideoHeight;
1236 /*if had set the window size, we will scall
1237 video surface to this window size*/
1238 if (mWindowRect.w > 0 && mWindowRect.h > 0) {
1239 dst.x = mWindowRect.x;
1240 dst.y = mWindowRect.y;
1241 dst.w = mWindowRect.w;
1242 dst.h = mWindowRect.h;
1243 if (mWindowRect.w > mRenderRect.w && mWindowRect.h > mRenderRect.h) {
fei.dengb9a1a572023-09-13 01:33:57 +00001244 WARNING(mLogCategory,"Error window size:%dx%d, but render size:%dx%d,reset to render size",
fei.dengf7a0cd32023-08-29 09:36:37 +00001245 mWindowRect.w,mWindowRect.h,mRenderRect.w,mRenderRect.h);
1246 dst.x = mRenderRect.x;
1247 dst.y = mRenderRect.y;
1248 dst.w = mRenderRect.w;
1249 dst.h = mRenderRect.h;
1250 }
1251 //to do,we need set geometry?
1252 //if (mXdgSurface) {
1253 // xdg_surface_set_window_geometry(mXdgSurface, mWindowRect.x, mWindowRect.y, mWindowRect.w, mWindowRect.h);
1254 //}
1255 } else { //scal video to full screen
1256 dst.w = mRenderRect.w;
1257 dst.h = mRenderRect.h;
1258 }
1259
1260 if (mViewporter) {
1261 videoCenterRect(src, dst, &res, true);
1262 } else {
1263 videoCenterRect(src, dst, &res, false);
1264 }
1265
1266 wl_subsurface_set_position (mVideoSubSurface, res.x, res.y);
1267
1268 if (commit) {
1269 wl_surface_damage (mVideoSurfaceWrapper, 0, 0, res.w, res.h);
1270 wl_surface_commit (mVideoSurfaceWrapper);
1271 }
1272
1273 //top level setting
1274 if (mXdgToplevel) {
1275 struct wl_region *region;
1276
1277 region = wl_compositor_create_region (mCompositor);
1278 wl_region_add (region, 0, 0, mRenderRect.w, mRenderRect.h);
1279 wl_surface_set_input_region (mAreaSurface, region);
1280 wl_region_destroy (region);
1281 }
1282
1283 /* this is saved for use in wl_surface_damage */
1284 mVideoRect.x = res.x;
1285 mVideoRect.y = res.y;
1286 mVideoRect.w = res.w;
1287 mVideoRect.h = res.h;
1288
fei.denga4abbd52024-07-11 19:17:50 +08001289 //to scale video surface
fei.dengf7a0cd32023-08-29 09:36:37 +00001290 wp_viewport_set_destination(mVideoViewport, res.w, res.h);
fei.denga4abbd52024-07-11 19:17:50 +08001291 wl_display_flush (mWlDisplay);
fei.dengb9a1a572023-09-13 01:33:57 +00001292 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 +00001293}
1294
1295void WaylandDisplay::setOpaque()
1296{
1297 struct wl_region *region;
1298
1299 /* Set area opaque */
1300 region = wl_compositor_create_region (mCompositor);
1301 wl_region_add (region, 0, 0, mRenderRect.w, mRenderRect.h);
1302 wl_surface_set_opaque_region (mAreaSurface, region);
1303 wl_region_destroy (region);
1304}
1305
1306int WaylandDisplay::prepareFrameBuffer(RenderBuffer * buf)
1307{
1308 WaylandBuffer *waylandBuf = NULL;
1309 int ret;
fei.dengda0cd9f2024-07-24 09:25:11 +08001310 bool isNew = false;
fei.dengf7a0cd32023-08-29 09:36:37 +00001311
fei.dengdd910ef2024-06-07 10:25:30 +08001312 if (!mDmabuf)
1313 {
1314 ERROR(mLogCategory,"Error zwp_linux_dmabuf_v1");
1315 return ERROR_UNKNOWN;
1316 }
1317
fei.dengf7a0cd32023-08-29 09:36:37 +00001318 waylandBuf = findWaylandBuffer(buf);
1319 if (waylandBuf == NULL) {
fei.dengb9a1a572023-09-13 01:33:57 +00001320 waylandBuf = new WaylandBuffer(this, mLogCategory);
fei.dengda0cd9f2024-07-24 09:25:11 +08001321 isNew = true;
1322 }
1323 waylandBuf->setBufferFormat(mBufferFormat);
1324 ret = waylandBuf->constructWlBuffer(buf);
1325 if (ret != NO_ERROR) {
1326 WARNING(mLogCategory,"dmabufConstructWlBuffer fail,release waylandbuf");
1327 //delete waylanBuf,WaylandBuffer object destruct will call release callback
1328 goto waylandbuf_fail;
1329 }
1330 if (isNew) {
1331 addWaylandBuffer(buf, waylandBuf);
fei.dengf7a0cd32023-08-29 09:36:37 +00001332 }
fei.dengb9a1a572023-09-13 01:33:57 +00001333 return NO_ERROR;
fei.dengf7a0cd32023-08-29 09:36:37 +00001334waylandbuf_fail:
1335 //delete waylandbuf
1336 delete waylandBuf;
1337 waylandBuf = NULL;
fei.dengb9a1a572023-09-13 01:33:57 +00001338 return ERROR_UNKNOWN;
fei.dengf7a0cd32023-08-29 09:36:37 +00001339}
1340
1341void WaylandDisplay::displayFrameBuffer(RenderBuffer * buf, int64_t realDisplayTime)
1342{
fei.deng19b48692024-08-13 14:17:55 +08001343 WaylandBuffer *waylandBuf = NULL;
1344 struct wl_buffer * wlbuffer = NULL;
1345 int ret;
1346
1347 if (!buf) {
1348 ERROR(mLogCategory,"Error input params, RenderBuffer is null");
1349 return;
1350 }
1351
1352 if (buf->flag & BUFFER_FLAG_DMA_BUFFER) {
1353 if (buf->dma.width <=0 || buf->dma.height <=0) {
1354 buf->dma.width = mVideoWidth;
1355 buf->dma.height = mVideoHeight;
1356 }
1357
1358 waylandBuf = findWaylandBuffer(buf);
1359 if (waylandBuf) {
1360 waylandBuf->setRenderRealTime(realDisplayTime);
1361 } else {
1362 ERROR(mLogCategory,"NOT found wayland buffer,please prepare buffer first");
1363 goto waylandbuf_fail;
1364 }
1365 }
1366
1367 //if no wl_output, drop this buffer
1368 if (mCurrentDisplayOutput->wlOutput == NULL) {
1369 TRACE(mLogCategory,"No wl_output");
1370 //insert this buffer to committed weston buffer manager
1371 std::pair<int64_t, WaylandBuffer *> item(realDisplayTime, waylandBuf);
1372 mCommittedBufferMap.insert(item);
1373 mWaylandPlugin->handleFrameDropped(buf);
1374 WaylandBuffer::bufferRelease(waylandBuf,NULL);
1375 return;
1376 }
1377
1378 //must commit areasurface first, because weston xdg surface maybe timeout
1379 //this cause video is not display,commit can resume xdg surface
1380 if (!mReCommitAreaSurface) {
1381 mReCommitAreaSurface = true;
1382 wl_surface_commit (mAreaSurface);
1383 }
1384
fei.deng6c425232024-07-19 16:15:31 +08001385 //set frame rate to weston,it lets weston to select suitable mode
1386 if (mFrameRateChanged && mAmlConfigAPIList.enableSetDisplayRate) {
1387 mFrameRateChanged = false;
1388 TRACE(mLogCategory,"set frame rate %d/%d to weston", mFrameRateFractionNum, mFrameRateFractionDenom);
1389 wl_surface_set_display_rate(mVideoSurfaceWrapper, mFrameRateFractionNum, mFrameRateFractionDenom);
1390 }
fei.denga4abbd52024-07-11 19:17:50 +08001391 //update video surface size
1392 if (mUpdateVideoSurface && mVideoSurface &&
1393 buf->dma.width == mVideoWidth && buf->dma.height == mVideoHeight) {
1394 mUpdateVideoSurface = false;
1395 //if had full screen, unset it and set window size
1396 if (mFullScreen) {
1397 mFullScreen = false;
1398 ensureFullscreen(mFullScreen);
1399 }
1400 resizeVideoSurface(true);
fei.dengda0cd9f2024-07-24 09:25:11 +08001401 /*clean wayland buffers those allocated
1402 before resolution changed and had release by weston */
1403 cleanWaylandBufferBeforeResChanged();
fei.denga4abbd52024-07-11 19:17:50 +08001404 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001405
fei.deng1c94a342024-08-05 19:33:28 +08001406 if (mVideoPlaneZorderChanged && mVideoSurfaceWrapper) {
1407 mVideoPlaneZorderChanged = false;
1408 wl_surface_set_zorder(mVideoSurfaceWrapper, mVideoPlaneZorder);
1409 }
1410
fei.dengdd910ef2024-06-07 10:25:30 +08001411 //TRACE(mLogCategory,"display renderBuffer:%p,PTS:%lld us,realtime:%lld",buf, buf->pts/1000, realDisplayTime);
fei.dengf7a0cd32023-08-29 09:36:37 +00001412
fei.dengf7a0cd32023-08-29 09:36:37 +00001413 if (waylandBuf) {
1414 wlbuffer = waylandBuf->getWlBuffer();
1415 }
fei.deng19b48692024-08-13 14:17:55 +08001416
fei.dengf7a0cd32023-08-29 09:36:37 +00001417 if (wlbuffer) {
fei.dengb9a1a572023-09-13 01:33:57 +00001418 Tls::Mutex::Autolock _l(mRenderMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001419 ++mCommitCnt;
1420 uint32_t hiPts = realDisplayTime >> 32;
1421 uint32_t lowPts = realDisplayTime & 0xFFFFFFFF;
1422 //attach this wl_buffer to weston
fei.denga4abbd52024-07-11 19:17:50 +08001423 TRACE(mLogCategory,"++attach,renderbuf:%p,wl_buffer:%p(%d,%d,%d,%d),pts:%lld us,commitCnt:%d",
1424 buf,wlbuffer,mVideoRect.x,mVideoRect.y,mVideoRect.w,mVideoRect.h,buf->pts/1000,mCommitCnt);
fei.dengf7a0cd32023-08-29 09:36:37 +00001425 waylandBuf->attach(mVideoSurfaceWrapper);
1426
fei.deng640c3c92024-04-12 08:31:19 +00001427 if (mAmlConfigAPIList.enableSetPts) {
fei.dengb9a1a572023-09-13 01:33:57 +00001428 TRACE(mLogCategory,"display time:%lld,hiPts:%u,lowPts:%u",realDisplayTime, hiPts, lowPts);
fei.dengf7a0cd32023-08-29 09:36:37 +00001429 wl_surface_set_pts(mVideoSurfaceWrapper, hiPts, lowPts);
1430 }
1431
1432 wl_surface_damage (mVideoSurfaceWrapper, 0, 0, mVideoRect.w, mVideoRect.h);
1433 wl_surface_commit (mVideoSurfaceWrapper);
1434 //insert this buffer to committed weston buffer manager
fei.dengae8c90a2024-06-27 13:39:53 +08001435 std::pair<int64_t, WaylandBuffer *> item(realDisplayTime, waylandBuf);
fei.dengf7a0cd32023-08-29 09:36:37 +00001436 mCommittedBufferMap.insert(item);
1437 } else {
fei.dengb9a1a572023-09-13 01:33:57 +00001438 WARNING(mLogCategory,"wlbuffer is NULL");
fei.dengf7a0cd32023-08-29 09:36:37 +00001439 /* clear both video and parent surfaces */
fei.deng19b48692024-08-13 14:17:55 +08001440 //cleanSurface();
1441 goto waylandbuf_fail;
fei.dengf7a0cd32023-08-29 09:36:37 +00001442 }
1443
1444 wl_display_flush (mWlDisplay);
fei.deng4029e682024-06-26 17:06:31 +08001445 //set keep last frame or not when after send first buffer to weston,1 keep last frame, 0 not
1446 if (mToSendKeepLastFrame) {
1447 setKeepLastFrame(mKeepLastFrame);
1448 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001449
1450 return;
1451waylandbuf_fail:
1452 //notify dropped
1453 mWaylandPlugin->handleFrameDropped(buf);
1454 //notify app release this buf
1455 mWaylandPlugin->handleBufferRelease(buf);
fei.dengf7a0cd32023-08-29 09:36:37 +00001456 return;
1457}
1458
1459void WaylandDisplay::handleBufferReleaseCallback(WaylandBuffer *buf)
1460{
fei.denga4abbd52024-07-11 19:17:50 +08001461 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.dengf7a0cd32023-08-29 09:36:37 +00001462 {
fei.dengb9a1a572023-09-13 01:33:57 +00001463 Tls::Mutex::Autolock _l(mRenderMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001464 //remove buffer if this buffer is ready to release
fei.dengae8c90a2024-06-27 13:39:53 +08001465 auto item = mCommittedBufferMap.find(buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001466 if (item != mCommittedBufferMap.end()) {
fei.dengdd910ef2024-06-07 10:25:30 +08001467 --mCommitCnt;
fei.dengf7a0cd32023-08-29 09:36:37 +00001468 mCommittedBufferMap.erase(item);
1469 } else {
fei.denga4abbd52024-07-11 19:17:50 +08001470 TRACE(mLogCategory,"Error,Can't find WaylandBuffer pts:%lld us (%lld) in buffer map",
1471 renderBuffer->pts/1000,buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001472 return;
1473 }
1474 }
fei.denga4abbd52024-07-11 19:17:50 +08001475
1476 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 +00001477 mWaylandPlugin->handleBufferRelease(renderBuffer);
1478}
1479
1480void WaylandDisplay::handleFrameDisplayedCallback(WaylandBuffer *buf)
1481{
1482 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.denga4abbd52024-07-11 19:17:50 +08001483 TRACE(mLogCategory,"renderBuffer :%p,PTS:%lld us,realtime:%lld us",renderBuffer,renderBuffer->pts/1000,buf->getRenderRealTime());
fei.deng3287c082024-04-23 09:29:22 +00001484 if (!mSignalFirstFramePts) {
1485 mSignalFirstFramePts = true;
1486 mWaylandPlugin->handleMsgNotify(MSG_FIRST_FRAME, (void*)&renderBuffer->pts);
1487 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001488 mWaylandPlugin->handleFrameDisplayed(renderBuffer);
1489}
1490
1491void WaylandDisplay::handleFrameDropedCallback(WaylandBuffer *buf)
1492{
1493 RenderBuffer *renderBuffer = buf->getRenderBuffer();
fei.denga4abbd52024-07-11 19:17:50 +08001494 TRACE(mLogCategory,"renderBuffer :%p,PTS:%lld us,realtime:%lld us",renderBuffer,renderBuffer->pts/1000,buf->getRenderRealTime());
fei.dengf7a0cd32023-08-29 09:36:37 +00001495 mWaylandPlugin->handleFrameDropped(renderBuffer);
1496}
1497
1498
1499void WaylandDisplay::readyToRun()
1500{
1501 mFd = wl_display_get_fd (mWlDisplay);
fei.dengb9a1a572023-09-13 01:33:57 +00001502 if (mPoll) {
1503 mPoll->addFd(mFd);
1504 mPoll->setFdReadable(mFd, true);
1505 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001506}
1507
fei.dengdd910ef2024-06-07 10:25:30 +08001508void WaylandDisplay::readyToExit()
1509{
1510 if (mPoll && mFd >= 0) {
1511 mPoll->removeFd(mFd);
1512 }
1513}
1514
fei.dengf7a0cd32023-08-29 09:36:37 +00001515bool WaylandDisplay::threadLoop()
1516{
1517 int ret;
fei.dengf7a0cd32023-08-29 09:36:37 +00001518
1519 while (wl_display_prepare_read_queue (mWlDisplay, mWlQueue) != 0) {
1520 wl_display_dispatch_queue_pending (mWlDisplay, mWlQueue);
1521 }
1522
1523 wl_display_flush (mWlDisplay);
1524
1525 /*poll timeout value must > 300 ms,otherwise zwp_linux_dmabuf will create failed,
1526 so do use -1 to wait for ever*/
fei.dengb9a1a572023-09-13 01:33:57 +00001527 ret = mPoll->wait(-1); //wait for ever
fei.dengf7a0cd32023-08-29 09:36:37 +00001528 if (ret < 0) { //poll error
fei.dengb9a1a572023-09-13 01:33:57 +00001529 WARNING(mLogCategory,"poll error");
fei.dengf7a0cd32023-08-29 09:36:37 +00001530 wl_display_cancel_read(mWlDisplay);
1531 return false;
1532 } else if (ret == 0) { //poll time out
1533 return true; //run loop
1534 }
1535
1536 if (wl_display_read_events (mWlDisplay) == -1) {
1537 goto tag_error;
1538 }
1539
1540 wl_display_dispatch_queue_pending (mWlDisplay, mWlQueue);
1541 return true;
1542tag_error:
fei.dengb9a1a572023-09-13 01:33:57 +00001543 ERROR(mLogCategory,"Error communicating with the wayland server");
fei.dengf7a0cd32023-08-29 09:36:37 +00001544 return false;
1545}
1546
1547void WaylandDisplay::videoCenterRect(Rectangle src, Rectangle dst, Rectangle *result, bool scaling)
1548{
1549 //if dst is a small window, we scale video to map window size,don't doing center
fei.dengda0cd9f2024-07-24 09:25:11 +08001550 // if (mRenderRect.w != dst.w && mRenderRect.h != dst.h) {
1551 // result->x = dst.x;
1552 // result->y = dst.y;
1553 // result->w = dst.w;
1554 // result->h = dst.h;
1555 // TRACE(mLogCategory,"small window source is %dx%d dest is %dx%d, result is %d,%d,%d,%d",
1556 // src.w, src.h, dst.w, dst.h, result->x, result->y, result->w, result->h);
1557 // return;
1558 // }
fei.dengf7a0cd32023-08-29 09:36:37 +00001559 if (!scaling) {
1560 result->w = MIN (src.w, dst.w);
1561 result->h = MIN (src.h, dst.h);
1562 result->x = dst.x + (dst.w - result->w) / 2;
1563 result->y = dst.y + (dst.h - result->h) / 2;
1564 } else {
1565 double src_ratio, dst_ratio;
1566
fei.denga4abbd52024-07-11 19:17:50 +08001567 src_ratio = (double) (src.w * mPixelAspectRatio) / src.h;
fei.dengf7a0cd32023-08-29 09:36:37 +00001568 dst_ratio = (double) dst.w / dst.h;
1569
1570 if (src_ratio > dst_ratio) {
1571 result->w = dst.w;
1572 result->h = dst.w / src_ratio;
1573 result->x = dst.x;
1574 result->y = dst.y + (dst.h - result->h) / 2;
1575 } else if (src_ratio < dst_ratio) {
1576 result->w = dst.h * src_ratio;
1577 result->h = dst.h;
1578 result->x = dst.x + (dst.w - result->w) / 2;
1579 result->y = dst.y;
1580 } else {
1581 result->x = dst.x;
1582 result->y = dst.y;
1583 result->w = dst.w;
1584 result->h = dst.h;
1585 }
1586 }
1587
fei.denga4abbd52024-07-11 19:17:50 +08001588 TRACE(mLogCategory,"source is %dx%d dest is %dx%d, result is %d,%d,%d,%d",
1589 src.w, src.h, dst.w, dst.h, result->x, result->y,result->w, result->h);
fei.dengf7a0cd32023-08-29 09:36:37 +00001590}
1591
1592void WaylandDisplay::updateBorders()
1593{
1594 int width,height;
1595
1596 if (mNoBorderUpdate)
1597 return;
1598
1599 if (mViewporter) {
1600 width = height = 1;
1601 mNoBorderUpdate = true;
1602 } else {
1603 width = mRenderRect.w;
1604 height = mRenderRect.h;
1605 }
1606
1607 RenderVideoFormat format = VIDEO_FORMAT_BGRA;
fei.dengb9a1a572023-09-13 01:33:57 +00001608 mAreaShmBuffer = new WaylandShmBuffer(this, mLogCategory);
fei.dengf7a0cd32023-08-29 09:36:37 +00001609 struct wl_buffer *wlbuf = mAreaShmBuffer->constructWlBuffer(width, height, format);
1610 if (wlbuf == NULL) {
1611 delete mAreaShmBuffer;
1612 mAreaShmBuffer = NULL;
1613 }
1614
1615 wl_surface_attach(mAreaSurfaceWrapper, wlbuf, 0, 0);
1616}
1617
1618std::size_t WaylandDisplay::calculateDmaBufferHash(RenderDmaBuffer &dmabuf)
1619{
1620 std::string hashString("");
1621 for (int i = 0; i < dmabuf.planeCnt; i++) {
1622 char hashtmp[1024];
fei.dengda0cd9f2024-07-24 09:25:11 +08001623 snprintf (hashtmp, 1024, "%d%d%d%d%d%d%d",i,dmabuf.width,dmabuf.height,dmabuf.planeCnt,
fei.dengf7a0cd32023-08-29 09:36:37 +00001624 dmabuf.stride[i],dmabuf.offset[i],dmabuf.fd[i]);
1625 std::string tmp(hashtmp);
1626 hashString += tmp;
1627 }
1628
1629 std::size_t hashval = std::hash<std::string>()(hashString);
fei.dengb9a1a572023-09-13 01:33:57 +00001630 //TRACE(mLogCategory,"hashstr:%s,val:%zu",hashString.c_str(),hashval);
fei.dengf7a0cd32023-08-29 09:36:37 +00001631 return hashval;
1632}
1633
1634void WaylandDisplay::addWaylandBuffer(RenderBuffer * buf, WaylandBuffer *waylandbuf)
1635{
fei.deng19b48692024-08-13 14:17:55 +08001636 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001637 if (buf->flag & BUFFER_FLAG_DMA_BUFFER) {
1638 std::size_t hashval = calculateDmaBufferHash(buf->dma);
1639 std::pair<std::size_t, WaylandBuffer *> item(hashval, waylandbuf);
fei.dengb9a1a572023-09-13 01:33:57 +00001640 //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 +00001641 mWaylandBuffersMap.insert(item);
1642 }
fei.dengb9a1a572023-09-13 01:33:57 +00001643 TRACE(mLogCategory,"mWaylandBuffersMap size:%d",mWaylandBuffersMap.size());
fei.dengf7a0cd32023-08-29 09:36:37 +00001644}
1645
1646WaylandBuffer* WaylandDisplay::findWaylandBuffer(RenderBuffer * buf)
1647{
fei.deng19b48692024-08-13 14:17:55 +08001648 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001649 std::size_t hashval = calculateDmaBufferHash(buf->dma);
1650 auto item = mWaylandBuffersMap.find(hashval);
1651 if (item == mWaylandBuffersMap.end()) {
1652 return NULL;
1653 }
1654
1655 return (WaylandBuffer*) item->second;
1656}
1657
1658void WaylandDisplay::cleanAllWaylandBuffer()
1659{
fei.deng19b48692024-08-13 14:17:55 +08001660 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001661 //free all obtain buff
1662 for (auto item = mWaylandBuffersMap.begin(); item != mWaylandBuffersMap.end(); ) {
1663 WaylandBuffer *waylandbuf = (WaylandBuffer*)item->second;
1664 mWaylandBuffersMap.erase(item++);
1665 delete waylandbuf;
1666 }
1667}
1668
fei.dengda0cd9f2024-07-24 09:25:11 +08001669
1670/**
1671 * @brief clean wayland buffers those malloc before resolution changed
1672 *
1673 */
1674void WaylandDisplay::cleanWaylandBufferBeforeResChanged()
1675{
fei.deng19b48692024-08-13 14:17:55 +08001676 Tls::Mutex::Autolock _l(mBufferMutex);
fei.dengda0cd9f2024-07-24 09:25:11 +08001677 for (auto item = mWaylandBuffersMap.begin(); item != mWaylandBuffersMap.end(); ) {
1678 WaylandBuffer *wlbuf = (WaylandBuffer*)item->second;
1679 if (wlbuf->isFree()) {
1680 mWaylandBuffersMap.erase(item++);
1681 delete wlbuf;
1682 } else {
1683 item++;
1684 }
1685 }
1686}
1687
fei.dengf7a0cd32023-08-29 09:36:37 +00001688void WaylandDisplay::flushBuffers()
1689{
fei.dengb9a1a572023-09-13 01:33:57 +00001690 INFO(mLogCategory,"flushBuffers");
1691 Tls::Mutex::Autolock _l(mRenderMutex);
fei.dengf7a0cd32023-08-29 09:36:37 +00001692 for (auto item = mCommittedBufferMap.begin(); item != mCommittedBufferMap.end(); item++) {
1693 WaylandBuffer *waylandbuf = (WaylandBuffer*)item->second;
1694 waylandbuf->forceRedrawing();
1695 handleFrameDisplayedCallback(waylandbuf);
1696 }
1697}
1698
1699void WaylandDisplay::cleanSurface()
1700{
1701 /* clear both video and parent surfaces */
1702 wl_surface_attach (mVideoSurfaceWrapper, NULL, 0, 0);
1703 wl_surface_commit (mVideoSurfaceWrapper);
1704 wl_surface_attach (mAreaSurfaceWrapper, NULL, 0, 0);
1705 wl_surface_commit (mAreaSurfaceWrapper);
fei.deng640c3c92024-04-12 08:31:19 +00001706}
1707
1708void WaylandDisplay::setKeepLastFrame(int keep)
1709{
1710 mKeepLastFrame = keep;
1711 if (mVideoSurfaceWrapper && mAmlConfigAPIList.enableKeepLastFrame) {
1712 INFO(mLogCategory,"keep last frame:%d",keep);
1713 wl_surface_keep_last_frame(mVideoSurfaceWrapper, keep);
fei.deng4029e682024-06-26 17:06:31 +08001714 mToSendKeepLastFrame = false;
1715 return;
fei.deng640c3c92024-04-12 08:31:19 +00001716 }
fei.deng4029e682024-06-26 17:06:31 +08001717 mToSendKeepLastFrame = true;
fei.deng6c425232024-07-19 16:15:31 +08001718}
1719
1720void WaylandDisplay::setFrameRate(int frameRateNum, int frameRateDenom)
1721{
1722 mFrameRateFractionNum = frameRateNum;
1723 mFrameRateFractionDenom = frameRateDenom;
1724 if (mFrameRateFractionDenom == 0) {
1725 mFrameRateFractionDenom = 1;
1726 }
1727 /*cobalt is not set frame rate to gst pipeline. we set default 59.94
1728 frame rate to weston*/
fei.deng19b48692024-08-13 14:17:55 +08001729 if (mFrameRateFractionNum == 0) {
fei.deng6c425232024-07-19 16:15:31 +08001730 mFrameRateFractionNum = 59940;
1731 mFrameRateFractionDenom = 1000;
1732 }
1733 mFrameRateChanged = true;
1734 INFO(mLogCategory,"num:%d,denom:%d",mFrameRateFractionNum, mFrameRateFractionDenom);
fei.deng1c94a342024-08-05 19:33:28 +08001735}
1736
1737void WaylandDisplay::setVideoPlaneZorder(int zorder)
1738{
1739 mVideoPlaneZorder = zorder;
1740 mVideoPlaneZorderChanged = true;
1741 if (mVideoSurfaceWrapper) {
1742 mVideoPlaneZorderChanged = false;
1743 wl_surface_set_zorder(mVideoSurfaceWrapper, mVideoPlaneZorder);
1744 }
fei.dengf7a0cd32023-08-29 09:36:37 +00001745}