1
0
Fork 0

Queue clipped redraws work in terms of paint volumes

There is an internal _clutter_actor_queue_redraw_with_clip API that gets
used for texture-from-pixmap to minimize what we redraw in response to
Damage events. It was previously working in terms of a ClutterActorBox
but it has now been changed so an actor can queue a redraw of volume
instead.

The plan is that clutter_actor_queue_redraw will start to transparently
use _clutter_actor_queue_redraw_with_clip when it can determine a paint
volume for the actor.
This commit is contained in:
Robert Bragg 2010-09-07 19:31:27 +01:00
parent f3bffe5cab
commit 1ea7145efc
5 changed files with 114 additions and 81 deletions

View file

@ -457,7 +457,7 @@ struct _ClutterActorPrivate
* of the QUEUE_REDRAW signal. It's an out-of-band argument.
* See clutter_actor_queue_clipped_redraw() for details.
*/
const ClutterActorBox *oob_queue_redraw_clip;
const ClutterPaintVolume *oob_queue_redraw_clip;
ClutterMetaGroup *actions;
ClutterMetaGroup *constraints;
@ -4907,7 +4907,7 @@ _clutter_actor_get_allocation_clip (ClutterActor *self,
ClutterActorBox allocation;
/* XXX: we don't care if we get an out of date allocation here
* because clutter_actor_queue_redraw_with_origin knows to ignore
* because clutter_actor_queue_redraw_with_clip knows to ignore
* the clip if the actor's allocation is invalid.
*
* This is noted because clutter_actor_get_allocation_box does some
@ -4917,7 +4917,7 @@ _clutter_actor_get_allocation_clip (ClutterActor *self,
*/
clutter_actor_get_allocation_box (self, &allocation);
/* NB: clutter_actor_queue_clipped_redraw expects a box in the
/* NB: clutter_actor_queue_redraw_with_clip expects a box in the
* actor's own coordinate space but the allocation is in parent
* coordinates */
clip->x1 = 0;
@ -4931,7 +4931,7 @@ _clutter_actor_get_allocation_clip (ClutterActor *self,
* @self: A #ClutterActor
* @flags: A mask of #ClutterRedrawFlags controlling the behaviour of
* this queue redraw.
* @clip: A #ClutterActorBox describing the bounds of what needs to be
* @volume: A #ClutterPaintVolume describing the bounds of what needs to be
* redrawn or %NULL if you are just using a @flag to state your
* desired clipping.
*
@ -4939,21 +4939,16 @@ _clutter_actor_get_allocation_clip (ClutterActor *self,
* occurs once the main loop becomes idle (after the current batch of
* events has been processed, roughly).
*
* If the %CLUTTER_REDRAW_CLIPPED_TO_BOX @flag is used, the clip box is
* If no flags are given the clip volume is defined by @volume
* specified in actor coordinates and tells Clutter that only content
* within this box has been changed so Clutter can optionally optimize
* the redraw.
* within this volume has been changed so Clutter can optionally
* optimize the redraw.
*
* If you are queuing a clipped redraw it is assumed that the actor is
* flat, and once the clip rectangle is projected into stage
* coordinates it will cover the area of the stage that needs to be
* redrawn. This is not possible to determine for 3D actors since the
* projection of such actors may escape the clip rectangle.
*
* If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @clip
* should be NULL and this tells Clutter to use the actors current
* allocation as a clip box. As above this flag can only be used for
* 2D actors.
* If the %CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION @flag is used, @volume
* should be %NULL and this tells Clutter to use the actor's current
* allocation as a clip box. This flag can only be used for 2D actors,
* because any actor with depth may be projected outside its
* allocation.
*
* Applications rarely need to call this, as redraws are handled
* automatically by modification functions.
@ -4963,16 +4958,25 @@ _clutter_actor_get_allocation_clip (ClutterActor *self,
*
* Also be aware that painting is a NOP for actors with an opacity of
* 0
*
* When you are implementing a custom actor you must queue a redraw
* whenever some private state changes that will affect painting or
* picking of your actor.
*/
void
_clutter_actor_queue_redraw_with_clip (ClutterActor *self,
ClutterRedrawFlags flags,
ClutterActorBox *clip)
ClutterPaintVolume *volume)
{
ClutterActorBox allocation_clip;
ClutterPaintVolume allocation_pv;
ClutterPaintVolume *pv;
gboolean should_free_pv;
/* If the actor doesn't have a valid allocation then we will queue a
* full stage redraw */
* full stage redraw.
*
* XXX: Is this check redundant? Or should it maybe only be done
* when flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION? */
if (self->priv->needs_allocation)
{
clutter_actor_queue_redraw (self);
@ -4981,16 +4985,37 @@ _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
if (flags & CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION)
{
ClutterActorBox allocation_clip;
ClutterVertex origin;
_clutter_paint_volume_init_static (self, &allocation_pv);
pv = &allocation_pv;
_clutter_actor_get_allocation_clip (self, &allocation_clip);
clip = &allocation_clip;
origin.x = allocation_clip.x1;
origin.y = allocation_clip.y1;
origin.z = 0;
clutter_paint_volume_set_origin (pv, &origin);
clutter_paint_volume_set_width (pv,
allocation_clip.x2 - allocation_clip.x1);
clutter_paint_volume_set_height (pv,
allocation_clip.y2 -
allocation_clip.y1);
should_free_pv = TRUE;
}
else
{
pv = volume;
should_free_pv = FALSE;
}
/* XXX: Ideally the redraw signal would take a clip rectangle
/* XXX: Ideally the redraw signal would take a clip volume
* argument, but that would be an ABI break. Until we can break the
* ABI we pass the argument out-of-band via an actor->priv member...
*/
_clutter_actor_set_queue_redraw_clip (self, clip);
_clutter_actor_set_queue_redraw_clip (self, pv);
clutter_actor_queue_redraw_with_origin (self, self);
@ -5001,6 +5026,9 @@ _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
* Note: A NULL clip denotes a full-stage, un-clipped redraw
*/
_clutter_actor_set_queue_redraw_clip (self, NULL);
if (should_free_pv)
clutter_paint_volume_free (pv);
}
/**
@ -10895,7 +10923,7 @@ clutter_actor_has_pointer (ClutterActor *self)
* the QUEUE_REDRAW signal. It is an out-of-band argument. See
* clutter_actor_queue_clipped_redraw() for details.
*/
const ClutterActorBox *
const ClutterPaintVolume *
_clutter_actor_get_queue_redraw_clip (ClutterActor *self)
{
return self->priv->oob_queue_redraw_clip;
@ -10903,7 +10931,7 @@ _clutter_actor_get_queue_redraw_clip (ClutterActor *self)
void
_clutter_actor_set_queue_redraw_clip (ClutterActor *self,
const ClutterActorBox *clip)
const ClutterPaintVolume *clip)
{
self->priv->oob_queue_redraw_clip = clip;
}

View file

@ -136,25 +136,6 @@ typedef enum
CLUTTER_ABSOLUTE_ORIGIN_CHANGED = 1 << 1
} ClutterAllocationFlags;
/**
* ClutterRedrawFlags:
* @CLUTTER_REDRAW_CLIPPED_TO_BOX: Tells clutter the redraw is clipped
* to a given clip box in actor coordinates.
* @CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION: Tells clutter the maximum
* extents of what needs to be redrawn lies within the actors
* current allocation.
*
* Flags passed to the clutter_actor_queue_redraw_with_clip ()
* function
*
* Since: 1.2
*/
typedef enum
{
CLUTTER_REDRAW_CLIPPED_TO_BOX = 0,
CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION = 1 << 1
} ClutterRedrawFlags;
/**
* ClutterActor:
* @flags: #ClutterActorFlags

View file

@ -91,6 +91,23 @@ typedef enum {
CLUTTER_INTERNAL_CHILD = 1 << 6
} ClutterPrivateFlags;
/*
* ClutterRedrawFlags:
* @CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION: Tells clutter the maximum
* extents of what needs to be redrawn lies within the actors
* current allocation. (Only use this for 2D actors though because
* any actor with depth may be projected outside of its allocation)
*
* Flags passed to the clutter_actor_queue_redraw_with_clip ()
* function
*
* Since: 1.6
*/
typedef enum
{
CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION = 1 << 0
} ClutterRedrawFlags;
struct _ClutterInputDevice
{
GObject parent_instance;
@ -452,10 +469,10 @@ gboolean _clutter_actor_transform_and_project_box (ClutterActor *self,
void _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
ClutterRedrawFlags flags,
ClutterActorBox *clip);
const ClutterActorBox *_clutter_actor_get_queue_redraw_clip (ClutterActor *self);
ClutterPaintVolume *clip_volume);
const ClutterPaintVolume *_clutter_actor_get_queue_redraw_clip (ClutterActor *self);
void _clutter_actor_set_queue_redraw_clip (ClutterActor *self,
const ClutterActorBox *clip);
const ClutterPaintVolume *clip_volume);
void _clutter_run_repaint_functions (void);

View file

@ -729,10 +729,10 @@ clutter_stage_real_queue_redraw (ClutterActor *actor,
ClutterStagePrivate *priv = stage->priv;
ClutterStageWindow *stage_window;
ClutterGeometry stage_clip;
const ClutterActorBox *clip;
ClutterActorBox bounds;
ClutterVertex v[4];
int i;
const ClutterPaintVolume *redraw_clip;
ClutterPaintVolume projected_clip;
CoglMatrix modelview;
ClutterActorBox bounding_box;
CLUTTER_NOTE (PAINT, "Redraw request number %lu",
CLUTTER_CONTEXT ()->redraw_count + 1);
@ -761,47 +761,50 @@ clutter_stage_real_queue_redraw (ClutterActor *actor,
/* If the backend can't do anything with redraw clips (e.g. it already knows
* it needs to redraw everything anyway) then don't spend time transforming
* any clip regions into stage coordinates... */
* any clip volume into stage coordinates... */
stage_window = _clutter_stage_get_window (stage);
if (_clutter_stage_window_ignoring_redraw_clips (stage_window))
return;
/* Convert the clip rectangle (which is in leaf actor coordinates) into stage
/* Convert the clip volume (which is in leaf actor coordinates) into stage
* coordinates and then into an axis aligned stage coordinates bounding
* box...
*/
clip = _clutter_actor_get_queue_redraw_clip (leaf);
if (!clip)
if (!_clutter_actor_get_queue_redraw_clip (leaf))
{
_clutter_stage_window_add_redraw_clip (stage_window, NULL);
return;
}
_clutter_actor_transform_and_project_box (leaf, clip, v);
redraw_clip = _clutter_actor_get_queue_redraw_clip (leaf);
bounds.x1 = v[0].x; bounds.y1 = v[0].y;
bounds.x2 = v[0].x; bounds.y2 = v[0].y;
_clutter_paint_volume_copy_static (redraw_clip, &projected_clip);
for (i = 0; i < 4; i++)
{
if (v[i].x < bounds.x1)
bounds.x1 = v[i].x;
else if (v[i].x > bounds.x2)
bounds.x2 = v[i].x;
/* NB: _clutter_actor_apply_modelview_transform_recursive will never
* include the transformation between stage coordinates and OpenGL
* window coordinates, we have to explicitly use the
* stage->apply_transform to get that... */
cogl_matrix_init_identity (&modelview);
_clutter_actor_apply_modelview_transform (CLUTTER_ACTOR (stage), &modelview);
_clutter_actor_apply_modelview_transform_recursive (leaf, NULL, &modelview);
if (v[i].y < bounds.y1)
bounds.y1 = v[i].y;
else if (v[i].y > bounds.y2)
bounds.y2 = v[i].y;
}
_clutter_paint_volume_project (&projected_clip,
&modelview,
&priv->projection,
priv->viewport);
_clutter_paint_volume_get_bounding_box (&projected_clip, &bounding_box);
clutter_paint_volume_free (&projected_clip);
clutter_actor_box_clamp_to_pixel (&bounding_box);
/* when converting to integer coordinates make sure we round the edges of the
* clip rectangle outwards... */
stage_clip.x = bounds.x1;
stage_clip.y = bounds.y1;
stage_clip.width = ceilf (bounds.x2) - stage_clip.x;
stage_clip.height = ceilf (bounds.y2) - stage_clip.y;
stage_clip.x = bounding_box.x1;
stage_clip.y = bounding_box.y1;
stage_clip.width = bounding_box.x2 - stage_clip.x;
stage_clip.height = bounding_box.y2 - stage_clip.y;
_clutter_stage_window_add_redraw_clip (stage_window, &stage_clip);
}

View file

@ -317,7 +317,8 @@ clutter_x11_texture_pixmap_real_queue_damage_redraw (
ClutterActorBox allocation;
float scale_x;
float scale_y;
ClutterActorBox clip;
ClutterVertex origin;
ClutterPaintVolume clip;
/* NB: clutter_actor_queue_clipped_redraw expects a box in the actor's
* coordinate space so we need to convert from pixmap coordinates to
@ -344,14 +345,17 @@ clutter_x11_texture_pixmap_real_queue_damage_redraw (
scale_x = (allocation.x2 - allocation.x1) / priv->pixmap_width;
scale_y = (allocation.y2 - allocation.y1) / priv->pixmap_height;
clip.x1 = x * scale_x;
clip.y1 = y * scale_y;
clip.x2 = clip.x1 + width * scale_x;
clip.y2 = clip.y1 + height * scale_y;
_clutter_paint_volume_init_static (self, &clip);
_clutter_actor_queue_redraw_with_clip (self,
CLUTTER_REDRAW_CLIPPED_TO_BOX,
&clip);
origin.x = x * scale_x;
origin.y = y * scale_y;
origin.z = 0;
clutter_paint_volume_set_origin (&clip, &origin);
clutter_paint_volume_set_width (&clip, width * scale_x);
clutter_paint_volume_set_height (&clip, height * scale_y);
_clutter_actor_queue_redraw_with_clip (self, 0, &clip);
clutter_paint_volume_free (&clip);
}
static void