From 30c4678ff4c7fdcded9756333cd220a67ba26125 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Thu, 15 Apr 2010 10:58:28 +0100 Subject: [PATCH] cogl: Implement retained clip stacks This adds three new internal API functions which can be used to retain the clip stack state and restore it later: _cogl_get_clip_stack _cogl_set_clip_stack _cogl_clip_stack_copy The functions are currently internal and not yet used but we may want to make them public in future to replace the cogl_clip_stack_save() and cogl_clip_stack_restore() APIs. The get function just returns the handle to the clip stack at the top of the stack of stacks and the set function just replaces it. The copy function makes a cheap copy of an existing stack by taking a reference to the top stack entry. This ends up working like a deep copy because there is no way to modify entries of a stack but it doesn't actually copy the data. --- cogl/cogl-clip-stack.c | 26 ++++++++++++++++++++++++++ cogl/cogl-clip-stack.h | 19 +++++++++++++++++++ cogl/cogl-clip-state.c | 34 ++++++++++++++++++++++++++++++++++ cogl/cogl-clip-state.h | 28 ++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+) diff --git a/cogl/cogl-clip-stack.c b/cogl/cogl-clip-stack.c index 37e7d3982..632215617 100644 --- a/cogl/cogl-clip-stack.c +++ b/cogl/cogl-clip-stack.c @@ -682,3 +682,29 @@ _cogl_clip_stack_free (CoglClipStack *stack) g_slice_free (CoglClipStack, stack); } + +CoglHandle +_cogl_clip_stack_copy (CoglHandle handle) +{ + CoglHandle new_handle; + CoglClipStack *new_stack, *old_stack; + + if (!cogl_is_clip_stack (handle)) + return COGL_INVALID_HANDLE; + + old_stack = COGL_CLIP_STACK (handle); + + new_handle = _cogl_clip_stack_new (); + new_stack = COGL_CLIP_STACK (new_handle); + + /* We can copy the stack by just referencing the other stack's + data. There's no need to implement copy-on-write because the + entries of the stack can't be modified. If the other stack pops + some entries off they will still be kept alive because this stack + holds a reference. */ + new_stack->stack_top = old_stack->stack_top; + if (new_stack->stack_top) + new_stack->stack_top->ref_count++; + + return new_handle; +} diff --git a/cogl/cogl-clip-stack.h b/cogl/cogl-clip-stack.h index efeac3a19..15d44b7a1 100644 --- a/cogl/cogl-clip-stack.h +++ b/cogl/cogl-clip-stack.h @@ -53,4 +53,23 @@ void _cogl_clip_stack_flush (CoglHandle handle, gboolean *stencil_used_p); + +/* TODO: we may want to make this function public because it can be + * used to implement a better API than cogl_clip_stack_save() and + * cogl_clip_stack_restore(). + */ +/* + * _cogl_clip_stack_copy: + * @handle: A handle to a clip stack + * + * Creates a copy of the given clip stack and returns a new handle to + * it. The data from the original stack is shared with the new stack + * so making copies is relatively cheap. Modifying the original stack + * does not affect the new stack. + * + * Return value: a new clip stack with the same data as @handle + */ +CoglHandle +_cogl_clip_stack_copy (CoglHandle handle); + #endif /* __COGL_CLIP_STACK_H */ diff --git a/cogl/cogl-clip-state.c b/cogl/cogl-clip-state.c index 289ff6ba0..41ad06237 100644 --- a/cogl/cogl-clip-state.c +++ b/cogl/cogl-clip-state.c @@ -403,3 +403,37 @@ _cogl_clip_state_dirty (CoglClipState *clip_state) { clip_state->stack_dirty = TRUE; } + +CoglHandle +_cogl_get_clip_stack (void) +{ + CoglHandle framebuffer; + CoglClipState *clip_state; + + _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); + + framebuffer = _cogl_get_framebuffer (); + clip_state = _cogl_framebuffer_get_clip_state (framebuffer); + + return clip_state->stacks->data; +} + +void +_cogl_set_clip_stack (CoglHandle handle) +{ + CoglHandle framebuffer; + CoglClipState *clip_state; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (handle == COGL_INVALID_HANDLE) + return; + + framebuffer = _cogl_get_framebuffer (); + clip_state = _cogl_framebuffer_get_clip_state (framebuffer); + + /* Replace the top of the stack of stacks */ + cogl_handle_ref (handle); + cogl_handle_unref (clip_state->stacks->data); + clip_state->stacks->data = handle; +} diff --git a/cogl/cogl-clip-state.h b/cogl/cogl-clip-state.h index 0f292dd55..dc5e80b76 100644 --- a/cogl/cogl-clip-state.h +++ b/cogl/cogl-clip-state.h @@ -47,4 +47,32 @@ _cogl_clip_state_dirty (CoglClipState *state); void _cogl_clip_state_flush (CoglClipState *clip_state); +/* TODO: we may want to make these two functions public because they + * can be used to implement a better API than cogl_clip_stack_save() + * and cogl_clip_stack_restore(). + */ +/* + * _cogl_get_clip_stack: + * + * Gets a handle to the current clip stack. This can be used to later + * return to the same clip stack state with _cogl_set_clip_stack(). A + * reference is not taken on the stack so if you want to keep it you + * should call cogl_handle_ref() or _cogl_clip_stack_copy(). + * + * Return value: a handle to the current clip stack. + */ +CoglHandle +_cogl_get_clip_stack (void); + +/* + * _cogl_set_clip_stack: + * @handle: a handle to the replacement clip stack + * + * Replaces the current clip stack with @handle. + * + * Return value: a handle to the current clip stack. + */ +void +_cogl_set_clip_stack (CoglHandle handle); + #endif /* __COGL_CLIP_STATE_H */