example: Add tinyds-tdm-hwc 18/278218/1
authorChangyeon Lee <cyeon.lee@samsung.com>
Thu, 16 Jun 2022 02:53:26 +0000 (11:53 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Mon, 18 Jul 2022 05:58:57 +0000 (14:58 +0900)
example ds_tdm_output_hwc

Change-Id: I5a6f9f0a6055eaf52f0d6456896d5e65c4a746ee

examples/meson.build
examples/tinyds-tdm-hwc.c [new file with mode: 0644]
packaging/libds-tizen.spec

index d9233fb..b7500a1 100644 (file)
@@ -60,3 +60,20 @@ executable('tinyds-tdm-dpms',
   install_dir: libds_tizen_bindir,
   install : true
 )
+
+tinyds_tdm_hwc_files = [
+  'tinyds-tdm-hwc.c',
+  'pixman-helper.c',
+  'pixman-tbm-helper.c',
+  'tinyds-tdm-renderer.c',
+]
+executable('tinyds-tdm-hwc',
+  tinyds_tdm_hwc_files,
+  dependencies: [
+    common_deps,
+    dependency('pixman-1', required: true),
+    dependency('threads', required: true),
+  ],
+  install_dir: libds_tizen_bindir,
+  install : true
+)
diff --git a/examples/tinyds-tdm-hwc.c b/examples/tinyds-tdm-hwc.c
new file mode 100644 (file)
index 0000000..46925f1
--- /dev/null
@@ -0,0 +1,768 @@
+#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/backend/tdm_output_hwc.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;
+
+    struct wl_event_source *idle_commit;
+    bool commitable;
+    bool damaged;
+
+    struct ds_tdm_output_hwc *hwc;
+};
+
+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 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
+
+    struct ds_tdm_output_hwc_window *hwc_window;
+
+    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);
+static void output_hwc_init(struct tinyds_output *output);
+static void output_schedule_commit(struct tinyds_output *output);
+static void output_commit(struct tinyds_output *output);
+#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
+
+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;
+
+    view = wl_container_of(listener, view, xdg_surface_destroy);
+
+    draw_server_with_damage(view->server);
+
+    ds_tdm_output_hwc_window_destroy(view->hwc_window);
+
+    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);
+}
+
+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);
+
+    view->hwc_window = ds_tdm_output_hwc_window_create(server->output->hwc);
+
+    wl_list_insert(server->views.prev, &view->link);
+}
+
+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->damaged = true;
+    output->commitable = 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_hwc_init(output);
+
+    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;
+
+    output_schedule_commit(output);
+}
+
+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);
+
+    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_commit(struct tinyds_output *output)
+{
+    uint32_t num_changed = 0;
+    uint32_t num_windows = 0, current_num_windows = 0;
+    struct ds_tdm_output_hwc_window **composited_hwc_windows = NULL;
+    struct ds_tdm_output_hwc_window **changed_hwc_windows = NULL;
+    enum ds_tdm_output_hwc_window_composition composition;
+    struct tinyds_view *view;
+    int i;
+    bool need_target = false;
+
+    if (!output->commitable || !output->damaged)
+        return;
+
+    wl_list_for_each_reverse(view, &output->server->views, link) {
+        if (!view->hwc_window)
+            continue;
+
+        if (view->mapped)
+            num_windows++;
+    }
+
+    if (num_windows) {
+        composited_hwc_windows = calloc(num_windows, sizeof *composited_hwc_windows);
+        if (!composited_hwc_windows)
+            return;
+    }
+
+    wl_list_for_each_reverse(view, &output->server->views, link) {
+        struct ds_buffer *ds_buffer;
+        struct ds_tdm_box src_box;
+        int w = 0, h = 0;
+
+        if (!view->hwc_window)
+            continue;
+
+        ds_buffer = ds_surface_get_buffer(
+                ds_xdg_surface_get_surface(view->xdg_surface));
+        if (!ds_buffer)
+            continue;
+
+        ds_tdm_output_hwc_window_set_buffer(view->hwc_window, ds_buffer);
+
+        if (ds_buffer)
+            ds_buffer_get_size(ds_buffer, &w, &h);
+
+        src_box.x = 0;
+        src_box.y = 0;
+        src_box.width = w;
+        src_box.height = h;
+
+        ds_tdm_output_hwc_window_set_src_box(view->hwc_window, &src_box);
+        ds_tdm_output_hwc_window_set_position(view->hwc_window, view->x, view->y);
+        ds_tdm_output_hwc_window_set_dest_size(view->hwc_window, w, h);
+        ds_tdm_output_hwc_window_set_transform(view->hwc_window, WL_OUTPUT_TRANSFORM_NORMAL);
+
+        if (view->mapped) {
+            ds_tdm_output_hwc_window_set_composition(view->hwc_window,
+                    DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE);
+
+            composited_hwc_windows[current_num_windows] = view->hwc_window;
+            current_num_windows++;
+        } else {
+            ds_tdm_output_hwc_window_set_composition(view->hwc_window,
+                    DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_NONE);
+        }
+    }
+
+    if (!ds_tdm_output_hwc_validate(output->hwc, composited_hwc_windows,
+            num_windows, &num_changed)) {
+        free(composited_hwc_windows);
+        ds_err("Could not hwc validate");
+        return;
+    }
+
+    if (composited_hwc_windows)
+        free(composited_hwc_windows);
+
+    if (num_changed > 0) {
+        changed_hwc_windows = calloc(num_windows, sizeof *changed_hwc_windows);
+        if (!changed_hwc_windows)
+            return;
+
+        if (!ds_tdm_output_hwc_get_changed_composition(output->hwc, &num_changed,
+                changed_hwc_windows)) {
+            ds_err("Could not get chaged composition");
+            return;
+        }
+
+        for (i = 0; i < num_changed; i++) {
+            composition = ds_tdm_output_hwc_window_get_composition(changed_hwc_windows[i]);
+            if (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CLIENT) {
+                need_target = true;
+                break;
+            }
+        }
+    }
+
+    if (changed_hwc_windows)
+        free(changed_hwc_windows);
+
+    if (!ds_tdm_output_hwc_accept_validation(output->hwc)) {
+        ds_err("Could not hwc accept validateion");
+        return;
+    }
+
+    if (need_target)
+        draw_output(output);
+
+#ifdef USE_TDM_BUFFER_QUEUE
+    struct ds_buffer *buffer;
+
+    buffer = ds_tdm_buffer_queue_acquire(output->buffer_queue);
+    if (buffer)
+        output_swap_buffer(output, buffer);
+#endif
+
+    ds_output_commit(output->ds_output);
+
+    output->commitable = false;
+    output->damaged = false;
+
+    wl_list_for_each(view, &output->server->views, link) {
+        enum ds_tdm_output_hwc_window_composition composition;
+
+        if (!view->mapped)
+            continue;
+
+        composition = ds_tdm_output_hwc_window_get_composition(view->hwc_window);
+        if ((composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE) ||
+            (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_VIDEO) ||
+            (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CURSOR))
+            view_send_frame_done(view);
+    }
+
+    ds_inf("output:%p commit", 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);
+
+    ds_inf("output:%p handle frame", output);
+
+    output->commitable = true;
+
+    output_commit(output);
+}
+
+static void
+draw_server_with_damage(struct tinyds_server *server)
+{
+    server->output->damaged = true;
+    output_schedule_commit(server->output);
+}
+
+static void
+output_hwc_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->hwc = ds_tdm_output_get_hwc(tdm_output);
+    assert(output->hwc);
+
+    ds_tdm_output_hwc_set_enabled(output->hwc, true);
+}
+
+#ifdef USE_TDM_BUFFER_QUEUE
+static void
+output_handle_buffer_queue_acquirable(struct wl_listener *listener,
+        void *data TINYDS_UNUSED)
+{
+    struct tinyds_output *output;
+
+    output = wl_container_of(listener, output, buffer_queue_acquirable);
+
+    draw_server_with_damage(output->server);
+}
+
+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, 0, 0, 0);
+}
+
+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;
+        enum ds_tdm_output_hwc_window_composition composition;
+
+        if (!view->mapped)
+            continue;
+
+        composition = ds_tdm_output_hwc_window_get_composition(view->hwc_window);
+        if ((composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE) ||
+            (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_VIDEO) ||
+            (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CURSOR))
+            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;
+    enum ds_tdm_output_hwc_window_composition composition;
+
+    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, 0, 0, 0);
+
+    wl_list_for_each(view, &output->server->views, link) {
+        if (!view->mapped)
+            continue;
+
+        composition = ds_tdm_output_hwc_window_get_composition(view->hwc_window);
+        if ((composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE) ||
+            (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_VIDEO) ||
+            (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CURSOR))
+            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)
+{
+#ifdef USE_TDM_BUFFER_QUEUE
+    output_draw_with_renderer(output);
+#else
+    output_draw_with_swapchain(output);
+#endif
+
+    ds_inf("output:%p draw", output);
+}
+
+static void
+output_swap_buffer(struct tinyds_output *output, struct ds_buffer *buffer)
+{
+    ds_output_attach_buffer(output->ds_output, buffer);
+
+    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 void
+output_schedule_commit_handle_idle_timer(void *data)
+{
+    struct tinyds_output *output = data;
+    output->idle_commit = NULL;
+
+    output_commit(output);
+}
+
+static void
+output_schedule_commit(struct tinyds_output *output)
+{
+    if (output->idle_commit)
+        return;
+
+    output->damaged = true;
+
+    struct wl_event_loop *ev = wl_display_get_event_loop(output->server->display);
+    output->idle_commit =
+        wl_event_loop_add_idle(ev, output_schedule_commit_handle_idle_timer, output);
+}
+
+static int
+server_dispatch_stdin(int fd, uint32_t mask, void *data)
+{
+    struct tinyds_server *server = data;
+
+    wl_display_terminate(server->display);
+
+    return 1;
+}
index c2e0180..000f5a9 100644 (file)
@@ -99,6 +99,7 @@ ninja -C builddir install
 %{_libdir}/libds-tizen.so
 %{_bindir}/tdm-backend
 %{_bindir}/tinyds-tdm
+%{_bindir}/tinyds-tdm-hwc
 %{_bindir}/ds-simple-tbm
 %{_bindir}/tinyds-tdm-dpms
 %{_bindir}/ds-simple-dpms