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>
This commit is contained in:
Robert Bragg 2011-07-11 02:27:54 +01:00
parent 9b6c1eb2cc
commit 8b34a39319
11 changed files with 260 additions and 3 deletions

View File

@ -204,6 +204,7 @@ struct _CoglContext
GLuint current_gl_program; GLuint current_gl_program;
gboolean current_gl_dither_enabled; gboolean current_gl_dither_enabled;
CoglColorMask current_gl_color_mask;
/* List of types that will be considered a subclass of CoglTexture in /* List of types that will be considered a subclass of CoglTexture in
cogl_is_texture */ cogl_is_texture */

View File

@ -277,6 +277,7 @@ cogl_context_new (CoglDisplay *display,
context->current_gl_program = 0; context->current_gl_program = 0;
context->current_gl_dither_enabled = TRUE; context->current_gl_dither_enabled = TRUE;
context->current_gl_color_mask = COGL_COLOR_MASK_ALL;
context->gl_blend_enable_cache = FALSE; context->gl_blend_enable_cache = FALSE;

View File

@ -75,6 +75,7 @@ struct _CoglFramebuffer
int alpha_bits; int alpha_bits;
gboolean dither_enabled; gboolean dither_enabled;
CoglColorMask color_mask;
/* We journal the textured rectangles we want to submit to OpenGL so /* We journal the textured rectangles we want to submit to OpenGL so
* we have an oppertunity to batch them together into less draw * we have an oppertunity to batch them together into less draw

View File

@ -155,6 +155,8 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
framebuffer->dirty_bitmasks = TRUE; framebuffer->dirty_bitmasks = TRUE;
framebuffer->color_mask = COGL_COLOR_MASK_ALL;
/* Initialise the clip stack */ /* Initialise the clip stack */
_cogl_clip_state_init (&framebuffer->clip_state); _cogl_clip_state_init (&framebuffer->clip_state);
@ -238,8 +240,24 @@ _cogl_clear4f (unsigned long buffers,
if (buffers & COGL_BUFFER_BIT_COLOR) if (buffers & COGL_BUFFER_BIT_COLOR)
{ {
CoglFramebuffer *draw_framebuffer;
GE( ctx, glClearColor (red, green, blue, alpha) ); GE( ctx, glClearColor (red, green, blue, alpha) );
gl_buffers |= GL_COLOR_BUFFER_BIT; 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) if (buffers & COGL_BUFFER_BIT_DEPTH)
@ -1492,6 +1510,26 @@ cogl_framebuffer_get_alpha_bits (CoglFramebuffer *framebuffer)
return framebuffer->alpha_bits; 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 gboolean
cogl_framebuffer_get_dither_enabled (CoglFramebuffer *framebuffer) cogl_framebuffer_get_dither_enabled (CoglFramebuffer *framebuffer)
{ {

View File

@ -227,6 +227,40 @@ void
cogl_framebuffer_set_dither_enabled (CoglFramebuffer *framebuffer, cogl_framebuffer_set_dither_enabled (CoglFramebuffer *framebuffer,
gboolean dither_enabled); 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 #define cogl_framebuffer_swap_buffers cogl_framebuffer_swap_buffers_EXP
void void
cogl_framebuffer_swap_buffers (CoglFramebuffer *framebuffer); cogl_framebuffer_swap_buffers (CoglFramebuffer *framebuffer);

View File

@ -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 != ctx->gl_blend_enable_cache)
{ {
if (pipeline->real_blend_enable) if (pipeline->real_blend_enable)

View File

@ -428,6 +428,7 @@ typedef enum
COGL_PIPELINE_STATE_DEPTH_INDEX, COGL_PIPELINE_STATE_DEPTH_INDEX,
COGL_PIPELINE_STATE_FOG_INDEX, COGL_PIPELINE_STATE_FOG_INDEX,
COGL_PIPELINE_STATE_POINT_SIZE_INDEX, COGL_PIPELINE_STATE_POINT_SIZE_INDEX,
COGL_PIPELINE_STATE_LOGIC_OPS_INDEX,
/* non-sparse */ /* non-sparse */
COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX, COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX,
@ -471,6 +472,8 @@ typedef enum _CoglPipelineState
1L<<COGL_PIPELINE_STATE_FOG_INDEX, 1L<<COGL_PIPELINE_STATE_FOG_INDEX,
COGL_PIPELINE_STATE_POINT_SIZE = COGL_PIPELINE_STATE_POINT_SIZE =
1L<<COGL_PIPELINE_STATE_POINT_SIZE_INDEX, 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 = COGL_PIPELINE_STATE_REAL_BLEND_ENABLE =
1L<<COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX, 1L<<COGL_PIPELINE_STATE_REAL_BLEND_ENABLE_INDEX,
@ -504,14 +507,16 @@ typedef enum _CoglPipelineState
COGL_PIPELINE_STATE_USER_SHADER | \ COGL_PIPELINE_STATE_USER_SHADER | \
COGL_PIPELINE_STATE_DEPTH | \ COGL_PIPELINE_STATE_DEPTH | \
COGL_PIPELINE_STATE_FOG | \ 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 \ #define COGL_PIPELINE_STATE_MULTI_PROPERTY \
(COGL_PIPELINE_STATE_LAYERS | \ (COGL_PIPELINE_STATE_LAYERS | \
COGL_PIPELINE_STATE_LIGHTING | \ COGL_PIPELINE_STATE_LIGHTING | \
COGL_PIPELINE_STATE_BLEND | \ COGL_PIPELINE_STATE_BLEND | \
COGL_PIPELINE_STATE_DEPTH | \ COGL_PIPELINE_STATE_DEPTH | \
COGL_PIPELINE_STATE_FOG) COGL_PIPELINE_STATE_FOG | \
COGL_PIPELINE_STATE_LOGIC_OPS)
#define COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN \ #define COGL_PIPELINE_STATE_AFFECTS_VERTEX_CODEGEN \
(COGL_PIPELINE_STATE_LAYERS | \ (COGL_PIPELINE_STATE_LAYERS | \
@ -576,6 +581,11 @@ typedef struct
float z_far; float z_far;
} CoglPipelineFogState; } CoglPipelineFogState;
typedef struct
{
CoglColorMask color_mask;
} CoglPipelineLogicOpsState;
typedef struct typedef struct
{ {
CoglPipelineLightingState lighting_state; CoglPipelineLightingState lighting_state;
@ -585,6 +595,7 @@ typedef struct
CoglDepthState depth_state; CoglDepthState depth_state;
CoglPipelineFogState fog_state; CoglPipelineFogState fog_state;
float point_size; float point_size;
CoglPipelineLogicOpsState logic_ops_state;
} CoglPipelineBigState; } CoglPipelineBigState;
typedef enum typedef enum

View File

@ -196,6 +196,7 @@ _cogl_pipeline_init_default_pipeline (void)
CoglPipelineAlphaFuncState *alpha_state = &big_state->alpha_state; CoglPipelineAlphaFuncState *alpha_state = &big_state->alpha_state;
CoglPipelineBlendState *blend_state = &big_state->blend_state; CoglPipelineBlendState *blend_state = &big_state->blend_state;
CoglDepthState *depth_state = &big_state->depth_state; CoglDepthState *depth_state = &big_state->depth_state;
CoglPipelineLogicOpsState *logic_ops_state = &big_state->logic_ops_state;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -301,6 +302,8 @@ _cogl_pipeline_init_default_pipeline (void)
big_state->point_size = 1.0f; big_state->point_size = 1.0f;
logic_ops_state->color_mask = COGL_COLOR_MASK_ALL;
ctx->default_pipeline = _cogl_pipeline_object_new (pipeline); 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) if (differences & COGL_PIPELINE_STATE_POINT_SIZE)
big_state->point_size = src->big_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 /* XXX: we shouldn't bother doing this in most cases since
* _copy_differences is typically used to initialize pipeline state * _copy_differences is typically used to initialize pipeline state
* by copying it from the current authority, so it's not actually * 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)); sizeof (CoglPipelineFogState));
break; 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; 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 static gboolean
_cogl_pipeline_user_shader_equal (CoglPipeline *authority0, _cogl_pipeline_user_shader_equal (CoglPipeline *authority0,
CoglPipeline *authority1) CoglPipeline *authority1)
@ -3794,6 +3821,12 @@ _cogl_pipeline_equal (CoglPipeline *pipeline0,
_cogl_pipeline_point_size_equal)) _cogl_pipeline_point_size_equal))
goto done; 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, if (!simple_property_equal (authorities0, authorities1,
pipelines_difference, pipelines_difference,
COGL_PIPELINE_STATE_USER_SHADER_INDEX, COGL_PIPELINE_STATE_USER_SHADER_INDEX,
@ -4745,6 +4778,49 @@ cogl_pipeline_get_depth_state (CoglPipeline *pipeline,
*state = authority->big_state->depth_state; *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 static void
_cogl_pipeline_set_fog_state (CoglPipeline *pipeline, _cogl_pipeline_set_fog_state (CoglPipeline *pipeline,
const CoglPipelineFogState *fog_state) const CoglPipelineFogState *fog_state)
@ -6193,6 +6269,15 @@ _cogl_pipeline_hash_point_size_state (CoglPipeline *authority,
sizeof (point_size)); 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); typedef void (*StateHashFunction) (CoglPipeline *authority, HashState *state);
static StateHashFunction static StateHashFunction
@ -6226,9 +6311,11 @@ _cogl_pipeline_init_state_hash_functions (void)
_cogl_pipeline_hash_fog_state; _cogl_pipeline_hash_fog_state;
state_hash_functions[COGL_PIPELINE_STATE_POINT_SIZE_INDEX] = state_hash_functions[COGL_PIPELINE_STATE_POINT_SIZE_INDEX] =
_cogl_pipeline_hash_point_size_state; _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! */ /* 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 unsigned int

View File

@ -633,6 +633,40 @@ cogl_pipeline_set_point_size (CoglHandle pipeline,
float float
cogl_pipeline_get_point_size (CoglHandle pipeline); 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: * cogl_pipeline_get_user_program:
* @pipeline: a #CoglPipeline object. * @pipeline: a #CoglPipeline object.

View File

@ -671,6 +671,32 @@ typedef enum _CoglWinsysFeature
COGL_WINSYS_FEATURE_N_FEATURES COGL_WINSYS_FEATURE_N_FEATURES
} CoglWinsysFeature; } 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 G_END_DECLS
#endif /* __COGL_TYPES_H__ */ #endif /* __COGL_TYPES_H__ */

View File

@ -320,6 +320,8 @@ cogl_framebuffer_get_red_bits
cogl_framebuffer_get_green_bits cogl_framebuffer_get_green_bits
cogl_framebuffer_get_blue_bits cogl_framebuffer_get_blue_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_buffers
cogl_framebuffer_swap_region cogl_framebuffer_swap_region
cogl_framebuffer_add_swap_buffers_callback cogl_framebuffer_add_swap_buffers_callback
@ -504,6 +506,9 @@ cogl_pipeline_set_blend_constant
cogl_pipeline_set_point_size cogl_pipeline_set_point_size
cogl_pipeline_get_point_size cogl_pipeline_get_point_size
cogl_pipeline_get_color_mask
cogl_pipeline_set_color_mask
cogl_pipeline_set_layer_texture cogl_pipeline_set_layer_texture
cogl_pipeline_get_layer_texture cogl_pipeline_get_layer_texture
CoglMaterialFilter CoglMaterialFilter
@ -620,6 +625,7 @@ CoglPixelFormat
CoglBufferTarget CoglBufferTarget
CoglBufferBit CoglBufferBit
CoglAttributeType CoglAttributeType
CoglColorMask
</SECTION> </SECTION>
<SECTION> <SECTION>