diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h index 177b5c375..175a2c914 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 83936e034..90ef988c4 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 1b0ee444f..3e41077db 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 af8cc9a26..6ece74d33 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 df8f8307c..7e31f2239 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 1b15b557a..874b82ec1 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 35d05e7dc..41f73ab80 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 28d756a8e..9e68e8393 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 55f22969c..0d17b9326 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 c4f833295..476bc9eca 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