Add tinyds on tdm (wip) 34/278134/1
authorSeunghun Lee <shiin.lee@samsung.com>
Thu, 24 Feb 2022 08:36:44 +0000 (17:36 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Mon, 18 Jul 2022 05:58:07 +0000 (14:58 +0900)
Change-Id: I058c8c05db6e6460caf50ad6eee59af2e9d13ff4

examples/meson.build
examples/tdm-backend.c
examples/tinyds-helper.c [new file with mode: 0644]
examples/tinyds-helper.h [new file with mode: 0644]
examples/tinyds-tdm.c [new file with mode: 0644]

index 530cbdd..54f1ba7 100644 (file)
@@ -24,3 +24,14 @@ executable('tinyds',
            ],
            install_dir: libds_bindir,
            install : true)
+
+executable('tinyds-tdm',
+           ['tinyds-tdm.c', 'tinyds-helper.c'],
+           dependencies: [ 
+             common_deps,
+             dependency('pixman-1', required: true),
+             dependency('libdrm', required: true),
+             dependency('libtbm', required: true),
+           ],
+           install_dir: libds_bindir,
+           install : true)
index 15f5711..ee39f06 100644 (file)
@@ -108,7 +108,6 @@ init_server(struct server *server, struct wl_display *display)
     server->backend = ds_tdm_backend_create(display);
     assert(server->backend);
 
-
     server->new_output.notify = backend_handle_new_output;
     ds_backend_add_new_output_listener(server->backend,
             &server->new_output);
diff --git a/examples/tinyds-helper.c b/examples/tinyds-helper.c
new file mode 100644 (file)
index 0000000..ef077b3
--- /dev/null
@@ -0,0 +1,18 @@
+#include "tinyds-helper.h"
+
+#include <libds/log.h>
+#include <libds/buffer.h>
+
+bool
+tinyds_renderer_init_display(struct tinyds_renderer *renderer,
+        struct wl_display *display)
+{
+    if (wl_display_init_shm(display)) {
+        ds_err("Could not initialize shm");
+        return false;
+    }
+
+    renderer->dummy = 1;
+
+    return true;
+}
diff --git a/examples/tinyds-helper.h b/examples/tinyds-helper.h
new file mode 100644 (file)
index 0000000..44415d6
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef TINYDS_HELPER_H
+#define TINYDS_HELPER_H
+
+#include <stdbool.h>
+#include <wayland-server.h>
+
+struct tinyds_renderer {
+    int dummy;
+};
+
+bool
+tinyds_renderer_init_display(struct tinyds_renderer *renderer,
+        struct wl_display *display);
+
+#endif
diff --git a/examples/tinyds-tdm.c b/examples/tinyds-tdm.c
new file mode 100644 (file)
index 0000000..23ff48e
--- /dev/null
@@ -0,0 +1,475 @@
+#include "tinyds-helper.h"
+
+#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/allocator/tbm.h>
+#include <libds/backend/tdm.h>
+#include <libds/swapchain.h>
+#include <libds/compositor.h>
+#include <libds/xdg_shell.h>
+
+#define TINYDS_UNUSED   __attribute__((unused))
+
+#define OUTPUT_WIDTH   1280
+#define OUTPUT_HEIGHT  720
+
+struct tinyds_output
+{
+    struct tinyds_server *server;
+    struct ds_output *ds_output;
+    struct ds_allocator *allocator;
+    struct ds_swapchain *swapchain;
+    struct ds_buffer *front_buffer;
+
+    struct wl_listener output_destroy;
+    struct wl_listener output_frame;
+
+    int width, height;
+
+    bool drawable;
+    bool damaged;
+};
+
+struct tinyds_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_renderer renderer;
+
+    struct wl_list views;
+
+    struct wl_listener new_output;
+    struct wl_listener new_xdg_surface;
+};
+
+struct tinyds_view
+{
+    struct tinyds_server *server;
+
+    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 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(struct tinyds_server *server);
+static void draw_server_with_damage(struct tinyds_server *server);
+static void draw_output(struct tinyds_output *output);
+static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image);
+
+int
+main(void)
+{
+    struct tinyds_server *server = &_tinyds;
+    struct wl_display *display;
+    const char *socket;
+
+    ds_log_init(DS_DBG, NULL);
+
+    display = wl_display_create();
+    assert(display);
+
+    assert(init_server(server, display) == true);
+
+    assert(tinyds_renderer_init_display(&server->renderer, display));
+
+    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);
+
+    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);
+
+    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);
+    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);
+}
+
+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;
+
+    server = wl_container_of(listener, server, new_output);
+    ds_output = data;
+
+    ds_inf("New output(%p)", ds_output);
+
+    if (server->output)
+        return;
+
+    output = calloc(1, sizeof *output);
+    if (!output)
+        return;
+
+    output->server = server;
+    output->ds_output = ds_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;
+}
+
+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->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);
+
+    if (output->swapchain)
+        ds_swapchain_destroy(output->swapchain);
+
+    if (output->allocator)
+        ds_allocator_destroy(output->allocator);
+
+    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);
+
+}
+
+static void
+draw_server(struct tinyds_server *server)
+{
+    draw_output(server->output);
+}
+
+static void
+draw_server_with_damage(struct tinyds_server *server)
+{
+    server->output->damaged = true;
+    draw_output(server->output);
+}
+
+static void image_fill_color(pixman_image_t *image,
+        uint8_t r, uint8_t g, uint8_t b);
+static pixman_image_t *image_from_buffer(struct ds_buffer *buffer,
+        enum ds_buffer_data_ptr_access_flag access_flag);
+static void view_send_frame_done(struct tinyds_view *view);
+
+static void
+draw_output(struct tinyds_output *output)
+{
+    struct ds_buffer *output_buffer;
+    pixman_image_t *output_image;
+    struct tinyds_view *view;
+
+    if (!output->drawable || !output->damaged)
+        return;
+
+    output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
+    if (!output_buffer)
+        return;
+
+    output_image = image_from_buffer(output_buffer,
+            DS_BUFFER_DATA_PTR_ACCESS_WRITE);
+    if (!output_image) {
+        ds_buffer_unlock(output_buffer);
+        return;
+    }
+
+    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);
+
+    ds_output_attach_buffer(output->ds_output, output_buffer);
+    ds_output_commit(output->ds_output);
+
+    if (output->front_buffer)
+        ds_buffer_unlock(output->front_buffer);
+    output->front_buffer = output_buffer;
+
+    output->drawable = false;
+    output->damaged = false;
+}
+
+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 = 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, 0, 0,
+            pixman_image_get_width(src_image),
+            pixman_image_get_height(src_image));
+    pixman_image_unref(src_image);
+
+    view_send_frame_done(view);
+}
+
+static pixman_color_t *
+color_rgb888(pixman_color_t *tmp, uint8_t r, uint8_t g, uint8_t b)
+{
+    tmp->alpha = 65535;
+    tmp->red = (r << 8) + r;
+    tmp->green = (g << 8) + g;
+    tmp->blue = (b << 8) +b;
+
+    return tmp;
+}
+
+static void
+image_fill_color(pixman_image_t *image, uint8_t r, uint8_t g, uint8_t b)
+{
+    pixman_image_t *color_image;
+    pixman_color_t color;
+
+    color_rgb888(&color, r, g, b);
+    color_image = pixman_image_create_solid_fill(&color);
+    pixman_image_composite32(PIXMAN_OP_SRC,
+            color_image,
+            NULL,
+            image,
+            0, 0, 0, 0, 0, 0,
+            pixman_image_get_width(image),
+            pixman_image_get_height(image));
+    pixman_image_unref(color_image);
+}
+
+static void                                             
+destroy_pixman_image(pixman_image_t *image TINYDS_UNUSED, void *data)
+{
+    struct ds_buffer *buffer = data;
+    ds_buffer_end_data_ptr_access(buffer);
+    ds_buffer_unlock(buffer);
+}
+
+static uint32_t
+convert_drm_format_to_pixman(uint32_t fmt)
+{
+    switch (fmt) {
+        case DRM_FORMAT_XRGB8888:
+            return PIXMAN_x8r8g8b8;
+        case DRM_FORMAT_ARGB8888:
+            return PIXMAN_a8r8g8b8;
+        default:
+            assert(0 && "not reached");
+    }
+}
+
+static pixman_image_t *
+image_from_buffer(struct ds_buffer *buffer,
+        enum ds_buffer_data_ptr_access_flag access_flag)
+{
+    pixman_image_t *image;
+    void *data;
+    uint32_t format;
+    size_t stride;
+    int width, height;
+
+    ds_buffer_get_size(buffer, &width, &height);
+
+    if (!ds_buffer_begin_data_ptr_access(buffer,
+                access_flag, &data, &format, &stride))
+        return NULL;
+
+    format = convert_drm_format_to_pixman(format);
+    image = pixman_image_create_bits(format, width, height, data, stride);
+    if (!image) {
+        ds_buffer_end_data_ptr_access(buffer);
+        return NULL;
+    }
+
+    pixman_image_set_destroy_function(image,
+            destroy_pixman_image, ds_buffer_lock(buffer));
+
+    return image;
+}
+
+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);
+}