1 #include "tinyds-helper.h"
10 #include <drm_fourcc.h>
12 #include <wayland-server.h>
13 #include <libds/log.h>
14 #include <libds/backend.h>
15 #include <libds/output.h>
16 #include <libds/allocator/tbm.h>
17 #include <libds/backend/tdm.h>
18 #include <libds/swapchain.h>
19 #include <libds/compositor.h>
20 #include <libds/xdg_shell.h>
22 #define TINYDS_UNUSED __attribute__((unused))
24 #define OUTPUT_WIDTH 1280
25 #define OUTPUT_HEIGHT 720
29 struct tinyds_server *server;
30 struct ds_output *ds_output;
31 struct ds_allocator *allocator;
32 struct ds_swapchain *swapchain;
33 struct ds_buffer *front_buffer;
35 struct wl_listener output_destroy;
36 struct wl_listener output_frame;
46 struct wl_display *display;
48 struct ds_backend *backend;
49 struct ds_compositor *compositor;
50 struct ds_xdg_shell *xdg_shell;
52 struct tinyds_output *output;
53 struct tinyds_renderer renderer;
57 struct wl_listener new_output;
58 struct wl_listener new_xdg_surface;
63 struct tinyds_server *server;
65 struct ds_xdg_surface *xdg_surface;
67 struct wl_listener xdg_surface_map;
68 struct wl_listener xdg_surface_unmap;
69 struct wl_listener xdg_surface_destroy;
70 struct wl_listener surface_commit;
71 struct wl_list link; // tinyds_server::views
77 struct tinyds_server _tinyds;
79 static bool init_server(struct tinyds_server *server, struct wl_display *display);
80 static void output_handle_destroy(struct wl_listener *listener, void *data);
81 static void output_handle_frame(struct wl_listener *listener, void *data);
82 static void draw_server(struct tinyds_server *server);
83 static void draw_server_with_damage(struct tinyds_server *server);
84 static void draw_output(struct tinyds_output *output);
85 static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image);
90 struct tinyds_server *server = &_tinyds;
91 struct wl_display *display;
94 ds_log_init(DS_DBG, NULL);
96 display = wl_display_create();
99 assert(init_server(server, display) == true);
101 assert(tinyds_renderer_init_display(&server->renderer, display));
103 socket = wl_display_add_socket_auto(display);
106 ds_backend_start(server->backend);
108 setenv("WAYLAND_DISPLAY", socket, true);
110 ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket);
112 wl_display_destroy(display);
118 view_handle_xdg_surface_map(struct wl_listener *listener,
119 void *data TINYDS_UNUSED)
121 struct tinyds_view *view;
123 view = wl_container_of(listener, view, xdg_surface_map);
128 view_handle_xdg_surface_unmap(struct wl_listener *listener,
129 void *data TINYDS_UNUSED)
131 struct tinyds_view *view;
133 view = wl_container_of(listener, view, xdg_surface_unmap);
134 view->mapped = false;
138 view_handle_xdg_surface_destroy(struct wl_listener *listener,
139 void *data TINYDS_UNUSED)
141 struct tinyds_view *view;
143 view = wl_container_of(listener, view, xdg_surface_destroy);
145 draw_server_with_damage(view->server);
147 wl_list_remove(&view->xdg_surface_destroy.link);
148 wl_list_remove(&view->xdg_surface_map.link);
149 wl_list_remove(&view->xdg_surface_unmap.link);
150 wl_list_remove(&view->surface_commit.link);
151 wl_list_remove(&view->link);
156 view_handle_surface_commit(struct wl_listener *listener,
157 void *data TINYDS_UNUSED)
159 struct tinyds_view *view;
161 view = wl_container_of(listener, view, surface_commit);
162 draw_server_with_damage(view->server);
166 server_new_xdg_surface(struct wl_listener *listener, void *data)
168 struct tinyds_server *server;
169 struct tinyds_view *view;
170 struct ds_xdg_surface *xdg_surface;
172 server = wl_container_of(listener, server, new_xdg_surface);
175 ds_inf("New xdg_surface(%p)", (void *)xdg_surface);
177 view = calloc(1, sizeof *view);
178 view->server = server;
179 view->xdg_surface = xdg_surface;
181 view->xdg_surface_map.notify = view_handle_xdg_surface_map;
182 ds_xdg_surface_add_map_listener(xdg_surface,
183 &view->xdg_surface_map);
185 view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap;
186 ds_xdg_surface_add_unmap_listener(xdg_surface,
187 &view->xdg_surface_unmap);
189 view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy;
190 ds_xdg_surface_add_destroy_listener(xdg_surface,
191 &view->xdg_surface_destroy);
193 view->surface_commit.notify = view_handle_surface_commit;
194 ds_surface_add_commit_listener(
195 ds_xdg_surface_get_surface(xdg_surface),
196 &view->surface_commit);
198 wl_list_insert(server->views.prev, &view->link);
202 backend_handle_new_output(struct wl_listener *listener, void *data)
204 struct tinyds_server *server;
205 struct tinyds_output *output;
206 struct ds_output *ds_output;
208 server = wl_container_of(listener, server, new_output);
211 ds_inf("New output(%p)", ds_output);
216 output = calloc(1, sizeof *output);
220 output->server = server;
221 output->ds_output = ds_output;
223 output->output_destroy.notify = output_handle_destroy;
224 ds_output_add_destroy_listener(ds_output,
225 &output->output_destroy);
227 output->output_frame.notify = output_handle_frame;
228 ds_output_add_frame_listener(ds_output,
229 &output->output_frame);
231 server->output = output;
235 init_server(struct tinyds_server *server, struct wl_display *display)
237 server->display = display;
239 wl_list_init(&server->views);
241 if (wl_display_init_shm(display) != 0)
244 server->backend = ds_tdm_backend_create(display);
245 if (!server->backend)
248 server->new_output.notify = backend_handle_new_output;
249 ds_backend_add_new_output_listener(server->backend,
250 &server->new_output);
252 server->compositor = ds_compositor_create(display);
253 if (!server->compositor) {
254 ds_backend_destroy(server->backend);
258 server->xdg_shell = ds_xdg_shell_create(display);
259 if (!server->xdg_shell) {
260 ds_backend_destroy(server->backend);
264 server->new_xdg_surface.notify = server_new_xdg_surface;
265 ds_xdg_shell_add_new_surface_listener(server->xdg_shell,
266 &server->new_xdg_surface);
272 output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
274 struct tinyds_output *output =
275 wl_container_of(listener, output, output_destroy);
277 wl_list_remove(&output->output_destroy.link);
278 wl_list_remove(&output->output_frame.link);
280 if (output->front_buffer)
281 ds_buffer_unlock(output->front_buffer);
283 if (output->swapchain)
284 ds_swapchain_destroy(output->swapchain);
286 if (output->allocator)
287 ds_allocator_destroy(output->allocator);
289 wl_display_terminate(output->server->display);
291 output->server->output = NULL;
297 output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED)
299 struct tinyds_output *output =
300 wl_container_of(listener, output, output_frame);
305 draw_server(struct tinyds_server *server)
307 draw_output(server->output);
311 draw_server_with_damage(struct tinyds_server *server)
313 server->output->damaged = true;
314 draw_output(server->output);
317 static void image_fill_color(pixman_image_t *image,
318 uint8_t r, uint8_t g, uint8_t b);
319 static pixman_image_t *image_from_buffer(struct ds_buffer *buffer,
320 enum ds_buffer_data_ptr_access_flag access_flag);
321 static void view_send_frame_done(struct tinyds_view *view);
324 draw_output(struct tinyds_output *output)
326 struct ds_buffer *output_buffer;
327 pixman_image_t *output_image;
328 struct tinyds_view *view;
330 if (!output->drawable || !output->damaged)
333 output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
337 output_image = image_from_buffer(output_buffer,
338 DS_BUFFER_DATA_PTR_ACCESS_WRITE);
340 ds_buffer_unlock(output_buffer);
344 image_fill_color(output_image, 80, 80, 80);
346 wl_list_for_each(view, &output->server->views, link) {
349 draw_view(view, output_image);
351 pixman_image_unref(output_image);
353 ds_output_attach_buffer(output->ds_output, output_buffer);
354 ds_output_commit(output->ds_output);
356 if (output->front_buffer)
357 ds_buffer_unlock(output->front_buffer);
358 output->front_buffer = output_buffer;
360 output->drawable = false;
361 output->damaged = false;
365 draw_view(struct tinyds_view *view, pixman_image_t *dst_image)
367 struct ds_buffer *buffer;
368 pixman_image_t *src_image;
370 buffer = ds_surface_get_buffer(
371 ds_xdg_surface_get_surface(view->xdg_surface));
375 src_image = image_from_buffer(buffer,
376 DS_BUFFER_DATA_PTR_ACCESS_READ);
377 pixman_image_composite32(PIXMAN_OP_OVER,
382 pixman_image_get_width(src_image),
383 pixman_image_get_height(src_image));
384 pixman_image_unref(src_image);
386 view_send_frame_done(view);
389 static pixman_color_t *
390 color_rgb888(pixman_color_t *tmp, uint8_t r, uint8_t g, uint8_t b)
393 tmp->red = (r << 8) + r;
394 tmp->green = (g << 8) + g;
395 tmp->blue = (b << 8) +b;
401 image_fill_color(pixman_image_t *image, uint8_t r, uint8_t g, uint8_t b)
403 pixman_image_t *color_image;
404 pixman_color_t color;
406 color_rgb888(&color, r, g, b);
407 color_image = pixman_image_create_solid_fill(&color);
408 pixman_image_composite32(PIXMAN_OP_SRC,
413 pixman_image_get_width(image),
414 pixman_image_get_height(image));
415 pixman_image_unref(color_image);
419 destroy_pixman_image(pixman_image_t *image TINYDS_UNUSED, void *data)
421 struct ds_buffer *buffer = data;
422 ds_buffer_end_data_ptr_access(buffer);
423 ds_buffer_unlock(buffer);
427 convert_drm_format_to_pixman(uint32_t fmt)
430 case DRM_FORMAT_XRGB8888:
431 return PIXMAN_x8r8g8b8;
432 case DRM_FORMAT_ARGB8888:
433 return PIXMAN_a8r8g8b8;
435 assert(0 && "not reached");
439 static pixman_image_t *
440 image_from_buffer(struct ds_buffer *buffer,
441 enum ds_buffer_data_ptr_access_flag access_flag)
443 pixman_image_t *image;
449 ds_buffer_get_size(buffer, &width, &height);
451 if (!ds_buffer_begin_data_ptr_access(buffer,
452 access_flag, &data, &format, &stride))
455 format = convert_drm_format_to_pixman(format);
456 image = pixman_image_create_bits(format, width, height, data, stride);
458 ds_buffer_end_data_ptr_access(buffer);
462 pixman_image_set_destroy_function(image,
463 destroy_pixman_image, ds_buffer_lock(buffer));
469 view_send_frame_done(struct tinyds_view *view)
472 clock_gettime(CLOCK_MONOTONIC, &now);
473 ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface),