From 3c8c1951151f16bedc7e298e2f0a8af536643617 Mon Sep 17 00:00:00 2001 From: Neil Roberts Date: Tue, 2 Nov 2010 17:35:17 +0000 Subject: [PATCH] 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. --- cogl/cogl-clip-state.c | 24 -------- cogl/cogl-journal-private.h | 2 + cogl/cogl-journal.c | 106 +++++++++++++++++++++++++++--------- 3 files changed, 83 insertions(+), 49 deletions(-) diff --git a/cogl/cogl-clip-state.c b/cogl/cogl-clip-state.c index f7fd7d33f..e261405ad 100644 --- a/cogl/cogl-clip-state.c +++ b/cogl/cogl-clip-state.c @@ -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); diff --git a/cogl/cogl-journal-private.h b/cogl/cogl-journal-private.h index a38fa801f..977866eb0 100644 --- a/cogl/cogl-journal-private.h +++ b/cogl/cogl-journal-private.h @@ -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. */ diff --git a/cogl/cogl-journal.c b/cogl/cogl-journal.c index e320ebf56..cb1e2e249 100644 --- a/cogl/cogl-journal.c +++ b/cogl/cogl-journal.c @@ -84,6 +84,7 @@ typedef struct _CoglJournalFlushState gsize indices_type_size; #endif CoglMatrixStack *modelview_stack; + CoglMatrixStack *projection_stack; CoglPipeline *source; } CoglJournalFlushState; @@ -194,7 +195,7 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start, COGL_TIMER_START (_cogl_uprof_context, time_flush_modelview_and_entries); if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING)) - g_print ("BATCHING: modelview batch len = %d\n", batch_len); + g_print ("BATCHING: modelview batch len = %d\n", batch_len); if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)) { @@ -331,7 +332,7 @@ _cogl_journal_flush_pipeline_and_entries (CoglJournalEntry *batch_start, COGL_TIMER_START (_cogl_uprof_context, time_flush_pipeline_entries); if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING)) - g_print ("BATCHING: pipeline batch len = %d\n", batch_len); + g_print ("BATCHING: pipeline batch len = %d\n", batch_len); state->source = batch_start->pipeline; @@ -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", @@ -483,7 +484,7 @@ _cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start, time_flush_vbo_texcoord_pipeline_entries); if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING)) - g_print ("BATCHING: vbo offset batch len = %d\n", batch_len); + g_print ("BATCHING: vbo offset batch len = %d\n", batch_len); /* XXX NB: * Our journal's vertex data is arranged as follows: @@ -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);