Add an example of using ds_tdm_buffer_queue 43/278043/1
authorSeunghun Lee <shiin.lee@samsung.com>
Thu, 17 Mar 2022 07:40:37 +0000 (16:40 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Mon, 18 Jul 2022 05:08:04 +0000 (14:08 +0900)
Dependeing on the declaration of USE_TDM_BUFFER_QUEUE macro, tinyds-tdm
may be run with ds_tbm_buffer_queue.

Change-Id: I1d221d2d5eb94024902eea66d08f5973f1914771

src/examples/meson.build
src/examples/pixman-helper.c
src/examples/pixman-helper.h
src/examples/pixman-tbm-helper.c [new file with mode: 0644]
src/examples/pixman-tbm-helper.h [new file with mode: 0644]
src/examples/tbm-server-helper.c
src/examples/tbm-server-helper.h
src/examples/tinyds-tdm-renderer.c [new file with mode: 0644]
src/examples/tinyds-tdm-renderer.h [new file with mode: 0644]
src/examples/tinyds-tdm.c

index f95bd50..c60b610 100644 (file)
@@ -35,8 +35,10 @@ if get_option('tizen')
 
   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,
@@ -46,6 +48,7 @@ if get_option('tizen')
       dependency('libdrm', required: true),
       dependency('libtbm', required: true),
       dependency('wayland-tbm-server', required: true),
+      dependency('threads', required: true),
     ],
     install_dir: libds_bindir,
     install : true
index 5d42ec6..36a22e8 100644 (file)
@@ -5,8 +5,6 @@
 
 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,
@@ -37,7 +35,6 @@ 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)
 {
@@ -56,7 +53,7 @@ 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;
index aa039ff..99ceaca 100644 (file)
@@ -12,4 +12,7 @@ void
 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
diff --git a/src/examples/pixman-tbm-helper.c b/src/examples/pixman-tbm-helper.c
new file mode 100644 (file)
index 0000000..710eceb
--- /dev/null
@@ -0,0 +1,64 @@
+#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");
+    }
+}
diff --git a/src/examples/pixman-tbm-helper.h b/src/examples/pixman-tbm-helper.h
new file mode 100644 (file)
index 0000000..bf9bd55
--- /dev/null
@@ -0,0 +1,13 @@
+#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
index bd3a34d..320ee4f 100644 (file)
@@ -8,6 +8,8 @@
 #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 *
@@ -42,6 +44,19 @@ tbm_server_init_display(struct tbm_server *tbm, struct wl_display *display)
     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)
 {
@@ -107,15 +122,6 @@ static const struct ds_buffer_resource_interface tbm_buffer_resource_iface = {
     .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)
 {
index a82ad5b..609f370 100644 (file)
@@ -32,4 +32,10 @@ bool
 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
diff --git a/src/examples/tinyds-tdm-renderer.c b/src/examples/tinyds-tdm-renderer.c
new file mode 100644 (file)
index 0000000..0074dc9
--- /dev/null
@@ -0,0 +1,187 @@
+#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);
+}
diff --git a/src/examples/tinyds-tdm-renderer.h b/src/examples/tinyds-tdm-renderer.h
new file mode 100644 (file)
index 0000000..5f3e6fd
--- /dev/null
@@ -0,0 +1,48 @@
+#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
index 143d53e..6ec1156 100644 (file)
@@ -1,6 +1,3 @@
-#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
@@ -27,7 +35,13 @@ 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;
@@ -62,6 +76,7 @@ struct tinyds_view
 {
     struct tinyds_server *server;
 
+    struct tinyds_texture *texture;
     struct ds_xdg_surface *xdg_surface;
 
     struct wl_listener xdg_surface_map;
@@ -82,7 +97,18 @@ static void output_handle_destroy(struct wl_listener *listener, void *data);
 static void output_handle_frame(struct wl_listener *listener, void *data);
 static void draw_server_with_damage(struct tinyds_server *server);
 static void draw_output(struct tinyds_output *output);
+static void output_swap_buffer(struct tinyds_output *output,
+        struct ds_buffer *buffer);
+static void view_send_frame_done(struct tinyds_view *view);
+#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)
@@ -150,10 +176,10 @@ view_handle_xdg_surface_destroy(struct wl_listener *listener,
         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);
@@ -161,6 +187,8 @@ view_handle_xdg_surface_destroy(struct wl_listener *listener,
     wl_list_remove(&view->surface_commit.link);
     wl_list_remove(&view->link);
     free(view);
+
+    draw_server_with_damage(server);
 }
 
 static void
@@ -237,32 +265,25 @@ 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,
-            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;
 
@@ -318,11 +339,15 @@ output_handle_destroy(struct wl_listener *listener, void *data TINYDS_UNUSED)
     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);
 
@@ -348,15 +373,102 @@ draw_server_with_damage(struct tinyds_server *server)
     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)
@@ -378,24 +490,7 @@ draw_output(struct tinyds_output *output)
     }
     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
@@ -423,6 +518,44 @@ draw_view(struct tinyds_view *view, pixman_image_t *dst_image)
 
     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)