cogl: Move the clip stack dirtiness to the context rather than the FB
Previously we tracked whether the clip stack needs flushing as part of the CoglClipState which is part of the CoglFramebuffer state. This is a bit odd because most of the clipping state (such as the clip planes and the scissor) are part of the GL context's state rather than the framebuffer. We were marking the clip state on the framebuffer dirty every time we change the framebuffer anyway so it seems to make more sense to have the dirtiness be part of the global context. Instead of a just a single boolean to record whether the state needs flushing, the CoglContext now holds a reference to the clip stack that was flushed. That way we can flush arbitrary stack states and if it happens to be the same as the state already flushed then Cogl will do nothing. This will be useful if we log the clip stack in the journal because then we will need to flush unrelated clip stack states for each batch.
This commit is contained in:
parent
57574f3995
commit
60de7939ee
@ -582,8 +582,7 @@ _cogl_clip_stack_pop (CoglClipStack *stack)
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_clip_stack_flush (CoglClipStack *stack,
|
||||
gboolean *stencil_used_p)
|
||||
_cogl_clip_stack_flush (CoglClipStack *stack)
|
||||
{
|
||||
int has_clip_planes;
|
||||
gboolean using_clip_planes = FALSE;
|
||||
@ -592,11 +591,32 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
|
||||
int scissor_y0 = 0;
|
||||
int scissor_x1 = G_MAXINT;
|
||||
int scissor_y1 = G_MAXINT;
|
||||
CoglMatrixStack *modelview_stack =
|
||||
_cogl_framebuffer_get_modelview_stack (_cogl_get_framebuffer ());
|
||||
CoglMatrixStack *modelview_stack;
|
||||
CoglClipStack *entry;
|
||||
int scissor_y_start;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
/* If we have already flushed this state then we don't need to do
|
||||
anything */
|
||||
if (ctx->current_clip_stack_valid)
|
||||
{
|
||||
if (ctx->current_clip_stack == stack)
|
||||
return;
|
||||
|
||||
_cogl_clip_stack_unref (ctx->current_clip_stack);
|
||||
}
|
||||
|
||||
ctx->current_clip_stack_valid = TRUE;
|
||||
ctx->current_clip_stack = _cogl_clip_stack_ref (stack);
|
||||
|
||||
/* The current primitive journal does not support tracking changes to the
|
||||
* clip stack... */
|
||||
_cogl_journal_flush ();
|
||||
|
||||
modelview_stack =
|
||||
_cogl_framebuffer_get_modelview_stack (_cogl_get_framebuffer ());
|
||||
|
||||
has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
|
||||
|
||||
if (has_clip_planes)
|
||||
@ -606,7 +626,7 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
|
||||
/* If the stack is empty then there's nothing else to do */
|
||||
if (stack == NULL)
|
||||
{
|
||||
*stencil_used_p = FALSE;
|
||||
ctx->current_clip_stack_uses_stencil = FALSE;
|
||||
GE (glDisable (GL_SCISSOR_TEST));
|
||||
return;
|
||||
}
|
||||
@ -718,5 +738,17 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
|
||||
if (using_clip_planes)
|
||||
enable_clip_planes ();
|
||||
|
||||
*stencil_used_p = using_stencil_buffer;
|
||||
ctx->current_clip_stack_uses_stencil = using_stencil_buffer;
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_clip_stack_dirty (void)
|
||||
{
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
if (ctx->current_clip_stack_valid)
|
||||
{
|
||||
ctx->current_clip_stack_valid = FALSE;
|
||||
_cogl_clip_stack_unref (ctx->current_clip_stack);
|
||||
}
|
||||
}
|
||||
|
@ -57,8 +57,7 @@ CoglClipStack *
|
||||
_cogl_clip_stack_pop (CoglClipStack *stack);
|
||||
|
||||
void
|
||||
_cogl_clip_stack_flush (CoglClipStack *stack,
|
||||
gboolean *stencil_used_p);
|
||||
_cogl_clip_stack_flush (CoglClipStack *stack);
|
||||
|
||||
CoglClipStack *
|
||||
_cogl_clip_stack_ref (CoglClipStack *stack);
|
||||
@ -66,4 +65,7 @@ _cogl_clip_stack_ref (CoglClipStack *stack);
|
||||
void
|
||||
_cogl_clip_stack_unref (CoglClipStack *stack);
|
||||
|
||||
void
|
||||
_cogl_clip_stack_dirty (void);
|
||||
|
||||
#endif /* __COGL_CLIP_STACK_H */
|
||||
|
@ -62,8 +62,6 @@ cogl_clip_push_window_rectangle (int x_offset,
|
||||
_cogl_clip_stack_push_window_rectangle (clip_state->stacks->data,
|
||||
x_offset, y_offset,
|
||||
width, height);
|
||||
|
||||
clip_state->stack_dirty = TRUE;
|
||||
}
|
||||
|
||||
/* XXX: This is deprecated API */
|
||||
@ -156,8 +154,6 @@ cogl_clip_push_rectangle (float x_1,
|
||||
_cogl_clip_stack_push_rectangle (clip_state->stacks->data,
|
||||
x_1, y_1, x_2, y_2,
|
||||
&modelview_matrix);
|
||||
|
||||
clip_state->stack_dirty = TRUE;
|
||||
}
|
||||
|
||||
/* XXX: Deprecated API */
|
||||
@ -194,8 +190,6 @@ cogl_clip_push_from_path_preserve (void)
|
||||
clip_state->stacks->data =
|
||||
_cogl_clip_stack_push_from_path (clip_state->stacks->data, cogl_get_path (),
|
||||
&modelview_matrix);
|
||||
|
||||
clip_state->stack_dirty = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
@ -214,8 +208,6 @@ _cogl_clip_pop_real (CoglClipState *clip_state)
|
||||
_cogl_journal_flush ();
|
||||
|
||||
clip_state->stacks->data = _cogl_clip_stack_pop (clip_state->stacks->data);
|
||||
|
||||
clip_state->stack_dirty = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
@ -235,25 +227,9 @@ cogl_clip_pop (void)
|
||||
void
|
||||
_cogl_clip_state_flush (CoglClipState *clip_state)
|
||||
{
|
||||
CoglClipStack *stack;
|
||||
|
||||
if (!clip_state->stack_dirty)
|
||||
return;
|
||||
|
||||
/* The current primitive journal does not support tracking changes to the
|
||||
* clip stack... */
|
||||
_cogl_journal_flush ();
|
||||
|
||||
/* XXX: the handling of clipping is quite complex. It may involve use of
|
||||
* the Cogl Journal or other Cogl APIs which may end up recursively
|
||||
* wanting to ensure the clip state is flushed. We need to ensure we
|
||||
* don't recurse infinitely...
|
||||
*/
|
||||
clip_state->stack_dirty = FALSE;
|
||||
|
||||
stack = clip_state->stacks->data;
|
||||
|
||||
_cogl_clip_stack_flush (stack, &clip_state->stencil_used);
|
||||
/* Flush the topmost stack. The clip stack code will bail out early
|
||||
if this is already flushed */
|
||||
_cogl_clip_stack_flush (clip_state->stacks->data);
|
||||
}
|
||||
|
||||
/* XXX: This should never have been made public API! */
|
||||
@ -274,7 +250,6 @@ _cogl_clip_stack_save_real (CoglClipState *clip_state)
|
||||
_cogl_journal_flush ();
|
||||
|
||||
clip_state->stacks = g_slist_prepend (clip_state->stacks, NULL);
|
||||
clip_state->stack_dirty = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
@ -309,8 +284,6 @@ _cogl_clip_stack_restore_real (CoglClipState *clip_state)
|
||||
/* Revert to an old stack */
|
||||
clip_state->stacks = g_slist_delete_link (clip_state->stacks,
|
||||
clip_state->stacks);
|
||||
|
||||
clip_state->stack_dirty = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
@ -333,7 +306,6 @@ _cogl_clip_state_init (CoglClipState *clip_state)
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
clip_state->stacks = NULL;
|
||||
clip_state->stack_dirty = TRUE;
|
||||
|
||||
/* Add an intial stack */
|
||||
_cogl_clip_stack_save_real (clip_state);
|
||||
@ -347,12 +319,6 @@ _cogl_clip_state_destroy (CoglClipState *clip_state)
|
||||
_cogl_clip_stack_restore_real (clip_state);
|
||||
}
|
||||
|
||||
void
|
||||
_cogl_clip_state_dirty (CoglClipState *clip_state)
|
||||
{
|
||||
clip_state->stack_dirty = TRUE;
|
||||
}
|
||||
|
||||
CoglClipStack *
|
||||
_cogl_get_clip_stack (void)
|
||||
{
|
||||
|
@ -30,9 +30,6 @@ struct _CoglClipState
|
||||
{
|
||||
/* Stack of CoglClipStacks */
|
||||
GSList *stacks;
|
||||
|
||||
gboolean stack_dirty;
|
||||
gboolean stencil_used;
|
||||
};
|
||||
|
||||
void
|
||||
@ -41,9 +38,6 @@ _cogl_clip_state_init (CoglClipState *state);
|
||||
void
|
||||
_cogl_clip_state_destroy (CoglClipState *state);
|
||||
|
||||
void
|
||||
_cogl_clip_state_dirty (CoglClipState *state);
|
||||
|
||||
void
|
||||
_cogl_clip_state_flush (CoglClipState *clip_state);
|
||||
|
||||
|
@ -209,6 +209,8 @@ cogl_create_context (void)
|
||||
|
||||
_context->texture_download_pipeline = COGL_INVALID_HANDLE;
|
||||
|
||||
_context->current_clip_stack_valid = FALSE;
|
||||
|
||||
/* The default for GL_ALPHA_TEST is to always pass which is equivalent to
|
||||
* the test being disabled therefore we assume that for all drivers there
|
||||
* will be no performance impact if we always leave the test enabled which
|
||||
@ -310,6 +312,9 @@ _cogl_destroy_context (void)
|
||||
if (_context->default_layer_0)
|
||||
cogl_handle_unref (_context->default_layer_0);
|
||||
|
||||
if (_context->current_clip_stack_valid)
|
||||
_cogl_clip_stack_unref (_context->current_clip_stack);
|
||||
|
||||
if (_context->atlas)
|
||||
_cogl_atlas_free (_context->atlas);
|
||||
|
||||
|
@ -187,6 +187,28 @@ typedef struct
|
||||
cogl_is_buffer */
|
||||
GSList *buffer_types;
|
||||
|
||||
/* Clipping */
|
||||
/* TRUE if we have a valid clipping stack flushed. In that case
|
||||
current_clip_stack will describe what the current state is. If
|
||||
this is FALSE then the current clip stack is completely unknown
|
||||
so it will need to be reflushed. In that case current_clip_stack
|
||||
doesn't need to be a valid pointer. We can't just use NULL in
|
||||
current_clip_stack to mark a dirty state because NULL is a valid
|
||||
stack (meaning no clipping) */
|
||||
gboolean current_clip_stack_valid;
|
||||
/* The clip state that was flushed. This isn't intended to be used
|
||||
as a stack to push and pop new entries. Instead the current stack
|
||||
that the user wants is part of the framebuffer state. This is
|
||||
just used to record the flush state so we can avoid flushing the
|
||||
same state multiple times. When the clip state is flushed this
|
||||
will hold a reference */
|
||||
CoglClipStack *current_clip_stack;
|
||||
/* Whether the stencil buffer was used as part of the current clip
|
||||
state. If TRUE then any further use of the stencil buffer (such
|
||||
as for drawing paths) would need to be merged with the existing
|
||||
stencil buffer */
|
||||
gboolean current_clip_stack_uses_stencil;
|
||||
|
||||
CoglContextDriver drv;
|
||||
CoglContextWinsys winsys;
|
||||
} CoglContext;
|
||||
|
@ -636,7 +636,7 @@ _cogl_set_framebuffer_real (CoglFramebuffer *framebuffer)
|
||||
* we flush */
|
||||
_cogl_matrix_stack_dirty (framebuffer->modelview_stack);
|
||||
_cogl_matrix_stack_dirty (framebuffer->projection_stack);
|
||||
_cogl_clip_state_dirty (&framebuffer->clip_state);
|
||||
_cogl_clip_stack_dirty ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -266,18 +266,14 @@ _cogl_path_get_bounds (CoglPath *path,
|
||||
static void
|
||||
_cogl_path_fill_nodes_with_stencil_buffer (CoglPath *path)
|
||||
{
|
||||
CoglFramebuffer *framebuffer;
|
||||
CoglClipState *clip_state;
|
||||
|
||||
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
|
||||
|
||||
_cogl_journal_flush ();
|
||||
|
||||
framebuffer = _cogl_get_framebuffer ();
|
||||
clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
|
||||
g_assert (ctx->current_clip_stack_valid);
|
||||
|
||||
_cogl_add_path_to_stencil_buffer (path,
|
||||
clip_state->stencil_used,
|
||||
ctx->current_clip_stack_uses_stencil,
|
||||
FALSE);
|
||||
|
||||
cogl_rectangle (path->data->path_nodes_min.x,
|
||||
@ -294,7 +290,7 @@ _cogl_path_fill_nodes_with_stencil_buffer (CoglPath *path)
|
||||
* we call cogl_flush() to emtpy the journal.
|
||||
*/
|
||||
cogl_flush ();
|
||||
_cogl_clip_state_dirty (clip_state);
|
||||
_cogl_clip_stack_dirty ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user