From a29b8c475e778f91fca3f6c4e6ef07e1786ae35f Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Mon, 25 Nov 2013 17:04:16 +0000 Subject: [PATCH] wayland: Add a convenience function to update a region from SHM buffer Adds cogl_wayland_texture_set_region_from_shm_buffer which is a convenience wrapper around cogl_texture_set_region but it uses the correct format to copy the data from a Wayland SHM buffer. This will typically be used by compositors to update the texture for a surface when an SHM buffer is attached. The ordering of the arguments is based on cogl_texture_set_region_from_bitmap. Based on a patch by Jasper St. Pierre. Reviewed-by: Robert Bragg (cherry picked from commit c76c1d136d2cac7f3d1331a4d1dc0dd0f06e812c) Conflicts: examples/cogland.c --- cogl/cogl-texture-2d.c | 96 ++++++++++++++++++++++++++++---------- cogl/cogl-wayland-server.h | 44 +++++++++++++++++ examples/cogland.c | 44 ++++------------- 3 files changed, 123 insertions(+), 61 deletions(-) diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c index bcbcc2907..d422a7a6d 100644 --- a/cogl/cogl-texture-2d.c +++ b/cogl/cogl-texture-2d.c @@ -293,6 +293,75 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx, #endif /* defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) */ #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT +static void +shm_buffer_get_cogl_pixel_format (struct wl_shm_buffer *shm_buffer, + CoglPixelFormat *format_out, + CoglPixelFormat *internal_format_out) +{ + CoglPixelFormat format; + CoglPixelFormat internal_format = COGL_PIXEL_FORMAT_ANY; + + switch (wl_shm_buffer_get_format (shm_buffer)) + { +#if G_BYTE_ORDER == G_BIG_ENDIAN + case WL_SHM_FORMAT_ARGB8888: + format = COGL_PIXEL_FORMAT_ARGB_8888_PRE; + break; + case WL_SHM_FORMAT_XRGB8888: + format = COGL_PIXEL_FORMAT_ARGB_8888; + internal_format = COGL_PIXEL_FORMAT_RGB_888; + break; +#elif G_BYTE_ORDER == G_LITTLE_ENDIAN + case WL_SHM_FORMAT_ARGB8888: + format = COGL_PIXEL_FORMAT_BGRA_8888_PRE; + break; + case WL_SHM_FORMAT_XRGB8888: + format = COGL_PIXEL_FORMAT_BGRA_8888; + internal_format = COGL_PIXEL_FORMAT_BGR_888; + break; +#endif + default: + g_warn_if_reached (); + format = COGL_PIXEL_FORMAT_ARGB_8888; + } + + if (format_out) + *format_out = format; + if (internal_format_out) + *internal_format_out = internal_format; +} + +CoglBool +cogl_wayland_texture_set_region_from_shm_buffer (CoglTexture *texture, + int src_x, + int src_y, + int width, + int height, + struct wl_shm_buffer * + shm_buffer, + int dst_x, + int dst_y, + int level, + CoglError **error) +{ + const uint8_t *data = wl_shm_buffer_get_data (shm_buffer); + int32_t stride = wl_shm_buffer_get_stride (shm_buffer); + CoglPixelFormat format; + int bpp; + + shm_buffer_get_cogl_pixel_format (shm_buffer, &format, NULL); + bpp = _cogl_pixel_format_get_bytes_per_pixel (format); + + return _cogl_texture_set_region (COGL_TEXTURE (texture), + width, height, + format, + stride, + data + src_x * bpp + src_y * stride, + dst_x, dst_y, + level, + error); +} + CoglTexture2D * cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx, struct wl_resource *buffer, @@ -305,34 +374,11 @@ cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx, if (shm_buffer) { int stride = wl_shm_buffer_get_stride (shm_buffer); - CoglPixelFormat format; - CoglPixelFormat internal_format = COGL_PIXEL_FORMAT_ANY; int width = wl_shm_buffer_get_width (shm_buffer); int height = wl_shm_buffer_get_height (shm_buffer); + CoglPixelFormat format, internal_format; - switch (wl_shm_buffer_get_format (shm_buffer)) - { -#if G_BYTE_ORDER == G_BIG_ENDIAN - case WL_SHM_FORMAT_ARGB8888: - format = COGL_PIXEL_FORMAT_ARGB_8888_PRE; - break; - case WL_SHM_FORMAT_XRGB8888: - format = COGL_PIXEL_FORMAT_ARGB_8888; - internal_format = COGL_PIXEL_FORMAT_RGB_888; - break; -#elif G_BYTE_ORDER == G_LITTLE_ENDIAN - case WL_SHM_FORMAT_ARGB8888: - format = COGL_PIXEL_FORMAT_BGRA_8888_PRE; - break; - case WL_SHM_FORMAT_XRGB8888: - format = COGL_PIXEL_FORMAT_BGRA_8888; - internal_format = COGL_PIXEL_FORMAT_BGR_888; - break; -#endif - default: - g_warn_if_reached (); - format = COGL_PIXEL_FORMAT_ARGB_8888; - } + shm_buffer_get_cogl_pixel_format (shm_buffer, &format, &internal_format); return cogl_texture_2d_new_from_data (ctx, width, height, diff --git a/cogl/cogl-wayland-server.h b/cogl/cogl-wayland-server.h index 7f008384c..26561c33a 100644 --- a/cogl/cogl-wayland-server.h +++ b/cogl/cogl-wayland-server.h @@ -95,6 +95,50 @@ cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx, struct wl_resource *buffer, CoglError **error); +/** + * cogl_wayland_texture_set_region_from_shm_buffer: + * @texture: a #CoglTexture + * @width: The width of the region to copy + * @height: The height of the region to copy + * @shm_buffer: The source buffer + * @src_x: The X offset within the source bufer to copy from + * @src_y: The Y offset within the source bufer to copy from + * @dst_x: The X offset within the texture to copy to + * @dst_y: The Y offset within the texture to copy to + * @level: The mipmap level of the texture to copy to + * @error: A #CoglError to return exceptional errors + * + * Sets the pixels in a rectangular subregion of @texture from a + * Wayland SHM buffer. Generally this would be used in response to + * wl_surface.damage event in a compositor in order to update the + * texture with the damaged region. This is just a convenience wrapper + * around getting the SHM buffer pointer and calling + * cogl_texture_set_region(). See that function for a description of + * the level parameter. + * + * Since the storage for a #CoglTexture is allocated lazily then + * if the given @texture has not previously been allocated then this + * api can return %FALSE and throw an exceptional @error if there is + * not enough memory to allocate storage for @texture. + * + * Return value: %TRUE if the subregion upload was successful, and + * %FALSE otherwise + * Since: 1.18 + * Stability: unstable + */ +CoglBool +cogl_wayland_texture_set_region_from_shm_buffer (CoglTexture *texture, + int src_x, + int src_y, + int width, + int height, + struct wl_shm_buffer * + shm_buffer, + int dst_x, + int dst_y, + int level, + CoglError **error); + COGL_END_DECLS /* The gobject introspection scanner seems to parse public headers in diff --git a/examples/cogland.c b/examples/cogland.c index eb4a92bda..f20821106 100644 --- a/examples/cogland.c +++ b/examples/cogland.c @@ -445,42 +445,14 @@ surface_damaged (CoglandSurface *surface, wl_shm_buffer_get (surface->buffer_ref.buffer->resource); if (shm_buffer) - { - CoglPixelFormat format; - int stride = wl_shm_buffer_get_stride (shm_buffer); - const uint8_t *data = wl_shm_buffer_get_data (shm_buffer); - - switch (wl_shm_buffer_get_format (shm_buffer)) - { -#if G_BYTE_ORDER == G_BIG_ENDIAN - case WL_SHM_FORMAT_ARGB8888: - format = COGL_PIXEL_FORMAT_ARGB_8888_PRE; - break; - case WL_SHM_FORMAT_XRGB8888: - format = COGL_PIXEL_FORMAT_ARGB_8888; - break; -#elif G_BYTE_ORDER == G_LITTLE_ENDIAN - case WL_SHM_FORMAT_ARGB8888: - format = COGL_PIXEL_FORMAT_BGRA_8888_PRE; - break; - case WL_SHM_FORMAT_XRGB8888: - format = COGL_PIXEL_FORMAT_BGRA_8888; - break; -#endif - default: - g_warn_if_reached (); - format = COGL_PIXEL_FORMAT_ARGB_8888; - } - - cogl_texture_set_region (surface->texture, - x, y, /* src_x/y */ - x, y, /* dst_x/y */ - width, height, /* dst_width/height */ - width, height, /* width/height */ - format, - stride, - data); - } + cogl_wayland_texture_set_region_from_shm_buffer (surface->texture, + x, y, + width, + height, + shm_buffer, + x, y, + 0, /* level */ + NULL); } cogland_queue_redraw (surface->compositor);