From c6b82fa13486a17fd23ebb0de54a8c9e1bcd01fe Mon Sep 17 00:00:00 2001 From: Anatolii Nikulin Date: Wed, 6 Jul 2016 12:42:44 +0300 Subject: [PATCH] fix screenshots use tbm buffer for image instead shared memory Change-Id: I60afc17c92adf39a8e6ef933d43e0b99a425ae93 Signed-off-by: Anatolii Nikulin --- Makefile | 12 +- helper/dacapture.c | 421 +++++++++++++++++++++++----------------------- helper/wayland-api.c | 26 --- helper/wayland-api.h | 68 -------- packaging/swap-probe.spec | 9 + 5 files changed, 235 insertions(+), 301 deletions(-) delete mode 100644 helper/wayland-api.c delete mode 100644 helper/wayland-api.h diff --git a/Makefile b/Makefile index cfed6fe..ae6410e 100644 --- a/Makefile +++ b/Makefile @@ -109,10 +109,20 @@ PROBE_SRCS = \ ./probe_file/da_io_stdc.c \ ifeq ($(WAYLAND_SUPPORT),y) -UTILITY_SRCS += ./helper/wayland-api.c UTILITY_SRCS += ./helper/dacapture.c PROBE_SRCS += ./probe_event/orientation.c CFLAGS += -DWAYLAND_SUPPORT +CFLAGS += -I/usr/include/wayland-extension/ +LDFLAGS+=-lecore \ + -levas \ + -ltizen-extension-client \ + -ltbm \ + -leina \ + -lecore_wayland \ + -lwayland-client \ + -lwayland-tbm-client \ + -lcapi-base-common \ + -lscreenshooter-client endif # WAYLAND_SUPPORT DUMMY_SRCS = ./custom_chart/da_chart_dummy.c diff --git a/helper/dacapture.c b/helper/dacapture.c index d61bf26..4211071 100755 --- a/helper/dacapture.c +++ b/helper/dacapture.c @@ -49,7 +49,13 @@ #include #include -#include "wayland-api.h" +#include +#include +#include +#include +#include +#include + #include "real_functions.h" #include "daprobe.h" #include "dahelper.h" @@ -60,12 +66,14 @@ #define CAPTURE_TIMEOUT 2.0 #define MAX_PATH_LENGTH 256 -struct screenshot_data { - struct wl_shm *shm; +struct efl_data { + struct wl_display *wl_display; + struct wl_registry *wl_registry; struct screenshooter *screenshooter; struct wl_list output_list; int min_x, min_y, max_x, max_y; int buffer_copy_done; + int width, height; }; struct screenshooter_output { @@ -128,7 +136,7 @@ static void screenshot_done(void *data, struct screenshooter __attribute__((unused)) *screenshooter) { - struct screenshot_data *sdata = data; + struct efl_data *sdata = data; sdata->buffer_copy_done = 1; } @@ -141,13 +149,12 @@ handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t __attribute__((unused)) version) { - struct screenshot_data *sdata = data; + struct efl_data *sdata = data; if (strcmp(interface, "wl_output") == 0) { struct screenshooter_output *output = malloc(sizeof(*output)); if (output) { - PRINTMSG("allocate %p", output); output->output = wl_registry_bind(registry, name, &wl_output_interface, 1); @@ -156,13 +163,13 @@ handle_global(void *data, struct wl_registry *registry, &output_listener, output); } - } else if (strcmp(interface, "wl_shm") == 0) { - sdata->shm = wl_registry_bind(registry, name, - &wl_shm_interface, 1); } else if (strcmp(interface, "screenshooter") == 0) { sdata->screenshooter = wl_registry_bind(registry, name, &screenshooter_interface, 1); + screenshooter_add_listener(sdata->screenshooter, + &screenshooter_listener, + sdata); } } @@ -171,180 +178,33 @@ static const struct wl_registry_listener registry_listener = { NULL }; -static struct wl_buffer * -create_shm_buffer(struct wl_shm *shm, int width, int height, void **data_out) -{ - char filename[] = "/tmp/wayland-shm-XXXXXX"; - struct wl_shm_pool *pool; - struct wl_buffer *buffer; - int fd, size, stride; - void *data; - - stride = width * 4; - size = stride * height; - - fd = mkstemp(filename); - if (fd < 0) - return NULL; - - if (ftruncate(fd, size) < 0) { - close(fd); - return NULL; - } - - data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - unlink(filename); - - if (data == MAP_FAILED) { - close(fd); - return NULL; - } - - pool = wl_shm_create_pool(shm, fd, size); - close(fd); - buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, - WL_SHM_FORMAT_XRGB8888); - wl_shm_pool_destroy(pool); - *data_out = data; - - return buffer; -} - -static void *__screenshot_to_buf(struct screenshot_data *sdata, int width, - int height) -{ - int output_stride, buffer_stride, i; - void *data, *d, *s; - struct screenshooter_output *output, *next; - - buffer_stride = width * 4; - data = malloc(buffer_stride * height); - if (!data) - return NULL; - - wl_list_for_each_safe(output, next, &sdata->output_list, link) { - output_stride = output->width * 4; - s = output->data; - d = data + (output->offset_y - sdata->min_y) * buffer_stride + - (output->offset_x - sdata->min_x) * 4; - - for (i = 0; i < output->height; i++) { - memcpy(d, s, output_stride); - d += buffer_stride; - s += output_stride; - } - - wl_list_remove(&output->link); - free(output); - } - - return data; -} - -static int -set_buffer_size(struct screenshot_data *sdata, int *width, int *height) +static void __set_buffer_size(struct efl_data *data) { struct screenshooter_output *output; - sdata->min_x = sdata->min_y = INT_MAX; - sdata->max_x = sdata->max_y = INT_MIN; + data->min_x = data->min_y = INT_MAX; + data->max_x = data->max_y = INT_MIN; int position = 0; - wl_list_for_each_reverse(output, &sdata->output_list, link) { + wl_list_for_each_reverse(output, &data->output_list, link) { output->offset_x = position; position += output->width; } - wl_list_for_each(output, &sdata->output_list, link) { - sdata->min_x = MIN(sdata->min_x, output->offset_x); - sdata->min_y = MIN(sdata->min_y, output->offset_y); - sdata->max_x = MAX(sdata->max_x, - output->offset_x + output->width); - sdata->max_y = MAX(sdata->max_y, - output->offset_y + output->height); + wl_list_for_each(output, &data->output_list, link) { + data->min_x = MIN(data->min_x, output->offset_x); + data->min_y = MIN(data->min_y, output->offset_y); + data->max_x = MAX(data->max_x, output->offset_x + output->width); + data->max_y = MAX(data->max_y, output->offset_y + output->height); } - if (sdata->max_x <= sdata->min_x || sdata->max_y <= sdata->min_y) - return -1; - - *width = sdata->max_x - sdata->min_x; - *height = sdata->max_y - sdata->min_y; - - return 0; -} - -static void *__capture_screnshot_wayland(int *width, int *height) -{ - struct wl_display *display = NULL; - struct wl_registry *registry; - struct screenshooter_output *output; - void *buf = NULL; - struct screenshot_data *sdata; - const char *wayland_socket = NULL; - - wayland_socket = getenv("WAYLAND_SOCKET"); - if (!wayland_socket) - wayland_socket = getenv("WAYLAND_DISPLAY"); - - if (!wayland_socket) { - PRINTERR("must be launched by wayland"); - return NULL; - } - - sdata = malloc(sizeof(*sdata)); - if (!sdata) - return NULL; - - sdata->shm = NULL; - sdata->screenshooter = NULL; - wl_list_init(&sdata->output_list); - sdata->min_x = 0; - sdata->min_y = 0; - sdata->max_x = 0; - sdata->max_y = 0; - sdata->buffer_copy_done = 0; - - display = wl_display_connect(wayland_socket); - if (display == NULL) - goto out; - - /* wl_list_init(&output_list); */ - registry = wl_display_get_registry(display); - wl_registry_add_listener(registry, ®istry_listener, sdata); - wl_display_dispatch(display); - wl_display_roundtrip(display); - - if (sdata->screenshooter == NULL) { - PRINTERR("display doesn't support screenshooter"); - return NULL; - } - - screenshooter_add_listener(sdata->screenshooter, &screenshooter_listener, - sdata); - - if (set_buffer_size(sdata, width, height)) - return NULL; - - - wl_list_for_each(output, &sdata->output_list, link) { - output->buffer = create_shm_buffer(sdata->shm, output->width, - output->height, &output->data); - screenshooter_shoot(sdata->screenshooter, - output->output, - output->buffer); - sdata->buffer_copy_done = 0; - while (!sdata->buffer_copy_done) { - wl_display_roundtrip(display); - } + if (data->max_x <= data->min_x || data->max_y <= data->min_y) { + data->width = 0; + data->height = 0; + } else { + data->width = data->max_x - data->min_x; + data->height = data->max_y - data->min_y; } - - buf = __screenshot_to_buf(sdata, *width, *height); - -out: - if (display) - wl_display_disconnect(display); - free(sdata); - return buf; } static Evas* create_canvas(int width, int height) @@ -451,8 +311,13 @@ static void destroy_canvas(Evas* canvas) __evas_free_p(canvas); } -int captureScreen() +static int __save_to_png(const char *path, unsigned char *buf, + int width, int height) { + int ret = -1, err; + Evas *ev = NULL; + Evas_Object *img; + static void (*__evas_object_resize_p)(Evas_Object *obj, Evas_Coord w, Evas_Coord h); @@ -473,13 +338,6 @@ int captureScreen() const char *key, const char *flags); static Evas_Object *(*__evas_object_image_add_p)(Evas *e); - static pthread_mutex_t captureScreenLock = PTHREAD_MUTEX_INITIALIZER; - char dstpath[MAX_PATH_LENGTH]; - char *scrimage; - int width, height, err; - Evas *ev = NULL; - Evas_Object *img; - int ret = -1; rtld_default_set_once(__evas_object_resize_p, "evas_object_resize"); @@ -496,36 +354,23 @@ int captureScreen() rtld_default_set_once(__evas_object_image_add_p, "evas_object_image_add"); - pthread_mutex_lock(&captureScreenLock); - - inc_current_event_index(); - scrimage = __capture_screnshot_wayland(&width, &height); - if (unlikely(scrimage == NULL)) { - ret = -1; - goto out; - } - ev = create_canvas(width, height); if (unlikely(ev == NULL)) { - ret = -1; - goto out_image; + PRINTERR("failed to create canvas"); + return -1; } - snprintf(dstpath, sizeof(dstpath), - SCREENSHOT_DIRECTORY "/%d_%d.png", getpid(), - getCurrentEventIndex()); - // make image buffer img = __evas_object_image_add_p(ev); if (unlikely(img == NULL)) { - ret = -1; + PRINTERR("failed to add image to canvas"); goto out_canvas; } //image buffer set __evas_object_image_data_set_p(img, NULL); __evas_object_image_size_set_p(img, width, height); - __evas_object_image_data_set_p(img, scrimage); + __evas_object_image_data_set_p(img, buf); // resize image if (height > MAX_HEIGHT) { @@ -537,8 +382,180 @@ int captureScreen() __evas_object_image_data_update_add_p(img, 0, 0, width, height); //save image to png file - err = __evas_object_image_save_p(img, dstpath, NULL, "compress=5"); - if (err != 0) { + err = __evas_object_image_save_p(img, path, NULL, "compress=5"); + if (err != 0) + ret = 0; + +out_canvas: + destroy_canvas(ev); + + return ret; +} + +static struct efl_data *__edata = NULL; + +void __wayland_deinit(void) +{ + struct screenshooter_output *output, *next; + + if (!__edata) + return; + + wl_list_for_each_safe(output, next, &__edata->output_list, link) + free(output); + + wl_registry_destroy(__edata->wl_registry); + wl_display_disconnect(__edata->wl_display); + free(__edata); +} + +struct efl_data *__wayland_init(void) +{ + struct wl_display *display = NULL; + struct wl_registry *registry; + struct efl_data *data; + const char *wayland_socket = NULL; + + if (__edata) + return __edata; + + wayland_socket = getenv("WAYLAND_SOCKET"); + if (!wayland_socket) + wayland_socket = getenv("WAYLAND_DISPLAY"); + + if (!wayland_socket) { + PRINTERR("must be launched by wayland"); + return NULL; + } + + data = malloc(sizeof(*data)); + if (!data) + return NULL; + + data->screenshooter = NULL; + wl_list_init(&data->output_list); + data->min_x = 0; + data->min_y = 0; + data->max_x = 0; + data->max_y = 0; + data->buffer_copy_done = 0; + + display = wl_display_connect(wayland_socket); + if (display == NULL) { + fprintf(stderr, "failed to create display: %m\n"); + goto fail; + } + data->wl_display = display; + + /* wl_list_init(&output_list); */ + registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, data); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + data->wl_registry = registry; + + __edata = data; + + return data; +fail: + free(data); + return NULL; +} +static int __capture_screnshot_wayland(const char *path) +{ + struct screenshooter_output *output; + struct efl_data *data; + tbm_surface_h t_surface; + struct wl_buffer *buffer; + struct wayland_tbm_client *tbm_client; + tbm_surface_info_s tsuri; + int plane_idx = 0; + int ret = -1; + int err; + + data = __wayland_init(); + if (!data) { + PRINTERR("failed to init wayland protocol\n"); + return -1; + } + + if (!data->screenshooter) { + PRINTERR("display doesn't support screenshooter\n"); + return -1; + } + + __set_buffer_size(data); + + tbm_client = wayland_tbm_client_init(data->wl_display); + if (!tbm_client) { + PRINTERR("failed to init tbm client\n"); + return -1; + } + + t_surface = tbm_surface_create(data->width, data->height, TBM_FORMAT_XRGB8888); + if (!t_surface) { + PRINTERR("failed to create tbm_surface\n"); + goto fail_tbm_client; + } + + buffer = wayland_tbm_client_create_buffer(tbm_client, t_surface); + if (!buffer) { + PRINTERR("failed to create wl_buffer for screenshot\n"); + goto fail_tbm_surface; + } + + wl_list_for_each(output, &data->output_list, link) { + screenshooter_shoot(data->screenshooter, + output->output, + buffer); + data->buffer_copy_done = 0; + while (!data->buffer_copy_done) { + wl_display_roundtrip(data->wl_display); + } + } + + err = tbm_surface_map(t_surface, + TBM_SURF_OPTION_READ | TBM_SURF_OPTION_WRITE, + &tsuri); + if (err != TBM_SURFACE_ERROR_NONE) { + PRINTERR("failed to map tbm_surface\n"); + goto fail_map_surface; + } + + ret = __save_to_png(path, tsuri.planes[plane_idx].ptr, + data->width, data->height); + + tbm_surface_unmap(t_surface); + +fail_map_surface: + wayland_tbm_client_destroy_buffer(tbm_client, buffer); + +fail_tbm_surface: + tbm_surface_destroy(t_surface); + +fail_tbm_client: + wayland_tbm_client_deinit(tbm_client); + + return ret; +} + +int captureScreen() +{ + static pthread_mutex_t captureScreenLock = PTHREAD_MUTEX_INITIALIZER; + char dstpath[MAX_PATH_LENGTH]; + int ret = -1; + + pthread_mutex_lock(&captureScreenLock); + + inc_current_event_index(); + + snprintf(dstpath, sizeof(dstpath), + SCREENSHOT_DIRECTORY "/%d_%d.png", getpid(), + getCurrentEventIndex()); + + ret = __capture_screnshot_wayland(dstpath); + if (!ret) { if (chmod(dstpath, 0777) == -1) PRINTWRN("cannot chmod -R777 <%s>", dstpath); @@ -564,14 +581,6 @@ int captureScreen() ret = 0; } - // release resources -out_canvas: - destroy_canvas(ev); - -out_image: - free(scrimage); - -out: pthread_mutex_unlock(&captureScreenLock); return ret; } diff --git a/helper/wayland-api.c b/helper/wayland-api.c deleted file mode 100644 index 5a3a8fb..0000000 --- a/helper/wayland-api.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include "wayland-util.h" - -extern const struct wl_interface wl_buffer_interface; -extern const struct wl_interface wl_output_interface; - -static const struct wl_interface *types[] = { - &wl_output_interface, - &wl_buffer_interface, -}; - -static const struct wl_message screenshooter_requests[] = { - { "shoot", "oo", types + 0 }, -}; - -static const struct wl_message screenshooter_events[] = { - { "done", "", types + 0 }, -}; - -WL_EXPORT const struct wl_interface screenshooter_interface = { - "screenshooter", 1, - 1, screenshooter_requests, - 1, screenshooter_events, -}; - diff --git a/helper/wayland-api.h b/helper/wayland-api.h deleted file mode 100644 index 5518f2b..0000000 --- a/helper/wayland-api.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef SCREENSHOOTER_CLIENT_PROTOCOL_H -#define SCREENSHOOTER_CLIENT_PROTOCOL_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include "wayland-client.h" - -struct wl_client; -struct wl_resource; - -struct screenshooter; -struct wl_buffer; -struct wl_output; - -extern const struct wl_interface screenshooter_interface; - -struct screenshooter_listener { - /** - * done - (none) - */ - void (*done)(void *data, - struct screenshooter *screenshooter); -}; - -static inline int -screenshooter_add_listener(struct screenshooter *screenshooter, - const struct screenshooter_listener *listener, void *data) -{ - return wl_proxy_add_listener((struct wl_proxy *) screenshooter, - (void (**)(void)) listener, data); -} - -#define SCREENSHOOTER_SHOOT 0 - -static inline void -screenshooter_set_user_data(struct screenshooter *screenshooter, void *user_data) -{ - wl_proxy_set_user_data((struct wl_proxy *) screenshooter, user_data); -} - -static inline void * -screenshooter_get_user_data(struct screenshooter *screenshooter) -{ - return wl_proxy_get_user_data((struct wl_proxy *) screenshooter); -} - -static inline void -screenshooter_destroy(struct screenshooter *screenshooter) -{ - wl_proxy_destroy((struct wl_proxy *) screenshooter); -} - -static inline void -screenshooter_shoot(struct screenshooter *screenshooter, struct wl_output *output, struct wl_buffer *buffer) -{ - wl_proxy_marshal((struct wl_proxy *) screenshooter, - SCREENSHOOTER_SHOOT, output, buffer); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/packaging/swap-probe.spec b/packaging/swap-probe.spec index feb89ea..f060b85 100644 --- a/packaging/swap-probe.spec +++ b/packaging/swap-probe.spec @@ -27,6 +27,15 @@ BuildRequires: capi-system-runtime-info-devel BuildRequires: python BuildRequires: capi-appfw-application +%if "%{_with_wayland}" == "1" +BuildRequires: pkgconfig(wayland-server) +BuildRequires: pkgconfig(wayland-tbm-client) +BuildRequires: pkgconfig(screenshooter-client) +BuildRequires: pkgconfig(ecore-wayland) +BuildRequires: pkgconfig(wayland-client) >= 1.0.0 +BuildRequires: pkgconfig(tizen-extension-client) +%endif + # Applied python acceleration %ifarch armv7l BuildRequires: python-accel-armv7l-cross-arm -- 2.7.4