dc32e8f76c5793d25a79a672c3b24caf473401e3
[platform/core/uifw/libds-tizen.git] / src / examples / tinyds-tdm-dpms.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 #include <libds-tizen/dpms.h>
20
21 #define USE_TDM_BUFFER_QUEUE
22
23 #ifdef USE_TDM_BUFFER_QUEUE
24 #include "pixman-tbm-helper.h"
25 #include "tinyds-tdm-renderer.h"
26 #else
27 #include <libds/swapchain.h>
28 #endif
29
30 #include "pixman-helper.h"
31
32 #define TINYDS_UNUSED   __attribute__((unused))
33
34 struct tinyds_output
35 {
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;
43 #else
44     struct ds_swapchain *swapchain;
45 #endif
46     struct ds_buffer *front_buffer;
47
48     struct wl_listener output_destroy;
49     struct wl_listener output_frame;
50
51     int width, height;
52
53     bool drawable;
54     bool damaged;
55 };
56
57 struct tinyds_dpms
58 {
59     struct ds_tizen_dpms *ds_dpms;
60     struct tinyds_server *server;
61
62     struct wl_listener destroy;
63     struct wl_listener set_dpms;
64     struct wl_listener get_dpms;
65 };
66
67 struct tinyds_server
68 {
69     struct ds_tbm_server *tbm_server;
70
71     struct wl_display *display;
72
73     struct ds_backend *backend;
74     struct ds_compositor *compositor;
75     struct ds_xdg_shell *xdg_shell;
76
77     struct tinyds_output *output;
78     struct tinyds_dpms *dpms;
79     struct wl_event_source *stdin_source;
80
81     struct wl_list views;
82
83     struct wl_listener new_output;
84     struct wl_listener new_xdg_surface;
85 };
86
87 struct tinyds_view
88 {
89     struct tinyds_server *server;
90
91     struct tinyds_texture *texture;
92     struct ds_xdg_surface *xdg_surface;
93
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
99
100     int x, y;
101     bool mapped;
102 };
103
104 struct tinyds_server tinyds;
105
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);
119 #else
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);
124 #endif
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);
128
129
130 int
131 main(void)
132 {
133     struct tinyds_server *server = &tinyds;
134     struct wl_display *display;
135     struct wl_event_loop *loop;
136     const char *socket;
137     bool res;
138
139     ds_log_init(DS_INF, NULL);
140
141     display = wl_display_create();
142     assert(display);
143
144     res = init_server(server, display);
145     assert(res);
146
147     socket = wl_display_add_socket_auto(display);
148     assert(socket);
149
150     ds_backend_start(server->backend);
151
152     setenv("WAYLAND_DISPLAY", socket, true);
153
154     ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket);
155
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);
159
160     wl_display_run(display);
161
162     wl_display_destroy_clients(display);
163     wl_display_destroy(display);
164
165     return 0;
166 }
167
168 static void
169 view_handle_xdg_surface_map(struct wl_listener *listener,
170         void *data TINYDS_UNUSED)
171 {
172     struct tinyds_view *view;
173
174     view = wl_container_of(listener, view, xdg_surface_map);
175     view->mapped = true;
176 }
177
178 static void
179 view_handle_xdg_surface_unmap(struct wl_listener *listener,
180         void *data TINYDS_UNUSED)
181 {
182     struct tinyds_view *view;
183
184     view = wl_container_of(listener, view, xdg_surface_unmap);
185     view->mapped = false;
186 }
187
188 static void
189 view_handle_xdg_surface_destroy(struct wl_listener *listener,
190         void *data TINYDS_UNUSED) 
191 {
192     struct tinyds_view *view;
193     struct tinyds_server *server;
194
195     view = wl_container_of(listener, view, xdg_surface_destroy);
196     server = view->server;
197
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);
203     free(view);
204
205     draw_server_with_damage(server);
206 }
207
208 static void
209 view_handle_surface_commit(struct wl_listener *listener,
210         void *data TINYDS_UNUSED)
211 {
212     struct tinyds_view *view;
213
214     view = wl_container_of(listener, view, surface_commit);
215     draw_server_with_damage(view->server);
216 }
217
218 static void
219 server_new_xdg_surface(struct wl_listener *listener, void *data)
220 {
221     struct tinyds_server *server;
222     struct tinyds_view *view;
223     struct ds_xdg_surface *xdg_surface;
224
225     server = wl_container_of(listener, server, new_xdg_surface);
226     xdg_surface = data;
227
228     ds_inf("New xdg_surface(%p)", (void *)xdg_surface);
229
230     view = calloc(1, sizeof *view);
231     assert(view);
232
233     view->server = server;
234     view->xdg_surface = xdg_surface;
235
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);
239
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);
243
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);
247
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);
252
253     wl_list_insert(server->views.prev, &view->link);
254
255     view->x = rand() % 1000;
256     view->y = rand() % 500;
257 }
258
259 static void
260 backend_handle_new_output(struct wl_listener *listener, void *data)
261 {
262     struct tinyds_server *server;
263     struct tinyds_output *output;
264     struct ds_output *ds_output;
265     const struct ds_output_mode *mode;
266
267     server = wl_container_of(listener, server, new_output);
268     ds_output = data;
269
270     ds_inf("New output(%p)", ds_output);
271
272     if (server->output)
273         return;
274
275     mode = ds_output_get_preferred_mode(ds_output);
276     ds_output_set_mode(ds_output, mode);
277
278     output = calloc(1, sizeof *output);
279     if (!output)
280         return;
281
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;
288
289 #ifdef USE_TDM_BUFFER_QUEUE
290     output_buffer_queue_init(output);
291     output_renderer_init(output);
292 #else
293     output_swapchain_init(output, mode->width, mode->height,
294             DRM_FORMAT_XRGB8888);
295 #endif
296
297     output->output_destroy.notify = output_handle_destroy;
298     ds_output_add_destroy_listener(ds_output, &output->output_destroy);
299
300     output->output_frame.notify = output_handle_frame;
301     ds_output_add_frame_listener(ds_output, &output->output_frame);
302
303     server->output = output;
304
305     draw_output(output);
306 }
307
308 static bool
309 add_new_dpms(struct tinyds_server *server)
310 {
311     struct tinyds_dpms *dpms;
312
313     dpms = calloc(1, sizeof *dpms);
314     if (!dpms)
315         return false;
316
317     dpms->ds_dpms = ds_tizen_dpms_create(server->display);
318     if (!dpms->ds_dpms)
319         return false;
320
321     dpms->destroy.notify = dpms_handle_destroy;
322     ds_tizen_dpms_add_destroy_listener(dpms->ds_dpms, &dpms->destroy);
323
324     dpms->set_dpms.notify = dpms_handle_set_dpms;
325     ds_tizen_dpms_add_set_dpms_listener(dpms->ds_dpms, &dpms->set_dpms);
326
327     dpms->get_dpms.notify = dpms_handle_get_dpms;
328     ds_tizen_dpms_add_get_dpms_listener(dpms->ds_dpms, &dpms->get_dpms);
329
330     server->dpms = dpms;
331
332     ds_inf("Dpms (%p) added", dpms);
333
334     return true;
335 }
336
337 static bool
338 init_server(struct tinyds_server *server, struct wl_display *display)
339 {
340     server->display = display;
341
342     wl_list_init(&server->views);
343
344     if (wl_display_init_shm(display) != 0)
345         return false;
346
347     server->backend = ds_tdm_backend_create(display);
348     if (!server->backend)
349         return false;
350
351     server->new_output.notify = backend_handle_new_output;
352     ds_backend_add_new_output_listener(server->backend,
353             &server->new_output);
354
355     server->compositor = ds_compositor_create(display);
356     if (!server->compositor) {
357         ds_backend_destroy(server->backend);
358         return false;
359     }
360
361     server->tbm_server = ds_tbm_server_create(display);
362     if (!server->tbm_server) {
363         ds_backend_destroy(server->backend);
364         return false;
365     }
366
367     server->xdg_shell = ds_xdg_shell_create(display);
368     if (!server->xdg_shell) {
369         ds_backend_destroy(server->backend);
370         return false;
371     }
372
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);
376
377     if (!add_new_dpms(server)) {
378         ds_backend_destroy(server->backend);
379         return false;
380     }
381
382     return true;
383 }
384
385 static void
386 output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
387 {
388     struct tinyds_output *output =
389         wl_container_of(listener, output, output_destroy);
390
391     wl_list_remove(&output->output_destroy.link);
392     wl_list_remove(&output->output_frame.link);
393
394     if (output->front_buffer)
395         ds_buffer_unlock(output->front_buffer);
396
397 #ifdef USE_TDM_BUFFER_QUEUE
398     fini_renderer(&output->renderer);
399 #else
400     if (output->swapchain)
401         ds_swapchain_destroy(output->swapchain);
402
403     if (output->allocator)
404         ds_allocator_destroy(output->allocator);
405 #endif
406
407     wl_display_terminate(output->server->display);
408
409     output->server->output = NULL;
410
411     free(output);
412 }
413
414 static void
415 output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED)
416 {
417     struct tinyds_output *output =
418         wl_container_of(listener, output, output_frame);
419
420     output->drawable = true;
421     draw_output(output);
422 }
423
424 static void
425 draw_server_with_damage(struct tinyds_server *server)
426 {
427     server->output->damaged = true;
428     draw_output(server->output);
429 }
430
431 #ifdef USE_TDM_BUFFER_QUEUE
432 static void
433 output_handle_buffer_queue_acquirable(struct wl_listener *listener,
434         void *data TINYDS_UNUSED)
435 {
436     struct tinyds_output *output;
437     struct ds_buffer *buffer;
438
439     output = wl_container_of(listener, output, buffer_queue_acquirable);
440
441     buffer = ds_tdm_buffer_queue_acquire(output->buffer_queue);
442     assert(buffer);
443
444     output_swap_buffer(output, buffer);
445 }
446
447 static void
448 output_buffer_queue_init(struct tinyds_output *output)
449 {
450     struct ds_tdm_output *tdm_output;
451
452     tdm_output = ds_tdm_output_from_output(output->ds_output);
453     assert(tdm_output);
454
455     output->buffer_queue = ds_tdm_output_get_buffer_queue(tdm_output);
456     assert(output->buffer_queue);
457
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);
462 }
463
464 static void
465 output_renderer_init(struct tinyds_output *output)
466 {
467     init_renderer(&output->renderer);
468
469     renderer_set_surface_queue(&output->renderer,
470             ds_tdm_buffer_queue_get_native_queue(output->buffer_queue));
471
472     renderer_set_bg_color(&output->renderer, 80, 80, 80);
473 }
474
475 static void
476 output_draw_with_renderer(struct tinyds_output *output)
477 {
478     struct tinyds_view *view;
479
480     ds_dbg(">> BEGIN UPDATE TEXTURES");
481
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;
486
487         if (!view->mapped)
488             continue;
489
490         ds_buffer = ds_surface_get_buffer(
491                 ds_xdg_surface_get_surface(view->xdg_surface));
492         assert(ds_buffer);
493
494         tbm_buffer = ds_tbm_client_buffer_from_buffer(ds_buffer);
495         assert(tbm_buffer);
496
497         surface = ds_tbm_client_buffer_get_tbm_surface(tbm_buffer);
498
499         renderer_add_texture(&output->renderer, surface, view->x, view->y);
500
501         view_send_frame_done(view);
502     }
503
504     ds_dbg("<< END UPDATE TEXTURES");
505
506     renderer_draw(&output->renderer);
507
508 }
509 #else
510 static void
511 output_swapchain_init(struct tinyds_output *output,
512         int width, int height, uint32_t format);
513
514 {
515     output->allocator = ds_tbm_allocator_create();
516     assert(output->allocator);
517
518     output->swapchain = ds_swapchain_create(output->allocator,
519             width, height, format);
520     assert(output->swapchain);
521 }
522
523 static void
524 output_draw_with_swapchain(struct tinyds_output *output)
525 {
526     struct tinyds_view *view;
527     struct ds_buffer *output_buffer;
528     pixman_image_t *output_image;
529
530     output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
531     if (!output_buffer)
532         return;
533
534     output_image = pixman_image_from_buffer(output_buffer,
535             DS_BUFFER_DATA_PTR_ACCESS_WRITE);
536     if (!output_image) {
537         ds_buffer_unlock(output_buffer);
538         return;
539     }
540
541     pixman_image_fill_color(output_image, 80, 80, 80);
542
543     wl_list_for_each(view, &output->server->views, link) {
544         if (!view->mapped)
545             continue;
546         draw_view(view, output_image);
547     }
548     pixman_image_unref(output_image);
549
550     output_swap_buffer(output, output_buffer);
551 }
552
553 static void
554 draw_view(struct tinyds_view *view, pixman_image_t *dst_image)
555 {
556     struct ds_buffer *buffer;
557     pixman_image_t *src_image;
558
559     buffer = ds_surface_get_buffer(
560             ds_xdg_surface_get_surface(view->xdg_surface));
561     if (!buffer)
562         return;
563
564     src_image = pixman_image_from_buffer(buffer,
565             DS_BUFFER_DATA_PTR_ACCESS_READ);
566     pixman_image_composite32(PIXMAN_OP_OVER,
567             src_image,
568             NULL,
569             dst_image,
570             0, 0, 0, 0,
571             view->x, view->y,
572             pixman_image_get_width(src_image),
573             pixman_image_get_height(src_image));
574     pixman_image_unref(src_image);
575
576     view_send_frame_done(view);
577 }
578 #endif
579
580 static void
581 draw_output(struct tinyds_output *output)
582 {
583
584     if (!output->drawable || !output->damaged)
585         return;
586
587 #ifdef USE_TDM_BUFFER_QUEUE
588     output_draw_with_renderer(output);
589 #else
590     output_draw_with_swapchain(output);
591 #endif
592
593     output->drawable = false;
594     output->damaged = false;
595 }
596
597 static void
598 output_swap_buffer(struct tinyds_output *output, struct ds_buffer *buffer)
599 {
600     ds_output_attach_buffer(output->ds_output, buffer);
601     ds_output_commit(output->ds_output);
602
603     if (output->front_buffer)
604         ds_buffer_unlock(output->front_buffer);
605     output->front_buffer = buffer;
606 }
607
608 static void
609 view_send_frame_done(struct tinyds_view *view)
610 {
611     struct timespec now;
612     clock_gettime(CLOCK_MONOTONIC, &now);
613     ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface),
614             &now);
615 }
616
617 static int
618 server_dispatch_stdin(int fd, uint32_t mask, void *data)
619 {
620     struct tinyds_server *server = data;
621
622     wl_display_terminate(server->display);
623
624     return 1;
625 }
626
627 static void
628 dpms_handle_destroy(struct wl_listener *listener, void *data)
629 {
630     struct tinyds_dpms *dpms;
631
632     dpms = wl_container_of(listener, dpms, destroy);
633
634     ds_inf("Dpms(%p) destroyed", dpms);
635
636     wl_list_remove(&dpms->destroy.link);
637     wl_list_remove(&dpms->set_dpms.link);
638     wl_list_remove(&dpms->get_dpms.link);
639
640     free(dpms);
641 }
642
643 static void
644 dpms_handle_set_dpms(struct wl_listener *listener, void *data)
645 {
646     struct tinyds_dpms *dpms;
647     struct ds_tizen_dpms_event *event = data;
648
649     dpms = wl_container_of(listener, dpms, set_dpms);
650
651     ds_inf("Dpms(%p) set dpms : %d", dpms, event->mode);
652
653     //To do
654     //set dpms mode to output
655     ds_tizen_dpms_send_set_result(dpms->ds_dpms, event->mode,
656         DS_TIZEN_DPMS_ERROR_NONE);
657 }
658
659 static void
660 dpms_handle_get_dpms(struct wl_listener *listener, void *data)
661 {
662     struct tinyds_dpms *dpms;
663
664     dpms = wl_container_of(listener, dpms, get_dpms);
665
666     ds_inf("Dpms(%p) get dpms", dpms);
667
668     //To do
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);
672 }