tinyds_tdm_files = [
'tinyds-tdm.c',
+ 'tinyds-tdm-renderer.c',
'tbm-server-helper.c',
'pixman-helper.c',
+ 'pixman-tbm-helper.c',
]
executable('tinyds-tdm',
tinyds_tdm_files,
dependency('libdrm', required: true),
dependency('libtbm', required: true),
dependency('wayland-tbm-server', required: true),
+ dependency('threads', required: true),
],
install_dir: libds_bindir,
install : true
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,
return image;
}
-
void
pixman_image_fill_color(pixman_image_t *image, uint8_t r, uint8_t g, uint8_t b)
{
pixman_image_unref(color_image);
}
-static pixman_color_t *
+pixman_color_t *
color_rgb888(pixman_color_t *tmp, uint8_t r, uint8_t g, uint8_t b)
{
tmp->alpha = 65535;
pixman_image_fill_color(pixman_image_t *image,
uint8_t r, uint8_t g, uint8_t b);
+pixman_color_t *
+color_rgb888(pixman_color_t *tmp, uint8_t r, uint8_t g, uint8_t b);
+
#endif
--- /dev/null
+#include <assert.h>
+
+#include "pixman-tbm-helper.h"
+
+static uint32_t convert_tbm_format_to_pixman(uint32_t fmt);
+static void destroy_tbm_pixman_image(pixman_image_t *image, void *data);
+
+pixman_image_t *
+pixman_image_from_tbm_surface(tbm_surface_h surface,
+ enum ds_buffer_data_ptr_access_flag access_flag)
+{
+ pixman_image_t *image;
+ tbm_surface_info_s info;
+ uint32_t format;
+ int tbm_access_flag = 0;
+ int width, height;
+ int ret;
+
+ width = tbm_surface_get_width(surface);
+ height = tbm_surface_get_height(surface);
+
+ if (access_flag & DS_BUFFER_DATA_PTR_ACCESS_READ)
+ tbm_access_flag |= TBM_OPTION_READ;
+ if (access_flag & DS_BUFFER_DATA_PTR_ACCESS_WRITE)
+ tbm_access_flag |= TBM_OPTION_WRITE;
+
+ ret = tbm_surface_map(surface, tbm_access_flag, &info);
+ assert(ret == TBM_SURFACE_ERROR_NONE);
+
+ format = convert_tbm_format_to_pixman(info.format);
+ image = pixman_image_create_bits(format, width, height,
+ (uint32_t *)info.planes[0].ptr,
+ info.planes[0].stride);
+ assert(image);
+
+ tbm_surface_internal_ref(surface);
+
+ pixman_image_set_destroy_function(image,
+ destroy_tbm_pixman_image, surface);
+
+ return image;
+}
+
+static void
+destroy_tbm_pixman_image(pixman_image_t *image, void *data)
+{
+ tbm_surface_h surface = data;
+
+ tbm_surface_unmap(surface);
+ tbm_surface_internal_unref(surface);
+}
+
+static uint32_t
+convert_tbm_format_to_pixman(uint32_t fmt)
+{
+ switch (fmt) {
+ case TBM_FORMAT_XRGB8888:
+ return PIXMAN_x8r8g8b8;
+ case TBM_FORMAT_ARGB8888:
+ return PIXMAN_a8r8g8b8;
+ default:
+ assert(0 && "not reached");
+ }
+}
--- /dev/null
+#ifndef EXAMPLES_PIXMAN_TBM_HELPER_H
+#define EXAMPLES_PIXMAN_TBM_HELPER_H
+
+#include <pixman.h>
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+#include <libds/buffer.h>
+
+pixman_image_t *
+pixman_image_from_tbm_surface(tbm_surface_h surface,
+ enum ds_buffer_data_ptr_access_flag access_flag);
+
+#endif
#include <libds/log.h>
static const struct ds_buffer_resource_interface tbm_buffer_resource_iface;
+static const struct ds_buffer_interface tbm_client_buffer_iface;
+
static void tbm_server_handle_display_destroy(struct wl_listener *listener,
void *data);
static struct tbm_client_buffer *
return true;
}
+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;
+}
+
+tbm_surface_h
+tbm_client_buffer_get_tbm_surface(struct tbm_client_buffer *buffer)
+{
+ return buffer->surface;
+}
+
static void
tbm_server_handle_display_destroy(struct wl_listener *listener, void *data)
{
.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)
{
tbm_server_init_display(struct tbm_server *tbm_server,
struct wl_display *display);
+struct tbm_client_buffer *
+tbm_client_buffer_from_buffer(struct ds_buffer *ds_buffer);
+
+tbm_surface_h
+tbm_client_buffer_get_tbm_surface(struct tbm_client_buffer *buffer);
+
#endif
--- /dev/null
+#include <assert.h>
+#include <stdlib.h>
+
+#include <libds/log.h>
+
+#include "pixman-helper.h"
+#include "pixman-tbm-helper.h"
+#include "tinyds-tdm-renderer.h"
+
+static void renderer_setup_thread(struct tinyds_renderer *renderer);
+static void *renderer_thread_func(void *data);
+static void texture_destroy(struct tinyds_texture *texture);
+
+bool
+init_renderer(struct tinyds_renderer *renderer)
+{
+ renderer->damaged = false;
+
+ wl_list_init(&renderer->textures);
+
+ renderer_setup_thread(renderer);
+
+ return true;
+}
+
+void
+fini_renderer(struct tinyds_renderer *renderer)
+{
+ pthread_mutex_lock(&renderer->mutex);
+
+ renderer->destroying = true;
+ pthread_cond_signal(&renderer->cond);
+
+ pthread_mutex_unlock(&renderer->mutex);
+
+ pthread_join(renderer->worker_thread, NULL);
+
+ pthread_mutex_destroy(&renderer->mutex);
+ pthread_cond_destroy(&renderer->cond);
+}
+
+void
+renderer_set_surface_queue(struct tinyds_renderer *renderer,
+ void *surface_queue)
+{
+ pthread_mutex_lock(&renderer->mutex);
+
+ renderer->surface_queue = (tbm_surface_queue_h)surface_queue;
+
+ pthread_mutex_unlock(&renderer->mutex);
+}
+
+void
+renderer_set_bg_color(struct tinyds_renderer *renderer,
+ uint8_t r, uint8_t g, uint8_t b)
+{
+ pixman_color_t color;
+
+ pthread_mutex_lock(&renderer->mutex);
+
+ color_rgb888(&color, r, g, b);
+
+ renderer->bg_image = pixman_image_create_solid_fill(&color);
+ assert(renderer->bg_image);
+
+ renderer->damaged = true;
+
+ pthread_mutex_unlock(&renderer->mutex);
+}
+
+void
+renderer_add_texture(struct tinyds_renderer *renderer,
+ tbm_surface_h tbm_surface, int x, int y)
+{
+ struct tinyds_texture *texture;
+
+ pthread_mutex_lock(&renderer->mutex);
+
+ texture = calloc(1, sizeof *texture);
+
+ texture->x = x;
+ texture->y = y;
+ texture->renderer = renderer;
+ texture->surface = tbm_surface;
+ texture->image = pixman_image_from_tbm_surface(tbm_surface,
+ DS_BUFFER_DATA_PTR_ACCESS_READ);
+
+ wl_list_insert(renderer->textures.prev, &texture->link);
+
+ ds_dbg("Add texture(%p)", texture);
+
+ pthread_mutex_unlock(&renderer->mutex);
+}
+
+void
+renderer_draw(struct tinyds_renderer *renderer)
+{
+ pthread_mutex_lock(&renderer->mutex);
+
+ renderer->damaged = true;
+ pthread_cond_signal(&renderer->cond);
+
+ pthread_mutex_unlock(&renderer->mutex);
+}
+
+static void
+renderer_setup_thread(struct tinyds_renderer *renderer)
+{
+ pthread_mutex_init(&renderer->mutex, NULL);
+ pthread_cond_init(&renderer->cond, NULL);
+ pthread_create(&renderer->worker_thread, NULL,
+ renderer_thread_func, renderer);
+}
+
+static void *
+renderer_thread_func(void *data)
+{
+ struct tinyds_renderer *renderer = data;
+ struct tinyds_texture *texture, *texture_tmp;
+ pixman_image_t *dst_image;
+ tbm_surface_h surface;
+ tbm_surface_queue_error_e err;
+
+ pthread_mutex_lock(&renderer->mutex);
+
+ while (!renderer->destroying) {
+ if (!renderer->damaged)
+ pthread_cond_wait(&renderer->cond, &renderer->mutex);
+
+ if (!renderer->damaged)
+ continue;
+
+ if (!tbm_surface_queue_can_dequeue(renderer->surface_queue, 0))
+ continue;
+
+ ds_dbg(">> BEGIN DRAW");
+
+ err = tbm_surface_queue_dequeue(renderer->surface_queue, &surface);
+ assert(err == TBM_SURFACE_QUEUE_ERROR_NONE);
+
+ dst_image = pixman_image_from_tbm_surface(surface,
+ DS_BUFFER_DATA_PTR_ACCESS_WRITE);
+
+ if (renderer->bg_image) {
+ pixman_image_composite32(PIXMAN_OP_SRC,
+ renderer->bg_image,
+ NULL,
+ dst_image,
+ 0, 0, 0, 0, 0, 0,
+ pixman_image_get_width(dst_image),
+ pixman_image_get_height(dst_image));
+ }
+
+ wl_list_for_each_safe(texture, texture_tmp, &renderer->textures, link) {
+ ds_dbg("Draw texture(%p)", texture);
+ pixman_image_composite32(PIXMAN_OP_OVER,
+ texture->image,
+ NULL,
+ dst_image,
+ 0, 0, 0, 0,
+ texture->x, texture->y,
+ pixman_image_get_width(texture->image),
+ pixman_image_get_height(texture->image));
+ texture_destroy(texture);
+ }
+ pixman_image_unref(dst_image);
+
+ err = tbm_surface_queue_enqueue(renderer->surface_queue, surface);
+ assert(err == TBM_SURFACE_QUEUE_ERROR_NONE);
+
+ renderer->damaged = false;
+
+ ds_dbg("<< END DRAW");
+ }
+
+ pthread_mutex_unlock(&renderer->mutex);
+
+ return NULL;
+}
+
+static void
+texture_destroy(struct tinyds_texture *texture)
+{
+ pixman_image_unref(texture->image);
+ wl_list_remove(&texture->link);
+ free(texture);
+}
--- /dev/null
+#ifndef EXAMPLES_TINYDS_TDM_RENDERER_H
+#define EXAMPLES_TINYDS_TDM_RENDERER_H
+
+#include <pthread.h>
+#include <pixman.h>
+#include <tbm_surface_queue.h>
+#include <tbm_surface.h>
+#include <wayland-server.h>
+
+struct tinyds_renderer
+{
+ tbm_surface_queue_h surface_queue;
+
+ struct wl_list textures;
+
+ pthread_t worker_thread;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+
+ pixman_image_t *bg_image;
+
+ bool damaged;
+ bool destroying;
+};
+
+struct tinyds_texture
+{
+ struct tinyds_renderer *renderer;
+ pixman_image_t *image;
+ tbm_surface_h surface;
+
+ struct wl_list link;
+ struct wl_listener buffer_destroy;
+
+ int x, y;
+};
+
+bool init_renderer(struct tinyds_renderer *renderer);
+void fini_renderer(struct tinyds_renderer *renderer);
+void renderer_set_surface_queue(struct tinyds_renderer *renderer,
+ void *surface_queue);
+void renderer_set_bg_color(struct tinyds_renderer *renderer,
+ uint8_t r, uint8_t g, uint8_t b);
+void renderer_add_texture(struct tinyds_renderer *renderer,
+ tbm_surface_h tbm_surface, int x, int y);
+void renderer_draw(struct tinyds_renderer *renderer);
+
+#endif
-#include "tbm-server-helper.h"
-#include "pixman-helper.h"
-
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <libds/log.h>
#include <libds/backend.h>
#include <libds/output.h>
-#include <libds/swapchain.h>
#include <libds/compositor.h>
#include <libds/xdg_shell.h>
#include <libds-tizen/allocator/tbm.h>
#include <libds-tizen/backend/tdm.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 "tbm-server-helper.h"
+#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 tinyds_server *server;
+ struct tinyds_texture *texture;
struct ds_xdg_surface *xdg_surface;
struct wl_listener xdg_surface_map;
static void output_handle_frame(struct wl_listener *listener, void *data);
static void draw_server_with_damage(struct tinyds_server *server);
static void draw_output(struct tinyds_output *output);
+static void output_swap_buffer(struct tinyds_output *output,
+ struct ds_buffer *buffer);
+static void view_send_frame_done(struct tinyds_view *view);
+#ifdef USE_TDM_BUFFER_QUEUE
+static void output_buffer_queue_init(struct tinyds_output *output);
+static void output_renderer_init(struct tinyds_output *output);
+static void output_draw_with_renderer(struct tinyds_output *output);
+#else
+static void output_swapchain_init(struct tinyds_output *output);
+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)
void *data TINYDS_UNUSED)
{
struct tinyds_view *view;
+ struct tinyds_server *server;
view = wl_container_of(listener, view, xdg_surface_destroy);
-
- draw_server_with_damage(view->server);
+ server = view->server;
wl_list_remove(&view->xdg_surface_destroy.link);
wl_list_remove(&view->xdg_surface_map.link);
wl_list_remove(&view->surface_commit.link);
wl_list_remove(&view->link);
free(view);
+
+ draw_server_with_damage(server);
}
static void
if (!output)
return;
- output->allocator = ds_tbm_allocator_create();
- if (!output->allocator) {
- free(output);
- return;
- }
-
- output->swapchain = ds_swapchain_create(output->allocator,
- mode->width, mode->height, DRM_FORMAT_XRGB8888);
- if (!output->swapchain) {
- ds_allocator_destroy(output->allocator);
- free(output);
- return;
- }
-
output->server = server;
output->ds_output = ds_output;
+ output->width = mode->width;
+ output->height = mode->height;
output->drawable = true;
output->damaged = true;
+#ifdef USE_TDM_BUFFER_QUEUE
+ output_buffer_queue_init(output);
+ output_renderer_init(output);
+#else
+ output_swapchain_init(output);
+#endif
+
output->output_destroy.notify = output_handle_destroy;
- ds_output_add_destroy_listener(ds_output,
- &output->output_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);
+ ds_output_add_frame_listener(ds_output, &output->output_frame);
server->output = output;
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);
draw_output(server->output);
}
+#ifdef USE_TDM_BUFFER_QUEUE
static void
-draw_output(struct tinyds_output *output)
+output_handle_buffer_queue_acquirable(struct wl_listener *listener,
+ void *data TINYDS_UNUSED)
+{
+ struct tinyds_output *output;
+ struct ds_buffer *buffer;
+
+ output = wl_container_of(listener, output, buffer_queue_acquirable);
+
+ buffer = ds_tdm_buffer_queue_acquire(output->buffer_queue);
+ assert(buffer);
+
+ output_swap_buffer(output, buffer);
+}
+
+static void
+output_buffer_queue_init(struct tinyds_output *output)
+{
+ struct ds_tdm_output *tdm_output;
+
+ tdm_output = ds_tdm_output_from_output(output->ds_output);
+ assert(tdm_output);
+
+ output->buffer_queue = ds_tdm_output_get_buffer_queue(tdm_output);
+ assert(output->buffer_queue);
+
+ output->buffer_queue_acquirable.notify =
+ output_handle_buffer_queue_acquirable;
+ ds_tdm_buffer_queue_add_acquirable_listener(output->buffer_queue,
+ &output->buffer_queue_acquirable);
+}
+
+static void
+output_renderer_init(struct tinyds_output *output)
+{
+ init_renderer(&output->renderer);
+
+ renderer_set_surface_queue(&output->renderer,
+ ds_tdm_buffer_queue_get_native_queue(output->buffer_queue));
+
+ renderer_set_bg_color(&output->renderer, 80, 80, 80);
+}
+
+static void
+output_draw_with_renderer(struct tinyds_output *output)
{
- struct ds_buffer *output_buffer;
- pixman_image_t *output_image;
struct tinyds_view *view;
- if (!output->drawable || !output->damaged)
- return;
+ ds_dbg(">> BEGIN UPDATE TEXTURES");
+
+ wl_list_for_each(view, &output->server->views, link) {
+ struct ds_buffer *ds_buffer;
+ struct tbm_client_buffer *buffer;
+ tbm_surface_h surface;
+
+ if (!view->mapped)
+ continue;
+
+ ds_buffer = ds_surface_get_buffer(
+ ds_xdg_surface_get_surface(view->xdg_surface));
+ assert(buffer);
+
+ buffer = tbm_client_buffer_from_buffer(ds_buffer);
+ assert(buffer);
+
+ surface = tbm_client_buffer_get_tbm_surface(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)
+{
+ output->allocator = ds_tbm_allocator_create();
+ assert(output->allocator);
+
+ output->swapchain = ds_swapchain_create(output->allocator,
+ mode->width, mode->height, DRM_FORMAT_XRGB8888);
+ assert(output->swapchain);
+}
+
+static void
+output_draw_with_swapchain(struct tinyds_output *output)
+{
+ struct tinyds_view *view;
+ struct ds_buffer *output_buffer;
+ pixman_image_t *output_image;
output_buffer = ds_swapchain_acquire(output->swapchain, NULL);
if (!output_buffer)
}
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
-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);
+ output_swap_buffer(output, output_buffer);
}
static void
view_send_frame_done(view);
}
+#endif
+
+static void
+draw_output(struct tinyds_output *output)
+{
+
+ if (!output->drawable || !output->damaged)
+ return;
+
+#ifdef USE_TDM_BUFFER_QUEUE
+ output_draw_with_renderer(output);
+#else
+ output_draw_with_swapchain(output);
+#endif
+
+ output->drawable = false;
+ output->damaged = false;
+}
+
+static void
+output_swap_buffer(struct tinyds_output *output, struct ds_buffer *buffer)
+{
+ ds_output_attach_buffer(output->ds_output, buffer);
+ ds_output_commit(output->ds_output);
+
+ if (output->front_buffer)
+ ds_buffer_unlock(output->front_buffer);
+ output->front_buffer = buffer;
+}
+
+static void
+view_send_frame_done(struct tinyds_view *view)
+{
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ ds_surface_send_frame_done(ds_xdg_surface_get_surface(view->xdg_surface),
+ &now);
+}
static int
server_dispatch_stdin(int fd, uint32_t mask, void *data)