blob: 039ed71ca747068fa68f4a653cd0eeaa0b14b436 [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"
18#include "Logger.h"
19#include "wayland_plugin.h"
20#include "wayland_videoformat.h"
21#include "wayland_shm.h"
22#include "wayland_dma.h"
23#include "wayland_buffer.h"
24
25#ifndef MAX
26# define MAX(a,b) ((a) > (b)? (a) : (b))
27# define MIN(a,b) ((a) < (b)? (a) : (b))
28#endif
29
30#define UNUSED_PARAM(x) ((void)(x))
31
32#define TAG "rlib:wayland_display"
33
34void WaylandDisplay::dmabuf_modifiers(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
35 uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo)
36{
37 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
38 std::lock_guard<std::mutex> lck(self->mMutex);
39 if (wl_dmabuf_format_to_video_format (format) != VIDEO_FORMAT_UNKNOWN) {
40 TRACE("regist dmabuffer format:%d (%s) hi:%x,lo:%x",format,print_dmabuf_format_name(format),modifier_hi,modifier_lo);
41 uint64_t modifier = ((uint64_t)modifier_hi << 32) | modifier_lo;
42 auto item = self->mDmaBufferFormats.find(format);
43 if (item == self->mDmaBufferFormats.end()) {
44 std::pair<uint32_t ,uint64_t> item(format, modifier);
45 self->mDmaBufferFormats.insert(item);
46 } else { //found format
47 item->second = modifier;
48 }
49 }
50}
51
52void
53WaylandDisplay::dmaBufferFormat (void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
54 uint32_t format)
55{
56#if 0
57 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
58
59 if (wl_dmabuf_format_to_video_format (format) != VIDEO_FORMAT_UNKNOWN) {
60 TRACE(mLogCategory,"regist dmabuffer format:%d : %s",format);
61 //self->mDmaBufferFormats.push_back(format);
62 }
63#endif
64 /* XXX: deprecated */
65}
66
67static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
68 WaylandDisplay::dmaBufferFormat,
69 WaylandDisplay::dmabuf_modifiers
70};
71
72static void
73handle_xdg_wm_base_ping (void *user_data, struct xdg_wm_base *xdg_wm_base,
74 uint32_t serial)
75{
76 xdg_wm_base_pong (xdg_wm_base, serial);
77}
78
79static const struct xdg_wm_base_listener xdg_wm_base_listener = {
80 handle_xdg_wm_base_ping
81};
82
83void WaylandDisplay::shmFormat(void *data, struct wl_shm *wl_shm, uint32_t format)
84{
85 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
86 self->mShmFormats.push_back(format);
87}
88
89static const struct wl_shm_listener shm_listener = {
90 WaylandDisplay::shmFormat
91};
92
93void WaylandDisplay::outputHandleGeometry( void *data,
94 struct wl_output *output,
95 int x,
96 int y,
97 int physicalWidth,
98 int physicalHeight,
99 int subPixel,
100 const char *make,
101 const char *model,
102 int transform )
103{
104 UNUSED_PARAM(make);
105 UNUSED_PARAM(model);
106
107 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
108 DEBUG("wl_output %p x:%d,y:%d,physicalWidth:%d,physicalHeight:%d,subPixel:%d,trans:%d",
109 output,x, y,physicalWidth, physicalHeight,subPixel,transform);;
110 std::lock_guard<std::mutex> lck(self->mMutex);
111 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
112 if (output == self->mOutput[i].wlOutput) {
113 self->mOutput[i].offsetX = x;
114 self->mOutput[i].offsetY = y;
115 }
116 }
117}
118
119void WaylandDisplay::outputHandleMode( void *data,
120 struct wl_output *output,
121 uint32_t flags,
122 int width,
123 int height,
124 int refreshRate )
125{
126 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
127
128 if ( flags & WL_OUTPUT_MODE_CURRENT ) {
129 std::lock_guard<std::mutex> lck(self->mMutex);
130 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
131 if (output == self->mOutput[i].wlOutput) {
132 self->mOutput[i].width = width;
133 self->mOutput[i].height = height;
134 self->mOutput[i].refreshRate = refreshRate;
135 }
136 }
137 //if a displayoutput had been selected,set this rectangle to wayland
138 int selectOutput = self->mActiveOutput;
139 DEBUG("wl_output: %p (%dx%d) refreshrate:%d,active output index %d\n",output, width, height,refreshRate,selectOutput);
140 if (selectOutput >= 0 && selectOutput < DEFAULT_DISPLAY_OUTPUT_NUM) {
141 if (self->mOutput[selectOutput].width > 0 && self->mOutput[selectOutput].height > 0) {
142 self->setRenderRectangle(self->mOutput[selectOutput].offsetX,
143 self->mOutput[selectOutput].offsetY,
144 self->mOutput[selectOutput].width,
145 self->mOutput[selectOutput].height);
146 }
147 }
148 }
149}
150
151void WaylandDisplay::outputHandleDone( void *data,
152 struct wl_output *output )
153{
154 UNUSED_PARAM(data);
155 UNUSED_PARAM(output);
156}
157
158void WaylandDisplay::outputHandleScale( void *data,
159 struct wl_output *output,
160 int32_t scale )
161{
162 UNUSED_PARAM(data);
163 UNUSED_PARAM(output);
164 UNUSED_PARAM(scale);
165}
166
167static const struct wl_output_listener outputListener = {
168 WaylandDisplay::outputHandleGeometry,
169 WaylandDisplay::outputHandleMode,
170 WaylandDisplay::outputHandleDone,
171 WaylandDisplay::outputHandleScale
172};
173
174void WaylandDisplay::pointerHandleEnter(void *data, struct wl_pointer *pointer,
175 uint32_t serial, struct wl_surface *surface,
176 wl_fixed_t sx, wl_fixed_t sy)
177{
178 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
179
180 if (self->mFullScreen) {
181 wl_pointer_set_cursor(pointer, serial, NULL, 0, 0);
182 }
183}
184
185void WaylandDisplay::pointerHandleLeave(void *data, struct wl_pointer *pointer,
186 uint32_t serial, struct wl_surface *surface)
187{
188 UNUSED_PARAM(data);
189 UNUSED_PARAM(pointer);
190 UNUSED_PARAM(serial);
191 UNUSED_PARAM(surface);
192}
193
194void WaylandDisplay::pointerHandleMotion(void *data, struct wl_pointer *pointer,
195 uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
196{
197 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
198 int x = wl_fixed_to_int(sx);
199 int y = wl_fixed_to_int(sy);
200 DEBUG("pointer motion fixed[%d, %d] to-int: x[%d] y[%d]\n", sx, sy, x, y);
201}
202
203void WaylandDisplay::pointerHandleButton(void *data, struct wl_pointer *wl_pointer,
204 uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
205{
206 UNUSED_PARAM(data);
207 UNUSED_PARAM(wl_pointer);
208 UNUSED_PARAM(time);
209 UNUSED_PARAM(serial);
210 UNUSED_PARAM(button);
211 UNUSED_PARAM(state);
212}
213
214void WaylandDisplay::pointerHandleAxis(void *data, struct wl_pointer *wl_pointer,
215 uint32_t time, uint32_t axis, wl_fixed_t value)
216{
217 UNUSED_PARAM(data);
218 UNUSED_PARAM(wl_pointer);
219 UNUSED_PARAM(time);
220 UNUSED_PARAM(axis);
221 UNUSED_PARAM(value);
222}
223
224static const struct wl_pointer_listener pointer_listener = {
225 WaylandDisplay::pointerHandleEnter,
226 WaylandDisplay::pointerHandleLeave,
227 WaylandDisplay::pointerHandleMotion,
228 WaylandDisplay::pointerHandleButton,
229 WaylandDisplay::pointerHandleAxis,
230};
231
232void WaylandDisplay::touchHandleDown(void *data, struct wl_touch *wl_touch,
233 uint32_t serial, uint32_t time, struct wl_surface *surface,
234 int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
235{
236 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
237}
238
239void WaylandDisplay::touchHandleUp(void *data, struct wl_touch *wl_touch,
240 uint32_t serial, uint32_t time, int32_t id)
241{
242 UNUSED_PARAM(data);
243 UNUSED_PARAM(wl_touch);
244 UNUSED_PARAM(serial);
245 UNUSED_PARAM(time);
246 UNUSED_PARAM(id);
247}
248
249void WaylandDisplay::touchHandleMotion(void *data, struct wl_touch *wl_touch,
250 uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
251{
252 UNUSED_PARAM(data);
253 UNUSED_PARAM(wl_touch);
254 UNUSED_PARAM(time);
255 UNUSED_PARAM(id);
256 UNUSED_PARAM(x_w);
257 UNUSED_PARAM(y_w);
258}
259
260void WaylandDisplay::touchHandleFrame(void *data, struct wl_touch *wl_touch)
261{
262 UNUSED_PARAM(data);
263 UNUSED_PARAM(wl_touch);
264}
265
266void WaylandDisplay::touchHandleCancel(void *data, struct wl_touch *wl_touch)
267{
268 UNUSED_PARAM(data);
269 UNUSED_PARAM(wl_touch);
270}
271
272static const struct wl_touch_listener touch_listener = {
273 WaylandDisplay::touchHandleDown,
274 WaylandDisplay::touchHandleUp,
275 WaylandDisplay::touchHandleMotion,
276 WaylandDisplay::touchHandleFrame,
277 WaylandDisplay::touchHandleCancel,
278};
279
280void WaylandDisplay::keyboardHandleKeymap(void *data, struct wl_keyboard *keyboard,
281 uint32_t format, int fd, uint32_t size)
282{
283 UNUSED_PARAM(data);
284 UNUSED_PARAM(keyboard);
285 UNUSED_PARAM(format);
286 UNUSED_PARAM(fd);
287 UNUSED_PARAM(size);
288}
289
290void WaylandDisplay::keyboardHandleEnter(void *data, struct wl_keyboard *keyboard,
291 uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
292{
293 UNUSED_PARAM(data);
294 UNUSED_PARAM(keyboard);
295 UNUSED_PARAM(serial);
296 UNUSED_PARAM(surface);
297 UNUSED_PARAM(keys);
298}
299
300void WaylandDisplay::keyboardHandleLeave(void *data, struct wl_keyboard *keyboard,
301 uint32_t serial, struct wl_surface *surface)
302{
303 UNUSED_PARAM(data);
304 UNUSED_PARAM(keyboard);
305 UNUSED_PARAM(serial);
306 UNUSED_PARAM(surface);
307}
308
309void WaylandDisplay::keyboardHandleKey(void *data, struct wl_keyboard *keyboard,
310 uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
311{
312 UNUSED_PARAM(data);
313 UNUSED_PARAM(keyboard);
314 UNUSED_PARAM(serial);
315 UNUSED_PARAM(time);
316 UNUSED_PARAM(key);
317 UNUSED_PARAM(state);
318}
319
320void WaylandDisplay::keyboardHandleModifiers(void *data, struct wl_keyboard *keyboard,
321 uint32_t serial, uint32_t mods_depressed,
322 uint32_t mods_latched, uint32_t mods_locked,
323 uint32_t group)
324{
325 UNUSED_PARAM(data);
326 UNUSED_PARAM(keyboard);
327 UNUSED_PARAM(serial);
328 UNUSED_PARAM(mods_depressed);
329 UNUSED_PARAM(mods_latched);
330 UNUSED_PARAM(mods_locked);
331 UNUSED_PARAM(group);
332}
333
334static const struct wl_keyboard_listener keyboard_listener = {
335 WaylandDisplay::keyboardHandleKeymap,
336 WaylandDisplay::keyboardHandleEnter,
337 WaylandDisplay::keyboardHandleLeave,
338 WaylandDisplay::keyboardHandleKey,
339 WaylandDisplay::keyboardHandleModifiers,
340};
341
342void WaylandDisplay::seatHandleCapabilities(void *data, struct wl_seat *seat,
343 uint32_t caps)
344{
345 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
346 if ((caps & WL_SEAT_CAPABILITY_POINTER) && !self->mPointer) {
347 self->mPointer = wl_seat_get_pointer(seat);
348 wl_pointer_add_listener(self->mPointer, &pointer_listener, data);
349 } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && self->mPointer) {
350 wl_pointer_destroy(self->mPointer);
351 self->mPointer = NULL;
352 }
353
354 if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !self->mKeyboard) {
355 self->mKeyboard = wl_seat_get_keyboard(seat);
356 wl_keyboard_add_listener(self->mKeyboard, &keyboard_listener, data);
357 } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && self->mKeyboard) {
358 wl_keyboard_destroy(self->mKeyboard);
359 self->mKeyboard = NULL;
360 }
361
362 if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !self->mTouch) {
363 self->mTouch = wl_seat_get_touch(seat);
364 wl_touch_set_user_data(self->mTouch, data);
365 wl_touch_add_listener(self->mTouch, &touch_listener, data);
366 } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && self->mTouch) {
367 wl_touch_destroy(self->mTouch);
368 self->mTouch = NULL;
369 }
370}
371
372static const struct wl_seat_listener seat_listener = {
373 WaylandDisplay::seatHandleCapabilities,
374};
375
376
377void WaylandDisplay::handleXdgToplevelClose (void *data, struct xdg_toplevel *xdg_toplevel)
378{
379 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
380
381 INFO("XDG toplevel got a close event.");
382}
383
384void WaylandDisplay::handleXdgToplevelConfigure (void *data, struct xdg_toplevel *xdg_toplevel,
385 int32_t width, int32_t height, struct wl_array *states)
386{
387 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
388 uint32_t *state;
389
390 INFO("XDG toplevel got a configure event, width:height [ %d, %d ].", width, height);
391 /*
392 wl_array_for_each (state, states) {
393 switch (*state) {
394 case XDG_TOPLEVEL_STATE_FULLSCREEN:
395 case XDG_TOPLEVEL_STATE_MAXIMIZED:
396 case XDG_TOPLEVEL_STATE_RESIZING:
397 case XDG_TOPLEVEL_STATE_ACTIVATED:
398 break;
399 }
400 }
401 */
402
403 if (width <= 0 || height <= 0)
404 return;
405
406 int selectOutput = self->mActiveOutput;
407 if (width == self->mOutput[selectOutput].width && height == self->mOutput[selectOutput].height) {
408 self->setRenderRectangle(self->mOutput[selectOutput].offsetX,
409 self->mOutput[selectOutput].offsetY,
410 self->mOutput[selectOutput].width,
411 self->mOutput[selectOutput].height);
412 } else{
413 self->setRenderRectangle(self->mRenderRect.x, self->mRenderRect.y, width, height);
414 }
415}
416
417static const struct xdg_toplevel_listener xdg_toplevel_listener = {
418 WaylandDisplay::handleXdgToplevelConfigure,
419 WaylandDisplay::handleXdgToplevelClose,
420};
421
422void WaylandDisplay::handleXdgSurfaceConfigure (void *data, struct xdg_surface *xdg_surface,
423 uint32_t serial)
424{
425 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
426 xdg_surface_ack_configure (xdg_surface, serial);
427
428 TRACE("handleXdgSurfaceConfigure");
429 std::lock_guard<std::mutex> lck(self->mConfigureMutex);
430 self->mXdgSurfaceConfigured = true;
431 if (self->mRenderRect.w > 0 && self->mRenderRect.h) {
432 DEBUG("set xdg surface geometry(%d,%d,%d,%d)",self->mRenderRect.x,self->mRenderRect.y,self->mRenderRect.w,self->mRenderRect.h);
433 xdg_surface_set_window_geometry(self->mXdgSurface,self->mRenderRect.x,self->mRenderRect.y,self->mRenderRect.w,self->mRenderRect.h);
434 }
435}
436
437static const struct xdg_surface_listener xdg_surface_listener = {
438 WaylandDisplay::handleXdgSurfaceConfigure,
439};
440
441void
442WaylandDisplay::registryHandleGlobal (void *data, struct wl_registry *registry,
443 uint32_t id, const char *interface, uint32_t version)
444{
445 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
446 TRACE("registryHandleGlobal,interface:%s,version:%d",interface,version);
447
448 if (strcmp (interface, "wl_compositor") == 0) {
449 self->mCompositor = (struct wl_compositor *)wl_registry_bind (registry, id, &wl_compositor_interface, 1/*MIN (version, 3)*/);
450 } else if (strcmp (interface, "wl_subcompositor") == 0) {
451 self->mSubCompositor = (struct wl_subcompositor *)wl_registry_bind (registry, id, &wl_subcompositor_interface, 1);
452 } else if (strcmp (interface, "xdg_wm_base") == 0) {
453 self->mXdgWmBase = (struct xdg_wm_base *)wl_registry_bind (registry, id, &xdg_wm_base_interface, 1);
454 xdg_wm_base_add_listener (self->mXdgWmBase, &xdg_wm_base_listener, (void *)self);
455 } else if (strcmp (interface, "wl_shm") == 0) {
456 self->mShm = (struct wl_shm *)wl_registry_bind (registry, id, &wl_shm_interface, 1);
457 wl_shm_add_listener (self->mShm, &shm_listener, self);
458 } else if (strcmp (interface, "zwp_fullscreen_shell_v1") == 0) {
459 //self->mFullscreenShell = (struct zwp_fullscreen_shell_v1 *)wl_registry_bind (registry, id,
460 // &zwp_fullscreen_shell_v1_interface, 1);
461 } else if (strcmp (interface, "wp_viewporter") == 0) {
462 self->mViewporter = (struct wp_viewporter *)wl_registry_bind (registry, id, &wp_viewporter_interface, 1);
463 } else if (strcmp (interface, "zwp_linux_dmabuf_v1") == 0) {
464 if (version < 3)
465 return;
466 self->mDmabuf = (struct zwp_linux_dmabuf_v1 *)wl_registry_bind (registry, id, &zwp_linux_dmabuf_v1_interface, 3);
467 zwp_linux_dmabuf_v1_add_listener (self->mDmabuf, &dmabuf_listener, (void *)self);
468 } else if (strcmp (interface, "wl_output") == 0) {
469 int index = self->mNextOutput;
470 if (index == 0) { //primary wl_output
471 self->mOutput[index].isPrimary = true;
472 }
473 self->mNextOutput += 1;
474 self->mOutput[index].wlOutput = (struct wl_output*)wl_registry_bind(registry, id, &wl_output_interface, version);
475 wl_output_add_listener(self->mOutput[index].wlOutput, &outputListener, (void *)self);
476 } else if (strcmp(interface, "wl_seat") == 0) {
477 //self->mSeat = (struct wl_seat *)wl_registry_bind(registry, id, &wl_seat_interface, 1);
478 //wl_seat_add_listener(self->mSeat, &seat_listener, (void *)self);
479 }
480}
481
482void
483WaylandDisplay::registryHandleGlobalRemove (void *data, struct wl_registry *registry, uint32_t name)
484{
485 WaylandDisplay *self = static_cast<WaylandDisplay *>(data);
486 /* temporarily do nothing */
487 DEBUG("wayland display remove registry handle global");
488}
489
490static const struct wl_registry_listener registry_listener = {
491 WaylandDisplay::registryHandleGlobal,
492 WaylandDisplay::registryHandleGlobalRemove
493};
494
495WaylandDisplay::WaylandDisplay(WaylandPlugin *plugin)
496 :mWaylandPlugin(plugin)
497{
498 TRACE("construct WaylandDisplay");
499 mWlDisplay = NULL;
500 mWlDisplayWrapper = NULL;
501 mWlQueue = NULL;
502 mRegistry = NULL;
503 mCompositor = NULL;
504 mXdgWmBase = NULL;
505 mViewporter = NULL;
506 mDmabuf = NULL;
507 mShm = NULL;
508 mSeat = NULL;
509 mPointer = NULL;
510 mTouch = NULL;
511 mKeyboard = NULL;
512 mNextOutput = 0;
513 mActiveOutput = 0; //default is primary output
514 //window
515 mVideoWidth = 0;
516 mVideoHeight = 0;
517 mVideoSurface = NULL;
518 mXdgSurface = NULL;
519 mXdgToplevel = NULL;
520 mAreaViewport = NULL;
521 mVideoViewport = NULL;
522 mNoBorderUpdate = false;
523 mAreaShmBuffer = NULL;
524 mCommitCnt = 0;
525 mIsSendPtsToWeston = false;
526 mReCommitAreaSurface = false;
527 mAreaSurface = NULL;
528 mAreaSurfaceWrapper = NULL;
529 mVideoSurfaceWrapper = NULL;
530 mVideoSubSurface = NULL;
531 mXdgSurfaceConfigured = false;
532 mPip = 0;
533 mIsSendVideoPlaneId = true;
534 memset(&mRenderRect, 0, sizeof(struct Rectangle));
535 memset(&mVideoRect, 0, sizeof(struct Rectangle));
536 memset(&mWindowRect, 0, sizeof(struct Rectangle));
537 mFullScreen = true; //default is full screen
538 char *env = getenv("VIDEO_RENDER_SEND_PTS_TO_WESTON");
539 if (env) {
540 int isSet = atoi(env);
541 if (isSet > 0) {
542 mIsSendPtsToWeston = true;
543 INFO("set send pts to weston");
544 } else {
545 mIsSendPtsToWeston = false;
546 INFO("do not send pts to weston");
547 }
548 }
549 env = getenv("VIDEO_RENDER_SEND_VIDEO_PLANE_ID_TO_WESTON");
550 if (env) {
551 int isSet = atoi(env);
552 if (isSet == 0) {
553 mIsSendVideoPlaneId = false;
554 INFO("do not send video plane id to weston");
555 } else {
556 mIsSendVideoPlaneId = true;
557 INFO("send video plane id to weston");
558 }
559 }
560 for (int i = 0; i < DEFAULT_DISPLAY_OUTPUT_NUM; i++) {
561 mOutput[i].wlOutput = NULL;
562 mOutput[i].offsetX = 0;
563 mOutput[i].offsetY = 0;
564 mOutput[i].width = 0;
565 mOutput[i].height = 0;
566 mOutput[i].refreshRate = 0;
567 mOutput[i].isPrimary = false;
568 }
569}
570
571WaylandDisplay::~WaylandDisplay()
572{
573 TRACE("desconstruct WaylandDisplay");
574}
575
576char *WaylandDisplay::require_xdg_runtime_dir()
577{
578 char *val = getenv("XDG_RUNTIME_DIR");
579 INFO("XDG_RUNTIME_DIR=%s",val);
580
581 return val;
582}
583
584int WaylandDisplay::openDisplay()
585{
586 char *name = require_xdg_runtime_dir();
587 //DEBUG(mLogCategory,"name:%s",name);
588 DEBUG("openDisplay in");
589 mWlDisplay = wl_display_connect(NULL);
590 if (!mWlDisplay) {
591 ERROR("Failed to connect to the wayland display, XDG_RUNTIME_DIR='%s'",
592 name ? name : "NULL");
593 return -1;
594 }
595
596 mWlDisplayWrapper = (struct wl_display *)wl_proxy_create_wrapper ((void *)mWlDisplay);
597 mWlQueue = wl_display_create_queue (mWlDisplay);
598 wl_proxy_set_queue ((struct wl_proxy *)mWlDisplayWrapper, mWlQueue);
599
600 mRegistry = wl_display_get_registry (mWlDisplayWrapper);
601 wl_registry_add_listener (mRegistry, &registry_listener, (void *)this);
602
603 /* we need exactly 2 roundtrips to discover global objects and their state */
604 for (int i = 0; i < 2; i++) {
605 if (wl_display_roundtrip_queue (mWlDisplay, mWlQueue) < 0) {
606 ERROR("Error communicating with the wayland display");
607 return -1;
608 }
609 }
610
611 if (!mCompositor) {
612 ERROR("Could not bind to wl_compositor. Either it is not implemented in " \
613 "the compositor, or the implemented version doesn't match");
614 return -1;
615 }
616
617 if (!mDmabuf) {
618 ERROR("Could not bind to zwp_linux_dmabuf_v1");
619 return -1;
620 }
621
622 if (!mXdgWmBase) {
623 /* If wl_surface and wl_display are passed via GstContext
624 * wl_shell, xdg_shell and zwp_fullscreen_shell are not used.
625 * In this case is correct to continue.
626 */
627 ERROR("Could not bind to either wl_shell, xdg_wm_base or "
628 "zwp_fullscreen_shell, video display may not work properly.");
629 return -1;
630 }
631
632 //create window surface
633 createCommonWindowSurface();
634 createXdgShellWindowSurface();
635
636 //config weston video plane
637 if (mIsSendVideoPlaneId) {
638 INFO("set weston video plane:%d",mPip);
639 wl_surface_set_video_plane(mVideoSurfaceWrapper, mPip);
640 }
641
642 //run wl display queue dispatch
643 DEBUG("To run wl display dispatch queue");
644 run("display queue");
645 mRedrawingPending = false;
646
647 DEBUG("openDisplay out");
648 return 0;
649}
650
651void WaylandDisplay::closeDisplay()
652{
653 DEBUG("closeDisplay in");
654
655 if (isRunning()) {
656 TRACE("try stop dispatch thread");
657 requestExitAndWait();
658 }
659
660 //first destroy window surface
661 destroyWindowSurfaces();
662
663 if (mViewporter) {
664 wp_viewporter_destroy (mViewporter);
665 mViewporter = NULL;
666 }
667
668 if (mDmabuf) {
669 zwp_linux_dmabuf_v1_destroy (mDmabuf);
670 mDmabuf = NULL;
671 }
672
673 if (mXdgWmBase) {
674 xdg_wm_base_destroy (mXdgWmBase);
675 mXdgWmBase = NULL;
676 }
677
678 if (mCompositor) {
679 wl_compositor_destroy (mCompositor);
680 mCompositor = NULL;
681 }
682
683 if (mSubCompositor) {
684 wl_subcompositor_destroy (mSubCompositor);
685 mSubCompositor = NULL;
686 }
687
688 if (mRegistry) {
689 wl_registry_destroy (mRegistry);
690 mRegistry= NULL;
691 }
692
693 if (mWlDisplayWrapper) {
694 wl_proxy_wrapper_destroy (mWlDisplayWrapper);
695 mWlDisplayWrapper = NULL;
696 }
697
698 if (mWlQueue) {
699 wl_event_queue_destroy (mWlQueue);
700 mWlQueue = NULL;
701 }
702
703 if (mWlDisplay) {
704 wl_display_flush (mWlDisplay);
705 wl_display_disconnect (mWlDisplay);
706 mWlDisplay = NULL;
707 }
708
709 DEBUG("closeDisplay out");
710}
711
712int WaylandDisplay::toDmaBufferFormat(RenderVideoFormat format, uint32_t *outDmaformat /*out param*/, uint64_t *outDmaformatModifiers /*out param*/)
713{
714 if (!outDmaformat || !outDmaformatModifiers) {
715 WARNING("NULL params");
716 return -1;
717 }
718
719 *outDmaformat = 0;
720 *outDmaformatModifiers = 0;
721
722 uint32_t dmaformat = video_format_to_wl_dmabuf_format (format);
723 if (dmaformat == -1) {
724 ERROR("Error not found render video format:%d to wl dmabuf format",format);
725 return -1;
726 }
727
728 TRACE("render video format:%d -> dmabuf format:%d",format,dmaformat);
729 *outDmaformat = (uint32_t)dmaformat;
730
731 /*get dmaformat and modifiers*/
732 auto item = mDmaBufferFormats.find(dmaformat);
733 if (item == mDmaBufferFormats.end()) { //not found
734 WARNING("Not found dmabuf for render video format :%d",format);
735 *outDmaformatModifiers = 0;
736 return 0;
737 }
738
739 *outDmaformatModifiers = (uint64_t)item->second;
740
741 return 0;
742}
743
744int WaylandDisplay::toShmBufferFormat(RenderVideoFormat format, uint32_t *outformat)
745{
746 if (!outformat) {
747 WARNING("NULL params");
748 return -1;
749 }
750
751 *outformat = 0;
752
753 int shmformat = (int)video_format_to_wl_shm_format(format);
754 if (shmformat < 0) {
755 ERROR("Error not found render video format:%d to wl shmbuf format",format);
756 return -1;
757 }
758
759 for (auto item = mShmFormats.begin(); item != mShmFormats.end(); ++item) {
760 uint32_t registFormat = (uint32_t)*item;
761 if (registFormat == (uint32_t)shmformat) {
762 *outformat = registFormat;
763 return 0;
764 }
765 }
766
767 return -1;
768}
769
770void WaylandDisplay::setVideoBufferFormat(RenderVideoFormat format)
771{
772 TRACE("set video buffer format: %d",format);
773 mBufferFormat = format;
774};
775
776void WaylandDisplay::setDisplayOutput(int output)
777{
778 TRACE("select display output: %d",output);
779 if (output < 0 || output >= DEFAULT_DISPLAY_OUTPUT_NUM) {
780 ERROR( "display output index error,please set 0:primary or 1:extend,now:%d",output);
781 return;
782 }
783 if (mActiveOutput != output) {
784 setRenderRectangle(mOutput[output].offsetX, mOutput[output].offsetY,
785 mOutput[output].width, mOutput[output].height);
786 mActiveOutput = output;
787 }
788}
789
790int WaylandDisplay::getDisplayOutput()
791{
792 return mActiveOutput;
793}
794
795void WaylandDisplay::setPip(int pip)
796{
797 INFO("set pip:%d",pip);
798 mPip = pip;
799}
800
801void WaylandDisplay::createCommonWindowSurface()
802{
803 struct wl_region *region;
804
805 mAreaSurface = wl_compositor_create_surface (mCompositor);
806 mVideoSurface = wl_compositor_create_surface (mCompositor);
807 mAreaSurfaceWrapper = (struct wl_surface *)wl_proxy_create_wrapper (mAreaSurface);
808 mVideoSurfaceWrapper = (struct wl_surface *)wl_proxy_create_wrapper (mVideoSurface);
809
810 wl_proxy_set_queue ((struct wl_proxy *) mAreaSurfaceWrapper, mWlQueue);
811 wl_proxy_set_queue ((struct wl_proxy *) mVideoSurfaceWrapper, mWlQueue);
812
813 /* embed video_surface in area_surface */
814 mVideoSubSurface = wl_subcompositor_get_subsurface (mSubCompositor, mVideoSurface, mAreaSurface);
815 wl_subsurface_set_desync (mVideoSubSurface);
816
817 if (mViewporter) {
818 mAreaViewport = wp_viewporter_get_viewport (mViewporter, mAreaSurface);
819 mVideoViewport = wp_viewporter_get_viewport (mViewporter, mVideoSurface);
820 }
821
822 /* do not accept input */
823 region = wl_compositor_create_region (mCompositor);
824 wl_surface_set_input_region (mAreaSurface, region);
825 wl_region_destroy (region);
826
827 region = wl_compositor_create_region (mCompositor);
828 wl_surface_set_input_region (mVideoSurface, region);
829 wl_region_destroy (region);
830}
831
832void WaylandDisplay::createXdgShellWindowSurface()
833{
834 /* Check which protocol we will use (in order of preference) */
835 if (mXdgWmBase) {
836 /* First create the XDG surface */
837 mXdgSurface= xdg_wm_base_get_xdg_surface (mXdgWmBase, mAreaSurface);
838 if (!mXdgSurface) {
839 ERROR("Unable to get xdg_surface");
840 return;
841 }
842 xdg_surface_add_listener (mXdgSurface, &xdg_surface_listener,(void *)this);
843
844 /* Then the toplevel */
845 mXdgToplevel= xdg_surface_get_toplevel (mXdgSurface);
846 if (!mXdgSurface) {
847 ERROR("Unable to get xdg_toplevel");
848 return;
849 }
850 xdg_toplevel_add_listener (mXdgToplevel, &xdg_toplevel_listener, this);
851
852 /* Finally, commit the xdg_surface state as toplevel */
853 mXdgSurfaceConfigured = false;
854 wl_surface_commit (mAreaSurface);
855 wl_display_flush (mWlDisplay);
856 /* we need exactly 3 roundtrips to discover global objects and their state */
857 for (int i = 0; i < 3; i++) {
858 if (wl_display_roundtrip_queue(mWlDisplay, mWlQueue) < 0) {
859 ERROR("Error communicating with the wayland display");
860 }
861 }
862
863 if (mXdgSurfaceConfigured) {
864 INFO("xdg surface had configured");
865 } else {
866 WARNING("xdg surface not configured");
867 }
868
869 //full screen show
870 if (mFullScreen && mOutput[mActiveOutput].wlOutput) {
871 ensureFullscreen(mFullScreen);
872 }
873
874 //if wl_output had detected, the width and height of mRenderRect will be set
875 //we need invoking setRenderRectangle
876 // if (mRenderRect.w > 0 && mRenderRect.h > 0) {
877 // setRenderRectangle(mRenderRect.x, mRenderRect.y, mRenderRect.w, mRenderRect.h);
878 // }
879 } else {
880 ERROR("Unable to use xdg_wm_base ");
881 return;
882 }
883}
884
885void WaylandDisplay::destroyWindowSurfaces()
886{
887 if (mAreaShmBuffer) {
888 delete mAreaShmBuffer;
889 mAreaShmBuffer = NULL;
890 }
891
892 //clean all wayland buffers
893 cleanAllWaylandBuffer();
894
895 if (mXdgToplevel) {
896 xdg_toplevel_destroy (mXdgToplevel);
897 mXdgToplevel = NULL;
898 }
899
900 if (mXdgSurface) {
901 xdg_surface_destroy (mXdgSurface);
902 mXdgSurface = NULL;
903 }
904
905 if (mVideoSurfaceWrapper) {
906 wl_proxy_wrapper_destroy (mVideoSurfaceWrapper);
907 mVideoSurfaceWrapper = NULL;
908 }
909
910 if (mVideoSubSurface) {
911 wl_subsurface_destroy (mVideoSubSurface);
912 mVideoSubSurface = NULL;
913 }
914
915 if (mVideoSurface) {
916 wl_surface_destroy (mVideoSurface);
917 mVideoSurface = NULL;
918 }
919
920 if (mAreaSurfaceWrapper) {
921 wl_proxy_wrapper_destroy (mAreaSurfaceWrapper);
922 mAreaSurfaceWrapper = NULL;
923 }
924
925 if (mAreaSurface) {
926 wl_surface_destroy (mAreaSurface);
927 mAreaSurface = NULL;
928 mReCommitAreaSurface = false;
929 }
930}
931
932void WaylandDisplay::ensureFullscreen(bool fullscreen)
933{
934 if (mXdgWmBase) {
935 DEBUG("full screen : %d",fullscreen);
936 if (fullscreen) {
937 xdg_toplevel_set_fullscreen (mXdgToplevel, mOutput[mActiveOutput].wlOutput);
938 } else {
939 xdg_toplevel_unset_fullscreen (mXdgToplevel);
940 }
941 }
942}
943
944void WaylandDisplay::setRenderRectangle(int x, int y, int w, int h)
945{
946 DEBUG("set render rect:x:%d,y:%d,w:%d,h:%d",x,y,w,h);
947
948 if (w <= 0 || h <= 0) {
949 WARNING( "wrong render width or height %dx%d",w,h);
950 return;
951 }
952
953 mRenderRect.x = x;
954 mRenderRect.y = y;
955 mRenderRect.w = w;
956 mRenderRect.h = h;
957
958 if (!mXdgSurfaceConfigured) {
959 WARNING("Not configured xdg");
960 return;
961 }
962
963 if (mAreaViewport) {
964 wp_viewport_set_destination (mAreaViewport, w, h);
965 }
966
967 updateBorders();
968
969 if (mVideoWidth != 0 && mVideoSurface) {
970 wl_subsurface_set_sync (mVideoSubSurface);
971 resizeVideoSurface(true);
972 }
973
974 wl_surface_damage (mAreaSurfaceWrapper, 0, 0, w, h);
975 wl_surface_commit (mAreaSurfaceWrapper);
976
977 if (mVideoWidth != 0) {
978 wl_subsurface_set_desync (mVideoSubSurface);
979 }
980}
981
982
983void WaylandDisplay::setFrameSize(int w, int h)
984{
985 mVideoWidth = w;
986 mVideoHeight = h;
987 TRACE("frame w:%d,h:%d",mVideoWidth,mVideoHeight);
988 if (mRenderRect.w > 0 && mVideoSurface) {
989 resizeVideoSurface(true);
990 }
991}
992
993void WaylandDisplay::setWindowSize(int x, int y, int w, int h)
994{
995 mWindowRect.x = x;
996 mWindowRect.y = y;
997 mWindowRect.w = w;
998 mWindowRect.h = h;
999 TRACE("window size:x:%d,y:%d,w:%d,h:%d",mWindowRect.x,mWindowRect.y,mWindowRect.w,mWindowRect.h);
1000 if (mWindowRect.w > 0 && mVideoWidth > 0 && mVideoSurface) {
1001 //if had full screen, unset it and set window size
1002 if (mFullScreen) {
1003 mFullScreen = false;
1004 ensureFullscreen(mFullScreen);
1005 }
1006 resizeVideoSurface(true);
1007 }
1008}
1009
1010
1011void WaylandDisplay::resizeVideoSurface(bool commit)
1012{
1013 Rectangle src = {0,};
1014 Rectangle dst = {0,};
1015 Rectangle res;
1016
1017 /* center the video_subsurface inside area_subsurface */
1018 src.w = mVideoWidth;
1019 src.h = mVideoHeight;
1020 /*if had set the window size, we will scall
1021 video surface to this window size*/
1022 if (mWindowRect.w > 0 && mWindowRect.h > 0) {
1023 dst.x = mWindowRect.x;
1024 dst.y = mWindowRect.y;
1025 dst.w = mWindowRect.w;
1026 dst.h = mWindowRect.h;
1027 if (mWindowRect.w > mRenderRect.w && mWindowRect.h > mRenderRect.h) {
1028 WARNING("Error window size:%dx%d, but render size:%dx%d,reset to render size",
1029 mWindowRect.w,mWindowRect.h,mRenderRect.w,mRenderRect.h);
1030 dst.x = mRenderRect.x;
1031 dst.y = mRenderRect.y;
1032 dst.w = mRenderRect.w;
1033 dst.h = mRenderRect.h;
1034 }
1035 //to do,we need set geometry?
1036 //if (mXdgSurface) {
1037 // xdg_surface_set_window_geometry(mXdgSurface, mWindowRect.x, mWindowRect.y, mWindowRect.w, mWindowRect.h);
1038 //}
1039 } else { //scal video to full screen
1040 dst.w = mRenderRect.w;
1041 dst.h = mRenderRect.h;
1042 }
1043
1044 if (mViewporter) {
1045 videoCenterRect(src, dst, &res, true);
1046 } else {
1047 videoCenterRect(src, dst, &res, false);
1048 }
1049
1050 wl_subsurface_set_position (mVideoSubSurface, res.x, res.y);
1051
1052 if (commit) {
1053 wl_surface_damage (mVideoSurfaceWrapper, 0, 0, res.w, res.h);
1054 wl_surface_commit (mVideoSurfaceWrapper);
1055 }
1056
1057 //top level setting
1058 if (mXdgToplevel) {
1059 struct wl_region *region;
1060
1061 region = wl_compositor_create_region (mCompositor);
1062 wl_region_add (region, 0, 0, mRenderRect.w, mRenderRect.h);
1063 wl_surface_set_input_region (mAreaSurface, region);
1064 wl_region_destroy (region);
1065 }
1066
1067 /* this is saved for use in wl_surface_damage */
1068 mVideoRect.x = res.x;
1069 mVideoRect.y = res.y;
1070 mVideoRect.w = res.w;
1071 mVideoRect.h = res.h;
1072
1073 //to scale video surface to full screen
1074 wp_viewport_set_destination(mVideoViewport, res.w, res.h);
1075 TRACE("video rectangle,x:%d,y:%d,w:%d,h:%d",mVideoRect.x, mVideoRect.y, mVideoRect.w, mVideoRect.h);
1076}
1077
1078void WaylandDisplay::setOpaque()
1079{
1080 struct wl_region *region;
1081
1082 /* Set area opaque */
1083 region = wl_compositor_create_region (mCompositor);
1084 wl_region_add (region, 0, 0, mRenderRect.w, mRenderRect.h);
1085 wl_surface_set_opaque_region (mAreaSurface, region);
1086 wl_region_destroy (region);
1087}
1088
1089int WaylandDisplay::prepareFrameBuffer(RenderBuffer * buf)
1090{
1091 WaylandBuffer *waylandBuf = NULL;
1092 int ret;
1093
1094 waylandBuf = findWaylandBuffer(buf);
1095 if (waylandBuf == NULL) {
1096 waylandBuf = new WaylandBuffer(this);
1097 waylandBuf->setBufferFormat(mBufferFormat);
1098 ret = waylandBuf->constructWlBuffer(buf);
1099 if (ret != 0) {
1100 WARNING("dmabufConstructWlBuffer fail,release waylandbuf");
1101 //delete waylanBuf,WaylandBuffer object destruct will call release callback
1102 goto waylandbuf_fail;
1103 } else {
1104 addWaylandBuffer(buf, waylandBuf);
1105 }
1106 }
1107 return 0;
1108waylandbuf_fail:
1109 //delete waylandbuf
1110 delete waylandBuf;
1111 waylandBuf = NULL;
1112 return -1;
1113}
1114
1115void WaylandDisplay::displayFrameBuffer(RenderBuffer * buf, int64_t realDisplayTime)
1116{
1117 WaylandBuffer *waylandBuf = NULL;
1118 struct wl_buffer * wlbuffer = NULL;
1119 int ret;
1120
1121 if (!buf) {
1122 ERROR("Error input params, waylandbuffer is null");
1123 return;
1124 }
1125
1126 //must commit areasurface first, because weston xdg surface maybe timeout
1127 //this cause video is not display,commit can resume xdg surface
1128 if (!mReCommitAreaSurface) {
1129 mReCommitAreaSurface = true;
1130 wl_surface_commit (mAreaSurface);
1131 }
1132
1133 TRACE("display renderBuffer:%p,PTS:%lld,realtime:%lld",buf, buf->pts, realDisplayTime);
1134
1135 if (buf->flag & BUFFER_FLAG_DMA_BUFFER) {
1136 if (buf->dma.width <=0 || buf->dma.height <=0) {
1137 buf->dma.width = mVideoWidth;
1138 buf->dma.height = mVideoHeight;
1139 }
1140 waylandBuf = findWaylandBuffer(buf);
1141 if (waylandBuf) {
1142 waylandBuf->setRenderRealTime(realDisplayTime);
1143 ret = waylandBuf->constructWlBuffer(buf);
1144 if (ret != 0) {
1145 WARNING("dmabufConstructWlBuffer fail,release waylandbuf");
1146 //delete waylanBuf,WaylandBuffer object destruct will call release callback
1147 goto waylandbuf_fail;
1148 }
1149 } else {
1150 ERROR("NOT found wayland buffer,please prepare buffer first");
1151 goto waylandbuf_fail;
1152 }
1153 }
1154
1155 if (waylandBuf) {
1156 wlbuffer = waylandBuf->getWlBuffer();
1157 }
1158 if (wlbuffer) {
1159 std::lock_guard<std::mutex> lck(mRenderMutex);
1160 ++mCommitCnt;
1161 uint32_t hiPts = realDisplayTime >> 32;
1162 uint32_t lowPts = realDisplayTime & 0xFFFFFFFF;
1163 //attach this wl_buffer to weston
1164 TRACE("++attach,renderbuf:%p,wl_buffer:%p(0,0,%d,%d),pts:%lld,commitCnt:%d",buf,wlbuffer,mVideoRect.w,mVideoRect.h,buf->pts,mCommitCnt);
1165 waylandBuf->attach(mVideoSurfaceWrapper);
1166
1167 if (mIsSendPtsToWeston) {
1168 TRACE("display time:%lld,hiPts:%u,lowPts:%u",realDisplayTime, hiPts, lowPts);
1169 wl_surface_set_pts(mVideoSurfaceWrapper, hiPts, lowPts);
1170 }
1171
1172 wl_surface_damage (mVideoSurfaceWrapper, 0, 0, mVideoRect.w, mVideoRect.h);
1173 wl_surface_commit (mVideoSurfaceWrapper);
1174 //insert this buffer to committed weston buffer manager
1175 std::pair<int64_t, WaylandBuffer *> item(buf->pts, waylandBuf);
1176 mCommittedBufferMap.insert(item);
1177 } else {
1178 WARNING("wlbuffer is NULL");
1179 /* clear both video and parent surfaces */
1180 cleanSurface();
1181 }
1182
1183 wl_display_flush (mWlDisplay);
1184
1185 return;
1186waylandbuf_fail:
1187 //notify dropped
1188 mWaylandPlugin->handleFrameDropped(buf);
1189 //notify app release this buf
1190 mWaylandPlugin->handleBufferRelease(buf);
1191 //delete waylandbuf
1192 delete waylandBuf;
1193 waylandBuf = NULL;
1194 return;
1195}
1196
1197void WaylandDisplay::handleBufferReleaseCallback(WaylandBuffer *buf)
1198{
1199 {
1200 std::lock_guard<std::mutex> lck(mRenderMutex);
1201 --mCommitCnt;
1202 //remove buffer if this buffer is ready to release
1203 RenderBuffer *renderBuffer = buf->getRenderBuffer();
1204 auto item = mCommittedBufferMap.find(renderBuffer->pts);
1205 if (item != mCommittedBufferMap.end()) {
1206 mCommittedBufferMap.erase(item);
1207 } else {
1208 WARNING("Can't find WaylandBuffer in buffer map");
1209 return;
1210 }
1211 }
1212 RenderBuffer *renderBuffer = buf->getRenderBuffer();
1213 TRACE("handle release renderBuffer :%p,priv:%p,PTS:%lld,realtime:%lld us,commitCnt:%d",renderBuffer,renderBuffer->priv,renderBuffer->pts/1000,buf->getRenderRealTime(),mCommitCnt);
1214 mWaylandPlugin->handleBufferRelease(renderBuffer);
1215}
1216
1217void WaylandDisplay::handleFrameDisplayedCallback(WaylandBuffer *buf)
1218{
1219 RenderBuffer *renderBuffer = buf->getRenderBuffer();
1220 TRACE("handle displayed renderBuffer :%p,PTS:%lld us,realtime:%lld us",renderBuffer,renderBuffer->pts/1000,buf->getRenderRealTime());
1221 mWaylandPlugin->handleFrameDisplayed(renderBuffer);
1222}
1223
1224void WaylandDisplay::handleFrameDropedCallback(WaylandBuffer *buf)
1225{
1226 RenderBuffer *renderBuffer = buf->getRenderBuffer();
1227 TRACE("handle droped renderBuffer :%p,PTS:%lld us,realtime:%lld us",renderBuffer,renderBuffer->pts/1000,buf->getRenderRealTime());
1228 mWaylandPlugin->handleFrameDropped(renderBuffer);
1229}
1230
1231
1232void WaylandDisplay::readyToRun()
1233{
1234 mFd = wl_display_get_fd (mWlDisplay);
1235}
1236
1237bool WaylandDisplay::threadLoop()
1238{
1239 int ret;
1240 struct pollfd pfd;
1241
1242 pfd.fd = mFd;
1243 pfd.events = POLLERR | POLLNVAL | POLLHUP |POLLIN | POLLPRI | POLLRDNORM;
1244 pfd.revents = 0;
1245
1246 while (wl_display_prepare_read_queue (mWlDisplay, mWlQueue) != 0) {
1247 wl_display_dispatch_queue_pending (mWlDisplay, mWlQueue);
1248 }
1249
1250 wl_display_flush (mWlDisplay);
1251
1252 /*poll timeout value must > 300 ms,otherwise zwp_linux_dmabuf will create failed,
1253 so do use -1 to wait for ever*/
1254 ret = poll(&pfd, 1, 500);
1255 if (ret < 0) { //poll error
1256 WARNING("poll error");
1257 wl_display_cancel_read(mWlDisplay);
1258 return false;
1259 } else if (ret == 0) { //poll time out
1260 return true; //run loop
1261 }
1262
1263 if (wl_display_read_events (mWlDisplay) == -1) {
1264 goto tag_error;
1265 }
1266
1267 wl_display_dispatch_queue_pending (mWlDisplay, mWlQueue);
1268 return true;
1269tag_error:
1270 ERROR("Error communicating with the wayland server");
1271 return false;
1272}
1273
1274void WaylandDisplay::videoCenterRect(Rectangle src, Rectangle dst, Rectangle *result, bool scaling)
1275{
1276 //if dst is a small window, we scale video to map window size,don't doing center
1277 if (mRenderRect.w != dst.w && mRenderRect.h != dst.h) {
1278 result->x = dst.x;
1279 result->y = dst.y;
1280 result->w = dst.w;
1281 result->h = dst.h;
1282 TRACE("small window source is %dx%d dest is %dx%d, result is %dx%d with x,y %dx%d",
1283 src.w, src.h, dst.w, dst.h, result->w, result->h, result->x, result->y);
1284 return;
1285 }
1286 if (!scaling) {
1287 result->w = MIN (src.w, dst.w);
1288 result->h = MIN (src.h, dst.h);
1289 result->x = dst.x + (dst.w - result->w) / 2;
1290 result->y = dst.y + (dst.h - result->h) / 2;
1291 } else {
1292 double src_ratio, dst_ratio;
1293
1294 src_ratio = (double) src.w / src.h;
1295 dst_ratio = (double) dst.w / dst.h;
1296
1297 if (src_ratio > dst_ratio) {
1298 result->w = dst.w;
1299 result->h = dst.w / src_ratio;
1300 result->x = dst.x;
1301 result->y = dst.y + (dst.h - result->h) / 2;
1302 } else if (src_ratio < dst_ratio) {
1303 result->w = dst.h * src_ratio;
1304 result->h = dst.h;
1305 result->x = dst.x + (dst.w - result->w) / 2;
1306 result->y = dst.y;
1307 } else {
1308 result->x = dst.x;
1309 result->y = dst.y;
1310 result->w = dst.w;
1311 result->h = dst.h;
1312 }
1313 }
1314
1315 TRACE("source is %dx%d dest is %dx%d, result is %dx%d with x,y %dx%d",
1316 src.w, src.h, dst.w, dst.h, result->w, result->h, result->x, result->y);
1317}
1318
1319void WaylandDisplay::updateBorders()
1320{
1321 int width,height;
1322
1323 if (mNoBorderUpdate)
1324 return;
1325
1326 if (mViewporter) {
1327 width = height = 1;
1328 mNoBorderUpdate = true;
1329 } else {
1330 width = mRenderRect.w;
1331 height = mRenderRect.h;
1332 }
1333
1334 RenderVideoFormat format = VIDEO_FORMAT_BGRA;
1335 mAreaShmBuffer = new WaylandShmBuffer(this);
1336 struct wl_buffer *wlbuf = mAreaShmBuffer->constructWlBuffer(width, height, format);
1337 if (wlbuf == NULL) {
1338 delete mAreaShmBuffer;
1339 mAreaShmBuffer = NULL;
1340 }
1341
1342 wl_surface_attach(mAreaSurfaceWrapper, wlbuf, 0, 0);
1343}
1344
1345std::size_t WaylandDisplay::calculateDmaBufferHash(RenderDmaBuffer &dmabuf)
1346{
1347 std::string hashString("");
1348 for (int i = 0; i < dmabuf.planeCnt; i++) {
1349 char hashtmp[1024];
1350 snprintf (hashtmp, 1024, "%d%d%d%d%d%d", dmabuf.width,dmabuf.height,dmabuf.planeCnt,
1351 dmabuf.stride[i],dmabuf.offset[i],dmabuf.fd[i]);
1352 std::string tmp(hashtmp);
1353 hashString += tmp;
1354 }
1355
1356 std::size_t hashval = std::hash<std::string>()(hashString);
1357 //TRACE("hashstr:%s,val:%zu",hashString.c_str(),hashval);
1358 return hashval;
1359}
1360
1361void WaylandDisplay::addWaylandBuffer(RenderBuffer * buf, WaylandBuffer *waylandbuf)
1362{
1363 if (buf->flag & BUFFER_FLAG_DMA_BUFFER) {
1364 std::size_t hashval = calculateDmaBufferHash(buf->dma);
1365 std::pair<std::size_t, WaylandBuffer *> item(hashval, waylandbuf);
1366 //TRACE("fd:%d,w:%d,h:%d,%p,hash:%zu",buf->dma.fd[0],buf->dma.width,buf->dma.height,waylandbuf,hashval);
1367 mWaylandBuffersMap.insert(item);
1368 }
1369
1370 //clean invalid wayland buffer,if video resolution changed
1371 for (auto item = mWaylandBuffersMap.begin(); item != mWaylandBuffersMap.end(); ) {
1372 WaylandBuffer *waylandbuf = (WaylandBuffer*)item->second;
1373 if ((waylandbuf->getFrameWidth() != buf->dma.width ||
1374 waylandbuf->getFrameHeight() != buf->dma.height) &&
1375 waylandbuf->isFree()) {
1376 TRACE("delete wayland buffer,width:%d(%d),height:%d(%d)",
1377 waylandbuf->getFrameWidth(),buf->dma.width,
1378 waylandbuf->getFrameHeight(),buf->dma.height);
1379 mWaylandBuffersMap.erase(item++);
1380 delete waylandbuf;
1381 } else {
1382 item++;
1383 }
1384 }
1385 TRACE("mWaylandBuffersMap size:%d",mWaylandBuffersMap.size());
1386}
1387
1388WaylandBuffer* WaylandDisplay::findWaylandBuffer(RenderBuffer * buf)
1389{
1390 std::size_t hashval = calculateDmaBufferHash(buf->dma);
1391 auto item = mWaylandBuffersMap.find(hashval);
1392 if (item == mWaylandBuffersMap.end()) {
1393 return NULL;
1394 }
1395
1396 return (WaylandBuffer*) item->second;
1397}
1398
1399void WaylandDisplay::cleanAllWaylandBuffer()
1400{
1401 //free all obtain buff
1402 for (auto item = mWaylandBuffersMap.begin(); item != mWaylandBuffersMap.end(); ) {
1403 WaylandBuffer *waylandbuf = (WaylandBuffer*)item->second;
1404 mWaylandBuffersMap.erase(item++);
1405 delete waylandbuf;
1406 }
1407}
1408
1409void WaylandDisplay::flushBuffers()
1410{
1411 INFO("flushBuffers");
1412 std::lock_guard<std::mutex> lck(mRenderMutex);
1413 for (auto item = mCommittedBufferMap.begin(); item != mCommittedBufferMap.end(); item++) {
1414 WaylandBuffer *waylandbuf = (WaylandBuffer*)item->second;
1415 waylandbuf->forceRedrawing();
1416 handleFrameDisplayedCallback(waylandbuf);
1417 }
1418}
1419
1420void WaylandDisplay::cleanSurface()
1421{
1422 /* clear both video and parent surfaces */
1423 wl_surface_attach (mVideoSurfaceWrapper, NULL, 0, 0);
1424 wl_surface_commit (mVideoSurfaceWrapper);
1425 wl_surface_attach (mAreaSurfaceWrapper, NULL, 0, 0);
1426 wl_surface_commit (mAreaSurfaceWrapper);
1427}