2008-09-24 16:36:38 -04:00
|
|
|
/*
|
|
|
|
* Authored By Neil Roberts <neil@linux.intel.com>
|
2012-04-27 00:14:42 -04:00
|
|
|
* and Jasper St. Pierre <jstpierre@mecheye.net>
|
2008-09-24 16:36:38 -04:00
|
|
|
*
|
|
|
|
* Copyright (C) 2008 Intel Corporation
|
2012-04-27 00:14:42 -04:00
|
|
|
* Copyright (C) 2012 Red Hat, Inc.
|
2008-09-24 16:36:38 -04:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2014-01-11 20:42:06 -05:00
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2008-09-24 16:36:38 -04:00
|
|
|
*/
|
|
|
|
|
2013-03-11 11:52:36 -04:00
|
|
|
/**
|
|
|
|
* SECTION:meta-shaped-texture
|
|
|
|
* @title: MetaShapedTexture
|
2020-04-22 10:02:08 -04:00
|
|
|
* @short_description: A ClutterContent which draws a shaped texture
|
|
|
|
*
|
|
|
|
* A MetaShapedTexture draws a #CoglTexture (often provided from a client
|
|
|
|
* surface) in such a way that it matches any required transformations that
|
|
|
|
* give its final shape, such as a #MetaMonitorTransform, y-invertedness, or a
|
|
|
|
* crop-and-scale operation.
|
2013-03-11 11:52:36 -04:00
|
|
|
*/
|
|
|
|
|
2018-07-10 04:36:24 -04:00
|
|
|
#include "config.h"
|
2008-09-30 10:33:18 -04:00
|
|
|
|
2018-12-21 11:13:38 -05:00
|
|
|
#include "backends/meta-monitor-transform.h"
|
2018-07-10 04:36:24 -04:00
|
|
|
#include "compositor/meta-shaped-texture-private.h"
|
2018-12-21 11:13:38 -05:00
|
|
|
#include "core/boxes-private.h"
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2018-07-10 04:36:24 -04:00
|
|
|
#include <gdk/gdk.h>
|
2018-11-30 09:34:00 -05:00
|
|
|
#include <math.h>
|
2014-08-26 14:50:16 -04:00
|
|
|
|
2018-07-10 04:36:24 -04:00
|
|
|
#include "cogl/cogl.h"
|
|
|
|
#include "compositor/clutter-utils.h"
|
|
|
|
#include "compositor/meta-texture-tower.h"
|
2018-12-20 11:20:25 -05:00
|
|
|
#include "compositor/region-utils.h"
|
2018-12-20 11:34:18 -05:00
|
|
|
#include "core/boxes-private.h"
|
2018-07-10 04:36:24 -04:00
|
|
|
#include "meta/meta-shaped-texture.h"
|
2008-09-24 16:36:38 -04:00
|
|
|
|
2018-05-09 03:08:40 -04:00
|
|
|
/* MAX_MIPMAPPING_FPS needs to be as small as possible for the best GPU
|
|
|
|
* performance, but higher than the refresh rate of commonly slow updating
|
|
|
|
* windows like top or a blinking cursor, so that such windows do get
|
|
|
|
* mipmapped.
|
|
|
|
*/
|
|
|
|
#define MAX_MIPMAPPING_FPS 5
|
|
|
|
#define MIN_MIPMAP_AGE_USEC (G_USEC_PER_SEC / MAX_MIPMAPPING_FPS)
|
|
|
|
|
|
|
|
/* MIN_FAST_UPDATES_BEFORE_UNMIPMAP allows windows to update themselves
|
|
|
|
* occasionally without causing mipmapping to be disabled, so long as such
|
|
|
|
* an update takes fewer update_area calls than:
|
|
|
|
*/
|
|
|
|
#define MIN_FAST_UPDATES_BEFORE_UNMIPMAP 20
|
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
static void meta_shaped_texture_dispose (GObject *object);
|
2008-09-24 16:36:38 -04:00
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
static void clutter_content_iface_init (ClutterContentInterface *iface);
|
2013-11-21 16:25:20 -05:00
|
|
|
|
2018-12-19 03:04:25 -05:00
|
|
|
enum
|
|
|
|
{
|
2014-07-31 05:05:34 -04:00
|
|
|
SIZE_CHANGED,
|
|
|
|
|
|
|
|
LAST_SIGNAL,
|
|
|
|
};
|
|
|
|
|
|
|
|
static guint signals[LAST_SIGNAL];
|
|
|
|
|
2020-07-15 15:03:48 -04:00
|
|
|
static CoglPipelineKey opaque_overlay_pipeline_key =
|
|
|
|
"meta-shaped-texture-opaque-pipeline-key";
|
|
|
|
static CoglPipelineKey blended_overlay_pipeline_key =
|
|
|
|
"meta-shaped-texture-blended-pipeline-key";
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
struct _MetaShapedTexture
|
2008-09-24 16:36:38 -04:00
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
GObject parent;
|
2018-10-31 06:47:17 -04:00
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
MetaTextureTower *paint_tower;
|
2012-01-07 17:21:32 -05:00
|
|
|
|
|
|
|
CoglTexture *texture;
|
2013-02-19 19:34:47 -05:00
|
|
|
CoglTexture *mask_texture;
|
2016-10-20 03:48:42 -04:00
|
|
|
CoglSnippet *snippet;
|
2008-09-24 16:36:38 -04:00
|
|
|
|
2016-10-20 03:44:27 -04:00
|
|
|
CoglPipeline *base_pipeline;
|
|
|
|
CoglPipeline *masked_pipeline;
|
|
|
|
CoglPipeline *unblended_pipeline;
|
|
|
|
|
|
|
|
gboolean is_y_inverted;
|
|
|
|
|
2014-02-05 14:06:32 -05:00
|
|
|
/* The region containing only fully opaque pixels */
|
2013-08-27 16:17:34 -04:00
|
|
|
cairo_region_t *opaque_region;
|
2009-06-29 14:30:26 -04:00
|
|
|
|
2020-06-22 09:53:23 -04:00
|
|
|
/* MetaCullable regions, see that documentation for more details */
|
|
|
|
cairo_region_t *clip_region;
|
|
|
|
|
2018-11-24 12:27:29 -05:00
|
|
|
gboolean size_invalid;
|
|
|
|
MetaMonitorTransform transform;
|
2018-11-30 09:34:00 -05:00
|
|
|
gboolean has_viewport_src_rect;
|
2019-02-20 10:23:04 -05:00
|
|
|
graphene_rect_t viewport_src_rect;
|
2018-11-30 09:34:00 -05:00
|
|
|
gboolean has_viewport_dst_size;
|
|
|
|
int viewport_dst_width;
|
|
|
|
int viewport_dst_height;
|
2018-11-24 12:27:29 -05:00
|
|
|
|
2018-09-14 09:37:50 -04:00
|
|
|
int tex_width, tex_height;
|
|
|
|
int fallback_width, fallback_height;
|
2018-11-24 12:27:29 -05:00
|
|
|
int dst_width, dst_height;
|
2008-09-24 16:36:38 -04:00
|
|
|
|
2018-05-09 03:08:40 -04:00
|
|
|
gint64 prev_invalidation, last_invalidation;
|
|
|
|
guint fast_updates;
|
|
|
|
guint remipmap_timeout_id;
|
|
|
|
gint64 earliest_remipmap;
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
int buffer_scale;
|
|
|
|
|
2010-08-17 17:33:41 -04:00
|
|
|
guint create_mipmaps : 1;
|
2008-09-24 16:36:38 -04:00
|
|
|
};
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
G_DEFINE_TYPE_WITH_CODE (MetaShapedTexture, meta_shaped_texture, G_TYPE_OBJECT,
|
|
|
|
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
|
|
|
|
clutter_content_iface_init));
|
2018-07-19 07:40:39 -04:00
|
|
|
|
2008-09-24 16:36:38 -04:00
|
|
|
static void
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_shaped_texture_class_init (MetaShapedTextureClass *klass)
|
2008-09-24 16:36:38 -04:00
|
|
|
{
|
|
|
|
GObjectClass *gobject_class = (GObjectClass *) klass;
|
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
gobject_class->dispose = meta_shaped_texture_dispose;
|
2008-09-24 16:36:38 -04:00
|
|
|
|
2014-07-31 05:05:34 -04:00
|
|
|
signals[SIZE_CHANGED] = g_signal_new ("size-changed",
|
|
|
|
G_TYPE_FROM_CLASS (gobject_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
0,
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
G_TYPE_NONE, 0);
|
2008-09-24 16:36:38 -04:00
|
|
|
}
|
|
|
|
|
2018-11-24 12:27:29 -05:00
|
|
|
static void
|
|
|
|
invalidate_size (MetaShapedTexture *stex)
|
|
|
|
{
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->size_invalid = TRUE;
|
2018-11-24 12:27:29 -05:00
|
|
|
}
|
|
|
|
|
2008-09-24 16:36:38 -04:00
|
|
|
static void
|
2018-10-31 06:47:17 -04:00
|
|
|
meta_shaped_texture_init (MetaShapedTexture *stex)
|
2008-09-24 16:36:38 -04:00
|
|
|
{
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->paint_tower = meta_texture_tower_new ();
|
2008-09-24 16:36:38 -04:00
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
stex->buffer_scale = 1;
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->texture = NULL;
|
|
|
|
stex->mask_texture = NULL;
|
|
|
|
stex->create_mipmaps = TRUE;
|
|
|
|
stex->is_y_inverted = TRUE;
|
|
|
|
stex->transform = META_MONITOR_TRANSFORM_NORMAL;
|
2018-11-24 12:27:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
update_size (MetaShapedTexture *stex)
|
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
int buffer_scale = stex->buffer_scale;
|
2018-11-24 12:27:29 -05:00
|
|
|
int dst_width;
|
|
|
|
int dst_height;
|
|
|
|
|
2018-11-30 09:34:00 -05:00
|
|
|
if (stex->has_viewport_dst_size)
|
2018-11-24 12:27:29 -05:00
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
dst_width = stex->viewport_dst_width;
|
|
|
|
dst_height = stex->viewport_dst_height;
|
2018-11-30 09:34:00 -05:00
|
|
|
}
|
|
|
|
else if (stex->has_viewport_src_rect)
|
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
dst_width = stex->viewport_src_rect.size.width;
|
|
|
|
dst_height = stex->viewport_src_rect.size.height;
|
2018-11-24 12:27:29 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-11-30 09:34:00 -05:00
|
|
|
if (meta_monitor_transform_is_rotated (stex->transform))
|
2018-11-24 12:27:29 -05:00
|
|
|
{
|
2018-11-30 09:34:00 -05:00
|
|
|
if (stex->texture)
|
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
dst_width = stex->tex_height / buffer_scale;
|
|
|
|
dst_height = stex->tex_width / buffer_scale;
|
2018-11-30 09:34:00 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
dst_width = stex->fallback_height / buffer_scale;
|
|
|
|
dst_height = stex->fallback_width / buffer_scale;
|
2018-11-30 09:34:00 -05:00
|
|
|
}
|
2018-11-24 12:27:29 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-11-30 09:34:00 -05:00
|
|
|
if (stex->texture)
|
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
dst_width = stex->tex_width / buffer_scale;
|
|
|
|
dst_height = stex->tex_height / buffer_scale;
|
2018-11-30 09:34:00 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
dst_width = stex->fallback_width / buffer_scale;
|
|
|
|
dst_height = stex->fallback_height / buffer_scale;
|
2018-11-30 09:34:00 -05:00
|
|
|
}
|
2018-11-24 12:27:29 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->size_invalid = FALSE;
|
2018-11-24 12:27:29 -05:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->dst_width != dst_width ||
|
|
|
|
stex->dst_height != dst_height)
|
2018-11-24 12:27:29 -05:00
|
|
|
{
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->dst_width = dst_width;
|
|
|
|
stex->dst_height = dst_height;
|
2018-11-24 12:27:29 -05:00
|
|
|
meta_shaped_texture_set_mask_texture (stex, NULL);
|
2018-12-26 10:41:26 -05:00
|
|
|
clutter_content_invalidate_size (CLUTTER_CONTENT (stex));
|
2018-11-24 12:27:29 -05:00
|
|
|
g_signal_emit (stex, signals[SIZE_CHANGED], 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ensure_size_valid (MetaShapedTexture *stex)
|
|
|
|
{
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->size_invalid)
|
2018-11-24 12:27:29 -05:00
|
|
|
update_size (stex);
|
2008-09-24 16:36:38 -04:00
|
|
|
}
|
|
|
|
|
2020-06-22 09:53:23 -04:00
|
|
|
void
|
|
|
|
meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
|
|
|
|
cairo_region_t *clip_region)
|
|
|
|
{
|
|
|
|
g_clear_pointer (&stex->clip_region, cairo_region_destroy);
|
|
|
|
if (clip_region)
|
|
|
|
stex->clip_region = cairo_region_reference (clip_region);
|
|
|
|
}
|
|
|
|
|
2016-10-20 03:44:27 -04:00
|
|
|
static void
|
|
|
|
meta_shaped_texture_reset_pipelines (MetaShapedTexture *stex)
|
|
|
|
{
|
2018-10-31 06:47:17 -04:00
|
|
|
g_clear_pointer (&stex->base_pipeline, cogl_object_unref);
|
|
|
|
g_clear_pointer (&stex->masked_pipeline, cogl_object_unref);
|
|
|
|
g_clear_pointer (&stex->unblended_pipeline, cogl_object_unref);
|
2016-10-20 03:44:27 -04:00
|
|
|
}
|
|
|
|
|
2008-09-24 16:36:38 -04:00
|
|
|
static void
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_shaped_texture_dispose (GObject *object)
|
2008-09-24 16:36:38 -04:00
|
|
|
{
|
2018-10-31 06:47:17 -04:00
|
|
|
MetaShapedTexture *stex = (MetaShapedTexture *) object;
|
2008-09-24 16:36:38 -04:00
|
|
|
|
2019-11-21 18:25:30 -05:00
|
|
|
g_clear_handle_id (&stex->remipmap_timeout_id, g_source_remove);
|
2018-05-09 03:08:40 -04:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->paint_tower)
|
|
|
|
meta_texture_tower_free (stex->paint_tower);
|
|
|
|
stex->paint_tower = NULL;
|
2009-10-30 09:06:28 -04:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
g_clear_pointer (&stex->texture, cogl_object_unref);
|
2009-01-30 06:56:58 -05:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
meta_shaped_texture_set_mask_texture (stex, NULL);
|
|
|
|
meta_shaped_texture_reset_pipelines (stex);
|
2016-10-20 03:44:27 -04:00
|
|
|
|
2020-01-11 00:53:11 -05:00
|
|
|
g_clear_pointer (&stex->opaque_region, cairo_region_destroy);
|
2020-06-22 09:53:23 -04:00
|
|
|
g_clear_pointer (&stex->clip_region, cairo_region_destroy);
|
2020-01-11 00:53:11 -05:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
g_clear_pointer (&stex->snippet, cogl_object_unref);
|
2016-10-20 03:48:42 -04:00
|
|
|
|
2010-10-18 13:27:14 -04:00
|
|
|
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
|
2008-09-24 16:36:38 -04:00
|
|
|
}
|
|
|
|
|
2015-07-05 17:53:33 -04:00
|
|
|
static CoglPipeline *
|
2016-10-20 03:44:27 -04:00
|
|
|
get_base_pipeline (MetaShapedTexture *stex,
|
|
|
|
CoglContext *ctx)
|
2015-07-05 17:53:33 -04:00
|
|
|
{
|
2016-10-20 03:44:27 -04:00
|
|
|
CoglPipeline *pipeline;
|
2020-09-11 14:57:28 -04:00
|
|
|
graphene_matrix_t matrix;
|
2016-10-20 03:44:27 -04:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->base_pipeline)
|
|
|
|
return stex->base_pipeline;
|
2016-10-20 03:44:27 -04:00
|
|
|
|
|
|
|
pipeline = cogl_pipeline_new (ctx);
|
|
|
|
cogl_pipeline_set_layer_wrap_mode_s (pipeline, 0,
|
|
|
|
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
|
|
|
|
cogl_pipeline_set_layer_wrap_mode_t (pipeline, 0,
|
|
|
|
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
|
|
|
|
cogl_pipeline_set_layer_wrap_mode_s (pipeline, 1,
|
|
|
|
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
|
|
|
|
cogl_pipeline_set_layer_wrap_mode_t (pipeline, 1,
|
|
|
|
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
|
2019-03-24 15:16:05 -04:00
|
|
|
|
2020-09-11 18:07:06 -04:00
|
|
|
graphene_matrix_init_identity (&matrix);
|
2016-10-20 03:44:27 -04:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->transform != META_MONITOR_TRANSFORM_NORMAL)
|
2018-11-24 12:27:29 -05:00
|
|
|
{
|
2019-02-16 06:41:43 -05:00
|
|
|
graphene_euler_t euler;
|
2018-11-24 12:27:29 -05:00
|
|
|
|
2020-09-11 18:07:06 -04:00
|
|
|
graphene_matrix_translate (&matrix,
|
|
|
|
&GRAPHENE_POINT3D_INIT (-0.5, -0.5, 0.0));
|
2018-10-31 06:47:17 -04:00
|
|
|
switch (stex->transform)
|
2018-11-24 12:27:29 -05:00
|
|
|
{
|
|
|
|
case META_MONITOR_TRANSFORM_90:
|
2019-02-16 06:41:43 -05:00
|
|
|
graphene_euler_init_with_order (&euler, 0.0, 0.0, 90.0,
|
|
|
|
GRAPHENE_EULER_ORDER_SYXZ);
|
2018-11-24 12:27:29 -05:00
|
|
|
break;
|
|
|
|
case META_MONITOR_TRANSFORM_180:
|
2019-02-16 06:41:43 -05:00
|
|
|
graphene_euler_init_with_order (&euler, 0.0, 0.0, 180.0,
|
|
|
|
GRAPHENE_EULER_ORDER_SYXZ);
|
2018-11-24 12:27:29 -05:00
|
|
|
break;
|
|
|
|
case META_MONITOR_TRANSFORM_270:
|
2019-02-16 06:41:43 -05:00
|
|
|
graphene_euler_init_with_order (&euler, 0.0, 0.0, 270.0,
|
|
|
|
GRAPHENE_EULER_ORDER_SYXZ);
|
2018-11-24 12:27:29 -05:00
|
|
|
break;
|
|
|
|
case META_MONITOR_TRANSFORM_FLIPPED:
|
2019-02-16 06:41:43 -05:00
|
|
|
graphene_euler_init_with_order (&euler, 0.0, 180.0, 0.0,
|
|
|
|
GRAPHENE_EULER_ORDER_SYXZ);
|
2018-11-24 12:27:29 -05:00
|
|
|
break;
|
|
|
|
case META_MONITOR_TRANSFORM_FLIPPED_90:
|
2019-02-16 06:41:43 -05:00
|
|
|
graphene_euler_init_with_order (&euler, 180.0, 0.0, 90.0,
|
|
|
|
GRAPHENE_EULER_ORDER_SYXZ);
|
2018-11-24 12:27:29 -05:00
|
|
|
break;
|
|
|
|
case META_MONITOR_TRANSFORM_FLIPPED_180:
|
2019-02-16 06:41:43 -05:00
|
|
|
graphene_euler_init_with_order (&euler, 0.0, 180.0, 180.0,
|
|
|
|
GRAPHENE_EULER_ORDER_SYXZ);
|
2018-11-24 12:27:29 -05:00
|
|
|
break;
|
|
|
|
case META_MONITOR_TRANSFORM_FLIPPED_270:
|
2019-02-16 06:41:43 -05:00
|
|
|
graphene_euler_init_with_order (&euler, 180.0, 0.0, 270.0,
|
|
|
|
GRAPHENE_EULER_ORDER_SYXZ);
|
2018-11-24 12:27:29 -05:00
|
|
|
break;
|
|
|
|
case META_MONITOR_TRANSFORM_NORMAL:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
2020-09-11 18:07:06 -04:00
|
|
|
graphene_matrix_rotate_euler (&matrix, &euler);
|
|
|
|
graphene_matrix_translate (&matrix,
|
|
|
|
&GRAPHENE_POINT3D_INIT (0.5, 0.5, 0.0));
|
2019-03-24 15:16:05 -04:00
|
|
|
}
|
2018-11-24 12:27:29 -05:00
|
|
|
|
2019-03-24 15:16:05 -04:00
|
|
|
if (stex->has_viewport_src_rect)
|
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
float scaled_tex_width = stex->tex_width / (float) stex->buffer_scale;
|
|
|
|
float scaled_tex_height = stex->tex_height / (float) stex->buffer_scale;
|
2020-09-11 18:07:06 -04:00
|
|
|
graphene_point3d_t p;
|
|
|
|
|
|
|
|
graphene_point3d_init (&p,
|
|
|
|
stex->viewport_src_rect.origin.x /
|
|
|
|
stex->viewport_src_rect.size.width,
|
|
|
|
stex->viewport_src_rect.origin.y /
|
|
|
|
stex->viewport_src_rect.size.height,
|
|
|
|
0);
|
|
|
|
graphene_matrix_translate (&matrix, &p);
|
2019-03-24 15:16:05 -04:00
|
|
|
|
|
|
|
if (meta_monitor_transform_is_rotated (stex->transform))
|
|
|
|
{
|
2020-09-11 18:07:06 -04:00
|
|
|
graphene_matrix_scale (&matrix,
|
|
|
|
stex->viewport_src_rect.size.width /
|
|
|
|
scaled_tex_height,
|
|
|
|
stex->viewport_src_rect.size.height /
|
|
|
|
scaled_tex_width,
|
|
|
|
1);
|
2019-03-24 15:16:05 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-11 18:07:06 -04:00
|
|
|
graphene_matrix_scale (&matrix,
|
|
|
|
stex->viewport_src_rect.size.width /
|
|
|
|
scaled_tex_width,
|
|
|
|
stex->viewport_src_rect.size.height /
|
|
|
|
scaled_tex_height,
|
|
|
|
1);
|
2019-03-24 15:16:05 -04:00
|
|
|
}
|
2020-09-11 18:07:06 -04:00
|
|
|
}
|
2019-03-24 15:16:05 -04:00
|
|
|
|
2020-09-11 18:07:06 -04:00
|
|
|
if (!stex->is_y_inverted)
|
|
|
|
{
|
|
|
|
graphene_matrix_translate (&matrix, &GRAPHENE_POINT3D_INIT (0, -1, 0));
|
|
|
|
graphene_matrix_scale (&matrix, 1, -1, 1);
|
|
|
|
cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
|
2018-11-24 12:27:29 -05:00
|
|
|
}
|
|
|
|
|
2019-03-24 15:16:05 -04:00
|
|
|
cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
|
|
|
|
cogl_pipeline_set_layer_matrix (pipeline, 1, &matrix);
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->snippet)
|
|
|
|
cogl_pipeline_add_layer_snippet (pipeline, 0, stex->snippet);
|
2016-10-20 03:48:42 -04:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->base_pipeline = pipeline;
|
2016-10-20 03:44:27 -04:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
return stex->base_pipeline;
|
2015-07-05 17:53:33 -04:00
|
|
|
}
|
|
|
|
|
2013-08-27 16:03:42 -04:00
|
|
|
static CoglPipeline *
|
2016-10-20 03:44:27 -04:00
|
|
|
get_unmasked_pipeline (MetaShapedTexture *stex,
|
|
|
|
CoglContext *ctx)
|
2013-08-27 16:03:42 -04:00
|
|
|
{
|
2016-10-20 03:44:27 -04:00
|
|
|
return get_base_pipeline (stex, ctx);
|
2013-08-27 16:03:42 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static CoglPipeline *
|
2016-10-20 03:44:27 -04:00
|
|
|
get_masked_pipeline (MetaShapedTexture *stex,
|
|
|
|
CoglContext *ctx)
|
2013-08-27 16:03:42 -04:00
|
|
|
{
|
2016-10-20 03:44:27 -04:00
|
|
|
CoglPipeline *pipeline;
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->masked_pipeline)
|
|
|
|
return stex->masked_pipeline;
|
2016-10-20 03:44:27 -04:00
|
|
|
|
|
|
|
pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx));
|
|
|
|
cogl_pipeline_set_layer_combine (pipeline, 1,
|
|
|
|
"RGBA = MODULATE (PREVIOUS, TEXTURE[A])",
|
|
|
|
NULL);
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->masked_pipeline = pipeline;
|
2013-08-27 16:03:42 -04:00
|
|
|
|
2016-10-20 03:44:27 -04:00
|
|
|
return pipeline;
|
2013-08-27 16:03:42 -04:00
|
|
|
}
|
|
|
|
|
2013-08-27 16:17:34 -04:00
|
|
|
static CoglPipeline *
|
2016-10-20 03:44:27 -04:00
|
|
|
get_unblended_pipeline (MetaShapedTexture *stex,
|
|
|
|
CoglContext *ctx)
|
2013-08-27 16:17:34 -04:00
|
|
|
{
|
2016-10-20 03:44:27 -04:00
|
|
|
CoglPipeline *pipeline;
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->unblended_pipeline)
|
|
|
|
return stex->unblended_pipeline;
|
2013-08-27 16:17:34 -04:00
|
|
|
|
2016-10-20 03:44:27 -04:00
|
|
|
pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx));
|
2020-06-25 07:00:29 -04:00
|
|
|
cogl_pipeline_set_layer_combine (pipeline, 0,
|
|
|
|
"RGBA = REPLACE (TEXTURE)",
|
|
|
|
NULL);
|
2016-10-20 03:44:27 -04:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->unblended_pipeline = pipeline;
|
2016-10-20 03:44:27 -04:00
|
|
|
|
|
|
|
return pipeline;
|
2013-08-27 16:17:34 -04:00
|
|
|
}
|
|
|
|
|
2020-07-15 15:03:48 -04:00
|
|
|
static CoglPipeline *
|
|
|
|
get_opaque_overlay_pipeline (CoglContext *ctx)
|
|
|
|
{
|
|
|
|
CoglPipeline *pipeline;
|
|
|
|
|
|
|
|
pipeline = cogl_context_get_named_pipeline (ctx,
|
|
|
|
&opaque_overlay_pipeline_key);
|
|
|
|
if (!pipeline)
|
|
|
|
{
|
|
|
|
pipeline = cogl_pipeline_new (ctx);
|
|
|
|
cogl_pipeline_set_color4ub (pipeline, 0x00, 0x33, 0x00, 0x33);
|
|
|
|
|
|
|
|
cogl_context_set_named_pipeline (ctx,
|
|
|
|
&opaque_overlay_pipeline_key,
|
|
|
|
pipeline);
|
|
|
|
}
|
|
|
|
|
|
|
|
return pipeline;
|
|
|
|
}
|
|
|
|
|
|
|
|
static CoglPipeline *
|
|
|
|
get_blended_overlay_pipeline (CoglContext *ctx)
|
|
|
|
{
|
|
|
|
CoglPipeline *pipeline;
|
|
|
|
|
|
|
|
pipeline = cogl_context_get_named_pipeline (ctx,
|
|
|
|
&blended_overlay_pipeline_key);
|
|
|
|
if (!pipeline)
|
|
|
|
{
|
|
|
|
pipeline = cogl_pipeline_new (ctx);
|
|
|
|
cogl_pipeline_set_color4ub (pipeline, 0x33, 0x00, 0x33, 0x33);
|
|
|
|
|
|
|
|
cogl_context_set_named_pipeline (ctx,
|
|
|
|
&blended_overlay_pipeline_key,
|
|
|
|
pipeline);
|
|
|
|
}
|
|
|
|
|
|
|
|
return pipeline;
|
|
|
|
}
|
|
|
|
|
2013-08-27 16:17:34 -04:00
|
|
|
static void
|
2018-12-26 10:41:26 -05:00
|
|
|
paint_clipped_rectangle_node (MetaShapedTexture *stex,
|
|
|
|
ClutterPaintNode *root_node,
|
|
|
|
CoglPipeline *pipeline,
|
|
|
|
cairo_rectangle_int_t *rect,
|
|
|
|
ClutterActorBox *alloc)
|
2013-08-27 16:17:34 -04:00
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
g_autoptr (ClutterPaintNode) node = NULL;
|
2018-12-27 11:16:50 -05:00
|
|
|
float ratio_h, ratio_v;
|
|
|
|
float x1, y1, x2, y2;
|
2013-08-27 16:17:34 -04:00
|
|
|
float coords[8];
|
2018-11-30 09:34:00 -05:00
|
|
|
float alloc_width;
|
|
|
|
float alloc_height;
|
2013-08-27 16:17:34 -04:00
|
|
|
|
2018-12-27 11:16:50 -05:00
|
|
|
ratio_h = clutter_actor_box_get_width (alloc) / (float) stex->dst_width;
|
|
|
|
ratio_v = clutter_actor_box_get_height (alloc) / (float) stex->dst_height;
|
|
|
|
|
|
|
|
x1 = alloc->x1 + rect->x * ratio_h;
|
|
|
|
y1 = alloc->y1 + rect->y * ratio_v;
|
|
|
|
x2 = alloc->x1 + (rect->x + rect->width) * ratio_h;
|
|
|
|
y2 = alloc->y1 + (rect->y + rect->height) * ratio_v;
|
|
|
|
|
2018-11-30 09:34:00 -05:00
|
|
|
alloc_width = alloc->x2 - alloc->x1;
|
|
|
|
alloc_height = alloc->y2 - alloc->y1;
|
|
|
|
|
2018-12-27 11:16:50 -05:00
|
|
|
coords[0] = rect->x / alloc_width * ratio_h;
|
|
|
|
coords[1] = rect->y / alloc_height * ratio_v;
|
|
|
|
coords[2] = (rect->x + rect->width) / alloc_width * ratio_h;
|
|
|
|
coords[3] = (rect->y + rect->height) / alloc_height * ratio_v;
|
2013-08-27 16:17:34 -04:00
|
|
|
|
|
|
|
coords[4] = coords[0];
|
|
|
|
coords[5] = coords[1];
|
|
|
|
coords[6] = coords[2];
|
|
|
|
coords[7] = coords[3];
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
node = clutter_pipeline_node_new (pipeline);
|
2020-02-21 17:36:31 -05:00
|
|
|
clutter_paint_node_set_static_name (node, "MetaShapedTexture (clipped)");
|
2018-12-26 10:41:26 -05:00
|
|
|
clutter_paint_node_add_child (root_node, node);
|
|
|
|
|
|
|
|
clutter_paint_node_add_multitexture_rectangle (node,
|
|
|
|
&(ClutterActorBox) {
|
2018-12-27 11:16:50 -05:00
|
|
|
.x1 = x1,
|
|
|
|
.y1 = y1,
|
|
|
|
.x2 = x2,
|
|
|
|
.y2 = y2,
|
2018-12-26 10:41:26 -05:00
|
|
|
},
|
|
|
|
coords, 8);
|
2013-08-27 16:17:34 -04:00
|
|
|
}
|
|
|
|
|
2012-01-07 17:21:32 -05:00
|
|
|
static void
|
|
|
|
set_cogl_texture (MetaShapedTexture *stex,
|
|
|
|
CoglTexture *cogl_tex)
|
|
|
|
{
|
2018-09-14 09:37:50 -04:00
|
|
|
int width, height;
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2019-12-06 12:38:46 -05:00
|
|
|
cogl_clear_object (&stex->texture);
|
2012-01-07 17:21:32 -05:00
|
|
|
|
|
|
|
if (cogl_tex != NULL)
|
|
|
|
{
|
2019-12-06 12:38:46 -05:00
|
|
|
stex->texture = cogl_object_ref (cogl_tex);
|
2012-01-07 17:21:32 -05:00
|
|
|
width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
|
|
|
|
height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-07-28 05:08:25 -04:00
|
|
|
width = 0;
|
|
|
|
height = 0;
|
|
|
|
}
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->tex_width != width ||
|
|
|
|
stex->tex_height != height)
|
2014-07-28 05:08:25 -04:00
|
|
|
{
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->tex_width = width;
|
|
|
|
stex->tex_height = height;
|
2018-11-24 12:27:29 -05:00
|
|
|
update_size (stex);
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* NB: We don't queue a redraw of the actor here because we don't
|
|
|
|
* know how much of the buffer has changed with respect to the
|
|
|
|
* previous buffer. We only queue a redraw in response to surface
|
|
|
|
* damage. */
|
2013-11-04 21:44:25 -05:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->create_mipmaps)
|
|
|
|
meta_texture_tower_set_base_texture (stex->paint_tower, cogl_tex);
|
2012-01-07 17:21:32 -05:00
|
|
|
}
|
|
|
|
|
2018-05-09 03:08:40 -04:00
|
|
|
static gboolean
|
|
|
|
texture_is_idle_and_not_mipmapped (gpointer user_data)
|
|
|
|
{
|
|
|
|
MetaShapedTexture *stex = META_SHAPED_TEXTURE (user_data);
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
if ((g_get_monotonic_time () - stex->earliest_remipmap) < 0)
|
2018-05-09 03:08:40 -04:00
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
clutter_content_invalidate (CLUTTER_CONTENT (stex));
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->remipmap_timeout_id = 0;
|
2018-05-09 03:08:40 -04:00
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
shaped-texture: Fix use-nearest check when viewports are scaled
We checked that the content size was appropriately painted in the stage,
but didn't take into account that the size of the sampled texture
region, meaning that when stage views were scaled, we'd think that we
would draw a texture scaled, as e.g. a 200x200 sized texture with buffer
scale 2 would have the size 100x100. When stage views were not scaled,
we'd apply a geometry scale meaning it'd end up as 200x200 anyway, thus
pass the check, but when stage views are scaled, it'd still be painted
as a 100x100 shaped texture on the stage, thus failing the
are-we-unscaled test.
Fix this by comparing the transformed paint size with the sampled size,
instead of the paint size again, when checking whether we are being
painted scaled or not. For example, when stage views are scaled, our
200x200 buffer with buffer scale 2, thus content size 100x100 will
transform to a 200x200 paint command, thus passing the test. For
non-scaled stage views, our 200x200 buffer with buffer scale 2 thus
content size 100x100 will also transform into a 200x200 paint command,
and will also pass the check, as the texture sample region is still
200x200.
Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/804
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1124
2020-03-13 14:31:23 -04:00
|
|
|
static inline void
|
|
|
|
flip_ints (int *x,
|
|
|
|
int *y)
|
|
|
|
{
|
|
|
|
int tmp;
|
|
|
|
|
|
|
|
tmp = *x;
|
|
|
|
*x = *y;
|
|
|
|
*y = tmp;
|
|
|
|
}
|
|
|
|
|
2008-09-24 16:36:38 -04:00
|
|
|
static void
|
2019-11-22 05:41:04 -05:00
|
|
|
do_paint_content (MetaShapedTexture *stex,
|
|
|
|
ClutterPaintNode *root_node,
|
|
|
|
ClutterPaintContext *paint_context,
|
|
|
|
CoglTexture *paint_tex,
|
|
|
|
ClutterActorBox *alloc,
|
|
|
|
uint8_t opacity)
|
2008-09-24 16:36:38 -04:00
|
|
|
{
|
2018-11-24 12:27:29 -05:00
|
|
|
int dst_width, dst_height;
|
2018-12-26 10:41:26 -05:00
|
|
|
cairo_rectangle_int_t content_rect;
|
2018-09-14 12:52:56 -04:00
|
|
|
gboolean use_opaque_region;
|
|
|
|
cairo_region_t *blended_tex_region;
|
2013-08-27 16:03:42 -04:00
|
|
|
CoglContext *ctx;
|
2013-10-09 20:38:52 -04:00
|
|
|
CoglPipelineFilter filter;
|
2019-11-22 04:19:09 -05:00
|
|
|
CoglFramebuffer *framebuffer;
|
shaped-texture: Fix use-nearest check when viewports are scaled
We checked that the content size was appropriately painted in the stage,
but didn't take into account that the size of the sampled texture
region, meaning that when stage views were scaled, we'd think that we
would draw a texture scaled, as e.g. a 200x200 sized texture with buffer
scale 2 would have the size 100x100. When stage views were not scaled,
we'd apply a geometry scale meaning it'd end up as 200x200 anyway, thus
pass the check, but when stage views are scaled, it'd still be painted
as a 100x100 shaped texture on the stage, thus failing the
are-we-unscaled test.
Fix this by comparing the transformed paint size with the sampled size,
instead of the paint size again, when checking whether we are being
painted scaled or not. For example, when stage views are scaled, our
200x200 buffer with buffer scale 2, thus content size 100x100 will
transform to a 200x200 paint command, thus passing the test. For
non-scaled stage views, our 200x200 buffer with buffer scale 2 thus
content size 100x100 will also transform into a 200x200 paint command,
and will also pass the check, as the texture sample region is still
200x200.
Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/804
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1124
2020-03-13 14:31:23 -04:00
|
|
|
int sample_width, sample_height;
|
2020-07-15 15:03:48 -04:00
|
|
|
gboolean debug_paint_opaque_region;
|
2008-11-22 11:19:17 -05:00
|
|
|
|
2018-11-24 12:27:29 -05:00
|
|
|
ensure_size_valid (stex);
|
2008-11-22 11:19:17 -05:00
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
dst_width = stex->dst_width;
|
2018-10-31 06:47:17 -04:00
|
|
|
dst_height = stex->dst_height;
|
2018-12-26 10:41:26 -05:00
|
|
|
|
2018-11-24 12:27:29 -05:00
|
|
|
if (dst_width == 0 || dst_height == 0) /* no contents yet */
|
2008-11-22 11:19:17 -05:00
|
|
|
return;
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
content_rect = (cairo_rectangle_int_t) {
|
|
|
|
.x = 0,
|
|
|
|
.y = 0,
|
|
|
|
.width = dst_width,
|
|
|
|
.height = dst_height,
|
|
|
|
};
|
2014-08-24 12:02:53 -04:00
|
|
|
|
2020-07-15 15:03:48 -04:00
|
|
|
debug_paint_opaque_region =
|
|
|
|
meta_get_debug_paint_flags() & META_DEBUG_PAINT_OPAQUE_REGION;
|
|
|
|
|
2013-10-09 20:38:52 -04:00
|
|
|
/* Use nearest-pixel interpolation if the texture is unscaled. This
|
|
|
|
* improves performance, especially with software rendering.
|
|
|
|
*/
|
|
|
|
|
2019-11-22 04:19:09 -05:00
|
|
|
framebuffer = clutter_paint_node_get_framebuffer (root_node);
|
|
|
|
if (!framebuffer)
|
2019-11-22 05:41:04 -05:00
|
|
|
framebuffer = clutter_paint_context_get_framebuffer (paint_context);
|
shaped-texture: Fix use-nearest check when viewports are scaled
We checked that the content size was appropriately painted in the stage,
but didn't take into account that the size of the sampled texture
region, meaning that when stage views were scaled, we'd think that we
would draw a texture scaled, as e.g. a 200x200 sized texture with buffer
scale 2 would have the size 100x100. When stage views were not scaled,
we'd apply a geometry scale meaning it'd end up as 200x200 anyway, thus
pass the check, but when stage views are scaled, it'd still be painted
as a 100x100 shaped texture on the stage, thus failing the
are-we-unscaled test.
Fix this by comparing the transformed paint size with the sampled size,
instead of the paint size again, when checking whether we are being
painted scaled or not. For example, when stage views are scaled, our
200x200 buffer with buffer scale 2, thus content size 100x100 will
transform to a 200x200 paint command, thus passing the test. For
non-scaled stage views, our 200x200 buffer with buffer scale 2 thus
content size 100x100 will also transform into a 200x200 paint command,
and will also pass the check, as the texture sample region is still
200x200.
Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/804
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1124
2020-03-13 14:31:23 -04:00
|
|
|
|
|
|
|
if (stex->has_viewport_src_rect)
|
|
|
|
{
|
|
|
|
sample_width = stex->viewport_src_rect.size.width * stex->buffer_scale;
|
|
|
|
sample_height = stex->viewport_src_rect.size.height * stex->buffer_scale;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sample_width = cogl_texture_get_width (stex->texture);
|
|
|
|
sample_height = cogl_texture_get_height (stex->texture);
|
|
|
|
}
|
|
|
|
if (meta_monitor_transform_is_rotated (stex->transform))
|
|
|
|
flip_ints (&sample_width, &sample_height);
|
|
|
|
|
2019-11-22 04:19:09 -05:00
|
|
|
if (meta_actor_painting_untransformed (framebuffer,
|
2018-12-19 05:55:43 -05:00
|
|
|
dst_width, dst_height,
|
shaped-texture: Fix use-nearest check when viewports are scaled
We checked that the content size was appropriately painted in the stage,
but didn't take into account that the size of the sampled texture
region, meaning that when stage views were scaled, we'd think that we
would draw a texture scaled, as e.g. a 200x200 sized texture with buffer
scale 2 would have the size 100x100. When stage views were not scaled,
we'd apply a geometry scale meaning it'd end up as 200x200 anyway, thus
pass the check, but when stage views are scaled, it'd still be painted
as a 100x100 shaped texture on the stage, thus failing the
are-we-unscaled test.
Fix this by comparing the transformed paint size with the sampled size,
instead of the paint size again, when checking whether we are being
painted scaled or not. For example, when stage views are scaled, our
200x200 buffer with buffer scale 2, thus content size 100x100 will
transform to a 200x200 paint command, thus passing the test. For
non-scaled stage views, our 200x200 buffer with buffer scale 2 thus
content size 100x100 will also transform into a 200x200 paint command,
and will also pass the check, as the texture sample region is still
200x200.
Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/804
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1124
2020-03-13 14:31:23 -04:00
|
|
|
sample_width, sample_height,
|
2018-12-19 05:55:43 -05:00
|
|
|
NULL, NULL))
|
2013-11-25 15:27:48 -05:00
|
|
|
filter = COGL_PIPELINE_FILTER_NEAREST;
|
shaped-texture: Fix use-nearest check when viewports are scaled
We checked that the content size was appropriately painted in the stage,
but didn't take into account that the size of the sampled texture
region, meaning that when stage views were scaled, we'd think that we
would draw a texture scaled, as e.g. a 200x200 sized texture with buffer
scale 2 would have the size 100x100. When stage views were not scaled,
we'd apply a geometry scale meaning it'd end up as 200x200 anyway, thus
pass the check, but when stage views are scaled, it'd still be painted
as a 100x100 shaped texture on the stage, thus failing the
are-we-unscaled test.
Fix this by comparing the transformed paint size with the sampled size,
instead of the paint size again, when checking whether we are being
painted scaled or not. For example, when stage views are scaled, our
200x200 buffer with buffer scale 2, thus content size 100x100 will
transform to a 200x200 paint command, thus passing the test. For
non-scaled stage views, our 200x200 buffer with buffer scale 2 thus
content size 100x100 will also transform into a 200x200 paint command,
and will also pass the check, as the texture sample region is still
200x200.
Fixes: https://gitlab.gnome.org/GNOME/mutter/issues/804
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1124
2020-03-13 14:31:23 -04:00
|
|
|
else
|
|
|
|
filter = COGL_PIPELINE_FILTER_LINEAR;
|
2013-10-09 20:38:52 -04:00
|
|
|
|
2013-08-27 16:03:42 -04:00
|
|
|
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
use_opaque_region = stex->opaque_region && opacity == 255;
|
2014-08-24 12:02:53 -04:00
|
|
|
|
|
|
|
if (use_opaque_region)
|
|
|
|
{
|
2020-06-22 09:53:23 -04:00
|
|
|
if (stex->clip_region)
|
|
|
|
blended_tex_region = cairo_region_copy (stex->clip_region);
|
|
|
|
else
|
|
|
|
blended_tex_region = cairo_region_create_rectangle (&content_rect);
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
cairo_region_subtract (blended_tex_region, stex->opaque_region);
|
2014-08-24 12:02:53 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-06-22 09:53:23 -04:00
|
|
|
if (stex->clip_region)
|
|
|
|
blended_tex_region = cairo_region_reference (stex->clip_region);
|
|
|
|
else
|
|
|
|
blended_tex_region = NULL;
|
2014-08-24 12:02:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Limit to how many separate rectangles we'll draw; beyond this just
|
|
|
|
* fall back and draw the whole thing */
|
|
|
|
#define MAX_RECTS 16
|
|
|
|
|
2018-09-14 12:52:56 -04:00
|
|
|
if (blended_tex_region)
|
2014-08-24 12:02:53 -04:00
|
|
|
{
|
2018-09-14 12:52:56 -04:00
|
|
|
int n_rects = cairo_region_num_rectangles (blended_tex_region);
|
2014-08-24 12:02:53 -04:00
|
|
|
if (n_rects > MAX_RECTS)
|
|
|
|
{
|
|
|
|
/* Fall back to taking the fully blended path. */
|
|
|
|
use_opaque_region = FALSE;
|
|
|
|
|
2018-09-14 12:52:56 -04:00
|
|
|
g_clear_pointer (&blended_tex_region, cairo_region_destroy);
|
2014-08-24 12:02:53 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* First, paint the unblended parts, which are part of the opaque region. */
|
|
|
|
if (use_opaque_region)
|
2013-08-27 16:17:34 -04:00
|
|
|
{
|
2020-06-22 09:53:23 -04:00
|
|
|
cairo_region_t *region;
|
2013-08-27 16:17:34 -04:00
|
|
|
int n_rects;
|
|
|
|
int i;
|
|
|
|
|
2020-06-22 09:53:23 -04:00
|
|
|
if (stex->clip_region)
|
|
|
|
{
|
|
|
|
region = cairo_region_copy (stex->clip_region);
|
|
|
|
cairo_region_intersect (region, stex->opaque_region);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
region = cairo_region_reference (stex->opaque_region);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cairo_region_is_empty (region))
|
2013-08-27 16:17:34 -04:00
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
CoglPipeline *opaque_pipeline;
|
|
|
|
|
2016-10-20 03:44:27 -04:00
|
|
|
opaque_pipeline = get_unblended_pipeline (stex, ctx);
|
2014-08-24 12:02:53 -04:00
|
|
|
cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex);
|
|
|
|
cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter);
|
|
|
|
|
2020-06-22 09:53:23 -04:00
|
|
|
n_rects = cairo_region_num_rectangles (region);
|
2014-08-24 12:02:53 -04:00
|
|
|
for (i = 0; i < n_rects; i++)
|
|
|
|
{
|
|
|
|
cairo_rectangle_int_t rect;
|
2020-06-22 09:53:23 -04:00
|
|
|
cairo_region_get_rectangle (region, i, &rect);
|
2018-12-26 10:41:26 -05:00
|
|
|
paint_clipped_rectangle_node (stex, root_node,
|
|
|
|
opaque_pipeline,
|
|
|
|
&rect, alloc);
|
2020-07-15 15:03:48 -04:00
|
|
|
|
|
|
|
if (G_UNLIKELY (debug_paint_opaque_region))
|
|
|
|
{
|
|
|
|
CoglPipeline *opaque_overlay_pipeline;
|
|
|
|
|
|
|
|
opaque_overlay_pipeline = get_opaque_overlay_pipeline (ctx);
|
|
|
|
paint_clipped_rectangle_node (stex, root_node,
|
|
|
|
opaque_overlay_pipeline,
|
|
|
|
&rect, alloc);
|
|
|
|
}
|
2014-08-24 12:02:53 -04:00
|
|
|
}
|
2013-08-27 16:17:34 -04:00
|
|
|
}
|
2020-06-22 09:53:23 -04:00
|
|
|
|
|
|
|
cairo_region_destroy (region);
|
2013-08-27 16:17:34 -04:00
|
|
|
}
|
|
|
|
|
2014-08-24 12:02:53 -04:00
|
|
|
/* Now, go ahead and paint the blended parts. */
|
2014-08-25 09:25:55 -04:00
|
|
|
|
|
|
|
/* We have three cases:
|
2018-09-14 12:52:56 -04:00
|
|
|
* 1) blended_tex_region has rectangles - paint the rectangles.
|
|
|
|
* 2) blended_tex_region is empty - don't paint anything
|
|
|
|
* 3) blended_tex_region is NULL - paint fully-blended.
|
2014-08-25 09:25:55 -04:00
|
|
|
*
|
|
|
|
* 1) and 3) are the times where we have to paint stuff. This tests
|
|
|
|
* for 1) and 3).
|
|
|
|
*/
|
2018-09-14 12:52:56 -04:00
|
|
|
if (!blended_tex_region || !cairo_region_is_empty (blended_tex_region))
|
2014-08-25 09:25:55 -04:00
|
|
|
{
|
|
|
|
CoglPipeline *blended_pipeline;
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->mask_texture == NULL)
|
2014-08-25 09:25:55 -04:00
|
|
|
{
|
2016-10-20 03:44:27 -04:00
|
|
|
blended_pipeline = get_unmasked_pipeline (stex, ctx);
|
2014-08-25 09:25:55 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-10-20 03:44:27 -04:00
|
|
|
blended_pipeline = get_masked_pipeline (stex, ctx);
|
2018-10-31 06:47:17 -04:00
|
|
|
cogl_pipeline_set_layer_texture (blended_pipeline, 1, stex->mask_texture);
|
2014-08-25 09:25:55 -04:00
|
|
|
cogl_pipeline_set_layer_filters (blended_pipeline, 1, filter, filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
cogl_pipeline_set_layer_texture (blended_pipeline, 0, paint_tex);
|
|
|
|
cogl_pipeline_set_layer_filters (blended_pipeline, 0, filter, filter);
|
|
|
|
|
|
|
|
CoglColor color;
|
|
|
|
cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
|
|
|
|
cogl_pipeline_set_color (blended_pipeline, &color);
|
|
|
|
|
2018-09-14 12:52:56 -04:00
|
|
|
if (blended_tex_region)
|
2014-08-25 09:25:55 -04:00
|
|
|
{
|
2018-09-14 12:52:56 -04:00
|
|
|
/* 1) blended_tex_region is not empty. Paint the rectangles. */
|
2014-08-25 09:25:55 -04:00
|
|
|
int i;
|
2018-09-14 12:52:56 -04:00
|
|
|
int n_rects = cairo_region_num_rectangles (blended_tex_region);
|
2014-08-25 09:25:55 -04:00
|
|
|
|
|
|
|
for (i = 0; i < n_rects; i++)
|
|
|
|
{
|
|
|
|
cairo_rectangle_int_t rect;
|
2018-09-14 12:52:56 -04:00
|
|
|
cairo_region_get_rectangle (blended_tex_region, i, &rect);
|
2014-08-25 09:25:55 -04:00
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
if (!gdk_rectangle_intersect (&content_rect, &rect, &rect))
|
2014-08-25 09:25:55 -04:00
|
|
|
continue;
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
paint_clipped_rectangle_node (stex, root_node,
|
|
|
|
blended_pipeline,
|
|
|
|
&rect, alloc);
|
2020-07-15 15:03:48 -04:00
|
|
|
|
|
|
|
if (G_UNLIKELY (debug_paint_opaque_region))
|
|
|
|
{
|
|
|
|
CoglPipeline *blended_overlay_pipeline;
|
|
|
|
|
|
|
|
blended_overlay_pipeline = get_blended_overlay_pipeline (ctx);
|
|
|
|
paint_clipped_rectangle_node (stex, root_node,
|
|
|
|
blended_overlay_pipeline,
|
|
|
|
&rect, alloc);
|
|
|
|
}
|
2014-08-25 09:25:55 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
g_autoptr (ClutterPaintNode) node = NULL;
|
|
|
|
|
|
|
|
node = clutter_pipeline_node_new (blended_pipeline);
|
2020-02-21 17:36:31 -05:00
|
|
|
clutter_paint_node_set_static_name (node, "MetaShapedTexture (unclipped)");
|
2018-12-26 10:41:26 -05:00
|
|
|
clutter_paint_node_add_child (root_node, node);
|
|
|
|
|
2018-09-14 12:52:56 -04:00
|
|
|
/* 3) blended_tex_region is NULL. Do a full paint. */
|
2018-12-26 10:41:26 -05:00
|
|
|
clutter_paint_node_add_rectangle (node, alloc);
|
2020-07-15 15:03:48 -04:00
|
|
|
|
|
|
|
if (G_UNLIKELY (debug_paint_opaque_region))
|
|
|
|
{
|
|
|
|
CoglPipeline *blended_overlay_pipeline;
|
|
|
|
g_autoptr (ClutterPaintNode) node_overlay = NULL;
|
|
|
|
|
|
|
|
blended_overlay_pipeline = get_blended_overlay_pipeline (ctx);
|
|
|
|
|
|
|
|
node_overlay = clutter_pipeline_node_new (blended_overlay_pipeline);
|
|
|
|
clutter_paint_node_set_static_name (node_overlay,
|
|
|
|
"MetaShapedTexture (unclipped overlay)");
|
|
|
|
clutter_paint_node_add_child (root_node, node_overlay);
|
|
|
|
clutter_paint_node_add_rectangle (node_overlay, alloc);
|
|
|
|
}
|
2014-08-25 09:25:55 -04:00
|
|
|
}
|
|
|
|
}
|
2009-01-12 08:18:39 -05:00
|
|
|
|
2018-09-14 12:52:56 -04:00
|
|
|
g_clear_pointer (&blended_tex_region, cairo_region_destroy);
|
2008-09-24 16:36:38 -04:00
|
|
|
}
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
static CoglTexture *
|
2019-11-22 05:41:04 -05:00
|
|
|
select_texture_for_paint (MetaShapedTexture *stex,
|
|
|
|
ClutterPaintContext *paint_context)
|
2018-12-19 06:52:58 -05:00
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
CoglTexture *texture = NULL;
|
|
|
|
int64_t now;
|
2018-12-19 06:52:58 -05:00
|
|
|
|
|
|
|
if (!stex->texture)
|
2018-12-26 10:41:26 -05:00
|
|
|
return NULL;
|
2018-12-19 06:52:58 -05:00
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
now = g_get_monotonic_time ();
|
2018-12-19 06:52:58 -05:00
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
if (stex->create_mipmaps && stex->last_invalidation)
|
2018-12-19 06:52:58 -05:00
|
|
|
{
|
|
|
|
int64_t age = now - stex->last_invalidation;
|
|
|
|
|
|
|
|
if (age >= MIN_MIPMAP_AGE_USEC ||
|
|
|
|
stex->fast_updates < MIN_FAST_UPDATES_BEFORE_UNMIPMAP)
|
2019-11-22 05:41:04 -05:00
|
|
|
{
|
|
|
|
texture = meta_texture_tower_get_paint_texture (stex->paint_tower,
|
|
|
|
paint_context);
|
|
|
|
}
|
2018-12-26 10:41:26 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!texture)
|
|
|
|
{
|
|
|
|
texture = stex->texture;
|
2018-12-19 06:52:58 -05:00
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
if (stex->create_mipmaps)
|
|
|
|
{
|
2018-12-19 06:52:58 -05:00
|
|
|
/* Minus 1000 to ensure we don't fail the age test in timeout */
|
|
|
|
stex->earliest_remipmap = now + MIN_MIPMAP_AGE_USEC - 1000;
|
|
|
|
|
|
|
|
if (!stex->remipmap_timeout_id)
|
|
|
|
stex->remipmap_timeout_id =
|
|
|
|
g_timeout_add (MIN_MIPMAP_AGE_USEC / 1000,
|
|
|
|
texture_is_idle_and_not_mipmapped,
|
|
|
|
stex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
return texture;
|
2018-12-19 06:52:58 -05:00
|
|
|
}
|
|
|
|
|
2009-10-30 09:06:28 -04:00
|
|
|
static void
|
2019-11-13 16:21:58 -05:00
|
|
|
meta_shaped_texture_paint_content (ClutterContent *content,
|
|
|
|
ClutterActor *actor,
|
|
|
|
ClutterPaintNode *root_node,
|
|
|
|
ClutterPaintContext *paint_context)
|
2009-10-30 09:06:28 -04:00
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
MetaShapedTexture *stex = META_SHAPED_TEXTURE (content);
|
|
|
|
ClutterActorBox alloc;
|
|
|
|
CoglTexture *paint_tex = NULL;
|
|
|
|
uint8_t opacity;
|
2011-10-04 17:35:11 -04:00
|
|
|
|
2020-06-22 09:53:23 -04:00
|
|
|
if (stex->clip_region && cairo_region_is_empty (stex->clip_region))
|
|
|
|
return;
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
/* 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.
|
|
|
|
*/
|
2019-11-22 05:41:04 -05:00
|
|
|
paint_tex = select_texture_for_paint (stex, paint_context);
|
2018-12-26 10:41:26 -05:00
|
|
|
if (!paint_tex)
|
|
|
|
return;
|
|
|
|
|
|
|
|
opacity = clutter_actor_get_paint_opacity (actor);
|
|
|
|
clutter_actor_get_content_box (actor, &alloc);
|
|
|
|
|
2019-11-22 05:41:04 -05:00
|
|
|
do_paint_content (stex, root_node, paint_context, paint_tex, &alloc, opacity);
|
2011-10-04 17:35:11 -04:00
|
|
|
}
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
static gboolean
|
|
|
|
meta_shaped_texture_get_preferred_size (ClutterContent *content,
|
|
|
|
float *width,
|
|
|
|
float *height)
|
2011-10-04 17:35:11 -04:00
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
MetaShapedTexture *stex = META_SHAPED_TEXTURE (content);
|
2011-10-04 17:35:11 -04:00
|
|
|
|
2018-11-24 12:27:29 -05:00
|
|
|
ensure_size_valid (stex);
|
2011-10-04 17:35:11 -04:00
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
if (width)
|
|
|
|
*width = stex->dst_width;
|
2014-07-31 05:11:43 -04:00
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
if (height)
|
|
|
|
*height = stex->dst_height;
|
2014-07-31 05:11:43 -04:00
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
return TRUE;
|
2014-07-31 05:11:43 -04:00
|
|
|
}
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
static void
|
|
|
|
clutter_content_iface_init (ClutterContentInterface *iface)
|
2012-02-21 10:42:39 -05:00
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
iface->paint_content = meta_shaped_texture_paint_content;
|
|
|
|
iface->get_preferred_size = meta_shaped_texture_get_preferred_size;
|
2012-02-21 10:42:39 -05:00
|
|
|
}
|
|
|
|
|
2010-08-17 17:33:41 -04:00
|
|
|
void
|
2010-10-18 13:27:14 -04:00
|
|
|
meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
|
|
|
|
gboolean create_mipmaps)
|
2010-08-17 17:33:41 -04:00
|
|
|
{
|
2010-10-18 13:27:14 -04:00
|
|
|
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
2010-08-17 17:33:41 -04:00
|
|
|
|
|
|
|
create_mipmaps = create_mipmaps != FALSE;
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
if (create_mipmaps != stex->create_mipmaps)
|
2010-08-17 17:33:41 -04:00
|
|
|
{
|
2013-02-19 19:34:47 -05:00
|
|
|
CoglTexture *base_texture;
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->create_mipmaps = create_mipmaps;
|
|
|
|
base_texture = create_mipmaps ? stex->texture : NULL;
|
|
|
|
meta_texture_tower_set_base_texture (stex->paint_tower, base_texture);
|
2010-08-17 17:33:41 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-18 16:53:32 -04:00
|
|
|
void
|
2012-04-27 00:14:42 -04:00
|
|
|
meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex,
|
2013-02-19 19:34:47 -05:00
|
|
|
CoglTexture *mask_texture)
|
2010-08-18 16:53:32 -04:00
|
|
|
{
|
2010-10-18 13:27:14 -04:00
|
|
|
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
2010-08-18 16:53:32 -04:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
g_clear_pointer (&stex->mask_texture, cogl_object_unref);
|
2010-08-18 16:53:32 -04:00
|
|
|
|
2013-02-19 19:34:47 -05:00
|
|
|
if (mask_texture != NULL)
|
2011-10-04 17:35:11 -04:00
|
|
|
{
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->mask_texture = mask_texture;
|
|
|
|
cogl_object_ref (stex->mask_texture);
|
2011-10-04 17:35:11 -04:00
|
|
|
}
|
2010-08-18 16:53:32 -04:00
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
clutter_content_invalidate (CLUTTER_CONTENT (stex));
|
2010-08-18 16:53:32 -04:00
|
|
|
}
|
|
|
|
|
2013-08-27 10:45:15 -04:00
|
|
|
/**
|
|
|
|
* meta_shaped_texture_update_area:
|
|
|
|
* @stex: #MetaShapedTexture
|
|
|
|
* @x: the x coordinate of the damaged area
|
|
|
|
* @y: the y coordinate of the damaged area
|
|
|
|
* @width: the width of the damaged area
|
|
|
|
* @height: the height of the damaged area
|
2019-01-29 16:53:50 -05:00
|
|
|
* @clip: (out): the resulting clip region
|
2013-08-27 10:45:15 -04:00
|
|
|
*
|
|
|
|
* Repairs the damaged area indicated by @x, @y, @width and @height
|
2014-02-05 14:06:32 -05:00
|
|
|
* and potentially queues a redraw.
|
2013-08-27 10:45:15 -04:00
|
|
|
*
|
|
|
|
* Return value: Whether a redraw have been queued or not
|
|
|
|
*/
|
|
|
|
gboolean
|
2019-01-29 16:53:50 -05:00
|
|
|
meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
|
|
|
int x,
|
|
|
|
int y,
|
|
|
|
int width,
|
|
|
|
int height,
|
|
|
|
cairo_rectangle_int_t *clip)
|
2012-01-07 17:21:32 -05:00
|
|
|
{
|
2018-12-21 11:13:38 -05:00
|
|
|
MetaMonitorTransform inverted_transform;
|
2008-09-24 16:36:38 -04:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->texture == NULL)
|
2013-08-27 10:45:15 -04:00
|
|
|
return FALSE;
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2019-01-29 16:53:50 -05:00
|
|
|
*clip = (cairo_rectangle_int_t) {
|
2018-12-21 11:13:38 -05:00
|
|
|
.x = x,
|
|
|
|
.y = y,
|
|
|
|
.width = width,
|
|
|
|
.height = height
|
|
|
|
};
|
|
|
|
|
2019-01-29 16:53:50 -05:00
|
|
|
meta_rectangle_scale_double (clip,
|
|
|
|
1.0 / stex->buffer_scale,
|
2020-10-29 04:57:45 -04:00
|
|
|
META_ROUNDING_STRATEGY_GROW,
|
2019-01-29 16:53:50 -05:00
|
|
|
clip);
|
|
|
|
|
2018-12-21 11:13:38 -05:00
|
|
|
inverted_transform = meta_monitor_transform_invert (stex->transform);
|
|
|
|
ensure_size_valid (stex);
|
2019-01-29 16:53:50 -05:00
|
|
|
meta_rectangle_transform (clip,
|
2018-12-21 11:13:38 -05:00
|
|
|
inverted_transform,
|
|
|
|
stex->dst_width,
|
|
|
|
stex->dst_height,
|
2019-01-29 16:53:50 -05:00
|
|
|
clip);
|
2018-12-21 11:13:38 -05:00
|
|
|
|
2018-11-30 09:34:00 -05:00
|
|
|
if (stex->has_viewport_src_rect || stex->has_viewport_dst_size)
|
|
|
|
{
|
2019-02-20 10:23:04 -05:00
|
|
|
graphene_rect_t viewport;
|
|
|
|
graphene_rect_t inverted_viewport;
|
2018-11-30 09:34:00 -05:00
|
|
|
float dst_width;
|
|
|
|
float dst_height;
|
|
|
|
int inverted_dst_width;
|
|
|
|
int inverted_dst_height;
|
|
|
|
|
|
|
|
if (stex->has_viewport_src_rect)
|
|
|
|
{
|
|
|
|
viewport = stex->viewport_src_rect;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-02-20 10:23:04 -05:00
|
|
|
viewport = (graphene_rect_t) {
|
2018-11-30 09:34:00 -05:00
|
|
|
.origin.x = 0,
|
|
|
|
.origin.y = 0,
|
2018-12-26 10:41:26 -05:00
|
|
|
.size.width = stex->tex_width,
|
|
|
|
.size.height = stex->tex_height,
|
2018-11-30 09:34:00 -05:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stex->has_viewport_dst_size)
|
|
|
|
{
|
|
|
|
dst_width = (float) stex->viewport_dst_width;
|
|
|
|
dst_height = (float) stex->viewport_dst_height;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
dst_width = (float) stex->tex_width;
|
|
|
|
dst_height = (float) stex->tex_height;
|
2018-11-30 09:34:00 -05:00
|
|
|
}
|
|
|
|
|
2019-02-20 10:23:04 -05:00
|
|
|
inverted_viewport = (graphene_rect_t) {
|
2018-12-26 10:41:26 -05:00
|
|
|
.origin.x = -(viewport.origin.x * (dst_width / viewport.size.width)),
|
|
|
|
.origin.y = -(viewport.origin.y * (dst_height / viewport.size.height)),
|
2018-11-30 09:34:00 -05:00
|
|
|
.size.width = dst_width,
|
|
|
|
.size.height = dst_height
|
|
|
|
};
|
|
|
|
inverted_dst_width = ceilf (viewport.size.width);
|
|
|
|
inverted_dst_height = ceilf (viewport.size.height);
|
|
|
|
|
2019-01-29 16:53:50 -05:00
|
|
|
meta_rectangle_crop_and_scale (clip,
|
2018-11-30 09:34:00 -05:00
|
|
|
&inverted_viewport,
|
|
|
|
inverted_dst_width,
|
|
|
|
inverted_dst_height,
|
2019-01-29 16:53:50 -05:00
|
|
|
clip);
|
2018-11-30 09:34:00 -05:00
|
|
|
}
|
|
|
|
|
2018-12-21 11:13:38 -05:00
|
|
|
meta_texture_tower_update_area (stex->paint_tower,
|
2018-12-26 10:41:26 -05:00
|
|
|
x,
|
|
|
|
y,
|
|
|
|
width,
|
|
|
|
height);
|
2012-01-07 17:21:32 -05:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->prev_invalidation = stex->last_invalidation;
|
|
|
|
stex->last_invalidation = g_get_monotonic_time ();
|
2018-05-09 03:08:40 -04:00
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->prev_invalidation)
|
2018-05-09 03:08:40 -04:00
|
|
|
{
|
2018-10-31 06:47:17 -04:00
|
|
|
gint64 interval = stex->last_invalidation - stex->prev_invalidation;
|
2018-05-09 03:08:40 -04:00
|
|
|
gboolean fast_update = interval < MIN_MIPMAP_AGE_USEC;
|
|
|
|
|
|
|
|
if (!fast_update)
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->fast_updates = 0;
|
|
|
|
else if (stex->fast_updates < MIN_FAST_UPDATES_BEFORE_UNMIPMAP)
|
|
|
|
stex->fast_updates++;
|
2018-05-09 03:08:40 -04:00
|
|
|
}
|
|
|
|
|
2019-01-29 16:53:50 -05:00
|
|
|
return TRUE;
|
2008-09-24 16:36:38 -04:00
|
|
|
}
|
2009-06-29 14:30:26 -04:00
|
|
|
|
2011-10-04 17:35:11 -04:00
|
|
|
/**
|
2013-11-04 22:13:33 -05:00
|
|
|
* meta_shaped_texture_set_texture:
|
2011-10-04 17:35:11 -04:00
|
|
|
* @stex: The #MetaShapedTexture
|
2013-11-04 22:13:33 -05:00
|
|
|
* @pixmap: The #CoglTexture to display
|
2011-10-04 17:35:11 -04:00
|
|
|
*/
|
|
|
|
void
|
2013-11-04 22:13:33 -05:00
|
|
|
meta_shaped_texture_set_texture (MetaShapedTexture *stex,
|
|
|
|
CoglTexture *texture)
|
2011-10-04 17:35:11 -04:00
|
|
|
{
|
|
|
|
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
|
|
|
|
2019-12-06 12:39:56 -05:00
|
|
|
if (stex->texture == texture)
|
|
|
|
return;
|
|
|
|
|
2013-11-04 22:13:33 -05:00
|
|
|
set_cogl_texture (stex, texture);
|
2011-10-04 17:35:11 -04:00
|
|
|
}
|
|
|
|
|
2016-10-20 03:44:27 -04:00
|
|
|
/**
|
|
|
|
* meta_shaped_texture_set_is_y_inverted: (skip)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
meta_shaped_texture_set_is_y_inverted (MetaShapedTexture *stex,
|
|
|
|
gboolean is_y_inverted)
|
|
|
|
{
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->is_y_inverted == is_y_inverted)
|
2016-10-20 03:44:27 -04:00
|
|
|
return;
|
|
|
|
|
|
|
|
meta_shaped_texture_reset_pipelines (stex);
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->is_y_inverted = is_y_inverted;
|
2016-10-20 03:44:27 -04:00
|
|
|
}
|
|
|
|
|
2016-10-20 03:48:42 -04:00
|
|
|
/**
|
|
|
|
* meta_shaped_texture_set_snippet: (skip)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
meta_shaped_texture_set_snippet (MetaShapedTexture *stex,
|
|
|
|
CoglSnippet *snippet)
|
|
|
|
{
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->snippet == snippet)
|
2016-10-20 03:48:42 -04:00
|
|
|
return;
|
|
|
|
|
|
|
|
meta_shaped_texture_reset_pipelines (stex);
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
g_clear_pointer (&stex->snippet, cogl_object_unref);
|
2016-10-20 03:48:42 -04:00
|
|
|
if (snippet)
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->snippet = cogl_object_ref (snippet);
|
2016-10-20 03:48:42 -04:00
|
|
|
}
|
|
|
|
|
2011-10-04 17:35:11 -04:00
|
|
|
/**
|
|
|
|
* meta_shaped_texture_get_texture:
|
|
|
|
* @stex: The #MetaShapedTexture
|
|
|
|
*
|
|
|
|
* Returns: (transfer none): the unshaped texture
|
|
|
|
*/
|
2013-02-19 19:34:47 -05:00
|
|
|
CoglTexture *
|
2011-10-04 17:35:11 -04:00
|
|
|
meta_shaped_texture_get_texture (MetaShapedTexture *stex)
|
|
|
|
{
|
2013-02-19 19:34:47 -05:00
|
|
|
g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL);
|
2018-10-31 06:47:17 -04:00
|
|
|
return COGL_TEXTURE (stex->texture);
|
2011-10-04 17:35:11 -04:00
|
|
|
}
|
|
|
|
|
2013-08-27 16:17:34 -04:00
|
|
|
/**
|
|
|
|
* meta_shaped_texture_set_opaque_region:
|
|
|
|
* @stex: a #MetaShapedTexture
|
|
|
|
* @opaque_region: (transfer full): the region of the texture that
|
|
|
|
* can have blending turned off.
|
|
|
|
*
|
|
|
|
* As most windows have a large portion that does not require blending,
|
|
|
|
* we can easily turn off blending if we know the areas that do not
|
|
|
|
* require blending. This sets the region where we will not blend for
|
|
|
|
* optimization purposes.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
meta_shaped_texture_set_opaque_region (MetaShapedTexture *stex,
|
|
|
|
cairo_region_t *opaque_region)
|
|
|
|
{
|
2020-06-29 06:57:14 -04:00
|
|
|
g_clear_pointer (&stex->opaque_region, cairo_region_destroy);
|
2013-08-27 16:17:34 -04:00
|
|
|
if (opaque_region)
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->opaque_region = cairo_region_reference (opaque_region);
|
2013-08-27 16:17:34 -04:00
|
|
|
}
|
|
|
|
|
2016-03-21 16:43:50 -04:00
|
|
|
cairo_region_t *
|
|
|
|
meta_shaped_texture_get_opaque_region (MetaShapedTexture *stex)
|
|
|
|
{
|
2018-10-31 06:47:17 -04:00
|
|
|
return stex->opaque_region;
|
2016-03-21 16:43:50 -04:00
|
|
|
}
|
|
|
|
|
2019-08-17 04:00:46 -04:00
|
|
|
gboolean
|
2019-08-16 12:08:30 -04:00
|
|
|
meta_shaped_texture_has_alpha (MetaShapedTexture *stex)
|
|
|
|
{
|
|
|
|
CoglTexture *texture;
|
|
|
|
|
|
|
|
texture = stex->texture;
|
|
|
|
if (!texture)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
switch (cogl_texture_get_components (texture))
|
|
|
|
{
|
|
|
|
case COGL_TEXTURE_COMPONENTS_A:
|
|
|
|
case COGL_TEXTURE_COMPONENTS_RGBA:
|
|
|
|
return TRUE;
|
|
|
|
case COGL_TEXTURE_COMPONENTS_RG:
|
|
|
|
case COGL_TEXTURE_COMPONENTS_RGB:
|
|
|
|
case COGL_TEXTURE_COMPONENTS_DEPTH:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_warn_if_reached ();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
meta_shaped_texture_is_opaque (MetaShapedTexture *stex)
|
|
|
|
{
|
|
|
|
CoglTexture *texture;
|
|
|
|
cairo_rectangle_int_t opaque_rect;
|
|
|
|
|
|
|
|
texture = stex->texture;
|
|
|
|
if (!texture)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!meta_shaped_texture_has_alpha (stex))
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
if (!stex->opaque_region)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (cairo_region_num_rectangles (stex->opaque_region) != 1)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
cairo_region_get_extents (stex->opaque_region, &opaque_rect);
|
|
|
|
|
|
|
|
ensure_size_valid (stex);
|
|
|
|
|
|
|
|
return meta_rectangle_equal (&opaque_rect,
|
|
|
|
&(MetaRectangle) {
|
|
|
|
.width = stex->dst_width,
|
|
|
|
.height = stex->dst_height
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-11-24 12:27:29 -05:00
|
|
|
void
|
|
|
|
meta_shaped_texture_set_transform (MetaShapedTexture *stex,
|
|
|
|
MetaMonitorTransform transform)
|
|
|
|
{
|
2018-10-31 06:47:17 -04:00
|
|
|
if (stex->transform == transform)
|
2018-11-24 12:27:29 -05:00
|
|
|
return;
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->transform = transform;
|
2018-11-24 12:27:29 -05:00
|
|
|
|
|
|
|
meta_shaped_texture_reset_pipelines (stex);
|
|
|
|
invalidate_size (stex);
|
|
|
|
}
|
|
|
|
|
2020-04-22 10:02:08 -04:00
|
|
|
/**
|
|
|
|
* meta_shaped_texture_set_viewport_src_rect:
|
|
|
|
* @stex: A #MetaShapedTexture
|
|
|
|
* @src_rect: The viewport source rectangle
|
|
|
|
*
|
|
|
|
* Sets the viewport area that can be used to crop the original texture. The
|
|
|
|
* cropped result can then be optionally scaled afterwards using
|
|
|
|
* meta_shaped_texture_set_viewport_dst_size() as part of a crop-and-scale
|
|
|
|
* operation.
|
|
|
|
*
|
|
|
|
* Note that the viewport's geometry should be provided in the coordinate space
|
|
|
|
* of the texture received by the client, which might've been scaled as noted by
|
|
|
|
* meta_shaped_texture_set_buffer_scale().
|
|
|
|
*
|
|
|
|
* %NULL is an invalid value for @src_rect. Use
|
|
|
|
* meta_shaped_texture_reset_viewport_src_rect() if you want to remove the
|
|
|
|
* cropping source rectangle.
|
|
|
|
*/
|
2018-11-30 09:34:00 -05:00
|
|
|
void
|
|
|
|
meta_shaped_texture_set_viewport_src_rect (MetaShapedTexture *stex,
|
2019-02-20 10:50:15 -05:00
|
|
|
graphene_rect_t *src_rect)
|
2018-11-30 09:34:00 -05:00
|
|
|
{
|
|
|
|
if (!stex->has_viewport_src_rect ||
|
|
|
|
stex->viewport_src_rect.origin.x != src_rect->origin.x ||
|
|
|
|
stex->viewport_src_rect.origin.y != src_rect->origin.y ||
|
|
|
|
stex->viewport_src_rect.size.width != src_rect->size.width ||
|
|
|
|
stex->viewport_src_rect.size.height != src_rect->size.height)
|
|
|
|
{
|
|
|
|
stex->has_viewport_src_rect = TRUE;
|
|
|
|
stex->viewport_src_rect = *src_rect;
|
2019-03-24 15:16:05 -04:00
|
|
|
meta_shaped_texture_reset_pipelines (stex);
|
2018-11-30 09:34:00 -05:00
|
|
|
invalidate_size (stex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_shaped_texture_reset_viewport_src_rect (MetaShapedTexture *stex)
|
|
|
|
{
|
2019-03-28 20:56:34 -04:00
|
|
|
if (!stex->has_viewport_src_rect)
|
|
|
|
return;
|
|
|
|
|
2018-11-30 09:34:00 -05:00
|
|
|
stex->has_viewport_src_rect = FALSE;
|
2019-03-24 15:16:05 -04:00
|
|
|
meta_shaped_texture_reset_pipelines (stex);
|
2018-11-30 09:34:00 -05:00
|
|
|
invalidate_size (stex);
|
|
|
|
}
|
|
|
|
|
2020-04-22 10:02:08 -04:00
|
|
|
/**
|
|
|
|
* meta_shaped_texture_set_viewport_dst_size:
|
|
|
|
* @stex: #MetaShapedTexture
|
|
|
|
* @dst_width: The final viewport width (> 0)
|
2020-05-13 06:10:38 -04:00
|
|
|
* @dst_height: The final viewport height (> 0)
|
2020-04-22 10:02:08 -04:00
|
|
|
*
|
|
|
|
* Sets a viewport size on @stex of the given @width and @height, which may
|
|
|
|
* lead to scaling the texture. If you need to have cropping, use
|
|
|
|
* meta_shaped_texture_set_viewport_src_rect() first, after which the scaling
|
|
|
|
* stemming from this method will be applied.
|
|
|
|
*
|
|
|
|
* If you no longer want to have any scaling, use
|
|
|
|
* meta_shaped_texture_reset_viewport_dst_size() to clear the current
|
|
|
|
* parameters.
|
|
|
|
*/
|
2018-11-30 09:34:00 -05:00
|
|
|
void
|
|
|
|
meta_shaped_texture_set_viewport_dst_size (MetaShapedTexture *stex,
|
|
|
|
int dst_width,
|
|
|
|
int dst_height)
|
|
|
|
{
|
|
|
|
if (!stex->has_viewport_dst_size ||
|
|
|
|
stex->viewport_dst_width != dst_width ||
|
|
|
|
stex->viewport_dst_height != dst_height)
|
|
|
|
{
|
|
|
|
stex->has_viewport_dst_size = TRUE;
|
|
|
|
stex->viewport_dst_width = dst_width;
|
|
|
|
stex->viewport_dst_height = dst_height;
|
|
|
|
invalidate_size (stex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
meta_shaped_texture_reset_viewport_dst_size (MetaShapedTexture *stex)
|
|
|
|
{
|
2019-03-28 20:56:34 -04:00
|
|
|
if (!stex->has_viewport_dst_size)
|
|
|
|
return;
|
|
|
|
|
2018-11-30 09:34:00 -05:00
|
|
|
stex->has_viewport_dst_size = FALSE;
|
|
|
|
invalidate_size (stex);
|
|
|
|
}
|
|
|
|
|
2018-12-20 11:34:18 -05:00
|
|
|
static gboolean
|
|
|
|
should_get_via_offscreen (MetaShapedTexture *stex)
|
|
|
|
{
|
2018-12-20 11:37:48 -05:00
|
|
|
if (!cogl_texture_is_get_data_supported (stex->texture))
|
|
|
|
return TRUE;
|
|
|
|
|
2018-11-30 09:34:00 -05:00
|
|
|
if (stex->has_viewport_src_rect || stex->has_viewport_dst_size)
|
|
|
|
return TRUE;
|
|
|
|
|
2018-12-20 11:34:18 -05:00
|
|
|
switch (stex->transform)
|
|
|
|
{
|
|
|
|
case META_MONITOR_TRANSFORM_90:
|
|
|
|
case META_MONITOR_TRANSFORM_180:
|
|
|
|
case META_MONITOR_TRANSFORM_270:
|
|
|
|
case META_MONITOR_TRANSFORM_FLIPPED:
|
|
|
|
case META_MONITOR_TRANSFORM_FLIPPED_90:
|
|
|
|
case META_MONITOR_TRANSFORM_FLIPPED_180:
|
|
|
|
case META_MONITOR_TRANSFORM_FLIPPED_270:
|
|
|
|
return TRUE;
|
|
|
|
case META_MONITOR_TRANSFORM_NORMAL:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static cairo_surface_t *
|
|
|
|
get_image_via_offscreen (MetaShapedTexture *stex,
|
2019-08-27 09:38:17 -04:00
|
|
|
cairo_rectangle_int_t *clip,
|
|
|
|
int image_width,
|
|
|
|
int image_height)
|
2018-12-20 11:34:18 -05:00
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
g_autoptr (ClutterPaintNode) root_node = NULL;
|
2018-12-20 11:34:18 -05:00
|
|
|
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;
|
2020-09-11 14:57:28 -04:00
|
|
|
graphene_matrix_t projection_matrix;
|
2018-12-20 11:34:18 -05:00
|
|
|
cairo_rectangle_int_t fallback_clip;
|
2018-12-26 10:41:26 -05:00
|
|
|
ClutterColor clear_color;
|
2019-11-13 16:21:58 -05:00
|
|
|
ClutterPaintContext *paint_context;
|
2018-12-20 11:34:18 -05:00
|
|
|
cairo_surface_t *surface;
|
|
|
|
|
|
|
|
if (!clip)
|
|
|
|
{
|
|
|
|
fallback_clip = (cairo_rectangle_int_t) {
|
2019-08-27 09:38:17 -04:00
|
|
|
.width = image_width,
|
|
|
|
.height = image_height,
|
2018-12-20 11:34:18 -05:00
|
|
|
};
|
|
|
|
clip = &fallback_clip;
|
|
|
|
}
|
|
|
|
|
|
|
|
image_texture =
|
|
|
|
COGL_TEXTURE (cogl_texture_2d_new_with_size (cogl_context,
|
2019-08-27 09:38:17 -04:00
|
|
|
image_width,
|
|
|
|
image_height));
|
2018-12-20 11:34:18 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2020-10-13 05:35:47 -04:00
|
|
|
g_object_unref (fb);
|
2018-12-20 11:34:18 -05:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
cogl_framebuffer_push_matrix (fb);
|
2020-09-11 18:07:06 -04:00
|
|
|
graphene_matrix_init_translate (&projection_matrix,
|
|
|
|
&GRAPHENE_POINT3D_INIT (-(image_width / 2.0),
|
|
|
|
-(image_height / 2.0),
|
|
|
|
0));
|
|
|
|
graphene_matrix_scale (&projection_matrix,
|
|
|
|
1.0 / (image_width / 2.0),
|
|
|
|
-1.0 / (image_height / 2.0), 0);
|
2018-12-20 11:34:18 -05:00
|
|
|
|
|
|
|
cogl_framebuffer_set_projection_matrix (fb, &projection_matrix);
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
clear_color = (ClutterColor) { 0, 0, 0, 0 };
|
|
|
|
|
|
|
|
root_node = clutter_root_node_new (fb, &clear_color, COGL_BUFFER_BIT_COLOR);
|
2020-02-21 17:36:31 -05:00
|
|
|
clutter_paint_node_set_static_name (root_node, "MetaShapedTexture.offscreen");
|
2018-12-20 11:34:18 -05:00
|
|
|
|
2020-04-20 15:10:23 -04:00
|
|
|
paint_context =
|
2020-04-20 15:13:38 -04:00
|
|
|
clutter_paint_context_new_for_framebuffer (fb, NULL,
|
|
|
|
CLUTTER_PAINT_FLAG_NONE);
|
2019-11-13 16:21:58 -05:00
|
|
|
|
2019-11-22 05:41:04 -05:00
|
|
|
do_paint_content (stex, root_node, paint_context,
|
2018-12-26 10:41:26 -05:00
|
|
|
stex->texture,
|
|
|
|
&(ClutterActorBox) {
|
2019-08-27 09:38:17 -04:00
|
|
|
0, 0,
|
|
|
|
image_width,
|
|
|
|
image_height,
|
2018-12-26 10:41:26 -05:00
|
|
|
},
|
|
|
|
255);
|
2018-12-20 11:34:18 -05:00
|
|
|
|
2019-11-13 16:21:58 -05:00
|
|
|
clutter_paint_node_paint (root_node, paint_context);
|
|
|
|
clutter_paint_context_destroy (paint_context);
|
2018-12-20 11:34:18 -05:00
|
|
|
|
|
|
|
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));
|
2020-10-13 05:35:47 -04:00
|
|
|
g_object_unref (fb);
|
2018-12-20 11:34:18 -05:00
|
|
|
|
|
|
|
cairo_surface_mark_dirty (surface);
|
|
|
|
|
|
|
|
return surface;
|
|
|
|
}
|
|
|
|
|
2011-12-20 17:21:59 -05:00
|
|
|
/**
|
|
|
|
* meta_shaped_texture_get_image:
|
|
|
|
* @stex: A #MetaShapedTexture
|
2019-09-13 00:00:35 -04:00
|
|
|
* @clip: (nullable): A clipping rectangle, to help prevent extra processing.
|
2011-12-20 17:21:59 -05:00
|
|
|
* In the case that the clipping rectangle is partially or fully
|
|
|
|
* outside the bounds of the texture, the rectangle will be clipped.
|
|
|
|
*
|
|
|
|
* Flattens the two layers of the shaped texture into one ARGB32
|
|
|
|
* image by alpha blending the two images, and returns the flattened
|
|
|
|
* image.
|
|
|
|
*
|
2019-09-13 00:00:35 -04:00
|
|
|
* Returns: (nullable) (transfer full): a new cairo surface to be freed with
|
2011-12-20 17:21:59 -05:00
|
|
|
* cairo_surface_destroy().
|
|
|
|
*/
|
|
|
|
cairo_surface_t *
|
|
|
|
meta_shaped_texture_get_image (MetaShapedTexture *stex,
|
|
|
|
cairo_rectangle_int_t *clip)
|
|
|
|
{
|
2019-08-27 09:38:17 -04:00
|
|
|
cairo_rectangle_int_t *image_clip = NULL;
|
2013-02-19 19:34:47 -05:00
|
|
|
CoglTexture *texture, *mask_texture;
|
2011-12-20 17:21:59 -05:00
|
|
|
cairo_surface_t *surface;
|
|
|
|
|
|
|
|
g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), NULL);
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
texture = COGL_TEXTURE (stex->texture);
|
2011-12-20 17:21:59 -05:00
|
|
|
|
|
|
|
if (texture == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2018-12-20 11:34:18 -05:00
|
|
|
ensure_size_valid (stex);
|
|
|
|
|
|
|
|
if (stex->dst_width == 0 || stex->dst_height == 0)
|
|
|
|
return NULL;
|
2011-12-20 17:21:59 -05:00
|
|
|
|
|
|
|
if (clip != NULL)
|
|
|
|
{
|
2018-12-20 11:34:18 -05:00
|
|
|
cairo_rectangle_int_t dst_rect;
|
|
|
|
|
2019-08-27 09:38:17 -04:00
|
|
|
image_clip = alloca (sizeof (cairo_rectangle_int_t));
|
2018-12-20 11:34:18 -05:00
|
|
|
dst_rect = (cairo_rectangle_int_t) {
|
|
|
|
.width = stex->dst_width,
|
|
|
|
.height = stex->dst_height,
|
|
|
|
};
|
|
|
|
|
2019-08-27 09:38:17 -04:00
|
|
|
if (!meta_rectangle_intersect (&dst_rect, clip,
|
|
|
|
image_clip))
|
2011-12-20 17:21:59 -05:00
|
|
|
return NULL;
|
2019-08-27 09:38:17 -04:00
|
|
|
|
|
|
|
*image_clip = (MetaRectangle) {
|
|
|
|
.x = image_clip->x * stex->buffer_scale,
|
|
|
|
.y = image_clip->y * stex->buffer_scale,
|
|
|
|
.width = image_clip->width * stex->buffer_scale,
|
|
|
|
.height = image_clip->height * stex->buffer_scale,
|
|
|
|
};
|
2011-12-20 17:21:59 -05:00
|
|
|
}
|
|
|
|
|
2018-12-20 11:34:18 -05:00
|
|
|
if (should_get_via_offscreen (stex))
|
2019-08-27 09:38:17 -04:00
|
|
|
{
|
|
|
|
int image_width;
|
|
|
|
int image_height;
|
|
|
|
|
|
|
|
image_width = stex->dst_width * stex->buffer_scale;
|
|
|
|
image_height = stex->dst_height * stex->buffer_scale;
|
|
|
|
return get_image_via_offscreen (stex,
|
|
|
|
image_clip,
|
|
|
|
image_width,
|
|
|
|
image_height);
|
|
|
|
}
|
2018-12-20 11:34:18 -05:00
|
|
|
|
2019-08-27 09:38:17 -04:00
|
|
|
if (image_clip)
|
2011-12-20 17:21:59 -05:00
|
|
|
texture = cogl_texture_new_from_sub_texture (texture,
|
2019-08-27 09:38:17 -04:00
|
|
|
image_clip->x,
|
|
|
|
image_clip->y,
|
|
|
|
image_clip->width,
|
|
|
|
image_clip->height);
|
2011-12-20 17:21:59 -05:00
|
|
|
|
|
|
|
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
|
|
cogl_texture_get_width (texture),
|
|
|
|
cogl_texture_get_height (texture));
|
|
|
|
|
|
|
|
cogl_texture_get_data (texture, CLUTTER_CAIRO_FORMAT_ARGB32,
|
|
|
|
cairo_image_surface_get_stride (surface),
|
|
|
|
cairo_image_surface_get_data (surface));
|
|
|
|
|
|
|
|
cairo_surface_mark_dirty (surface);
|
|
|
|
|
2019-08-27 09:38:17 -04:00
|
|
|
if (image_clip)
|
2011-12-20 17:21:59 -05:00
|
|
|
cogl_object_unref (texture);
|
|
|
|
|
2018-10-31 06:47:17 -04:00
|
|
|
mask_texture = stex->mask_texture;
|
2013-02-19 19:34:47 -05:00
|
|
|
if (mask_texture != NULL)
|
2011-12-20 17:21:59 -05:00
|
|
|
{
|
|
|
|
cairo_t *cr;
|
|
|
|
cairo_surface_t *mask_surface;
|
|
|
|
|
2019-08-27 09:38:17 -04:00
|
|
|
if (image_clip)
|
2018-12-20 11:32:27 -05:00
|
|
|
mask_texture =
|
|
|
|
cogl_texture_new_from_sub_texture (mask_texture,
|
2019-08-27 09:38:17 -04:00
|
|
|
image_clip->x,
|
|
|
|
image_clip->y,
|
|
|
|
image_clip->width,
|
|
|
|
image_clip->height);
|
2011-12-20 17:21:59 -05:00
|
|
|
|
|
|
|
mask_surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
|
|
|
|
cogl_texture_get_width (mask_texture),
|
|
|
|
cogl_texture_get_height (mask_texture));
|
|
|
|
|
|
|
|
cogl_texture_get_data (mask_texture, COGL_PIXEL_FORMAT_A_8,
|
|
|
|
cairo_image_surface_get_stride (mask_surface),
|
|
|
|
cairo_image_surface_get_data (mask_surface));
|
|
|
|
|
|
|
|
cairo_surface_mark_dirty (mask_surface);
|
|
|
|
|
|
|
|
cr = cairo_create (surface);
|
|
|
|
cairo_set_source_surface (cr, mask_surface, 0, 0);
|
|
|
|
cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN);
|
|
|
|
cairo_paint (cr);
|
|
|
|
cairo_destroy (cr);
|
|
|
|
|
|
|
|
cairo_surface_destroy (mask_surface);
|
|
|
|
|
2019-08-27 09:38:17 -04:00
|
|
|
if (image_clip)
|
2011-12-20 17:21:59 -05:00
|
|
|
cogl_object_unref (mask_texture);
|
|
|
|
}
|
|
|
|
|
|
|
|
return surface;
|
|
|
|
}
|
2013-11-04 22:13:33 -05:00
|
|
|
|
2015-06-23 19:23:45 -04:00
|
|
|
void
|
2018-11-24 12:27:29 -05:00
|
|
|
meta_shaped_texture_set_fallback_size (MetaShapedTexture *stex,
|
2018-09-14 09:37:50 -04:00
|
|
|
int fallback_width,
|
|
|
|
int fallback_height)
|
2015-06-23 19:23:45 -04:00
|
|
|
{
|
2018-10-31 06:47:17 -04:00
|
|
|
stex->fallback_width = fallback_width;
|
|
|
|
stex->fallback_height = fallback_height;
|
2018-11-24 12:27:29 -05:00
|
|
|
|
|
|
|
invalidate_size (stex);
|
2015-06-23 19:23:45 -04:00
|
|
|
}
|
|
|
|
|
2018-12-26 10:41:26 -05:00
|
|
|
MetaShapedTexture *
|
|
|
|
meta_shaped_texture_new (void)
|
|
|
|
{
|
|
|
|
return g_object_new (META_TYPE_SHAPED_TEXTURE, NULL);
|
|
|
|
}
|
|
|
|
|
2020-04-22 10:02:08 -04:00
|
|
|
/**
|
|
|
|
* meta_shaped_texture_set_buffer_scale:
|
|
|
|
* @stex: A #MetaShapedTexture
|
|
|
|
* @buffer_scale: The scale that should be applied to coorsinate space
|
|
|
|
*
|
2020-08-26 05:49:50 -04:00
|
|
|
* Instructs @stex to interpret the geometry of the input texture by scaling it
|
2020-04-22 10:02:08 -04:00
|
|
|
* with @buffer_scale. This means that the #CoglTexture that is provided by a
|
2020-08-26 05:49:50 -04:00
|
|
|
* client is already scaled by that factor.
|
2020-04-22 10:02:08 -04:00
|
|
|
*/
|
2018-12-26 10:41:26 -05:00
|
|
|
void
|
|
|
|
meta_shaped_texture_set_buffer_scale (MetaShapedTexture *stex,
|
|
|
|
int buffer_scale)
|
|
|
|
{
|
|
|
|
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
|
|
|
|
|
|
|
if (buffer_scale == stex->buffer_scale)
|
|
|
|
return;
|
|
|
|
|
|
|
|
stex->buffer_scale = buffer_scale;
|
|
|
|
|
|
|
|
invalidate_size (stex);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
meta_shaped_texture_get_buffer_scale (MetaShapedTexture *stex)
|
2013-11-21 16:25:20 -05:00
|
|
|
{
|
2018-12-26 10:41:26 -05:00
|
|
|
g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), 1.0);
|
|
|
|
|
|
|
|
return stex->buffer_scale;
|
|
|
|
}
|
2020-02-03 08:18:57 -05:00
|
|
|
|
2020-04-22 10:02:08 -04:00
|
|
|
/**
|
|
|
|
* meta_shaped_texture_get_width:
|
|
|
|
* @stex: A #MetaShapedTexture
|
|
|
|
*
|
|
|
|
* Returns: The final width of @stex after its shaping operations are applied.
|
|
|
|
*/
|
2020-02-03 08:18:57 -05:00
|
|
|
int
|
|
|
|
meta_shaped_texture_get_width (MetaShapedTexture *stex)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), 0);
|
|
|
|
|
|
|
|
ensure_size_valid (stex);
|
|
|
|
|
|
|
|
return stex->dst_width;
|
|
|
|
}
|
|
|
|
|
2020-04-22 10:02:08 -04:00
|
|
|
/**
|
|
|
|
* meta_shaped_texture_get_height:
|
|
|
|
* @stex: A #MetaShapedTexture
|
|
|
|
*
|
|
|
|
* Returns: The final height of @stex after its shaping operations are applied.
|
|
|
|
*/
|
2020-02-03 08:18:57 -05:00
|
|
|
int
|
|
|
|
meta_shaped_texture_get_height (MetaShapedTexture *stex)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (META_IS_SHAPED_TEXTURE (stex), 0);
|
|
|
|
|
|
|
|
ensure_size_valid (stex);
|
|
|
|
|
|
|
|
return stex->dst_height;
|
|
|
|
}
|