1 From b60e0a361d29723643fe81b47bff8f86d5200258 Mon Sep 17 00:00:00 2001
2 From: Kenta <murakami.kenta002@jp.panasonic.com>
3 Date: Wed, 6 Sep 2023 18:44:22 +0900
4 Subject: [PATCH] Add agl-shell-desktop and xdg-shell supports
7 CMakeLists.txt | 25 +++
8 include/rvgpu-renderer/renderer/rvgpu-egl.h | 9 +-
9 src/rvgpu-renderer/CMakeLists.txt | 3 +
10 src/rvgpu-renderer/backend/rvgpu-gbm.c | 2 +
11 src/rvgpu-renderer/backend/rvgpu-wayland.c | 192 +++++++++++++++++---
12 src/rvgpu-renderer/renderer/rvgpu-egl.c | 3 +
13 src/rvgpu-renderer/rvgpu-renderer.c | 11 +-
14 7 files changed, 220 insertions(+), 25 deletions(-)
16 diff --git a/CMakeLists.txt b/CMakeLists.txt
17 index f569ca2..85c875a 100644
20 @@ -20,6 +20,31 @@ cmake_minimum_required(VERSION 3.2)
22 set(CMAKE_C_STANDARD 11)
24 +find_program(WAYLAND_SCANNER_EXECUTABLE wayland-scanner)
26 +message("generating agl-shell-desktop client files from: agl-shell-desktop.xml")
28 +execute_process ( COMMAND mkdir ${CMAKE_BINARY_DIR}/protocol)
30 +execute_process ( COMMAND ${WAYLAND_SCANNER_EXECUTABLE} private-code
31 + ${CMAKE_SYSROOT}/usr/share/agl-compositor/protocols/agl-shell-desktop.xml
32 + ${CMAKE_BINARY_DIR}/protocol/agl-shell-desktop-protocol.c)
34 +execute_process ( COMMAND ${WAYLAND_SCANNER_EXECUTABLE} client-header
35 + ${CMAKE_SYSROOT}/usr/share/agl-compositor/protocols/agl-shell-desktop.xml
36 + ${CMAKE_BINARY_DIR}/protocol/agl-shell-desktop-protocol.h)
38 +message("generating agl-shell-desktop client files from: xdg-shell.xml")
40 +execute_process ( COMMAND ${WAYLAND_SCANNER_EXECUTABLE} private-code
41 + ${CMAKE_SYSROOT}/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml
42 + ${CMAKE_BINARY_DIR}/protocol/xdg-shell-protocol.c)
44 +execute_process ( COMMAND ${WAYLAND_SCANNER_EXECUTABLE} client-header
45 + ${CMAKE_SYSROOT}/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml
46 + ${CMAKE_BINARY_DIR}/protocol/xdg-shell-protocol.h)
49 if (CMAKE_SYSROOT AND NOT ENV{PKG_CONFIG_LIBDIR})
50 set(ENV{PKG_CONFIG_DIR} "")
51 set(ENV{PKG_CONFIG_LIBDIR} "${CMAKE_SYSROOT}/usr/lib/pkgconfig:${CMAKE_SYSROOT}/usr/share/pkgconfig")
52 diff --git a/include/rvgpu-renderer/renderer/rvgpu-egl.h b/include/rvgpu-renderer/renderer/rvgpu-egl.h
53 index ebd2bd2..dcff36a 100644
54 --- a/include/rvgpu-renderer/renderer/rvgpu-egl.h
55 +++ b/include/rvgpu-renderer/renderer/rvgpu-egl.h
56 @@ -59,6 +59,9 @@ struct rvgpu_scanout_params {
57 uint32_t id; /**< ID for scanout window (i.e. IVI id)*/
58 bool enabled; /**< enable/disable scanout */
59 bool boxed; /**< box is set by user */
60 + struct rvgpu_box agl_win; /** Window position & limit on AGL */
65 struct rvgpu_scanout {
66 @@ -118,6 +121,8 @@ struct rvgpu_egl_state {
71 + bool user_specified_scanouts;
74 /** Initialize main context */
75 @@ -150,11 +155,11 @@ void rvgpu_egl_destroy_scanout(struct rvgpu_egl_state *e,
77 /** Draw Virgl output on the surface */
78 void rvgpu_egl_draw(struct rvgpu_egl_state *e, struct rvgpu_scanout *s,
82 /** Redraw all scanouts with given resource id */
83 void rvgpu_egl_drawall(struct rvgpu_egl_state *e, unsigned int res_id,
87 /* Async event handling */
88 /** Call before polling */
89 diff --git a/src/rvgpu-renderer/CMakeLists.txt b/src/rvgpu-renderer/CMakeLists.txt
90 index dc5f5b0..c8a8c34 100644
91 --- a/src/rvgpu-renderer/CMakeLists.txt
92 +++ b/src/rvgpu-renderer/CMakeLists.txt
96 add_executable(rvgpu-renderer
97 + ${CMAKE_BINARY_DIR}/protocol/agl-shell-desktop-protocol.c
98 + ${CMAKE_BINARY_DIR}/protocol/xdg-shell-protocol.c
99 backend/rvgpu-wayland.c
102 @@ -28,6 +30,7 @@ add_executable(rvgpu-renderer
103 target_include_directories(rvgpu-renderer
105 ${PROJECT_SOURCE_DIR}/include
106 + ${CMAKE_BINARY_DIR}/protocol
107 ${extlibs_INCLUDE_DIRS}
109 target_compile_definitions(rvgpu-renderer PRIVATE _GNU_SOURCE)
110 diff --git a/src/rvgpu-renderer/backend/rvgpu-gbm.c b/src/rvgpu-renderer/backend/rvgpu-gbm.c
111 index 4194b0d..b2b3ed3 100644
112 --- a/src/rvgpu-renderer/backend/rvgpu-gbm.c
113 +++ b/src/rvgpu-renderer/backend/rvgpu-gbm.c
114 @@ -259,6 +259,8 @@ static void rvgpu_gbm_create_scanout(struct rvgpu_egl_state *e,
116 eglMakeCurrent(e->dpy, s->surface, s->surface, e->context);
117 glGenFramebuffers(1, &s->fb);
119 + rvgpu_egl_draw(e, s, false);
122 static void rvgpu_gbm_page_flip_handler(int fd, unsigned int sequence,
123 diff --git a/src/rvgpu-renderer/backend/rvgpu-wayland.c b/src/rvgpu-renderer/backend/rvgpu-wayland.c
124 index 0aaeaa7..c00ff00 100644
125 --- a/src/rvgpu-renderer/backend/rvgpu-wayland.c
126 +++ b/src/rvgpu-renderer/backend/rvgpu-wayland.c
128 #include <rvgpu-renderer/renderer/rvgpu-egl.h>
129 #include <rvgpu-renderer/renderer/rvgpu-input.h>
131 +#include "agl-shell-desktop-protocol.h"
132 +#include "xdg-shell-protocol.h"
134 struct rvgpu_native {
135 /* Window structures */
136 struct wl_surface *surface;
137 struct wl_shell_surface *shell_surface;
138 struct wl_egl_window *egl_window;
139 struct ivi_surface *ivi_surface;
140 + struct xdg_surface *xdg_surface;
141 + struct xdg_toplevel *xdg_toplevel;
142 + bool wait_for_configure;
145 struct rvgpu_wl_state {
146 @@ -58,6 +64,9 @@ struct rvgpu_wl_state {
147 struct wl_keyboard *keyboard;
148 struct wl_shell *shell;
149 struct ivi_application *ivi_app;
150 + struct xdg_wm_base *wm_base;
151 + struct agl_shell_desktop *agl_shell_desktop;
152 + struct wl_output *output;
155 struct rvgpu_egl_state egl;
156 @@ -78,6 +87,16 @@ static inline struct rvgpu_wl_state *to_wl(struct rvgpu_egl_state *e)
157 return rvgpu_container_of(e, struct rvgpu_wl_state, egl);
160 +static void xdg_wm_base_ping(void *data, struct xdg_wm_base *shell,
163 + xdg_wm_base_pong(shell, serial);
166 +static const struct xdg_wm_base_listener xdg_wm_base_listener = {
170 static struct wl_seat_listener seat_listener;
172 static void registry_add_object(void *data, struct wl_registry *registry,
173 @@ -98,8 +117,17 @@ static void registry_add_object(void *data, struct wl_registry *registry,
174 wl_registry_bind(registry, name, &wl_seat_interface, 1);
175 wl_seat_add_listener(r->seat, &seat_listener, r);
176 } else if (!strcmp(interface, "ivi_application")) {
177 - r->ivi_app = wl_registry_bind(registry, name,
178 - &ivi_application_interface, 1);
179 + r->ivi_app = wl_registry_bind(registry, name, &ivi_application_interface, 1);
180 + } else if (strcmp(interface, "xdg_wm_base") == 0) {
181 + r->wm_base = wl_registry_bind(registry, name,
182 + &xdg_wm_base_interface, 1);
183 + xdg_wm_base_add_listener(r->wm_base, &xdg_wm_base_listener, r);
184 + } else if (strcmp(interface, "agl_shell_desktop") == 0) {
185 + r->agl_shell_desktop = wl_registry_bind(registry, name,
186 + &agl_shell_desktop_interface, 1);
187 + } else if (strcmp(interface, "wl_output") == 0) {
188 + r->output = wl_registry_bind(registry, name,
189 + &wl_output_interface, 1);
193 @@ -157,6 +185,57 @@ static const struct ivi_surface_listener ivi_surface_listener = {
194 handle_ivi_surface_configure,
197 +static void handle_xdg_toplevel_configure(void *data,
198 + struct xdg_toplevel *xdg_toplevel,
199 + int32_t width, int32_t height, struct wl_array *states)
201 + (void)xdg_toplevel;
202 + struct rvgpu_scanout *s = data;
204 + s->window.w = (unsigned int)width;
205 + s->window.h = (unsigned int)height;
207 + wl_egl_window_resize(s->native->egl_window, width, height, 0, 0);
210 +static const struct xdg_toplevel_listener xdg_toplevel_listener = {
211 + handle_xdg_toplevel_configure,
214 +static struct config_param {
215 + struct rvgpu_egl_state *egl_state;
216 + struct rvgpu_scanout *scanout;
219 +static void handle_xdg_surface_configure(void *data,
220 + struct xdg_surface *surface, uint32_t serial)
222 + struct config_param *cp = data;
223 + struct rvgpu_scanout *s = cp->scanout;
224 + struct rvgpu_egl_state *egl = cp->egl_state;
226 + if (surface == NULL)
229 + xdg_surface_ack_configure(surface, serial);
230 + if (s->native->wait_for_configure) {
231 + if (egl->user_specified_scanouts){
232 + for (unsigned int i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; i++) {
233 + if (egl->scanouts[i].params.enabled) {
234 + rvgpu_egl_draw(egl, &egl->scanouts[i], false);
238 + rvgpu_egl_draw(egl, &egl->scanouts[0], false);
240 + s->native->wait_for_configure = false;
244 +static const struct xdg_surface_listener xdg_surface_listener = {
245 + handle_xdg_surface_configure,
248 static void pointer_handle_enter(void *data, struct wl_pointer *pointer,
249 uint32_t serial, struct wl_surface *surface,
250 wl_fixed_t sx, wl_fixed_t sy)
251 @@ -493,6 +572,12 @@ static void rvgpu_wl_destroy_scanout(struct rvgpu_egl_state *e,
252 if (s->native->ivi_surface)
253 ivi_surface_destroy(s->native->ivi_surface);
255 + if (s->native->xdg_toplevel)
256 + xdg_toplevel_destroy(s->native->xdg_toplevel);
258 + if (s->native->xdg_surface)
259 + xdg_surface_destroy(s->native->xdg_surface);
261 wl_surface_destroy(s->native->surface);
264 @@ -510,6 +595,12 @@ static void rvgpu_wl_free(struct rvgpu_egl_state *e)
266 wl_shell_destroy(r->shell);
269 + xdg_wm_base_destroy(r->wm_base);
271 + if (r->agl_shell_desktop)
272 + agl_shell_desktop_destroy(r->agl_shell_desktop);
274 wl_seat_destroy(r->seat);
276 wl_pointer_destroy(r->pointer);
277 @@ -564,6 +655,21 @@ static void rvgpu_wl_process_events(struct rvgpu_egl_state *e, const void *ev,
281 +static void create_opaque_region(struct rvgpu_egl_state *e,
282 + struct rvgpu_scanout *s)
284 + struct rvgpu_wl_state *r = to_wl(e);
285 + struct wl_region *region =
286 + wl_compositor_create_region(r->comp);
288 + wl_region_add(region, 0, 0, (int)s->window.w,
290 + wl_surface_set_opaque_region(s->native->surface,
292 + wl_region_destroy(region);
296 static void rvgpu_wl_set_scanout(struct rvgpu_egl_state *e,
297 struct rvgpu_scanout *s)
299 @@ -572,15 +678,9 @@ static void rvgpu_wl_set_scanout(struct rvgpu_egl_state *e,
300 if (!r->fullscreen) {
301 s->window = s->virgl.box;
303 - if (!r->translucent) {
304 - struct wl_region *region =
305 - wl_compositor_create_region(r->comp);
306 - wl_region_add(region, 0, 0, (int)s->window.w,
308 - wl_surface_set_opaque_region(s->native->surface,
310 - wl_region_destroy(region);
312 + if (!r->translucent)
313 + create_opaque_region(e, s);
315 wl_egl_window_resize(s->native->egl_window,
316 (int)s->window.w, (int)s->window.h,
318 @@ -629,6 +729,59 @@ static void rvgpu_wl_create_scanout(struct rvgpu_egl_state *e,
319 assert(n->ivi_surface);
320 ivi_surface_add_listener(n->ivi_surface, &ivi_surface_listener,
323 + } else if (r->wm_base) {
324 + if (r->agl_shell_desktop){
325 + /* Default create window at the center of the AGL homescreen */
326 + unsigned int agl_x = 0;
327 + unsigned int agl_y = 215;
328 + unsigned int agl_w = 1080;
329 + unsigned int agl_h = 1500;
330 + if (sp && sp->agl_win_set) {
331 + agl_x = sp->agl_win.x;
332 + agl_y = sp->agl_win.y;
336 + * Because we can not resize the surface automatically, window size
337 + * have to be fit to the size of renderer box.
339 + if (sp && sp->boxed) {
340 + agl_w = s->window.w;
341 + agl_h = s->window.h;
344 + agl_shell_desktop_set_app_property(r->agl_shell_desktop,
346 + AGL_SHELL_DESKTOP_APP_ROLE_POPUP,
348 + 0, 0, agl_w, agl_h,
353 + xdg_wm_base_get_xdg_surface(r->wm_base, n->surface);
354 + assert(n->xdg_surface);
356 + struct config_param *cp = malloc(sizeof(*cp));
362 + xdg_surface_add_listener(n->xdg_surface,
363 + &xdg_surface_listener, cp);
364 + n->xdg_toplevel = xdg_surface_get_toplevel(n->xdg_surface);
365 + assert(n->xdg_toplevel);
367 + xdg_toplevel_add_listener(n->xdg_toplevel,
368 + &xdg_toplevel_listener, s);
370 + xdg_toplevel_set_app_id(n->xdg_toplevel, "rvgpu-renderer");
371 + wl_surface_commit(n->surface);
372 + n->wait_for_configure = true;
373 + create_opaque_region(e, s);
375 } else if (r->shell) {
378 @@ -654,16 +807,9 @@ static void rvgpu_wl_create_scanout(struct rvgpu_egl_state *e,
381 wl_shell_surface_set_toplevel(n->shell_surface);
382 - if (!r->translucent) {
383 - struct wl_region *region =
384 - wl_compositor_create_region(r->comp);
386 - wl_region_add(region, 0, 0, (int)s->window.w,
388 - wl_surface_set_opaque_region(n->surface,
390 - wl_region_destroy(region);
392 + if (!r->translucent)
393 + create_opaque_region(e, s);
398 @@ -677,6 +823,10 @@ static void rvgpu_wl_create_scanout(struct rvgpu_egl_state *e,
399 eglMakeCurrent(e->dpy, s->surface, s->surface, e->context);
401 glGenFramebuffers(1, &s->fb);
404 + rvgpu_egl_draw(e, s, false);
408 static const struct rvgpu_egl_callbacks wl_callbacks = {
409 diff --git a/src/rvgpu-renderer/renderer/rvgpu-egl.c b/src/rvgpu-renderer/renderer/rvgpu-egl.c
410 index a9dd398..6918843 100644
411 --- a/src/rvgpu-renderer/renderer/rvgpu-egl.c
412 +++ b/src/rvgpu-renderer/renderer/rvgpu-egl.c
419 #include <rvgpu-renderer/renderer/rvgpu-egl.h>
421 @@ -146,6 +147,7 @@ void rvgpu_egl_free(struct rvgpu_egl_state *e)
426 void rvgpu_egl_draw(struct rvgpu_egl_state *e, struct rvgpu_scanout *s,
429 @@ -191,6 +193,7 @@ void rvgpu_egl_draw(struct rvgpu_egl_state *e, struct rvgpu_scanout *s,
430 (int)s->window.w, (int)s->window.h,
431 GL_COLOR_BUFFER_BIT, GL_NEAREST);
435 e->cb->draw(e, s, vsync);
437 diff --git a/src/rvgpu-renderer/rvgpu-renderer.c b/src/rvgpu-renderer/rvgpu-renderer.c
438 index 3e74289..40b78d4 100644
439 --- a/src/rvgpu-renderer/rvgpu-renderer.c
440 +++ b/src/rvgpu-renderer/rvgpu-renderer.c
441 @@ -52,6 +52,7 @@ static void usage(void)
442 info("\t-f\t\tRun in fullscreen mode\n");
443 info("\t-p port\t\tport for listening (default: %u)\n",
445 + info("\t-w\t\tSet AGL window position\n");
446 info("\t-h\t\tShow this message\n");
449 @@ -189,7 +190,7 @@ int main(int argc, char **argv)
451 memset(sp, 0, sizeof(sp));
453 - while ((opt = getopt(argc, argv, "afhi:c:s:S:b:B:p:g:")) != -1) {
454 + while ((opt = getopt(argc, argv, "afhi:c:s:S:b:w:B:p:g:")) != -1) {
458 @@ -240,6 +241,13 @@ int main(int argc, char **argv)
463 + if (sscanf(optarg, "%u,%u",
464 + &cp->agl_win.x, &cp->agl_win.y) != 2) {
465 + errx(1, "invalid AGL popup application window%s", optarg);
467 + cp->agl_win_set = true;
470 cp->id = (uint32_t)sanity_strtonum(
471 optarg, 1, UINT32_MAX, &errstr);
472 @@ -300,7 +308,6 @@ int main(int argc, char **argv)
475 rvgpu_egl_create_scanout(egl, &egl->scanouts[i]);
476 - rvgpu_egl_draw(egl, &egl->scanouts[i], false);