rearrange the directories of git repository
[platform/core/uifw/libds-tizen.git] / examples / tinyds-tdm.c
1 #include <assert.h>
2 #include <stdbool.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <signal.h>
6 #include <time.h>
7
8 #include <drm_fourcc.h>
9 #include <pixman.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
20 #define USE_TDM_BUFFER_QUEUE
21
22 #ifdef USE_TDM_BUFFER_QUEUE
23 #include "pixman-tbm-helper.h"
24 #include "tinyds-tdm-renderer.h"
25 #else
26 #include <libds/swapchain.h>
27 #endif
28
29 #include "pixman-helper.h"
30
31 #define TINYDS_UNUSED   __attribute__((unused))
32
33 struct tinyds_output
34 {
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;
42 #else
43     struct ds_swapchain *swapchain;
44 #endif
45     struct ds_buffer *front_buffer;
46
47     struct wl_listener output_destroy;
48     struct wl_listener output_frame;
49
50     int width, height;
51
52     bool drawable;
53     bool damaged;
54 };
55
56 struct tinyds_server
57 {
58     struct ds_tbm_server *tbm_server;
59
60     struct wl_display *display;
61
62     struct ds_backend *backend;
63     struct ds_compositor *compositor;
64     struct ds_xdg_shell *xdg_shell;
65
66     struct tinyds_output *output;
67     struct wl_event_source *stdin_source;
68
69     struct wl_list views;
70
71     struct wl_listener new_output;
72     struct wl_listener new_xdg_surface;
73 };
74
75 struct tinyds_view
76 {
77     struct tinyds_server *server;
78
79     struct tinyds_texture *texture;
80     struct ds_xdg_surface *xdg_surface;
81
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
87
88     int x, y;
89     bool mapped;
90 };
91
92 struct tinyds_server tinyds;
93
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);
107 #else
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);
112 #endif
113
114 int
115 main(void)
116 {
117     struct tinyds_server *server = &tinyds;
118     struct wl_display *display;
119     struct wl_event_loop *loop;
120     const char *socket;
121     bool res;
122
123     ds_log_init(DS_INF, NULL);
124
125     display = wl_display_create();
126     assert(display);
127
128     res = init_server(server, display);
129     assert(res);
130
131     socket = wl_display_add_socket_auto(display);
132     assert(socket);
133
134     ds_backend_start(server->backend);
135
136     setenv("WAYLAND_DISPLAY", socket, true);
137
138     ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket);
139
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);
143
144     wl_display_run(display);
145
146     wl_display_destroy_clients(display);
147     wl_display_destroy(display);
148
149     return 0;
150 }
151
152 static void
153 view_handle_xdg_surface_map(struct wl_listener *listener,
154         void *data TINYDS_UNUSED)
155 {
156     struct tinyds_view *view;
157
158     view = wl_container_of(listener, view, xdg_surface_map);
159     view->mapped = true;
160 }
161
162 static void
163 view_handle_xdg_surface_unmap(struct wl_listener *listener,
164         void *data TINYDS_UNUSED)
165 {
166     struct tinyds_view *view;
167
168     view = wl_container_of(listener, view, xdg_surface_unmap);
169     view->mapped = false;
170 }
171
172 static void
173 view_handle_xdg_surface_destroy(struct wl_listener *listener,
174         void *data TINYDS_UNUSED) 
175 {
176     struct tinyds_view *view;
177     struct tinyds_server *server;
178
179     view = wl_container_of(listener, view, xdg_surface_destroy);
180     server = view->server;
181
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);
187     free(view);
188
189     draw_server_with_damage(server);
190 }
191
192 static void
193 view_handle_surface_commit(struct wl_listener *listener,
194         void *data TINYDS_UNUSED)
195 {
196     struct tinyds_view *view;
197
198     view = wl_container_of(listener, view, surface_commit);
199     draw_server_with_damage(view->server);
200 }
201
202 static void
203 server_new_xdg_surface(struct wl_listener *listener, void *data)
204 {
205     struct tinyds_server *server;
206     struct tinyds_view *view;
207     struct ds_xdg_surface *xdg_surface;
208
209     server = wl_container_of(listener, server, new_xdg_surface);
210     xdg_surface = data;
211
212     ds_inf("New xdg_surface(%p)", (void *)xdg_surface);
213
214     view = calloc(1, sizeof *view);
215     assert(view);
216
217     view->server = server;
218     view->xdg_surface = xdg_surface;
219
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);
223
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);
227
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);
231
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);
236
237     wl_list_insert(server->views.prev, &view->link);
238
239     view->x = rand() % 1000;
240     view->y = rand() % 500;
241 }
242
243 static void
244 backend_handle_new_output(struct wl_listener *listener, void *data)
245 {
246     struct tinyds_server *server;
247     struct tinyds_output *output;
248     struct ds_output *ds_output;
249     const struct ds_output_mode *mode;
250
251     server = wl_container_of(listener, server, new_output);
252     ds_output = data;
253
254     ds_inf("New output(%p)", ds_output);
255
256     if (server->output)
257         return;
258
259     mode = ds_output_get_preferred_mode(ds_output);
260     ds_output_set_mode(ds_output, mode);
261
262     output = calloc(1, sizeof *output);
263     if (!output)
264         return;
265
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;
272
273 #ifdef USE_TDM_BUFFER_QUEUE
274     output_buffer_queue_init(output);
275     output_renderer_init(output);
276 #else
277     output_swapchain_init(output, mode->width, mode->height,
278             DRM_FORMAT_XRGB8888);
279 #endif
280
281     output->output_destroy.notify = output_handle_destroy;
282     ds_output_add_destroy_listener(ds_output, &output->output_destroy);
283
284     output->output_frame.notify = output_handle_frame;
285     ds_output_add_frame_listener(ds_output, &output->output_frame);
286
287     server->output = output;
288
289     draw_output(output);
290 }
291
292 static bool
293 init_server(struct tinyds_server *server, struct wl_display *display)
294 {
295     server->display = display;
296
297     wl_list_init(&server->views);
298
299     if (wl_display_init_shm(display) != 0)
300         return false;
301
302     server->backend = ds_tdm_backend_create(display);
303     if (!server->backend)
304         return false;
305
306     server->new_output.notify = backend_handle_new_output;
307     ds_backend_add_new_output_listener(server->backend,
308             &server->new_output);
309
310     server->compositor = ds_compositor_create(display);
311     if (!server->compositor) {
312         ds_backend_destroy(server->backend);
313         return false;
314     }
315
316     server->tbm_server = ds_tbm_server_create(display);
317     if (!server->tbm_server) {
318         ds_backend_destroy(server->backend);
319         return false;
320     }
321
322     server->xdg_shell = ds_xdg_shell_create(display);
323     if (!server->xdg_shell) {
324         ds_backend_destroy(server->backend);
325         return false;
326     }
327
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);
331
332     return true;
333 }
334
335 static void
336 output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
337 {
338     struct tinyds_output *output =
339         wl_container_of(listener, output, output_destroy);
340
341     wl_list_remove(&output->output_destroy.link);
342     wl_list_remove(&output->output_frame.link);
343
344     if (output->front_buffer)
345         ds_buffer_unlock(output->front_buffer);
346
347 #ifdef USE_TDM_BUFFER_QUEUE
348     fini_renderer(&output->renderer);
349 #else
350     if (output->swapchain)
351         ds_swapchain_destroy(output->swapchain);
352
353     if (output->allocator)
354         ds_allocator_destroy(output->allocator);
355 #endif
356
357     wl_display_terminate(output->server->display);
358
359     output->server->output = NULL;
360
361     free(output);
362 }
363
364 static void
365 output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED)
366 {
367     struct tinyds_output *output =
368         wl_container_of(listener, output, output_frame);
369
370     output->drawable = true;
371     draw_output(output);
372 }
373
374 static void
375 draw_server_with_damage(struct tinyds_server *server)
376 {
377     server->output->damaged = true;
378     draw_output(server->output);
379 }
380
381 #ifdef USE_TDM_BUFFER_QUEUE
382 static void
383 output_handle_buffer_queue_acquirable(struct wl_listener *listener,
384         void *data TINYDS_UNUSED)
385 {
386     struct tinyds_output *output;
387     struct ds_buffer *buffer;
388
389     output = wl_container_of(listener, output, buffer_queue_acquirable);
390
391     buffer = ds_tdm_buffer_queue_acquire(output->buffer_queue);
392     assert(buffer);
393
394     output_swap_buffer(output, buffer);
395 }
396
397 static void
398 output_buffer_queue_init(struct tinyds_output *output)
399 {
400     struct ds_tdm_output *tdm_output;
401
402     tdm_output = ds_tdm_output_from_output(output->ds_output);
403     assert(tdm_output);
404
405     output->buffer_queue = ds_tdm_output_get_buffer_queue(tdm_output);
406     assert(output->buffer_queue);
407
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);
412 }
413
414 static void
415 output_renderer_init(struct tinyds_output *output)
416 {
417     init_renderer(&output->renderer);
418
419     renderer_set_surface_queue(&output->renderer,
420             ds_tdm_buffer_queue_get_native_queue(output->buffer_queue));
421
422     renderer_set_bg_color(&output->renderer, 80, 80, 80);
423 }
424
425 static void
426 output_draw_with_renderer(struct tinyds_output *output)
427 {
428     struct tinyds_view *view;
429
430     ds_dbg(">> BEGIN UPDATE TEXTURES");
431
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;
436
437         if (!view->mapped)
438             continue;
439
440         ds_buffer = ds_surface_get_buffer(
441                 ds_xdg_surface_get_surface(view->xdg_surface));
442         assert(ds_buffer);
443
444         tbm_buffer = ds_tbm_client_buffer_from_buffer(ds_buffer);
445         assert(tbm_buffer);
446
447         surface = ds_tbm_client_buffer_get_tbm_surface(tbm_buffer);
448
449         renderer_add_texture(&output->renderer, surface, view->x, view->y);
450
451         view_send_frame_done(view);
452     }
453
454     ds_dbg("<< END UPDATE TEXTURES");
455
456     renderer_draw(&output->renderer);
457
458 }
459 #else
460 static void
461 output_swapchain_init(struct tinyds_output *output,
462         int width, int height, uint32_t format);
463
464 {
465     output->allocator = ds_tbm_allocator_create();
466     assert(output->allocator);
467
468     output->swapchain = ds_swapchain_create(output->allocator,
469             width, height, format);
470     assert(output->swapchain);
471 }
472
473 static void
474 output_draw_with_swapchain(struct tinyds_output *output)
475 {
476     struct tinyds_view *view;
477     struct ds_buffer *output_buffer;
478     pixman_image_t *output_image;
479
480     output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
481     if (!output_buffer)
482         return;
483
484     output_image = pixman_image_from_buffer(output_buffer,
485             DS_BUFFER_DATA_PTR_ACCESS_WRITE);
486     if (!output_image) {
487         ds_buffer_unlock(output_buffer);
488         return;
489     }
490
491     pixman_image_fill_color(output_image, 80, 80, 80);
492
493     wl_list_for_each(view, &output->server->views, link) {
494         if (!view->mapped)
495             continue;
496         draw_view(view, output_image);
497     }
498     pixman_image_unref(output_image);
499
500     output_swap_buffer(output, output_buffer);
501 }
502
503 static void
504 draw_view(struct tinyds_view *view, pixman_image_t *dst_image)
505 {
506     struct ds_buffer *buffer;
507     pixman_image_t *src_image;
508
509     buffer = ds_surface_get_buffer(
510             ds_xdg_surface_get_surface(view->xdg_surface));
511     if (!buffer)
512         return;
513
514     src_image = pixman_image_from_buffer(buffer,
515             DS_BUFFER_DATA_PTR_ACCESS_READ);
516     pixman_image_composite32(PIXMAN_OP_OVER,
517             src_image,
518             NULL,
519             dst_image,
520             0, 0, 0, 0,
521             view->x, view->y,
522             pixman_image_get_width(src_image),
523             pixman_image_get_height(src_image));
524     pixman_image_unref(src_image);
525
526     view_send_frame_done(view);
527 }
528 #endif
529
530 static void
531 draw_output(struct tinyds_output *output)
532 {
533
534     if (!output->drawable || !output->damaged)
535         return;
536
537 #ifdef USE_TDM_BUFFER_QUEUE
538     output_draw_with_renderer(output);
539 #else
540     output_draw_with_swapchain(output);
541 #endif
542
543     output->drawable = false;
544     output->damaged = false;
545 }
546
547 static void
548 output_swap_buffer(struct tinyds_output *output, struct ds_buffer *buffer)
549 {
550     ds_output_attach_buffer(output->ds_output, buffer);
551     ds_output_commit(output->ds_output);
552
553     if (output->front_buffer)
554         ds_buffer_unlock(output->front_buffer);
555     output->front_buffer = buffer;
556 }
557
558 static void
559 view_send_frame_done(struct tinyds_view *view)
560 {
561     struct timespec now;
562     clock_gettime(CLOCK_MONOTONIC, &now);
563     ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface),
564             &now);
565 }
566
567 static int
568 server_dispatch_stdin(int fd, uint32_t mask, void *data)
569 {
570     struct tinyds_server *server = data;
571
572     wl_display_terminate(server->display);
573
574     return 1;
575 }