diff --git a/cogl/Makefile.am b/cogl/Makefile.am index de85ae35a..8fceb8249 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -175,6 +175,7 @@ cogl_sources_c = \ $(cogl_driver_sources) \ $(cogl_winsys_common_sources) \ $(cogl_tesselator_sources) \ + $(srcdir)/cogl-private.h \ $(srcdir)/cogl-debug.h \ $(srcdir)/cogl-debug-options.h \ $(srcdir)/cogl-handle.h \ @@ -190,6 +191,7 @@ cogl_sources_c = \ $(srcdir)/cogl-bitmap-private.h \ $(srcdir)/cogl-bitmap.c \ $(srcdir)/cogl-bitmap-fallback.c \ + $(srcdir)/cogl-primitives-private.h \ $(srcdir)/cogl-primitives.h \ $(srcdir)/cogl-primitives.c \ $(srcdir)/cogl-path-private.h \ diff --git a/cogl/cogl-clip-stack.c b/cogl/cogl-clip-stack.c index ab117c9d9..22cdce3f7 100644 --- a/cogl/cogl-clip-stack.c +++ b/cogl/cogl-clip-stack.c @@ -40,6 +40,7 @@ #include "cogl-util.h" #include "cogl-path-private.h" #include "cogl-matrix-private.h" +#include "cogl-primitives-private.h" typedef struct _CoglClipStackRect CoglClipStackRect; typedef struct _CoglClipStackWindowRect CoglClipStackWindowRect; @@ -283,15 +284,13 @@ add_stencil_clip_rectangle (float x_1, gboolean first) { CoglFramebuffer *framebuffer = _cogl_get_framebuffer (); + CoglMatrixStack *modelview_stack = + _cogl_framebuffer_get_modelview_stack (framebuffer); + CoglMatrixStack *projection_stack = + _cogl_framebuffer_get_projection_stack (framebuffer); _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* We don't log changes to the stencil buffer so need to flush any - * batched geometry before we start... */ - _cogl_journal_flush (); - - _cogl_framebuffer_flush_state (framebuffer, 0); - /* temporarily swap in our special stenciling pipeline */ cogl_push_source (ctx->stencil_pipeline); @@ -307,24 +306,23 @@ add_stencil_clip_rectangle (float x_1, GE( glStencilFunc (GL_NEVER, 0x1, 0x1) ); GE( glStencilOp (GL_REPLACE, GL_REPLACE, GL_REPLACE) ); - cogl_rectangle (x_1, y_1, x_2, y_2); + /* This can be called from the journal code which doesn't flush + the matrix stacks between calls so we need to ensure they're + flushed now */ + _cogl_matrix_stack_flush_to_gl (modelview_stack, + COGL_MATRIX_MODELVIEW); + _cogl_matrix_stack_flush_to_gl (projection_stack, + COGL_MATRIX_PROJECTION); + + _cogl_rectangle_immediate (x_1, y_1, x_2, y_2); } else { - CoglMatrixStack *modelview_stack = - _cogl_framebuffer_get_modelview_stack (framebuffer); - CoglMatrixStack *projection_stack = - _cogl_framebuffer_get_projection_stack (framebuffer); - /* Add one to every pixel of the stencil buffer in the rectangle */ GE( glStencilFunc (GL_NEVER, 0x1, 0x3) ); GE( glStencilOp (GL_INCR, GL_INCR, GL_INCR) ); - cogl_rectangle (x_1, y_1, x_2, y_2); - - /* make sure our rectangle hits the stencil buffer before we - * change the stencil operation */ - _cogl_journal_flush (); + _cogl_rectangle_immediate (x_1, y_1, x_2, y_2); /* Subtract one from all pixels in the stencil buffer so that only pixels where both the original stencil buffer and the @@ -337,16 +335,17 @@ add_stencil_clip_rectangle (float x_1, _cogl_matrix_stack_push (modelview_stack); _cogl_matrix_stack_load_identity (modelview_stack); - cogl_rectangle (-1.0, -1.0, 1.0, 1.0); + _cogl_matrix_stack_flush_to_gl (modelview_stack, + COGL_MATRIX_MODELVIEW); + _cogl_matrix_stack_flush_to_gl (projection_stack, + COGL_MATRIX_PROJECTION); + + _cogl_rectangle_immediate (-1.0, -1.0, 1.0, 1.0); _cogl_matrix_stack_pop (modelview_stack); _cogl_matrix_stack_pop (projection_stack); } - /* make sure our rectangles hit the stencil buffer before we restore - * the stencil function / operation */ - _cogl_journal_flush (); - /* Restore the stencil mode */ GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) ); GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) ); @@ -610,10 +609,6 @@ _cogl_clip_stack_flush (CoglClipStack *stack) ctx->current_clip_stack_valid = TRUE; ctx->current_clip_stack = _cogl_clip_stack_ref (stack); - /* The current primitive journal does not support tracking changes to the - * clip stack... */ - _cogl_journal_flush (); - modelview_stack = _cogl_framebuffer_get_modelview_stack (_cogl_get_framebuffer ()); diff --git a/cogl/cogl-clip-state.c b/cogl/cogl-clip-state.c index 1b1033ce3..f7fd7d33f 100644 --- a/cogl/cogl-clip-state.c +++ b/cogl/cogl-clip-state.c @@ -239,6 +239,11 @@ cogl_clip_ensure (void) CoglClipState *clip_state; clip_state = _cogl_framebuffer_get_clip_state (_cogl_get_framebuffer ()); + /* Flushing the clip state doesn't cause the journal to be + flushed. This function may be being called by an external + application however so it makes sense to flush the journal + here */ + _cogl_journal_flush (); _cogl_clip_state_flush (clip_state); } diff --git a/cogl/cogl-path.c b/cogl/cogl-path.c index 154b698ef..0c8b1f349 100644 --- a/cogl/cogl-path.c +++ b/cogl/cogl-path.c @@ -35,6 +35,10 @@ #include "cogl-framebuffer-private.h" #include "cogl-path-private.h" #include "cogl-texture-private.h" +#include "cogl-primitives-private.h" +#include "cogl-path.h" +#include "cogl-private.h" +#include "cogl-vertex-attribute-private.h" #include "tesselator/tesselator.h" #include @@ -276,18 +280,16 @@ _cogl_path_fill_nodes_with_stencil_buffer (CoglPath *path) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_journal_flush (); - g_assert (ctx->current_clip_stack_valid); _cogl_add_path_to_stencil_buffer (path, ctx->current_clip_stack_uses_stencil, FALSE); - cogl_rectangle (path->data->path_nodes_min.x, - path->data->path_nodes_min.y, - path->data->path_nodes_max.x, - path->data->path_nodes_max.y); + _cogl_rectangle_immediate (path->data->path_nodes_min.x, + path->data->path_nodes_min.y, + path->data->path_nodes_max.x, + path->data->path_nodes_max.y); /* The stencil buffer now contains garbage so the clip area needs to * be rebuilt. @@ -297,7 +299,6 @@ _cogl_path_fill_nodes_with_stencil_buffer (CoglPath *path) * only called when the journal first gets something logged in it; so * we call cogl_flush() to emtpy the journal. */ - cogl_flush (); _cogl_clip_stack_dirty (); } @@ -342,11 +343,11 @@ _cogl_path_fill_nodes (CoglPath *path) _cogl_path_build_vbo (path); - cogl_draw_indexed_vertex_attributes_array (COGL_VERTICES_MODE_TRIANGLES, - 0, /* first_vertex */ - path->data->vbo_n_indices, - path->data->vbo_indices, - path->data->vbo_attributes); + _cogl_draw_indexed_vertex_attributes_array (COGL_VERTICES_MODE_TRIANGLES, + 0, /* first_vertex */ + path->data->vbo_n_indices, + path->data->vbo_indices, + path->data->vbo_attributes); } void @@ -364,14 +365,13 @@ _cogl_add_path_to_stencil_buffer (CoglPath *path, _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* We don't track changes to the stencil buffer in the journal - * so we need to flush any batched geometry first */ - _cogl_journal_flush (); - - /* NB: _cogl_framebuffer_flush_state may disrupt various state (such - * as the pipeline state) when flushing the clip stack, so should - * always be done first when preparing to draw. */ - _cogl_framebuffer_flush_state (framebuffer, 0); + /* This can be called from the clip stack code which doesn't flush + the matrix stacks between calls so we need to ensure they're + flushed now */ + _cogl_matrix_stack_flush_to_gl (modelview_stack, + COGL_MATRIX_MODELVIEW); + _cogl_matrix_stack_flush_to_gl (projection_stack, + COGL_MATRIX_PROJECTION); /* Just setup a simple pipeline that doesn't use texturing... */ cogl_push_source (ctx->stencil_pipeline); @@ -399,24 +399,20 @@ _cogl_add_path_to_stencil_buffer (CoglPath *path, /* If this is being called from the clip stack code then it will have set up a scissor for the minimum bounding box of all of the clips. That box will likely mean that this - cogl_clear won't need to clear the entire buffer */ - cogl_clear (NULL, COGL_BUFFER_BIT_STENCIL); + _cogl_clear won't need to clear the entire + buffer. _cogl_clear is used instead of cogl_clear because + it won't try to flush the journal */ + _cogl_clear (NULL, COGL_BUFFER_BIT_STENCIL); else { /* Just clear the bounding box */ GE( glStencilMask (~(GLuint) 0) ); GE( glStencilOp (GL_ZERO, GL_ZERO, GL_ZERO) ); - cogl_rectangle (data->path_nodes_min.x, - data->path_nodes_min.y, - data->path_nodes_max.x, - data->path_nodes_max.y); - /* Make sure the rectangle hits the stencil buffer before - * directly changing other GL state. */ - _cogl_journal_flush (); - /* NB: The journal flushing may trash the modelview state and - * enable flags */ - _cogl_matrix_stack_flush_to_gl (modelview_stack, - COGL_MATRIX_MODELVIEW); + _cogl_rectangle_immediate (data->path_nodes_min.x, + data->path_nodes_min.y, + data->path_nodes_max.x, + data->path_nodes_max.y); + /* NB: The rectangle may trash the enable flags */ _cogl_enable (enable_flags); } GE (glStencilMask (1)); @@ -448,11 +444,8 @@ _cogl_add_path_to_stencil_buffer (CoglPath *path, _cogl_matrix_stack_flush_to_gl (modelview_stack, COGL_MATRIX_MODELVIEW); - cogl_rectangle (-1.0, -1.0, 1.0, 1.0); - cogl_rectangle (-1.0, -1.0, 1.0, 1.0); - /* Make sure these rectangles hit the stencil buffer before we - * restore the stencil op/func. */ - _cogl_journal_flush (); + _cogl_rectangle_immediate (-1.0, -1.0, 1.0, 1.0); + _cogl_rectangle_immediate (-1.0, -1.0, 1.0, 1.0); _cogl_matrix_stack_pop (modelview_stack); _cogl_matrix_stack_pop (projection_stack); @@ -489,6 +482,13 @@ cogl_path_fill_preserve (void) if (path->data->path_nodes->len == 0) return; + _cogl_journal_flush (); + + /* NB: _cogl_framebuffer_flush_state may disrupt various state (such + * as the pipeline state) when flushing the clip stack, so should + * always be done first when preparing to draw. */ + _cogl_framebuffer_flush_state (_cogl_get_framebuffer (), 0); + _cogl_path_fill_nodes (path); } diff --git a/cogl/cogl-primitives-private.h b/cogl/cogl-primitives-private.h new file mode 100644 index 000000000..debd90c53 --- /dev/null +++ b/cogl/cogl-primitives-private.h @@ -0,0 +1,43 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * + */ + +#ifndef __COGL_PRIMITIVES_PRIVATE_H +#define __COGL_PRIMITIVES_PRIVATE_H + +#include + +G_BEGIN_DECLS + +/* Draws a rectangle without going through the journal so that it will + be flushed immediately. This should only be used in situations + where the code may be called while the journal is already being + flushed. In that case using the journal would go wrong */ +void +_cogl_rectangle_immediate (float x_1, + float y_1, + float x_2, + float y_2); + +G_END_DECLS + +#endif /* __COGL_PRIMITIVES_PRIVATE_H */ diff --git a/cogl/cogl-primitives.c b/cogl/cogl-primitives.c index 63bd8d474..c9cf1993a 100644 --- a/cogl/cogl-primitives.c +++ b/cogl/cogl-primitives.c @@ -819,6 +819,46 @@ cogl_rectangle (float x_1, _cogl_rectangles_with_multitexture_coords (&rect, 1); } +void +_cogl_rectangle_immediate (float x_1, + float y_1, + float x_2, + float y_2) +{ + /* Draw a rectangle using the vertex array API to avoid going + through the journal. This should only be used in cases where the + code might be called while the journal is already being flushed + such as when flushing the clip state */ + float vertices[8] = + { + x_1, y_1, + x_1, y_2, + x_2, y_1, + x_2, y_2 + }; + CoglVertexArray *vertex_array; + CoglVertexAttribute *attributes[2]; + + vertex_array = cogl_vertex_array_new (sizeof (vertices)); + cogl_buffer_set_data (COGL_BUFFER (vertex_array), 0, + (guint8 *) vertices, sizeof (vertices)); + attributes[0] = cogl_vertex_attribute_new (vertex_array, + "cogl_position_in", + sizeof (float) * 2, /* stride */ + 0, /* offset */ + 2, /* n_components */ + COGL_VERTEX_ATTRIBUTE_TYPE_FLOAT); + attributes[1] = NULL; + + _cogl_draw_vertex_attributes_array (COGL_VERTICES_MODE_TRIANGLE_STRIP, + 0, /* first_index */ + 4, /* n_vertices */ + attributes); + + cogl_object_unref (attributes[0]); + cogl_object_unref (vertex_array); +} + typedef struct _AppendTexCoordsState { const CoglTextureVertex *vertices_in; diff --git a/cogl/cogl-private.h b/cogl/cogl-private.h new file mode 100644 index 000000000..c2f6947ac --- /dev/null +++ b/cogl/cogl-private.h @@ -0,0 +1,34 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2010 Intel Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * + */ + +#ifndef __COGL_PRIVATE_H__ +#define __COGL_PRIVATE_H__ + +G_BEGIN_DECLS + +void +_cogl_clear (const CoglColor *color, unsigned long buffers); + +G_END_DECLS + +#endif /* __COGL_PRIVATE_H__ */ diff --git a/cogl/cogl.c b/cogl/cogl.c index af3a3d57b..3e12c4d71 100644 --- a/cogl/cogl.c +++ b/cogl/cogl.c @@ -148,20 +148,15 @@ cogl_check_extension (const char *name, const char *ext) return _cogl_check_extension (name, ext); } +/* This version of cogl_clear can be used internally as an alternative + to avoid flushing the journal or the framebuffer state. This is + needed when doing operations that may be called whiling flushing + the journal */ void -cogl_clear (const CoglColor *color, unsigned long buffers) +_cogl_clear (const CoglColor *color, unsigned long buffers) { GLbitfield gl_buffers = 0; - COGL_NOTE (DRAW, "Clear begin"); - - _cogl_journal_flush (); - - /* NB: _cogl_framebuffer_flush_state may disrupt various state (such - * as the pipeline state) when flushing the clip stack, so should - * always be done first when preparing to draw. */ - _cogl_framebuffer_flush_state (_cogl_get_framebuffer (), 0); - if (buffers & COGL_BUFFER_BIT_COLOR) { GE( glClearColor (cogl_color_get_red_float (color), @@ -201,6 +196,21 @@ cogl_clear (const CoglColor *color, unsigned long buffers) _COGL_GET_CONTEXT (ctxt, NO_RETVAL); ctxt->journal_rectangles_color = 1; } +} + +void +cogl_clear (const CoglColor *color, unsigned long buffers) +{ + COGL_NOTE (DRAW, "Clear begin"); + + _cogl_journal_flush (); + + /* NB: _cogl_framebuffer_flush_state may disrupt various state (such + * as the pipeline state) when flushing the clip stack, so should + * always be done first when preparing to draw. */ + _cogl_framebuffer_flush_state (_cogl_get_framebuffer (), 0); + + _cogl_clear (color, buffers);; COGL_NOTE (DRAW, "Clear end"); }