Support fixed scanout buffer 87/62087/1 accepted/tizen/ivi/20160315.002520 accepted/tizen/mobile/20160315.002430 accepted/tizen/tv/20160315.002444 accepted/tizen/wearable/20160315.002501 submit/tizen/20160314.083728
authorSangjin Lee <lsj119@samsung.com>
Mon, 7 Mar 2016 00:50:57 +0000 (09:50 +0900)
committerSangjin Lee <lsj119@samsung.com>
Mon, 14 Mar 2016 08:21:39 +0000 (17:21 +0900)
Change-Id: I4cc6090652f69f69d823fbfa089468c2125e22e6

12 files changed:
protocol/wayland-tbm.xml
src/wayland-tbm-client.c
src/wayland-tbm-client.h
src/wayland-tbm-server.c
src/wayland-tbm-server.h
test/Makefile.am
test/tbm-client-queue-test.c [new file with mode: 0644]
test/tbm-server-queue-test.c [new file with mode: 0644]
test/wayland-tbm-test-client-protocol.h [new file with mode: 0644]
test/wayland-tbm-test-protocol.c [new file with mode: 0644]
test/wayland-tbm-test-server-protocol.h [new file with mode: 0644]
test/wayland-tbm-test.xml [new file with mode: 0644]

index 2670075..9ba342c 100644 (file)
       <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>
index 80e1d21..e6866d8 100644 (file)
@@ -35,6 +35,7 @@ DEALINGS IN THE SOFTWARE.
 #include <fcntl.h>
 
 #include <tbm_surface.h>
+#include <tbm_surface_queue.h>
 #include <tbm_surface_internal.h>
 
 #include "wayland-tbm-client.h"
@@ -50,6 +51,35 @@ struct wayland_tbm_client {
        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,
@@ -198,6 +228,15 @@ wayland_tbm_client_create_buffer(struct wayland_tbm_client *tbm_client,
        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");
@@ -253,7 +292,7 @@ wayland_tbm_client_create_buffer(struct wayland_tbm_client *tbm_client,
                                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
@@ -265,7 +304,7 @@ wayland_tbm_client_create_buffer(struct wayland_tbm_client *tbm_client,
                                                 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) {
@@ -278,6 +317,13 @@ wayland_tbm_client_create_buffer(struct wayland_tbm_client *tbm_client,
                        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:
@@ -318,3 +364,387 @@ _wayland_tbm_client_get_wl_tbm(struct wayland_tbm_client *tbm_client)
        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;
+}
+
index 2da021d..0186b68 100644 (file)
@@ -36,6 +36,7 @@ extern "C" {
 
 #include <wayland-client.h>
 #include <tbm_surface.h>
+#include <tbm_surface_queue.h>
 
 struct wayland_tbm_client;
 
@@ -53,8 +54,12 @@ void
 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
index 11d8a0f..903ecc2 100644 (file)
@@ -56,11 +56,16 @@ struct wayland_tbm_server {
        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;
 };
 
@@ -71,8 +76,42 @@ struct wayland_tbm_client_resource {
        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
 };
@@ -82,6 +121,14 @@ _destroy_buffer(struct wl_resource *resource)
 {
        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);
@@ -93,52 +140,35 @@ _buffer_destroy(struct wl_client *client, struct wl_resource *resource)
        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;
                        }
                }
@@ -147,14 +177,52 @@ _create_buffer(struct wl_client *client, struct wl_resource *resource,
        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
@@ -384,10 +452,20 @@ _wayland_tbm_server_impl_create_buffer_with_fd(struct wl_client *client,
        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
@@ -468,6 +546,7 @@ wayland_tbm_server_init(struct wl_display *display, const char *device_name,
 
        /* 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);
@@ -476,11 +555,16 @@ wayland_tbm_server_init(struct wl_display *display, const char *device_name,
                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;
 }
 
@@ -512,6 +596,38 @@ wayland_tbm_server_get_surface(struct wayland_tbm_server *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)
 {
@@ -521,3 +637,300 @@ 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;
+}
+
+
index a7c7071..530f6d6 100644 (file)
@@ -36,8 +36,10 @@ extern "C" {
 
 #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,
@@ -55,6 +57,24 @@ tbm_surface_h
 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
 }
index c433812..e5be06a 100644 (file)
@@ -1,7 +1,10 @@
 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)
@@ -12,14 +15,27 @@ SERVER_TEST_LDADD = ../src/libwayland-tbm-server.la $(WL_TBM_COMMON_LIBS) $(WL_T
 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
diff --git a/test/tbm-client-queue-test.c b/test/tbm-client-queue-test.c
new file mode 100644 (file)
index 0000000..c3f265d
--- /dev/null
@@ -0,0 +1,230 @@
+#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;
+}
diff --git a/test/tbm-server-queue-test.c b/test/tbm-server-queue-test.c
new file mode 100644 (file)
index 0000000..d93e498
--- /dev/null
@@ -0,0 +1,345 @@
+#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;
+}
diff --git a/test/wayland-tbm-test-client-protocol.h b/test/wayland-tbm-test-client-protocol.h
new file mode 100644 (file)
index 0000000..333c89d
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 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
diff --git a/test/wayland-tbm-test-protocol.c b/test/wayland-tbm-test-protocol.c
new file mode 100644 (file)
index 0000000..10ba05d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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,
+};
+
diff --git a/test/wayland-tbm-test-server-protocol.h b/test/wayland-tbm-test-server-protocol.h
new file mode 100644 (file)
index 0000000..d5eaaad
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * 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
diff --git a/test/wayland-tbm-test.xml b/test/wayland-tbm-test.xml
new file mode 100644 (file)
index 0000000..85f47d3
--- /dev/null
@@ -0,0 +1,45 @@
+<?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>