Merge branch 'size-cache' into ebassi-next

* size-cache:
  tests: Clean up the BoxLayout interactive test
  actor: Add debugging notes for size cache
  Add a cache of size requests
This commit is contained in:
Emmanuele Bassi 2009-12-09 23:32:18 +00:00
commit dc47550bc8
2 changed files with 136 additions and 31 deletions

View File

@ -234,6 +234,18 @@ struct _AnchorCoord
} v; } v;
}; };
/* 3 entries should be a good compromise, few layout managers
* will ask for 3 different preferred size in each allocation cycle */
#define N_CACHED_SIZE_REQUESTS 3
typedef struct _SizeRequest SizeRequest;
struct _SizeRequest
{
guint age;
gfloat for_size;
gfloat min_size;
gfloat natural_size;
};
/* Internal enum used to control mapped state update. This is a hint /* Internal enum used to control mapped state update. This is a hint
* which indicates when to do something other than just enforce * which indicates when to do something other than just enforce
* invariants. * invariants.
@ -262,14 +274,17 @@ struct _ClutterActorPrivate
/* request mode */ /* request mode */
ClutterRequestMode request_mode; ClutterRequestMode request_mode;
/* our cached request width is for this height */ /* our cached size requests for different width / height */
gfloat request_width_for_height; SizeRequest width_requests[N_CACHED_SIZE_REQUESTS];
gfloat request_min_width; SizeRequest height_requests[N_CACHED_SIZE_REQUESTS];
gfloat request_natural_width;
/* our cached request height is for this width */ /* An age of 0 means the entry is not set */
gfloat request_height_for_width; guint cached_height_age;
guint cached_width_age;
gfloat request_min_width;
gfloat request_min_height; gfloat request_min_height;
gfloat request_natural_width;
gfloat request_natural_height; gfloat request_natural_height;
ClutterActorBox allocation; ClutterActorBox allocation;
@ -1663,6 +1678,12 @@ clutter_actor_real_queue_relayout (ClutterActor *self)
priv->needs_height_request = TRUE; priv->needs_height_request = TRUE;
priv->needs_allocation = TRUE; priv->needs_allocation = TRUE;
/* reset the cached size requests */
memset (priv->width_requests, 0,
N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
memset (priv->height_requests, 0,
N_CACHED_SIZE_REQUESTS * sizeof (SizeRequest));
/* always repaint also (no-op if not mapped) */ /* always repaint also (no-op if not mapped) */
clutter_actor_queue_redraw (self); clutter_actor_queue_redraw (self);
@ -4392,6 +4413,9 @@ clutter_actor_init (ClutterActor *self)
priv->needs_height_request = TRUE; priv->needs_height_request = TRUE;
priv->needs_allocation = TRUE; priv->needs_allocation = TRUE;
priv->cached_width_age = 1;
priv->cached_height_age = 1;
priv->opacity_parent = NULL; priv->opacity_parent = NULL;
priv->enable_model_view_transform = TRUE; priv->enable_model_view_transform = TRUE;
@ -4586,6 +4610,43 @@ clutter_actor_get_preferred_size (ClutterActor *self,
*natural_height_p = natural_height; *natural_height_p = natural_height;
} }
/* looks for a cached size request for this for_size. If not
* found, returns the oldest entry so it can be overwritten */
static gboolean
_clutter_actor_get_cached_size_request (gfloat for_size,
SizeRequest *cached_size_requests,
SizeRequest **result)
{
gboolean found_free_cache;
guint i;
found_free_cache = FALSE;
*result = &cached_size_requests[0];
for (i = 0; i < N_CACHED_SIZE_REQUESTS; i++)
{
SizeRequest *sr;
sr = &cached_size_requests[i];
if (sr->age > 0 &&
sr->for_size == for_size)
{
CLUTTER_NOTE (LAYOUT, "Size cache hit for size: %.2f", for_size);
*result = sr;
return TRUE;
}
else if (sr->age < (*result)->age)
{
*result = sr;
}
}
CLUTTER_NOTE (LAYOUT, "Size cache miss for size: %.2f", for_size);
return FALSE;
}
/** /**
* clutter_actor_get_preferred_width: * clutter_actor_get_preferred_width:
* @self: A #ClutterActor * @self: A #ClutterActor
@ -4616,14 +4677,23 @@ clutter_actor_get_preferred_width (ClutterActor *self,
{ {
ClutterActorClass *klass; ClutterActorClass *klass;
ClutterActorPrivate *priv; ClutterActorPrivate *priv;
gboolean found_in_cache;
SizeRequest *cached_size_request;
g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTOR (self));
klass = CLUTTER_ACTOR_GET_CLASS (self); klass = CLUTTER_ACTOR_GET_CLASS (self);
priv = self->priv; priv = self->priv;
if (priv->needs_width_request || found_in_cache = FALSE;
priv->request_width_for_height != for_height) cached_size_request = &priv->width_requests[0];
if (!priv->needs_width_request)
found_in_cache = _clutter_actor_get_cached_size_request (for_height,
priv->width_requests,
&cached_size_request);
if (!found_in_cache)
{ {
gfloat min_width, natural_width; gfloat min_width, natural_width;
@ -4641,16 +4711,21 @@ clutter_actor_get_preferred_width (ClutterActor *self,
if (natural_width < min_width) if (natural_width < min_width)
natural_width = min_width; natural_width = min_width;
if (!priv->min_width_set) cached_size_request->min_size = min_width;
priv->request_min_width = min_width; cached_size_request->natural_size = natural_width;
cached_size_request->for_size = for_height;
cached_size_request->age = priv->cached_width_age;
if (!priv->natural_width_set) priv->cached_width_age ++;
priv->request_natural_width = natural_width;
priv->request_width_for_height = for_height;
priv->needs_width_request = FALSE; priv->needs_width_request = FALSE;
} }
if (!priv->min_width_set)
priv->request_min_width = cached_size_request->min_size;
if (!priv->natural_width_set)
priv->request_natural_width = cached_size_request->natural_size;
if (min_width_p) if (min_width_p)
*min_width_p = priv->request_min_width; *min_width_p = priv->request_min_width;
@ -4687,20 +4762,29 @@ clutter_actor_get_preferred_height (ClutterActor *self,
{ {
ClutterActorClass *klass; ClutterActorClass *klass;
ClutterActorPrivate *priv; ClutterActorPrivate *priv;
gboolean found_in_cache;
SizeRequest *cached_size_request;
g_return_if_fail (CLUTTER_IS_ACTOR (self)); g_return_if_fail (CLUTTER_IS_ACTOR (self));
klass = CLUTTER_ACTOR_GET_CLASS (self); klass = CLUTTER_ACTOR_GET_CLASS (self);
priv = self->priv; priv = self->priv;
if (priv->needs_height_request || found_in_cache = FALSE;
priv->request_height_for_width != for_width) cached_size_request = &priv->height_requests[0];
if (!priv->needs_height_request)
found_in_cache = _clutter_actor_get_cached_size_request (for_width,
priv->height_requests,
&cached_size_request);
if (!found_in_cache)
{ {
gfloat min_height, natural_height; gfloat min_height, natural_height;
min_height = natural_height = 0; min_height = natural_height = 0;
CLUTTER_NOTE (LAYOUT, "Width request for %.2f px", for_width); CLUTTER_NOTE (LAYOUT, "Height request for %.2f px", for_width);
klass->get_preferred_height (self, for_width, klass->get_preferred_height (self, for_width,
&min_height, &min_height,
@ -4713,15 +4797,31 @@ clutter_actor_get_preferred_height (ClutterActor *self,
natural_height = min_height; natural_height = min_height;
if (!priv->min_height_set) if (!priv->min_height_set)
{
priv->request_min_height = min_height; priv->request_min_height = min_height;
}
if (!priv->natural_height_set) if (!priv->natural_height_set)
{
priv->request_natural_height = natural_height; priv->request_natural_height = natural_height;
}
cached_size_request->min_size = min_height;
cached_size_request->natural_size = natural_height;
cached_size_request->for_size = for_width;
cached_size_request->age = priv->cached_height_age;
priv->cached_height_age ++;
priv->request_height_for_width = for_width;
priv->needs_height_request = FALSE; priv->needs_height_request = FALSE;
} }
if (!priv->min_height_set)
priv->request_min_height = cached_size_request->min_size;
if (!priv->natural_height_set)
priv->request_natural_height = cached_size_request->natural_size;
if (min_height_p) if (min_height_p)
*min_height_p = priv->request_min_height; *min_height_p = priv->request_min_height;

View File

@ -32,6 +32,8 @@
"Press q\t\342\236\236\tQuit" "Press q\t\342\236\236\tQuit"
static ClutterActor *hover_actor = NULL; static ClutterActor *hover_actor = NULL;
static ClutterActor *box = NULL;
static ClutterActor *label = NULL;
static guint last_index = 0; static guint last_index = 0;
static void static void
@ -88,7 +90,7 @@ leave_event (ClutterActor *actor,
static gboolean static gboolean
button_release_event (ClutterActor *actor, button_release_event (ClutterActor *actor,
ClutterEvent *event, ClutterEvent *event,
ClutterBoxLayout *box) ClutterBoxLayout *layout)
{ {
gboolean xfill, yfill; gboolean xfill, yfill;
ClutterBoxAlignment xalign, yalign; ClutterBoxAlignment xalign, yalign;
@ -98,14 +100,14 @@ button_release_event (ClutterActor *actor,
if (button == 1) if (button == 1)
{ {
clutter_box_layout_get_fill (box, actor, &xfill, &yfill); clutter_box_layout_get_fill (layout, actor, &xfill, &yfill);
clutter_box_layout_set_fill (box, actor, clutter_box_layout_set_fill (layout, actor,
xfill ? FALSE : TRUE, xfill ? FALSE : TRUE,
yfill ? FALSE : TRUE); yfill ? FALSE : TRUE);
} }
else else
{ {
clutter_box_layout_get_alignment (box, actor, &xalign, &yalign); clutter_box_layout_get_alignment (layout, actor, &xalign, &yalign);
if (xalign < 2) if (xalign < 2)
xalign += 1; xalign += 1;
@ -117,14 +119,14 @@ button_release_event (ClutterActor *actor,
else else
yalign = 0; yalign = 0;
clutter_box_layout_set_alignment (box, actor, xalign, yalign); clutter_box_layout_set_alignment (layout, actor, xalign, yalign);
} }
return TRUE; return TRUE;
} }
static void static void
add_actor (ClutterBoxLayout *box, add_actor (ClutterBoxLayout *layout,
guint index_) guint index_)
{ {
ClutterActor *rect; ClutterActor *rect;
@ -138,7 +140,7 @@ add_actor (ClutterBoxLayout *box,
rect = clutter_rectangle_new_with_color (&color); rect = clutter_rectangle_new_with_color (&color);
clutter_actor_set_size (rect, 32, 64); clutter_actor_set_size (rect, 32, 64);
clutter_box_layout_pack (box, rect, expand, clutter_box_layout_pack (layout, rect, expand,
FALSE, /* x-fill */ FALSE, /* x-fill */
FALSE, /* y-fill */ FALSE, /* y-fill */
CLUTTER_BOX_ALIGNMENT_CENTER, CLUTTER_BOX_ALIGNMENT_CENTER,
@ -152,7 +154,7 @@ add_actor (ClutterBoxLayout *box,
g_signal_connect (rect, "leave-event", G_CALLBACK (leave_event), NULL); g_signal_connect (rect, "leave-event", G_CALLBACK (leave_event), NULL);
g_signal_connect (rect, "button-release-event", g_signal_connect (rect, "button-release-event",
G_CALLBACK (button_release_event), G_CALLBACK (button_release_event),
box); layout);
expand = !expand; expand = !expand;
} }
@ -207,18 +209,21 @@ static void
stage_size_changed_cb (ClutterActor *stage, stage_size_changed_cb (ClutterActor *stage,
const ClutterActorBox *allocation, const ClutterActorBox *allocation,
ClutterAllocationFlags flags, ClutterAllocationFlags flags,
ClutterActor *box) gpointer dummy G_GNUC_UNUSED)
{ {
gfloat width, height; gfloat width, height;
clutter_actor_box_get_size (allocation, &width, &height); clutter_actor_box_get_size (allocation, &width, &height);
clutter_actor_set_size (box, width - 100, height - 100); clutter_actor_set_size (box, width - 100, height - 100);
clutter_actor_set_y (label,
height - clutter_actor_get_height (label) - 8);
} }
G_MODULE_EXPORT int G_MODULE_EXPORT int
test_box_layout_main (int argc, char *argv[]) test_box_layout_main (int argc, char *argv[])
{ {
ClutterActor *stage, *box, *label; ClutterActor *stage;
ClutterLayoutManager *layout; ClutterLayoutManager *layout;
gint i; gint i;
@ -242,7 +247,7 @@ test_box_layout_main (int argc, char *argv[])
layout); layout);
g_signal_connect (stage, "allocation-changed", g_signal_connect (stage, "allocation-changed",
G_CALLBACK (stage_size_changed_cb), G_CALLBACK (stage_size_changed_cb),
box); NULL);
label = clutter_text_new_with_text ("Sans 12px", INSTRUCTIONS); label = clutter_text_new_with_text ("Sans 12px", INSTRUCTIONS);
clutter_container_add_actor (CLUTTER_CONTAINER (stage), label); clutter_container_add_actor (CLUTTER_CONTAINER (stage), label);