<arg name="pid" type="int"/>
</event>
+ <!-- version 2 -->
+ <request name="create_surface_queue">
+ <arg name="surface_queue" type="new_id" interface="wl_tbm_queue"/>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ </request>
</interface>
+ <interface name="wl_tbm_queue" version="1">
+ <event name="info">
+ <arg name="width" type="int"/>
+ <arg name="height" type="int"/>
+ <arg name="format" type="int"/>
+ <arg name="flags" type="uint"/>
+ <arg name="num_buffers" type="uint"/>
+ </event>
+ <event name="buffer_attached_with_id">
+ <arg name="id" type="new_id" interface="wl_buffer"/>
+ <arg name="width" type="int"/>
+ <arg name="height" type="int"/>
+ <arg name="format" type="uint"/>
+ <arg name="num_plane" type="int"/>
+ <arg name="buf_idx0" type="int"/>
+ <arg name="offset0" type="int"/>
+ <arg name="stride0" type="int"/>
+ <arg name="buf_idx1" type="int"/>
+ <arg name="offset1" type="int"/>
+ <arg name="stride1" type="int"/>
+ <arg name="buf_idx2" type="int"/>
+ <arg name="offset2" type="int"/>
+ <arg name="stride2" type="int"/>
+ <arg name="flags" type="uint"/>
+ <arg name="num_buf" type="int"/>
+ <arg name="buf0" type="uint"/>
+ <arg name="buf1" type="uint"/>
+ <arg name="buf2" type="uint"/>
+ </event>
+ <event name="buffer_attached_with_fd">
+ <arg name="id" type="new_id" interface="wl_buffer"/>
+ <arg name="width" type="int"/>
+ <arg name="height" type="int"/>
+ <arg name="format" type="uint"/>
+ <arg name="num_plane" type="int"/>
+ <arg name="buf_idx0" type="int"/>
+ <arg name="offset0" type="int"/>
+ <arg name="stride0" type="int"/>
+ <arg name="buf_idx1" type="int"/>
+ <arg name="offset1" type="int"/>
+ <arg name="stride1" type="int"/>
+ <arg name="buf_idx2" type="int"/>
+ <arg name="offset2" type="int"/>
+ <arg name="stride2" type="int"/>
+ <arg name="flags" type="uint"/>
+ <arg name="num_buf" type="int"/>
+ <arg name="buf0" type="fd"/>
+ <arg name="buf1" type="fd"/>
+ <arg name="buf2" type="fd"/>
+ </event>
+ <event name="active">
+ <arg name="usage" type="uint"/>
+ </event>
+ <event name="deactive"/>
+ <event name="flush"/>
+ <request name="destroy" type="destructor">
+ </request>
+ <request name="detach_buffer">
+ <arg name="buffer" type="object" interface="wl_buffer"/>
+ </request>
+ </interface>
</protocol>
#include <fcntl.h>
#include <tbm_surface.h>
+#include <tbm_surface_queue.h>
#include <tbm_surface_internal.h>
#include "wayland-tbm-client.h"
tbm_bufmgr bufmgr;
};
+struct wayland_tbm_buffer {
+ struct wl_buffer *wl_buffer;
+ tbm_surface_h tbm_surface;
+ uint32_t flags;
+
+ struct wl_tbm_queue *wl_tbm_queue;
+ struct wl_list link;
+};
+
+struct wayland_tbm_surface_queue {
+ struct wl_tbm_queue *wl_tbm_queue;
+ tbm_bufmgr bufmgr;
+
+ int width;
+ int height;
+ int format;
+ int flag;
+ uint num_bufs;
+
+ int is_active;
+ int usage;
+ struct wl_list attach_bufs;
+
+ tbm_surface_queue_h tbm_queue;
+};
+
+static const int key_wl_tbm_buffer;
+#define KEY_WL_TBM_BUFFER ((unsigned long)&key_wl_tbm_buffer)
+
static void
handle_tbm_monitor_client_tbm_bo(void *data,
struct wl_tbm *wl_tbm,
struct wl_buffer *wl_buffer = NULL;
int i;
+ struct wayland_tbm_buffer *tbm_buffer = NULL;
+ uint32_t flags = 0;
+
+ tbm_surface_internal_get_user_data(surface, KEY_WL_TBM_BUFFER,
+ (void **)&tbm_buffer);
+ if (tbm_buffer) {
+ return tbm_buffer->wl_buffer;
+ }
+
ret = tbm_surface_get_info(surface, &info);
if (ret != TBM_SURFACE_ERROR_NONE) {
WL_TBM_LOG("Failed to create buffer from surface\n");
info.planes[1].offset, info.planes[1].stride,
tbm_surface_internal_get_plane_bo_idx(surface, 2),
info.planes[2].offset, info.planes[2].stride,
- 0, num_buf, bufs[0],
+ flags, num_buf, bufs[0],
(bufs[1] == -1) ? bufs[0] : bufs[1],
(bufs[2] == -1) ? bufs[0] : bufs[2]);
else
info.planes[1].offset, info.planes[1].stride,
tbm_surface_internal_get_plane_bo_idx(surface, 2),
info.planes[2].offset, info.planes[2].stride,
- 0,
+ flags,
num_buf, bufs[0], bufs[1], bufs[2]);
if (!wl_buffer) {
close(bufs[i]);
}
+ tbm_buffer = calloc(1, sizeof(struct wayland_tbm_buffer));
+ tbm_buffer->wl_buffer = wl_buffer;
+ tbm_buffer->flags = flags;
+ wl_list_init(&tbm_buffer->link);
+ tbm_surface_internal_add_user_data(surface, KEY_WL_TBM_BUFFER, free);
+ tbm_surface_internal_set_user_data(surface, KEY_WL_TBM_BUFFER, tbm_buffer);
+
return wl_buffer;
err:
return tbm_client->wl_tbm;
}
+static tbm_surface_h
+__tbm_surface_from_param(tbm_bufmgr bufmgr,
+ int is_fd,
+ int32_t width,
+ int32_t height,
+ uint32_t format,
+ int32_t num_plane,
+ int32_t buf_idx0,
+ int32_t offset0,
+ int32_t stride0,
+ int32_t buf_idx1,
+ int32_t offset1,
+ int32_t stride1,
+ int32_t buf_idx2,
+ int32_t offset2,
+ int32_t stride2,
+ uint32_t flags,
+ int32_t num_buf,
+ uint32_t buf0,
+ uint32_t buf1,
+ uint32_t buf2)
+{
+ tbm_surface_h tbm_surface;
+
+ int32_t names[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
+ tbm_bo bos[TBM_SURF_PLANE_MAX];
+ tbm_surface_info_s info;
+ int bpp;
+ int numPlane, numName = 0;
+ int i;
+
+ bpp = tbm_surface_internal_get_bpp(format);
+ numPlane = tbm_surface_internal_get_num_planes(format);
+ WL_TBM_RETURN_VAL_IF_FAIL(numPlane == num_plane, NULL);
+
+ memset(&info, 0x0, sizeof(tbm_surface_info_s));
+
+ info.width = width;
+ info.height = height;
+ info.format = format;
+ info.bpp = bpp;
+ info.num_planes = numPlane;
+
+ /*Fill plane info*/
+ if (numPlane > 0) {
+ info.planes[0].offset = offset0;
+ info.planes[0].stride = stride0;
+ numPlane--;
+ }
+
+ if (numPlane > 0) {
+ info.planes[1].offset = offset1;
+ info.planes[1].stride = stride1;
+ numPlane--;
+ }
+
+ if (numPlane > 0) {
+ info.planes[2].offset = offset2;
+ info.planes[2].stride = stride2;
+ numPlane--;
+ }
+
+ /*Fill buffer*/
+ numName = num_buf;
+ names[0] = buf0;
+ names[1] = buf1;
+ names[2] = buf2;
+
+
+ for (i = 0; i < numName; i++) {
+ if (is_fd) {
+ bos[i] = tbm_bo_import_fd(bufmgr, names[i]);
+ } else {
+ bos[i] = tbm_bo_import(bufmgr, names[i]);
+ }
+ }
+ tbm_surface = tbm_surface_internal_create_with_bos(&info, bos, numName);
+ WL_TBM_RETURN_VAL_IF_FAIL(tbm_surface != NULL, NULL);
+
+ if (is_fd) {
+ close(buf0);
+ close(buf1);
+ close(buf2);
+ }
+
+ return tbm_surface;
+}
+
+static tbm_surface_h
+__tbm_surface_alloc_cb(tbm_surface_queue_h surface_queue, void *data)
+{
+ struct wayland_tbm_surface_queue *queue_info = data;
+ struct wayland_tbm_buffer *buffer;
+ tbm_surface_h surface;
+
+ if (queue_info->is_active) {
+ struct wl_list *link;
+ if (wl_list_empty(&queue_info->attach_bufs))
+ return NULL;
+ link = queue_info->attach_bufs.next;
+ buffer = wl_container_of(link, buffer, link);
+ surface = buffer->tbm_surface;
+ wl_list_remove(link);
+
+ } else {
+ surface = tbm_surface_internal_create_with_flags(queue_info->width,
+ queue_info->height,
+ queue_info->format,
+ queue_info->flag);
+ }
+
+ return surface;
+}
+
+static void
+__tbm_surface_free_cb(tbm_surface_queue_h surface_queue, void *data,
+ tbm_surface_h surface)
+{
+ struct wayland_tbm_buffer *buffer = NULL;
+
+ tbm_surface_internal_get_user_data(surface, KEY_WL_TBM_BUFFER,
+ (void **)&buffer);
+
+ if (buffer) {
+ if (buffer->wl_buffer) {
+ wl_buffer_destroy(buffer->wl_buffer);
+ }
+ tbm_surface_internal_set_user_data(surface, KEY_WL_TBM_BUFFER, NULL);
+ tbm_surface_internal_delete_user_data(surface, KEY_WL_TBM_BUFFER);
+ }
+
+ tbm_surface_destroy(surface);
+}
+
+static void
+__tbm_surface_queue_flush(struct wayland_tbm_surface_queue *queue_info)
+{
+ struct wayland_tbm_buffer *buffer, *tmp;
+
+ wl_list_for_each_safe(buffer, tmp, &queue_info->attach_bufs, link) {
+ wl_list_remove(&buffer->link);
+
+ wl_buffer_destroy(buffer->wl_buffer);
+ buffer->wl_buffer = NULL;
+ tbm_surface_destroy(buffer->tbm_surface);
+ }
+
+ tbm_surface_queue_flush(queue_info->tbm_queue);
+}
+
+static void
+handle_tbm_queue_info(void *data,
+ struct wl_tbm_queue *wl_tbm_queue,
+ int32_t width,
+ int32_t height,
+ int32_t format,
+ uint32_t flags,
+ uint32_t num_buffers)
+{
+ struct wayland_tbm_surface_queue *queue_info = data;
+
+ queue_info->width = width;
+ queue_info->height = height;
+ queue_info->format = format;
+ queue_info->flag = flags;
+ queue_info->num_bufs = num_buffers;
+
+ queue_info->tbm_queue = tbm_surface_queue_sequence_create(num_buffers,
+ width,
+ height,
+ format,
+ flags);
+
+ if (queue_info->tbm_queue == NULL) {
+ WL_TBM_C_LOG("failed to create_surface %dx%d format:0x%x flags:%d, num_bufs:%d",
+ width, height, format, flags, num_buffers);
+ }
+
+ tbm_surface_queue_set_alloc_cb(queue_info->tbm_queue,
+ __tbm_surface_alloc_cb,
+ __tbm_surface_free_cb,
+ queue_info);
+}
+
+static void
+handle_tbm_queue_buffer_attached_with_id(void *data,
+ struct wl_tbm_queue *wl_tbm_queue,
+ struct wl_buffer *id,
+ int32_t width,
+ int32_t height,
+ uint32_t format,
+ int32_t num_plane,
+ int32_t buf_idx0,
+ int32_t offset0,
+ int32_t stride0,
+ int32_t buf_idx1,
+ int32_t offset1,
+ int32_t stride1,
+ int32_t buf_idx2,
+ int32_t offset2,
+ int32_t stride2,
+ uint32_t flags,
+ int32_t num_buf,
+ uint32_t buf0,
+ uint32_t buf1,
+ uint32_t buf2)
+{
+ struct wayland_tbm_surface_queue *queue_info = data;
+ struct wayland_tbm_buffer *buffer;
+
+ buffer = calloc(1, sizeof(struct wayland_tbm_buffer));
+ wl_list_init(&buffer->link);
+
+ buffer->wl_tbm_queue = wl_tbm_queue;
+ buffer->wl_buffer = id;
+ WL_TBM_GOTO_IF_FAIL(buffer->wl_buffer != NULL, fail);
+
+ buffer->tbm_surface = __tbm_surface_from_param(queue_info->bufmgr, 0,
+ width, height, format,
+ num_plane,
+ buf_idx0, offset0, stride0,
+ buf_idx1, offset1, stride1,
+ buf_idx2, offset2, stride2,
+ queue_info->flag,
+ num_buf,
+ buf0, buf1, buf2);
+ WL_TBM_GOTO_IF_FAIL(buffer->tbm_surface != NULL, fail);
+ buffer->flags = flags;
+
+ wl_list_insert(&queue_info->attach_bufs, &buffer->link);
+
+ tbm_surface_internal_add_user_data(buffer->tbm_surface,
+ KEY_WL_TBM_BUFFER, free);
+ tbm_surface_internal_set_user_data(buffer->tbm_surface,
+ KEY_WL_TBM_BUFFER,
+ buffer);
+ return;
+
+fail:
+ if (buffer->wl_buffer)
+ wl_buffer_destroy(buffer->wl_buffer);
+
+ if (buffer->tbm_surface)
+ tbm_surface_destroy(buffer->tbm_surface);
+ free(buffer);
+}
+
+static void
+handle_tbm_queue_buffer_attached_with_fd(void *data,
+ struct wl_tbm_queue *wl_tbm_queue,
+ struct wl_buffer *id,
+ int32_t width,
+ int32_t height,
+ uint32_t format,
+ int32_t num_plane,
+ int32_t buf_idx0,
+ int32_t offset0,
+ int32_t stride0,
+ int32_t buf_idx1,
+ int32_t offset1,
+ int32_t stride1,
+ int32_t buf_idx2,
+ int32_t offset2,
+ int32_t stride2,
+ uint32_t flags,
+ int32_t num_buf,
+ int32_t buf0,
+ int32_t buf1,
+ int32_t buf2)
+{
+ struct wayland_tbm_surface_queue *queue_info = data;
+ struct wayland_tbm_buffer *buffer;
+
+ buffer = calloc(1, sizeof(struct wayland_tbm_buffer));
+ wl_list_init(&buffer->link);
+
+ buffer->wl_tbm_queue = wl_tbm_queue;
+ buffer->wl_buffer = id;
+ WL_TBM_GOTO_IF_FAIL(buffer->wl_buffer != NULL, fail);
+
+ buffer->tbm_surface = __tbm_surface_from_param(queue_info->bufmgr, 1,
+ width, height, format,
+ num_plane,
+ buf_idx0, offset0, stride0,
+ buf_idx1, offset1, stride1,
+ buf_idx2, offset2, stride2,
+ queue_info->flag,
+ num_buf,
+ buf0, buf1, buf2);
+ WL_TBM_GOTO_IF_FAIL(buffer->tbm_surface != NULL, fail);
+ buffer->flags = flags;
+
+ wl_list_insert(&queue_info->attach_bufs, &buffer->link);
+
+ tbm_surface_internal_add_user_data(buffer->tbm_surface,
+ KEY_WL_TBM_BUFFER, free);
+ tbm_surface_internal_set_user_data(buffer->tbm_surface,
+ KEY_WL_TBM_BUFFER,
+ buffer);
+ return;
+fail:
+ if (buffer->wl_buffer)
+ wl_buffer_destroy(buffer->wl_buffer);
+
+ if (buffer->tbm_surface)
+ tbm_surface_destroy(buffer->tbm_surface);
+ free(buffer);
+}
+
+static void
+handle_tbm_queue_active(void *data,
+ struct wl_tbm_queue *wl_tbm_queue,
+ uint32_t usage)
+{
+ struct wayland_tbm_surface_queue *queue_info = data;
+
+ queue_info->is_active = 1;
+ queue_info->usage = usage;
+
+ __tbm_surface_queue_flush(queue_info);
+}
+
+static void
+handle_tbm_queue_deactive(void *data,
+ struct wl_tbm_queue *wl_tbm_queue)
+{
+ struct wayland_tbm_surface_queue *queue_info = data;
+
+ if (queue_info->is_active == 0)
+ return;
+
+ queue_info->is_active = 0;
+ __tbm_surface_queue_flush(queue_info);
+}
+
+static void
+handle_tbm_queue_flush(void *data,
+ struct wl_tbm_queue *wl_tbm_queue)
+{
+ struct wayland_tbm_surface_queue *queue_info = data;
+
+ __tbm_surface_queue_flush(queue_info);
+}
+
+
+const struct wl_tbm_queue_listener wl_tbm_queue_listener = {
+ handle_tbm_queue_info,
+ handle_tbm_queue_buffer_attached_with_id,
+ handle_tbm_queue_buffer_attached_with_fd,
+ handle_tbm_queue_active,
+ handle_tbm_queue_deactive,
+ handle_tbm_queue_flush
+};
+
+tbm_surface_queue_h
+wayland_tbm_client_create_surface_queue(struct wayland_tbm_client *tbm_client,
+ struct wl_surface *surface)
+{
+ struct wayland_tbm_surface_queue *queue_info;
+ struct wl_tbm_queue *queue;
+
+ WL_TBM_RETURN_VAL_IF_FAIL(tbm_client != NULL, NULL);
+ WL_TBM_RETURN_VAL_IF_FAIL(surface != NULL, NULL);
+
+ queue_info = calloc(1, sizeof(struct wayland_tbm_surface_queue));
+ WL_TBM_RETURN_VAL_IF_FAIL(queue_info != NULL, NULL);
+ queue_info->bufmgr = tbm_client->bufmgr;
+ wl_list_init(&queue_info->attach_bufs);
+
+ queue = wl_tbm_create_surface_queue(tbm_client->wl_tbm, surface);
+ WL_TBM_GOTO_IF_FAIL(queue != NULL, fail);
+ queue_info->wl_tbm_queue = queue;
+
+ wl_tbm_queue_add_listener(queue, &wl_tbm_queue_listener, queue_info);
+ wl_display_roundtrip(tbm_client->dpy);
+ WL_TBM_GOTO_IF_FAIL(queue_info->tbm_queue != NULL, fail);
+
+ return queue_info->tbm_queue;
+fail:
+ if (queue_info)
+ free(queue_info);
+ return NULL;
+}
+
#include <wayland-client.h>
#include <tbm_surface.h>
+#include <tbm_surface_queue.h>
struct wayland_tbm_client;
wayland_tbm_client_destroy_buffer(struct wayland_tbm_client *tbm_client,
struct wl_buffer *buffer);
-void *wayland_tbm_client_get_bufmgr(struct wayland_tbm_client *tbm_client);
+void *
+wayland_tbm_client_get_bufmgr(struct wayland_tbm_client *tbm_client);
+tbm_surface_queue_h
+wayland_tbm_client_create_surface_queue(struct wayland_tbm_client *tbm_client,
+ struct wl_surface *surface);
#ifdef __cplusplus
}
#endif
struct wl_list client_resource_list;
tbm_bufmgr bufmgr;
+
+ /*Scanout*/
+ struct wl_list queue_list;
+ struct wl_list server_queue_list;
};
struct wl_tbm_buffer {
struct wl_resource *resource;
tbm_surface_h tbm_surface;
+ tbm_surface_queue_h tbm_queue;
int flags;
};
struct wl_list link;
};
+struct wayland_tbm_server_queue {
+ struct wl_list link;
+ struct wayland_tbm_server *tbm_srv;
+ tbm_surface_queue_h tbm_queue;
+ uint32_t flags;
+
+ struct wl_tbm_queue *client_queue;
+};
+
+struct wl_tbm_queue {
+ struct wl_list link;
+
+ struct wl_resource *resource;
+ struct wl_resource *wl_tbm;
+ struct wl_resource *surface;
+ struct wayland_tbm_server_queue *server_queue;
+
+ int num_attached;
+};
+
+static const int key_wl_tbm_queue;
+#define KEY_WL_TBM_QUEUE ((unsigned long)&key_wl_tbm_queue)
+
+const static int key_wl_tbm_buffer;
+#define KEY_WL_TBM_BUFFER ((unsigned long)&key_wl_tbm_buffer)
+
+static void _create_tbm_queue(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t surface_queue,
+ struct wl_resource *surface);
+
+static void _destory_tbm_queue(struct wl_resource *resource);
+
static void _buffer_destroy(struct wl_client *client,
struct wl_resource *resource);
+
static const struct wl_buffer_interface _wayland_tbm_buffer_impementation = {
_buffer_destroy
};
{
struct wl_tbm_buffer *buffer = wl_resource_get_user_data(resource);
+ tbm_surface_internal_delete_user_data(buffer->tbm_surface, KEY_WL_TBM_BUFFER);
+
+ if (buffer->tbm_queue) {
+ tbm_surface_queue_release(buffer->tbm_queue, buffer->tbm_surface);
+ WL_TBM_S_LOG("Release to queue(%p), tbm_surface:%p\n", buffer->tbm_queue,
+ buffer->tbm_surface);
+ }
+
tbm_surface_destroy(buffer->tbm_surface);
free(buffer);
wl_resource_destroy(resource);
}
-static void
-_create_buffer(struct wl_client *client, struct wl_resource *resource,
- uint32_t id,
- tbm_surface_info_s *info,
- int32_t is_fd, int32_t *names, int32_t num_name, uint32_t flags)
+static struct wl_tbm_buffer *
+_create_wl_buffer(struct wl_client *client, struct wl_resource *resource,
+ uint id, tbm_surface_h tbm_buffer, int flags)
{
struct wayland_tbm_server *tbm_srv = wl_resource_get_user_data(resource);
struct wayland_tbm_client_resource *c_res = NULL, *tmp_res = NULL;
struct wl_tbm_buffer *buffer;
- tbm_surface_h surface;
- tbm_bo bos[TBM_SURF_PLANE_MAX];
- int i;
buffer = calloc(1, sizeof * buffer);
if (buffer == NULL) {
wl_resource_post_no_memory(resource);
- return;
- }
-
- for (i = 0; i < num_name; i++) {
- if (is_fd) {
- bos[i] = tbm_bo_import_fd(tbm_srv->bufmgr, names[i]);
- } else {
- bos[i] = tbm_bo_import(tbm_srv->bufmgr, names[i]);
- }
+ return NULL;
}
- surface = tbm_surface_internal_create_with_bos(info, bos, num_name);
- for (i = 0; i < num_name; i++)
- tbm_bo_unref(bos[i]);
-
buffer->flags = flags;
- buffer->tbm_surface = (void *)surface;
+ buffer->tbm_surface = (void *)tbm_buffer;
if (buffer->tbm_surface == NULL) {
wl_resource_post_error(resource,
WL_TBM_ERROR_INVALID_NAME,
- "invalid name:is_fd(%d)", is_fd);
+ "tbm_surface is NULL");
free(buffer);
- return;
+ return NULL;
}
/* set the debug_pid to the surface for debugging */
if (!wl_list_empty(&tbm_srv->client_resource_list)) {
wl_list_for_each_safe(c_res, tmp_res, &tbm_srv->client_resource_list, link) {
if (c_res->resource == resource) {
- tbm_surface_internal_set_debug_pid(surface, c_res->pid);
+ tbm_surface_internal_set_debug_pid(tbm_buffer, c_res->pid);
break;
}
}
buffer->resource = wl_resource_create(client, &wl_buffer_interface, 1, id);
if (!buffer->resource) {
wl_resource_post_no_memory(resource);
- tbm_surface_destroy(buffer->tbm_surface);
free(buffer);
- return;
+ return NULL;
}
wl_resource_set_implementation(buffer->resource,
(void (* *)(void)) &_wayland_tbm_buffer_impementation,
buffer, _destroy_buffer);
+ tbm_surface_internal_add_user_data(tbm_buffer, KEY_WL_TBM_BUFFER, NULL);
+ tbm_surface_internal_set_user_data(tbm_buffer, KEY_WL_TBM_BUFFER,
+ (void *)buffer);
+
+ return buffer;
+}
+
+static void
+_create_buffer(struct wl_client *client, struct wl_resource *resource,
+ uint32_t id,
+ tbm_surface_info_s *info,
+ int32_t is_fd, int32_t *names, int32_t num_name, uint32_t flags)
+{
+ struct wayland_tbm_server *tbm_srv = wl_resource_get_user_data(resource);
+ struct wl_tbm_buffer *buffer;
+ tbm_surface_h surface;
+ tbm_bo bos[TBM_SURF_PLANE_MAX];
+ int i;
+
+ for (i = 0; i < num_name; i++) {
+ if (is_fd) {
+ bos[i] = tbm_bo_import_fd(tbm_srv->bufmgr, names[i]);
+ } else {
+ bos[i] = tbm_bo_import(tbm_srv->bufmgr, names[i]);
+ }
+ }
+
+ surface = tbm_surface_internal_create_with_bos(info, bos, num_name);
+ for (i = 0; i < num_name; i++)
+ tbm_bo_unref(bos[i]);
+
+ buffer = _create_wl_buffer(client, resource, id, surface, flags);
+ if (!buffer) {
+ WL_TBM_S_LOG("failed to create wl_buffer id:%d\n", id);
+ tbm_surface_destroy(surface);
+ return;
+ }
+
+ return;
}
static void
close(buf2);
}
+static void
+_wayland_tbm_server_impl_create_surface_queue(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t surface_queue,
+ struct wl_resource *surface)
+{
+ _create_tbm_queue(client, resource, surface_queue, surface);
+}
+
static const struct wl_tbm_interface _wayland_tbm_server_implementation = {
_wayland_tbm_server_impl_create_buffer,
_wayland_tbm_server_impl_create_buffer_with_fd,
_wayland_tbm_server_impl_request_tbm_monitor,
+ _wayland_tbm_server_impl_create_surface_queue,
};
static void
/* init the client resource list */
wl_list_init(&tbm_srv->client_resource_list);
+ wl_list_init(&tbm_srv->server_queue_list);
//init bufmgr
tbm_srv->bufmgr = tbm_bufmgr_init(-1);
return NULL;
}
- tbm_bufmgr_bind_native_display(tbm_srv->bufmgr, (void *)display);
-
+ if (!getenv("WL_TBM_EMBEDDED_SERVER")) {
+ WL_TBM_S_LOG("Bind start\n");
+ tbm_bufmgr_bind_native_display(tbm_srv->bufmgr, (void *)display);
+ }
tbm_srv->wl_tbm_global = wl_global_create(display, &wl_tbm_interface, 1,
tbm_srv, _wayland_tbm_server_bind_cb);
+ //init wl_tbm_queue
+ wl_list_init(&tbm_srv->queue_list);
+
return tbm_srv;
}
return NULL;
}
+struct wl_resource *
+wayland_tbm_server_get_resource(struct wayland_tbm_server *tbm_srv,
+ tbm_surface_h surface)
+{
+ struct wl_tbm_buffer *wl_buffer = NULL;
+
+ tbm_surface_internal_get_user_data(surface, KEY_WL_TBM_BUFFER,
+ (void **)&wl_buffer);
+ if (wl_buffer)
+ return wl_buffer->resource;
+
+ return NULL;
+}
+
+uint32_t
+wayland_tbm_server_get_flags(struct wayland_tbm_server *tbm_srv,
+ struct wl_resource *resource)
+{
+ struct wl_tbm_buffer *wl_buffer;
+
+ if (resource == NULL)
+ return 0;
+
+ if (wl_resource_instance_of(resource, &wl_buffer_interface,
+ &_wayland_tbm_buffer_impementation)) {
+ wl_buffer = wl_resource_get_user_data(resource);
+ return wl_buffer->flags;
+ }
+
+ return 0;
+}
+
void *
wayland_tbm_server_get_bufmgr(struct wayland_tbm_server *tbm_srv)
{
return (void *)tbm_srv->bufmgr;
}
+static void
+_wayland_tbm_queue_impl_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ _destory_tbm_queue(resource);
+}
+
+static void
+_wayland_tbm_queue_impl_detach_buffer(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *buffer)
+{
+}
+
+static const struct wl_tbm_queue_interface _wayland_tbm_queue_impementation = {
+ _wayland_tbm_queue_impl_destroy,
+ _wayland_tbm_queue_impl_detach_buffer,
+};
+
+struct wl_tbm_queue *
+_find_tbm_queue(struct wayland_tbm_server *tbm_srv, struct wl_resource *surface)
+{
+ struct wl_tbm_queue *queue = NULL;
+
+ wl_list_for_each(queue, &tbm_srv->queue_list, link) {
+ if (queue && queue->surface == surface)
+ return queue;
+ }
+
+ return NULL;
+}
+
+static void
+_destory_tbm_queue(struct wl_resource *resource)
+{
+ struct wl_tbm_queue *queue = wl_resource_get_user_data(resource);
+
+ wl_list_remove(&queue->link);
+
+ free(queue);
+}
+
+static void
+_create_tbm_queue(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t surface_queue,
+ struct wl_resource *surface)
+{
+ struct wayland_tbm_server *tbm_srv = wl_resource_get_user_data(resource);
+ struct wl_tbm_queue *queue;
+
+ queue = calloc(1, sizeof * queue);
+ if (queue == NULL) {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ wl_list_init(&queue->link);
+ queue->wl_tbm = resource;
+ queue->surface = surface;
+ queue->resource = wl_resource_create(client, &wl_tbm_queue_interface, 1,
+ surface_queue);
+ if (!queue->resource) {
+ wl_resource_post_no_memory(resource);
+ free(queue);
+ return;
+ }
+
+ wl_resource_set_implementation(queue->resource,
+ (void (* *)(void)) &_wayland_tbm_queue_impementation,
+ queue, _destory_tbm_queue);
+ wl_list_insert(&tbm_srv->queue_list, &queue->link);
+
+ //send info
+ wl_tbm_queue_send_info(queue->resource, 1, 1, TBM_FORMAT_ABGR8888, 0, 3);
+}
+
+static void
+_server_queue_buffer_attach(struct wl_tbm_queue *client_queue,
+ tbm_surface_h buffer)
+{
+ struct wl_tbm_buffer *wl_tbm_buffer = NULL;
+ tbm_surface_info_s info;
+ int num_buf;
+ int bufs[TBM_SURF_PLANE_MAX] = { -1, -1, -1, -1};
+ int is_fd = -1;
+ int ret = -1, i;
+ uint32_t flags;
+
+ flags = client_queue->server_queue->flags;
+ wl_tbm_buffer = _create_wl_buffer(wl_resource_get_client(client_queue->wl_tbm),
+ client_queue->wl_tbm,
+ 0, buffer, flags);
+ WL_TBM_RETURN_IF_FAIL(wl_tbm_buffer != NULL);
+ tbm_surface_internal_ref(buffer);
+
+ ret = tbm_surface_get_info(buffer, &info);
+ if (ret != TBM_SURFACE_ERROR_NONE) {
+ WL_TBM_S_LOG("Failed to create buffer from surface\n");
+ _destroy_buffer(wl_tbm_buffer->resource);
+ return;
+ }
+
+ if (info.num_planes > 3) {
+ WL_TBM_S_LOG("invalid num_planes(%d)\n", info.num_planes);
+ _destroy_buffer(wl_tbm_buffer->resource);
+ return;
+ }
+
+ num_buf = tbm_surface_internal_get_num_bos(buffer);
+ if (num_buf == 0) {
+ WL_TBM_S_LOG("surface doesn't have any bo.\n");
+ _destroy_buffer(wl_tbm_buffer->resource);
+ goto err;
+ }
+
+ for (i = 0; i < num_buf; i++) {
+ tbm_bo bo = tbm_surface_internal_get_bo(buffer, i);
+ if (bo == NULL) {
+ WL_TBM_S_LOG("Failed to get bo from surface\n");
+ goto err;
+ }
+
+ /* try to get fd first */
+ if (is_fd == -1 || is_fd == 1) {
+ bufs[i] = tbm_bo_export_fd(bo);
+ if (bufs[i] >= 0)
+ is_fd = 1;
+ }
+
+ /* if fail to get fd, try to get name second */
+ if (is_fd == -1 || is_fd == 0) {
+ bufs[i] = tbm_bo_export(bo);
+ if (bufs[i] > 0)
+ is_fd = 0;
+ }
+
+ if (is_fd == -1 ||
+ (is_fd == 1 && bufs[i] < 0) ||
+ (is_fd == 0 && bufs[i] <= 0)) {
+ WL_TBM_S_LOG("Failed to export(is_fd:%d, bufs:%d)\n", is_fd, bufs[i]);
+ goto err;
+ }
+ }
+
+ if (is_fd == 1)
+ wl_tbm_queue_send_buffer_attached_with_fd(client_queue->resource,
+ wl_tbm_buffer->resource,
+ info.width, info.height, info.format, info.num_planes,
+ tbm_surface_internal_get_plane_bo_idx(buffer, 0),
+ info.planes[0].offset, info.planes[0].stride,
+ tbm_surface_internal_get_plane_bo_idx(buffer, 1),
+ info.planes[1].offset, info.planes[1].stride,
+ tbm_surface_internal_get_plane_bo_idx(buffer, 2),
+ info.planes[2].offset, info.planes[2].stride,
+ flags, num_buf, bufs[0],
+ (bufs[1] == -1) ? bufs[0] : bufs[1],
+ (bufs[2] == -1) ? bufs[0] : bufs[2]);
+ else
+ wl_tbm_queue_send_buffer_attached_with_fd(client_queue->resource,
+ wl_tbm_buffer->resource,
+ info.width, info.height, info.format, info.num_planes,
+ tbm_surface_internal_get_plane_bo_idx(buffer, 0),
+ info.planes[0].offset, info.planes[0].stride,
+ tbm_surface_internal_get_plane_bo_idx(buffer, 1),
+ info.planes[1].offset, info.planes[1].stride,
+ tbm_surface_internal_get_plane_bo_idx(buffer, 2),
+ info.planes[2].offset, info.planes[2].stride,
+ flags, num_buf, bufs[0],
+ (bufs[1] == -1) ? bufs[0] : bufs[1],
+ (bufs[2] == -1) ? bufs[0] : bufs[2]);
+
+
+ for (i = 0; i < TBM_SURF_PLANE_MAX; i++) {
+ if (is_fd == 1 && (bufs[i] >= 0))
+ close(bufs[i]);
+ }
+
+ wl_tbm_buffer->tbm_queue = client_queue->server_queue->tbm_queue;
+ return;
+err:
+ for (i = 0; i < TBM_SURF_PLANE_MAX; i++) {
+ if (is_fd == 1 && (bufs[i] >= 0))
+ close(bufs[i]);
+ }
+
+ if (wl_tbm_buffer) {
+ _destroy_buffer(wl_tbm_buffer->resource);
+ tbm_surface_internal_unref(buffer);
+ }
+
+ return;
+}
+
+static void
+_server_queue_buffer_attach_free_queue(struct wl_tbm_queue *client_queue)
+{
+ tbm_surface_queue_h queue;
+ tbm_surface_h buffer;
+ struct wl_resource *wl_buffer;
+
+ queue = client_queue->server_queue->tbm_queue;
+ while (tbm_surface_queue_can_dequeue(queue, 0)) {
+ tbm_surface_queue_dequeue(queue, &buffer);
+
+ wl_buffer = wayland_tbm_server_get_resource(NULL, buffer);
+ if (wl_buffer) {
+ wl_buffer_send_release(wl_buffer);
+ continue;
+ }
+
+ _server_queue_buffer_attach(client_queue, buffer);
+ }
+}
+
+static void
+_server_queue_dequeuable_cb(tbm_surface_queue_h surface_queue,
+ void *data)
+{
+ struct wl_tbm_queue *client_queue = data;
+ struct wl_resource *wl_buffer;
+ tbm_surface_h buffer = NULL;
+
+ tbm_surface_queue_dequeue(surface_queue, &buffer);
+ WL_TBM_RETURN_IF_FAIL(buffer != NULL);
+
+ wl_buffer = wayland_tbm_server_get_resource(NULL, buffer);
+ if (wl_buffer) {
+ wl_buffer_send_release(wl_buffer);
+ return;
+ }
+
+ _server_queue_buffer_attach(client_queue, buffer);
+}
+
+struct wayland_tbm_server_queue *
+wayland_tbm_server_create_queue(struct wayland_tbm_server *tbm_srv,
+ tbm_surface_queue_h queue, uint32_t flags)
+{
+ struct wayland_tbm_server_queue *server_queue = NULL;
+
+ WL_TBM_RETURN_VAL_IF_FAIL(tbm_srv != NULL, NULL);
+ WL_TBM_RETURN_VAL_IF_FAIL(queue != NULL, NULL);
+
+ server_queue = calloc(1, sizeof(struct wayland_tbm_server_queue));
+ WL_TBM_RETURN_VAL_IF_FAIL(server_queue != NULL, NULL);
+
+ server_queue->tbm_srv = tbm_srv;
+ server_queue->tbm_queue = queue;
+ server_queue->flags = flags;
+ wl_list_insert(&tbm_srv->server_queue_list, &server_queue->link);
+
+ return server_queue;
+}
+
+int
+wayland_tbm_server_queue_set_surface(struct wayland_tbm_server_queue
+ *server_queue,
+ struct wl_resource *surface, uint32_t usage)
+{
+ struct wl_tbm_queue *client_queue = NULL;
+
+ WL_TBM_RETURN_VAL_IF_FAIL(server_queue != NULL, 1);
+
+ if (surface) {
+ client_queue = _find_tbm_queue(server_queue->tbm_srv, surface);
+ WL_TBM_RETURN_VAL_IF_FAIL(client_queue != NULL, 2);
+ }
+
+ if (client_queue == server_queue->client_queue)
+ return 0;
+
+ if (server_queue->client_queue) {
+ //Send deactivate;
+ server_queue->client_queue->server_queue = NULL;
+
+ tbm_surface_queue_remove_dequeuable_cb(server_queue->tbm_queue,
+ _server_queue_dequeuable_cb,
+ server_queue->client_queue);
+ wl_tbm_queue_send_deactive(server_queue->client_queue->resource);
+ }
+
+ if (client_queue) {
+ //Send activate and attach free buffer;
+ client_queue->server_queue = server_queue;
+
+ wl_tbm_queue_send_active(client_queue->resource, usage);
+ _server_queue_buffer_attach_free_queue(client_queue);
+ tbm_surface_queue_add_dequeuable_cb(server_queue->tbm_queue,
+ _server_queue_dequeuable_cb, client_queue);
+ }
+
+ server_queue->client_queue = client_queue;
+ return 0;
+}
+
+
#include <wayland-server.h>
#include <tbm_surface.h>
+#include <tbm_surface_queue.h>
struct wayland_tbm_server;
+struct wayland_tbm_server_queue;
struct wayland_tbm_server *
wayland_tbm_server_init(struct wl_display *display,
wayland_tbm_server_get_surface(struct wayland_tbm_server *tbm_srv,
struct wl_resource *resource);
+struct wl_resource *
+wayland_tbm_server_get_resource(struct wayland_tbm_server *tbm_srv,
+ tbm_surface_h surface);
+
+uint32_t
+wayland_tbm_server_get_flags(struct wayland_tbm_server *tbm_srv,
+ struct wl_resource *resource);
+
+struct wayland_tbm_server_queue *
+wayland_tbm_server_create_queue(struct wayland_tbm_server *tbm_srv,
+ tbm_surface_queue_h queue, uint32_t flags);
+
+
+int
+wayland_tbm_server_queue_set_surface(struct wayland_tbm_server_queue
+ *server_queue,
+ struct wl_resource *surface, uint32_t usage);
+
#ifdef __cplusplus
}
TESTS = \
tbm-server-test \
tbm-client-test \
- tbm-subcomp-test
+ tbm-subcomp-test \
+ tbm-server-queue-test \
+ tbm-client-queue-test
+
#bin_PROGRAMS = $(TESTS)
#check_PROGRAMS = $(TESTS)
CLIENT_TEST_CFLAGS = -I$(top_srcdir)/src/ $(AM_CFLAGS) $(WL_TBM_CLIENT_CFLAGS)
CLIENT_TEST_LDADD = ../src/libwayland-tbm-client.la $(WL_TBM_COMMON_LIBS) $(WL_TBM_CLIENT_LIBS)
+PROTOCOL_SOURCES = \
+ wayland-tbm-test-server-protocol.h \
+ wayland-tbm-test-client-protocol.h \
+ wayland-tbm-test-protocol.c
+
tbm_server_test_LDADD = $(SERVER_TEST_LDADD)
tbm_server_test_CFLAGS = $(SERVER_TEST_CFLAGS)
-tbm_server_test_SOURCES = tbm-server-test.c
+tbm_server_test_SOURCES = $(PROTOCOL_SOURCES) tbm-server-test.c
tbm_client_test_LDADD = $(CLIENT_TEST_LDADD)
tbm_client_test_CFLAGS = $(CLIENT_TEST_CFLAGS)
-tbm_client_test_SOURCES = tbm-client-test.c
+tbm_client_test_SOURCES = $(PROTOCOL_SOURCES) tbm-client-test.c
tbm_subcomp_test_LDADD = $(CLIENT_TEST_LDADD) $(SERVER_TEST_LDADD)
tbm_subcomp_test_CFLAGS = $(CLIENT_TEST_CFLAGS) $(SERVER_TEST_CFLAGS)
-tbm_subcomp_test_SOURCES = tbm-subcomp-test.c
+tbm_subcomp_test_SOURCES = $(PROTOCOL_SOURCES) tbm-subcomp-test.c
+
+tbm_server_queue_test_LDADD = $(SERVER_TEST_LDADD)
+tbm_server_queue_test_CFLAGS = $(SERVER_TEST_CFLAGS)
+tbm_server_queue_test_SOURCES = $(PROTOCOL_SOURCES) tbm-server-queue-test.c
+
+tbm_client_queue_test_LDADD = $(CLIENT_TEST_LDADD)
+tbm_client_queue_test_CFLAGS = $(CLIENT_TEST_CFLAGS)
+tbm_client_queue_test_SOURCES = $(PROTOCOL_SOURCES) tbm-client-queue-test.c
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#define WL_HIDE_DEPRECATED
+#include <wayland-client.h>
+#include <wayland-tbm-client.h>
+#include <wayland-tbm-int.h>
+
+#include <tbm_surface.h>
+#include <tbm_surface_queue.h>
+#include <tbm_surface_internal.h>
+
+#include "wayland-tbm-test-client-protocol.h"
+
+#define WL_APP_C_LOG(fmt, ...) fprintf (stderr, "[CLIENT(%d):%s] " fmt, getpid(), __func__, ##__VA_ARGS__)
+
+typedef struct {
+ struct wayland_tbm_client *tbm_client;
+ struct wl_tbm_test *wl_tbm_test;
+ struct wl_test_surface *surface;
+ tbm_surface_queue_h surface_queue;
+
+ int try_draw;
+} AppInfoClient;
+
+typedef struct {
+ tbm_surface_h buffer;
+ tbm_surface_queue_h surface_queue;
+ struct wl_buffer *wl_buffer;
+} AppBuffer;
+
+AppInfoClient gApp;
+static void _drawing_surface(AppInfoClient *app);
+
+static void
+_create_surface_and_queue(AppInfoClient *app)
+{
+ app->surface = wl_tbm_test_create_surface(app->wl_tbm_test);
+ app->surface_queue = wayland_tbm_client_create_surface_queue(app->tbm_client,
+ (struct wl_surface *)app->surface);
+ WL_APP_C_LOG("surface:%p, surface_queue:%p\n", app->surface,
+ app->surface_queue);
+ return;
+}
+
+static const int key_app_buffer;
+
+static struct wl_buffer *
+_get_wl_buffer(tbm_surface_h buffer)
+{
+ AppBuffer *app_buffer = NULL;
+
+ tbm_surface_internal_get_user_data(buffer,
+ (unsigned long)&key_app_buffer,
+ (void **)&app_buffer);
+
+ if (!app_buffer)
+ return (struct wl_buffer *)NULL;
+
+ return app_buffer->wl_buffer;
+}
+
+static void
+_set_wl_buffer(tbm_surface_h buffer, AppBuffer *app_buffer)
+{
+ tbm_surface_internal_add_user_data(buffer,
+ (unsigned long)&key_app_buffer,
+ NULL);
+ tbm_surface_internal_set_user_data(buffer,
+ (unsigned long)&key_app_buffer,
+ (void *)app_buffer);
+}
+
+static void
+_cb_wl_buffer_release_callback(void *data, struct wl_buffer *wl_buffer)
+{
+ AppBuffer *app_buffer = data;
+
+ tbm_surface_queue_release(app_buffer->surface_queue, app_buffer->buffer);
+ WL_APP_C_LOG("RELEASE queue:%p, tbm_surface:%p\n", app_buffer->surface_queue,
+ app_buffer->buffer);
+}
+
+static const struct wl_buffer_listener buffer_release_listener = {
+ _cb_wl_buffer_release_callback
+};
+
+static void
+_cb_wl_callback_surface_frame_done (void *data,
+ struct wl_callback *wl_callback,
+ uint32_t callback_data)
+{
+ AppInfoClient *app = data;
+
+ WL_APP_C_LOG("FRAME DONE\n");
+ _drawing_surface(app);
+ wl_callback_destroy(wl_callback);
+}
+
+static const struct wl_callback_listener surface_callback_listener = {
+ _cb_wl_callback_surface_frame_done
+};
+
+static void
+_drawing_surface(AppInfoClient *app)
+{
+ tbm_surface_queue_h surface_queue = app->surface_queue;
+ tbm_surface_h buffer = NULL;
+ tbm_surface_info_s info;
+ struct wl_buffer *wl_buffer;
+ struct wl_callback *wl_callback;
+
+ if (!tbm_surface_queue_can_dequeue(surface_queue, 0)) {
+ WL_APP_C_LOG("Wait free_buffer\n");
+ app->try_draw = 1;
+ return;
+ } else {
+ app->try_draw = 0;
+ }
+
+ tbm_surface_queue_dequeue(surface_queue, &buffer);
+ if (buffer == NULL) {
+ WL_APP_C_LOG("Failed to dequeue_buffer\n");
+ return;
+ }
+ //WL_APP_C_LOG("DEQUEUE queue:%p, tbm_surface:%p\n", app->surface_queue, buffer);
+
+ tbm_surface_map(buffer, TBM_OPTION_READ | TBM_OPTION_WRITE, &info);
+ WL_APP_C_LOG("\tDraw: buf:%p\n", buffer);
+ tbm_surface_unmap(buffer);
+ tbm_surface_queue_enqueue(app->surface_queue, buffer);
+ //WL_APP_C_LOG("ENQUEUE queue:%p, tbm_surface:%p\n", app->surface_queue, buffer);
+
+ tbm_surface_queue_acquire(app->surface_queue, &buffer);
+ //WL_APP_C_LOG("ACQUIRE queue:%p, tbm_surface:%p\n", app->surface_queue, buffer);
+ wl_buffer = _get_wl_buffer(buffer);
+ if (!wl_buffer) {
+ AppBuffer *app_buffer = calloc(1, sizeof(AppBuffer));
+
+ wl_buffer = wayland_tbm_client_create_buffer(app->tbm_client, buffer);
+ wl_buffer_add_listener(wl_buffer, &buffer_release_listener, (void *)app_buffer);
+
+ app_buffer->wl_buffer = wl_buffer;
+ app_buffer->surface_queue = app->surface_queue;
+ app_buffer->buffer = buffer;
+ _set_wl_buffer(buffer, app_buffer);
+ WL_APP_C_LOG("\tCreate NEW wl_buffer: buf:%p\n", buffer);
+ }
+
+ wl_callback = wl_test_surface_frame(app->surface);
+ wl_callback_add_listener(wl_callback, &surface_callback_listener, app);
+ wl_test_surface_attach(app->surface, wl_buffer);
+ //WL_APP_C_LOG("ATTACH wl_surface:%p, wl_buffer:%p\n", app->surface, wl_buffer);
+}
+
+static void
+_wl_registry_global_cb(void *data,
+ struct wl_registry *wl_registry,
+ uint32_t name,
+ const char *interface,
+ uint32_t version)
+{
+ AppInfoClient *app = (AppInfoClient *)data;
+
+ if (!strcmp(interface, "wl_tbm_test")) {
+ WL_APP_C_LOG("bind %s", interface);
+ app->wl_tbm_test = wl_registry_bind(wl_registry, name,
+ &wl_tbm_test_interface, 1);
+ }
+}
+
+static void
+_wl_registry_global_remove_cb(void *data,
+ struct wl_registry *wl_registry,
+ uint32_t name)
+{
+}
+
+static const struct wl_registry_listener wl_registry_impl = {
+ _wl_registry_global_cb,
+ _wl_registry_global_remove_cb,
+};
+
+int
+main(int argc, char *argv[])
+{
+ struct wl_display *dpy = NULL;
+ struct wl_registry *registry;
+ const char *dpy_name = NULL;
+ const static char *default_dpy_name = "queue";
+ int ret = 0;
+
+ if (argc > 1) {
+ dpy_name = argv[1];
+ } else {
+ dpy_name = default_dpy_name;
+ }
+
+ dpy = wl_display_connect(dpy_name);
+ if (!dpy) {
+ printf("[APP] failed to connect server\n");
+ return -1;
+ }
+
+ registry = wl_display_get_registry(dpy);
+ wl_registry_add_listener(registry, &wl_registry_impl, &gApp);
+ wl_display_roundtrip(dpy);
+ if (gApp.wl_tbm_test == NULL) {
+ WL_APP_C_LOG("fail to bind::wl_tbm_test");
+ return 0;
+ }
+
+ gApp.tbm_client = wayland_tbm_client_init(dpy);
+ if (!gApp.tbm_client) {
+ WL_APP_C_LOG("fail to wayland_tbm_client_init()\n");
+ goto finish;
+ }
+
+ _create_surface_and_queue(&gApp);
+ _drawing_surface(&gApp);
+ while (ret >= 0) {
+ ret = wl_display_dispatch(dpy);
+ if (gApp.try_draw)
+ _drawing_surface(&gApp);
+ }
+finish:
+ return 1;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define WL_HIDE_DEPRECATED
+#include <wayland-server.h>
+#include <wayland-tbm-server.h>
+#include <wayland-tbm-int.h>
+
+#include <tbm_surface.h>
+#include <tbm_surface_queue.h>
+
+#include "wayland-tbm-test-server-protocol.h"
+
+#define SERVER_LOG(fmt, ...) fprintf (stderr, "[SERVER(%d):%s] " fmt, getpid(), __func__, ##__VA_ARGS__)
+
+#define NUM_SCANOUT_BUFFER 3
+#define SCANOUT_BUFFER 0xFF30
+#define UPDATE_TIMER 20
+
+typedef struct _AppInfo AppInfo;
+typedef struct _AppSurface AppSurface;
+
+struct _AppInfo {
+ struct wl_display *dpy;
+ struct wl_list list_surface;
+ struct wl_global *wl_tbm_test;
+ struct wl_event_source *mode_change_timer; //for switch comp_mode
+ struct wl_event_source *update_timer; //vertual VSYNC
+ struct wl_event_source *idler; //For display update
+
+ struct wayland_tbm_server *tbm_server;
+
+ //For display
+ tbm_surface_queue_h scanout_queue;
+ struct wayland_tbm_server_queue *server_queue;
+
+ int need_update;
+ AppSurface *active_surface;
+ uint32_t update_count;
+
+ tbm_surface_h front, back;
+};
+
+struct _AppSurface {
+ struct wl_list link;
+ struct wl_resource *resource;
+ struct wl_resource *frame_callback;
+ AppInfo *app;
+
+ struct wl_resource *front_buffer;
+ struct wl_resource *update_buffer;
+ int need_frame_done;
+};
+
+AppInfo gApp;
+static void wl_tbm_test_idle_cb(void *data);
+
+static void
+_wl_test_surface_destroy(struct wl_resource *resource)
+{
+ SERVER_LOG("resource:%p\n", resource);
+}
+
+
+static void
+_wl_test_surface_destroy_cb(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ _wl_test_surface_destroy(resource);
+}
+
+static void
+_wl_test_surface_attach_cb(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *wl_buffer)
+{
+ AppInfo *app;
+ AppSurface *app_surface = wl_resource_get_user_data(resource);
+ struct wl_resource *old_wl_buffer = app_surface->update_buffer;
+
+ app = app_surface->app;
+ app_surface->update_buffer = wl_buffer;
+
+ if (!app->idler) {
+ app->idler = wl_event_loop_add_idle(wl_display_get_event_loop(app->dpy),
+ wl_tbm_test_idle_cb, app);
+ }
+
+ if (old_wl_buffer) {
+ wl_buffer_send_release(old_wl_buffer);
+ }
+}
+
+static void
+_wl_test_surface_frame_cb(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t callback)
+{
+ AppSurface *app_surface = wl_resource_get_user_data(resource);
+ struct wl_resource *done;
+
+ done = wl_resource_create(client, &wl_callback_interface, 1, callback);
+ if (app_surface->frame_callback)
+ wl_resource_destroy(app_surface->frame_callback);
+
+ app_surface->frame_callback = done;
+}
+
+static const struct wl_test_surface_interface wl_test_surface_impl = {
+ _wl_test_surface_destroy_cb,
+ _wl_test_surface_attach_cb,
+ _wl_test_surface_frame_cb
+};
+
+static void
+_wl_tbm_test_create_surface(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t surface)
+{
+ AppInfo *app = (AppInfo *)wl_resource_get_user_data(resource);
+ AppSurface *app_surface;
+ struct wl_resource *test_surface;
+
+ app_surface = calloc(1, sizeof(AppSurface));
+
+ test_surface = wl_resource_create(client, &wl_test_surface_interface, 1,
+ surface);
+ wl_resource_set_implementation(test_surface,
+ &wl_test_surface_impl,
+ app_surface,
+ _wl_test_surface_destroy);
+
+ wl_list_insert(&app->list_surface, &app_surface->link);
+
+ app_surface->app = app;
+ app_surface->resource = test_surface;
+ SERVER_LOG("Add surface:%p\n", test_surface);
+}
+
+static const struct wl_tbm_test_interface wl_tbm_test_impl = {
+ _wl_tbm_test_create_surface
+};
+
+static void
+wl_tbm_test_bind_cb(struct wl_client *client, void *data,
+ uint32_t version, uint32_t id)
+{
+ struct wl_resource *resource;
+
+ resource = wl_resource_create(client, &wl_tbm_test_interface, version, id);
+ wl_resource_set_implementation(resource, &wl_tbm_test_impl, data, NULL);
+
+ SERVER_LOG("client:%p, wl_tbm_test:%p\n", client, resource);
+}
+
+static int
+wl_tbm_test_mode_timer_cb(void *data)
+{
+// AppInfo* app = (AppInfo*)data;
+
+ return 1;
+}
+
+static int
+wl_tbm_test_update_timer_cb(void *data)
+{
+ AppInfo *app = (AppInfo *)data;
+ AppSurface *app_surface, *tmp;
+
+ if (!app->need_update) {
+ wl_event_source_timer_update(app->update_timer, UPDATE_TIMER);
+ return 1;
+ }
+ app->need_update = 0;
+
+ SERVER_LOG("VSYNC, PageFlipComplete~\n");
+ if (app->front) {
+ tbm_surface_queue_release(app->scanout_queue, app->front);
+ }
+
+ app->front = app->back;
+ app->back = NULL;
+
+ wl_list_for_each_reverse_safe(app_surface, tmp, &app->list_surface, link) {
+ if (app_surface->need_frame_done) {
+ app_surface->need_frame_done = 0;
+
+ if (app_surface->frame_callback) {
+ wl_callback_send_done(app_surface->frame_callback, 0);
+ wl_resource_destroy(app_surface->frame_callback);
+ app_surface->frame_callback = NULL;
+ }
+ }
+ }
+
+ wl_event_source_timer_update(app->update_timer, UPDATE_TIMER);
+ return 1;
+}
+
+static void
+wl_tbm_test_idle_cb(void *data)
+{
+ AppInfo *app = data;
+ AppSurface *app_surface, *tmp;
+ tbm_surface_h back = NULL;
+
+ SERVER_LOG("\n");
+
+ app->idler = NULL;
+
+ if (app->active_surface) {
+ if (app->active_surface->update_buffer) {
+ tbm_surface_h buffer;
+ uint32_t flags;
+ buffer = wayland_tbm_server_get_surface(NULL,
+ app->active_surface->update_buffer);
+ flags = wayland_tbm_server_get_flags(NULL, app->active_surface->update_buffer);
+ if (flags == SCANOUT_BUFFER) {
+ tbm_surface_queue_enqueue(app->scanout_queue, buffer);
+ app->active_surface->update_buffer = NULL;
+ app->active_surface->need_frame_done = 1;
+ SERVER_LOG("\tDirect present\n");
+ goto present;
+ }
+ }
+ }
+
+ //DO Composite
+ wl_list_for_each_reverse_safe(app_surface, tmp, &app->list_surface, link) {
+ tbm_surface_h buffer;
+ uint32_t flags;
+
+ if (app_surface->update_buffer == NULL)
+ continue;
+
+ buffer = wayland_tbm_server_get_surface(NULL, app_surface->update_buffer);
+ flags = wayland_tbm_server_get_flags(NULL, app_surface->update_buffer);
+
+ SERVER_LOG("Composite %p buffer:%p\n", app_surface, app_surface->update_buffer);
+ if (flags == SCANOUT_BUFFER) {
+ tbm_surface_queue_release(app->scanout_queue, buffer);
+ } else {
+ wl_buffer_send_release(app_surface->update_buffer);
+ }
+
+ app_surface->update_buffer = NULL;
+ app_surface->need_frame_done = 1;
+ }
+
+ tbm_surface_queue_dequeue(app->scanout_queue, &back);
+ if (back == NULL) {
+ SERVER_LOG("NO_FREE_BUFFER for comp\n");
+ return;
+ }
+ tbm_surface_queue_enqueue(app->scanout_queue, back);
+
+present:
+ app->update_count++;
+ if (!(app->update_count % 5)) {
+ SERVER_LOG("MODE_CHANGE active:%p\n", app->active_surface);
+ if (app->active_surface) {
+ wayland_tbm_server_queue_set_surface(app->server_queue,
+ NULL,
+ 0);
+ app->active_surface = NULL;
+ } else {
+ if (!wl_list_empty(&app->list_surface)) {
+ app_surface = wl_container_of(app->list_surface.next, app_surface, link);
+ if (wayland_tbm_server_queue_set_surface(app->server_queue,
+ app_surface->resource, 1)) {
+ SERVER_LOG("!! ERROR wayland_tbm_server_queue_set_surface\n");
+ } else {
+ app->active_surface = app_surface;
+ }
+ }
+ }
+ }
+
+ //Present to LCD
+ if (app->back) {
+ SERVER_LOG("SKIP this frame\n");
+ tbm_surface_queue_release(app->scanout_queue, app->back);
+ app->back = NULL;
+ }
+
+ tbm_surface_queue_acquire(app->scanout_queue, &app->back);
+ if (app->back) {
+ SERVER_LOG("need_update\n");
+ app->need_update = 1;
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct wl_display *dpy;
+ tbm_surface_h init_front;
+
+ const char *dpy_name = "queue";
+
+ dpy = wl_display_create();
+ if (!dpy) {
+ printf("[SRV] failed to create display\n");
+ return -1;
+ }
+
+ wl_display_add_socket(dpy, dpy_name);
+ printf("[SRV] wl_display : %s\n", dpy_name);
+
+ wl_list_init(&gApp.list_surface);
+
+ setenv("WL_TBM_EMBEDDED_SERVER", "true", 1);
+ gApp.dpy = dpy;
+ gApp.tbm_server = wayland_tbm_server_init(dpy, NULL, -1, 0);
+ if (!gApp.tbm_server) {
+ printf("[SRV] failed to tbm_server init\n");
+ wl_display_destroy(dpy);
+ return -1;
+ }
+
+ gApp.wl_tbm_test = wl_global_create(dpy, &wl_tbm_test_interface, 1, &gApp,
+ wl_tbm_test_bind_cb);
+
+ gApp.scanout_queue = tbm_surface_queue_create(NUM_SCANOUT_BUFFER, 100, 100,
+ TBM_FORMAT_ABGR8888, 0);
+ gApp.server_queue = wayland_tbm_server_create_queue(gApp.tbm_server,
+ gApp.scanout_queue, SCANOUT_BUFFER);
+
+ tbm_surface_queue_dequeue(gApp.scanout_queue, &init_front);
+ /*TODO : Clear Screen*/
+ tbm_surface_queue_enqueue(gApp.scanout_queue, init_front);
+ tbm_surface_queue_acquire(gApp.scanout_queue, &init_front);
+ gApp.front = init_front;
+
+ gApp.mode_change_timer = wl_event_loop_add_timer(wl_display_get_event_loop(dpy),
+ wl_tbm_test_mode_timer_cb, &gApp);
+ gApp.update_timer = wl_event_loop_add_timer(wl_display_get_event_loop(dpy),
+ wl_tbm_test_update_timer_cb, &gApp);
+ wl_event_source_timer_update(gApp.update_timer, UPDATE_TIMER);
+
+ wl_display_run(dpy);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this
+ * software and its documentation for any purpose is hereby granted
+ * without fee, provided that\n the above copyright notice appear in
+ * all copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * the copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+
+#ifndef TBM_TEST_CLIENT_PROTOCOL_H
+#define TBM_TEST_CLIENT_PROTOCOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+struct wl_client;
+struct wl_resource;
+
+struct wl_buffer;
+struct wl_callback;
+struct wl_tbm_test;
+struct wl_test_surface;
+
+extern const struct wl_interface wl_tbm_test_interface;
+extern const struct wl_interface wl_test_surface_interface;
+
+#define WL_TBM_TEST_CREATE_SURFACE 0
+
+#define WL_TBM_TEST_CREATE_SURFACE_SINCE_VERSION 1
+
+static inline void
+wl_tbm_test_set_user_data(struct wl_tbm_test *wl_tbm_test, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) wl_tbm_test, user_data);
+}
+
+static inline void *
+wl_tbm_test_get_user_data(struct wl_tbm_test *wl_tbm_test)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) wl_tbm_test);
+}
+
+static inline void
+wl_tbm_test_destroy(struct wl_tbm_test *wl_tbm_test)
+{
+ wl_proxy_destroy((struct wl_proxy *) wl_tbm_test);
+}
+
+static inline struct wl_test_surface *
+wl_tbm_test_create_surface(struct wl_tbm_test *wl_tbm_test)
+{
+ struct wl_proxy *surface;
+
+ surface = wl_proxy_marshal_constructor((struct wl_proxy *) wl_tbm_test,
+ WL_TBM_TEST_CREATE_SURFACE, &wl_test_surface_interface, NULL);
+
+ return (struct wl_test_surface *) surface;
+}
+
+#define WL_TEST_SURFACE_DESTROY 0
+#define WL_TEST_SURFACE_ATTACH 1
+#define WL_TEST_SURFACE_FRAME 2
+
+#define WL_TEST_SURFACE_DESTROY_SINCE_VERSION 1
+#define WL_TEST_SURFACE_ATTACH_SINCE_VERSION 1
+#define WL_TEST_SURFACE_FRAME_SINCE_VERSION 1
+
+static inline void
+wl_test_surface_set_user_data(struct wl_test_surface *wl_test_surface,
+ void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) wl_test_surface, user_data);
+}
+
+static inline void *
+wl_test_surface_get_user_data(struct wl_test_surface *wl_test_surface)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) wl_test_surface);
+}
+
+static inline void
+wl_test_surface_destroy(struct wl_test_surface *wl_test_surface)
+{
+ wl_proxy_marshal((struct wl_proxy *) wl_test_surface,
+ WL_TEST_SURFACE_DESTROY);
+
+ wl_proxy_destroy((struct wl_proxy *) wl_test_surface);
+}
+
+static inline void
+wl_test_surface_attach(struct wl_test_surface *wl_test_surface,
+ struct wl_buffer *buffer)
+{
+ wl_proxy_marshal((struct wl_proxy *) wl_test_surface,
+ WL_TEST_SURFACE_ATTACH, buffer);
+}
+
+static inline struct wl_callback *
+wl_test_surface_frame(struct wl_test_surface *wl_test_surface)
+{
+ struct wl_proxy *callback;
+
+ callback = wl_proxy_marshal_constructor((struct wl_proxy *) wl_test_surface,
+ WL_TEST_SURFACE_FRAME, &wl_callback_interface, NULL);
+
+ return (struct wl_callback *) callback;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this
+ * software and its documentation for any purpose is hereby granted
+ * without fee, provided that\n the above copyright notice appear in
+ * all copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * the copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+extern const struct wl_interface wl_buffer_interface;
+extern const struct wl_interface wl_callback_interface;
+extern const struct wl_interface wl_test_surface_interface;
+
+static const struct wl_interface *types[] = {
+ &wl_test_surface_interface,
+ &wl_buffer_interface,
+ &wl_callback_interface,
+};
+
+static const struct wl_message wl_tbm_test_requests[] = {
+ { "create_surface", "n", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_tbm_test_interface = {
+ "wl_tbm_test", 1,
+ 1, wl_tbm_test_requests,
+ 0, NULL,
+};
+
+static const struct wl_message wl_test_surface_requests[] = {
+ { "destroy", "", types + 0 },
+ { "attach", "o", types + 1 },
+ { "frame", "n", types + 2 },
+};
+
+WL_EXPORT const struct wl_interface wl_test_surface_interface = {
+ "wl_surface", 1,
+ 3, wl_test_surface_requests,
+ 0, NULL,
+};
+
--- /dev/null
+/*
+ * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+ *
+ * Permission to use, copy, modify, distribute, and sell this
+ * software and its documentation for any purpose is hereby granted
+ * without fee, provided that\n the above copyright notice appear in
+ * all copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * the copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+
+#ifndef TBM_TEST_SERVER_PROTOCOL_H
+#define TBM_TEST_SERVER_PROTOCOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server.h"
+
+struct wl_client;
+struct wl_resource;
+
+struct wl_buffer;
+struct wl_callback;
+struct wl_tbm_test;
+struct wl_test_surface;
+
+extern const struct wl_interface wl_tbm_test_interface;
+extern const struct wl_interface wl_test_surface_interface;
+
+struct wl_tbm_test_interface {
+ /**
+ * create_surface - (none)
+ * @surface: (none)
+ */
+ void (*create_surface)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t surface);
+};
+
+
+struct wl_test_surface_interface {
+ /**
+ * destroy - (none)
+ */
+ void (*destroy)(struct wl_client *client,
+ struct wl_resource *resource);
+ /**
+ * attach - (none)
+ * @buffer: (none)
+ */
+ void (*attach)(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *buffer);
+ /**
+ * frame - (none)
+ * @callback: (none)
+ */
+ void (*frame)(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t callback);
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="tbm_test">
+
+ <copyright>
+ Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+ Permission to use, copy, modify, distribute, and sell this
+ software and its documentation for any purpose is hereby granted
+ without fee, provided that\n the above copyright notice appear in
+ all copies and that both that copyright notice and this permission
+ notice appear in supporting documentation, and that the name of
+ the copyright holders not be used in advertising or publicity
+ pertaining to distribution of the software without specific,
+ written prior permission. The copyright holders make no
+ representations about the suitability of this software for any
+ purpose. It is provided "as is" without express or implied
+ warranty.
+
+ THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ THIS SOFTWARE.
+ </copyright>
+
+ <interface name="wl_tbm_test" version="1">
+ <request name="create_surface">
+ <arg name="surface" type="new_id" interface="wl_test_surface"/>
+ </request>
+ </interface>
+
+ <interface name="wl_test_surface" version="1">
+ <request name="destroy" type="destructor">
+ </request>
+ <request name="attach">
+ <arg name="buffer" type="object" interface="wl_buffer"/>
+ </request>
+ <request name="frame">
+ <arg name="callback" type="new_id" interface="wl_callback"/>
+ </request>
+ </interface>
+</protocol>