cogl-journal: Log the clip state in the journal

When adding a new entry to the journal a reference is now taken on the
current clip stack. Modifying the current clip state no longer causes
a journal flush. The journal flushing code now has an extra stage to
compare the clip state of each entry. The comparison can simply be
done by comparing the pointers. Although different clip states will
still end up with multiple draw calls this at leasts allows a scene
comprising of multiple different clips to be upload with one vbo. It
also lays the groundwork to do certain tricks when drawing clipped
rectangles such as modifying the geometry instead of setting a clip
state.
This commit is contained in:
Neil Roberts 2010-11-02 17:35:17 +00:00
parent 6cf01ff0f4
commit 3c8c195115
3 changed files with 83 additions and 49 deletions

View File

@ -51,10 +51,6 @@ cogl_clip_push_window_rectangle (int x_offset,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* We don't log clip stack changes in the journal so we must flush
* it before making modifications */
_cogl_journal_flush ();
framebuffer = _cogl_get_framebuffer ();
clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
@ -136,10 +132,6 @@ cogl_clip_push_rectangle (float x_1,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* We don't log clip stack changes in the journal so we must flush
* it before making modifications */
_cogl_journal_flush ();
/* Try and catch window space rectangles so we can redirect to
* cogl_clip_push_window_rect which will use scissoring. */
if (try_pushing_rect_as_window_rect (x_1, y_1, x_2, y_2))
@ -178,10 +170,6 @@ cogl_clip_push_from_path_preserve (void)
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* We don't log clip stack changes in the journal so we must flush
* it before making modifications */
_cogl_journal_flush ();
framebuffer = _cogl_get_framebuffer ();
clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
@ -203,10 +191,6 @@ cogl_clip_push_from_path (void)
static void
_cogl_clip_pop_real (CoglClipState *clip_state)
{
/* We don't log clip stack changes in the journal so we must flush
* it before making modifications */
_cogl_journal_flush ();
clip_state->stacks->data = _cogl_clip_stack_pop (clip_state->stacks->data);
}
@ -250,10 +234,6 @@ cogl_clip_ensure (void)
static void
_cogl_clip_stack_save_real (CoglClipState *clip_state)
{
/* We don't log clip stack changes in the journal so we must flush
* it before making modifications */
_cogl_journal_flush ();
clip_state->stacks = g_slist_prepend (clip_state->stacks, NULL);
}
@ -278,10 +258,6 @@ _cogl_clip_stack_restore_real (CoglClipState *clip_state)
g_return_if_fail (clip_state->stacks != NULL);
/* We don't log clip stack changes in the journal so we must flush
* it before making modifications */
_cogl_journal_flush ();
stack = clip_state->stacks->data;
_cogl_clip_stack_unref (stack);

View File

@ -25,6 +25,7 @@
#define __COGL_JOURNAL_PRIVATE_H
#include "cogl-handle.h"
#include "cogl-clip-stack.h"
/* To improve batching of geometry when submitting vertices to OpenGL we
* log the texture rectangles we want to draw to a journal, so when we
@ -34,6 +35,7 @@ typedef struct _CoglJournalEntry
CoglPipeline *pipeline;
int n_layers;
CoglMatrix model_view;
CoglClipStack *clip_stack;
/* XXX: These entries are pretty big now considering the padding in
* CoglPipelineFlushOptions and CoglMatrix, so we might need to optimize this
* later. */

View File

@ -84,6 +84,7 @@ typedef struct _CoglJournalFlushState
gsize indices_type_size;
#endif
CoglMatrixStack *modelview_stack;
CoglMatrixStack *projection_stack;
CoglPipeline *source;
} CoglJournalFlushState;
@ -471,7 +472,7 @@ _cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
int i;
CoglVertexAttribute **attribute_entry;
COGL_STATIC_TIMER (time_flush_vbo_texcoord_pipeline_entries,
"Journal Flush", /* parent */
"flush: clip+vbo+texcoords+pipeline+entries", /* parent */
"flush: vbo+texcoords+pipeline+entries",
"The time spent flushing vbo + texcoord offsets + "
"pipeline + entries",
@ -580,6 +581,68 @@ compare_entry_strides (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
return FALSE;
}
/* At this point we know the batch has a unique clip stack */
static void
_cogl_journal_flush_clip_stacks_and_entries (CoglJournalEntry *batch_start,
int batch_len,
void *data)
{
CoglJournalFlushState *state = data;
COGL_STATIC_TIMER (time_flush_clip_stack_pipeline_entries,
"Journal Flush", /* parent */
"flush: clip+vbo+texcoords+pipeline+entries",
"The time spent flushing clip + vbo + texcoord offsets + "
"pipeline + entries",
0 /* no application private data */);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
COGL_TIMER_START (_cogl_uprof_context,
time_flush_clip_stack_pipeline_entries);
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
g_print ("BATCHING: clip stack batch len = %d\n", batch_len);
_cogl_clip_stack_flush (batch_start->clip_stack);
_cogl_matrix_stack_push (state->modelview_stack);
/* If we have transformed all our quads at log time then we ensure
* no further model transform is applied by loading the identity
* matrix here. We need to do this after flushing the clip stack
* because the clip stack flushing code can modify the matrix */
if (G_LIKELY (!(cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
{
_cogl_matrix_stack_load_identity (state->modelview_stack);
_cogl_matrix_stack_flush_to_gl (state->modelview_stack,
COGL_MATRIX_MODELVIEW);
}
/* Setting up the clip state can sometimes also flush the projection
matrix so we should flush it again. This will be a no-op if the
clip code didn't modify the projection */
_cogl_matrix_stack_flush_to_gl (state->projection_stack,
COGL_MATRIX_PROJECTION);
batch_and_call (batch_start,
batch_len,
compare_entry_strides,
_cogl_journal_flush_vbo_offsets_and_entries, /* callback */
data);
_cogl_matrix_stack_pop (state->modelview_stack);
COGL_TIMER_STOP (_cogl_uprof_context,
time_flush_clip_stack_pipeline_entries);
}
static gboolean
compare_entry_clip_stacks (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
{
return entry0->clip_stack == entry1->clip_stack;
}
static CoglVertexArray *
upload_vertices (GArray *vertices, CoglJournalFlushState *state)
{
@ -638,53 +701,43 @@ _cogl_journal_flush (void)
framebuffer = _cogl_get_framebuffer ();
modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer);
state.modelview_stack = modelview_stack;
_cogl_matrix_stack_push (modelview_stack);
/* If we have transformed all our quads at log time then we ensure no
* further model transform is applied by loading the identity matrix
* here... */
if (G_LIKELY (!(cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
{
_cogl_matrix_stack_load_identity (modelview_stack);
_cogl_matrix_stack_flush_to_gl (modelview_stack, COGL_MATRIX_MODELVIEW);
}
state.projection_stack = _cogl_framebuffer_get_projection_stack (framebuffer);
/* batch_and_call() batches a list of journal entries according to some
* given criteria and calls a callback once for each determined batch.
*
* The process of flushing the journal is staggered to reduce the amount
* of driver/GPU state changes necessary:
* 1) We split the entries according to the stride of the vertices:
* 1) We split the entries according to the clip state.
* 2) We split the entries according to the stride of the vertices:
* Each time the stride of our vertex data changes we need to call
* gl{Vertex,Color}Pointer to inform GL of new VBO offsets.
* Currently the only thing that affects the stride of our vertex data
* is the number of pipeline layers.
* 2) We split the entries explicitly by the number of pipeline layers:
* 3) We split the entries explicitly by the number of pipeline layers:
* We pad our vertex data when the number of layers is < 2 so that we
* can minimize changes in stride. Each time the number of layers
* changes we need to call glTexCoordPointer to inform GL of new VBO
* offsets.
* 3) We then split according to compatible Cogl pipelines:
* 4) We then split according to compatible Cogl pipelines:
* This is where we flush pipeline state
* 4) Finally we split according to modelview matrix changes:
* 5) Finally we split according to modelview matrix changes:
* This is when we finally tell GL to draw something.
* Note: Splitting by modelview changes is skipped when are doing the
* vertex transformation in software at log time.
*/
batch_and_call ((CoglJournalEntry *)ctx->journal->data, /* first entry */
ctx->journal->len, /* max number of entries to consider */
compare_entry_strides,
_cogl_journal_flush_vbo_offsets_and_entries, /* callback */
compare_entry_clip_stacks,
_cogl_journal_flush_clip_stacks_and_entries, /* callback */
&state); /* data */
_cogl_matrix_stack_pop (modelview_stack);
for (i = 0; i < ctx->journal->len; i++)
{
CoglJournalEntry *entry =
&g_array_index (ctx->journal, CoglJournalEntry, i);
_cogl_pipeline_journal_unref (entry->pipeline);
_cogl_clip_stack_unref (entry->clip_stack);
}
g_array_set_size (ctx->journal, 0);
@ -700,9 +753,11 @@ _cogl_journal_init (void)
* next the the journal is flushed. Note: This lets up flush things
* that themselves depend on the journal, such as clip state. */
/* NB: the journal deals with flushing the modelview stack manually */
/* NB: the journal deals with flushing the modelview stack and clip
state manually */
_cogl_framebuffer_flush_state (_cogl_get_framebuffer (),
COGL_FRAMEBUFFER_FLUSH_SKIP_MODELVIEW);
COGL_FRAMEBUFFER_FLUSH_SKIP_MODELVIEW |
COGL_FRAMEBUFFER_FLUSH_SKIP_CLIP_STATE);
}
void
@ -887,6 +942,7 @@ _cogl_journal_log_quad (const float *position,
}
entry->pipeline = _cogl_pipeline_journal_ref (source);
entry->clip_stack = _cogl_clip_stack_ref (_cogl_get_clip_stack ());
if (G_UNLIKELY (source != pipeline))
cogl_handle_unref (source);