Add tdm backend server and client as an example
[platform/core/uifw/libds-tizen.git] / examples / tinyds-tdm.c
1 #include "tbm-server-helper.h"
2 #include "pixman-helper.h"
3
4 #include <assert.h>
5 #include <stdbool.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <signal.h>
9 #include <time.h>
10
11 #include <drm_fourcc.h>
12 #include <pixman.h>
13 #include <wayland-server.h>
14 #include <libds/log.h>
15 #include <libds/backend.h>
16 #include <libds/output.h>
17 #include <libds/allocator/tbm.h>
18 #include <libds/backend/tdm.h>
19 #include <libds/swapchain.h>
20 #include <libds/compositor.h>
21 #include <libds/xdg_shell.h>
22
23 #define TINYDS_UNUSED   __attribute__((unused))
24
25 #define OUTPUT_WIDTH   1280
26 #define OUTPUT_HEIGHT  720
27
28 struct tinyds_output
29 {
30     struct tinyds_server *server;
31     struct ds_output *ds_output;
32     struct ds_allocator *allocator;
33     struct ds_swapchain *swapchain;
34     struct ds_buffer *front_buffer;
35
36     struct wl_listener output_destroy;
37     struct wl_listener output_frame;
38
39     int width, height;
40
41     bool drawable;
42     bool damaged;
43 };
44
45 struct tinyds_server
46 {
47     struct tbm_server tbm_server;
48
49     struct wl_display *display;
50
51     struct ds_backend *backend;
52     struct ds_compositor *compositor;
53     struct ds_xdg_shell *xdg_shell;
54
55     struct tinyds_output *output;
56     struct wl_event_source *stdin_source;
57
58     struct wl_list views;
59
60     struct wl_listener new_output;
61     struct wl_listener new_xdg_surface;
62 };
63
64 struct tinyds_view
65 {
66     struct tinyds_server *server;
67
68     struct ds_xdg_surface *xdg_surface;
69
70     struct wl_listener xdg_surface_map;
71     struct wl_listener xdg_surface_unmap;
72     struct wl_listener xdg_surface_destroy;
73     struct wl_listener surface_commit;
74     struct wl_list link; // tinyds_server::views
75
76     int x, y;
77     bool mapped;
78 };
79
80 struct tinyds_server tinyds;
81
82 static bool init_server(struct tinyds_server *server, struct wl_display *display);
83 static int server_dispatch_stdin(int fd, uint32_t mask, void *data);
84 static void output_handle_destroy(struct wl_listener *listener, void *data);
85 static void output_handle_frame(struct wl_listener *listener, void *data);
86 static void draw_server_with_damage(struct tinyds_server *server);
87 static void draw_output(struct tinyds_output *output);
88 static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image);
89
90 int
91 main(void)
92 {
93     struct tinyds_server *server = &tinyds;
94     struct wl_display *display;
95     struct wl_event_loop *loop;
96     const char *socket;
97     bool res;
98
99     ds_log_init(DS_INF, NULL);
100
101     display = wl_display_create();
102     assert(display);
103
104     res = init_server(server, display);
105     assert(res);
106
107     res = tbm_server_init_display(&server->tbm_server, display);
108     assert(res);
109
110     socket = wl_display_add_socket_auto(display);
111     assert(socket);
112
113     ds_backend_start(server->backend);
114
115     setenv("WAYLAND_DISPLAY", socket, true);
116
117     ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket);
118
119     loop = wl_display_get_event_loop(display);
120     server->stdin_source = wl_event_loop_add_fd(loop, STDIN_FILENO,
121             WL_EVENT_READABLE, server_dispatch_stdin, server);
122
123     wl_display_run(display);
124
125     wl_display_destroy_clients(display);
126     wl_display_destroy(display);
127
128     return 0;
129 }
130
131 static void
132 view_handle_xdg_surface_map(struct wl_listener *listener,
133         void *data TINYDS_UNUSED)
134 {
135     struct tinyds_view *view;
136
137     view = wl_container_of(listener, view, xdg_surface_map);
138     view->mapped = true;
139 }
140
141 static void
142 view_handle_xdg_surface_unmap(struct wl_listener *listener,
143         void *data TINYDS_UNUSED)
144 {
145     struct tinyds_view *view;
146
147     view = wl_container_of(listener, view, xdg_surface_unmap);
148     view->mapped = false;
149 }
150
151 static void
152 view_handle_xdg_surface_destroy(struct wl_listener *listener,
153         void *data TINYDS_UNUSED) 
154 {
155     struct tinyds_view *view;
156
157     view = wl_container_of(listener, view, xdg_surface_destroy);
158
159     draw_server_with_damage(view->server);
160
161     wl_list_remove(&view->xdg_surface_destroy.link);
162     wl_list_remove(&view->xdg_surface_map.link);
163     wl_list_remove(&view->xdg_surface_unmap.link);
164     wl_list_remove(&view->surface_commit.link);
165     wl_list_remove(&view->link);
166     free(view);
167 }
168
169 static void
170 view_handle_surface_commit(struct wl_listener *listener,
171         void *data TINYDS_UNUSED)
172 {
173     struct tinyds_view *view;
174
175     view = wl_container_of(listener, view, surface_commit);
176     draw_server_with_damage(view->server);
177 }
178
179 static void
180 server_new_xdg_surface(struct wl_listener *listener, void *data)
181 {
182     struct tinyds_server *server;
183     struct tinyds_view *view;
184     struct ds_xdg_surface *xdg_surface;
185
186     server = wl_container_of(listener, server, new_xdg_surface);
187     xdg_surface = data;
188
189     ds_inf("New xdg_surface(%p)", (void *)xdg_surface);
190
191     view = calloc(1, sizeof *view);
192     assert(view);
193
194     view->server = server;
195     view->xdg_surface = xdg_surface;
196
197     view->xdg_surface_map.notify = view_handle_xdg_surface_map;
198     ds_xdg_surface_add_map_listener(xdg_surface,
199             &view->xdg_surface_map);
200
201     view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap;
202     ds_xdg_surface_add_unmap_listener(xdg_surface,
203             &view->xdg_surface_unmap);
204
205     view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy;
206     ds_xdg_surface_add_destroy_listener(xdg_surface,
207             &view->xdg_surface_destroy);
208
209     view->surface_commit.notify = view_handle_surface_commit;
210     ds_surface_add_commit_listener(
211             ds_xdg_surface_get_surface(xdg_surface),
212             &view->surface_commit);
213
214     wl_list_insert(server->views.prev, &view->link);
215
216     view->x = rand() % 1000;
217     view->y = rand() % 500;
218 }
219
220 static void
221 backend_handle_new_output(struct wl_listener *listener, void *data)
222 {
223     struct tinyds_server *server;
224     struct tinyds_output *output;
225     struct ds_output *ds_output;
226
227     server = wl_container_of(listener, server, new_output);
228     ds_output = data;
229
230     ds_inf("New output(%p)", ds_output);
231
232     if (server->output)
233         return;
234
235     output = calloc(1, sizeof *output);
236     if (!output)
237         return;
238
239     output->allocator = ds_tbm_allocator_create();
240     if (!output->allocator) {
241         free(output);
242         return;
243     }
244
245     output->swapchain = ds_swapchain_create(output->allocator,
246             OUTPUT_WIDTH, OUTPUT_HEIGHT, DRM_FORMAT_XRGB8888); // FIXME output mode
247     if (!output->swapchain) {
248         ds_allocator_destroy(output->allocator);
249         free(output);
250         return;
251     }
252
253     output->server = server;
254     output->ds_output = ds_output;
255     output->drawable = true;
256     output->damaged = true;
257
258     output->output_destroy.notify = output_handle_destroy;
259     ds_output_add_destroy_listener(ds_output,
260             &output->output_destroy);
261
262     output->output_frame.notify = output_handle_frame;
263     ds_output_add_frame_listener(ds_output,
264             &output->output_frame);
265
266     server->output = output;
267
268     draw_output(output);
269 }
270
271 static bool
272 init_server(struct tinyds_server *server, struct wl_display *display)
273 {
274     server->display = display;
275
276     wl_list_init(&server->views);
277
278     if (wl_display_init_shm(display) != 0)
279         return false;
280
281     server->backend = ds_tdm_backend_create(display);
282     if (!server->backend)
283         return false;
284
285     server->new_output.notify = backend_handle_new_output;
286     ds_backend_add_new_output_listener(server->backend,
287             &server->new_output);
288
289     server->compositor = ds_compositor_create(display);
290     if (!server->compositor) {
291         ds_backend_destroy(server->backend);
292         return false;
293     }
294
295     server->xdg_shell = ds_xdg_shell_create(display);
296     if (!server->xdg_shell) {
297         ds_backend_destroy(server->backend);
298         return false;
299     }
300
301     server->new_xdg_surface.notify = server_new_xdg_surface;
302     ds_xdg_shell_add_new_surface_listener(server->xdg_shell,
303             &server->new_xdg_surface);
304
305     return true;
306 }
307
308 static void
309 output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
310 {
311     struct tinyds_output *output =
312         wl_container_of(listener, output, output_destroy);
313
314     wl_list_remove(&output->output_destroy.link);
315     wl_list_remove(&output->output_frame.link);
316
317     if (output->front_buffer)
318         ds_buffer_unlock(output->front_buffer);
319
320     if (output->swapchain)
321         ds_swapchain_destroy(output->swapchain);
322
323     if (output->allocator)
324         ds_allocator_destroy(output->allocator);
325
326     wl_display_terminate(output->server->display);
327
328     output->server->output = NULL;
329
330     free(output);
331 }
332
333 static void
334 output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED)
335 {
336     struct tinyds_output *output =
337         wl_container_of(listener, output, output_frame);
338
339     output->drawable = true;
340     draw_output(output);
341 }
342
343 static void
344 draw_server_with_damage(struct tinyds_server *server)
345 {
346     server->output->damaged = true;
347     draw_output(server->output);
348 }
349
350 static void
351 draw_output(struct tinyds_output *output)
352 {
353     struct ds_buffer *output_buffer;
354     pixman_image_t *output_image;
355     struct tinyds_view *view;
356
357     if (!output->drawable || !output->damaged)
358         return;
359
360     output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
361     if (!output_buffer)
362         return;
363
364     output_image = pixman_image_from_buffer(output_buffer,
365             DS_BUFFER_DATA_PTR_ACCESS_WRITE);
366     if (!output_image) {
367         ds_buffer_unlock(output_buffer);
368         return;
369     }
370
371     pixman_image_fill_color(output_image, 80, 80, 80);
372
373     wl_list_for_each(view, &output->server->views, link) {
374         if (!view->mapped)
375             continue;
376         draw_view(view, output_image);
377     }
378     pixman_image_unref(output_image);
379
380     ds_output_attach_buffer(output->ds_output, output_buffer);
381     ds_output_commit(output->ds_output);
382
383     if (output->front_buffer)
384         ds_buffer_unlock(output->front_buffer);
385     output->front_buffer = output_buffer;
386
387     output->drawable = false;
388     output->damaged = false;
389 }
390
391 static void
392 view_send_frame_done(struct tinyds_view *view)
393 {
394     struct timespec now;
395     clock_gettime(CLOCK_MONOTONIC, &now);
396     ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface),
397             &now);
398 }
399
400 static void
401 draw_view(struct tinyds_view *view, pixman_image_t *dst_image)
402 {
403     struct ds_buffer *buffer;
404     pixman_image_t *src_image;
405
406     buffer = ds_surface_get_buffer(
407             ds_xdg_surface_get_surface(view->xdg_surface));
408     if (!buffer)
409         return;
410
411     src_image = pixman_image_from_buffer(buffer,
412             DS_BUFFER_DATA_PTR_ACCESS_READ);
413     pixman_image_composite32(PIXMAN_OP_OVER,
414             src_image,
415             NULL,
416             dst_image,
417             0, 0, 0, 0,
418             view->x, view->y,
419             pixman_image_get_width(src_image),
420             pixman_image_get_height(src_image));
421     pixman_image_unref(src_image);
422
423     view_send_frame_done(view);
424 }
425
426 static int
427 server_dispatch_stdin(int fd, uint32_t mask, void *data)
428 {
429     struct tinyds_server *server = data;
430
431     wl_display_terminate(server->display);
432
433     return 1;
434 }