From bd02702c42070764c9b5b0b2c72de4fad1cc3c25 Mon Sep 17 00:00:00 2001 From: Nobuhiko Tanibata Date: Mon, 28 Jul 2014 18:02:51 +0900 Subject: weston-ivi-shell: Add surface-screenshot function. Signed-off-by: Nobuhiko Tanibata --- weston-ivi-shell/src/ivi-controller.c | 263 +++++++++++++++++++++++++++---- weston-ivi-shell/src/ivi-layout-export.h | 18 +++ 2 files changed, 251 insertions(+), 30 deletions(-) diff --git a/weston-ivi-shell/src/ivi-controller.c b/weston-ivi-shell/src/ivi-controller.c index eddcf08..231567c 100755 --- a/weston-ivi-shell/src/ivi-controller.c +++ b/weston-ivi-shell/src/ivi-controller.c @@ -27,10 +27,12 @@ #include #include #include +#include #include "weston/compositor.h" #include "ivi-controller-server-protocol.h" #include "ivi-layout-export.h" +#include "bitmap.h" struct ivishell; struct ivilayer; @@ -776,16 +778,243 @@ controller_surface_set_orientation(struct wl_client *client, ivi_layout_surfaceSetOrientation(ivisurf->layout_surface, (uint32_t)orientation); } +static int +shm_surface_screenshot(struct weston_surface *surface, + int32_t width, + int32_t height, + int32_t stride, + const char *filename) +{ + struct weston_buffer *weston_buffer = NULL; + struct wl_shm_buffer *shm_buffer = NULL; + cairo_surface_t *cairo_surf = NULL; + uint8_t *source_buffer = NULL; + uint8_t *dest_buffer = NULL; + + weston_buffer = surface->buffer_ref.buffer; + if (weston_buffer == NULL) { + fprintf(stderr, "Failed to get weston buffer.\n"); + return -1; + } + + shm_buffer = wl_shm_buffer_get(weston_buffer->resource); + if (shm_buffer == NULL) { + return -1; + } + + source_buffer = wl_shm_buffer_get_data(shm_buffer); + if (source_buffer == NULL) { + fprintf(stderr, "Failed to get data from shm buffer.\n"); + return -1; + } + + dest_buffer = malloc(stride * height); + if (dest_buffer == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + return -1; + } + + memcpy(dest_buffer, source_buffer, stride * height); + + cairo_surf = cairo_image_surface_create_for_data( + dest_buffer, + CAIRO_FORMAT_RGB24, + width, + height, + stride); + + cairo_surface_write_to_png(cairo_surf, filename); + cairo_surface_destroy(cairo_surf); + free(dest_buffer); + + return 0; +} + +static void +bind_framebuffer(GLuint *fbo_id, GLuint *tex_id, GLsizei width, GLsizei height) +{ + glGenTextures(1, tex_id); + glGenFramebuffers(1, fbo_id); + glBindTexture(GL_TEXTURE_2D, *tex_id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glBindFramebuffer(GL_FRAMEBUFFER, *fbo_id); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *tex_id, 0); + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); +} + +static void +unbind_framebuffer(GLuint fbo_id, GLuint tex_id) +{ + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteTextures(1, &tex_id); + glDeleteFramebuffers(1, &fbo_id); +} + +static void +dump_surface(struct weston_output *output, + struct weston_compositor *compositor, + const char *filename, + int32_t x, + int32_t y, + int32_t width, + int32_t height) +{ + struct weston_renderer *renderer = compositor->renderer; + pixman_region32_t region; + uint8_t *readpixs = NULL; + int32_t stride = width * (PIXMAN_FORMAT_BPP(compositor->read_format) / 8); + GLuint fbo_id, tex_id; + + readpixs = malloc(stride * height); + if (readpixs == NULL) { + fprintf(stderr, "Failed to allocate memory.\n"); + return; + } + + pixman_region32_init_rect(®ion, x, y, width, height); + bind_framebuffer(&fbo_id, &tex_id, output->current_mode->width, output->current_mode->height); + renderer->repaint_output(output, ®ion); + glFinish(); + + y = output->current_mode->height - (y + height); + int result = renderer->read_pixels(output, + compositor->read_format, + readpixs, + x, + y, + width, + height); + unbind_framebuffer(fbo_id, tex_id); + + save_as_bitmap(filename, readpixs, stride * height, width, height, PIXMAN_FORMAT_BPP(compositor->read_format)); + free(readpixs); +} + +static void +clear_viewlist_but_specified_surface(struct weston_compositor *compositor, + struct weston_surface *surface) +{ + struct weston_view *view = NULL; + wl_list_init(&compositor->view_list); + + wl_list_for_each(view, &surface->views, surface_link) { + if (view == NULL) { + continue; + } + + wl_list_insert(compositor->view_list.prev, &view->link); + } +} + +static void +get_gl_surface_rectangle(struct ivi_layout_SurfaceProperties *prop, + int32_t *x, + int32_t *y, + int32_t *width, + int32_t *height) +{ + if (prop == NULL) { + return; + } + + if ((prop->destX == 0) && + (prop->destY == 0) && + (prop->destWidth == 0) && + (prop->destHeight == 0)) { + *x = prop->sourceX; + *y = prop->sourceY; + *width = prop->sourceWidth; + *height = prop->sourceHeight; + } + else { + *x = prop->destX; + *y = prop->destY; + *width = prop->destWidth; + *height = prop->destHeight; + } +} + +static int +gl_surface_screenshot(struct ivisurface *ivisurf, + struct weston_surface *surface, + const char *filename) +{ + struct weston_compositor *compositor = surface->compositor; + struct link_layer *link_layer = NULL; + struct link_screen *link_scrn = NULL; + struct ivi_layout_SurfaceProperties prop = {}; + int32_t x = 0; + int32_t y = 0; + int32_t width = 0; + int32_t height = 0; + + wl_list_for_each(link_layer, &ivisurf->list_layer, link) { + if (link_layer == NULL) { + continue; + } + + wl_list_for_each(link_scrn, &link_layer->layer->list_screen, link) { + if (link_scrn != NULL) { + break; + } + } + } + + if (link_scrn == NULL) { + fprintf(stderr, "Failed to get iviscreen\n"); + return -1; + } + + if (ivi_layout_getPropertiesOfSurface(ivisurf->layout_surface, &prop) != 0) { + fprintf(stderr, "Failed to get surface properties."); + return -1; + } + + get_gl_surface_rectangle(&prop, &x, &y, &width, &height); + clear_viewlist_but_specified_surface(compositor, surface); + dump_surface(link_scrn->screen->output, + compositor, + filename, + x, + y, + width, + height); + + return 0; +} + static void controller_surface_screenshot(struct wl_client *client, struct wl_resource *resource, const char *filename) { - (void)client; - (void)resource; - (void)filename; + struct ivisurface *ivisurf = wl_resource_get_user_data(resource); + struct weston_surface *weston_surface = NULL; + int32_t width = 0; + int32_t height = 0; + int32_t stride = 0; + + weston_surface = ivi_layout_surfaceGetWestonSurface(ivisurf->layout_surface); + if (weston_surface == NULL) { + fprintf(stderr, "Failed to get weston surface.\n"); + return; + } + + if (ivi_layout_surfaceGetSize(ivisurf->layout_surface, &width, &height, &stride) != 0) { + fprintf(stderr, "Failed to get surface size.\n"); + return; + } + + if (shm_surface_screenshot(weston_surface, width, height, stride, filename) != 0) { + if (gl_surface_screenshot(ivisurf, weston_surface, filename) != 0) { + fprintf(stderr, "Failed to capture surface.\n"); + } + } } + static void controller_surface_send_stats(struct wl_client *client, struct wl_resource *resource) @@ -1078,9 +1307,6 @@ controller_screen_screenshot(struct wl_client *client, int32_t height = 0; int32_t stride = 0; uint8_t *readpixs = NULL; - uint8_t *writepixs = NULL; - uint8_t *d = NULL; - uint8_t *s = NULL; output = ivi_layout_screenGetOutput(iviscrn->layout_screen); --output->disable_planes; @@ -1095,12 +1321,6 @@ controller_screen_screenshot(struct wl_client *client, return; } - writepixs = malloc(stride * height); - if (writepixs == NULL) { - weston_log("fails to allocate memory\n"); - return; - } - output->compositor->renderer->read_pixels( output, output->compositor->read_format, @@ -1110,24 +1330,7 @@ controller_screen_screenshot(struct wl_client *client, width, height); - s = readpixs; - d = writepixs + stride * (height - 1); - - for (i = 0; i < height; ++i) { - memcpy(d, s, stride); - d -= stride; - s += stride; - } - - cairo_surf = cairo_image_surface_create_for_data( - writepixs, - CAIRO_FORMAT_ARGB32, - width, - height, - stride); - cairo_surface_write_to_png(cairo_surf, filename); - cairo_surface_destroy(cairo_surf); - free(writepixs); + save_as_bitmap(filename, readpixs, stride * height, width, height, PIXMAN_FORMAT_BPP(output->compositor->read_format)); free(readpixs); } diff --git a/weston-ivi-shell/src/ivi-layout-export.h b/weston-ivi-shell/src/ivi-layout-export.h index 874911d..f0654f1 100644 --- a/weston-ivi-shell/src/ivi-layout-export.h +++ b/weston-ivi-shell/src/ivi-layout-export.h @@ -81,6 +81,10 @@ enum ivi_layout_transition_type{ IVI_LAYOUT_TRANSITION_MAX, }; +typedef void(*shellWarningNotificationFunc)(uint32_t id_surface, + enum ivi_layout_warning_flag warn, + void *userdata); + typedef void(*layerPropertyNotificationFunc)(struct ivi_layout_layer *ivilayer, struct ivi_layout_LayerProperties*, enum ivi_layout_notification_mask mask, @@ -110,6 +114,14 @@ typedef void(*ivi_controller_surface_content_callback)(struct ivi_layout_surface int32_t content, void *userdata); +int32_t +ivi_layout_addNotificationShellWarning(shellWarningNotificationFunc callback, + void *userdata); + +void +ivi_layout_removeNotificationShellWarning(shellWarningNotificationFunc callback, + void *userdata); + /** * \brief to be called by ivi-shell in order to set initail view of * weston_surface. @@ -896,6 +908,12 @@ ivi_layout_surfaceSetSourceRectangle(struct ivi_layout_surface *ivisurf, struct weston_output * ivi_layout_screenGetOutput(struct ivi_layout_screen *); +struct weston_surface * +ivi_layout_surfaceGetWestonSurface(struct ivi_layout_surface *ivisurf); + +int32_t +ivi_layout_surfaceGetSize(struct ivi_layout_surface *ivisurf, int32_t *width, int32_t *height, int32_t *stride); + int32_t ivi_layout_layerSetTransition(struct ivi_layout_layer *ivilayer, enum ivi_layout_transition_type type, -- cgit v1.2.1