From 7bbe68b149d387ce65aaf35542a67bcc93a80d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 19 Dec 2018 10:08:05 +0100 Subject: [PATCH 01/10] cogl/texture-2d-gl: Try to determine format for external textures Don't just set the internal format to the dummy format "any", as that causes code intended to be unreachable code to be reached. It's not possible to actually know the internal format of an external texture, however, so it might not actually correspond to the real format. https://gitlab.gnome.org/GNOME/mutter/merge_requests/362 --- cogl/cogl/driver/gl/cogl-texture-2d-gl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c index d1eff4507..53be13216 100644 --- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c +++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c @@ -470,7 +470,12 @@ allocate_custom_egl_image_external (CoglTexture2D *tex_2d, { CoglTexture *tex = COGL_TEXTURE (tex_2d); CoglContext *ctx = tex->context; - CoglPixelFormat internal_format = loader->src.egl_image_external.format; + CoglPixelFormat external_format; + CoglPixelFormat internal_format; + + external_format = loader->src.egl_image_external.format; + internal_format = _cogl_texture_determine_internal_format (tex, + external_format); _cogl_gl_util_clear_gl_errors (ctx); -- 2.19.2 From 320add39ea8e1d035f139167561ddb5ae7757d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 19 Dec 2018 10:12:49 +0100 Subject: [PATCH 02/10] cogl/texture-2d-gl: Bind correct target when getting data While for normal textures, GL_TEXTURE_2D should be used, when it's an external texture, binding it using GL_TEXTURE_2D results in an error. Reading the specification for GL_TEXTURE_EXTERNAL_OES it is unclear whether getting pixel data from a texture is possible, and tests show it doesn't result in any data, but in case it would eventually start working, at least bind the correct target for now. https://gitlab.gnome.org/GNOME/mutter/merge_requests/362 --- cogl/cogl/driver/gl/cogl-texture-2d-gl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c index 53be13216..2cf6fed51 100644 --- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c +++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c @@ -859,12 +859,12 @@ _cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d, width, bpp); - _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, + _cogl_bind_gl_texture_transient (tex_2d->gl_target, tex_2d->gl_texture, tex_2d->is_foreign); ctx->texture_driver->gl_get_tex_image (ctx, - GL_TEXTURE_2D, + tex_2d->gl_target, gl_format, gl_type, data); -- 2.19.2 From f890ffe0f8970b640085d4cf767dc64bed1479a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 19 Dec 2018 11:46:45 +0100 Subject: [PATCH 03/10] cogl/texture: Add API to check whether _get_data() will work Currently, GL_TEXTURE_EXTERNAL_OES textures doesn't support getting pixel data. Make it possible for texture users to know this. https://gitlab.gnome.org/GNOME/mutter/merge_requests/362 --- cogl/cogl/cogl-atlas-texture.c | 3 ++- cogl/cogl/cogl-driver.h | 3 +++ cogl/cogl/cogl-sub-texture.c | 11 ++++++++++- cogl/cogl/cogl-texture-2d-sliced.c | 3 ++- cogl/cogl/cogl-texture-2d.c | 12 +++++++++++- cogl/cogl/cogl-texture-3d.c | 3 ++- cogl/cogl/cogl-texture-private.h | 2 ++ cogl/cogl/cogl-texture-rectangle.c | 3 ++- cogl/cogl/cogl-texture.c | 9 +++++++++ cogl/cogl/cogl-texture.h | 6 ++++++ cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h | 3 +++ cogl/cogl/driver/gl/cogl-texture-2d-gl.c | 9 +++++++++ cogl/cogl/driver/gl/gl/cogl-driver-gl.c | 1 + cogl/cogl/driver/gl/gles/cogl-driver-gles.c | 1 + cogl/cogl/driver/nop/cogl-driver-nop.c | 1 + cogl/cogl/winsys/cogl-texture-pixmap-x11.c | 3 ++- 16 files changed, 66 insertions(+), 7 deletions(-) diff --git a/cogl/cogl/cogl-atlas-texture.c b/cogl/cogl/cogl-atlas-texture.c index 97bb84a6a..1a1f99b11 100644 --- a/cogl/cogl/cogl-atlas-texture.c +++ b/cogl/cogl/cogl-atlas-texture.c @@ -1043,5 +1043,6 @@ cogl_atlas_texture_vtable = _cogl_atlas_texture_get_gl_format, _cogl_atlas_texture_get_type, NULL, /* is_foreign */ - NULL /* set_auto_mipmap */ + NULL, /* set_auto_mipmap */ + NULL /* is_get_data_supported */ }; diff --git a/cogl/cogl/cogl-driver.h b/cogl/cogl/cogl-driver.h index 85aa0d870..33a7598a9 100644 --- a/cogl/cogl/cogl-driver.h +++ b/cogl/cogl/cogl-driver.h @@ -210,6 +210,9 @@ struct _CoglDriverVtable int rowstride, uint8_t *data); + CoglBool + (* texture_2d_is_get_data_supported) (CoglTexture2D *tex_2d); + /* Prepares for drawing by flushing the journal, framebuffer state, * pipeline state and attribute state. */ diff --git a/cogl/cogl/cogl-sub-texture.c b/cogl/cogl/cogl-sub-texture.c index 9d7abea90..c3b436140 100644 --- a/cogl/cogl/cogl-sub-texture.c +++ b/cogl/cogl/cogl-sub-texture.c @@ -454,6 +454,14 @@ _cogl_sub_texture_get_type (CoglTexture *tex) return _cogl_texture_get_type (sub_tex->full_texture); } +static CoglBool +_cogl_sub_texture_is_get_data_supported (CoglTexture *tex) +{ + CoglSubTexture *sub_tex = COGL_SUB_TEXTURE (tex); + + return cogl_texture_is_get_data_supported (sub_tex->full_texture); +} + static const CoglTextureVtable cogl_sub_texture_vtable = { @@ -476,5 +484,6 @@ cogl_sub_texture_vtable = _cogl_sub_texture_get_gl_format, _cogl_sub_texture_get_type, NULL, /* is_foreign */ - NULL /* set_auto_mipmap */ + NULL, /* set_auto_mipmap */ + _cogl_sub_texture_is_get_data_supported }; diff --git a/cogl/cogl/cogl-texture-2d-sliced.c b/cogl/cogl/cogl-texture-2d-sliced.c index 4f586cde7..458b29ce5 100644 --- a/cogl/cogl/cogl-texture-2d-sliced.c +++ b/cogl/cogl/cogl-texture-2d-sliced.c @@ -1542,5 +1542,6 @@ cogl_texture_2d_sliced_vtable = _cogl_texture_2d_sliced_get_gl_format, _cogl_texture_2d_sliced_get_type, _cogl_texture_2d_sliced_is_foreign, - NULL /* set_auto_mipmap */ + NULL, /* set_auto_mipmap */ + NULL /* is_get_data_supported */ }; diff --git a/cogl/cogl/cogl-texture-2d.c b/cogl/cogl/cogl-texture-2d.c index 663125890..0e4a73de0 100644 --- a/cogl/cogl/cogl-texture-2d.c +++ b/cogl/cogl/cogl-texture-2d.c @@ -94,6 +94,15 @@ _cogl_texture_2d_set_auto_mipmap (CoglTexture *tex, tex_2d->auto_mipmap = value; } +static CoglBool +_cogl_texture_2d_is_get_data_supported (CoglTexture *tex) +{ + CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex); + CoglContext *ctx = tex->context; + + return ctx->driver_vtable->texture_2d_is_get_data_supported (tex_2d); +} + CoglTexture2D * _cogl_texture_2d_create_base (CoglContext *ctx, int width, @@ -693,5 +702,6 @@ cogl_texture_2d_vtable = _cogl_texture_2d_get_gl_format, _cogl_texture_2d_get_type, _cogl_texture_2d_is_foreign, - _cogl_texture_2d_set_auto_mipmap + _cogl_texture_2d_set_auto_mipmap, + _cogl_texture_2d_is_get_data_supported }; diff --git a/cogl/cogl/cogl-texture-3d.c b/cogl/cogl/cogl-texture-3d.c index 5644119d7..00b3447ec 100644 --- a/cogl/cogl/cogl-texture-3d.c +++ b/cogl/cogl/cogl-texture-3d.c @@ -755,5 +755,6 @@ cogl_texture_3d_vtable = _cogl_texture_3d_get_gl_format, _cogl_texture_3d_get_type, NULL, /* is_foreign */ - _cogl_texture_3d_set_auto_mipmap + _cogl_texture_3d_set_auto_mipmap, + NULL /* is_get_data_supported */ }; diff --git a/cogl/cogl/cogl-texture-private.h b/cogl/cogl/cogl-texture-private.h index 742983e2d..44100f0b7 100644 --- a/cogl/cogl/cogl-texture-private.h +++ b/cogl/cogl/cogl-texture-private.h @@ -149,6 +149,8 @@ struct _CoglTextureVtable /* Only needs to be implemented if is_primitive == TRUE */ void (* set_auto_mipmap) (CoglTexture *texture, CoglBool value); + + CoglBool (* is_get_data_supported) (CoglTexture *texture); }; typedef enum _CoglTextureSoureType { diff --git a/cogl/cogl/cogl-texture-rectangle.c b/cogl/cogl/cogl-texture-rectangle.c index cc2e642d3..0179324a4 100644 --- a/cogl/cogl/cogl-texture-rectangle.c +++ b/cogl/cogl/cogl-texture-rectangle.c @@ -773,5 +773,6 @@ cogl_texture_rectangle_vtable = _cogl_texture_rectangle_get_gl_format, _cogl_texture_rectangle_get_type, _cogl_texture_rectangle_is_foreign, - _cogl_texture_rectangle_set_auto_mipmap + _cogl_texture_rectangle_set_auto_mipmap, + NULL /* is_get_data_supported */ }; diff --git a/cogl/cogl/cogl-texture.c b/cogl/cogl/cogl-texture.c index e2d37e225..eef2abdbe 100644 --- a/cogl/cogl/cogl-texture.c +++ b/cogl/cogl/cogl-texture.c @@ -205,6 +205,15 @@ _cogl_texture_is_foreign (CoglTexture *texture) return FALSE; } +CoglBool +cogl_texture_is_get_data_supported (CoglTexture *texture) +{ + if (texture->vtable->is_get_data_supported) + return texture->vtable->is_get_data_supported (texture); + else + return TRUE; +} + unsigned int cogl_texture_get_width (CoglTexture *texture) { diff --git a/cogl/cogl/cogl-texture.h b/cogl/cogl/cogl-texture.h index ef7d14281..67647aa9c 100644 --- a/cogl/cogl/cogl-texture.h +++ b/cogl/cogl/cogl-texture.h @@ -511,6 +511,12 @@ CoglBool cogl_texture_allocate (CoglTexture *texture, CoglError **error); +/** + * cogl_texture_is_get_data_supported: (skip) + */ +CoglBool +cogl_texture_is_get_data_supported (CoglTexture *texture); + COGL_END_DECLS #endif /* __COGL_TEXTURE_H__ */ diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h b/cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h index e5c658534..1379e9a93 100644 --- a/cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h +++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl-private.h @@ -116,4 +116,7 @@ _cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d, int rowstride, uint8_t *data); +CoglBool +_cogl_texture_2d_gl_is_get_data_supported (CoglTexture2D *tex_2d); + #endif /* _COGL_TEXTURE_2D_GL_PRIVATE_H_ */ diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c index 2cf6fed51..f04e3ebca 100644 --- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c +++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c @@ -869,3 +869,12 @@ _cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d, gl_type, data); } + +CoglBool +_cogl_texture_2d_gl_is_get_data_supported (CoglTexture2D *tex_2d) +{ + if (tex_2d->gl_target == GL_TEXTURE_EXTERNAL_OES) + return FALSE; + else + return TRUE; +} diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c index 178262ac0..9247e4e78 100644 --- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c +++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c @@ -714,6 +714,7 @@ _cogl_driver_gl = _cogl_texture_2d_gl_generate_mipmap, _cogl_texture_2d_gl_copy_from_bitmap, _cogl_texture_2d_gl_get_data, + _cogl_texture_2d_gl_is_get_data_supported, _cogl_gl_flush_attributes_state, _cogl_clip_stack_gl_flush, _cogl_buffer_gl_create, diff --git a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c index 521f6ef3d..14f9b282c 100644 --- a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c +++ b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c @@ -493,6 +493,7 @@ _cogl_driver_gles = _cogl_texture_2d_gl_generate_mipmap, _cogl_texture_2d_gl_copy_from_bitmap, NULL, /* texture_2d_get_data */ + NULL, /* texture_2d_is_get_data_supported */ _cogl_gl_flush_attributes_state, _cogl_clip_stack_gl_flush, _cogl_buffer_gl_create, diff --git a/cogl/cogl/driver/nop/cogl-driver-nop.c b/cogl/cogl/driver/nop/cogl-driver-nop.c index 6e04e7164..8424c64ef 100644 --- a/cogl/cogl/driver/nop/cogl-driver-nop.c +++ b/cogl/cogl/driver/nop/cogl-driver-nop.c @@ -82,6 +82,7 @@ _cogl_driver_nop = _cogl_texture_2d_nop_generate_mipmap, _cogl_texture_2d_nop_copy_from_bitmap, NULL, /* texture_2d_get_data */ + NULL, /* texture_2d_is_get_data_supported */ _cogl_nop_flush_attributes_state, _cogl_clip_stack_nop_flush, }; diff --git a/cogl/cogl/winsys/cogl-texture-pixmap-x11.c b/cogl/cogl/winsys/cogl-texture-pixmap-x11.c index d03040c24..3bb057f4a 100644 --- a/cogl/cogl/winsys/cogl-texture-pixmap-x11.c +++ b/cogl/cogl/winsys/cogl-texture-pixmap-x11.c @@ -1180,5 +1180,6 @@ cogl_texture_pixmap_x11_vtable = _cogl_texture_pixmap_x11_get_gl_format, _cogl_texture_pixmap_x11_get_type, NULL, /* is_foreign */ - NULL /* set_auto_mipmap */ + NULL, /* set_auto_mipmap */ + NULL /* is_get_data_supported */ }; -- 2.19.2 From 363816fab233b965ff8b9e3a55bdb80b9cee4515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 19 Dec 2018 11:55:43 +0100 Subject: [PATCH 04/10] compositor: Make meta_actor_painting_untransformed take a framebuffer Stop using the cogl draw framebuffer implicitly. https://gitlab.gnome.org/GNOME/mutter/merge_requests/362 --- src/compositor/clutter-utils.c | 9 +++++---- src/compositor/clutter-utils.h | 9 +++++---- src/compositor/meta-background-actor.c | 7 ++++++- src/compositor/meta-shaped-texture.c | 7 +++++-- src/compositor/meta-window-group.c | 6 +++++- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/compositor/clutter-utils.c b/src/compositor/clutter-utils.c index fb74732ce..6591ee2d3 100644 --- a/src/compositor/clutter-utils.c +++ b/src/compositor/clutter-utils.c @@ -143,7 +143,8 @@ meta_actor_is_untransformed (ClutterActor *actor, * transform. */ gboolean -meta_actor_painting_untransformed (int paint_width, +meta_actor_painting_untransformed (CoglFramebuffer *fb, + int paint_width, int paint_height, int *x_origin, int *y_origin) @@ -153,8 +154,8 @@ meta_actor_painting_untransformed (int paint_width, float viewport[4]; int i; - cogl_get_modelview_matrix (&modelview); - cogl_get_projection_matrix (&projection); + cogl_framebuffer_get_modelview_matrix (fb, &modelview); + cogl_framebuffer_get_projection_matrix (fb, &projection); cogl_matrix_multiply (&modelview_projection, &projection, @@ -173,7 +174,7 @@ meta_actor_painting_untransformed (int paint_width, vertices[3].y = paint_height; vertices[3].z = 0; - cogl_get_viewport (viewport); + cogl_framebuffer_get_viewport4fv (fb, viewport); for (i = 0; i < 4; i++) { diff --git a/src/compositor/clutter-utils.h b/src/compositor/clutter-utils.h index 36a5925cf..b96733e4a 100644 --- a/src/compositor/clutter-utils.h +++ b/src/compositor/clutter-utils.h @@ -31,9 +31,10 @@ gboolean meta_actor_is_untransformed (ClutterActor *actor, int *x_origin, int *y_origin); -gboolean meta_actor_painting_untransformed (int paint_width, - int paint_height, - int *x_origin, - int *y_origin); +gboolean meta_actor_painting_untransformed (CoglFramebuffer *fb, + int paint_width, + int paint_height, + int *x_origin, + int *y_origin); #endif /* __META_CLUTTER_UTILS_H__ */ diff --git a/src/compositor/meta-background-actor.c b/src/compositor/meta-background-actor.c index 197a62c0f..c4c0f9561 100644 --- a/src/compositor/meta-background-actor.c +++ b/src/compositor/meta-background-actor.c @@ -325,6 +325,7 @@ setup_pipeline (MetaBackgroundActor *self, PipelineFlags pipeline_flags = 0; guint8 opacity; float color_component; + CoglFramebuffer *fb; CoglPipelineFilter filter; opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (self)); @@ -417,8 +418,12 @@ setup_pipeline (MetaBackgroundActor *self, color_component, opacity / 255.); + fb = cogl_get_draw_framebuffer (); if (!priv->force_bilinear && - meta_actor_painting_untransformed (actor_pixel_rect->width, actor_pixel_rect->height, NULL, NULL)) + meta_actor_painting_untransformed (fb, + actor_pixel_rect->width, + actor_pixel_rect->height, + NULL, NULL)) filter = COGL_PIPELINE_FILTER_NEAREST; else filter = COGL_PIPELINE_FILTER_LINEAR; diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index 98346c6ae..133041ba9 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -422,17 +422,20 @@ meta_shaped_texture_paint (ClutterActor *actor) cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height }; + fb = cogl_get_draw_framebuffer (); + /* Use nearest-pixel interpolation if the texture is unscaled. This * improves performance, especially with software rendering. */ filter = COGL_PIPELINE_FILTER_LINEAR; - if (meta_actor_painting_untransformed (tex_width, tex_height, NULL, NULL)) + if (meta_actor_painting_untransformed (fb, + tex_width, tex_height, + NULL, NULL)) filter = COGL_PIPELINE_FILTER_NEAREST; ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - fb = cogl_get_draw_framebuffer (); opacity = clutter_actor_get_paint_opacity (actor); clutter_actor_get_allocation_box (actor, &alloc); diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c index 665adee77..d41c00783 100644 --- a/src/compositor/meta-window-group.c +++ b/src/compositor/meta-window-group.c @@ -81,7 +81,11 @@ meta_window_group_paint (ClutterActor *actor) */ if (clutter_actor_is_in_clone_paint (actor)) { - if (!meta_actor_painting_untransformed (screen_width, + CoglFramebuffer *fb; + + fb = cogl_get_draw_framebuffer (); + if (!meta_actor_painting_untransformed (fb, + screen_width, screen_height, &paint_x_origin, &paint_y_origin) || -- 2.19.2 From ff3110a1a547e0a5523cc5ef33f52b1d706c072e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 19 Dec 2018 12:52:58 +0100 Subject: [PATCH 05/10] shaped-texture: Put actual texture painting in helper This is so that it can be reused later by meta_shaped_texture_get_image() for drawing via an offscreen framebuffer. https://gitlab.gnome.org/GNOME/mutter/merge_requests/362 --- src/compositor/meta-shaped-texture.c | 89 ++++++++++++++++------------ 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index 133041ba9..68098a536 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -373,47 +373,18 @@ set_cogl_texture (MetaShapedTexture *stex, } static void -meta_shaped_texture_paint (ClutterActor *actor) +do_paint (MetaShapedTexture *stex, + CoglFramebuffer *fb, + CoglTexture *paint_tex, + cairo_region_t *clip_region) { - MetaShapedTexture *stex = (MetaShapedTexture *) actor; MetaShapedTexturePrivate *priv = stex->priv; guint tex_width, tex_height; guchar opacity; CoglContext *ctx; - CoglFramebuffer *fb; - CoglTexture *paint_tex; ClutterActorBox alloc; CoglPipelineFilter filter; - if (priv->clip_region && cairo_region_is_empty (priv->clip_region)) - return; - - if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex))) - clutter_actor_realize (CLUTTER_ACTOR (stex)); - - /* The GL EXT_texture_from_pixmap extension does allow for it to be - * used together with SGIS_generate_mipmap, however this is very - * rarely supported. Also, even when it is supported there - * are distinct performance implications from: - * - * - Updating mipmaps that we don't need - * - Having to reallocate pixmaps on the server into larger buffers - * - * So, we just unconditionally use our mipmap emulation code. If we - * wanted to use SGIS_generate_mipmap, we'd have to query COGL to - * see if it was supported (no API currently), and then if and only - * if that was the case, set the clutter texture quality to HIGH. - * Setting the texture quality to high without SGIS_generate_mipmap - * support for TFP textures will result in fallbacks to XGetImage. - */ - if (priv->create_mipmaps) - paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower); - else - paint_tex = COGL_TEXTURE (priv->texture); - - if (paint_tex == NULL) - return; - tex_width = priv->tex_width; tex_height = priv->tex_height; @@ -422,8 +393,6 @@ meta_shaped_texture_paint (ClutterActor *actor) cairo_rectangle_int_t tex_rect = { 0, 0, tex_width, tex_height }; - fb = cogl_get_draw_framebuffer (); - /* Use nearest-pixel interpolation if the texture is unscaled. This * improves performance, especially with software rendering. */ @@ -437,8 +406,8 @@ meta_shaped_texture_paint (ClutterActor *actor) ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); - opacity = clutter_actor_get_paint_opacity (actor); - clutter_actor_get_allocation_box (actor, &alloc); + opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (stex)); + clutter_actor_get_allocation_box (CLUTTER_ACTOR (stex), &alloc); cairo_region_t *blended_region; gboolean use_opaque_region = (priv->opaque_region != NULL && opacity == 255); @@ -576,6 +545,52 @@ meta_shaped_texture_paint (ClutterActor *actor) cairo_region_destroy (blended_region); } +static void +meta_shaped_texture_paint (ClutterActor *actor) +{ + MetaShapedTexture *stex = META_SHAPED_TEXTURE (actor); + MetaShapedTexturePrivate *priv = stex->priv; + CoglTexture *paint_tex = NULL; + CoglFramebuffer *fb; + + if (!priv->texture) + return; + + if (priv->clip_region && cairo_region_is_empty (priv->clip_region)) + return; + + if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex))) + clutter_actor_realize (CLUTTER_ACTOR (stex)); + + /* The GL EXT_texture_from_pixmap extension does allow for it to be + * used together with SGIS_generate_mipmap, however this is very + * rarely supported. Also, even when it is supported there + * are distinct performance implications from: + * + * - Updating mipmaps that we don't need + * - Having to reallocate pixmaps on the server into larger buffers + * + * So, we just unconditionally use our mipmap emulation code. If we + * wanted to use SGIS_generate_mipmap, we'd have to query COGL to + * see if it was supported (no API currently), and then if and only + * if that was the case, set the clutter texture quality to HIGH. + * Setting the texture quality to high without SGIS_generate_mipmap + * support for TFP textures will result in fallbacks to XGetImage. + */ + if (priv->create_mipmaps) + paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower); + + if (!paint_tex) + paint_tex = COGL_TEXTURE (priv->texture); + + if (cogl_texture_get_width (paint_tex) == 0 || + cogl_texture_get_height (paint_tex) == 0) + return; + + fb = cogl_get_draw_framebuffer (); + do_paint (META_SHAPED_TEXTURE (actor), fb, paint_tex, priv->clip_region); +} + static void meta_shaped_texture_get_preferred_width (ClutterActor *self, gfloat for_height, -- 2.19.2 From f594c31d3f9fad5cafced8dc3e8cacb459f87bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 20 Dec 2018 16:58:03 +0100 Subject: [PATCH 06/10] boxes: Add helper to scale rectangles by a double And change the similar region scaling helper to use this one. https://gitlab.gnome.org/GNOME/mutter/merge_requests/362 --- src/core/boxes-private.h | 10 ++++++++++ src/core/boxes.c | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/core/boxes-private.h b/src/core/boxes-private.h index bf019b4d6..793f39527 100644 --- a/src/core/boxes-private.h +++ b/src/core/boxes-private.h @@ -38,6 +38,12 @@ typedef enum FIXED_DIRECTION_Y = 1 << 1, } FixedDirections; +typedef enum _MetaRoundingStrategy +{ + META_ROUNDING_STRATEGY_SHRINK, + META_ROUNDING_STRATEGY_GROW, +} MetaRoundingStrategy; + /* Output functions -- note that the output buffer had better be big enough: * rect_to_string: RECT_LENGTH * region_to_string: (RECT_LENGTH+strlen(separator_string)) * @@ -218,6 +224,10 @@ GList* meta_rectangle_find_nonintersected_monitor_edges ( gboolean meta_rectangle_is_adjecent_to (MetaRectangle *rect, MetaRectangle *other); +void meta_rectangle_scale_double (MetaRectangle *rect, + double scale, + MetaRoundingStrategy rounding_strategy); + static inline ClutterRect meta_rectangle_to_clutter_rect (MetaRectangle *rect) { diff --git a/src/core/boxes.c b/src/core/boxes.c index 35e9ac3cd..0854ecf94 100644 --- a/src/core/boxes.c +++ b/src/core/boxes.c @@ -2036,3 +2036,25 @@ meta_rectangle_is_adjecent_to (MetaRectangle *rect, else return FALSE; } + +void +meta_rectangle_scale_double (MetaRectangle *rect, + double scale, + MetaRoundingStrategy rounding_strategy) +{ + switch (rounding_strategy) + { + case META_ROUNDING_STRATEGY_SHRINK: + rect->x = (int) ceil (rect->x * scale); + rect->y = (int) ceil (rect->y * scale); + rect->width = (int) floor (rect->width * scale); + rect->height = (int) floor (rect->height * scale); + break; + case META_ROUNDING_STRATEGY_GROW: + rect->x = (int) floor (rect->x * scale); + rect->y = (int) floor (rect->y * scale); + rect->width = (int) ceil (rect->width * scale); + rect->height = (int) ceil (rect->height * scale); + break; + } +} -- 2.19.2 From 7826c0fdc45a62c6ca563d2f1526b81975243dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 20 Dec 2018 17:21:26 +0100 Subject: [PATCH 07/10] shaped-texture: Stop using gdk rect helper We have our own version, just use that. https://gitlab.gnome.org/GNOME/mutter/merge_requests/362 --- src/compositor/meta-shaped-texture.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index 68098a536..6cde86390 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -940,9 +940,7 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, if (clip != NULL) { - /* GdkRectangle is just a typedef of cairo_rectangle_int_t, - * so we can use the gdk_rectangle_* APIs on these. */ - if (!gdk_rectangle_intersect (&texture_rect, clip, clip)) + if (!meta_rectangle_intersect (&texture_rect, clip, clip)) return NULL; } -- 2.19.2 From a8cecf4997d28e6672bc51afea9682504225c997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 20 Dec 2018 17:22:37 +0100 Subject: [PATCH 08/10] shaped-texture: Add priv pointer to _get_image() The MetaShapedTexturePrivate is accessed more than once, so keep a pointer to it. https://gitlab.gnome.org/GNOME/mutter/merge_requests/362 --- src/compositor/meta-shaped-texture.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index 6cde86390..0fa5fa92f 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -924,13 +924,14 @@ cairo_surface_t * meta_shaped_texture_get_image (MetaShapedTexture *stex, cairo_rectangle_int_t *clip) { + MetaShapedTexturePrivate *priv = stex->priv; CoglTexture *texture, *mask_texture; cairo_rectangle_int_t texture_rect = { 0, 0, 0, 0 }; cairo_surface_t *surface; g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL); - texture = COGL_TEXTURE (stex->priv->texture); + texture = COGL_TEXTURE (priv->texture); if (texture == NULL) return NULL; @@ -964,7 +965,7 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, if (clip != NULL) cogl_object_unref (texture); - mask_texture = stex->priv->mask_texture; + mask_texture = priv->mask_texture; if (mask_texture != NULL) { cairo_t *cr; -- 2.19.2 From a2fb231955a41a9e87ffcdf845fa4dbca0d31dc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 20 Dec 2018 17:32:27 +0100 Subject: [PATCH 09/10] shaped-texture: Don't change the callers clip rect We intersected the callers clip rect. That is probably not a good idea, and easily avoided, so lets avoid it. https://gitlab.gnome.org/GNOME/mutter/merge_requests/362 --- src/compositor/meta-shaped-texture.c | 36 +++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index 0fa5fa92f..823bd47f2 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -925,6 +925,7 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, cairo_rectangle_int_t *clip) { MetaShapedTexturePrivate *priv = stex->priv; + cairo_rectangle_int_t *transformed_clip = NULL; CoglTexture *texture, *mask_texture; cairo_rectangle_int_t texture_rect = { 0, 0, 0, 0 }; cairo_surface_t *surface; @@ -936,21 +937,23 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, if (texture == NULL) return NULL; - texture_rect.width = cogl_texture_get_width (texture); - texture_rect.height = cogl_texture_get_height (texture); if (clip != NULL) { - if (!meta_rectangle_intersect (&texture_rect, clip, clip)) + transformed_clip = alloca (sizeof (cairo_rectangle_int_t)); + *transformed_clip = *clip; + + if (!meta_rectangle_intersect (&texture_rect, transformed_clip, + transformed_clip)) return NULL; } - if (clip != NULL) + if (transformed_clip) texture = cogl_texture_new_from_sub_texture (texture, - clip->x, - clip->y, - clip->width, - clip->height); + transformed_clip->x, + transformed_clip->y, + transformed_clip->width, + transformed_clip->height); surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, cogl_texture_get_width (texture), @@ -962,7 +965,7 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, cairo_surface_mark_dirty (surface); - if (clip != NULL) + if (transformed_clip) cogl_object_unref (texture); mask_texture = priv->mask_texture; @@ -971,12 +974,13 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, cairo_t *cr; cairo_surface_t *mask_surface; - if (clip != NULL) - mask_texture = cogl_texture_new_from_sub_texture (mask_texture, - clip->x, - clip->y, - clip->width, - clip->height); + if (transformed_clip) + mask_texture = + cogl_texture_new_from_sub_texture (mask_texture, + transformed_clip->x, + transformed_clip->y, + transformed_clip->width, + transformed_clip->height); mask_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, cogl_texture_get_width (mask_texture), @@ -996,7 +1000,7 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, cairo_surface_destroy (mask_surface); - if (clip != NULL) + if (transformed_clip) cogl_object_unref (mask_texture); } -- 2.19.2 From 0adfd8966c2de7bfb3223911d194119f1ab46828 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Thu, 20 Dec 2018 17:34:18 +0100 Subject: [PATCH 10/10] shaped-texture: Draw external textures via offscreen EGLStream textures are imported as GL_TEXTURE_EXTERNAL_OES and reading pixels directly from them is not supported. To make it possible to get pixels, create an offscreen framebuffer and paint the actor to it, then read pixels from the framebuffer instead of the texture directly. https://gitlab.gnome.org/GNOME/mutter/merge_requests/362 --- src/compositor/meta-shaped-texture.c | 136 ++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 2 deletions(-) diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index 823bd47f2..d8c250fc9 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -35,6 +35,7 @@ #include "clutter-utils.h" #include "meta-texture-tower.h" +#include "core/boxes-private.h" #include "meta-cullable.h" @@ -906,6 +907,121 @@ meta_shaped_texture_get_opaque_region (MetaShapedTexture *stex) return priv->opaque_region; } +static gboolean +should_get_via_offscreen (MetaShapedTexture *stex) +{ + MetaShapedTexturePrivate *priv = stex->priv; + + if (!cogl_texture_is_get_data_supported (priv->texture)) + return TRUE; + + return FALSE; +} + +static cairo_surface_t * +get_image_via_offscreen (MetaShapedTexture *stex, + cairo_rectangle_int_t *clip) +{ + MetaShapedTexturePrivate *priv = stex->priv; + ClutterBackend *clutter_backend = clutter_get_default_backend (); + CoglContext *cogl_context = + clutter_backend_get_cogl_context (clutter_backend); + CoglTexture *image_texture; + GError *error = NULL; + CoglOffscreen *offscreen; + CoglFramebuffer *fb; + CoglMatrix projection_matrix; + unsigned int fb_width, fb_height; + cairo_rectangle_int_t fallback_clip; + CoglColor clear_color; + cairo_surface_t *surface; + + if (cogl_has_feature (cogl_context, COGL_FEATURE_ID_TEXTURE_NPOT)) + { + fb_width = priv->tex_width; + fb_height = priv->tex_height; + } + else + { + fb_width = clutter_util_next_p2 (priv->tex_width); + fb_height = clutter_util_next_p2 (priv->tex_height); + } + + if (!clip) + { + fallback_clip = (cairo_rectangle_int_t) { + .width = priv->tex_width, + .height = priv->tex_height, + }; + clip = &fallback_clip; + } + + image_texture = + COGL_TEXTURE (cogl_texture_2d_new_with_size (cogl_context, + fb_width, fb_height)); + cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (image_texture), + FALSE); + if (!cogl_texture_allocate (COGL_TEXTURE (image_texture), &error)) + { + g_error_free (error); + cogl_object_unref (image_texture); + return FALSE; + } + + if (fb_width != priv->tex_width || fb_height != priv->tex_height) + { + CoglSubTexture *sub_texture; + + sub_texture = cogl_sub_texture_new (cogl_context, + image_texture, + 0, 0, + priv->tex_width, priv->tex_height); + cogl_object_unref (image_texture); + image_texture = COGL_TEXTURE (sub_texture); + } + + offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (image_texture)); + fb = COGL_FRAMEBUFFER (offscreen); + cogl_object_unref (image_texture); + if (!cogl_framebuffer_allocate (fb, &error)) + { + g_error_free (error); + cogl_object_unref (fb); + return FALSE; + } + + cogl_framebuffer_push_matrix (fb); + cogl_matrix_init_identity (&projection_matrix); + cogl_matrix_scale (&projection_matrix, + 1.0 / (priv->tex_width / 2.0), + -1.0 / (priv->tex_height / 2.0), 0); + cogl_matrix_translate (&projection_matrix, + -(priv->tex_width / 2.0), + -(priv->tex_height / 2.0), 0); + + cogl_framebuffer_set_projection_matrix (fb, &projection_matrix); + + cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0); + cogl_framebuffer_clear (fb, COGL_BUFFER_BIT_COLOR, &clear_color); + + do_paint (stex, fb, priv->texture, NULL); + + cogl_framebuffer_pop_matrix (fb); + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + clip->width, clip->height); + cogl_framebuffer_read_pixels (fb, + clip->x, clip->y, + clip->width, clip->height, + CLUTTER_CAIRO_FORMAT_ARGB32, + cairo_image_surface_get_data (surface)); + cogl_object_unref (fb); + + cairo_surface_mark_dirty (surface); + + return surface; +} + /** * meta_shaped_texture_get_image: * @stex: A #MetaShapedTexture @@ -927,7 +1043,6 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, MetaShapedTexturePrivate *priv = stex->priv; cairo_rectangle_int_t *transformed_clip = NULL; CoglTexture *texture, *mask_texture; - cairo_rectangle_int_t texture_rect = { 0, 0, 0, 0 }; cairo_surface_t *surface; g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL); @@ -937,17 +1052,34 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, if (texture == NULL) return NULL; + if (priv->tex_width == 0 || priv->tex_height == 0) + return NULL; if (clip != NULL) { + double tex_scale; + cairo_rectangle_int_t tex_rect; + transformed_clip = alloca (sizeof (cairo_rectangle_int_t)); *transformed_clip = *clip; - if (!meta_rectangle_intersect (&texture_rect, transformed_clip, + clutter_actor_get_scale (CLUTTER_ACTOR (stex), &tex_scale, NULL); + meta_rectangle_scale_double (transformed_clip, 1.0 / tex_scale, + META_ROUNDING_STRATEGY_GROW); + + tex_rect = (cairo_rectangle_int_t) { + .width = priv->tex_width, + .height = priv->tex_height, + }; + + if (!meta_rectangle_intersect (&tex_rect, transformed_clip, transformed_clip)) return NULL; } + if (should_get_via_offscreen (stex)) + return get_image_via_offscreen (stex, transformed_clip); + if (transformed_clip) texture = cogl_texture_new_from_sub_texture (texture, transformed_clip->x, -- 2.19.2