diff --git a/src/backends/meta-cursor.c b/src/backends/meta-cursor.c index d9b020ed6..8fd6a9cb1 100644 --- a/src/backends/meta-cursor.c +++ b/src/backends/meta-cursor.c @@ -91,11 +91,6 @@ meta_cursor_sprite_set_texture (MetaCursorSprite *sprite, MetaCursorSpritePrivate *priv = meta_cursor_sprite_get_instance_private (sprite); - if (priv->texture == COGL_TEXTURE_2D (texture) && - priv->hot_x == hot_x && - priv->hot_y == hot_y) - return; - g_clear_pointer (&priv->texture, cogl_object_unref); if (texture) priv->texture = cogl_object_ref (texture); diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c index a82e242e6..8fda90016 100644 --- a/src/wayland/meta-wayland-buffer.c +++ b/src/wayland/meta-wayland-buffer.c @@ -139,7 +139,7 @@ meta_wayland_buffer_realize (MetaWaylandBuffer *buffer) buffer->egl_stream.stream = stream; buffer->type = META_WAYLAND_BUFFER_TYPE_EGL_STREAM; - buffer->texture = COGL_TEXTURE (texture); + buffer->egl_stream.texture = COGL_TEXTURE (texture); buffer->is_y_inverted = meta_wayland_egl_stream_is_y_inverted (stream); return TRUE; @@ -196,8 +196,10 @@ shm_buffer_get_cogl_pixel_format (struct wl_shm_buffer *shm_buffer, } static gboolean -shm_buffer_attach (MetaWaylandBuffer *buffer, - GError **error) +shm_buffer_attach (MetaWaylandBuffer *buffer, + CoglTexture **texture, + gboolean *changed_texture, + GError **error) { MetaBackend *backend = meta_get_backend (); ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend); @@ -207,48 +209,60 @@ shm_buffer_attach (MetaWaylandBuffer *buffer, CoglPixelFormat format; CoglTextureComponents components; CoglBitmap *bitmap; - CoglTexture *texture; - - if (buffer->texture) - return TRUE; + CoglTexture2D *texture_2d; shm_buffer = wl_shm_buffer_get (buffer->resource); stride = wl_shm_buffer_get_stride (shm_buffer); width = wl_shm_buffer_get_width (shm_buffer); height = wl_shm_buffer_get_height (shm_buffer); + shm_buffer_get_cogl_pixel_format (shm_buffer, &format, &components); + + if (*texture && + cogl_texture_get_width (*texture) == width && + cogl_texture_get_height (*texture) == height && + cogl_texture_get_components (*texture) == components && + _cogl_texture_get_format (*texture) == format) + { + buffer->is_y_inverted = TRUE; + *changed_texture = FALSE; + return TRUE; + } + + cogl_clear_object (texture); wl_shm_buffer_begin_access (shm_buffer); - shm_buffer_get_cogl_pixel_format (shm_buffer, &format, &components); - bitmap = cogl_bitmap_new_for_data (cogl_context, width, height, format, stride, wl_shm_buffer_get_data (shm_buffer)); - texture = COGL_TEXTURE (cogl_texture_2d_new_from_bitmap (bitmap)); - cogl_texture_set_components (COGL_TEXTURE (texture), components); + texture_2d = cogl_texture_2d_new_from_bitmap (bitmap); + cogl_texture_set_components (COGL_TEXTURE (texture_2d), components); cogl_object_unref (bitmap); - if (!cogl_texture_allocate (COGL_TEXTURE (texture), error)) - g_clear_pointer (&texture, cogl_object_unref); + if (!cogl_texture_allocate (COGL_TEXTURE (texture_2d), error)) + g_clear_pointer (&texture_2d, cogl_object_unref); wl_shm_buffer_end_access (shm_buffer); - buffer->texture = texture; - buffer->is_y_inverted = TRUE; - - if (!buffer->texture) + if (!texture_2d) return FALSE; + *texture = COGL_TEXTURE (texture_2d); + *changed_texture = TRUE; + buffer->is_y_inverted = TRUE; + return TRUE; } static gboolean -egl_image_buffer_attach (MetaWaylandBuffer *buffer, - GError **error) +egl_image_buffer_attach (MetaWaylandBuffer *buffer, + CoglTexture **texture, + gboolean *changed_texture, + GError **error) { MetaBackend *backend = meta_get_backend (); MetaEgl *egl = meta_backend_get_egl (backend); @@ -258,10 +272,15 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer, int format, width, height, y_inverted; CoglPixelFormat cogl_format; EGLImageKHR egl_image; - CoglTexture2D *texture; + CoglTexture2D *texture_2d; - if (buffer->texture) - return TRUE; + if (buffer->egl_image.texture) + { + *changed_texture = *texture != buffer->egl_image.texture; + cogl_clear_object (texture); + *texture = cogl_object_ref (buffer->egl_image.texture); + return TRUE; + } if (!meta_egl_query_wayland_buffer (egl, egl_display, buffer->resource, EGL_TEXTURE_FORMAT, &format, @@ -307,26 +326,32 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer, if (egl_image == EGL_NO_IMAGE_KHR) return FALSE; - texture = cogl_egl_texture_2d_new_from_image (cogl_context, - width, height, - cogl_format, - egl_image, - error); + texture_2d = cogl_egl_texture_2d_new_from_image (cogl_context, + width, height, + cogl_format, + egl_image, + error); meta_egl_destroy_image (egl, egl_display, egl_image, NULL); - if (!texture) + if (!texture_2d) return FALSE; - buffer->texture = COGL_TEXTURE (texture); + buffer->egl_image.texture = COGL_TEXTURE (texture_2d); buffer->is_y_inverted = !!y_inverted; + cogl_clear_object (texture); + *texture = cogl_object_ref (buffer->egl_image.texture); + *changed_texture = TRUE; + return TRUE; } #ifdef HAVE_WAYLAND_EGLSTREAM static gboolean egl_stream_buffer_attach (MetaWaylandBuffer *buffer, + CoglTexture **texture, + gboolean *changed_texture, GError **error) { MetaWaylandEglStream *stream = buffer->egl_stream.stream; @@ -336,13 +361,38 @@ egl_stream_buffer_attach (MetaWaylandBuffer *buffer, if (!meta_wayland_egl_stream_attach (stream, error)) return FALSE; + *changed_texture = *texture != buffer->egl_stream.texture; + cogl_clear_object (texture); + *texture = cogl_object_ref (buffer->egl_stream.texture); + return TRUE; } #endif /* HAVE_WAYLAND_EGLSTREAM */ +/** + * meta_wayland_buffer_attach: + * @buffer: a pointer to a #MetaWaylandBuffer + * @texture: (inout) (transfer full): a #CoglTexture representing the surface + * content + * @error: return location for error or %NULL + * + * This function should be passed a pointer to the texture used to draw the + * surface content. The texture will either be replaced by a new texture, or + * stay the same, in which case, it may later be updated with new content when + * processing damage. The new texture might be newly created, or it may be a + * reference to an already existing one. + * + * If replaced, the old texture will have its reference count decreased by one, + * potentially freeing it. When a new texture is set, the caller (i.e. the + * surface) will be the owner of one reference count. It must free it, either + * using g_object_unref() or have it updated again using + * meta_wayland_buffer_attach(), which also might free it, as described above. + */ gboolean -meta_wayland_buffer_attach (MetaWaylandBuffer *buffer, - GError **error) +meta_wayland_buffer_attach (MetaWaylandBuffer *buffer, + CoglTexture **texture, + gboolean *changed_texture, + GError **error) { g_return_val_if_fail (buffer->resource, FALSE); @@ -358,15 +408,18 @@ meta_wayland_buffer_attach (MetaWaylandBuffer *buffer, switch (buffer->type) { case META_WAYLAND_BUFFER_TYPE_SHM: - return shm_buffer_attach (buffer, error); + return shm_buffer_attach (buffer, texture, changed_texture, error); case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE: - return egl_image_buffer_attach (buffer, error); + return egl_image_buffer_attach (buffer, texture, changed_texture, error); #ifdef HAVE_WAYLAND_EGLSTREAM case META_WAYLAND_BUFFER_TYPE_EGL_STREAM: - return egl_stream_buffer_attach (buffer, error); + return egl_stream_buffer_attach (buffer, texture, changed_texture, error); #endif case META_WAYLAND_BUFFER_TYPE_DMA_BUF: - return meta_wayland_dma_buf_buffer_attach (buffer, error); + return meta_wayland_dma_buf_buffer_attach (buffer, + texture, + changed_texture, + error); case META_WAYLAND_BUFFER_TYPE_UNKNOWN: g_assert_not_reached (); return FALSE; @@ -376,12 +429,6 @@ meta_wayland_buffer_attach (MetaWaylandBuffer *buffer, return FALSE; } -CoglTexture * -meta_wayland_buffer_get_texture (MetaWaylandBuffer *buffer) -{ - return buffer->texture; -} - CoglSnippet * meta_wayland_buffer_create_snippet (MetaWaylandBuffer *buffer) { @@ -403,6 +450,7 @@ meta_wayland_buffer_is_y_inverted (MetaWaylandBuffer *buffer) static gboolean process_shm_buffer_damage (MetaWaylandBuffer *buffer, + CoglTexture *texture, cairo_region_t *region, GError **error) { @@ -427,7 +475,7 @@ process_shm_buffer_damage (MetaWaylandBuffer *buffer, bpp = _cogl_pixel_format_get_bytes_per_pixel (format); cairo_region_get_rectangle (region, i, &rect); - if (!_cogl_texture_set_region (buffer->texture, + if (!_cogl_texture_set_region (texture, rect.width, rect.height, format, stride, @@ -448,6 +496,7 @@ process_shm_buffer_damage (MetaWaylandBuffer *buffer, void meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer, + CoglTexture *texture, cairo_region_t *region) { gboolean res = FALSE; @@ -458,7 +507,7 @@ meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer, switch (buffer->type) { case META_WAYLAND_BUFFER_TYPE_SHM: - res = process_shm_buffer_damage (buffer, region, &error); + res = process_shm_buffer_damage (buffer, texture, region, &error); break; case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE: #ifdef HAVE_WAYLAND_EGLSTREAM @@ -487,10 +536,12 @@ meta_wayland_buffer_finalize (GObject *object) { MetaWaylandBuffer *buffer = META_WAYLAND_BUFFER (object); - g_clear_pointer (&buffer->texture, cogl_object_unref); + g_clear_pointer (&buffer->egl_image.texture, cogl_object_unref); #ifdef HAVE_WAYLAND_EGLSTREAM + g_clear_pointer (&buffer->egl_stream.texture, cogl_object_unref); g_clear_object (&buffer->egl_stream.stream); #endif + g_clear_pointer (&buffer->dma_buf.texture, cogl_object_unref); g_clear_object (&buffer->dma_buf.dma_buf); G_OBJECT_CLASS (meta_wayland_buffer_parent_class)->finalize (object); diff --git a/src/wayland/meta-wayland-buffer.h b/src/wayland/meta-wayland-buffer.h index 3709c85ff..5d75a3451 100644 --- a/src/wayland/meta-wayland-buffer.h +++ b/src/wayland/meta-wayland-buffer.h @@ -51,19 +51,24 @@ struct _MetaWaylandBuffer struct wl_resource *resource; struct wl_listener destroy_listener; - CoglTexture *texture; gboolean is_y_inverted; MetaWaylandBufferType type; + struct { + CoglTexture *texture; + } egl_image; + #ifdef HAVE_WAYLAND_EGLSTREAM struct { MetaWaylandEglStream *stream; + CoglTexture *texture; } egl_stream; #endif struct { MetaWaylandDmaBufBuffer *dma_buf; + CoglTexture *texture; } dma_buf; }; @@ -76,11 +81,13 @@ struct wl_resource * meta_wayland_buffer_get_resource (MetaWaylandBuff gboolean meta_wayland_buffer_is_realized (MetaWaylandBuffer *buffer); gboolean meta_wayland_buffer_realize (MetaWaylandBuffer *buffer); gboolean meta_wayland_buffer_attach (MetaWaylandBuffer *buffer, + CoglTexture **texture, + gboolean *changed_texture, GError **error); -CoglTexture * meta_wayland_buffer_get_texture (MetaWaylandBuffer *buffer); CoglSnippet * meta_wayland_buffer_create_snippet (MetaWaylandBuffer *buffer); gboolean meta_wayland_buffer_is_y_inverted (MetaWaylandBuffer *buffer); void meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer, + CoglTexture *texture, cairo_region_t *region); #endif /* META_WAYLAND_BUFFER_H */ diff --git a/src/wayland/meta-wayland-cursor-surface.c b/src/wayland/meta-wayland-cursor-surface.c index 92f86c9ec..d46b3511f 100644 --- a/src/wayland/meta-wayland-cursor-surface.c +++ b/src/wayland/meta-wayland-cursor-surface.c @@ -57,18 +57,17 @@ update_cursor_sprite_texture (MetaWaylandCursorSurface *cursor_surface) meta_wayland_cursor_surface_get_instance_private (cursor_surface); MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (cursor_surface)); - MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface); MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (priv->cursor_sprite); - - g_return_if_fail (!buffer || buffer->texture); + CoglTexture *texture; if (!priv->cursor_renderer) return; - if (buffer) + texture = meta_wayland_surface_get_texture (surface); + if (texture) { meta_cursor_sprite_set_texture (cursor_sprite, - buffer->texture, + texture, priv->hot_x * surface->scale, priv->hot_y * surface->scale); } @@ -170,7 +169,9 @@ meta_wayland_cursor_surface_commit (MetaWaylandSurfaceRole *surface_role, &pending->frame_callback_list); wl_list_init (&pending->frame_callback_list); - if (pending->newly_attached) + if (pending->newly_attached && + (!cairo_region_is_empty (pending->surface_damage) || + !cairo_region_is_empty (pending->buffer_damage))) update_cursor_sprite_texture (META_WAYLAND_CURSOR_SURFACE (surface_role)); } diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c index fd610cc17..e49fba9cf 100644 --- a/src/wayland/meta-wayland-dma-buf.c +++ b/src/wayland/meta-wayland-dma-buf.c @@ -81,7 +81,7 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer, EGLint attribs[64]; int attr_idx = 0; - if (buffer->texture) + if (buffer->dma_buf.texture) return TRUE; switch (dma_buf->drm_format) @@ -196,7 +196,7 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer, if (!texture) return FALSE; - buffer->texture = COGL_TEXTURE (texture); + buffer->dma_buf.texture = COGL_TEXTURE (texture); buffer->is_y_inverted = dma_buf->is_y_inverted; return TRUE; @@ -205,9 +205,16 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer, gboolean meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer, CoglTexture **texture, + gboolean *changed_texture, GError **error) { - return meta_wayland_dma_buf_realize_texture (buffer, error); + if (!meta_wayland_dma_buf_realize_texture (buffer, error)) + return FALSE; + + *changed_texture = *texture != buffer->dma_buf.texture; + cogl_clear_object (texture); + *texture = cogl_object_ref (buffer->dma_buf.texture); + return TRUE; } static void diff --git a/src/wayland/meta-wayland-dma-buf.h b/src/wayland/meta-wayland-dma-buf.h index 28f14b4c2..580a3e777 100644 --- a/src/wayland/meta-wayland-dma-buf.h +++ b/src/wayland/meta-wayland-dma-buf.h @@ -30,6 +30,7 @@ #include #include +#include "cogl/cogl.h" #include "wayland/meta-wayland-types.h" #define META_TYPE_WAYLAND_DMA_BUF_BUFFER (meta_wayland_dma_buf_buffer_get_type ()) @@ -41,8 +42,10 @@ typedef struct _MetaWaylandDmaBufBuffer MetaWaylandDmaBufBuffer; gboolean meta_wayland_dma_buf_init (MetaWaylandCompositor *compositor); gboolean -meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer, - GError **error); +meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer, + CoglTexture **texture, + gboolean *changed_texture, + GError **error); MetaWaylandDmaBufBuffer * meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer); diff --git a/src/wayland/meta-wayland-shell-surface.c b/src/wayland/meta-wayland-shell-surface.c index 50dbb9bcd..04f2aaeea 100644 --- a/src/wayland/meta-wayland-shell-surface.c +++ b/src/wayland/meta-wayland-shell-surface.c @@ -169,7 +169,7 @@ meta_wayland_shell_surface_surface_commit (MetaWaylandSurfaceRole *surface_role return; scale = meta_wayland_actor_surface_calculate_scale (actor_surface); - texture = meta_wayland_buffer_get_texture (buffer); + texture = meta_wayland_surface_get_texture (surface); window->buffer_rect.width = cogl_texture_get_width (texture) * scale; window->buffer_rect.height = cogl_texture_get_height (texture) * scale; diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index ccdbdf4ae..893227771 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -245,14 +245,9 @@ get_buffer_width (MetaWaylandSurface *surface) MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface); if (buffer) - { - CoglTexture *texture = meta_wayland_buffer_get_texture (buffer); - return cogl_texture_get_width (texture); - } + return cogl_texture_get_width (surface->texture); else - { - return 0; - } + return 0; } static int @@ -261,14 +256,9 @@ get_buffer_height (MetaWaylandSurface *surface) MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface); if (buffer) - { - CoglTexture *texture = meta_wayland_buffer_get_texture (buffer); - return cogl_texture_get_height (texture); - } + return cogl_texture_get_height (surface->texture); else - { - return 0; - } + return 0; } static void @@ -342,8 +332,7 @@ surface_process_damage (MetaWaylandSurface *surface, cairo_region_intersect_rectangle (buffer_region, &buffer_rect); - /* First update the buffer. */ - meta_wayland_buffer_process_damage (buffer, buffer_region); + meta_wayland_buffer_process_damage (buffer, surface->texture, buffer_region); actor = meta_wayland_surface_get_actor (surface); if (actor) @@ -693,8 +682,6 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface, if (pending->newly_attached) { - gboolean switched_buffer; - if (!surface->buffer_ref.buffer && surface->window) meta_window_queue (surface->window, META_QUEUE_CALC_SHOWING); @@ -706,8 +693,7 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface, if (surface->buffer_held) meta_wayland_surface_unref_buffer_use_count (surface); - switched_buffer = g_set_object (&surface->buffer_ref.buffer, - pending->buffer); + g_set_object (&surface->buffer_ref.buffer, pending->buffer); if (pending->buffer) meta_wayland_surface_ref_buffer_use_count (surface); @@ -715,19 +701,23 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface, if (pending->buffer) { GError *error = NULL; + gboolean changed_texture; - if (!meta_wayland_buffer_attach (pending->buffer, &error)) + if (!meta_wayland_buffer_attach (pending->buffer, + &surface->texture, + &changed_texture, + &error)) { g_warning ("Could not import pending buffer: %s", error->message); wl_resource_post_error (surface->resource, WL_DISPLAY_ERROR_NO_MEMORY, - "Failed to create a texture for surface %i: %s", + "Failed to attach buffer to surface %i: %s", wl_resource_get_id (surface->resource), error->message); g_error_free (error); goto cleanup; } - if (switched_buffer && meta_wayland_surface_get_actor (surface)) + if (changed_texture && meta_wayland_surface_get_actor (surface)) { MetaShapedTexture *stex; CoglTexture *texture; @@ -735,7 +725,7 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface, gboolean is_y_inverted; stex = meta_surface_actor_get_texture (meta_wayland_surface_get_actor (surface)); - texture = meta_wayland_buffer_get_texture (pending->buffer); + texture = surface->texture; snippet = meta_wayland_buffer_create_snippet (pending->buffer); is_y_inverted = meta_wayland_buffer_is_y_inverted (pending->buffer); @@ -1329,6 +1319,7 @@ wl_surface_destructor (struct wl_resource *resource) if (surface->buffer_held) meta_wayland_surface_unref_buffer_use_count (surface); + g_clear_pointer (&surface->texture, cogl_object_unref); g_clear_object (&surface->buffer_ref.buffer); g_clear_object (&surface->pending); @@ -1850,6 +1841,12 @@ meta_wayland_surface_is_shortcuts_inhibited (MetaWaylandSurface *surface, return g_hash_table_contains (surface->shortcut_inhibited_seats, seat); } +CoglTexture * +meta_wayland_surface_get_texture (MetaWaylandSurface *surface) +{ + return surface->texture; +} + MetaSurfaceActor * meta_wayland_surface_get_actor (MetaWaylandSurface *surface) { diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index 63e088357..e244a3fdf 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -149,6 +149,8 @@ struct _MetaWaylandSurface GHashTable *outputs_to_destroy_notify_id; MetaMonitorTransform buffer_transform; + CoglTexture *texture; + /* Buffer reference state. */ struct { MetaWaylandBuffer *buffer; @@ -317,6 +319,8 @@ void meta_wayland_surface_restore_shortcuts (MetaWaylandSurface * gboolean meta_wayland_surface_is_shortcuts_inhibited (MetaWaylandSurface *surface, MetaWaylandSeat *seat); +CoglTexture * meta_wayland_surface_get_texture (MetaWaylandSurface *surface); + MetaSurfaceActor * meta_wayland_surface_get_actor (MetaWaylandSurface *surface); void meta_wayland_surface_notify_geometry_changed (MetaWaylandSurface *surface);