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.
This commit is contained in:
Neil Roberts 2010-11-02 17:15:06 +00:00
parent db86a5a486
commit caa991d7a1
8 changed files with 203 additions and 74 deletions

View File

@ -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 \

View File

@ -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 ());

View File

@ -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);
}

View File

@ -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 <string.h>
@ -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);
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*
*
*/
#ifndef __COGL_PRIMITIVES_PRIVATE_H
#define __COGL_PRIMITIVES_PRIVATE_H
#include <glib.h>
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 */

View File

@ -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;

34
cogl/cogl-private.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*
*
*/
#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__ */

View File

@ -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");
}