Add tdm backend server and client as an example 38/278138/1
authorSeunghun Lee <shiin.lee@samsung.com>
Wed, 2 Mar 2022 09:09:39 +0000 (18:09 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Mon, 18 Jul 2022 05:58:09 +0000 (14:58 +0900)
Change-Id: If5305c3ee0ae11d8e0c9d2aed581e4142a2e4c2a

12 files changed:
clients/meson.build [new file with mode: 0644]
clients/simple-tbm.c [new file with mode: 0644]
examples/meson.build
examples/pixman-helper.c [new file with mode: 0644]
examples/pixman-helper.h [new file with mode: 0644]
examples/tbm-server-helper.c [new file with mode: 0644]
examples/tbm-server-helper.h [new file with mode: 0644]
examples/tinyds-helper.c [deleted file]
examples/tinyds-helper.h [deleted file]
examples/tinyds-tdm.c
meson.build
packaging/libds.spec

diff --git a/clients/meson.build b/clients/meson.build
new file mode 100644 (file)
index 0000000..360c425
--- /dev/null
@@ -0,0 +1,45 @@
+wayland_tbm_client = dependency('wayland-tbm-client', required: false)
+libtbm = dependency('libtbm', required: false)
+
+if not wayland_tbm_client.found() or not libtbm.found()
+  subdir_done()
+endif
+
+simple_tbm_files = ['simple-tbm.c']
+simple_tbm_deps = [
+  dependency('wayland-client', required: true),
+  wayland_tbm_client,
+  libtbm,
+]
+
+protocols = {
+  'xdg-shell': wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml',
+}
+
+protocols_code = {}
+protocols_client_header = {}
+foreach name, path : protocols
+  code = custom_target(
+    name.underscorify() + '_c',
+    input: path,
+    output: '@BASENAME@-protocol.c',
+    command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'],
+    )
+  simple_tbm_files += code
+
+  client_header = custom_target(
+    name.underscorify() + '_client_h',
+    input: path,
+    output: '@BASENAME@-client-protocol.h',
+    command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'],
+    build_by_default: false,
+  )
+  simple_tbm_files += client_header
+endforeach
+
+executable('ds-simple-tbm',
+  simple_tbm_files,
+  dependencies: simple_tbm_deps,
+  install_dir: libds_bindir,
+  install: true,
+)
diff --git a/clients/simple-tbm.c b/clients/simple-tbm.c
new file mode 100644 (file)
index 0000000..f572b60
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * Copyright © 2011 Benjamin Franzke
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <wayland-client.h>
+#include <wayland-tbm-client.h>
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+#include "xdg-shell-client-protocol.h"
+
+static uint64_t buffer_info_key;
+#define BUFFER_INFO_KEY (unsigned long)(&buffer_info_key)
+
+struct display {
+       struct wl_display *display;
+       struct wl_registry *registry;
+       struct wl_compositor *compositor;
+       struct xdg_wm_base *wm_base;
+       struct wl_shm *shm;
+    struct wayland_tbm_client *wl_tbm;
+       bool has_xrgb;
+};
+
+struct window {
+       struct display *display;
+       int width, height;
+       struct wl_surface *surface;
+       struct xdg_surface *xdg_surface;
+       struct xdg_toplevel *xdg_toplevel;
+       struct wl_callback *callback;
+    tbm_surface_queue_h surface_queue;
+       bool wait_for_configure;
+};
+
+struct buffer_info {
+    struct window *window;
+    struct wl_buffer *wl_buffer;
+};
+
+static int running = 1;
+
+static void
+redraw(void *data, struct wl_callback *callback, uint32_t time);
+
+static void
+handle_xdg_surface_configure(void *data, struct xdg_surface *surface,
+                            uint32_t serial)
+{
+       struct window *window = data;
+
+       xdg_surface_ack_configure(surface, serial);
+
+       if (window->wait_for_configure) {
+               redraw(window, NULL, 0);
+               window->wait_for_configure = false;
+       }
+}
+
+static const struct xdg_surface_listener xdg_surface_listener = {
+       handle_xdg_surface_configure,
+};
+
+static void
+handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
+                             int32_t width, int32_t height,
+                             struct wl_array *state)
+{
+}
+
+static void
+handle_xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
+{
+       running = 0;
+}
+
+static const struct xdg_toplevel_listener xdg_toplevel_listener = {
+       handle_xdg_toplevel_configure,
+       handle_xdg_toplevel_close,
+};
+
+static struct window *
+create_window(struct display *display, int width, int height)
+{
+       struct window *window;
+
+       window = calloc(1, sizeof *window);
+       if (!window)
+               return NULL;
+
+       window->callback = NULL;
+       window->display = display;
+       window->width = width;
+       window->height = height;
+       window->surface = wl_compositor_create_surface(display->compositor);
+
+       if (display->wm_base) {
+               window->xdg_surface =
+                       xdg_wm_base_get_xdg_surface(display->wm_base,
+                                                   window->surface);
+               assert(window->xdg_surface);
+               xdg_surface_add_listener(window->xdg_surface,
+                                        &xdg_surface_listener, window);
+
+               window->xdg_toplevel =
+                       xdg_surface_get_toplevel(window->xdg_surface);
+               assert(window->xdg_toplevel);
+               xdg_toplevel_add_listener(window->xdg_toplevel,
+                                         &xdg_toplevel_listener, window);
+
+               xdg_toplevel_set_title(window->xdg_toplevel, "simple-tbm");
+               wl_surface_commit(window->surface);
+               window->wait_for_configure = true;
+       } else {
+               assert(0);
+       }
+
+    window->surface_queue =
+        wayland_tbm_client_create_surface_queue(display->wl_tbm,
+                window->surface,
+                3,
+                width,
+                height,
+                TBM_FORMAT_XRGB8888);
+    assert(window->surface_queue);
+
+       return window;
+}
+
+static void
+destroy_window(struct window *window)
+{
+    tbm_surface_queue_destroy(window->surface_queue);
+
+       if (window->callback)
+               wl_callback_destroy(window->callback);
+
+       if (window->xdg_toplevel)
+               xdg_toplevel_destroy(window->xdg_toplevel);
+       if (window->xdg_surface)
+               xdg_surface_destroy(window->xdg_surface);
+       wl_surface_destroy(window->surface);
+       free(window);
+}
+
+static void
+paint_pixels(void *image, int padding, int width, int height, uint32_t time)
+{
+       const int halfh = padding + (height - padding * 2) / 2;
+       const int halfw = padding + (width  - padding * 2) / 2;
+       int ir, or;
+       uint32_t *pixel = image;
+       int y;
+
+       /* squared radii thresholds */
+       or = (halfw < halfh ? halfw : halfh) - 8;
+       ir = or - 32;
+       or *= or;
+       ir *= ir;
+
+       pixel += padding * width;
+       for (y = padding; y < height - padding; y++) {
+               int x;
+               int y2 = (y - halfh) * (y - halfh);
+
+               pixel += padding;
+               for (x = padding; x < width - padding; x++) {
+                       uint32_t v;
+
+                       /* squared distance from center */
+                       int r2 = (x - halfw) * (x - halfw) + y2;
+
+                       if (r2 < ir)
+                               v = (r2 / 32 + time / 64) * 0x0080401;
+                       else if (r2 < or)
+                               v = (y + time / 32) * 0x0080401;
+                       else
+                               v = (x + time / 16) * 0x0080401;
+                       v &= 0x00ffffff;
+
+                       /* cross if compositor uses X from XRGB as alpha */
+                       if (abs(x - y) > 6 && abs(x + y - height) > 6)
+                               v |= 0xff000000;
+
+                       *pixel++ = v;
+               }
+
+               pixel += padding;
+       }
+}
+
+static void
+buffer_info_free_cb(void *data)
+{
+    struct buffer_info *buffer_info = data;
+
+    if (!buffer_info)
+        return;
+
+    wayland_tbm_client_destroy_buffer(buffer_info->window->display->wl_tbm,
+            buffer_info->wl_buffer);
+    free(buffer_info);
+}
+
+static void
+buffer_handle_release(void *data, struct wl_buffer *wl_buffer)
+{
+    tbm_surface_h surface = data;
+    struct buffer_info *buffer_info;
+
+    tbm_surface_internal_get_user_data(surface, BUFFER_INFO_KEY,
+            (void **)&buffer_info);
+    if (buffer_info)
+        tbm_surface_queue_release(buffer_info->window->surface_queue, surface);
+}
+
+static const struct wl_buffer_listener buffer_listener = {
+    .release = buffer_handle_release,
+};
+
+static const struct wl_callback_listener frame_listener;
+
+static void
+redraw(void *data, struct wl_callback *callback, uint32_t time)
+{
+       struct window *window = data;
+    struct buffer_info *buffer_info = NULL;
+    tbm_surface_h surface = NULL;
+    tbm_surface_info_s surface_info;
+
+    if (!tbm_surface_queue_can_dequeue(window->surface_queue, 0))
+        return;
+
+    tbm_surface_queue_dequeue(window->surface_queue, &surface);
+    assert(surface);
+
+    tbm_surface_internal_get_user_data(surface, BUFFER_INFO_KEY,
+            (void **)&buffer_info);
+    if (!buffer_info) {
+        buffer_info = calloc(1, sizeof *buffer_info);
+        assert(buffer_info);
+
+        tbm_surface_internal_add_user_data(surface, BUFFER_INFO_KEY, buffer_info_free_cb);
+        tbm_surface_internal_set_user_data(surface, BUFFER_INFO_KEY, buffer_info);
+
+        buffer_info->wl_buffer =
+            wayland_tbm_client_create_buffer(window->display->wl_tbm, surface);
+        assert(buffer_info->wl_buffer);
+
+        wl_buffer_add_listener(buffer_info->wl_buffer, &buffer_listener,
+                surface);
+
+        buffer_info->window = window;
+    }
+
+    tbm_surface_map(surface, TBM_SURF_OPTION_WRITE, &surface_info);
+
+       paint_pixels(surface_info.planes[0].ptr, 20,
+            (surface_info.planes[0].stride/4), surface_info.height, time);
+
+    tbm_surface_unmap(surface);
+
+       wl_surface_attach(window->surface, buffer_info->wl_buffer, 0, 0);
+       wl_surface_damage(window->surface,
+                         20, 20, window->width - 40, window->height - 40);
+
+       if (callback)
+               wl_callback_destroy(callback);
+
+       window->callback = wl_surface_frame(window->surface);
+       wl_callback_add_listener(window->callback, &frame_listener, window);
+       wl_surface_commit(window->surface);
+}
+
+static const struct wl_callback_listener frame_listener = {
+       redraw
+};
+
+static void
+shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
+{
+       struct display *d = data;
+
+       if (format == WL_SHM_FORMAT_XRGB8888)
+               d->has_xrgb = true;
+}
+
+struct wl_shm_listener shm_listener = {
+       shm_format
+};
+
+static void
+xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
+{
+       xdg_wm_base_pong(shell, serial);
+}
+
+static const struct xdg_wm_base_listener xdg_wm_base_listener = {
+       xdg_wm_base_ping,
+};
+
+static void
+registry_handle_global(void *data, struct wl_registry *registry,
+                      uint32_t id, const char *interface, uint32_t version)
+{
+       struct display *d = data;
+
+       if (strcmp(interface, "wl_compositor") == 0) {
+               d->compositor =
+                       wl_registry_bind(registry,
+                                        id, &wl_compositor_interface, 1);
+       } else if (strcmp(interface, "xdg_wm_base") == 0) {
+               d->wm_base = wl_registry_bind(registry,
+                                             id, &xdg_wm_base_interface, 1);
+               xdg_wm_base_add_listener(d->wm_base, &xdg_wm_base_listener, d);
+       } else if (strcmp(interface, "wl_shm") == 0) {
+               d->shm = wl_registry_bind(registry,
+                                         id, &wl_shm_interface, 1);
+               wl_shm_add_listener(d->shm, &shm_listener, d);
+       }
+}
+
+static void
+registry_handle_global_remove(void *data, struct wl_registry *registry,
+                             uint32_t name)
+{
+}
+
+static const struct wl_registry_listener registry_listener = {
+       registry_handle_global,
+       registry_handle_global_remove
+};
+
+static struct display *
+create_display(void)
+{
+       struct display *display;
+
+       display = calloc(1, sizeof *display);
+       if (display == NULL) {
+               fprintf(stderr, "out of memory\n");
+               exit(1);
+       }
+       display->display = wl_display_connect(NULL);
+       assert(display->display);
+
+       display->has_xrgb = false;
+       display->registry = wl_display_get_registry(display->display);
+       wl_registry_add_listener(display->registry,
+                                &registry_listener, display);
+       wl_display_roundtrip(display->display);
+       if (display->shm == NULL) {
+               fprintf(stderr, "No wl_shm global\n");
+               exit(1);
+       }
+
+       wl_display_roundtrip(display->display);
+
+       /*
+        * Why do we need two roundtrips here?
+        *
+        * wl_display_get_registry() sends a request to the server, to which
+        * the server replies by emitting the wl_registry.global events.
+        * The first wl_display_roundtrip() sends wl_display.sync. The server
+        * first processes the wl_display.get_registry which includes sending
+        * the global events, and then processes the sync. Therefore when the
+        * sync (roundtrip) returns, we are guaranteed to have received and
+        * processed all the global events.
+        *
+        * While we are inside the first wl_display_roundtrip(), incoming
+        * events are dispatched, which causes registry_handle_global() to
+        * be called for each global. One of these globals is wl_shm.
+        * registry_handle_global() sends wl_registry.bind request for the
+        * wl_shm global. However, wl_registry.bind request is sent after
+        * the first wl_display.sync, so the reply to the sync comes before
+        * the initial events of the wl_shm object.
+        *
+        * The initial events that get sent as a reply to binding to wl_shm
+        * include wl_shm.format. These tell us which pixel formats are
+        * supported, and we need them before we can create buffers. They
+        * don't change at runtime, so we receive them as part of init.
+        *
+        * When the reply to the first sync comes, the server may or may not
+        * have sent the initial wl_shm events. Therefore we need the second
+        * wl_display_roundtrip() call here.
+        *
+        * The server processes the wl_registry.bind for wl_shm first, and
+        * the second wl_display.sync next. During our second call to
+        * wl_display_roundtrip() the initial wl_shm events are received and
+        * processed. Finally, when the reply to the second wl_display.sync
+        * arrives, it guarantees we have processed all wl_shm initial events.
+        *
+        * This sequence contains two examples on how wl_display_roundtrip()
+        * can be used to guarantee, that all reply events to a request
+        * have been received and processed. This is a general Wayland
+        * technique.
+        */
+
+       if (!display->has_xrgb) {
+               fprintf(stderr, "WL_SHM_FORMAT_XRGB32 not available\n");
+               exit(1);
+       }
+
+    display->wl_tbm = wayland_tbm_client_init(display->display);
+    if (!display->wl_tbm) {
+        fprintf(stderr, "failed wayland_tbm_client_init()\n");
+        exit(1);
+    }
+
+       return display;
+}
+
+static void
+destroy_display(struct display *display)
+{
+       if (display->shm)
+               wl_shm_destroy(display->shm);
+
+       if (display->wm_base)
+               xdg_wm_base_destroy(display->wm_base);
+
+       if (display->compositor)
+               wl_compositor_destroy(display->compositor);
+
+    wayland_tbm_client_deinit(display->wl_tbm);
+       wl_registry_destroy(display->registry);
+       wl_display_flush(display->display);
+       wl_display_disconnect(display->display);
+       free(display);
+}
+
+static void
+signal_int(int signum)
+{
+       running = 0;
+}
+
+int
+main(int argc, char **argv)
+{
+       struct sigaction sigint;
+       struct display *display;
+       struct window *window;
+       int ret = 0;
+
+       display = create_display();
+       window = create_window(display, 250, 250);
+       if (!window)
+               return 1;
+
+       sigint.sa_handler = signal_int;
+       sigemptyset(&sigint.sa_mask);
+       sigint.sa_flags = SA_RESETHAND;
+       sigaction(SIGINT, &sigint, NULL);
+
+       /* Initialise damage to full surface, so the padding gets painted */
+       wl_surface_damage(window->surface, 0, 0,
+                         window->width, window->height);
+
+       if (!window->wait_for_configure)
+               redraw(window, NULL, 0);
+
+       while (running && ret != -1)
+               ret = wl_display_dispatch(display->display);
+
+       fprintf(stderr, "simple-shm exiting\n");
+
+       destroy_window(window);
+       destroy_display(display);
+
+       return 0;
+}
index 66336f5..7a841e4 100644 (file)
@@ -24,16 +24,24 @@ if features.get('tdm-backend')
     'tdm-backend.c',
     dependencies: common_deps,
     install_dir: libds_bindir,
-    install : true)
+    install : true
+  )
 
+  tinyds_tdm_files = [
+    'tinyds-tdm.c',
+    'tbm-server-helper.c',
+    'pixman-helper.c',
+  ]
   executable('tinyds-tdm',
-    ['tinyds-tdm.c', 'tinyds-helper.c'],
+    tinyds_tdm_files,
     dependencies: [
       common_deps,
       dependency('pixman-1', required: true),
       dependency('libdrm', required: true),
       dependency('libtbm', required: true),
+      dependency('wayland-tbm-server', required: true),
     ],
     install_dir: libds_bindir,
-    install : true)
+    install : true
+  )
 endif
diff --git a/examples/pixman-helper.c b/examples/pixman-helper.c
new file mode 100644 (file)
index 0000000..5d42ec6
--- /dev/null
@@ -0,0 +1,89 @@
+#include "pixman-helper.h"
+
+#include <assert.h>
+#include <drm_fourcc.h>
+
+static void destroy_pixman_image(pixman_image_t *image, void *data);
+static uint32_t convert_drm_format_to_pixman(uint32_t fmt);
+static pixman_color_t *color_rgb888(pixman_color_t *tmp,
+        uint8_t r, uint8_t g, uint8_t b);
+
+pixman_image_t *
+pixman_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;
+}
+
+
+void
+pixman_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 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 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 void                                             
+destroy_pixman_image(pixman_image_t *image, void *data)
+{
+    struct ds_buffer *buffer = data;
+    ds_buffer_end_data_ptr_access(buffer);
+    ds_buffer_unlock(buffer);
+}
diff --git a/examples/pixman-helper.h b/examples/pixman-helper.h
new file mode 100644 (file)
index 0000000..aa039ff
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef EXAMPLES_PIXMAN_HELPER_H
+#define EXAMPLES_PIXMAN_HELPER_H
+
+#include <pixman.h>
+#include <libds/buffer.h>
+
+pixman_image_t *
+pixman_image_from_buffer(struct ds_buffer *buffer,
+        enum ds_buffer_data_ptr_access_flag access_flag);
+
+void
+pixman_image_fill_color(pixman_image_t *image, 
+        uint8_t r, uint8_t g, uint8_t b);
+
+#endif
diff --git a/examples/tbm-server-helper.c b/examples/tbm-server-helper.c
new file mode 100644 (file)
index 0000000..bd3a34d
--- /dev/null
@@ -0,0 +1,222 @@
+#include "tbm-server-helper.h"
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <drm_fourcc.h>
+#include <tbm_bufmgr.h>
+#include <libds/log.h>
+
+static const struct ds_buffer_resource_interface tbm_buffer_resource_iface;
+static void tbm_server_handle_display_destroy(struct wl_listener *listener,
+        void *data);
+static struct tbm_client_buffer *
+tbm_client_buffer_create(struct wl_resource *resource);
+
+bool
+tbm_server_init_display(struct tbm_server *tbm, struct wl_display *display)
+{
+    tbm_bufmgr bufmgr;
+
+    tbm->wl_tbm = wayland_tbm_server_init(display, NULL, -1, 0);
+    if (!tbm->wl_tbm) {
+        return false;
+    }
+
+    bufmgr = wayland_tbm_server_get_bufmgr(tbm->wl_tbm);
+    if (!bufmgr) {
+        wayland_tbm_server_deinit(tbm->wl_tbm);
+        return false;
+    }
+
+    if (!tbm_bufmgr_bind_native_display(bufmgr, (void *)display)) {
+        wayland_tbm_server_deinit(tbm->wl_tbm);
+        return false;
+    }
+
+    ds_buffer_register_resource_interface(&tbm_buffer_resource_iface);
+
+    tbm->display_destroy.notify = tbm_server_handle_display_destroy;
+    wl_display_add_destroy_listener(display, &tbm->display_destroy);
+
+    return true;
+}
+
+static void
+tbm_server_handle_display_destroy(struct wl_listener *listener, void *data)
+{
+    struct tbm_server *tbm;
+
+    tbm = wl_container_of(listener, tbm, display_destroy);
+    wayland_tbm_server_deinit(tbm->wl_tbm);
+}
+
+static bool
+tbm_buffer_resource_iface_is_instance(struct wl_resource *resource)
+{
+    return !!wayland_tbm_server_get_surface(NULL, resource);
+}
+
+static void
+tbm_client_buffer_handle_resource_destroy(struct wl_listener *listener,
+        void *data)
+{
+    struct tbm_client_buffer *buffer;
+
+    buffer = wl_container_of(listener, buffer, resource_destroy);
+
+    buffer->resource = NULL;
+    buffer->surface = NULL;
+    wl_list_remove(&buffer->resource_destroy.link);
+    wl_list_init(&buffer->resource_destroy.link);
+
+    ds_buffer_drop(&buffer->base);
+}
+
+static struct tbm_client_buffer *
+tbm_client_buffer_get_or_create(struct wl_resource *resource)
+{
+    struct tbm_client_buffer *buffer;
+    struct wl_listener *resource_destroy_listener;
+
+    resource_destroy_listener = wl_resource_get_destroy_listener(resource,
+            tbm_client_buffer_handle_resource_destroy);;
+    if (resource_destroy_listener) {
+        buffer = wl_container_of(resource_destroy_listener,
+                buffer, resource_destroy);
+        return buffer;
+    }
+
+    return tbm_client_buffer_create(resource);
+}
+
+static struct ds_buffer *
+tbm_buffer_resource_iface_from_resource(struct wl_resource *resource)
+{
+    struct tbm_client_buffer *buffer;
+
+    buffer = tbm_client_buffer_get_or_create(resource);
+    assert(buffer);
+
+    return &buffer->base;
+}
+
+static const struct ds_buffer_resource_interface tbm_buffer_resource_iface = {
+    .name = "tbm",
+    .is_instance = tbm_buffer_resource_iface_is_instance,
+    .from_resource = tbm_buffer_resource_iface_from_resource,
+};
+
+static const struct ds_buffer_interface tbm_client_buffer_iface;
+
+static struct tbm_client_buffer *
+tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer)
+{
+    assert(ds_buffer->iface == &tbm_client_buffer_iface);
+    return (struct tbm_client_buffer *)ds_buffer;
+}
+
+static void
+tbm_client_buffer_destroy(struct ds_buffer *ds_buffer)
+{
+    struct tbm_client_buffer *buffer;
+
+    buffer = tbm_client_buffer_from_buffer(ds_buffer);
+
+    ds_inf("Destroy TBM client buffer(%p)", buffer);
+
+    wl_list_remove(&buffer->resource_destroy.link);
+    wl_list_remove(&buffer->buffer_release.link);
+    free(buffer);
+}
+
+static bool
+tbm_client_buffer_begin_data_ptr_access(struct ds_buffer *ds_buffer,
+        enum ds_buffer_data_ptr_access_flag flags, void **data,
+        uint32_t *format, size_t *stride)
+{
+    struct tbm_client_buffer *buffer;
+    tbm_surface_info_s info;
+    tbm_bo_access_option op = TBM_OPTION_NONE;
+    int err;
+
+    buffer = tbm_client_buffer_from_buffer(ds_buffer);
+
+    if (flags & DS_BUFFER_DATA_PTR_ACCESS_READ)
+        op |= TBM_OPTION_READ;
+
+    if (flags & DS_BUFFER_DATA_PTR_ACCESS_WRITE)
+        op |= TBM_OPTION_WRITE;
+
+    err = tbm_surface_map(buffer->surface, op, &info);
+    if (err != TBM_SURFACE_ERROR_NONE) {
+        ds_err("Failed tbm_surface_map()");
+        return false;
+    }
+
+    *format = DRM_FORMAT_XRGB8888; // FIXME
+    *stride = info.planes[0].stride;
+    *data = info.planes[0].ptr;
+
+    return true;
+}
+
+static void
+tbm_client_buffer_end_data_ptr_access(struct ds_buffer *ds_buffer)
+{
+    struct tbm_client_buffer *buffer;
+
+    buffer = tbm_client_buffer_from_buffer(ds_buffer);
+
+    tbm_surface_unmap(buffer->surface);
+}
+
+static const struct ds_buffer_interface tbm_client_buffer_iface = {
+    .destroy = tbm_client_buffer_destroy,
+    .begin_data_ptr_access = tbm_client_buffer_begin_data_ptr_access,
+    .end_data_ptr_access = tbm_client_buffer_end_data_ptr_access,
+};
+
+static void
+tbm_client_buffer_handle_release(struct wl_listener *listener, void *data)
+{
+    struct tbm_client_buffer *buffer;
+
+    buffer = wl_container_of(listener, buffer, buffer_release);
+    if (buffer->resource)
+        wl_buffer_send_release(buffer->resource);
+}
+
+static struct tbm_client_buffer *
+tbm_client_buffer_create(struct wl_resource *resource)
+{
+    struct tbm_client_buffer *buffer;
+    tbm_surface_h surface;
+    int32_t width, height;
+
+    surface = wayland_tbm_server_get_surface(NULL, resource);
+    assert(surface);
+
+    width = tbm_surface_get_width(surface);
+    height = tbm_surface_get_height(surface);
+
+    buffer = calloc(1, sizeof *buffer);
+    assert(buffer);
+
+    ds_buffer_init(&buffer->base, &tbm_client_buffer_iface, width, height);
+
+    buffer->resource = resource;
+    buffer->surface = surface;
+    buffer->format = tbm_surface_get_format(surface);
+
+    buffer->buffer_release.notify = tbm_client_buffer_handle_release;
+    ds_buffer_add_release_listener(&buffer->base, &buffer->buffer_release);
+
+    buffer->resource_destroy.notify =
+        tbm_client_buffer_handle_resource_destroy;
+    wl_resource_add_destroy_listener(resource, &buffer->resource_destroy);
+
+    ds_inf("TBM client buffer(%p) created", buffer);
+
+    return buffer;
+}
diff --git a/examples/tbm-server-helper.h b/examples/tbm-server-helper.h
new file mode 100644 (file)
index 0000000..a82ad5b
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef EXAMPLES_TBM_SERVER_H
+#define EXAMPLES_TBM_SERVER_H 
+
+#include <stdbool.h>
+#include <wayland-server.h>
+#include <wayland-tbm-server.h>
+#include <tbm_surface.h>
+#include <libds/interfaces/buffer.h>
+
+struct tbm_server
+{
+    struct wayland_tbm_server *wl_tbm;
+
+    struct wl_listener display_destroy;
+};
+
+struct tbm_client_buffer
+{
+    struct ds_buffer base;
+
+    tbm_surface_h surface;
+    struct wl_resource *resource;
+
+    struct wl_listener buffer_release;
+    struct wl_listener resource_destroy;
+
+    uint32_t format;
+    size_t stride;
+};
+
+bool
+tbm_server_init_display(struct tbm_server *tbm_server,
+        struct wl_display *display);
+
+#endif
diff --git a/examples/tinyds-helper.c b/examples/tinyds-helper.c
deleted file mode 100644 (file)
index ef077b3..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#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
deleted file mode 100644 (file)
index 44415d6..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#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
index 23ff48e..4207fb1 100644 (file)
@@ -1,4 +1,5 @@
-#include "tinyds-helper.h"
+#include "tbm-server-helper.h"
+#include "pixman-helper.h"
 
 #include <assert.h>
 #include <stdbool.h>
@@ -43,6 +44,8 @@ struct tinyds_output
 
 struct tinyds_server
 {
+    struct tbm_server tbm_server;
+
     struct wl_display *display;
 
     struct ds_backend *backend;
@@ -50,7 +53,7 @@ struct tinyds_server
     struct ds_xdg_shell *xdg_shell;
 
     struct tinyds_output *output;
-    struct tinyds_renderer renderer;
+    struct wl_event_source *stdin_source;
 
     struct wl_list views;
 
@@ -74,12 +77,12 @@ struct tinyds_view
     bool mapped;
 };
 
-struct tinyds_server _tinyds;
+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(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);
@@ -87,18 +90,22 @@ static void draw_view(struct tinyds_view *view, pixman_image_t *dst_image);
 int
 main(void)
 {
-    struct tinyds_server *server = &_tinyds;
+    struct tinyds_server *server = &tinyds;
     struct wl_display *display;
+    struct wl_event_loop *loop;
     const char *socket;
+    bool res;
 
-    ds_log_init(DS_DBG, NULL);
+    ds_log_init(DS_INF, NULL);
 
     display = wl_display_create();
     assert(display);
 
-    assert(init_server(server, display) == true);
+    res = init_server(server, display);
+    assert(res);
 
-    assert(tinyds_renderer_init_display(&server->renderer, display));
+    res = tbm_server_init_display(&server->tbm_server, display);
+    assert(res);
 
     socket = wl_display_add_socket_auto(display);
     assert(socket);
@@ -109,6 +116,13 @@ main(void)
 
     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;
@@ -175,6 +189,8 @@ server_new_xdg_surface(struct wl_listener *listener, void *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;
 
@@ -196,6 +212,9 @@ server_new_xdg_surface(struct wl_listener *listener, void *data)
             &view->surface_commit);
 
     wl_list_insert(server->views.prev, &view->link);
+
+    view->x = rand() % 1000;
+    view->y = rand() % 500;
 }
 
 static void
@@ -217,8 +236,24 @@ backend_handle_new_output(struct wl_listener *listener, void *data)
     if (!output)
         return;
 
+    output->allocator = ds_tbm_allocator_create();
+    if (!output->allocator) {
+        free(output);
+        return;
+    }
+
+    output->swapchain = ds_swapchain_create(output->allocator,
+            OUTPUT_WIDTH, OUTPUT_HEIGHT, DRM_FORMAT_XRGB8888); // FIXME output mode
+    if (!output->swapchain) {
+        ds_allocator_destroy(output->allocator);
+        free(output);
+        return;
+    }
+
     output->server = server;
     output->ds_output = ds_output;
+    output->drawable = true;
+    output->damaged = true;
 
     output->output_destroy.notify = output_handle_destroy;
     ds_output_add_destroy_listener(ds_output,
@@ -229,6 +264,8 @@ backend_handle_new_output(struct wl_listener *listener, void *data)
             &output->output_frame);
 
     server->output = output;
+
+    draw_output(output);
 }
 
 static bool
@@ -299,12 +336,8 @@ 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);
+    output->drawable = true;
+    draw_output(output);
 }
 
 static void
@@ -314,12 +347,6 @@ draw_server_with_damage(struct tinyds_server *server)
     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)
 {
@@ -334,14 +361,14 @@ draw_output(struct tinyds_output *output)
     if (!output_buffer)
         return;
 
-    output_image = image_from_buffer(output_buffer,
+    output_image = pixman_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);
+    pixman_image_fill_color(output_image, 80, 80, 80);
 
     wl_list_for_each(view, &output->server->views, link) {
         if (!view->mapped)
@@ -362,6 +389,15 @@ draw_output(struct tinyds_output *output)
 }
 
 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
 draw_view(struct tinyds_view *view, pixman_image_t *dst_image)
 {
     struct ds_buffer *buffer;
@@ -372,13 +408,14 @@ draw_view(struct tinyds_view *view, pixman_image_t *dst_image)
     if (!buffer)
         return;
 
-    src_image = image_from_buffer(buffer,
+    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, 0, 0,
+            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);
@@ -386,90 +423,12 @@ draw_view(struct tinyds_view *view, pixman_image_t *dst_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)
+static int
+server_dispatch_stdin(int fd, uint32_t mask, void *data)
 {
-    tmp->alpha = 65535;
-    tmp->red = (r << 8) + r;
-    tmp->green = (g << 8) + g;
-    tmp->blue = (b << 8) +b;
+    struct tinyds_server *server = data;
 
-    return tmp;
-}
+    wl_display_terminate(server->display);
 
-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);
+    return 1;
 }
index 2bf1398..445fd6a 100644 (file)
@@ -33,6 +33,7 @@ features = {
 subdir('include')
 subdir('src')
 subdir('examples')
+subdir('clients')
 
 configure_file(output: 'config.h', install: false, configuration: cdata)
 
index 69d58f6..3b479e2 100644 (file)
@@ -16,6 +16,8 @@ BuildRequires:  pkgconfig(libdrm)
 
 BuildRequires:  pkgconfig(libtdm)
 BuildRequires:  pkgconfig(libtbm)
+BuildRequires:  pkgconfig(wayland-tbm-server)
+BuildRequires:  pkgconfig(wayland-tbm-client)
 
 %description
 Wayland Compositor Library