summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuhiko Tanibata <ntanibata@jp.adit-jv.com>2015-12-16 19:43:21 +0900
committerNobuhiko Tanibata <nobuhiko_tanibata@xddp.denso.co.jp>2015-12-23 00:11:34 +0900
commitad71697d1d4e225e0561ee3ba57822b18dfaccd9 (patch)
treee4e985654dca5d2382c306a1ffe0f5df40d582b2
parentd3b0f7fb92af6ff10f1343f283bacab54eecc81f (diff)
downloadwayland-ivi-extension-ad71697d1d4e225e0561ee3ba57822b18dfaccd9.tar.gz
ivi-share: Initial implementation of ivi_share protocol.
It uses libgbm to handle id to share graphic buffer inter processes. Signed-off-by: Nobuhiko Tanibata <ntanibata@jp.adit-jv.com>
-rw-r--r--README13
-rw-r--r--protocol/CMakeLists.txt27
-rw-r--r--weston-ivi-shell/CMakeLists.txt37
-rwxr-xr-xweston-ivi-shell/src/ivi-extension.c10
-rw-r--r--weston-ivi-shell/src/ivi-share-gbm.c169
-rw-r--r--weston-ivi-shell/src/ivi-share.c733
-rw-r--r--weston-ivi-shell/src/ivi-share.h76
7 files changed, 1065 insertions, 0 deletions
diff --git a/README b/README
index a9327fe..8f756ae 100644
--- a/README
+++ b/README
@@ -2,6 +2,7 @@ Sections in this file describe:
- How to build
- Example applications
- How to test
+- Features
How to build on different platforms
====================================
@@ -60,3 +61,15 @@ How to test
2. After starting up Weston run the testsuite.
Example: <your installation path>/bin/ivi-layermanagement-api-test
<your installation path>/bin/ivi-input-api-test
+
+Features
+====================================
+ivi_share protocol:
+ ivi-controller provides ivi_share protocol to share native buffer of other clients.
+ A application which shared native buffer can create texture from it using EGL extension
+ API (eglCreateImageKHR) and GL extension API (glEGLImageTargetTexture2DOES).
+ And the texture can manipulate in your rendering scene.
+ Example: <your installtion path>/bin/simple-ivi-share
+
+ To build this feature, add the following line into toolchain file.
+ option (IVI_SHARE "Enable ivi_share protocol" ON)
diff --git a/protocol/CMakeLists.txt b/protocol/CMakeLists.txt
index 6842131..492ab1d 100644
--- a/protocol/CMakeLists.txt
+++ b/protocol/CMakeLists.txt
@@ -99,6 +99,30 @@ add_custom_command(
DEPENDS ${CMAKE_SOURCE_DIR}/protocol/ivi-input.xml
)
+add_custom_command(
+ OUTPUT ivi-share-client-protocol.h
+ COMMAND ${WAYLAND_SCANNER_EXECUTABLE} client-header
+ < ${CMAKE_SOURCE_DIR}/protocol/ivi-share.xml
+ > ${CMAKE_CURRENT_BINARY_DIR}/ivi-share-client-protocol.h
+ DEPENDS ${CMAKE_SOURCE_DIR}/protocol/ivi-share.xml
+)
+
+add_custom_command(
+ OUTPUT ivi-share-server-protocol.h
+ COMMAND ${WAYLAND_SCANNER_EXECUTABLE} server-header
+ < ${CMAKE_SOURCE_DIR}/protocol/ivi-share.xml
+ > ${CMAKE_CURRENT_BINARY_DIR}/ivi-share-server-protocol.h
+ DEPENDS ${CMAKE_SOURCE_DIR}/protocol/ivi-share.xml
+)
+
+add_custom_command(
+ OUTPUT ivi-share-protocol.c
+ COMMAND ${WAYLAND_SCANNER_EXECUTABLE} code
+ < ${CMAKE_SOURCE_DIR}/protocol/ivi-share.xml
+ > ${CMAKE_CURRENT_BINARY_DIR}/ivi-share-protocol.c
+ DEPENDS ${CMAKE_SOURCE_DIR}/protocol/ivi-share.xml
+)
+
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${WAYLAND_CLIENT_INCLUDE_DIRS}
@@ -120,6 +144,9 @@ add_library(${PROJECT_NAME} STATIC
${CMAKE_CURRENT_BINARY_DIR}/ivi-input-client-protocol.h
${CMAKE_CURRENT_BINARY_DIR}/ivi-input-server-protocol.h
${CMAKE_CURRENT_BINARY_DIR}/ivi-input-protocol.c
+ ${CMAKE_CURRENT_BINARY_DIR}/ivi-share-client-protocol.h
+ ${CMAKE_CURRENT_BINARY_DIR}/ivi-share-server-protocol.h
+ ${CMAKE_CURRENT_BINARY_DIR}/ivi-share-protocol.c
)
set_target_properties(${PROJECT_NAME} PROPERTIES
diff --git a/weston-ivi-shell/CMakeLists.txt b/weston-ivi-shell/CMakeLists.txt
index c2664df..d90a002 100644
--- a/weston-ivi-shell/CMakeLists.txt
+++ b/weston-ivi-shell/CMakeLists.txt
@@ -27,6 +27,17 @@ pkg_check_modules(WAYLAND_SERVER wayland-server>=1.9.0 REQUIRED)
pkg_check_modules(WESTON weston>=1.9.0 REQUIRED)
pkg_check_modules(PIXMAN pixman-1 REQUIRED)
+find_package(Threads REQUIRED)
+if (IVI_SHARE)
+ pkg_check_modules(GBM gbm REQUIRED)
+ pkg_check_modules(LIBDRM libdrm REQUIRED)
+ ADD_DEFINITIONS("-DIVI_SHARE_ENABLE")
+ SET(BUFFER_SHARING_SRC_FILES
+ src/ivi-share.c
+ src/ivi-share-gbm.c
+ )
+endif (IVI_SHARE)
+
GET_TARGET_PROPERTY(IVI_EXTENSION_INCLUDE_DIRS ivi-extension-protocol INCLUDE_DIRECTORIES)
include_directories(
@@ -46,6 +57,7 @@ link_directories(
add_library(${PROJECT_NAME} MODULE
src/ivi-extension.c src/ivi-controller-impl.c
src/bitmap.c
+ ${BUFFER_SHARING_SRC_FILES}
)
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")
@@ -62,6 +74,31 @@ set(LIBS
${WAYLAND_SERVER_LIBRARIES}
)
+if (IVI_SHARE)
+ include_directories(
+ ${include_directories}
+ ${GBM_INCLUDE_DIRS}
+ ${LIBDRM_INCLUDE_DIRS}
+ )
+
+ link_directories(
+ ${link_directories}
+ ${GBM_LIBRARY_DIRS}
+ ${LIBDRM_LIBRARY_DIRS}
+ )
+
+ add_dependencies(${PROJECT_NAME}
+ ${GBM_LIBRARIES}
+ ${LIBDRM_LIBRARIES}
+ )
+
+ set(LIBS
+ ${LIBS}
+ ${GBM_LIBRARIES}
+ ${LIBDRM_LIBRARIES}
+ )
+endif (IVI_SHARE)
+
set(CMAKE_C_LDFLAGS "-module -avoid-version")
target_link_libraries(${PROJECT_NAME} ${LIBS})
diff --git a/weston-ivi-shell/src/ivi-extension.c b/weston-ivi-shell/src/ivi-extension.c
index d437c87..7014cce 100755
--- a/weston-ivi-shell/src/ivi-extension.c
+++ b/weston-ivi-shell/src/ivi-extension.c
@@ -23,6 +23,9 @@
#include "ivi-controller-interface.h"
#include "ivi-extension.h"
#include "ivi-controller-impl.h"
+#ifdef IVI_SHARE_ENABLE
+# include "ivi-share.h"
+#endif
struct ivi_controller_shell {
struct ivishell base;
@@ -759,6 +762,13 @@ controller_module_init(struct weston_compositor *compositor,
init_ivi_shell(compositor, &controller_shell->base);
+#ifdef IVI_SHARE_ENABLE
+ if (setup_buffer_sharing(compositor, interface) < 0) {
+ free(controller_shell);
+ return -1;
+ }
+#endif
+
if (setup_ivi_controller_server(compositor, &controller_shell->base)) {
free(controller_shell);
return -1;
diff --git a/weston-ivi-shell/src/ivi-share-gbm.c b/weston-ivi-shell/src/ivi-share-gbm.c
new file mode 100644
index 0000000..310270b
--- /dev/null
+++ b/weston-ivi-shell/src/ivi-share-gbm.c
@@ -0,0 +1,169 @@
+/**************************************************************************
+ *
+ * Copyright 2015 Codethink Ltd
+ * Copyright (C) 2015 Advanced Driver Information Technology Joint Venture GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ****************************************************************************/
+#include <stdio.h>
+#include <stdint.h>
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <gbm.h>
+#include <libudev.h>
+
+#include "wayland-server.h"
+#include "weston/compositor.h"
+#include "ivi-share-server-protocol.h"
+#include "ivi-controller-interface.h"
+#include "ivi-share.h"
+
+static uint32_t nativesurface_name;
+
+/* copied from libinput-seat.h of weston-1.9.0 */
+struct udev_input {
+ struct libinput *libinput;
+ struct wl_event_source *libinput_source;
+ struct weston_compositor *compositor;
+ int suspended;
+};
+
+/* copied from compositor-drm.c of weston-1.9.0 */
+struct drm_backend {
+ struct weston_backend base;
+ struct weston_compositor *compositor;
+
+ struct udev *udev;
+ struct wl_event_source *drm_source;
+
+ struct udev_monitor *udev_monitor;
+ struct wl_event_source *udev_drm_source;
+
+ struct {
+ int id;
+ int fd;
+ char *filename;
+ } drm;
+ struct gbm_device *gbm;
+ uint32_t *crtcs;
+ int num_crtcs;
+ uint32_t crtc_allocator;
+ uint32_t connector_allocator;
+ struct wl_listener session_listener;
+ uint32_t format;
+
+ /* we need these parameters in order to not fail drmModeAddFB2()
+ * due to out of bounds dimensions, and then mistakenly set
+ * sprites_are_broken:
+ */
+ uint32_t min_width, max_width;
+ uint32_t min_height, max_height;
+ int no_addfb2;
+
+ struct wl_list sprite_list;
+ int sprites_are_broken;
+ int sprites_hidden;
+
+ int cursors_are_broken;
+
+ int use_pixman;
+
+ uint32_t prev_state;
+
+ struct udev_input input;
+
+ int32_t cursor_width;
+ int32_t cursor_height;
+};
+
+uint32_t
+get_buffer_name(struct weston_surface *surface,
+ struct ivi_shell_share_ext *shell_ext)
+{
+ (void)surface;
+ return nativesurface_name;
+}
+
+uint32_t
+update_buffer_nativesurface(struct ivi_share_nativesurface *p_nativesurface,
+ struct ivi_shell_share_ext *shell_ext)
+{
+ if (NULL == p_nativesurface || NULL == p_nativesurface->surface) {
+ return IVI_SHAREBUFFER_NOT_AVAILABLE;
+ }
+
+ struct drm_backend *backend =
+ (struct drm_backend*)p_nativesurface->surface->compositor->backend;
+ if (NULL == backend) {
+ return IVI_SHAREBUFFER_NOT_AVAILABLE;
+ }
+
+ struct weston_buffer *buffer = p_nativesurface->surface->buffer_ref.buffer;
+ if (!buffer) {
+ return IVI_SHAREBUFFER_NOT_AVAILABLE;
+ }
+
+ struct gbm_bo *bo = gbm_bo_import(backend->gbm, GBM_BO_IMPORT_WL_BUFFER,
+ buffer->legacy_buffer, GBM_BO_USE_SCANOUT);
+ if (!bo) {
+ weston_log("failed to import gbm_bo\n");
+ return IVI_SHAREBUFFER_INVALID;
+ }
+
+ struct drm_gem_flink flink = {0};
+ flink.handle = gbm_bo_get_handle(bo).u32;
+ if (drmIoctl(gbm_device_get_fd(backend->gbm), DRM_IOCTL_GEM_FLINK, &flink) != 0) {
+ weston_log("gem_flink: returned non-zero failed\n");
+ gbm_bo_destroy(bo);
+ return IVI_SHAREBUFFER_INVALID;
+ }
+
+ uint32_t name = flink.name;
+ uint32_t width = gbm_bo_get_width(bo);
+ uint32_t height = gbm_bo_get_height(bo);
+ uint32_t stride = gbm_bo_get_stride(bo);
+ uint32_t format = IVI_SHARE_SURFACE_FORMAT_ARGB8888;
+ uint32_t ret = IVI_SHAREBUFFER_STABLE;
+
+ nativesurface_name = name;
+
+ if (name != p_nativesurface->name) {
+ ret |= IVI_SHAREBUFFER_DAMAGE;
+ }
+ if (width != p_nativesurface->width) {
+ ret |= IVI_SHAREBUFFER_CONFIGURE;
+ }
+ if (height != p_nativesurface->height) {
+ ret |= IVI_SHAREBUFFER_CONFIGURE;
+ }
+ if (stride != p_nativesurface->stride) {
+ ret |= IVI_SHAREBUFFER_CONFIGURE;
+ }
+
+ p_nativesurface->name = name;
+ p_nativesurface->width = width;
+ p_nativesurface->height = height;
+ p_nativesurface->stride = stride;
+ p_nativesurface->format = format;
+
+ gbm_bo_destroy(bo);
+
+ return ret;
+}
diff --git a/weston-ivi-shell/src/ivi-share.c b/weston-ivi-shell/src/ivi-share.c
new file mode 100644
index 0000000..dedbf45
--- /dev/null
+++ b/weston-ivi-shell/src/ivi-share.c
@@ -0,0 +1,733 @@
+/**************************************************************************
+ *
+ * Copyright 2015 Codethink Ltd
+ * Copyright (C) 2015 Advanced Driver Information Technology Joint Venture GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ****************************************************************************/
+#include <stdio.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <assert.h>
+
+#include "ivi-share.h"
+#include "ivi-share-server-protocol.h"
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({ \
+ const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+#endif
+
+struct ivi_share_nativesurface_client_link
+{
+ struct wl_resource *resource;
+ struct wl_client *client;
+ bool firstSendConfigureComp;
+ struct wl_list link; /* ivi_share_nativesurface link */
+ struct ivi_share_nativesurface *parent;
+};
+
+struct shell_surface
+{
+ struct wl_resource *resource;
+ struct wl_listener surface_destroy_listener;
+ struct weston_surface *surface;
+ uint32_t surface_id;
+ struct wl_list link; /* ivi_shell_share_ext link */
+};
+
+struct redirect_target {
+ struct wl_client *client;
+ struct wl_resource *resource;
+ struct wl_resource *target_resource;
+ uint32_t id;
+ struct wl_list link;
+};
+
+struct update_sharing_surface_content {
+ struct wl_listener listener;
+ struct ivi_shell_share_ext *shell_ext;
+};
+
+static void
+free_nativesurface(struct ivi_share_nativesurface *nativesurf)
+{
+ if (NULL == nativesurf) {
+ return;
+ }
+
+ nativesurf->surface_destroy_listener.notify = NULL;
+ wl_list_remove(&nativesurf->surface_destroy_listener.link);
+ free(nativesurf);
+}
+
+static void
+share_surface_destroy(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct ivi_share_nativesurface_client_link *client_link =
+ wl_resource_get_user_data(resource);
+ if (NULL == client_link) {
+ weston_log("share_surface does not have user data\n");
+ return;
+ }
+
+ wl_resource_destroy(resource);
+}
+
+static struct weston_seat *
+get_weston_seat(struct weston_compositor *compositor,
+ struct ivi_share_nativesurface_client_link *client_link)
+{
+ struct weston_seat *link = NULL;
+ struct wl_client *target_client =
+ wl_resource_get_client(client_link->parent->surface->resource);
+
+ wl_list_for_each(link, &compositor->seat_list, link) {
+ struct wl_resource *res;
+ wl_list_for_each(res, &link->base_resource_list, link) {
+ struct wl_client *client = wl_resource_get_client(res);
+ if (target_client == client && link->touch_state != NULL) {
+ return link;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static uint32_t
+get_event_time()
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
+}
+
+static void
+share_surface_redirect_touch_down(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t serial,
+ int32_t id,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ struct ivi_share_nativesurface_client_link *client_link = wl_resource_get_user_data(resource);
+ struct weston_seat *seat = NULL;
+ struct wl_resource *target_resource = NULL;
+ uint32_t time = get_event_time();
+ struct redirect_target *redirect_target = NULL;
+ struct wl_resource *surface_resource;
+
+ if (client_link->parent == NULL) {
+ weston_log("share_surface_redirect_touch_down: No parent surface\n");
+ return;
+ }
+ surface_resource = client_link->parent->surface->resource;
+
+ seat = get_weston_seat(client_link->parent->shell_ext->wc, client_link);
+ if (seat == NULL || seat->touch_state == NULL) {
+ return;
+ }
+
+ wl_list_for_each(target_resource, &seat->touch_state->resource_list, link) {
+ if (wl_resource_get_client(target_resource) == wl_resource_get_client(surface_resource)) {
+ uint32_t new_serial =
+ wl_display_next_serial(client_link->parent->shell_ext->wc->wl_display);
+ wl_touch_send_down(target_resource, new_serial, time, surface_resource, id, x, y);
+ break;
+ }
+ }
+
+ redirect_target = malloc(sizeof *redirect_target);
+ redirect_target->client = client;
+ redirect_target->resource = resource;
+ redirect_target->target_resource = target_resource;
+ redirect_target->id = id;
+ wl_list_insert(&client_link->parent->shell_ext->list_redirect_target, &redirect_target->link);
+}
+
+static void
+share_surface_redirect_touch_up(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t serial,
+ int32_t id)
+{
+ struct ivi_share_nativesurface_client_link *client_link = wl_resource_get_user_data(resource);
+ struct redirect_target *redirect_target = NULL;
+ struct redirect_target *next = NULL;
+ uint32_t new_serial = wl_display_next_serial(client_link->parent->shell_ext->wc->wl_display);
+ uint32_t time = get_event_time();
+
+ wl_list_for_each_safe(redirect_target, next, &client_link->parent->shell_ext->list_redirect_target, link) {
+ if (client == redirect_target->client &&
+ resource == redirect_target->resource &&
+ id == redirect_target->id) {
+ wl_touch_send_up(redirect_target->target_resource, new_serial, time, id);
+ wl_list_remove(&redirect_target->link);
+ free(redirect_target);
+ break;
+ }
+ }
+}
+
+static void
+share_surface_redirect_touch_motion(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t id,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ struct ivi_share_nativesurface_client_link *client_link = wl_resource_get_user_data(resource);
+ struct weston_seat *seat = NULL;
+ struct wl_resource *target_resource = NULL;
+ uint32_t time = get_event_time();
+ struct wl_resource *surface_resource;
+
+ if (client_link->parent == NULL) {
+ weston_log("share_surface_redirect_touch_motion: No parent surface\n");
+ return;
+ }
+ surface_resource = client_link->parent->surface->resource;
+
+ seat = get_weston_seat(client_link->parent->shell_ext->wc, client_link);
+ if (seat == NULL || seat->touch_state == NULL) {
+ return;
+ }
+
+ wl_list_for_each(target_resource, &seat->touch_state->resource_list, link) {
+ if (wl_resource_get_client(target_resource) == wl_resource_get_client(surface_resource)) {
+ wl_touch_send_motion(target_resource, time, id, x, y);
+ break;
+ }
+ }
+}
+
+static void
+share_surface_redirect_touch_frame(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct ivi_share_nativesurface_client_link *client_link = wl_resource_get_user_data(resource);
+ struct weston_seat *seat = NULL;
+ struct wl_resource *target_resource = NULL;
+ struct wl_resource *surface_resource = client_link->parent->surface->resource;
+
+ seat = get_weston_seat(client_link->parent->shell_ext->wc, client_link);
+ if (seat == NULL || seat->touch_state == NULL) {
+ return;
+ }
+
+ wl_list_for_each(target_resource, &seat->touch_state->resource_list, link) {
+ if (wl_resource_get_client(target_resource) == wl_resource_get_client(surface_resource)) {
+ wl_touch_send_frame(target_resource);
+ break;
+ }
+ }
+}
+
+static void
+share_surface_redirect_touch_cancel(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct ivi_share_nativesurface_client_link *client_link = wl_resource_get_user_data(resource);
+ struct weston_seat *seat = NULL;
+ struct wl_resource *target_resource = NULL;
+ uint32_t time = get_event_time();
+ struct wl_resource *surface_resource = client_link->parent->surface->resource;
+
+ seat = get_weston_seat(client_link->parent->shell_ext->wc, client_link);
+ if (seat == NULL || seat->touch_state == NULL) {
+ return;
+ }
+
+ wl_list_for_each(target_resource, &seat->touch_state->resource_list, link) {
+ if (wl_resource_get_client(target_resource) == wl_resource_get_client(surface_resource)) {
+ wl_touch_send_cancel(target_resource);
+ break;
+ }
+ }
+}
+
+static const
+struct ivi_share_surface_interface share_surface_implementation = {
+ share_surface_destroy,
+ share_surface_redirect_touch_down,
+ share_surface_redirect_touch_up,
+ share_surface_redirect_touch_motion,
+ share_surface_redirect_touch_frame,
+ share_surface_redirect_touch_cancel
+};
+
+static struct shell_surface *
+get_shell_surface_from_weston_surface(struct weston_surface *surface,
+ struct ivi_shell_share_ext *shell_ext)
+{
+ struct shell_surface *shsurf;
+
+ wl_list_for_each(shsurf, &shell_ext->list_shell_surface, link) {
+ if (shsurf->surface == surface) {
+ return shsurf;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+send_share_surface_state(struct ivi_share_nativesurface_client_link *client_link,
+ uint32_t share_surface_state);
+
+static void
+remove_nativesurface(struct ivi_share_nativesurface *nativesurf)
+{
+ if (NULL == nativesurf) {
+ return;
+ }
+
+ struct ivi_share_nativesurface_client_link *p_link = NULL;
+ struct ivi_share_nativesurface_client_link *p_next = NULL;
+ wl_list_for_each_safe(p_link, p_next, &nativesurf->client_list, link) {
+ /* Notify the shared surface has been destroyed */
+ send_share_surface_state(p_link,
+ IVI_SHARE_SURFACE_SHARE_SURFACE_STATE_DESTROYED);
+
+ /* Initialize information about shared surface */
+ p_link->parent = NULL;
+ p_link->firstSendConfigureComp = false;
+ wl_list_remove(&p_link->link);
+ wl_list_init(&p_link->link);
+ }
+
+ wl_list_remove(&nativesurf->link);
+ free_nativesurface(nativesurf);
+}
+
+static void
+nativesurface_destroy(struct wl_listener *listener, void *data)
+{
+ struct weston_surface *surface = data;
+ struct ivi_share_nativesurface *nativesurf =
+ container_of(listener, struct ivi_share_nativesurface,
+ surface_destroy_listener);
+
+ if (nativesurf->surface == surface) {
+ remove_nativesurface(nativesurf);
+ }
+}
+
+struct ivi_share_nativesurface*
+alloc_share_nativesurface(struct weston_surface *surface, uint32_t id, uint32_t surface_id,
+ uint32_t bufferType, uint32_t format,
+ struct ivi_shell_share_ext *shell_ext)
+{
+ struct ivi_share_nativesurface *nativesurface =
+ malloc(sizeof(struct ivi_share_nativesurface));
+ if (NULL == nativesurface) {
+ return NULL;
+ }
+
+ nativesurface->id = id;
+ nativesurface->surface = surface;
+ nativesurface->bufferType = bufferType;
+ nativesurface->name = 0;
+ nativesurface->width = 0;
+ nativesurface->height = 0;
+ nativesurface->stride = 0;
+ nativesurface->format = format;
+ nativesurface->surface_id = surface_id;
+ nativesurface->shell_ext = shell_ext;
+ wl_list_init(&nativesurface->client_list);
+
+ if (NULL != surface) {
+ nativesurface->surface_destroy_listener.notify = nativesurface_destroy;
+ wl_signal_add(&surface->destroy_signal, &nativesurface->surface_destroy_listener);
+ }
+
+ return nativesurface;
+}
+
+static void
+destroy_client_link(struct wl_resource *resource)
+{
+ struct ivi_share_nativesurface_client_link *client_link = wl_resource_get_user_data(resource);
+
+ wl_list_remove(&client_link->link);
+ free(client_link);
+}
+
+static struct ivi_share_nativesurface_client_link *
+add_nativesurface_client(struct ivi_share_nativesurface *nativesurface,
+ uint32_t id, struct wl_client *client, uint32_t version)
+{
+ struct ivi_share_nativesurface_client_link *link = malloc(sizeof(*link));
+ if (NULL == link) {
+ return NULL;
+ }
+
+ link->resource = wl_resource_create(client, &ivi_share_surface_interface, version, id);
+ link->client = client;
+ link->firstSendConfigureComp = false;
+ link->parent = nativesurface;
+
+ wl_resource_set_implementation(link->resource, &share_surface_implementation,
+ link, destroy_client_link);
+ wl_list_insert(&nativesurface->client_list, &link->link);
+
+ return link;
+}
+
+static struct ivi_share_nativesurface_client_link *
+create_empty_nativesurface_client(struct wl_client *client,
+ uint32_t id, uint32_t version,
+ struct ivi_shell_share_ext *shell_ext)
+{
+ struct ivi_share_nativesurface *nativesurf;
+
+ nativesurf = alloc_share_nativesurface(NULL, 0, 0,
+ IVI_SHARE_SURFACE_TYPE_GBM,
+ IVI_SHARE_SURFACE_FORMAT_ARGB8888,
+ shell_ext);
+ if (NULL == nativesurf) {
+ return NULL;
+ }
+
+ return add_nativesurface_client(nativesurf, id, client, version);
+}
+
+static struct ivi_share_nativesurface*
+find_nativesurface(struct shell_surface *shsurf, struct ivi_shell_share_ext *shell_ext)
+{
+ struct ivi_share_nativesurface *nativesurf = NULL;
+
+ wl_list_for_each(nativesurf, &shell_ext->list_nativesurface, link) {
+ if (shsurf->surface_id == nativesurf->surface_id) {
+ return nativesurf;
+ }
+ }
+ return NULL;
+}
+
+static uint32_t
+get_shared_client_input_caps(struct ivi_share_nativesurface_client_link *client_link,
+ struct ivi_shell_share_ext *shell_ext)
+{
+ uint32_t caps = 0;
+ struct weston_seat *seat = get_weston_seat(shell_ext->wc, client_link);
+ struct wl_client *creator = wl_resource_get_client(client_link->parent->surface->resource);
+
+ if ((seat != NULL) && (seat->touch_state != NULL)) {
+ struct wl_resource *resource = NULL;
+ wl_list_for_each(resource, &seat->touch_state->focus_resource_list, link) {
+ if (wl_resource_get_client(resource) == creator) {
+ caps |= (uint32_t)IVI_SHARE_SURFACE_INPUT_CAPS_TOUCH;
+ break;
+ }
+ }
+
+ wl_list_for_each(resource, &seat->touch_state->resource_list, link) {
+ if (wl_resource_get_client(resource) == creator) {
+ caps |= (uint32_t)IVI_SHARE_SURFACE_INPUT_CAPS_TOUCH;
+ break;
+ }
+ }
+ }
+
+ return caps;
+}
+
+static void
+send_share_surface_state(struct ivi_share_nativesurface_client_link *client_link,
+ uint32_t share_surface_state)
+{
+ if (NULL != client_link->resource) {
+ ivi_share_surface_send_share_surface_state(client_link->resource,
+ share_surface_state);
+ }
+}
+
+static void
+share_get_ivi_share_surface(struct wl_client *client, struct wl_resource *resource,
+ uint32_t id, uint32_t surface_id)
+{
+ struct ivi_shell_share_ext *shell_ext = wl_resource_get_user_data(resource);
+ struct ivi_layout_surface *layout_surface;
+ struct weston_surface *surface;
+ struct ivi_share_nativesurface *nativesurf;
+ struct shell_surface *shsurf;
+ struct ivi_share_nativesurface_client_link *client_link = NULL;
+ uint32_t caps = 0;
+ uint32_t version = wl_resource_get_version(resource);
+
+ layout_surface = shell_ext->controller_interface->get_surface_from_id(surface_id);
+ surface = shell_ext->controller_interface->surface_get_weston_surface(layout_surface);
+
+ shsurf = get_shell_surface_from_weston_surface(surface, shell_ext);
+ if (shsurf == NULL) {
+ client_link = create_empty_nativesurface_client(client, id, version, shell_ext);
+ if (NULL == client_link) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+ send_share_surface_state(client_link,
+ IVI_SHARE_SURFACE_SHARE_SURFACE_STATE_NOT_EXIST);
+ return;
+ }
+
+ if (shsurf->surface_id != surface_id) {
+ shsurf->surface_id = surface_id;
+ }
+
+ nativesurf = find_nativesurface(shsurf, shell_ext);
+ if (nativesurf == NULL) {
+ nativesurf = alloc_share_nativesurface(shsurf->surface, id, 0,
+ (int32_t)IVI_SHARE_SURFACE_TYPE_GBM,
+ (int32_t)IVI_SHARE_SURFACE_FORMAT_ARGB8888,
+ shell_ext);
+
+ if (NULL == nativesurf) {
+ weston_log("Buffer Sharing Insufficient memory\n");
+ wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "Insufficient memory");
+ return;
+ }
+
+ wl_list_insert(&shell_ext->list_nativesurface, &nativesurf->link);
+ }
+
+ client_link = add_nativesurface_client(nativesurf, id, client, version);
+
+ caps = get_shared_client_input_caps(client_link, shell_ext);
+ ivi_share_surface_send_input_capabilities(client_link->resource, caps);
+}
+
+static struct ivi_share_interface g_share_implementation = {
+ share_get_ivi_share_surface
+};
+
+static struct ivi_shell_share_ext*
+init_ivi_shell_share_ext(struct weston_compositor *wc,
+ const struct ivi_controller_interface *controller_interface,
+ struct ivi_shell_share_ext *shell_ext)
+{
+ shell_ext = calloc(1, sizeof(*shell_ext));
+ if (shell_ext == NULL) {
+ weston_log("no memory to allocate ivi_shell_share_ext\n");
+ return NULL;
+ }
+
+ shell_ext->wc = wc;
+ shell_ext->controller_interface = controller_interface;
+ wl_list_init(&shell_ext->list_shell_surface);
+ wl_list_init(&shell_ext->list_nativesurface);
+ wl_list_init(&shell_ext->list_redirect_target);
+
+ return shell_ext;
+}
+
+static void
+send_configure(struct wl_resource *p_resource, uint32_t id,
+ struct ivi_share_nativesurface *p_nativesurface)
+{
+ if ((NULL == p_resource) || (NULL == p_nativesurface)) {
+ return;
+ }
+
+ ivi_share_surface_send_configure(p_resource,
+ p_nativesurface->bufferType,
+ p_nativesurface->width,
+ p_nativesurface->height,
+ p_nativesurface->stride / 4,
+ p_nativesurface->format);
+}
+
+static void
+send_damage(struct wl_resource *p_resource, uint32_t id, uint32_t name)
+{
+ if (!p_resource)
+ return;
+
+ ivi_share_surface_send_damage(p_resource, name);
+}
+
+static void
+bind_share_interface(struct wl_client *p_client, void *p_data,
+ uint32_t version, uint32_t id)
+{
+ struct ivi_shell_share_ext *shell_ext = p_data;
+
+ weston_log("Buffer Sharing Request bind: version(%d)\n", version);
+
+ if (NULL == p_client) {
+ return;
+ }
+
+ shell_ext->resource = wl_resource_create(p_client, &ivi_share_interface, 1, id);
+ wl_resource_set_implementation(shell_ext->resource,
+ &g_share_implementation,
+ shell_ext, NULL);
+}
+
+static void
+send_to_client(struct ivi_share_nativesurface *p_nativesurface, uint32_t send_flag,
+ struct ivi_shell_share_ext *shell_ext)
+{
+ struct ivi_share_nativesurface_client_link *p_link = NULL;
+
+ if ((IVI_SHAREBUFFER_NOT_AVAILABLE & send_flag) == IVI_SHAREBUFFER_NOT_AVAILABLE) {
+ return;
+ }
+
+ if (IVI_SHAREBUFFER_INVALID & send_flag) {
+ /* Notify the shared surface is invalid */
+ wl_list_for_each(p_link, &p_nativesurface->client_list, link) {
+ send_share_surface_state(p_link,
+ IVI_SHARE_SURFACE_SHARE_SURFACE_STATE_INVALID_SURFACE);
+ }
+ return;
+ }
+
+ wl_list_for_each(p_link, &p_nativesurface->client_list, link)
+ {
+ if ((!p_link->firstSendConfigureComp) ||
+ (IVI_SHAREBUFFER_CONFIGURE & send_flag) == IVI_SHAREBUFFER_CONFIGURE) {
+ send_configure(p_link->resource, p_nativesurface->id,
+ p_nativesurface);
+ p_link->firstSendConfigureComp = true;
+ }
+ if ((IVI_SHAREBUFFER_DAMAGE & send_flag) == IVI_SHAREBUFFER_DAMAGE) {
+ send_damage(p_link->resource, p_nativesurface->id,
+ get_buffer_name(p_nativesurface->surface, shell_ext));
+ }
+ }
+}
+
+static void
+send_nativesurface_event(struct wl_listener *listener, void *data)
+{
+ struct update_sharing_surface_content *surface_content =
+ container_of(listener, struct update_sharing_surface_content, listener);
+ struct ivi_shell_share_ext *shell_ext = surface_content->shell_ext;
+ if (wl_list_empty(&shell_ext->list_nativesurface)) {
+ return;
+ }
+
+ struct ivi_share_nativesurface *p_nativesurface = NULL;
+ struct ivi_share_nativesurface *p_next = NULL;
+ wl_list_for_each_safe(p_nativesurface, p_next, &shell_ext->list_nativesurface, link)
+ {
+ if (NULL == p_nativesurface) {
+ continue;
+ }
+
+ if (wl_list_empty(&p_nativesurface->client_list) ||
+ (0 == p_nativesurface->id)) {
+ weston_log("Buffer Sharing warning, Unnecessary nativesurface exists.\n");
+ wl_list_remove(&p_nativesurface->link);
+ free_nativesurface(p_nativesurface);
+ continue;
+ }
+
+ p_nativesurface->send_flag = update_buffer_nativesurface(p_nativesurface, shell_ext);
+ send_to_client(p_nativesurface, p_nativesurface->send_flag, shell_ext);
+ }
+}
+
+static int32_t
+buffer_sharing_init(struct weston_compositor *wc,
+ struct ivi_shell_share_ext *shell_ext)
+{
+ if (NULL == wc) {
+ weston_log("Can not execute buffer sharing.\n");
+ return -1;
+ }
+
+ if (NULL == wl_global_create(wc->wl_display, &ivi_share_interface, 1,
+ shell_ext, bind_share_interface)) {
+ weston_log("Buffer Sharing, Failed to global create\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+add_weston_surf_data(struct wl_listener *listener, void *data)
+{
+ struct weston_surface *ws = data;
+ struct ivi_shell_share_ext *shell_ext = NULL;
+ struct shell_surface *s = NULL;
+ shell_ext = container_of(listener, struct ivi_shell_share_ext, surface_created_listener);
+
+ wl_list_for_each(s, &shell_ext->list_shell_surface, link) {
+ if (s->surface == ws) {
+ return;
+ }
+ }
+
+ struct shell_surface *shsurf = NULL;
+ shsurf = malloc(sizeof *shsurf);
+ if (NULL == shsurf || NULL == ws) {
+ return;
+ }
+
+ shsurf->resource = ws->resource;
+ shsurf->surface = ws;
+ wl_list_init(&shsurf->link);
+ wl_list_insert(shell_ext->list_shell_surface.prev, &shsurf->link);
+}
+
+int32_t
+setup_buffer_sharing(struct weston_compositor *wc,
+ const struct ivi_controller_interface *interface)
+{
+ if (NULL == wc || NULL == interface) {
+ weston_log("Can not execute buffer sharing.\n");
+ return -1;
+ }
+
+ struct ivi_shell_share_ext *shell_ext = NULL;
+
+ shell_ext = init_ivi_shell_share_ext(wc, interface, shell_ext);
+ if (shell_ext == NULL) {
+ weston_log("ivi_shell_share_ext initialize failed\n");
+ return -1;
+ }
+
+ int32_t init_ret = buffer_sharing_init(wc, shell_ext);
+ if (init_ret < 0) {
+ weston_log("Buffer Sharing initialize failed. init_ret = %d\n", init_ret);
+ return init_ret;
+ }
+
+ struct weston_output *output = NULL;
+
+ wl_list_for_each(output, &wc->output_list, link) {
+ struct update_sharing_surface_content *surf_content = malloc(sizeof *surf_content);
+ if (surf_content == NULL) {
+ weston_log("Failed to allocate surf_content. Buffer Sharing can't use.\n");
+ return -1;
+ }
+
+ surf_content->shell_ext = shell_ext;
+ surf_content->listener.notify = send_nativesurface_event;
+ wl_signal_add(&output->frame_signal, &surf_content->listener);
+ }
+
+ shell_ext->surface_created_listener.notify = add_weston_surf_data;
+ wl_signal_add(&wc->create_surface_signal, &shell_ext->surface_created_listener);
+}
diff --git a/weston-ivi-shell/src/ivi-share.h b/weston-ivi-shell/src/ivi-share.h
new file mode 100644
index 0000000..63dbd60
--- /dev/null
+++ b/weston-ivi-shell/src/ivi-share.h
@@ -0,0 +1,76 @@
+/**************************************************************************
+ *
+ * Copyright 2015 Codethink Ltd
+ * Copyright (C) 2015 Advanced Driver Information Technology Joint Venture GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ****************************************************************************/
+#include <stdbool.h>
+#include <sys/time.h>
+
+#include <wayland-server.h>
+#include <weston/compositor.h>
+
+#include "ivi-controller-interface.h"
+
+/**
+ * convenience macro to access single bits of a bitmask
+ */
+#define IVI_BIT(x) (1 << (x))
+
+struct ivi_share_nativesurface
+{
+ struct weston_surface *surface; /* resource */
+ uint32_t id; /* object id */
+ struct wl_list link; /* link */
+ struct wl_list client_list; /* ivi_nativesurface_client_link list */
+ uint32_t bufferType; /* buffer type (GBM only) */
+ uint32_t name; /* buffer name */
+ uint32_t width; /* buffer width */
+ uint32_t height; /* buffer height */
+ uint32_t stride; /* buffer stride[LSB:byte] */
+ uint32_t format; /* ARGB8888 */
+ uint32_t surface_id;
+ uint32_t send_flag;
+ struct wl_listener surface_destroy_listener;
+ struct ivi_shell_share_ext *shell_ext;
+};
+
+struct ivi_shell_share_ext
+{
+ struct weston_compositor *wc;
+ const struct ivi_controller_interface *controller_interface;
+ struct wl_resource *resource;
+ struct wl_list list_shell_surface; /* shell_surface list */
+ struct wl_list list_nativesurface; /* ivi_nativesurface list */
+ struct wl_list list_redirect_target; /* redirect_target list */
+ struct wl_listener surface_created_listener;
+};
+
+enum ivi_sharebuffer_updatetype
+{
+ IVI_SHAREBUFFER_STABLE = IVI_BIT(0),
+ IVI_SHAREBUFFER_DAMAGE = IVI_BIT(1),
+ IVI_SHAREBUFFER_CONFIGURE = IVI_BIT(2),
+ IVI_SHAREBUFFER_INVALID = IVI_BIT(3),
+ IVI_SHAREBUFFER_NOT_AVAILABLE = IVI_BIT(4)
+};
+
+int32_t setup_buffer_sharing(struct weston_compositor *wc,
+ const struct ivi_controller_interface *interface);
+
+uint32_t get_buffer_name(struct weston_surface *surface,
+ struct ivi_shell_share_ext *shell_ext);
+uint32_t update_buffer_nativesurface(struct ivi_share_nativesurface *nativesurface,
+ struct ivi_shell_share_ext *shell_ext);