--- /dev/null
+#include <assert.h>
+#include <stdlib.h>
+#include <drm_fourcc.h>
+#include <wayland-server.h>
+
+#include <tbm_bufmgr.h>
+#include <tbm_surface.h>
+
+#include "libds/interfaces/allocator.h"
+#include "libds/interfaces/buffer.h"
+#include "libds/log.h"
+
+struct ds_tbm_allocator
+{
+ struct ds_allocator base;
+ tbm_bufmgr bufmgr;
+};
+
+struct ds_tbm_buffer
+{
+ struct ds_buffer base;
+ tbm_surface_h surface;
+};
+
+static const struct ds_allocator_interface tbm_allocator_iface;
+static struct ds_tbm_buffer *tbm_buffer_from_buffer(struct ds_buffer *buffer);
+
+WL_EXPORT struct ds_allocator *
+ds_tbm_allocator_create(void)
+{
+ struct ds_tbm_allocator *alloc;
+
+ alloc = calloc(1, sizeof *alloc);
+ if (!alloc)
+ return NULL;
+
+ alloc->bufmgr = tbm_bufmgr_init(-1);
+ if (!alloc->bufmgr) {
+ ds_err("Could not initialize tbm_bufmgr");
+ free(alloc);
+ return NULL;
+ }
+
+ ds_allocator_init(&alloc->base, &tbm_allocator_iface,
+ DS_BUFFER_CAP_DATA_PTR);
+
+ ds_inf("TBM allocator(%p) created", alloc);
+
+ return &alloc->base;
+}
+
+WL_EXPORT void *
+ds_tbm_buffer_get_surface(struct ds_buffer *ds_buffer)
+{
+ struct ds_tbm_buffer *buffer;
+
+ buffer = tbm_buffer_from_buffer(ds_buffer);
+ if (!buffer)
+ return NULL;
+
+ return buffer->surface;
+}
+
+static struct ds_tbm_allocator *
+tbm_allocator_from_allocator(struct ds_allocator *ds_allocator)
+{
+ assert(ds_allocator->iface == &tbm_allocator_iface);
+ return (struct ds_tbm_allocator *)ds_allocator;
+}
+
+static const struct ds_buffer_interface tbm_buffer_iface;
+
+static struct ds_tbm_buffer *
+tbm_buffer_from_buffer(struct ds_buffer *buffer)
+{
+ assert(buffer->iface == &tbm_buffer_iface);
+ return (struct ds_tbm_buffer *)buffer;
+}
+
+static void
+tbm_buffer_destroy(struct ds_buffer *ds_buffer)
+{
+ struct ds_tbm_buffer *buffer;
+
+ buffer = tbm_buffer_from_buffer(ds_buffer);
+
+ ds_dbg("Destroy tbm buffer(%p)", buffer);
+
+ tbm_surface_destroy(buffer->surface);
+ free(buffer);
+}
+
+static bool
+tbm_buffer_begin_data_ptr_access(struct ds_buffer *ds_buffer, uint32_t flags,
+ void **data, uint32_t *format, size_t *stride)
+{
+ struct ds_tbm_buffer *buffer;
+ tbm_surface_info_s info;
+ int tbm_access_flags = 0;
+ int ret;
+
+ buffer = tbm_buffer_from_buffer(ds_buffer);
+
+ if (flags & DS_BUFFER_DATA_PTR_ACCESS_READ)
+ tbm_access_flags |= TBM_OPTION_READ;
+ else if (flags & DS_BUFFER_DATA_PTR_ACCESS_WRITE)
+ tbm_access_flags |= TBM_OPTION_WRITE;
+
+ ret = tbm_surface_map(buffer->surface, tbm_access_flags, &info);
+ if (ret != TBM_SURFACE_ERROR_NONE) {
+ ds_err("Could not map tbm_surface of buffer(%p)", buffer);
+ return false;
+ }
+
+ *data = info.planes[0].ptr;
+ *format = info.format;
+ *stride = info.planes[0].stride;
+
+ return true;
+}
+
+static void
+tbm_buffer_end_data_ptr_access(struct ds_buffer *ds_buffer)
+{
+ struct ds_tbm_buffer *buffer;
+
+ buffer = tbm_buffer_from_buffer(ds_buffer);
+
+ tbm_surface_unmap(buffer->surface);
+}
+
+static const struct ds_buffer_interface tbm_buffer_iface =
+{
+ .destroy = tbm_buffer_destroy,
+ .begin_data_ptr_access = tbm_buffer_begin_data_ptr_access,
+ .end_data_ptr_access = tbm_buffer_end_data_ptr_access,
+};
+
+
+static void
+tbm_allocator_destroy(struct ds_allocator *ds_allocator)
+{
+ struct ds_tbm_allocator *alloc;
+
+ alloc = tbm_allocator_from_allocator(ds_allocator);
+
+ ds_inf("Destroy TBM allocator(%p)", alloc);
+
+ tbm_bufmgr_deinit(alloc->bufmgr);
+ free(alloc);
+}
+
+static struct ds_buffer *
+tbm_allocator_create_buffer(struct ds_allocator *ds_allocator,
+ int width, int height, uint32_t format)
+{
+ static int num_buffers = 0;
+ struct ds_tbm_buffer *buffer;
+
+ buffer = calloc(1, sizeof *buffer);
+ if (!buffer)
+ return NULL;
+
+ ds_buffer_init(&buffer->base, &tbm_buffer_iface, width, height);
+
+ buffer->surface = tbm_surface_create(width, height, TBM_FORMAT_XRGB8888);
+
+ ds_dbg("tbm buffer(%p) created: size(%dx%d) number of buffers: %d",
+ buffer, width, height, ++num_buffers);
+
+ return &buffer->base;
+}
+
+static const struct ds_allocator_interface tbm_allocator_iface = {
+ .destroy = tbm_allocator_destroy,
+ .create_buffer = tbm_allocator_create_buffer,
+};