--- /dev/null
+#include <assert.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <time.h>
+
+#include <drm_fourcc.h>
+#include <pixman.h>
+#include <wayland-server.h>
+#include <libds/log.h>
+#include <libds/backend.h>
+#include <libds/output.h>
+#include <libds/compositor.h>
+#include <libds/xdg_shell.h>
+#include <libds-tizen/allocator/tbm.h>
+#include <libds-tizen/backend/tdm.h>
+#include <libds-tizen/tbm_server.h>
+#include <libds-tizen/dpms.h>
+
+#define USE_TDM_BUFFER_QUEUE
+
+#ifdef USE_TDM_BUFFER_QUEUE
+#include "pixman-tbm-helper.h"
+#include "tinyds-tdm-renderer.h"
+#else
+#include <libds/swapchain.h>
+#endif
+
+#include "pixman-helper.h"
+
+#define TINYDS_UNUSED __attribute__((unused))
+
+struct tinyds_output
+{
+ struct tinyds_server *server;
+ struct ds_output *ds_output;
+ struct ds_allocator *allocator;
+#ifdef USE_TDM_BUFFER_QUEUE
+ struct tinyds_renderer renderer;
+ struct ds_tdm_buffer_queue *buffer_queue;
+ struct wl_listener buffer_queue_acquirable;
+#else
+ struct ds_swapchain *swapchain;
+#endif
+ struct ds_buffer *front_buffer;
+
+ struct wl_listener output_destroy;
+ struct wl_listener output_frame;
+
+ int width, height;
+
+ bool drawable;
+ bool damaged;
+};
+
+struct tinyds_dpms
+{
+ struct ds_tizen_dpms *ds_dpms;
+ struct tinyds_server *server;
+
+ struct wl_listener destroy;
+ struct wl_listener set_dpms;
+ struct wl_listener get_dpms;
+};
+
+struct tinyds_server
+{
+ struct ds_tbm_server *tbm_server;
+
+ struct wl_display *display;
+
+ struct ds_backend *backend;
+ struct ds_compositor *compositor;
+ struct ds_xdg_shell *xdg_shell;
+
+ struct tinyds_output *output;
+ struct tinyds_dpms *dpms;
+ struct wl_event_source *stdin_source;
+
+ struct wl_list views;
+
+ struct wl_listener new_output;
+ struct wl_listener new_xdg_surface;
+};
+
+struct tinyds_view
+{
+ struct tinyds_server *server;
+
+ struct tinyds_texture *texture;
+ struct ds_xdg_surface *xdg_surface;
+
+ struct wl_listener xdg_surface_map;
+ struct wl_listener xdg_surface_unmap;
+ struct wl_listener xdg_surface_destroy;
+ struct wl_listener surface_commit;
+ struct wl_list link; // tinyds_server::views
+
+ int x, y;
+ bool mapped;
+};
+
+struct tinyds_server tinyds;
+
+static bool init_server(struct tinyds_server *server, struct wl_display *display);
+static int server_dispatch_stdin(int fd, uint32_t mask, void *data);
+static void output_handle_destroy(struct wl_listener *listener, void *data);
+static void output_handle_frame(struct wl_listener *listener, void *data);
+static void draw_server_with_damage(struct tinyds_server *server);
+static void draw_output(struct tinyds_output *output);
+static void output_swap_buffer(struct tinyds_output *output,
+ struct ds_buffer *buffer);
+static void view_send_frame_done(struct tinyds_view *view);
+#ifdef USE_TDM_BUFFER_QUEUE
+static void output_buffer_queue_init(struct tinyds_output *output);
+static void output_renderer_init(struct tinyds_output *output);
+static void output_draw_with_renderer(struct tinyds_output *output);
+#else
+static void output_swapchain_init(struct tinyds_output *output,
+ int width, int height, uint32_t format);
+static void output_draw_with_swapchain(struct tinyds_output *output);
+static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image);
+#endif
+static void dpms_handle_destroy(struct wl_listener *listener, void *data);
+static void dpms_handle_set_dpms(struct wl_listener *listener, void *data);
+static void dpms_handle_get_dpms(struct wl_listener *listener, void *data);
+
+
+int
+main(void)
+{
+ struct tinyds_server *server = &tinyds;
+ struct wl_display *display;
+ struct wl_event_loop *loop;
+ const char *socket;
+ bool res;
+
+ ds_log_init(DS_INF, NULL);
+
+ display = wl_display_create();
+ assert(display);
+
+ res = init_server(server, display);
+ assert(res);
+
+ socket = wl_display_add_socket_auto(display);
+ assert(socket);
+
+ ds_backend_start(server->backend);
+
+ setenv("WAYLAND_DISPLAY", socket, true);
+
+ ds_inf("Running Wayland compositor on WAYLAND_DISPLAY=%s", socket);
+
+ loop = wl_display_get_event_loop(display);
+ server->stdin_source = wl_event_loop_add_fd(loop, STDIN_FILENO,
+ WL_EVENT_READABLE, server_dispatch_stdin, server);
+
+ wl_display_run(display);
+
+ wl_display_destroy_clients(display);
+ wl_display_destroy(display);
+
+ return 0;
+}
+
+static void
+view_handle_xdg_surface_map(struct wl_listener *listener,
+ void *data TINYDS_UNUSED)
+{
+ struct tinyds_view *view;
+
+ view = wl_container_of(listener, view, xdg_surface_map);
+ view->mapped = true;
+}
+
+static void
+view_handle_xdg_surface_unmap(struct wl_listener *listener,
+ void *data TINYDS_UNUSED)
+{
+ struct tinyds_view *view;
+
+ view = wl_container_of(listener, view, xdg_surface_unmap);
+ view->mapped = false;
+}
+
+static void
+view_handle_xdg_surface_destroy(struct wl_listener *listener,
+ void *data TINYDS_UNUSED)
+{
+ struct tinyds_view *view;
+ struct tinyds_server *server;
+
+ view = wl_container_of(listener, view, xdg_surface_destroy);
+ server = view->server;
+
+ wl_list_remove(&view->xdg_surface_destroy.link);
+ wl_list_remove(&view->xdg_surface_map.link);
+ wl_list_remove(&view->xdg_surface_unmap.link);
+ wl_list_remove(&view->surface_commit.link);
+ wl_list_remove(&view->link);
+ free(view);
+
+ draw_server_with_damage(server);
+}
+
+static void
+view_handle_surface_commit(struct wl_listener *listener,
+ void *data TINYDS_UNUSED)
+{
+ struct tinyds_view *view;
+
+ view = wl_container_of(listener, view, surface_commit);
+ draw_server_with_damage(view->server);
+}
+
+static void
+server_new_xdg_surface(struct wl_listener *listener, void *data)
+{
+ struct tinyds_server *server;
+ struct tinyds_view *view;
+ struct ds_xdg_surface *xdg_surface;
+
+ server = wl_container_of(listener, server, new_xdg_surface);
+ xdg_surface = data;
+
+ ds_inf("New xdg_surface(%p)", (void *)xdg_surface);
+
+ view = calloc(1, sizeof *view);
+ assert(view);
+
+ view->server = server;
+ view->xdg_surface = xdg_surface;
+
+ view->xdg_surface_map.notify = view_handle_xdg_surface_map;
+ ds_xdg_surface_add_map_listener(xdg_surface,
+ &view->xdg_surface_map);
+
+ view->xdg_surface_unmap.notify = view_handle_xdg_surface_unmap;
+ ds_xdg_surface_add_unmap_listener(xdg_surface,
+ &view->xdg_surface_unmap);
+
+ view->xdg_surface_destroy.notify = view_handle_xdg_surface_destroy;
+ ds_xdg_surface_add_destroy_listener(xdg_surface,
+ &view->xdg_surface_destroy);
+
+ view->surface_commit.notify = view_handle_surface_commit;
+ ds_surface_add_commit_listener(
+ ds_xdg_surface_get_surface(xdg_surface),
+ &view->surface_commit);
+
+ wl_list_insert(server->views.prev, &view->link);
+
+ view->x = rand() % 1000;
+ view->y = rand() % 500;
+}
+
+static void
+backend_handle_new_output(struct wl_listener *listener, void *data)
+{
+ struct tinyds_server *server;
+ struct tinyds_output *output;
+ struct ds_output *ds_output;
+ const struct ds_output_mode *mode;
+
+ server = wl_container_of(listener, server, new_output);
+ ds_output = data;
+
+ ds_inf("New output(%p)", ds_output);
+
+ if (server->output)
+ return;
+
+ mode = ds_output_get_preferred_mode(ds_output);
+ ds_output_set_mode(ds_output, mode);
+
+ output = calloc(1, sizeof *output);
+ if (!output)
+ return;
+
+ output->server = server;
+ output->ds_output = ds_output;
+ output->width = mode->width;
+ output->height = mode->height;
+ output->drawable = true;
+ output->damaged = true;
+
+#ifdef USE_TDM_BUFFER_QUEUE
+ output_buffer_queue_init(output);
+ output_renderer_init(output);
+#else
+ output_swapchain_init(output, mode->width, mode->height,
+ DRM_FORMAT_XRGB8888);
+#endif
+
+ output->output_destroy.notify = output_handle_destroy;
+ ds_output_add_destroy_listener(ds_output, &output->output_destroy);
+
+ output->output_frame.notify = output_handle_frame;
+ ds_output_add_frame_listener(ds_output, &output->output_frame);
+
+ server->output = output;
+
+ draw_output(output);
+}
+
+static bool
+add_new_dpms(struct tinyds_server *server)
+{
+ struct tinyds_dpms *dpms;
+
+ dpms = calloc(1, sizeof *dpms);
+ if (!dpms)
+ return false;
+
+ dpms->ds_dpms = ds_tizen_dpms_create(server->display);
+ if (!dpms->ds_dpms)
+ return false;
+
+ dpms->destroy.notify = dpms_handle_destroy;
+ ds_tizen_dpms_add_destroy_listener(dpms->ds_dpms, &dpms->destroy);
+
+ dpms->set_dpms.notify = dpms_handle_set_dpms;
+ ds_tizen_dpms_add_set_dpms_listener(dpms->ds_dpms, &dpms->set_dpms);
+
+ dpms->get_dpms.notify = dpms_handle_get_dpms;
+ ds_tizen_dpms_add_get_dpms_listener(dpms->ds_dpms, &dpms->get_dpms);
+
+ server->dpms = dpms;
+
+ ds_inf("Dpms (%p) added", dpms);
+
+ return true;
+}
+
+static bool
+init_server(struct tinyds_server *server, struct wl_display *display)
+{
+ server->display = display;
+
+ wl_list_init(&server->views);
+
+ if (wl_display_init_shm(display) != 0)
+ return false;
+
+ server->backend = ds_tdm_backend_create(display);
+ if (!server->backend)
+ return false;
+
+ server->new_output.notify = backend_handle_new_output;
+ ds_backend_add_new_output_listener(server->backend,
+ &server->new_output);
+
+ server->compositor = ds_compositor_create(display);
+ if (!server->compositor) {
+ ds_backend_destroy(server->backend);
+ return false;
+ }
+
+ server->tbm_server = ds_tbm_server_create(display);
+ if (!server->tbm_server) {
+ ds_backend_destroy(server->backend);
+ return false;
+ }
+
+ server->xdg_shell = ds_xdg_shell_create(display);
+ if (!server->xdg_shell) {
+ ds_backend_destroy(server->backend);
+ return false;
+ }
+
+ server->new_xdg_surface.notify = server_new_xdg_surface;
+ ds_xdg_shell_add_new_surface_listener(server->xdg_shell,
+ &server->new_xdg_surface);
+
+ if (!add_new_dpms(server)) {
+ ds_backend_destroy(server->backend);
+ return false;
+ }
+
+ return true;
+}
+
+static void
+output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
+{
+ struct tinyds_output *output =
+ wl_container_of(listener, output, output_destroy);
+
+ wl_list_remove(&output->output_destroy.link);
+ wl_list_remove(&output->output_frame.link);
+
+ if (output->front_buffer)
+ ds_buffer_unlock(output->front_buffer);
+
+#ifdef USE_TDM_BUFFER_QUEUE
+ fini_renderer(&output->renderer);
+#else
+ if (output->swapchain)
+ ds_swapchain_destroy(output->swapchain);
+
+ if (output->allocator)
+ ds_allocator_destroy(output->allocator);
+#endif
+
+ wl_display_terminate(output->server->display);
+
+ output->server->output = NULL;
+
+ free(output);
+}
+
+static void
+output_handle_frame(struct wl_listener *listener, void *data TINYDS_UNUSED)
+{
+ struct tinyds_output *output =
+ wl_container_of(listener, output, output_frame);
+
+ output->drawable = true;
+ draw_output(output);
+}
+
+static void
+draw_server_with_damage(struct tinyds_server *server)
+{
+ server->output->damaged = true;
+ draw_output(server->output);
+}
+
+#ifdef USE_TDM_BUFFER_QUEUE
+static void
+output_handle_buffer_queue_acquirable(struct wl_listener *listener,
+ void *data TINYDS_UNUSED)
+{
+ struct tinyds_output *output;
+ struct ds_buffer *buffer;
+
+ output = wl_container_of(listener, output, buffer_queue_acquirable);
+
+ buffer = ds_tdm_buffer_queue_acquire(output->buffer_queue);
+ assert(buffer);
+
+ output_swap_buffer(output, buffer);
+}
+
+static void
+output_buffer_queue_init(struct tinyds_output *output)
+{
+ struct ds_tdm_output *tdm_output;
+
+ tdm_output = ds_tdm_output_from_output(output->ds_output);
+ assert(tdm_output);
+
+ output->buffer_queue = ds_tdm_output_get_buffer_queue(tdm_output);
+ assert(output->buffer_queue);
+
+ output->buffer_queue_acquirable.notify =
+ output_handle_buffer_queue_acquirable;
+ ds_tdm_buffer_queue_add_acquirable_listener(output->buffer_queue,
+ &output->buffer_queue_acquirable);
+}
+
+static void
+output_renderer_init(struct tinyds_output *output)
+{
+ init_renderer(&output->renderer);
+
+ renderer_set_surface_queue(&output->renderer,
+ ds_tdm_buffer_queue_get_native_queue(output->buffer_queue));
+
+ renderer_set_bg_color(&output->renderer, 80, 80, 80);
+}
+
+static void
+output_draw_with_renderer(struct tinyds_output *output)
+{
+ struct tinyds_view *view;
+
+ ds_dbg(">> BEGIN UPDATE TEXTURES");
+
+ wl_list_for_each(view, &output->server->views, link) {
+ struct ds_buffer *ds_buffer;
+ struct ds_tbm_client_buffer *tbm_buffer;
+ tbm_surface_h surface;
+
+ if (!view->mapped)
+ continue;
+
+ ds_buffer = ds_surface_get_buffer(
+ ds_xdg_surface_get_surface(view->xdg_surface));
+ assert(ds_buffer);
+
+ tbm_buffer = ds_tbm_client_buffer_from_buffer(ds_buffer);
+ assert(tbm_buffer);
+
+ surface = ds_tbm_client_buffer_get_tbm_surface(tbm_buffer);
+
+ renderer_add_texture(&output->renderer, surface, view->x, view->y);
+
+ view_send_frame_done(view);
+ }
+
+ ds_dbg("<< END UPDATE TEXTURES");
+
+ renderer_draw(&output->renderer);
+
+}
+#else
+static void
+output_swapchain_init(struct tinyds_output *output,
+ int width, int height, uint32_t format);
+
+{
+ output->allocator = ds_tbm_allocator_create();
+ assert(output->allocator);
+
+ output->swapchain = ds_swapchain_create(output->allocator,
+ width, height, format);
+ assert(output->swapchain);
+}
+
+static void
+output_draw_with_swapchain(struct tinyds_output *output)
+{
+ struct tinyds_view *view;
+ struct ds_buffer *output_buffer;
+ pixman_image_t *output_image;
+
+ output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
+ if (!output_buffer)
+ return;
+
+ output_image = pixman_image_from_buffer(output_buffer,
+ DS_BUFFER_DATA_PTR_ACCESS_WRITE);
+ if (!output_image) {
+ ds_buffer_unlock(output_buffer);
+ return;
+ }
+
+ pixman_image_fill_color(output_image, 80, 80, 80);
+
+ wl_list_for_each(view, &output->server->views, link) {
+ if (!view->mapped)
+ continue;
+ draw_view(view, output_image);
+ }
+ pixman_image_unref(output_image);
+
+ output_swap_buffer(output, output_buffer);
+}
+
+static void
+draw_view(struct tinyds_view *view, pixman_image_t *dst_image)
+{
+ struct ds_buffer *buffer;
+ pixman_image_t *src_image;
+
+ buffer = ds_surface_get_buffer(
+ ds_xdg_surface_get_surface(view->xdg_surface));
+ if (!buffer)
+ return;
+
+ src_image = pixman_image_from_buffer(buffer,
+ DS_BUFFER_DATA_PTR_ACCESS_READ);
+ pixman_image_composite32(PIXMAN_OP_OVER,
+ src_image,
+ NULL,
+ dst_image,
+ 0, 0, 0, 0,
+ view->x, view->y,
+ pixman_image_get_width(src_image),
+ pixman_image_get_height(src_image));
+ pixman_image_unref(src_image);
+
+ view_send_frame_done(view);
+}
+#endif
+
+static void
+draw_output(struct tinyds_output *output)
+{
+
+ if (!output->drawable || !output->damaged)
+ return;
+
+#ifdef USE_TDM_BUFFER_QUEUE
+ output_draw_with_renderer(output);
+#else
+ output_draw_with_swapchain(output);
+#endif
+
+ output->drawable = false;
+ output->damaged = false;
+}
+
+static void
+output_swap_buffer(struct tinyds_output *output, struct ds_buffer *buffer)
+{
+ ds_output_attach_buffer(output->ds_output, buffer);
+ ds_output_commit(output->ds_output);
+
+ if (output->front_buffer)
+ ds_buffer_unlock(output->front_buffer);
+ output->front_buffer = buffer;
+}
+
+static void
+view_send_frame_done(struct tinyds_view *view)
+{
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface),
+ &now);
+}
+
+static int
+server_dispatch_stdin(int fd, uint32_t mask, void *data)
+{
+ struct tinyds_server *server = data;
+
+ wl_display_terminate(server->display);
+
+ return 1;
+}
+
+static void
+dpms_handle_destroy(struct wl_listener *listener, void *data)
+{
+ struct tinyds_dpms *dpms;
+
+ dpms = wl_container_of(listener, dpms, destroy);
+
+ ds_inf("Dpms(%p) destroyed", dpms);
+
+ wl_list_remove(&dpms->destroy.link);
+ wl_list_remove(&dpms->set_dpms.link);
+ wl_list_remove(&dpms->get_dpms.link);
+
+ free(dpms);
+}
+
+static void
+dpms_handle_set_dpms(struct wl_listener *listener, void *data)
+{
+ struct tinyds_dpms *dpms;
+ struct ds_tizen_dpms_event *event = data;
+
+ dpms = wl_container_of(listener, dpms, set_dpms);
+
+ ds_inf("Dpms(%p) set dpms : %d", dpms, event->mode);
+
+ //To do
+ //set dpms mode to output
+ ds_tizen_dpms_send_set_result(dpms->ds_dpms, event->mode,
+ DS_TIZEN_DPMS_ERROR_NONE);
+}
+
+static void
+dpms_handle_get_dpms(struct wl_listener *listener, void *data)
+{
+ struct tinyds_dpms *dpms;
+
+ dpms = wl_container_of(listener, dpms, get_dpms);
+
+ ds_inf("Dpms(%p) get dpms", dpms);
+
+ //To do
+ //get dpms mode from output
+ ds_tizen_dpms_send_get_result(dpms->ds_dpms, DS_TIZEN_DPMS_MODE_ON,
+ DS_TIZEN_DPMS_ERROR_NONE);
+}
\ No newline at end of file