cogl: Implement retained clip stacks
authorNeil Roberts <neil@linux.intel.com>
Thu, 15 Apr 2010 09:58:28 +0000 (10:58 +0100)
committerNeil Roberts <neil@linux.intel.com>
Thu, 15 Apr 2010 13:51:01 +0000 (14:51 +0100)
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.

clutter/cogl/cogl/cogl-clip-stack.c
clutter/cogl/cogl/cogl-clip-stack.h
clutter/cogl/cogl/cogl-clip-state.c
clutter/cogl/cogl/cogl-clip-state.h

index 37e7d39..6322156 100644 (file)
@@ -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;
+}
index efeac3a..15d44b7 100644 (file)
@@ -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 */
index 289ff6b..41ad062 100644 (file)
@@ -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;
+}
index 0f292dd..dc5e80b 100644 (file)
@@ -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 */