Add tinyds on tdm (wip)
[platform/core/uifw/libds-tizen.git] / examples / tinyds-tdm.c
1 #include "tinyds-helper.h"
2
3 #include <assert.h>
4 #include <stdbool.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <signal.h>
8 #include <time.h>
9
10 #include <drm_fourcc.h>
11 #include <pixman.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>
21
22 #define TINYDS_UNUSED   __attribute__((unused))
23
24 #define OUTPUT_WIDTH   1280
25 #define OUTPUT_HEIGHT  720
26
27 struct tinyds_output
28 {
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;
34
35     struct wl_listener output_destroy;
36     struct wl_listener output_frame;
37
38     int width, height;
39
40     bool drawable;
41     bool damaged;
42 };
43
44 struct tinyds_server
45 {
46     struct wl_display *display;
47
48     struct ds_backend *backend;
49     struct ds_compositor *compositor;
50     struct ds_xdg_shell *xdg_shell;
51
52     struct tinyds_output *output;
53     struct tinyds_renderer renderer;
54
55     struct wl_list views;
56
57     struct wl_listener new_output;
58     struct wl_listener new_xdg_surface;
59 };
60
61 struct tinyds_view
62 {
63     struct tinyds_server *server;
64
65     struct ds_xdg_surface *xdg_surface;
66
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
72
73     int x, y;
74     bool mapped;
75 };
76
77 struct tinyds_server _tinyds;
78
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);
86
87 int
88 main(void)
89 {
90     struct tinyds_server *server = &_tinyds;
91     struct wl_display *display;
92     const char *socket;
93
94     ds_log_init(DS_DBG, NULL);
95
96     display = wl_display_create();
97     assert(display);
98
99     assert(init_server(server, display) == true);
100
101     assert(tinyds_renderer_init_display(&server->renderer, display));
102
103     socket = wl_display_add_socket_auto(display);
104     assert(socket);
105
106     ds_backend_start(server->backend);
107
108     setenv("WAYLAND_DISPLAY", socket, true);
109
110     ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket);
111
112     wl_display_destroy(display);
113
114     return 0;
115 }
116
117 static void
118 view_handle_xdg_surface_map(struct wl_listener *listener,
119         void *data TINYDS_UNUSED)
120 {
121     struct tinyds_view *view;
122
123     view = wl_container_of(listener, view, xdg_surface_map);
124     view->mapped = true;
125 }
126
127 static void
128 view_handle_xdg_surface_unmap(struct wl_listener *listener,
129         void *data TINYDS_UNUSED)
130 {
131     struct tinyds_view *view;
132
133     view = wl_container_of(listener, view, xdg_surface_unmap);
134     view->mapped = false;
135 }
136
137 static void
138 view_handle_xdg_surface_destroy(struct wl_listener *listener,
139         void *data TINYDS_UNUSED) 
140 {
141     struct tinyds_view *view;
142
143     view = wl_container_of(listener, view, xdg_surface_destroy);
144
145     draw_server_with_damage(view->server);
146
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);
152     free(view);
153 }
154
155 static void
156 view_handle_surface_commit(struct wl_listener *listener,
157         void *data TINYDS_UNUSED)
158 {
159     struct tinyds_view *view;
160
161     view = wl_container_of(listener, view, surface_commit);
162     draw_server_with_damage(view->server);
163 }
164
165 static void
166 server_new_xdg_surface(struct wl_listener *listener, void *data)
167 {
168     struct tinyds_server *server;
169     struct tinyds_view *view;
170     struct ds_xdg_surface *xdg_surface;
171
172     server = wl_container_of(listener, server, new_xdg_surface);
173     xdg_surface = data;
174
175     ds_inf("New xdg_surface(%p)", (void *)xdg_surface);
176
177     view = calloc(1, sizeof *view);
178     view->server = server;
179     view->xdg_surface = xdg_surface;
180
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);
184
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);
188
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);
192
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);
197
198     wl_list_insert(server->views.prev, &view->link);
199 }
200
201 static void
202 backend_handle_new_output(struct wl_listener *listener, void *data)
203 {
204     struct tinyds_server *server;
205     struct tinyds_output *output;
206     struct ds_output *ds_output;
207
208     server = wl_container_of(listener, server, new_output);
209     ds_output = data;
210
211     ds_inf("New output(%p)", ds_output);
212
213     if (server->output)
214         return;
215
216     output = calloc(1, sizeof *output);
217     if (!output)
218         return;
219
220     output->server = server;
221     output->ds_output = ds_output;
222
223     output->output_destroy.notify = output_handle_destroy;
224     ds_output_add_destroy_listener(ds_output,
225             &output->output_destroy);
226
227     output->output_frame.notify = output_handle_frame;
228     ds_output_add_frame_listener(ds_output,
229             &output->output_frame);
230
231     server->output = output;
232 }
233
234 static bool
235 init_server(struct tinyds_server *server, struct wl_display *display)
236 {
237     server->display = display;
238
239     wl_list_init(&server->views);
240
241     if (wl_display_init_shm(display) != 0)
242         return false;
243
244     server->backend = ds_tdm_backend_create(display);
245     if (!server->backend)
246         return false;
247
248     server->new_output.notify = backend_handle_new_output;
249     ds_backend_add_new_output_listener(server->backend,
250             &server->new_output);
251
252     server->compositor = ds_compositor_create(display);
253     if (!server->compositor) {
254         ds_backend_destroy(server->backend);
255         return false;
256     }
257
258     server->xdg_shell = ds_xdg_shell_create(display);
259     if (!server->xdg_shell) {
260         ds_backend_destroy(server->backend);
261         return false;
262     }
263
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);
267
268     return true;
269 }
270
271 static void
272 output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
273 {
274     struct tinyds_output *output =
275         wl_container_of(listener, output, output_destroy);
276
277     wl_list_remove(&output->output_destroy.link);
278     wl_list_remove(&output->output_frame.link);
279
280     if (output->front_buffer)
281         ds_buffer_unlock(output->front_buffer);
282
283     if (output->swapchain)
284         ds_swapchain_destroy(output->swapchain);
285
286     if (output->allocator)
287         ds_allocator_destroy(output->allocator);
288
289     wl_display_terminate(output->server->display);
290
291     output->server->output = NULL;
292
293     free(output);
294 }
295
296 static void
297 output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED)
298 {
299     struct tinyds_output *output =
300         wl_container_of(listener, output, output_frame);
301
302 }
303
304 static void
305 draw_server(struct tinyds_server *server)
306 {
307     draw_output(server->output);
308 }
309
310 static void
311 draw_server_with_damage(struct tinyds_server *server)
312 {
313     server->output->damaged = true;
314     draw_output(server->output);
315 }
316
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);
322
323 static void
324 draw_output(struct tinyds_output *output)
325 {
326     struct ds_buffer *output_buffer;
327     pixman_image_t *output_image;
328     struct tinyds_view *view;
329
330     if (!output->drawable || !output->damaged)
331         return;
332
333     output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
334     if (!output_buffer)
335         return;
336
337     output_image = image_from_buffer(output_buffer,
338             DS_BUFFER_DATA_PTR_ACCESS_WRITE);
339     if (!output_image) {
340         ds_buffer_unlock(output_buffer);
341         return;
342     }
343
344     image_fill_color(output_image, 80, 80, 80);
345
346     wl_list_for_each(view, &output->server->views, link) {
347         if (!view->mapped)
348             continue;
349         draw_view(view, output_image);
350     }
351     pixman_image_unref(output_image);
352
353     ds_output_attach_buffer(output->ds_output, output_buffer);
354     ds_output_commit(output->ds_output);
355
356     if (output->front_buffer)
357         ds_buffer_unlock(output->front_buffer);
358     output->front_buffer = output_buffer;
359
360     output->drawable = false;
361     output->damaged = false;
362 }
363
364 static void
365 draw_view(struct tinyds_view *view, pixman_image_t *dst_image)
366 {
367     struct ds_buffer *buffer;
368     pixman_image_t *src_image;
369
370     buffer = ds_surface_get_buffer(
371             ds_xdg_surface_get_surface(view->xdg_surface));
372     if (!buffer)
373         return;
374
375     src_image = image_from_buffer(buffer,
376             DS_BUFFER_DATA_PTR_ACCESS_READ);
377     pixman_image_composite32(PIXMAN_OP_OVER,
378             src_image,
379             NULL,
380             dst_image,
381             0, 0, 0, 0, 0, 0,
382             pixman_image_get_width(src_image),
383             pixman_image_get_height(src_image));
384     pixman_image_unref(src_image);
385
386     view_send_frame_done(view);
387 }
388
389 static pixman_color_t *
390 color_rgb888(pixman_color_t *tmp, uint8_t r, uint8_t g, uint8_t b)
391 {
392     tmp->alpha = 65535;
393     tmp->red = (r << 8) + r;
394     tmp->green = (g << 8) + g;
395     tmp->blue = (b << 8) +b;
396
397     return tmp;
398 }
399
400 static void
401 image_fill_color(pixman_image_t *image, uint8_t r, uint8_t g, uint8_t b)
402 {
403     pixman_image_t *color_image;
404     pixman_color_t color;
405
406     color_rgb888(&color, r, g, b);
407     color_image = pixman_image_create_solid_fill(&color);
408     pixman_image_composite32(PIXMAN_OP_SRC,
409             color_image,
410             NULL,
411             image,
412             0, 0, 0, 0, 0, 0,
413             pixman_image_get_width(image),
414             pixman_image_get_height(image));
415     pixman_image_unref(color_image);
416 }
417
418 static void                                             
419 destroy_pixman_image(pixman_image_t *image TINYDS_UNUSED, void *data)
420 {
421     struct ds_buffer *buffer = data;
422     ds_buffer_end_data_ptr_access(buffer);
423     ds_buffer_unlock(buffer);
424 }
425
426 static uint32_t
427 convert_drm_format_to_pixman(uint32_t fmt)
428 {
429     switch (fmt) {
430         case DRM_FORMAT_XRGB8888:
431             return PIXMAN_x8r8g8b8;
432         case DRM_FORMAT_ARGB8888:
433             return PIXMAN_a8r8g8b8;
434         default:
435             assert(0 && "not reached");
436     }
437 }
438
439 static pixman_image_t *
440 image_from_buffer(struct ds_buffer *buffer,
441         enum ds_buffer_data_ptr_access_flag access_flag)
442 {
443     pixman_image_t *image;
444     void *data;
445     uint32_t format;
446     size_t stride;
447     int width, height;
448
449     ds_buffer_get_size(buffer, &width, &height);
450
451     if (!ds_buffer_begin_data_ptr_access(buffer,
452                 access_flag, &data, &format, &stride))
453         return NULL;
454
455     format = convert_drm_format_to_pixman(format);
456     image = pixman_image_create_bits(format, width, height, data, stride);
457     if (!image) {
458         ds_buffer_end_data_ptr_access(buffer);
459         return NULL;
460     }
461
462     pixman_image_set_destroy_function(image,
463             destroy_pixman_image, ds_buffer_lock(buffer));
464
465     return image;
466 }
467
468 static void
469 view_send_frame_done(struct tinyds_view *view)
470 {
471     struct timespec now;
472     clock_gettime(CLOCK_MONOTONIC, &now);
473     ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface),
474             &now);
475 }