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 d1eff4507..f04e3ebca 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); @@ -854,13 +859,22 @@ _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); } + +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 */ }; 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..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" @@ -373,47 +374,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; @@ -428,14 +400,15 @@ meta_shaped_texture_paint (ClutterActor *actor) 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); + 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); @@ -573,6 +546,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, @@ -888,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 @@ -906,34 +1040,52 @@ cairo_surface_t * 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; 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; - texture_rect.width = cogl_texture_get_width (texture); - texture_rect.height = cogl_texture_get_height (texture); + if (priv->tex_width == 0 || priv->tex_height == 0) + return NULL; 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)) + double tex_scale; + cairo_rectangle_int_t tex_rect; + + transformed_clip = alloca (sizeof (cairo_rectangle_int_t)); + *transformed_clip = *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 (clip != 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, - 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), @@ -945,21 +1097,22 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, cairo_surface_mark_dirty (surface); - if (clip != NULL) + if (transformed_clip) cogl_object_unref (texture); - mask_texture = stex->priv->mask_texture; + mask_texture = priv->mask_texture; if (mask_texture != NULL) { 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), @@ -979,7 +1132,7 @@ meta_shaped_texture_get_image (MetaShapedTexture *stex, cairo_surface_destroy (mask_surface); - if (clip != NULL) + if (transformed_clip) cogl_object_unref (mask_texture); } 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) || 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; + } +}