8 #include <drm_fourcc.h>
10 #include <wayland-server.h>
11 #include <libds/log.h>
12 #include <libds/backend.h>
13 #include <libds/output.h>
14 #include <libds/compositor.h>
15 #include <libds/xdg_shell.h>
16 #include <libds-tizen/allocator/tbm.h>
17 #include <libds-tizen/backend/tdm.h>
18 #include <libds-tizen/tbm_server.h>
20 #define USE_TDM_BUFFER_QUEUE
22 #ifdef USE_TDM_BUFFER_QUEUE
23 #include "pixman-tbm-helper.h"
24 #include "tinyds-tdm-renderer.h"
26 #include <libds/swapchain.h>
29 #include "pixman-helper.h"
31 #define TINYDS_UNUSED __attribute__((unused))
35 struct tinyds_server *server;
36 struct ds_output *ds_output;
37 struct ds_allocator *allocator;
38 #ifdef USE_TDM_BUFFER_QUEUE
39 struct tinyds_renderer renderer;
40 struct ds_tdm_buffer_queue *buffer_queue;
41 struct wl_listener buffer_queue_acquirable;
43 struct ds_swapchain *swapchain;
45 struct ds_buffer *front_buffer;
47 struct wl_listener output_destroy;
48 struct wl_listener output_frame;
58 struct ds_tbm_server *tbm_server;
60 struct wl_display *display;
62 struct ds_backend *backend;
63 struct ds_compositor *compositor;
64 struct ds_xdg_shell *xdg_shell;
66 struct tinyds_output *output;
67 struct wl_event_source *stdin_source;
71 struct wl_listener new_output;
72 struct wl_listener new_xdg_surface;
77 struct tinyds_server *server;
79 struct tinyds_texture *texture;
80 struct ds_xdg_surface *xdg_surface;
82 struct wl_listener xdg_surface_map;
83 struct wl_listener xdg_surface_unmap;
84 struct wl_listener xdg_surface_destroy;
85 struct wl_listener surface_commit;
86 struct wl_list link; // tinyds_server::views
92 struct tinyds_server tinyds;
94 static bool init_server(struct tinyds_server *server, struct wl_display *display);
95 static int server_dispatch_stdin(int fd, uint32_t mask, void *data);
96 static void output_handle_destroy(struct wl_listener *listener, void *data);
97 static void output_handle_frame(struct wl_listener *listener, void *data);
98 static void draw_server_with_damage(struct tinyds_server *server);
99 static void draw_output(struct tinyds_output *output);
100 static void output_swap_buffer(struct tinyds_output *output,
101 struct ds_buffer *buffer);
102 static void view_send_frame_done(struct tinyds_view *view);
103 #ifdef USE_TDM_BUFFER_QUEUE
104 static void output_buffer_queue_init(struct tinyds_output *output);
105 static void output_renderer_init(struct tinyds_output *output);
106 static void output_draw_with_renderer(struct tinyds_output *output);
108 static void output_swapchain_init(struct tinyds_output *output,
109 int width, int height, uint32_t format);
110 static void output_draw_with_swapchain(struct tinyds_output *output);
111 static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image);
117 struct tinyds_server *server = &tinyds;
118 struct wl_display *display;
119 struct wl_event_loop *loop;
123 ds_log_init(DS_INF, NULL);
125 display = wl_display_create();
128 res = init_server(server, display);
131 socket = wl_display_add_socket_auto(display);
134 ds_backend_start(server->backend);
136 setenv("WAYLAND_DISPLAY", socket, true);
138 ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket);
140 loop = wl_display_get_event_loop(display);
141 server->stdin_source = wl_event_loop_add_fd(loop, STDIN_FILENO,
142 WL_EVENT_READABLE, server_dispatch_stdin, server);
144 wl_display_run(display);
146 wl_display_destroy_clients(display);
147 wl_display_destroy(display);
153 view_handle_xdg_surface_map(struct wl_listener *listener,
154 void *data TINYDS_UNUSED)
156 struct tinyds_view *view;
158 view = wl_container_of(listener, view, xdg_surface_map);
163 view_handle_xdg_surface_unmap(struct wl_listener *listener,
164 void *data TINYDS_UNUSED)
166 struct tinyds_view *view;
168 view = wl_container_of(listener, view, xdg_surface_unmap);
169 view->mapped = false;
173 view_handle_xdg_surface_destroy(struct wl_listener *listener,
174 void *data TINYDS_UNUSED)
176 struct tinyds_view *view;
177 struct tinyds_server *server;
179 view = wl_container_of(listener, view, xdg_surface_destroy);
180 server = view->server;
182 wl_list_remove(&view->xdg_surface_destroy.link);
183 wl_list_remove(&view->xdg_surface_map.link);
184 wl_list_remove(&view->xdg_surface_unmap.link);
185 wl_list_remove(&view->surface_commit.link);
186 wl_list_remove(&view->link);
189 draw_server_with_damage(server);
193 view_handle_surface_commit(struct wl_listener *listener,
194 void *data TINYDS_UNUSED)
196 struct tinyds_view *view;
198 view = wl_container_of(listener, view, surface_commit);
199 draw_server_with_damage(view->server);
203 server_new_xdg_surface(struct wl_listener *listener, void *data)
205 struct tinyds_server *server;
206 struct tinyds_view *view;
207 struct ds_xdg_surface *xdg_surface;
209 server = wl_container_of(listener, server, new_xdg_surface);
212 ds_inf("New xdg_surface(%p)", (void *)xdg_surface);
214 view = calloc(1, sizeof *view);
217 view->server = server;
218 view->xdg_surface = xdg_surface;
220 view->xdg_surface_map.notify = view_handle_xdg_surface_map;
221 ds_xdg_surface_add_map_listener(xdg_surface,
222 &view->xdg_surface_map);
224 view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap;
225 ds_xdg_surface_add_unmap_listener(xdg_surface,
226 &view->xdg_surface_unmap);
228 view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy;
229 ds_xdg_surface_add_destroy_listener(xdg_surface,
230 &view->xdg_surface_destroy);
232 view->surface_commit.notify = view_handle_surface_commit;
233 ds_surface_add_commit_listener(
234 ds_xdg_surface_get_surface(xdg_surface),
235 &view->surface_commit);
237 wl_list_insert(server->views.prev, &view->link);
239 view->x = rand() % 1000;
240 view->y = rand() % 500;
244 backend_handle_new_output(struct wl_listener *listener, void *data)
246 struct tinyds_server *server;
247 struct tinyds_output *output;
248 struct ds_output *ds_output;
249 const struct ds_output_mode *mode;
251 server = wl_container_of(listener, server, new_output);
254 ds_inf("New output(%p)", ds_output);
259 mode = ds_output_get_preferred_mode(ds_output);
260 ds_output_set_mode(ds_output, mode);
262 output = calloc(1, sizeof *output);
266 output->server = server;
267 output->ds_output = ds_output;
268 output->width = mode->width;
269 output->height = mode->height;
270 output->drawable = true;
271 output->damaged = true;
273 #ifdef USE_TDM_BUFFER_QUEUE
274 output_buffer_queue_init(output);
275 output_renderer_init(output);
277 output_swapchain_init(output, mode->width, mode->height,
278 DRM_FORMAT_XRGB8888);
281 output->output_destroy.notify = output_handle_destroy;
282 ds_output_add_destroy_listener(ds_output, &output->output_destroy);
284 output->output_frame.notify = output_handle_frame;
285 ds_output_add_frame_listener(ds_output, &output->output_frame);
287 server->output = output;
293 init_server(struct tinyds_server *server, struct wl_display *display)
295 server->display = display;
297 wl_list_init(&server->views);
299 if (wl_display_init_shm(display) != 0)
302 server->backend = ds_tdm_backend_create(display);
303 if (!server->backend)
306 server->new_output.notify = backend_handle_new_output;
307 ds_backend_add_new_output_listener(server->backend,
308 &server->new_output);
310 server->compositor = ds_compositor_create(display);
311 if (!server->compositor) {
312 ds_backend_destroy(server->backend);
316 server->tbm_server = ds_tbm_server_create(display);
317 if (!server->tbm_server) {
318 ds_backend_destroy(server->backend);
322 server->xdg_shell = ds_xdg_shell_create(display);
323 if (!server->xdg_shell) {
324 ds_backend_destroy(server->backend);
328 server->new_xdg_surface.notify = server_new_xdg_surface;
329 ds_xdg_shell_add_new_surface_listener(server->xdg_shell,
330 &server->new_xdg_surface);
336 output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
338 struct tinyds_output *output =
339 wl_container_of(listener, output, output_destroy);
341 wl_list_remove(&output->output_destroy.link);
342 wl_list_remove(&output->output_frame.link);
344 if (output->front_buffer)
345 ds_buffer_unlock(output->front_buffer);
347 #ifdef USE_TDM_BUFFER_QUEUE
348 fini_renderer(&output->renderer);
350 if (output->swapchain)
351 ds_swapchain_destroy(output->swapchain);
353 if (output->allocator)
354 ds_allocator_destroy(output->allocator);
357 wl_display_terminate(output->server->display);
359 output->server->output = NULL;
365 output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED)
367 struct tinyds_output *output =
368 wl_container_of(listener, output, output_frame);
370 output->drawable = true;
375 draw_server_with_damage(struct tinyds_server *server)
377 server->output->damaged = true;
378 draw_output(server->output);
381 #ifdef USE_TDM_BUFFER_QUEUE
383 output_handle_buffer_queue_acquirable(struct wl_listener *listener,
384 void *data TINYDS_UNUSED)
386 struct tinyds_output *output;
387 struct ds_buffer *buffer;
389 output = wl_container_of(listener, output, buffer_queue_acquirable);
391 buffer = ds_tdm_buffer_queue_acquire(output->buffer_queue);
394 output_swap_buffer(output, buffer);
398 output_buffer_queue_init(struct tinyds_output *output)
400 struct ds_tdm_output *tdm_output;
402 tdm_output = ds_tdm_output_from_output(output->ds_output);
405 output->buffer_queue = ds_tdm_output_get_buffer_queue(tdm_output);
406 assert(output->buffer_queue);
408 output->buffer_queue_acquirable.notify =
409 output_handle_buffer_queue_acquirable;
410 ds_tdm_buffer_queue_add_acquirable_listener(output->buffer_queue,
411 &output->buffer_queue_acquirable);
415 output_renderer_init(struct tinyds_output *output)
417 init_renderer(&output->renderer);
419 renderer_set_surface_queue(&output->renderer,
420 ds_tdm_buffer_queue_get_native_queue(output->buffer_queue));
422 renderer_set_bg_color(&output->renderer, 80, 80, 80);
426 output_draw_with_renderer(struct tinyds_output *output)
428 struct tinyds_view *view;
430 ds_dbg(">> BEGIN UPDATE TEXTURES");
432 wl_list_for_each(view, &output->server->views, link) {
433 struct ds_buffer *ds_buffer;
434 struct ds_tbm_client_buffer *tbm_buffer;
435 tbm_surface_h surface;
440 ds_buffer = ds_surface_get_buffer(
441 ds_xdg_surface_get_surface(view->xdg_surface));
444 tbm_buffer = ds_tbm_client_buffer_from_buffer(ds_buffer);
447 surface = ds_tbm_client_buffer_get_tbm_surface(tbm_buffer);
449 renderer_add_texture(&output->renderer, surface, view->x, view->y);
451 view_send_frame_done(view);
454 ds_dbg("<< END UPDATE TEXTURES");
456 renderer_draw(&output->renderer);
461 output_swapchain_init(struct tinyds_output *output,
462 int width, int height, uint32_t format);
465 output->allocator = ds_tbm_allocator_create();
466 assert(output->allocator);
468 output->swapchain = ds_swapchain_create(output->allocator,
469 width, height, format);
470 assert(output->swapchain);
474 output_draw_with_swapchain(struct tinyds_output *output)
476 struct tinyds_view *view;
477 struct ds_buffer *output_buffer;
478 pixman_image_t *output_image;
480 output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
484 output_image = pixman_image_from_buffer(output_buffer,
485 DS_BUFFER_DATA_PTR_ACCESS_WRITE);
487 ds_buffer_unlock(output_buffer);
491 pixman_image_fill_color(output_image, 80, 80, 80);
493 wl_list_for_each(view, &output->server->views, link) {
496 draw_view(view, output_image);
498 pixman_image_unref(output_image);
500 output_swap_buffer(output, output_buffer);
504 draw_view(struct tinyds_view *view, pixman_image_t *dst_image)
506 struct ds_buffer *buffer;
507 pixman_image_t *src_image;
509 buffer = ds_surface_get_buffer(
510 ds_xdg_surface_get_surface(view->xdg_surface));
514 src_image = pixman_image_from_buffer(buffer,
515 DS_BUFFER_DATA_PTR_ACCESS_READ);
516 pixman_image_composite32(PIXMAN_OP_OVER,
522 pixman_image_get_width(src_image),
523 pixman_image_get_height(src_image));
524 pixman_image_unref(src_image);
526 view_send_frame_done(view);
531 draw_output(struct tinyds_output *output)
534 if (!output->drawable || !output->damaged)
537 #ifdef USE_TDM_BUFFER_QUEUE
538 output_draw_with_renderer(output);
540 output_draw_with_swapchain(output);
543 output->drawable = false;
544 output->damaged = false;
548 output_swap_buffer(struct tinyds_output *output, struct ds_buffer *buffer)
550 ds_output_attach_buffer(output->ds_output, buffer);
551 ds_output_commit(output->ds_output);
553 if (output->front_buffer)
554 ds_buffer_unlock(output->front_buffer);
555 output->front_buffer = buffer;
559 view_send_frame_done(struct tinyds_view *view)
562 clock_gettime(CLOCK_MONOTONIC, &now);
563 ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface),
568 server_dispatch_stdin(int fd, uint32_t mask, void *data)
570 struct tinyds_server *server = data;
572 wl_display_terminate(server->display);