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>
19 #include <libds-tizen/dpms.h>
21 #define USE_TDM_BUFFER_QUEUE
23 #ifdef USE_TDM_BUFFER_QUEUE
24 #include "pixman-tbm-helper.h"
25 #include "tinyds-tdm-renderer.h"
27 #include <libds/swapchain.h>
30 #include "pixman-helper.h"
32 #define TINYDS_UNUSED __attribute__((unused))
36 struct tinyds_server *server;
37 struct ds_output *ds_output;
38 struct ds_allocator *allocator;
39 #ifdef USE_TDM_BUFFER_QUEUE
40 struct tinyds_renderer renderer;
41 struct ds_tdm_buffer_queue *buffer_queue;
42 struct wl_listener buffer_queue_acquirable;
44 struct ds_swapchain *swapchain;
46 struct ds_buffer *front_buffer;
48 struct wl_listener output_destroy;
49 struct wl_listener output_frame;
59 struct ds_tizen_dpms *ds_dpms;
60 struct tinyds_server *server;
62 struct wl_listener destroy;
63 struct wl_listener set_dpms;
64 struct wl_listener get_dpms;
69 struct ds_tbm_server *tbm_server;
71 struct wl_display *display;
73 struct ds_backend *backend;
74 struct ds_compositor *compositor;
75 struct ds_xdg_shell *xdg_shell;
77 struct tinyds_output *output;
78 struct tinyds_dpms *dpms;
79 struct wl_event_source *stdin_source;
83 struct wl_listener new_output;
84 struct wl_listener new_xdg_surface;
89 struct tinyds_server *server;
91 struct tinyds_texture *texture;
92 struct ds_xdg_surface *xdg_surface;
94 struct wl_listener xdg_surface_map;
95 struct wl_listener xdg_surface_unmap;
96 struct wl_listener xdg_surface_destroy;
97 struct wl_listener surface_commit;
98 struct wl_list link; // tinyds_server::views
104 struct tinyds_server tinyds;
106 static bool init_server(struct tinyds_server *server, struct wl_display *display);
107 static int server_dispatch_stdin(int fd, uint32_t mask, void *data);
108 static void output_handle_destroy(struct wl_listener *listener, void *data);
109 static void output_handle_frame(struct wl_listener *listener, void *data);
110 static void draw_server_with_damage(struct tinyds_server *server);
111 static void draw_output(struct tinyds_output *output);
112 static void output_swap_buffer(struct tinyds_output *output,
113 struct ds_buffer *buffer);
114 static void view_send_frame_done(struct tinyds_view *view);
115 #ifdef USE_TDM_BUFFER_QUEUE
116 static void output_buffer_queue_init(struct tinyds_output *output);
117 static void output_renderer_init(struct tinyds_output *output);
118 static void output_draw_with_renderer(struct tinyds_output *output);
120 static void output_swapchain_init(struct tinyds_output *output,
121 int width, int height, uint32_t format);
122 static void output_draw_with_swapchain(struct tinyds_output *output);
123 static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image);
125 static void dpms_handle_destroy(struct wl_listener *listener, void *data);
126 static void dpms_handle_set_dpms(struct wl_listener *listener, void *data);
127 static void dpms_handle_get_dpms(struct wl_listener *listener, void *data);
133 struct tinyds_server *server = &tinyds;
134 struct wl_display *display;
135 struct wl_event_loop *loop;
139 ds_log_init(DS_INF, NULL);
141 display = wl_display_create();
144 res = init_server(server, display);
147 socket = wl_display_add_socket_auto(display);
150 ds_backend_start(server->backend);
152 setenv("WAYLAND_DISPLAY", socket, true);
154 ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket);
156 loop = wl_display_get_event_loop(display);
157 server->stdin_source = wl_event_loop_add_fd(loop, STDIN_FILENO,
158 WL_EVENT_READABLE, server_dispatch_stdin, server);
160 wl_display_run(display);
162 wl_display_destroy_clients(display);
163 wl_display_destroy(display);
169 view_handle_xdg_surface_map(struct wl_listener *listener,
170 void *data TINYDS_UNUSED)
172 struct tinyds_view *view;
174 view = wl_container_of(listener, view, xdg_surface_map);
179 view_handle_xdg_surface_unmap(struct wl_listener *listener,
180 void *data TINYDS_UNUSED)
182 struct tinyds_view *view;
184 view = wl_container_of(listener, view, xdg_surface_unmap);
185 view->mapped = false;
189 view_handle_xdg_surface_destroy(struct wl_listener *listener,
190 void *data TINYDS_UNUSED)
192 struct tinyds_view *view;
193 struct tinyds_server *server;
195 view = wl_container_of(listener, view, xdg_surface_destroy);
196 server = view->server;
198 wl_list_remove(&view->xdg_surface_destroy.link);
199 wl_list_remove(&view->xdg_surface_map.link);
200 wl_list_remove(&view->xdg_surface_unmap.link);
201 wl_list_remove(&view->surface_commit.link);
202 wl_list_remove(&view->link);
205 draw_server_with_damage(server);
209 view_handle_surface_commit(struct wl_listener *listener,
210 void *data TINYDS_UNUSED)
212 struct tinyds_view *view;
214 view = wl_container_of(listener, view, surface_commit);
215 draw_server_with_damage(view->server);
219 server_new_xdg_surface(struct wl_listener *listener, void *data)
221 struct tinyds_server *server;
222 struct tinyds_view *view;
223 struct ds_xdg_surface *xdg_surface;
225 server = wl_container_of(listener, server, new_xdg_surface);
228 ds_inf("New xdg_surface(%p)", (void *)xdg_surface);
230 view = calloc(1, sizeof *view);
233 view->server = server;
234 view->xdg_surface = xdg_surface;
236 view->xdg_surface_map.notify = view_handle_xdg_surface_map;
237 ds_xdg_surface_add_map_listener(xdg_surface,
238 &view->xdg_surface_map);
240 view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap;
241 ds_xdg_surface_add_unmap_listener(xdg_surface,
242 &view->xdg_surface_unmap);
244 view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy;
245 ds_xdg_surface_add_destroy_listener(xdg_surface,
246 &view->xdg_surface_destroy);
248 view->surface_commit.notify = view_handle_surface_commit;
249 ds_surface_add_commit_listener(
250 ds_xdg_surface_get_surface(xdg_surface),
251 &view->surface_commit);
253 wl_list_insert(server->views.prev, &view->link);
255 view->x = rand() % 1000;
256 view->y = rand() % 500;
260 backend_handle_new_output(struct wl_listener *listener, void *data)
262 struct tinyds_server *server;
263 struct tinyds_output *output;
264 struct ds_output *ds_output;
265 const struct ds_output_mode *mode;
267 server = wl_container_of(listener, server, new_output);
270 ds_inf("New output(%p)", ds_output);
275 mode = ds_output_get_preferred_mode(ds_output);
276 ds_output_set_mode(ds_output, mode);
278 output = calloc(1, sizeof *output);
282 output->server = server;
283 output->ds_output = ds_output;
284 output->width = mode->width;
285 output->height = mode->height;
286 output->drawable = true;
287 output->damaged = true;
289 #ifdef USE_TDM_BUFFER_QUEUE
290 output_buffer_queue_init(output);
291 output_renderer_init(output);
293 output_swapchain_init(output, mode->width, mode->height,
294 DRM_FORMAT_XRGB8888);
297 output->output_destroy.notify = output_handle_destroy;
298 ds_output_add_destroy_listener(ds_output, &output->output_destroy);
300 output->output_frame.notify = output_handle_frame;
301 ds_output_add_frame_listener(ds_output, &output->output_frame);
303 server->output = output;
309 add_new_dpms(struct tinyds_server *server)
311 struct tinyds_dpms *dpms;
313 dpms = calloc(1, sizeof *dpms);
317 dpms->ds_dpms = ds_tizen_dpms_create(server->display);
321 dpms->destroy.notify = dpms_handle_destroy;
322 ds_tizen_dpms_add_destroy_listener(dpms->ds_dpms, &dpms->destroy);
324 dpms->set_dpms.notify = dpms_handle_set_dpms;
325 ds_tizen_dpms_add_set_dpms_listener(dpms->ds_dpms, &dpms->set_dpms);
327 dpms->get_dpms.notify = dpms_handle_get_dpms;
328 ds_tizen_dpms_add_get_dpms_listener(dpms->ds_dpms, &dpms->get_dpms);
332 ds_inf("Dpms (%p) added", dpms);
338 init_server(struct tinyds_server *server, struct wl_display *display)
340 server->display = display;
342 wl_list_init(&server->views);
344 if (wl_display_init_shm(display) != 0)
347 server->backend = ds_tdm_backend_create(display);
348 if (!server->backend)
351 server->new_output.notify = backend_handle_new_output;
352 ds_backend_add_new_output_listener(server->backend,
353 &server->new_output);
355 server->compositor = ds_compositor_create(display);
356 if (!server->compositor) {
357 ds_backend_destroy(server->backend);
361 server->tbm_server = ds_tbm_server_create(display);
362 if (!server->tbm_server) {
363 ds_backend_destroy(server->backend);
367 server->xdg_shell = ds_xdg_shell_create(display);
368 if (!server->xdg_shell) {
369 ds_backend_destroy(server->backend);
373 server->new_xdg_surface.notify = server_new_xdg_surface;
374 ds_xdg_shell_add_new_surface_listener(server->xdg_shell,
375 &server->new_xdg_surface);
377 if (!add_new_dpms(server)) {
378 ds_backend_destroy(server->backend);
386 output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
388 struct tinyds_output *output =
389 wl_container_of(listener, output, output_destroy);
391 wl_list_remove(&output->output_destroy.link);
392 wl_list_remove(&output->output_frame.link);
394 if (output->front_buffer)
395 ds_buffer_unlock(output->front_buffer);
397 #ifdef USE_TDM_BUFFER_QUEUE
398 fini_renderer(&output->renderer);
400 if (output->swapchain)
401 ds_swapchain_destroy(output->swapchain);
403 if (output->allocator)
404 ds_allocator_destroy(output->allocator);
407 wl_display_terminate(output->server->display);
409 output->server->output = NULL;
415 output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED)
417 struct tinyds_output *output =
418 wl_container_of(listener, output, output_frame);
420 output->drawable = true;
425 draw_server_with_damage(struct tinyds_server *server)
427 server->output->damaged = true;
428 draw_output(server->output);
431 #ifdef USE_TDM_BUFFER_QUEUE
433 output_handle_buffer_queue_acquirable(struct wl_listener *listener,
434 void *data TINYDS_UNUSED)
436 struct tinyds_output *output;
437 struct ds_buffer *buffer;
439 output = wl_container_of(listener, output, buffer_queue_acquirable);
441 buffer = ds_tdm_buffer_queue_acquire(output->buffer_queue);
444 output_swap_buffer(output, buffer);
448 output_buffer_queue_init(struct tinyds_output *output)
450 struct ds_tdm_output *tdm_output;
452 tdm_output = ds_tdm_output_from_output(output->ds_output);
455 output->buffer_queue = ds_tdm_output_get_buffer_queue(tdm_output);
456 assert(output->buffer_queue);
458 output->buffer_queue_acquirable.notify =
459 output_handle_buffer_queue_acquirable;
460 ds_tdm_buffer_queue_add_acquirable_listener(output->buffer_queue,
461 &output->buffer_queue_acquirable);
465 output_renderer_init(struct tinyds_output *output)
467 init_renderer(&output->renderer);
469 renderer_set_surface_queue(&output->renderer,
470 ds_tdm_buffer_queue_get_native_queue(output->buffer_queue));
472 renderer_set_bg_color(&output->renderer, 80, 80, 80);
476 output_draw_with_renderer(struct tinyds_output *output)
478 struct tinyds_view *view;
480 ds_dbg(">> BEGIN UPDATE TEXTURES");
482 wl_list_for_each(view, &output->server->views, link) {
483 struct ds_buffer *ds_buffer;
484 struct ds_tbm_client_buffer *tbm_buffer;
485 tbm_surface_h surface;
490 ds_buffer = ds_surface_get_buffer(
491 ds_xdg_surface_get_surface(view->xdg_surface));
494 tbm_buffer = ds_tbm_client_buffer_from_buffer(ds_buffer);
497 surface = ds_tbm_client_buffer_get_tbm_surface(tbm_buffer);
499 renderer_add_texture(&output->renderer, surface, view->x, view->y);
501 view_send_frame_done(view);
504 ds_dbg("<< END UPDATE TEXTURES");
506 renderer_draw(&output->renderer);
511 output_swapchain_init(struct tinyds_output *output,
512 int width, int height, uint32_t format);
515 output->allocator = ds_tbm_allocator_create();
516 assert(output->allocator);
518 output->swapchain = ds_swapchain_create(output->allocator,
519 width, height, format);
520 assert(output->swapchain);
524 output_draw_with_swapchain(struct tinyds_output *output)
526 struct tinyds_view *view;
527 struct ds_buffer *output_buffer;
528 pixman_image_t *output_image;
530 output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
534 output_image = pixman_image_from_buffer(output_buffer,
535 DS_BUFFER_DATA_PTR_ACCESS_WRITE);
537 ds_buffer_unlock(output_buffer);
541 pixman_image_fill_color(output_image, 80, 80, 80);
543 wl_list_for_each(view, &output->server->views, link) {
546 draw_view(view, output_image);
548 pixman_image_unref(output_image);
550 output_swap_buffer(output, output_buffer);
554 draw_view(struct tinyds_view *view, pixman_image_t *dst_image)
556 struct ds_buffer *buffer;
557 pixman_image_t *src_image;
559 buffer = ds_surface_get_buffer(
560 ds_xdg_surface_get_surface(view->xdg_surface));
564 src_image = pixman_image_from_buffer(buffer,
565 DS_BUFFER_DATA_PTR_ACCESS_READ);
566 pixman_image_composite32(PIXMAN_OP_OVER,
572 pixman_image_get_width(src_image),
573 pixman_image_get_height(src_image));
574 pixman_image_unref(src_image);
576 view_send_frame_done(view);
581 draw_output(struct tinyds_output *output)
584 if (!output->drawable || !output->damaged)
587 #ifdef USE_TDM_BUFFER_QUEUE
588 output_draw_with_renderer(output);
590 output_draw_with_swapchain(output);
593 output->drawable = false;
594 output->damaged = false;
598 output_swap_buffer(struct tinyds_output *output, struct ds_buffer *buffer)
600 ds_output_attach_buffer(output->ds_output, buffer);
601 ds_output_commit(output->ds_output);
603 if (output->front_buffer)
604 ds_buffer_unlock(output->front_buffer);
605 output->front_buffer = buffer;
609 view_send_frame_done(struct tinyds_view *view)
612 clock_gettime(CLOCK_MONOTONIC, &now);
613 ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface),
618 server_dispatch_stdin(int fd, uint32_t mask, void *data)
620 struct tinyds_server *server = data;
622 wl_display_terminate(server->display);
628 dpms_handle_destroy(struct wl_listener *listener, void *data)
630 struct tinyds_dpms *dpms;
632 dpms = wl_container_of(listener, dpms, destroy);
634 ds_inf("Dpms(%p) destroyed", dpms);
636 wl_list_remove(&dpms->destroy.link);
637 wl_list_remove(&dpms->set_dpms.link);
638 wl_list_remove(&dpms->get_dpms.link);
644 dpms_handle_set_dpms(struct wl_listener *listener, void *data)
646 struct tinyds_dpms *dpms;
647 struct ds_tizen_dpms_event *event = data;
649 dpms = wl_container_of(listener, dpms, set_dpms);
651 ds_inf("Dpms(%p) set dpms : %d", dpms, event->mode);
654 //set dpms mode to output
655 ds_tizen_dpms_send_set_result(dpms->ds_dpms, event->mode,
656 DS_TIZEN_DPMS_ERROR_NONE);
660 dpms_handle_get_dpms(struct wl_listener *listener, void *data)
662 struct tinyds_dpms *dpms;
664 dpms = wl_container_of(listener, dpms, get_dpms);
666 ds_inf("Dpms(%p) get dpms", dpms);
669 //get dpms mode from output
670 ds_tizen_dpms_send_get_result(dpms->ds_dpms, DS_TIZEN_DPMS_MODE_ON,
671 DS_TIZEN_DPMS_ERROR_NONE);