[cogl] Adds ColorMask support to Cogl



commit 8b34a3931981ea57a217db4170fc0ef5230feee2
Author: Robert Bragg <robert linux intel com>
Date:   Mon Jul 11 02:27:54 2011 +0100

    Adds ColorMask support to Cogl
    
    This adds CoglPipeline and CoglFramebuffer support for setting a color
    mask which is a bit mask defining which color channels should be written
    to the current framebuffer.
    
    The final color mask is the intersection of the framebuffer color mask
    and the pipeline color mask. The framebuffer mask affects all rendering
    to the framebuffer while the pipeline masks can be used to affect
    individual primitives.
    
    Reviewed-by: Neil Roberts <neil linux intel com>

 cogl/cogl-context-private.h                        |    1 +
 cogl/cogl-context.c                                |    1 +
 cogl/cogl-framebuffer-private.h                    |    1 +
 cogl/cogl-framebuffer.c                            |   38 ++++++++
 cogl/cogl-framebuffer.h                            |   34 ++++++++
 cogl/cogl-pipeline-opengl.c                        |   18 ++++
 cogl/cogl-pipeline-private.h                       |   15 +++-
 cogl/cogl-pipeline.c                               |   89 +++++++++++++++++++-
 cogl/cogl-pipeline.h                               |   34 ++++++++
 cogl/cogl-types.h                                  |   26 ++++++
 .../cogl-2.0-experimental-sections.txt             |    6 ++
 11 files changed, 260 insertions(+), 3 deletions(-)
---
diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index 177b5c3..175a2c9 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl-context-private.h
@@ -204,6 +204,7 @@ struct _CoglContext
   GLuint                  current_gl_program;
 
   gboolean current_gl_dither_enabled;
+  CoglColorMask current_gl_color_mask;
 
   /* List of types that will be considered a subclass of CoglTexture in
      cogl_is_texture */
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index 83936e0..90ef988 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -277,6 +277,7 @@ cogl_context_new (CoglDisplay *display,
   context->current_gl_program = 0;
 
   context->current_gl_dither_enabled = TRUE;
+  context->current_gl_color_mask = COGL_COLOR_MASK_ALL;
 
   context->gl_blend_enable_cache = FALSE;
 
diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h
index 1b0ee44..3e41077 100644
--- a/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl-framebuffer-private.h
@@ -75,6 +75,7 @@ struct _CoglFramebuffer
   int                 alpha_bits;
 
   gboolean            dither_enabled;
+  CoglColorMask       color_mask;
 
   /* We journal the textured rectangles we want to submit to OpenGL so
    * we have an oppertunity to batch them together into less draw
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index af8cc9a..6ece74d 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -155,6 +155,8 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
 
   framebuffer->dirty_bitmasks   = TRUE;
 
+  framebuffer->color_mask       = COGL_COLOR_MASK_ALL;
+
   /* Initialise the clip stack */
   _cogl_clip_state_init (&framebuffer->clip_state);
 
@@ -238,8 +240,24 @@ _cogl_clear4f (unsigned long buffers,
 
   if (buffers & COGL_BUFFER_BIT_COLOR)
     {
+      CoglFramebuffer *draw_framebuffer;
+
       GE( ctx, glClearColor (red, green, blue, alpha) );
       gl_buffers |= GL_COLOR_BUFFER_BIT;
+
+      draw_framebuffer = cogl_get_draw_framebuffer ();
+      if (ctx->current_gl_color_mask != draw_framebuffer->color_mask)
+        {
+          CoglColorMask color_mask = draw_framebuffer->color_mask;
+          GE( ctx, glColorMask (!!(color_mask & COGL_COLOR_MASK_RED),
+                                !!(color_mask & COGL_COLOR_MASK_GREEN),
+                                !!(color_mask & COGL_COLOR_MASK_BLUE),
+                                !!(color_mask & COGL_COLOR_MASK_ALPHA)));
+          ctx->current_gl_color_mask = color_mask;
+          /* Make sure the ColorMask is updated when the next primitive is drawn */
+          ctx->current_pipeline_changes_since_flush |=
+            COGL_PIPELINE_STATE_LOGIC_OPS;
+        }
     }
 
   if (buffers & COGL_BUFFER_BIT_DEPTH)
@@ -1492,6 +1510,26 @@ cogl_framebuffer_get_alpha_bits (CoglFramebuffer *framebuffer)
   return framebuffer->alpha_bits;
 }
 
+CoglColorMask
+cogl_framebuffer_get_color_mask (CoglFramebuffer *framebuffer)
+{
+  return framebuffer->color_mask;
+}
+
+void
+cogl_framebuffer_set_color_mask (CoglFramebuffer *framebuffer,
+                                 CoglColorMask color_mask)
+{
+  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+  cogl_flush (); /* XXX: Currently color mask changes don't go through the journal */
+  framebuffer->color_mask = color_mask;
+
+  /* Make sure the ColorMask is updated when the next primitive is drawn */
+  ctx->current_pipeline_changes_since_flush |=
+    COGL_PIPELINE_STATE_LOGIC_OPS;
+}
+
 gboolean
 cogl_framebuffer_get_dither_enabled (CoglFramebuffer *framebuffer)
 {
diff --git a/cogl/cogl-framebuffer.h b/cogl/cogl-framebuffer.h
index df8f830..7e31f22 100644
--- a/cogl/cogl-framebuffer.h
+++ b/cogl/cogl-framebuffer.h
@@ -227,6 +227,40 @@ void
 cogl_framebuffer_set_dither_enabled (CoglFramebuffer *framebuffer,
                                      gboolean dither_enabled);
 
+#define cogl_framebuffer_get_color_mask cogl_framebuffer_get_color_mask_EXP
+/**
+ * cogl_framebuffer_get_color_mask:
+ * @framebuffer: a pointer to a #CoglFramebuffer
+ *
+ * Gets the current #CoglColorMask of which channels would be written to the
+ * current framebuffer. Each bit set in the mask means that the
+ * corresponding color would be written.
+ *
+ * Returns: A #CoglColorMask
+ * Since: 1.8
+ * Stability: unstable
+ */
+CoglColorMask
+cogl_framebuffer_get_color_mask (CoglFramebuffer *framebuffer);
+
+#define cogl_framebuffer_set_color_mask cogl_framebuffer_set_color_mask_EXP
+/**
+ * cogl_framebuffer_set_color_mask:
+ * @framebuffer: a pointer to a #CoglFramebuffer
+ * @color_mask: A #CoglColorMask of which color channels to write to
+ *              the current framebuffer.
+ *
+ * Defines a bit mask of which color channels should be written to the
+ * given @framebuffer. If a bit is set in @color_mask that means that
+ * color will be written.
+ *
+ * Since: 1.8
+ * Stability: unstable
+ */
+void
+cogl_framebuffer_set_color_mask (CoglFramebuffer *framebuffer,
+                                 CoglColorMask color_mask);
+
 #define cogl_framebuffer_swap_buffers cogl_framebuffer_swap_buffers_EXP
 void
 cogl_framebuffer_swap_buffers (CoglFramebuffer *framebuffer);
diff --git a/cogl/cogl-pipeline-opengl.c b/cogl/cogl-pipeline-opengl.c
index 1b15b55..874b82e 100644
--- a/cogl/cogl-pipeline-opengl.c
+++ b/cogl/cogl-pipeline-opengl.c
@@ -607,6 +607,24 @@ _cogl_pipeline_flush_color_blend_alpha_depth_state (
         }
     }
 
+  if (pipelines_difference & COGL_PIPELINE_STATE_LOGIC_OPS)
+    {
+      CoglPipeline *authority =
+        _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LOGIC_OPS);
+      CoglPipelineLogicOpsState *logic_ops_state = &authority->big_state->logic_ops_state;
+      CoglColorMask color_mask = logic_ops_state->color_mask;
+      CoglFramebuffer *draw_framebuffer = cogl_get_draw_framebuffer ();
+
+      if (draw_framebuffer)
+        color_mask &= draw_framebuffer->color_mask;
+
+      GE (ctx, glColorMask (!!(color_mask & COGL_COLOR_MASK_RED),
+                            !!(color_mask & COGL_COLOR_MASK_GREEN),
+                            !!(color_mask & COGL_COLOR_MASK_BLUE),
+                            !!(color_mask & COGL_COLOR_MASK_ALPHA)));
+      ctx->current_gl_color_mask = color_mask;
+    }
+
   if (pipeline->real_blend_enable != ctx->gl_blend_enable_cache)
     {
       if (pipeline->real_blend_enable)
diff --git a/cogl/cogl-pipeline-private.h b/cogl/cogl-pipeline-private.h
index 35d05e7..41f73ab 100644
--- a/cogl/cogl-pipeline-private.h
+++ b/cogl/cogl-pipeline-private.h
@@ -428,6 +428,7 @@ typedef enum
   COGL_PIPELINE_STATE_DEPTH_INDEX,
   COGL_PIPELINE_STATE_FOG_INDEX,
   COGL_PIPELINE_STATE_POINT_SIZE_INDEX,
+  COGL_PIPELINE_STATE_LOGIC_OPS_INDEX,
 
   /* non-sparse */
   COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX,
@@ -471,6 +472,8 @@ typedef enum _CoglPipelineState
     1L<<COGL_PIPELINE_STATE_FOG_INDEX,
   COGL_PIPELINE_STATE_POINT_SIZE =
     1L<<COGL_PIPELINE_STATE_POINT_SIZE_INDEX,
+  COGL_PIPELINE_STATE_LOGIC_OPS =
+    1L<<COGL_PIPELINE_STATE_LOGIC_OPS_INDEX,
 
   COGL_PIPELINE_STATE_REAL_BLEND_ENABLE =
     1L<<COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX,
@@ -504,14 +507,16 @@ typedef enum _CoglPipelineState
    COGL_PIPELINE_STATE_USER_SHADER | \
    COGL_PIPELINE_STATE_DEPTH | \
    COGL_PIPELINE_STATE_FOG | \
-   COGL_PIPELINE_STATE_POINT_SIZE)
+   COGL_PIPELINE_STATE_POINT_SIZE | \
+   COGL_PIPELINE_STATE_LOGIC_OPS)
 
 #define COGL_PIPELINE_STATE_MULTI_PROPERTY \
   (COGL_PIPELINE_STATE_LAYERS | \
    COGL_PIPELINE_STATE_LIGHTING | \
    COGL_PIPELINE_STATE_BLEND | \
    COGL_PIPELINE_STATE_DEPTH | \
-   COGL_PIPELINE_STATE_FOG)
+   COGL_PIPELINE_STATE_FOG | \
+   COGL_PIPELINE_STATE_LOGIC_OPS)
 
 #define COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN \
   (COGL_PIPELINE_STATE_LAYERS | \
@@ -578,6 +583,11 @@ typedef struct
 
 typedef struct
 {
+  CoglColorMask color_mask;
+} CoglPipelineLogicOpsState;
+
+typedef struct
+{
   CoglPipelineLightingState lighting_state;
   CoglPipelineAlphaFuncState alpha_state;
   CoglPipelineBlendState blend_state;
@@ -585,6 +595,7 @@ typedef struct
   CoglDepthState depth_state;
   CoglPipelineFogState fog_state;
   float point_size;
+  CoglPipelineLogicOpsState logic_ops_state;
 } CoglPipelineBigState;
 
 typedef enum
diff --git a/cogl/cogl-pipeline.c b/cogl/cogl-pipeline.c
index 4d70a6f..8b87a2e 100644
--- a/cogl/cogl-pipeline.c
+++ b/cogl/cogl-pipeline.c
@@ -196,6 +196,7 @@ _cogl_pipeline_init_default_pipeline (void)
   CoglPipelineAlphaFuncState *alpha_state = &big_state->alpha_state;
   CoglPipelineBlendState *blend_state = &big_state->blend_state;
   CoglDepthState *depth_state = &big_state->depth_state;
+  CoglPipelineLogicOpsState *logic_ops_state = &big_state->logic_ops_state;
 
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
@@ -301,6 +302,8 @@ _cogl_pipeline_init_default_pipeline (void)
 
   big_state->point_size = 1.0f;
 
+  logic_ops_state->color_mask = COGL_COLOR_MASK_ALL;
+
   ctx->default_pipeline = _cogl_pipeline_object_new (pipeline);
 }
 
@@ -1067,6 +1070,13 @@ _cogl_pipeline_copy_differences (CoglPipeline *dest,
   if (differences & COGL_PIPELINE_STATE_POINT_SIZE)
     big_state->point_size = src->big_state->point_size;
 
+  if (differences & COGL_PIPELINE_STATE_LOGIC_OPS)
+    {
+      memcpy (&big_state->logic_ops_state,
+              &src->big_state->logic_ops_state,
+              sizeof (CoglPipelineLogicOpsState));
+    }
+
   /* XXX: we shouldn't bother doing this in most cases since
    * _copy_differences is typically used to initialize pipeline state
    * by copying it from the current authority, so it's not actually
@@ -1137,6 +1147,13 @@ _cogl_pipeline_init_multi_property_sparse_state (CoglPipeline *pipeline,
                 sizeof (CoglPipelineFogState));
         break;
       }
+    case COGL_PIPELINE_STATE_LOGIC_OPS:
+      {
+        memcpy (&pipeline->big_state->logic_ops_state,
+                &authority->big_state->logic_ops_state,
+                sizeof (CoglPipelineLogicOpsState));
+        break;
+      }
     }
 }
 
@@ -3481,6 +3498,16 @@ _cogl_pipeline_point_size_equal (CoglPipeline *authority0,
 }
 
 static gboolean
+_cogl_pipeline_logic_ops_state_equal (CoglPipeline *authority0,
+                                      CoglPipeline *authority1)
+{
+  CoglPipelineLogicOpsState *logic_ops_state0 = &authority0->big_state->logic_ops_state;
+  CoglPipelineLogicOpsState *logic_ops_state1 = &authority1->big_state->logic_ops_state;
+
+  return logic_ops_state0->color_mask == logic_ops_state1->color_mask;
+}
+
+static gboolean
 _cogl_pipeline_user_shader_equal (CoglPipeline *authority0,
                                   CoglPipeline *authority1)
 {
@@ -3796,6 +3823,12 @@ _cogl_pipeline_equal (CoglPipeline *pipeline0,
 
   if (!simple_property_equal (authorities0, authorities1,
                               pipelines_difference,
+                              COGL_PIPELINE_STATE_LOGIC_OPS_INDEX,
+                              _cogl_pipeline_logic_ops_state_equal))
+    goto done;
+
+  if (!simple_property_equal (authorities0, authorities1,
+                              pipelines_difference,
                               COGL_PIPELINE_STATE_USER_SHADER_INDEX,
                               _cogl_pipeline_user_shader_equal))
     goto done;
@@ -4745,6 +4778,49 @@ cogl_pipeline_get_depth_state (CoglPipeline *pipeline,
   *state = authority->big_state->depth_state;
 }
 
+CoglColorMask
+cogl_pipeline_get_color_mask (CoglPipeline *pipeline)
+{
+  CoglPipeline *authority;
+
+  g_return_val_if_fail (cogl_is_pipeline (pipeline), 0);
+
+  authority =
+    _cogl_pipeline_get_authority (pipeline, COGL_PIPELINE_STATE_LOGIC_OPS);
+
+  return authority->big_state->logic_ops_state.color_mask;
+}
+
+void
+cogl_pipeline_set_color_mask (CoglPipeline *pipeline,
+                              CoglColorMask color_mask)
+{
+  CoglPipelineState state = COGL_PIPELINE_STATE_LOGIC_OPS;
+  CoglPipeline *authority;
+  CoglPipelineLogicOpsState *logic_ops_state;
+
+  g_return_if_fail (cogl_is_pipeline (pipeline));
+
+  authority = _cogl_pipeline_get_authority (pipeline, state);
+
+  logic_ops_state = &authority->big_state->logic_ops_state;
+  if (logic_ops_state->color_mask == color_mask)
+    return;
+
+  /* - Flush journal primitives referencing the current state.
+   * - Make sure the pipeline has no dependants so it may be modified.
+   * - If the pipeline isn't currently an authority for the state being
+   *   changed, then initialize that state from the current authority.
+   */
+  _cogl_pipeline_pre_change_notify (pipeline, state, NULL, FALSE);
+
+  logic_ops_state = &pipeline->big_state->logic_ops_state;
+  logic_ops_state->color_mask = color_mask;
+
+  _cogl_pipeline_update_authority (pipeline, authority, state,
+                                   _cogl_pipeline_logic_ops_state_equal);
+}
+
 static void
 _cogl_pipeline_set_fog_state (CoglPipeline *pipeline,
                               const CoglPipelineFogState *fog_state)
@@ -6193,6 +6269,15 @@ _cogl_pipeline_hash_point_size_state (CoglPipeline *authority,
                                                sizeof (point_size));
 }
 
+static void
+_cogl_pipeline_hash_logic_ops_state (CoglPipeline *authority,
+                                     HashState *state)
+{
+  CoglPipelineLogicOpsState *logic_ops_state = &authority->big_state->logic_ops_state;
+  state->hash = _cogl_util_one_at_a_time_hash (state->hash, &logic_ops_state->color_mask,
+                                               sizeof (CoglColorMask));
+}
+
 typedef void (*StateHashFunction) (CoglPipeline *authority, HashState *state);
 
 static StateHashFunction
@@ -6226,9 +6311,11 @@ _cogl_pipeline_init_state_hash_functions (void)
     _cogl_pipeline_hash_fog_state;
   state_hash_functions[COGL_PIPELINE_STATE_POINT_SIZE_INDEX] =
     _cogl_pipeline_hash_point_size_state;
+  state_hash_functions[COGL_PIPELINE_STATE_LOGIC_OPS_INDEX] =
+    _cogl_pipeline_hash_logic_ops_state;
 
   /* So we get a big error if we forget to update this code! */
-  g_assert (COGL_PIPELINE_STATE_SPARSE_COUNT == 11);
+  g_assert (COGL_PIPELINE_STATE_SPARSE_COUNT == 12);
 }
 
 unsigned int
diff --git a/cogl/cogl-pipeline.h b/cogl/cogl-pipeline.h
index 28d756a..9e68e83 100644
--- a/cogl/cogl-pipeline.h
+++ b/cogl/cogl-pipeline.h
@@ -633,6 +633,40 @@ cogl_pipeline_set_point_size (CoglHandle pipeline,
 float
 cogl_pipeline_get_point_size (CoglHandle  pipeline);
 
+#define cogl_pipeline_get_color_mask cogl_pipeline_get_color_mask_EXP
+/**
+ * cogl_pipeline_get_color_mask:
+ * @pipeline: a #CoglPipeline object.
+ *
+ * Gets the current #CoglColorMask of which channels would be written to the
+ * current framebuffer. Each bit set in the mask means that the
+ * corresponding color would be written.
+ *
+ * Returns: A #CoglColorMask
+ * Since: 1.8
+ * Stability: unstable
+ */
+CoglColorMask
+cogl_pipeline_get_color_mask (CoglPipeline *pipeline);
+
+#define cogl_pipeline_set_color_mask cogl_pipeline_set_color_mask_EXP
+/**
+ * cogl_pipeline_set_color_mask:
+ * @pipeline: a #CoglPipeline object.
+ * @color_mask: A #CoglColorMask of which color channels to write to
+ *              the current framebuffer.
+ *
+ * Defines a bit mask of which color channels should be written to the
+ * current framebuffer. If a bit is set in @color_mask that means that
+ * color will be written.
+ *
+ * Since: 1.8
+ * Stability: unstable
+ */
+void
+cogl_pipeline_set_color_mask (CoglPipeline *pipeline,
+                              CoglColorMask color_mask);
+
 /**
  * cogl_pipeline_get_user_program:
  * @pipeline: a #CoglPipeline object.
diff --git a/cogl/cogl-types.h b/cogl/cogl-types.h
index 55f2296..0d17b93 100644
--- a/cogl/cogl-types.h
+++ b/cogl/cogl-types.h
@@ -671,6 +671,32 @@ typedef enum _CoglWinsysFeature
   COGL_WINSYS_FEATURE_N_FEATURES
 } CoglWinsysFeature;
 
+/**
+ * CoglColorMask:
+ * @COGL_COLOR_MASK_NONE: None of the color channels are masked
+ * @COGL_COLOR_MASK_RED: Masks the red color channel
+ * @COGL_COLOR_MASK_GREEN: Masks the green color channel
+ * @COGL_COLOR_MASK_BLUE: Masks the blue color channel
+ * @COGL_COLOR_MASK_ALPHA: Masks the alpha color channel
+ * @COGL_COLOR_MASK_ALL: All of the color channels are masked
+ *
+ * Defines a bit mask of color channels. This can be used with
+ * cogl_pipeline_set_color_mask() for example to define which color
+ * channels should be written to the current framebuffer when
+ * drawing something.
+ */
+typedef enum
+{
+  COGL_COLOR_MASK_NONE = 0,
+  COGL_COLOR_MASK_RED = 1L<<0,
+  COGL_COLOR_MASK_GREEN = 1L<<1,
+  COGL_COLOR_MASK_BLUE = 1L<<2,
+  COGL_COLOR_MASK_ALPHA = 1L<<3,
+  /* XXX: glib-mkenums is a perl script that can't cope if we split
+   * this onto multiple lines! *sigh* */
+  COGL_COLOR_MASK_ALL = (COGL_COLOR_MASK_RED | COGL_COLOR_MASK_GREEN | COGL_COLOR_MASK_BLUE | COGL_COLOR_MASK_ALPHA)
+} CoglColorMask;
+
 G_END_DECLS
 
 #endif /* __COGL_TYPES_H__ */
diff --git a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
index c4f8332..476bc9e 100644
--- a/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
+++ b/doc/reference/cogl-2.0-experimental/cogl-2.0-experimental-sections.txt
@@ -320,6 +320,8 @@ cogl_framebuffer_get_red_bits
 cogl_framebuffer_get_green_bits
 cogl_framebuffer_get_blue_bits
 cogl_framebuffer_get_blue_bits
+cogl_framebuffer_get_color_mask
+cogl_framebuffer_set_color_mask
 cogl_framebuffer_swap_buffers
 cogl_framebuffer_swap_region
 cogl_framebuffer_add_swap_buffers_callback
@@ -504,6 +506,9 @@ cogl_pipeline_set_blend_constant
 cogl_pipeline_set_point_size
 cogl_pipeline_get_point_size
 
+cogl_pipeline_get_color_mask
+cogl_pipeline_set_color_mask
+
 cogl_pipeline_set_layer_texture
 cogl_pipeline_get_layer_texture
 CoglMaterialFilter
@@ -620,6 +625,7 @@ CoglPixelFormat
 CoglBufferTarget
 CoglBufferBit
 CoglAttributeType
+CoglColorMask
 </SECTION>
 
 <SECTION>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]