From c5d909d0631dfeea5cd7f6beff900ed21762bf9d Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Tue, 2 Nov 2010 17:15:06 +0000 Subject: [PATCH] cogl: Don't flush the journal when flushing clip state Flushing the clip state no longer does anything that would cause the journal to flush. The clip state is only flushed when flushing the framebuffer state and in all cases this ends up flushing the journal in one way or another anyway. Avoiding flushing the journal will make it easier to log the clip state in the journal. Previously when trying to set up a rectangle clip that can't be scissored or when using a path clip the code would use cogl_rectangle as part of the process to fill the stencil buffer. This is now changed to use a new internal _cogl_rectangle_immediate function which directly uses the vertex array API to draw a triangle strip without affecting the journal. This should be just as efficient as the previous journalled code because these places would end up flushing the journal immediately before and after submitting the single rectangle anyway and flushing the journal always creates a new vbo so it would effectively do the same thing. Similarly there is also a new internal _cogl_clear function that does not flush the journal. --- clutter/cogl/cogl/Makefile.am | 2 + clutter/cogl/cogl/cogl-clip-stack.c | 47 ++++++------- clutter/cogl/cogl/cogl-clip-state.c | 5 ++ clutter/cogl/cogl/cogl-path.c | 76 ++++++++++----------- clutter/cogl/cogl/cogl-primitives-private.h | 43 ++++++++++++ clutter/cogl/cogl/cogl-primitives.c | 40 +++++++++++ clutter/cogl/cogl/cogl-private.h | 34 +++++++++ clutter/cogl/cogl/cogl.c | 30 +++++--- 8 files changed, 203 insertions(+), 74 deletions(-) create mode 100644 clutter/cogl/cogl/cogl-primitives-private.h create mode 100644 clutter/cogl/cogl/cogl-private.h diff --git a/clutter/cogl/cogl/Makefile.am b/clutter/cogl/cogl/Makefile.am index de85ae35a..8fceb8249 100644 --- a/clutter/cogl/cogl/Makefile.am +++ b/clutter/cogl/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/clutter/cogl/cogl/cogl-clip-stack.c b/clutter/cogl/cogl/cogl-clip-stack.c index ab117c9d9..22cdce3f7 100644 --- a/clutter/cogl/cogl/cogl-clip-stack.c +++ b/clutter/cogl/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/clutter/cogl/cogl/cogl-clip-state.c b/clutter/cogl/cogl/cogl-clip-state.c index 1b1033ce3..f7fd7d33f 100644 --- a/clutter/cogl/cogl/cogl-clip-state.c +++ b/clutter/cogl/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/clutter/cogl/cogl/cogl-path.c b/clutter/cogl/cogl/cogl-path.c index 154b698ef..0c8b1f349 100644 --- a/clutter/cogl/cogl/cogl-path.c +++ b/clutter/cogl/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/clutter/cogl/cogl/cogl-primitives-private.h b/clutter/cogl/cogl/cogl-primitives-private.h new file mode 100644 index 000000000..debd90c53 --- /dev/null +++ b/clutter/cogl/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/clutter/cogl/cogl/cogl-primitives.c b/clutter/cogl/cogl/cogl-primitives.c index 63bd8d474..c9cf1993a 100644 --- a/clutter/cogl/cogl/cogl-primitives.c +++ b/clutter/cogl/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/clutter/cogl/cogl/cogl-private.h b/clutter/cogl/cogl/cogl-private.h new file mode 100644 index 000000000..c2f6947ac --- /dev/null +++ b/clutter/cogl/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/clutter/cogl/cogl/cogl.c b/clutter/cogl/cogl/cogl.c index af3a3d57b..3e12c4d71 100644 --- a/clutter/cogl/cogl/cogl.c +++ b/clutter/cogl/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"); }