stage: Add the NO_CLEAR_ON_PAINT hint

Some apps or some use cases don't need to clear the stage on immediate
rendering GPUs. A media player playing a fullscreen video or a
tile-based game, for instance.

These apps are redrawing the whole screen, so we can avoid clearing the
color buffer when preparing to paint the stage, since there is no
blending with the stage color being performed.

We can add an private set of hints to ClutterStage, and expose accessors
for each potential hint; the first hint is the 'no-clear' one.

http://bugzilla.clutter-project.org/show_bug.cgi?id=2058
This commit is contained in:
Emmanuele Bassi 2010-04-16 15:34:36 +01:00
parent 984e04cae8
commit 0cbfabcda4
3 changed files with 135 additions and 5 deletions

View File

@ -53,8 +53,9 @@
#include "config.h"
#endif
#include "clutter-backend.h"
#include "clutter-stage.h"
#include "clutter-backend.h"
#include "clutter-main.h"
#include "clutter-color.h"
#include "clutter-util.h"
@ -78,6 +79,25 @@ G_DEFINE_TYPE (ClutterStage, clutter_stage, CLUTTER_TYPE_GROUP);
#define CLUTTER_STAGE_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_STAGE, ClutterStagePrivate))
/* <private>
* ClutterStageHint:
* @CLUTTER_STAGE_NONE: No hint set
* @CLUTTER_STAGE_NO_CLEAR_ON_PAINT: When this hint is set, the stage
* should not clear the viewport; this flag is useful when painting
* fully opaque actors covering the whole visible area of the stage,
* i.e. when no blending with the stage color happens over the whole
* stage viewport
*
* A series of hints that enable or disable behaviours on the stage
*/
typedef enum { /*< prefix=CLUTTER_STAGE >*/
CLUTTER_STAGE_HINT_NONE = 0,
CLUTTER_STAGE_NO_CLEAR_ON_PAINT = 1 << 0
} ClutterStageHint;
#define STAGE_NO_CLEAR_ON_PAINT(s) ((((ClutterStage *) (s))->priv->stage_hints & CLUTTER_STAGE_NO_CLEAR_ON_PAINT) != 0)
struct _ClutterStagePrivate
{
/* the stage implementation */
@ -92,6 +112,8 @@ struct _ClutterStagePrivate
GQueue *event_queue;
ClutterStageHint stage_hints;
guint redraw_pending : 1;
guint is_fullscreen : 1;
guint is_cursor_visible : 1;
@ -116,7 +138,8 @@ enum
PROP_USE_FOG,
PROP_FOG,
PROP_USE_ALPHA,
PROP_KEY_FOCUS
PROP_KEY_FOCUS,
PROP_NO_CLEAR_HINT
};
enum
@ -274,6 +297,7 @@ static void
clutter_stage_paint (ClutterActor *self)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
CoglBufferBit clear_flags;
CoglColor stage_color;
guint8 real_alpha;
CLUTTER_STATIC_TIMER (stage_clear_timer,
@ -300,10 +324,14 @@ clutter_stage_paint (ClutterActor *self)
: 255);
cogl_color_premultiply (&stage_color);
clear_flags = COGL_BUFFER_BIT_DEPTH;
if (!STAGE_NO_CLEAR_ON_PAINT (self))
clear_flags |= COGL_BUFFER_BIT_COLOR;
CLUTTER_TIMER_START (_clutter_uprof_context, stage_clear_timer);
cogl_clear (&stage_color,
COGL_BUFFER_BIT_COLOR |
COGL_BUFFER_BIT_DEPTH);
cogl_clear (&stage_color, clear_flags);
CLUTTER_TIMER_STOP (_clutter_uprof_context, stage_clear_timer);
if (priv->use_fog)
@ -817,6 +845,10 @@ clutter_stage_set_property (GObject *object,
clutter_stage_set_key_focus (stage, g_value_get_object (value));
break;
case PROP_NO_CLEAR_HINT:
clutter_stage_set_no_clear_hint (stage, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -877,6 +909,15 @@ clutter_stage_get_property (GObject *gobject,
g_value_set_object (value, priv->key_focused_actor);
break;
case PROP_NO_CLEAR_HINT:
{
gboolean hint =
(priv->stage_hints & CLUTTER_STAGE_NO_CLEAR_ON_PAINT) != 0;
g_value_set_boolean (value, hint);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@ -1138,6 +1179,23 @@ clutter_stage_class_init (ClutterStageClass *klass)
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_KEY_FOCUS, pspec);
/**
* ClutterStage:no-clear-hint:
*
* Whether or not the #ClutterStage should clear its contents
* before each paint cycle.
*
* See clutter_stage_set_no_clear_hint() for further information.
*
* Since: 1.4
*/
pspec = g_param_spec_boolean ("no-clear-hint",
"No Clear Hint",
"Whether the stage should clear its contents",
FALSE,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_NO_CLEAR_HINT, pspec);
/**
* ClutterStage::fullscreen
* @stage: the stage which was fullscreened
@ -2531,3 +2589,69 @@ _clutter_stage_get_pending_swaps (ClutterStage *stage)
return _clutter_stage_window_get_pending_swaps (stage_window);
}
/**
* clutter_stage_set_no_clear_hint:
* @stage: a #ClutterStage
* @no_clear: %TRUE if the @stage should not clear itself on every
* repaint cycle
*
* Sets whether the @stage should clear itself at the beginning
* of each paint cycle or not.
*
* Clearing the #ClutterStage can be a costly operation, especially
* if the stage is always covered - for instance, in a full-screen
* video player or in a game with a background texture.
*
* <note><para>This setting is a hint; Clutter might discard this
* hint depending on its internal state.</para></note>
*
* <warning><para>If parts of the stage are visible and you disable
* clearing you might end up with visual artifacts while painting the
* contents of the stage.</para></warning>
*
* Since: 1.4
*/
void
clutter_stage_set_no_clear_hint (ClutterStage *stage,
gboolean no_clear)
{
ClutterStagePrivate *priv;
ClutterStageHint new_hints;
g_return_if_fail (CLUTTER_IS_STAGE (stage));
priv = stage->priv;
new_hints = priv->stage_hints;
if (no_clear)
new_hints |= CLUTTER_STAGE_NO_CLEAR_ON_PAINT;
else
new_hints &= ~CLUTTER_STAGE_NO_CLEAR_ON_PAINT;
if (priv->stage_hints == new_hints)
return;
priv->stage_hints = new_hints;
g_object_notify (G_OBJECT (stage), "no-clear-hint");
}
/**
* clutter_stage_get_no_clear_hint:
* @stage: a #ClutterStage
*
* Retrieves the hint set with clutter_stage_set_no_clear_hint()
*
* Return value: %TRUE if the stage should not clear itself on every paint
* cycle, and %FALSE otherwise
*
* Since: 1.4
*/
gboolean
clutter_stage_get_no_clear_hint (ClutterStage *stage)
{
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
return (stage->priv->stage_hints & CLUTTER_STAGE_NO_CLEAR_ON_PAINT) != 0;
}

View File

@ -254,6 +254,10 @@ void clutter_stage_get_minimum_size (ClutterStage *stage,
guint *width,
guint *height);
void clutter_stage_set_no_clear_hint (ClutterStage *stage,
gboolean no_clear);
gboolean clutter_stage_get_no_clear_hint (ClutterStage *stage);
/* Commodity macro, for mallum only */
#define clutter_stage_add(stage,actor) G_STMT_START { \
if (CLUTTER_IS_STAGE ((stage)) && CLUTTER_IS_ACTOR ((actor))) \

View File

@ -576,6 +576,8 @@ clutter_stage_set_use_alpha
clutter_stage_get_use_alpha
clutter_stage_set_minimum_size
clutter_stage_get_minimum_size
clutter_stage_set_no_clear_hint
clutter_stage_get_no_clear_hint
<SUBSECTION>
ClutterPerspective