From 068ee55997d854debfcbad0689299ef29b111e7d Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Mon, 11 Jul 2011 02:27:54 +0100 Subject: 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 framebuffer mask has highest precedence and can be used to affect all rendering to the framebuffer while the pipeline masks can be used to affect individual primitives. --- 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 | 28 +++++++++++++ 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 ++++++++++++ 10 files changed, 248 insertions(+), 3 deletions(-) diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h index 4ce999b3..20123c6c 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 2674b235..088bfae6 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 1b0ee444..3e41077d 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 af8cc9a2..37d8514e 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 df8f8307..4462a601 100644 --- a/cogl/cogl-framebuffer.h +++ b/cogl/cogl-framebuffer.h @@ -227,6 +227,34 @@ void cogl_framebuffer_set_dither_enabled (CoglFramebuffer *framebuffer, gboolean dither_enabled); +/** + * 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); + +/** + * 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. + */ +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 1b15b557..80a7fdcf 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 35d05e7d..41f73ab8 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<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; + } } } @@ -3480,6 +3497,16 @@ _cogl_pipeline_point_size_equal (CoglPipeline *authority0, return authority0->big_state->point_size == authority1->big_state->point_size; } +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) @@ -3794,6 +3821,12 @@ _cogl_pipeline_equal (CoglPipeline *pipeline0, _cogl_pipeline_point_size_equal)) goto done; + 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, @@ -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 28d756a8..9e68e839 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 55f22969..0d17b932 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__ */ -- cgit v1.2.1