--- /dev/null
+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,
+)
--- /dev/null
+/*
+ * 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,
+ ®istry_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;
+}
'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
--- /dev/null
+#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);
+}
--- /dev/null
+#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
--- /dev/null
+#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;
+}
--- /dev/null
+#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
+++ /dev/null
-#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;
-}
+++ /dev/null
-#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
-#include "tinyds-helper.h"
+#include "tbm-server-helper.h"
+#include "pixman-helper.h"
#include <assert.h>
#include <stdbool.h>
struct tinyds_server
{
+ struct tbm_server tbm_server;
+
struct wl_display *display;
struct ds_backend *backend;
struct ds_xdg_shell *xdg_shell;
struct tinyds_output *output;
- struct tinyds_renderer renderer;
+ struct wl_event_source *stdin_source;
struct wl_list views;
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);
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);
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;
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->surface_commit);
wl_list_insert(server->views.prev, &view->link);
+
+ view->x = rand() % 1000;
+ view->y = rand() % 500;
}
static void
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,
&output->output_frame);
server->output = output;
+
+ draw_output(output);
}
static bool
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
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)
{
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)
}
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;
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);
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;
}
subdir('include')
subdir('src')
subdir('examples')
+subdir('clients')
configure_file(output: 'config.h', install: false, configuration: cdata)
BuildRequires: pkgconfig(libtdm)
BuildRequires: pkgconfig(libtbm)
+BuildRequires: pkgconfig(wayland-tbm-server)
+BuildRequires: pkgconfig(wayland-tbm-client)
%description
Wayland Compositor Library