paint volumes: another pass at the design

This is a fairly extensive second pass at exposing paint volumes for
actors.

The API has changed to allow clutter_actor_get_paint_volume to fail
since there are times - such as when an actor isn't a descendent of the
stage - when the volume can't be determined. Another example is when
something has connected to the "paint" signal of the actor and we simply
have no way of knowing what might be drawn in that handler.

The API has also be changed to return a const ClutterPaintVolume pointer
(transfer none) so we can avoid having to dynamically allocate the
volumes in the most common/performance critical code paths. Profiling was
showing the slice allocation of volumes taking about 1% of an apps time,
for some fairly basic tests. Most volumes can now simply be allocated on
the stack; for clutter_actor_get_paint_volume we return a pointer to
&priv->paint_volume and if we need a more dynamic allocation there is
now a _clutter_stage_paint_volume_stack_allocate() mechanism which lets
us allocate data which expires at the start of the next frame.

The API has been extended to make it easier to implement
get_paint_volume for containers by using
clutter_actor_get_transformed_paint_volume and
clutter_paint_volume_union. The first allows you to query the paint
volume of a child but transformed into parent actor coordinates. The
second lets you combine volumes together so you can union all the
volumes for a container's children and report that as the container's
own volume.

The representation of paint volumes has been updated to consider that
2D actors are the most common.

The effect apis, clutter-texture and clutter-group have been update
accordingly.
This commit is contained in:
Robert Bragg 2010-09-07 18:04:19 +01:00
parent 48a24a2e08
commit 3540d222e1
17 changed files with 1098 additions and 268 deletions

File diff suppressed because it is too large Load Diff

View File

@ -306,7 +306,7 @@ struct _ClutterActorClass
/* accessibility support */
AtkObject * (* get_accessible) (ClutterActor *actor);
void (* get_paint_volume) (ClutterActor *actor,
gboolean (* get_paint_volume) (ClutterActor *actor,
ClutterPaintVolume *volume);
/*< private >*/
@ -589,8 +589,12 @@ gboolean clutter_actor_has_allocation (ClutterActor *sel
AtkObject * clutter_actor_get_accessible (ClutterActor *self);
gboolean clutter_actor_has_key_focus (ClutterActor *self);
ClutterPaintVolume *clutter_actor_get_paint_volume (ClutterActor *self);
void clutter_actor_get_paint_box (ClutterActor *self,
const ClutterPaintVolume *clutter_actor_get_paint_volume (ClutterActor *self);
const ClutterPaintVolume *clutter_actor_get_transformed_paint_volume (ClutterActor *self,
ClutterActor *relative_to_ancestor);
gboolean clutter_actor_get_paint_box (ClutterActor *self,
ClutterActorBox *box);
G_END_DECLS

View File

@ -255,7 +255,7 @@ out:
parent->paint_target (effect);
}
static void
static gboolean
clutter_blur_effect_get_paint_volume (ClutterEffect *effect,
ClutterPaintVolume *volume)
{
@ -273,6 +273,8 @@ clutter_blur_effect_get_paint_volume (ClutterEffect *effect,
clutter_paint_volume_set_origin (volume, &origin);
clutter_paint_volume_set_width (volume, cur_width);
clutter_paint_volume_set_height (volume, cur_height);
return TRUE;
}
static void

View File

@ -191,10 +191,11 @@ clutter_effect_real_post_paint (ClutterEffect *effect)
{
}
static void
static gboolean
clutter_effect_real_get_paint_volume (ClutterEffect *effect,
ClutterPaintVolume *volume)
{
return TRUE;
}
static void
@ -226,12 +227,12 @@ _clutter_effect_post_paint (ClutterEffect *effect)
CLUTTER_EFFECT_GET_CLASS (effect)->post_paint (effect);
}
void
gboolean
_clutter_effect_get_paint_volume (ClutterEffect *effect,
ClutterPaintVolume *volume)
{
g_return_if_fail (CLUTTER_IS_EFFECT (effect));
g_return_if_fail (volume != NULL);
g_return_val_if_fail (CLUTTER_IS_EFFECT (effect), FALSE);
g_return_val_if_fail (volume != NULL, FALSE);
CLUTTER_EFFECT_GET_CLASS (effect)->get_paint_volume (effect, volume);
return CLUTTER_EFFECT_GET_CLASS (effect)->get_paint_volume (effect, volume);
}

View File

@ -75,7 +75,7 @@ struct _ClutterEffectClass
gboolean (* pre_paint) (ClutterEffect *effect);
void (* post_paint) (ClutterEffect *effect);
void (* get_paint_volume) (ClutterEffect *effect,
gboolean (* get_paint_volume) (ClutterEffect *effect,
ClutterPaintVolume *volume);
/*< private >*/

View File

@ -386,8 +386,32 @@ clutter_group_real_hide_all (ClutterActor *actor)
NULL);
}
static gboolean
clutter_group_real_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv;
GList *l;
if (priv->children == NULL)
return TRUE;
for (l = priv->children; l != NULL; l = l->next)
{
ClutterActor *child = l->data;
const ClutterPaintVolume *child_volume;
/* This gets the paint volume of the child transformed into the
* group's coordinate space... */
child_volume = clutter_actor_get_transformed_paint_volume (child, actor);
if (!child_volume)
return FALSE;
clutter_paint_volume_union (volume, child_volume);
}
return TRUE;
}
static void
clutter_group_class_init (ClutterGroupClass *klass)
@ -404,6 +428,7 @@ clutter_group_class_init (ClutterGroupClass *klass)
actor_class->pick = clutter_group_real_pick;
actor_class->show_all = clutter_group_real_show_all;
actor_class->hide_all = clutter_group_real_hide_all;
actor_class->get_paint_volume = clutter_group_real_get_paint_volume;
gobject_class->dispose = clutter_group_dispose;

View File

@ -665,7 +665,7 @@ _clutter_do_pick (ClutterStage *stage,
*/
CLUTTER_TIMER_START (_clutter_uprof_context, pick_paint);
context->pick_mode = mode;
clutter_actor_paint (CLUTTER_ACTOR (stage));
_clutter_stage_do_paint (stage);
context->pick_mode = CLUTTER_PICK_NONE;
CLUTTER_TIMER_STOP (_clutter_uprof_context, pick_paint);

View File

@ -130,11 +130,10 @@ clutter_offscreen_effect_real_create_texture (ClutterOffscreenEffect *effect,
}
static gboolean
update_fbo (ClutterEffect *effect)
update_fbo (ClutterEffect *effect, int fbo_width, int fbo_height)
{
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv;
gfloat width, height;
CoglHandle texture;
priv->stage = clutter_actor_get_stage (priv->actor);
@ -147,21 +146,8 @@ update_fbo (ClutterEffect *effect)
return FALSE;
}
/* the target should at least be big enough to contain the
* transformed allocation of the actor
*
* FIXME - this is actually not enough: we need the paint area
* to make this work reliably
*/
{
ClutterActorBox box = { 0, };
clutter_actor_get_paint_box (priv->actor, &box);
clutter_actor_box_get_size (&box, &width, &height);
}
if (priv->target_width == width &&
priv->target_height == height)
if (priv->target_width == fbo_width &&
priv->target_height == fbo_height)
return TRUE;
if (priv->target != COGL_INVALID_HANDLE)
@ -172,7 +158,8 @@ update_fbo (ClutterEffect *effect)
priv->target = cogl_material_new ();
texture = clutter_offscreen_effect_create_texture (self, width, height);
texture =
clutter_offscreen_effect_create_texture (self, fbo_width, fbo_height);
if (texture == COGL_INVALID_HANDLE)
return FALSE;
@ -203,49 +190,16 @@ update_fbo (ClutterEffect *effect)
return TRUE;
}
static void
get_screen_offsets (ClutterActor *actor,
gfloat *x_offset,
gfloat *y_offset)
{
gfloat v[4] = { 0, };
if (CLUTTER_ACTOR_IS_TOPLEVEL (actor))
{
/* trivial optimization: a top-level actor is always going to
* have a (0, 0) offset
*/
*x_offset = 0.0f;
*y_offset = 0.0f;
}
else
{
ClutterActorBox box = { 0, };
clutter_actor_get_paint_box (actor, &box);
clutter_actor_box_get_origin (&box, x_offset, y_offset);
}
/* since we're setting up a viewport with a negative offset to paint
* in an FBO with the same modelview and projection matrices as the
* stage, we need to offset the computed absolute allocation vertices
* with the current viewport's X and Y offsets. this works even with
* the default case where the viewport is set up by Clutter to be
* (0, 0, stage_width, stage_height)
*/
cogl_get_viewport (v);
*x_offset -= v[0];
*y_offset -= v[1];
}
static gboolean
clutter_offscreen_effect_pre_paint (ClutterEffect *effect)
{
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv;
ClutterActorBox box;
CoglMatrix projection;
CoglColor transparent;
CoglMatrix modelview;
gfloat fbo_width, fbo_height;
gfloat width, height;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
@ -254,7 +208,22 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect)
if (priv->actor == NULL)
return FALSE;
if (!update_fbo (effect))
/* The paint box is the bounding box of the actor's paint volume in
* stage coordinates. This will give us the size for the framebuffer
* we need to redirect its rendering offscreen and its position will
* be used to setup an offset viewport */
if (clutter_actor_get_paint_box (priv->actor, &box))
clutter_actor_box_get_size (&box, &fbo_width, &fbo_height);
else
{
/* If we can't get a valid paint box then we fallback to
* creating a full stage size fbo. */
ClutterActor *stage = _clutter_actor_get_stage_internal (priv->actor);
clutter_actor_get_size (stage, &fbo_width, &fbo_height);
}
/* First assert that the framebuffer is the right size... */
if (!update_fbo (effect, fbo_width, fbo_height))
return FALSE;
/* get the current modelview matrix so that we can copy it
@ -265,12 +234,11 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect)
/* let's draw offscreen */
cogl_push_framebuffer (priv->offscreen);
/* set up the viewport so that it has the same size of the stage,
* and it has its origin at the same position of the stage's; also
* set up the perspective to be the same as the stage's
*/
/* Set up the viewport so that it has the same size as the stage,
* but offset it so that the actor of interest lands on our
* framebuffer. */
clutter_actor_get_size (priv->stage, &width, &height);
get_screen_offsets (priv->actor, &priv->x_offset, &priv->y_offset);
clutter_actor_box_get_origin (&box, &priv->x_offset, &priv->y_offset);
cogl_set_viewport (-priv->x_offset, -priv->y_offset, width, height);
/* Copy the stage's projection matrix across to the framebuffer */
@ -306,10 +274,10 @@ clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect)
paint_opacity);
cogl_set_source (priv->target);
/* paint the texture at the same position as the actor would be,
* in Stage coordinates, since we set up the modelview matrix to
* be exactly as the stage sets it up, plus the eventual offsets
* due to offscreen effects stacking
/* At this point we are in stage coordinates translated so if
* we draw our texture using a textured quad the size of the paint
* box then we will overlay where the actor would have drawn if it
* hadn't been redirected offscreen.
*/
cogl_rectangle_with_texture_coords (0, 0,
priv->target_width,

View File

@ -185,6 +185,79 @@ struct _ClutterMainContext
ClutterSettings *settings;
};
struct _ClutterPaintVolume
{
ClutterActor *actor;
/* cuboid for the volume:
*
* 45
*
* 0 7 1
* 6
* 3 2
*
*
* 0: top, left (origin) : always valid
* 1: top, right : always valid
* 2: bottom, right : updated lazily
* 3: bottom, left : always valid
*
* 4: top, left, back : always valid
* 5: top, right, back : updated lazily
* 6: bottom, right, back : updated lazily
* 7: bottom, left, back : updated lazily
*
* Elements 0, 1, 3 and 4 are filled in by the PaintVolume setters
*
* Note: the reason for this ordering is that we can simply ignore
* elements 4, 5, 6 and 7 most of the time for 2D actors when
* calculating the projected paint box.
*/
ClutterVertex vertices[8];
/* As an optimization for internally managed PaintVolumes we allow
* initializing ClutterPaintVolume variables allocated on the stack
* so we can avoid hammering the slice allocator. */
guint is_static:1;
/* A newly initialized PaintVolume is considered empty as it is
* degenerate on all three axis.
*
* We consider this carefully when we union an empty volume with
* another so that the union simply results in a copy of the other
* volume instead of also bounding the origin of the empty volume.
*
* For example this is a convenient property when calculating the
* volume of a container as the union of the volume of its children
* where the initial volume passed to the containers
* ->get_paint_volume method will be empty. */
guint is_empty:1;
/* TRUE when we've updated the values we calculate lazily */
guint is_complete:1;
/* TRUE if vertices 4-7 can be ignored. (Only valid if complete is
* TRUE) */
guint is_2d:1;
/* Set to TRUE initialy but cleared if the paint volume is
* transfomed by a matrix. */
guint is_axis_aligned:1;
/* Note: There is a precedence to the above bitfields that should be
* considered whenever we implement code that manipulates
* PaintVolumes...
*
* Firstly if ->is_empty == TRUE then the values for ->is_complete
* and ->is_2d are undefined, so you should typically check
* ->is_empty as the first priority.
*
* XXX: document other invariables...
*/
};
#define CLUTTER_CONTEXT() (_clutter_context_get_default ())
ClutterMainContext *_clutter_context_get_default (void);
gboolean _clutter_context_is_initialized (void);
@ -239,6 +312,7 @@ void _clutter_stage_manager_set_default_stage (ClutterStageManager *stage_manage
ClutterStage *stage);
/* stage */
void _clutter_stage_do_paint (ClutterStage *stage);
void _clutter_stage_set_window (ClutterStage *stage,
ClutterStageWindow *stage_window);
ClutterStageWindow *_clutter_stage_get_window (ClutterStage *stage);
@ -283,6 +357,9 @@ void _clutter_stage_increment_picks_per_frame_counter (ClutterStage *stage);
void _clutter_stage_reset_picks_per_frame_counter (ClutterStage *stage);
guint _clutter_stage_get_picks_per_frame_counter (ClutterStage *stage);
ClutterPaintVolume *_clutter_stage_paint_volume_stack_allocate (ClutterStage *stage);
void _clutter_stage_paint_volume_stack_free_all (ClutterStage *stage);
/* vfuncs implemented by backend */
GType _clutter_backend_impl_get_type (void);
@ -386,7 +463,7 @@ gint32 _clutter_backend_get_units_serial (ClutterBackend *backend);
gboolean _clutter_effect_pre_paint (ClutterEffect *effect);
void _clutter_effect_post_paint (ClutterEffect *effect);
void _clutter_effect_get_paint_volume (ClutterEffect *effect,
gboolean _clutter_effect_get_paint_volume (ClutterEffect *effect,
ClutterPaintVolume *volume);
void _clutter_constraint_update_allocation (ClutterConstraint *constraint,
@ -411,9 +488,18 @@ gpointer _clutter_event_get_platform_data (const ClutterEvent *event);
#endif
ClutterPaintVolume *_clutter_paint_volume_new (ClutterActor *actor);
void _clutter_paint_volume_get_box (ClutterPaintVolume *pv,
ClutterActorBox *box);
void _clutter_paint_volume_init_static (ClutterActor *actor,
ClutterPaintVolume *pv);
ClutterPaintVolume *_clutter_paint_volume_new (ClutterActor *actor);
void _clutter_paint_volume_copy_static (const ClutterPaintVolume *src_pv,
ClutterPaintVolume *dst_pv);
void _clutter_paint_volume_project (ClutterPaintVolume *pv,
const CoglMatrix *modelview,
const CoglMatrix *projection,
const int *viewport);
void _clutter_paint_volume_get_bounding_box (ClutterPaintVolume *pv,
ClutterActorBox *box);
G_END_DECLS

View File

@ -118,6 +118,8 @@ struct _ClutterStagePrivate
gint picks_per_frame;
GArray *paint_volume_stack;
guint redraw_pending : 1;
guint is_fullscreen : 1;
guint is_cursor_visible : 1;
@ -309,6 +311,16 @@ clutter_stage_allocate (ClutterActor *self,
clutter_actor_queue_redraw (self);
}
/* This provides a common point of entry for painting the scenegraph
* for picking or painting...
*/
void
_clutter_stage_do_paint (ClutterStage *stage)
{
_clutter_stage_paint_volume_stack_free_all (stage);
clutter_actor_paint (CLUTTER_ACTOR (stage));
}
static void
clutter_stage_paint (ClutterActor *self)
{
@ -1071,6 +1083,8 @@ clutter_stage_finalize (GObject *object)
g_free (stage->priv->title);
g_array_free (priv->paint_volume_stack, TRUE);
G_OBJECT_CLASS (clutter_stage_parent_class)->finalize (object);
}
@ -1468,6 +1482,9 @@ clutter_stage_init (ClutterStage *self)
_clutter_stage_set_pick_buffer_valid (self, FALSE);
_clutter_stage_reset_picks_per_frame_counter (self);
priv->paint_volume_stack =
g_array_new (FALSE, FALSE, sizeof (ClutterPaintVolume));
}
/**
@ -2986,3 +3003,33 @@ _clutter_stage_get_picks_per_frame_counter (ClutterStage *stage)
return stage->priv->picks_per_frame;
}
ClutterPaintVolume *
_clutter_stage_paint_volume_stack_allocate (ClutterStage *stage)
{
GArray *paint_volume_stack = stage->priv->paint_volume_stack;
g_array_set_size (paint_volume_stack,
paint_volume_stack->len+1);
return &g_array_index (paint_volume_stack,
ClutterPaintVolume,
paint_volume_stack->len - 1);
}
void
_clutter_stage_paint_volume_stack_free_all (ClutterStage *stage)
{
GArray *paint_volume_stack = stage->priv->paint_volume_stack;
int i;
for (i = 0; i < paint_volume_stack->len; i++)
{
ClutterPaintVolume *pv =
&g_array_index (paint_volume_stack, ClutterPaintVolume, i);
clutter_paint_volume_free (pv);
}
g_array_set_size (paint_volume_stack, 0);
}

View File

@ -416,8 +416,46 @@ set_viewport_with_buffer_under_fbo_source (ClutterActor *fbo_source,
ClutterActorBox box = { 0, };
float x_offset, y_offset;
clutter_actor_get_paint_box (fbo_source, &box);
clutter_actor_box_get_origin (&box, &x_offset, &y_offset);
if (clutter_actor_get_paint_box (fbo_source, &box))
clutter_actor_box_get_origin (&box, &x_offset, &y_offset);
else
{
/* As a fallback when the paint box can't be determined we use
* the transformed allocation to come up with an offset instead.
*
* FIXME: when we don't have a paint box we should instead be
* falling back to a stage sized fbo with an offset of (0,0)
*/
ClutterVertex verts[4];
float x_min = G_MAXFLOAT, y_min = G_MAXFLOAT;
int i;
/* Get the actors allocation transformed into screen coordinates.
*
* XXX: Note: this may not be a bounding box for the actor, since an
* actor with depth may escape the box due to its perspective
* projection. */
clutter_actor_get_abs_allocation_vertices (fbo_source, verts);
for (i = 0; i < G_N_ELEMENTS (verts); ++i)
{
if (verts[i].x < x_min)
x_min = verts[i].x;
if (verts[i].y < y_min)
y_min = verts[i].y;
}
/* XXX: It's not good enough to round by simply truncating the fraction here
* via a cast, as it results in offscreen rendering being offset by 1 pixel
* in many cases... */
#define ROUND(x) ((x) >= 0 ? (long)((x) + 0.5) : (long)((x) - 0.5))
x_offset = ROUND (x_min);
y_offset = ROUND (y_min);
#undef ROUND
}
/* translate the viewport so that the source actor lands on the
* sub-region backed by the offscreen framebuffer... */
@ -432,7 +470,7 @@ update_fbo (ClutterActor *self)
ClutterMainContext *context;
ClutterShader *shader = NULL;
ClutterActor *stage = NULL;
ClutterPerspective perspective;
CoglMatrix projection;
CoglColor transparent_col;
context = _clutter_context_get_default ();
@ -466,24 +504,21 @@ update_fbo (ClutterActor *self)
* under the actor.
*/
clutter_stage_get_perspective (CLUTTER_STAGE (stage), &perspective);
_clutter_stage_get_projection_matrix (CLUTTER_STAGE (stage), &projection);
/* Set the projection matrix modelview matrix as it is for the
* stage... */
cogl_set_projection_matrix (&projection);
clutter_actor_get_size (stage, &stage_width, &stage_height);
/* Set the projection matrix modelview matrix and viewport size as
* they are for the stage... */
_cogl_setup_viewport (stage_width, stage_height,
perspective.fovy,
perspective.aspect,
perspective.z_near,
perspective.z_far);
/* Negatively offset the viewport so that the offscreen framebuffer is
* position underneath the fbo_source actor... */
/* Set a negatively offset the viewport so that the offscreen
* framebuffer is position underneath the fbo_source actor... */
set_viewport_with_buffer_under_fbo_source (priv->fbo_source,
stage_width,
stage_height);
/* Reapply the source's parent transformations */
/* Apply the source's parent transformations to the modelview */
if ((source_parent = clutter_actor_get_parent (priv->fbo_source)))
{
CoglMatrix modelview;
@ -2315,9 +2350,26 @@ on_fbo_source_size_change (GObject *object,
ClutterTexturePrivate *priv = texture->priv;
gfloat w, h;
ClutterActorBox box;
gboolean status;
clutter_actor_get_paint_box (priv->fbo_source, &box);
clutter_actor_box_get_size (&box, &w, &h);
status = clutter_actor_get_paint_box (priv->fbo_source, &box);
if (status)
clutter_actor_box_get_size (&box, &w, &h);
/* In the end we will size the framebuffer according to the paint
* box, but for code that does:
* tex = clutter_texture_new_from_actor (src);
* clutter_actor_get_size (tex, &width, &height);
* it seems more helpfull to return the src actor size if it has a
* degenerate paint box. The most likely reason it will have a
* degenerate paint box is simply that the src currently has no
* parent. */
if (status == FALSE || w == 0 || h == 0)
clutter_actor_get_size (priv->fbo_source, &w, &h);
/* We can't create a texture with a width or height of 0... */
w = MAX (1, w);
h = MAX (1, h);
if (w != priv->image_width || h != priv->image_height)
{
@ -2458,6 +2510,7 @@ clutter_texture_new_from_actor (ClutterActor *actor)
ClutterTexturePrivate *priv;
gfloat w, h;
ClutterActorBox box;
gboolean status;
g_return_val_if_fail (CLUTTER_IS_ACTOR (actor), NULL);
@ -2472,13 +2525,25 @@ clutter_texture_new_from_actor (ClutterActor *actor)
return NULL;
}
clutter_actor_get_paint_box (actor, &box);
clutter_actor_box_get_size (&box, &w, &h);
status = clutter_actor_get_paint_box (actor, &box);
if (status)
clutter_actor_box_get_size (&box, &w, &h);
/* In the end we will size the framebuffer according to the paint
* box, but for code that does:
* tex = clutter_texture_new_from_actor (src);
* clutter_actor_get_size (tex, &width, &height);
* it seems more helpfull to return the src actor size if it has a
* degenerate paint box. The most likely reason it will have a
* degenerate paint box is simply that the src currently has no
* parent. */
if (status == FALSE || w == 0 || h == 0)
clutter_actor_get_size (actor, &w, &h);
/* We can't create a 0x0 fbo so always bump the size up to at least
* 1 */
w = MAX(1,w);
h = MAX(1,h);
w = MAX (1, w);
h = MAX (1, h);
/* Hopefully now were good.. */
texture = g_object_new (CLUTTER_TYPE_TEXTURE,

View File

@ -91,6 +91,22 @@ typedef struct _ClutterActorBox ClutterActorBox;
typedef struct _ClutterGeometry ClutterGeometry;
typedef struct _ClutterKnot ClutterKnot;
typedef struct _ClutterVertex ClutterVertex;
/**
* ClutterPaintVolume:
*
* <structname>ClutterPaintVolume</structname> is an opaque structure
* whose members cannot be directly accessed.
*
* A <structname>ClutterPaintVolume</structname> represents an
* a bounding volume whos internal representation isn't defined but
* can be set and queried in terms of an axis aligned bounding box.
*
* Other internal representation and methods for describing the
* bounding volume may be added in the future.
*
* Since: 1.4
*/
typedef struct _ClutterPaintVolume ClutterPaintVolume;
/**
@ -456,6 +472,8 @@ gfloat clutter_paint_volume_get_height (const ClutterPaintVolume *p
void clutter_paint_volume_set_depth (ClutterPaintVolume *pv,
gfloat depth);
gfloat clutter_paint_volume_get_depth (const ClutterPaintVolume *pv);
void clutter_paint_volume_union (ClutterPaintVolume *pv,
const ClutterPaintVolume *another_pv);
G_END_DECLS

View File

@ -359,7 +359,7 @@ _clutter_stage_egl_redraw (ClutterStageEGL *stage_egl,
egl_surface = backend_egl->egl_surface;
#endif
clutter_actor_paint (wrapper);
_clutter_stage_do_paint (CLUTTER_STAGE (wrapper));
cogl_flush ();
eglSwapBuffers (backend_egl->edpy, egl_surface);

View File

@ -71,7 +71,7 @@ clutter_backend_egl_redraw (ClutterBackend *backend,
stage_egl = CLUTTER_STAGE_EGL (impl);
eglWaitNative (EGL_CORE_NATIVE_ENGINE);
clutter_actor_paint (CLUTTER_ACTOR (stage));
_clutter_stage_do_paint (stage);
cogl_flush ();
eglWaitGL();
eglSwapBuffers (backend_egl->edpy, stage_egl->egl_surface);

View File

@ -532,11 +532,11 @@ _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx,
stage_glx->bounding_redraw_clip.y,
stage_glx->bounding_redraw_clip.width,
stage_glx->bounding_redraw_clip.height);
clutter_actor_paint (CLUTTER_ACTOR (stage));
_clutter_stage_do_paint (stage);
cogl_clip_pop ();
}
else
clutter_actor_paint (CLUTTER_ACTOR (stage));
_clutter_stage_do_paint (stage);
cogl_flush ();
CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer);

View File

@ -147,7 +147,7 @@ clutter_stage_osx_get_wrapper (ClutterStageWindow *stage_window);
- (void) drawRect: (NSRect) bounds
{
clutter_actor_paint (CLUTTER_ACTOR (self->stage_osx->wrapper));
_clutter_stage_do_paint (CLUTTER_STAGE (self->stage_osx->wrapper));
cogl_flush ();
[[self openGLContext] flushBuffer];
}

View File

@ -494,7 +494,7 @@ clutter_backend_win32_redraw (ClutterBackend *backend,
stage_win32 = CLUTTER_STAGE_WIN32 (impl);
/* this will cause the stage implementation to be painted */
clutter_actor_paint (CLUTTER_ACTOR (stage));
_clutter_stage_do_paint (stage);
cogl_flush ();
if (stage_win32->client_dc)