From ad71697d1d4e225e0561ee3ba57822b18dfaccd9 Mon Sep 17 00:00:00 2001 From: Nobuhiko Tanibata Date: Wed, 16 Dec 2015 19:43:21 +0900 Subject: 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 --- README | 13 + protocol/CMakeLists.txt | 27 ++ weston-ivi-shell/CMakeLists.txt | 37 ++ weston-ivi-shell/src/ivi-extension.c | 10 + weston-ivi-shell/src/ivi-share-gbm.c | 169 ++++++++ weston-ivi-shell/src/ivi-share.c | 733 +++++++++++++++++++++++++++++++++++ weston-ivi-shell/src/ivi-share.h | 76 ++++ 7 files changed, 1065 insertions(+) create mode 100644 weston-ivi-shell/src/ivi-share-gbm.c create mode 100644 weston-ivi-shell/src/ivi-share.c create mode 100644 weston-ivi-shell/src/ivi-share.h 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: /bin/ivi-layermanagement-api-test /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: /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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + +#include +#include +#include + +#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 +#include + +#include +#include + +#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); -- cgit v1.2.1