cogl: Adds {push,pop,get}_source functions

This exposes the idea of a stack of source materials instead of just
having a single current material. This allows the writing of orthogonal
code that can change the current source material and restore it to its
previous state. It also allows the implementation of new composite
primitives that may want to validate the current source material and
possibly make override changes in a derived material.
This commit is contained in:
Robert Bragg 2010-10-25 13:25:21 +01:00
parent 4ccd915064
commit 1b9a247174
11 changed files with 254 additions and 123 deletions

View File

@ -298,7 +298,6 @@ add_stencil_clip_rectangle (float x_1,
float y_2,
gboolean first)
{
CoglHandle current_source;
CoglFramebuffer *framebuffer = _cogl_get_framebuffer ();
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -310,8 +309,7 @@ add_stencil_clip_rectangle (float x_1,
_cogl_framebuffer_flush_state (framebuffer, 0);
/* temporarily swap in our special stenciling material */
current_source = cogl_object_ref (ctx->source_material);
cogl_set_source (ctx->stencil_material);
cogl_push_source (ctx->stencil_material);
if (first)
{
@ -370,8 +368,7 @@ add_stencil_clip_rectangle (float x_1,
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
/* restore the original source material */
cogl_set_source (current_source);
cogl_object_unref (current_source);
cogl_pop_source ();
}
static void

View File

@ -130,8 +130,8 @@ cogl_create_context (void)
_context->legacy_fog_state.enabled = FALSE;
_context->simple_material = cogl_material_new ();
_context->source_material = NULL;
_context->arbfp_source_buffer = g_string_new ("");
_context->source_stack = NULL;
_context->legacy_state_set = 0;
@ -226,8 +226,8 @@ cogl_create_context (void)
0, /* auto calc row stride */
default_texture_data);
cogl_set_source (_context->simple_material);
_cogl_material_flush_gl_state (_context->source_material, FALSE);
cogl_push_source (_context->simple_material);
_cogl_material_flush_gl_state (_context->simple_material, FALSE);
_cogl_enable (enable_flags);
_cogl_flush_face_winding ();

View File

@ -84,8 +84,8 @@ typedef struct
/* Materials */
CoglMaterial *simple_material;
CoglMaterial *source_material;
GString *arbfp_source_buffer;
GList *source_stack;
int legacy_state_set;

View File

@ -919,5 +919,8 @@ _cogl_material_get_layer_combine_constant (CoglMaterial *material,
int layer_index,
float *constant);
void
_cogl_material_prune_to_n_layers (CoglMaterial *material, int n);
#endif /* __COGL_MATERIAL_PRIVATE_H */

View File

@ -181,7 +181,8 @@ _cogl_path_stroke_nodes (void)
unsigned int path_start = 0;
unsigned long enable_flags = COGL_ENABLE_VERTEX_ARRAY;
CoglPathData *data;
CoglHandle source;
CoglMaterial *copy = NULL;
CoglMaterial *source;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -198,25 +199,25 @@ _cogl_path_stroke_nodes (void)
if (G_UNLIKELY (ctx->legacy_state_set))
{
source = cogl_material_copy (ctx->source_material);
_cogl_material_apply_legacy_state (source);
CoglMaterial *users_source = cogl_get_source ();
copy = cogl_material_copy (users_source);
_cogl_material_apply_legacy_state (copy);
source = copy;
}
else
source = ctx->source_material;
source = cogl_get_source ();
if (cogl_material_get_n_layers (source) != 0)
{
CoglMaterialFlushOptions options;
options.flags = COGL_MATERIAL_FLUSH_DISABLE_MASK;
/* disable all texture layers */
options.disable_layers = (guint32)~0;
/* If we haven't already created a derived material... */
if (source == ctx->source_material)
source = cogl_material_copy (ctx->source_material);
_cogl_material_apply_overrides (source, &options);
/* If we haven't already created a derivative material... */
if (!copy)
copy = cogl_material_copy (source);
_cogl_material_prune_to_n_layers (copy, 0);
source = copy;
}
cogl_push_source (source);
_cogl_material_flush_gl_state (source, FALSE);
/* Disable all client texture coordinate arrays */
@ -234,8 +235,7 @@ _cogl_path_stroke_nodes (void)
path_start += node->path_size;
}
if (G_UNLIKELY (source != ctx->source_material))
cogl_handle_unref (source);
cogl_pop_source ();
}
void
@ -308,7 +308,7 @@ _cogl_path_fill_nodes (CoglPath *path)
textures or textures with waste then it won't work to draw the
path directly. Instead we can use draw the texture as a quad
clipped to the stencil buffer. */
for (l = cogl_material_get_layers (ctx->source_material); l; l = l->next)
for (l = cogl_material_get_layers (cogl_get_source ()); l; l = l->next)
{
CoglHandle layer = l->data;
CoglHandle texture = cogl_material_layer_get_texture (layer);
@ -352,7 +352,6 @@ _cogl_add_path_to_stencil_buffer (CoglPath *path,
{
CoglPathData *data = path->data;
unsigned long enable_flags = COGL_ENABLE_VERTEX_ARRAY;
CoglHandle prev_source;
CoglFramebuffer *framebuffer = _cogl_get_framebuffer ();
CoglMatrixStack *modelview_stack =
_cogl_framebuffer_get_modelview_stack (framebuffer);
@ -371,10 +370,9 @@ _cogl_add_path_to_stencil_buffer (CoglPath *path,
_cogl_framebuffer_flush_state (framebuffer, 0);
/* Just setup a simple material that doesn't use texturing... */
prev_source = cogl_object_ref (ctx->source_material);
cogl_set_source (ctx->stencil_material);
cogl_push_source (ctx->stencil_material);
_cogl_material_flush_gl_state (ctx->source_material, FALSE);
_cogl_material_flush_gl_state (ctx->stencil_material, FALSE);
_cogl_enable (enable_flags);
@ -464,8 +462,7 @@ _cogl_add_path_to_stencil_buffer (CoglPath *path,
GE (glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP));
/* restore the original material */
cogl_set_source (prev_source);
cogl_object_unref (prev_source);
cogl_pop_source ();
}
void

View File

@ -495,17 +495,17 @@ _cogl_rectangles_with_multitexture_coords (
struct _CoglMutiTexturedRect *rects,
int n_rects)
{
CoglHandle material;
const GList *layers;
int n_layers;
const GList *tmp;
guint32 fallback_layers = 0;
gboolean all_use_sliced_quad_fallback = FALSE;
int i;
CoglMaterial *material;
const GList *layers;
int n_layers;
const GList *tmp;
guint32 fallback_layers = 0;
gboolean all_use_sliced_quad_fallback = FALSE;
int i;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
material = ctx->source_material;
material = cogl_get_source ();
layers = cogl_material_get_layers (material);
n_layers = cogl_material_get_n_layers (material);
@ -839,7 +839,7 @@ draw_polygon_sub_texture_cb (CoglHandle tex_handle,
float virtual_origin_y;
float v_to_s_scale_x;
float v_to_s_scale_y;
CoglHandle source;
CoglMaterial *source;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -868,13 +868,10 @@ draw_polygon_sub_texture_cb (CoglHandle tex_handle,
v += state->stride;
}
source = cogl_material_copy (cogl_get_source ());
if (G_UNLIKELY (ctx->legacy_state_set))
{
source = cogl_material_copy (ctx->source_material);
_cogl_material_apply_legacy_state (source);
}
else
source = ctx->source_material;
_cogl_material_apply_legacy_state (source);
options.flags =
COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE |
@ -904,16 +901,13 @@ draw_polygon_sub_texture_cb (CoglHandle tex_handle,
}
/* If we haven't already created a derived material... */
if (source == ctx->source_material)
source = cogl_material_copy (ctx->source_material);
_cogl_material_apply_overrides (source, &options);
_cogl_material_flush_gl_state (source, FALSE);
GE (glDrawArrays (GL_TRIANGLE_FAN, 0, state->n_vertices));
if (G_UNLIKELY (source != ctx->source_material))
cogl_handle_unref (source);
cogl_handle_unref (source);
}
/* handles 2d-sliced textures with > 1 slice */
@ -934,7 +928,7 @@ _cogl_texture_polygon_multiple_primitives (const CoglTextureVertex *vertices,
/* We can assume in this case that we have at least one layer in the
* material that corresponds to a sliced cogl texture */
layers = cogl_material_get_layers (ctx->source_material);
layers = cogl_material_get_layers (cogl_get_source ());
layer0 = (CoglHandle)layers->data;
tex_handle = cogl_material_layer_get_texture (layer0);
@ -986,11 +980,12 @@ _cogl_multitexture_polygon_single_primitive (const CoglTextureVertex *vertices,
GList *tmp;
GLfloat *v;
CoglMaterialFlushOptions options;
CoglHandle source;
CoglMaterial *copy = NULL;
CoglMaterial *source;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
material = ctx->source_material;
material = cogl_get_source ();
layers = cogl_material_get_layers (material);
/* Convert the vertices into an array of GLfloats ready to pass to
@ -1045,11 +1040,12 @@ _cogl_multitexture_polygon_single_primitive (const CoglTextureVertex *vertices,
if (G_UNLIKELY (ctx->legacy_state_set))
{
source = cogl_material_copy (ctx->source_material);
_cogl_material_apply_legacy_state (source);
copy = cogl_material_copy (cogl_get_source ());
_cogl_material_apply_legacy_state (copy);
source = copy;
}
else
source = ctx->source_material;
source = cogl_get_source ();
options.flags = 0;
@ -1066,17 +1062,20 @@ _cogl_multitexture_polygon_single_primitive (const CoglTextureVertex *vertices,
if (options.flags)
{
/* If we haven't already created a derived material... */
if (source == ctx->source_material)
source = cogl_material_copy (ctx->source_material);
_cogl_material_apply_overrides (source, &options);
if (!copy)
{
copy = cogl_material_copy (source);
source = copy;
}
_cogl_material_apply_overrides (copy, &options);
}
_cogl_material_flush_gl_state (source, use_color);
GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices));
if (G_UNLIKELY (source != ctx->source_material))
cogl_handle_unref (source);
if (G_UNLIKELY (copy))
cogl_handle_unref (copy);
}
void
@ -1084,7 +1083,8 @@ cogl_polygon (const CoglTextureVertex *vertices,
unsigned int n_vertices,
gboolean use_color)
{
CoglHandle material;
CoglMaterial *material;
CoglMaterial *copy = NULL;
const GList *layers, *tmp;
int n_layers;
gboolean use_sliced_polygon_fallback = FALSE;
@ -1096,8 +1096,6 @@ cogl_polygon (const CoglTextureVertex *vertices,
GLfloat *v;
CoglMaterialWrapModeOverrides wrap_mode_overrides;
CoglMaterialWrapModeOverrides *wrap_mode_overrides_p = NULL;
CoglHandle original_source_material = NULL;
gboolean overrode_material = FALSE;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -1108,8 +1106,8 @@ cogl_polygon (const CoglTextureVertex *vertices,
* always be done first when preparing to draw. */
_cogl_framebuffer_flush_state (_cogl_get_framebuffer (), 0);
material = ctx->source_material;
layers = cogl_material_get_layers (ctx->source_material);
material = cogl_get_source ();
layers = cogl_material_get_layers (material);
n_layers = g_list_length ((GList *)layers);
memset (&wrap_mode_overrides, 0, sizeof (wrap_mode_overrides));
@ -1237,24 +1235,19 @@ cogl_polygon (const CoglTextureVertex *vertices,
if (use_color)
{
CoglHandle override;
enable_flags |= COGL_ENABLE_COLOR_ARRAY;
GE( glColorPointer (4, GL_UNSIGNED_BYTE,
stride_bytes,
/* NB: [X,Y,Z,TX,TY...,R,G,B,A,...] */
v + 3 + 2 * n_layers) );
if (!_cogl_material_get_real_blend_enabled (ctx->source_material))
if (!_cogl_material_get_real_blend_enabled (material))
{
CoglMaterialBlendEnable blend_enabled =
COGL_MATERIAL_BLEND_ENABLE_ENABLED;
original_source_material = ctx->source_material;
override = cogl_material_copy (original_source_material);
_cogl_material_set_blend_enabled (override, blend_enabled);
/* XXX: cogl_push_source () */
overrode_material = TRUE;
ctx->source_material = override;
copy = cogl_material_copy (material);
_cogl_material_set_blend_enabled (copy, blend_enabled);
material = copy;
}
}
@ -1277,6 +1270,8 @@ cogl_polygon (const CoglTextureVertex *vertices,
_cogl_bitmask_set_range (&ctx->temp_bitmask, n_layers, TRUE);
_cogl_disable_other_texcoord_arrays (&ctx->temp_bitmask);
cogl_push_source (material);
if (use_sliced_polygon_fallback)
_cogl_texture_polygon_multiple_primitives (vertices,
n_vertices,
@ -1291,15 +1286,13 @@ cogl_polygon (const CoglTextureVertex *vertices,
fallback_layers,
wrap_mode_overrides_p);
/* XXX: cogl_pop_source () */
if (overrode_material)
{
cogl_handle_unref (ctx->source_material);
ctx->source_material = original_source_material;
/* XXX: when we have weak materials then any override material
* should get associated with the original material so we don't
* create lots of one-shot materials! */
}
cogl_pop_source ();
if (copy)
cogl_object_unref (copy);
/* XXX: when we have weak materials then any override material
* should get associated with the original material so we don't
* create lots of one-shot materials! */
/* Reset the size of the logged vertex array because rendering
rectangles expects it to start at 0 */

View File

@ -1047,7 +1047,6 @@ _cogl_texture_draw_and_read (CoglHandle handle,
CoglFramebuffer *framebuffer;
int viewport[4];
CoglBitmap *alpha_bmp;
CoglHandle prev_source;
CoglMatrixStack *projection_stack;
CoglMatrixStack *modelview_stack;
int target_width = _cogl_bitmap_get_width (target_bmp);
@ -1093,8 +1092,7 @@ _cogl_texture_draw_and_read (CoglHandle handle,
NULL);
}
prev_source = cogl_handle_ref (ctx->source_material);
cogl_set_source (ctx->texture_download_material);
cogl_push_source (ctx->texture_download_material);
cogl_material_set_layer (ctx->texture_download_material, 0, handle);
@ -1178,8 +1176,7 @@ _cogl_texture_draw_and_read (CoglHandle handle,
_cogl_matrix_stack_pop (projection_stack);
/* restore the original material */
cogl_set_source (prev_source);
cogl_handle_unref (prev_source);
cogl_pop_source ();
return TRUE;
}

View File

@ -1524,11 +1524,12 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
int i;
gboolean skip_gl_color = FALSE;
CoglMaterialFlushOptions options;
CoglHandle source;
CoglMaterial *source;
CoglMaterial *copy = NULL;
_COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
source = ctx->source_material;
source = cogl_get_source ();
if (buffer->new_attributes)
cogl_vertex_buffer_submit_real (buffer);
@ -1592,12 +1593,13 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
attribute->stride,
pointer));
if (!_cogl_material_get_real_blend_enabled (ctx->source_material))
if (!_cogl_material_get_real_blend_enabled (source))
{
CoglMaterialBlendEnable blend_enable =
COGL_MATERIAL_BLEND_ENABLE_ENABLED;
source = cogl_material_copy (ctx->source_material);
_cogl_material_set_blend_enabled (source, blend_enable);
copy = cogl_material_copy (source);
_cogl_material_set_blend_enabled (copy, blend_enable);
source = copy;
skip_gl_color = TRUE;
}
break;
@ -1745,9 +1747,12 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
if (G_UNLIKELY (options.flags))
{
/* If we haven't already created a derived material... */
if (source == ctx->source_material)
source = cogl_material_copy (ctx->source_material);
_cogl_material_apply_overrides (source, &options);
if (!copy)
{
copy = cogl_material_copy (source);
source = copy;
}
_cogl_material_apply_overrides (copy, &options);
/* TODO:
* overrides = cogl_material_get_data (material,
@ -1770,7 +1775,7 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
* {
* overrides = g_slice_new (Overrides);
* overrides->weak_material =
* cogl_material_weak_copy (ctx->source_material);
* cogl_material_weak_copy (source);
* _cogl_material_apply_overrides (overrides->weak_material,
* &options);
*
@ -1786,9 +1791,12 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
if (G_UNLIKELY (ctx->legacy_state_set))
{
/* If we haven't already created a derived material... */
if (source == ctx->source_material)
source = cogl_material_copy (ctx->source_material);
_cogl_material_apply_legacy_state (source);
if (!copy)
{
copy = cogl_material_copy (source);
source = copy;
}
_cogl_material_apply_legacy_state (copy);
}
_cogl_material_flush_gl_state (source, skip_gl_color);
@ -1804,7 +1812,7 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
static void
disable_state_for_drawing_buffer (CoglVertexBuffer *buffer,
CoglHandle source)
CoglMaterial *source)
{
GList *tmp;
GLenum gl_type;
@ -1814,8 +1822,8 @@ disable_state_for_drawing_buffer (CoglVertexBuffer *buffer,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (G_UNLIKELY (source != ctx->source_material))
cogl_handle_unref (source);
if (G_UNLIKELY (source != cogl_get_source ()))
cogl_object_unref (source);
/* Disable all the client state that cogl doesn't currently know
* about:

View File

@ -756,7 +756,7 @@ cogl_begin_gl (void)
* A user should instead call cogl_set_source_color4ub() before
* cogl_begin_gl() to simplify the state flushed.
*/
_cogl_material_flush_gl_state (ctx->source_material, FALSE);
_cogl_material_flush_gl_state (cogl_get_source (), FALSE);
if (ctx->enable_backface_culling)
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
@ -946,22 +946,113 @@ _cogl_driver_error_quark (void)
return g_quark_from_static_string ("cogl-driver-error-quark");
}
void
cogl_set_source (CoglHandle material_handle)
typedef struct _CoglSourceState
{
CoglMaterial *material;
int push_count;
} CoglSourceState;
static void
_push_source_real (CoglMaterial *material)
{
CoglSourceState *top = g_slice_new (CoglSourceState);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
g_return_if_fail (cogl_is_material (material_handle));
top->material = cogl_object_ref (material);
top->push_count = 1;
if (ctx->source_material == material_handle)
ctx->source_stack = g_list_prepend (ctx->source_stack, top);
}
/* FIXME: This should take a context pointer for Cogl 2.0 Technically
* we could make it so we can retrieve a context reference from the
* material, but this would not by symmetric with cogl_pop_source. */
void
cogl_push_source (CoglMaterial *material)
{
CoglSourceState *top;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
g_return_if_fail (cogl_is_material (material));
if (ctx->source_stack)
{
top = ctx->source_stack->data;
if (top->material == material)
{
top->push_count++;
return;
}
else
_push_source_real (material);
}
else
_push_source_real (material);
}
/* FIXME: This needs to take a context pointer for Cogl 2.0 */
void
cogl_pop_source (void)
{
CoglSourceState *top;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
g_return_if_fail (ctx->source_stack);
top = ctx->source_stack->data;
top->push_count--;
if (top->push_count == 0)
{
cogl_object_unref (top->material);
g_slice_free (CoglSourceState, top);
ctx->source_stack = g_list_delete_link (ctx->source_stack,
ctx->source_stack);
}
}
/* FIXME: This needs to take a context pointer for Cogl 2.0 */
CoglMaterial *
cogl_get_source (void)
{
CoglSourceState *top;
_COGL_GET_CONTEXT (ctx, NULL);
g_return_val_if_fail (ctx->source_stack, NULL);
top = ctx->source_stack->data;
return top->material;
}
void
cogl_set_source (CoglMaterial *material)
{
CoglSourceState *top;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
g_return_if_fail (cogl_is_material (material));
g_return_if_fail (ctx->source_stack);
top = ctx->source_stack->data;
if (top->material == material)
return;
cogl_handle_ref (material_handle);
if (ctx->source_material)
cogl_handle_unref (ctx->source_material);
ctx->source_material = material_handle;
if (top->push_count == 1)
{
/* NB: top->material may be only thing keeping material
* alive currently so ref material first... */
cogl_object_ref (material);
cogl_object_unref (top->material);
top->material = material;
}
else
{
top->push_count--;
cogl_push_source (material);
}
}
void

View File

@ -574,19 +574,61 @@ cogl_clear (const CoglColor *color,
/**
* cogl_set_source:
* @material: A #CoglHandle for a material
* @material: A #CoglMaterial
*
* This function sets the source material that will be used to fill subsequent
* geometry emitted via the cogl API.
*
* <note>In the future we may add the ability to set a front facing material,
* and a back facing material, in which case this function will set both to the
* same.</note>
* This function changes the material at the top of the source stack.
* The material at the top of this stack defines the GPU state used to
* process subsequent primitives, such as rectangles drawn with
* cogl_rectangle() or vertices drawn using cogl_vertex_buffer_draw().
*
* Since: 1.0
*/
void
cogl_set_source (CoglHandle material);
cogl_set_source (CoglMaterial *material);
/**
* cogl_get_source:
*
* Returns the current source material as previously set using
* cogl_set_source().
*
* <note>You should typically consider the returned material immutable
* and not try to change any of its properties unless you own a
* reference to that material. At times you may be able to get a
* reference to an internally managed materials and the result of
* modifying such materials is undefined.</note>
*
* Return value: The current source material.
*
* Since: 1.6
*/
CoglMaterial *
cogl_get_source (void);
/**
* cogl_push_source:
* @material: A #CoglMaterial
*
* Pushes the given @material to the top of the source stack. The
* material at the top of this stack defines the GPU state used to
* process later primitives as defined by cogl_set_source().
*
* Since: 1.6
*/
void
cogl_push_source (CoglMaterial *material);
/**
* cogl_pop_source:
*
* Removes the material at the top of the source stack. The material
* at the top of this stack defines the GPU state used to process
* later primitives as defined by cogl_set_source().
*
* Since: 1.6
*/
void
cogl_pop_source (void);
/**
* cogl_set_source_color:

View File

@ -61,6 +61,9 @@ cogl_set_source_color
cogl_set_source_color4ub
cogl_set_source_color4f
cogl_set_source_texture
cogl_get_source
cogl_push_source
cogl_pop_source
<SUBSECTION>
CoglReadPixelsFlags