clutter/offscreen-effect: Support adding effect to resource scaled actors

At this level we use ceiled resource-scale when painting fractional value

When using fractional scaling we still need to create an integer-sized
texture and then we should paint it using a size which is proportional
to the real actor size ratio, and only paint a subsample of it, but this
doesn't seem to work properly with some weird scaling values.

Then, it's just better to draw the texture ceiled and then we scale it
down to match the proper actor scaling at paint level.

https://bugzilla.gnome.org/show_bug.cgi?id=765011
https://gitlab.gnome.org/GNOME/mutter/merge_requests/3
This commit is contained in:
Marco Trevisan (Treviño) 2017-09-07 22:59:50 +02:00 committed by Marco Trevisan
parent af3662775e
commit e3966882e8

View File

@ -66,6 +66,8 @@
#include "clutter-offscreen-effect.h" #include "clutter-offscreen-effect.h"
#include <math.h>
#include "cogl/cogl.h" #include "cogl/cogl.h"
#include "clutter-actor-private.h" #include "clutter-actor-private.h"
@ -93,8 +95,8 @@ struct _ClutterOffscreenEffectPrivate
through create_texture(). This needs to be tracked separately so through create_texture(). This needs to be tracked separately so
that we can detect when a different size is calculated and that we can detect when a different size is calculated and
regenerate the fbo */ regenerate the fbo */
int fbo_width; int target_width;
int fbo_height; int target_height;
gint old_opacity_override; gint old_opacity_override;
}; };
@ -136,7 +138,10 @@ clutter_offscreen_effect_real_create_texture (ClutterOffscreenEffect *effect,
} }
static gboolean static gboolean
update_fbo (ClutterEffect *effect, int fbo_width, int fbo_height) update_fbo (ClutterEffect *effect,
int target_width,
int target_height,
float resource_scale)
{ {
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect); ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv; ClutterOffscreenEffectPrivate *priv = self->priv;
@ -151,8 +156,8 @@ update_fbo (ClutterEffect *effect, int fbo_width, int fbo_height)
return FALSE; return FALSE;
} }
if (priv->fbo_width == fbo_width && if (priv->target_width == target_width &&
priv->fbo_height == fbo_height && priv->target_height == target_height &&
priv->offscreen != NULL) priv->offscreen != NULL)
return TRUE; return TRUE;
@ -163,6 +168,8 @@ update_fbo (ClutterEffect *effect, int fbo_width, int fbo_height)
priv->target = cogl_pipeline_new (ctx); priv->target = cogl_pipeline_new (ctx);
if (fmodf (resource_scale, 1.0f) == 0)
{
/* We're always going to render the texture at a 1:1 texel:pixel /* We're always going to render the texture at a 1:1 texel:pixel
ratio so we can use 'nearest' filtering to decrease the ratio so we can use 'nearest' filtering to decrease the
effects of rounding errors in the geometry calculation */ effects of rounding errors in the geometry calculation */
@ -171,6 +178,7 @@ update_fbo (ClutterEffect *effect, int fbo_width, int fbo_height)
COGL_PIPELINE_FILTER_NEAREST, COGL_PIPELINE_FILTER_NEAREST,
COGL_PIPELINE_FILTER_NEAREST); COGL_PIPELINE_FILTER_NEAREST);
} }
}
if (priv->texture != NULL) if (priv->texture != NULL)
{ {
@ -185,14 +193,14 @@ update_fbo (ClutterEffect *effect, int fbo_width, int fbo_height)
} }
priv->texture = priv->texture =
clutter_offscreen_effect_create_texture (self, fbo_width, fbo_height); clutter_offscreen_effect_create_texture (self, target_width, target_height);
if (priv->texture == NULL) if (priv->texture == NULL)
return FALSE; return FALSE;
cogl_pipeline_set_layer_texture (priv->target, 0, priv->texture); cogl_pipeline_set_layer_texture (priv->target, 0, priv->texture);
priv->fbo_width = fbo_width; priv->target_width = target_width;
priv->fbo_height = fbo_height; priv->target_height = target_height;
priv->offscreen = cogl_offscreen_new_to_texture (priv->texture); priv->offscreen = cogl_offscreen_new_to_texture (priv->texture);
if (priv->offscreen == NULL) if (priv->offscreen == NULL)
@ -202,8 +210,8 @@ update_fbo (ClutterEffect *effect, int fbo_width, int fbo_height)
cogl_handle_unref (priv->target); cogl_handle_unref (priv->target);
priv->target = NULL; priv->target = NULL;
priv->fbo_width = 0; priv->target_width = 0;
priv->fbo_height = 0; priv->target_height = 0;
return FALSE; return FALSE;
} }
@ -222,7 +230,9 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect)
const ClutterPaintVolume *volume; const ClutterPaintVolume *volume;
CoglColor transparent; CoglColor transparent;
gfloat stage_width, stage_height; gfloat stage_width, stage_height;
gfloat fbo_width = -1, fbo_height = -1; gfloat target_width = -1, target_height = -1;
gfloat resource_scale;
gfloat ceiled_resource_scale;
ClutterVertex local_offset = { 0.f, 0.f, 0.f }; ClutterVertex local_offset = { 0.f, 0.f, 0.f };
gfloat old_viewport[4]; gfloat old_viewport[4];
@ -235,6 +245,18 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect)
stage = _clutter_actor_get_stage_internal (priv->actor); stage = _clutter_actor_get_stage_internal (priv->actor);
clutter_actor_get_size (stage, &stage_width, &stage_height); clutter_actor_get_size (stage, &stage_width, &stage_height);
if (_clutter_actor_get_real_resource_scale (priv->actor, &resource_scale))
{
ceiled_resource_scale = ceilf (resource_scale);
stage_width *= ceiled_resource_scale;
stage_height *= ceiled_resource_scale;
}
else
{
/* We are sure we have a resource scale set to a good value at paint */
g_assert_not_reached ();
}
/* Get the minimal bounding box for what we want to paint, relative to the /* Get the minimal bounding box for what we want to paint, relative to the
* parent of priv->actor. Note that we may actually be painting a clone of * parent of priv->actor. Note that we may actually be painting a clone of
* priv->actor so we need to be careful to avoid querying the transformation * priv->actor so we need to be careful to avoid querying the transformation
@ -261,10 +283,14 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect)
priv->fbo_offset_x = box.x1 - raw_box.x1; priv->fbo_offset_x = box.x1 - raw_box.x1;
priv->fbo_offset_y = box.y1 - raw_box.y1; priv->fbo_offset_y = box.y1 - raw_box.y1;
clutter_actor_box_get_size (&box, &fbo_width, &fbo_height); clutter_actor_box_scale (&box, ceiled_resource_scale);
clutter_actor_box_get_size (&box, &target_width, &target_height);
target_width = ceilf (target_width);
target_height = ceilf (target_height);
/* First assert that the framebuffer is the right size... */ /* First assert that the framebuffer is the right size... */
if (!update_fbo (effect, fbo_width, fbo_height)) if (!update_fbo (effect, target_width, target_height, resource_scale))
return FALSE; return FALSE;
cogl_get_modelview_matrix (&old_modelview); cogl_get_modelview_matrix (&old_modelview);
@ -366,6 +392,7 @@ clutter_offscreen_effect_paint_texture (ClutterOffscreenEffect *effect)
{ {
ClutterOffscreenEffectPrivate *priv = effect->priv; ClutterOffscreenEffectPrivate *priv = effect->priv;
CoglMatrix modelview; CoglMatrix modelview;
float resource_scale;
cogl_push_matrix (); cogl_push_matrix ();
@ -373,6 +400,14 @@ clutter_offscreen_effect_paint_texture (ClutterOffscreenEffect *effect)
* missing a correction for the expanded FBO and offset rendering within... * missing a correction for the expanded FBO and offset rendering within...
*/ */
cogl_get_modelview_matrix (&modelview); cogl_get_modelview_matrix (&modelview);
if (clutter_actor_get_resource_scale (priv->actor, &resource_scale) &&
resource_scale != 1.0f)
{
float paint_scale = 1.0f / resource_scale;
cogl_matrix_scale (&modelview, paint_scale, paint_scale, 1);
}
cogl_matrix_translate (&modelview, cogl_matrix_translate (&modelview,
priv->fbo_offset_x, priv->fbo_offset_x,
priv->fbo_offset_y, priv->fbo_offset_y,