cogl/journal: Track viewport

CoglJournal tracks a few OpenGL states so that they can
be batch-applied if necessary. It also has a nice property
of allowing purely CPU-based glReadPixels() when the scene
is composed of simple rectangles.

However, the current journal implementation leaves various
other GL states out, such as dithering and the viewport.
In Clutter, that causes the journal to be flushed when
picking, touching the GPU when we didn't really need to.

Track the viewport of the framebuffer in the journal so that
we can avoid flushing the journal so often.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/402
This commit is contained in:
Georges Basile Stavracas Neto 2019-02-05 10:11:37 -02:00
parent d57dbe1d4c
commit 0556138b9f
4 changed files with 84 additions and 19 deletions

View File

@ -414,6 +414,11 @@ _cogl_framebuffer_try_creating_gl_fbo (CoglContext *ctx,
CoglOffscreenAllocateFlags flags,
CoglGLFramebuffer *gl_framebuffer);
void
cogl_framebuffer_set_viewport4fv (CoglFramebuffer *framebuffer,
float *viewport);
unsigned long
_cogl_framebuffer_compare (CoglFramebuffer *a,
CoglFramebuffer *b,

View File

@ -481,6 +481,23 @@ _cogl_framebuffer_set_clip_stack (CoglFramebuffer *framebuffer,
framebuffer->clip_stack = stack;
}
void
cogl_framebuffer_set_viewport4fv (CoglFramebuffer *framebuffer,
float *viewport)
{
if (framebuffer->viewport_x == viewport[0] &&
framebuffer->viewport_y == viewport[1] &&
framebuffer->viewport_width == viewport[2] &&
framebuffer->viewport_height == viewport[3])
return;
framebuffer->viewport_x = viewport[0];
framebuffer->viewport_y = viewport[1];
framebuffer->viewport_width = viewport[2];
framebuffer->viewport_height = viewport[3];
framebuffer->viewport_age++;
}
void
cogl_framebuffer_set_viewport (CoglFramebuffer *framebuffer,
float x,
@ -488,8 +505,6 @@ cogl_framebuffer_set_viewport (CoglFramebuffer *framebuffer,
float width,
float height)
{
CoglContext *context = framebuffer->context;
g_return_if_fail (width > 0 && height > 0);
if (framebuffer->viewport_x == x &&
@ -498,16 +513,10 @@ cogl_framebuffer_set_viewport (CoglFramebuffer *framebuffer,
framebuffer->viewport_height == height)
return;
_cogl_framebuffer_flush_journal (framebuffer);
framebuffer->viewport_x = x;
framebuffer->viewport_y = y;
framebuffer->viewport_width = width;
framebuffer->viewport_height = height;
framebuffer->viewport_age++;
if (context->current_draw_buffer == framebuffer)
context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_VIEWPORT;
}
float

View File

@ -78,6 +78,7 @@ typedef struct _CoglJournalEntry
CoglPipeline *pipeline;
CoglMatrixEntry *modelview_entry;
CoglClipStack *clip_stack;
float viewport[4];
/* Offset into ctx->logged_vertices */
size_t array_offset;
int n_layers;

View File

@ -1044,6 +1044,55 @@ compare_entry_clip_stacks (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
return entry0->clip_stack == entry1->clip_stack;
}
static void
_cogl_journal_flush_viewport_and_entries (CoglJournalEntry *batch_start,
int batch_len,
void *data)
{
CoglJournalFlushState *state = data;
CoglFramebuffer *framebuffer = state->journal->framebuffer;
CoglContext *ctx = framebuffer->context;
float current_viewport[4];
COGL_STATIC_TIMER (time_flush_viewport_and_entries,
"Journal Flush", /* parent */
"flush: viewport+clip+vbo+texcoords+pipeline+entries",
"The time spent flushing viewport + clip + vbo + texcoord offsets + "
"pipeline + entries",
0 /* no application private data */);
COGL_TIMER_START (_cogl_uprof_context, time_flush_viewport_and_entries);
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING)))
g_print ("BATCHING: viewport batch len = %d\n", batch_len);
ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_VIEWPORT;
cogl_framebuffer_get_viewport4fv (framebuffer, current_viewport);
cogl_framebuffer_set_viewport4fv (framebuffer, batch_start->viewport);
_cogl_framebuffer_flush_state (framebuffer,
framebuffer,
COGL_FRAMEBUFFER_STATE_VIEWPORT);
batch_and_call (batch_start,
batch_len,
compare_entry_clip_stacks,
_cogl_journal_flush_clip_stacks_and_entries,
state);
if (memcmp (batch_start->viewport, current_viewport, sizeof (float) * 4) != 0)
cogl_framebuffer_set_viewport4fv (framebuffer, current_viewport);
COGL_TIMER_STOP (_cogl_uprof_context, time_flush_viewport_and_entries);
}
static gboolean
compare_entry_viewports (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
{
return memcmp (entry0->viewport, entry1->viewport, sizeof (float) * 4) == 0;
}
/* Gets a new vertex array from the pool. A reference is taken on the
array so it can be treated as if it was just newly allocated */
static CoglAttributeBuffer *
@ -1331,12 +1380,13 @@ _cogl_journal_flush (CoglJournal *journal)
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING)))
g_print ("BATCHING: journal len = %d\n", journal->entries->len);
/* NB: the journal deals with flushing the modelview stack and clip
state manually */
/* NB: the journal deals with flushing the viewport, the modelview
* stack and clip state manually */
_cogl_framebuffer_flush_state (framebuffer,
framebuffer,
COGL_FRAMEBUFFER_STATE_ALL &
~(COGL_FRAMEBUFFER_STATE_MODELVIEW |
~(COGL_FRAMEBUFFER_STATE_VIEWPORT |
COGL_FRAMEBUFFER_STATE_MODELVIEW |
COGL_FRAMEBUFFER_STATE_CLIP));
/* We need to mark the current modelview state of the framebuffer as
@ -1395,11 +1445,11 @@ _cogl_journal_flush (CoglJournal *journal)
* Note: Splitting by modelview changes is skipped when are doing the
* vertex transformation in software at log time.
*/
batch_and_call ((CoglJournalEntry *)journal->entries->data, /* first entry */
journal->entries->len, /* max number of entries to consider */
compare_entry_clip_stacks,
_cogl_journal_flush_clip_stacks_and_entries, /* callback */
&state); /* data */
batch_and_call ((CoglJournalEntry *)journal->entries->data,
journal->entries->len,
compare_entry_viewports,
_cogl_journal_flush_viewport_and_entries,
&state);
for (i = 0; i < state.attributes->len; i++)
cogl_object_unref (g_array_index (state.attributes, CoglAttribute *, i));
@ -1553,6 +1603,8 @@ _cogl_journal_log_quad (CoglJournal *journal,
clip_stack = _cogl_framebuffer_get_clip_stack (framebuffer);
entry->clip_stack = _cogl_clip_stack_ref (clip_stack);
cogl_framebuffer_get_viewport4fv (framebuffer, entry->viewport);
if (G_UNLIKELY (final_pipeline != pipeline))
cogl_object_unref (final_pipeline);
@ -1582,7 +1634,7 @@ entry_to_screen_polygon (CoglFramebuffer *framebuffer,
CoglMatrix projection;
CoglMatrix modelview;
int i;
float viewport[4];
const float *viewport = entry->viewport;
poly[0] = vertices[0];
poly[1] = vertices[1];
@ -1631,8 +1683,6 @@ entry_to_screen_polygon (CoglFramebuffer *framebuffer,
poly, /* points_out */
4 /* n_points */);
cogl_framebuffer_get_viewport4fv (framebuffer, viewport);
/* Scale from OpenGL normalized device coordinates (ranging from -1 to 1)
* to Cogl window/framebuffer coordinates (ranging from 0 to buffer-size) with
* (0,0) being top left. */