summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2019-02-05 10:11:37 -0200
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2019-10-16 16:25:08 +0200
commit0556138b9f731048f2c7c31c9e3a00d431ea7d9a (patch)
treea98e87cb1b1778fac9990a7e59eb571a11d7f999
parentd57dbe1d4c783234fc346d4e0e06944059e44bcf (diff)
downloadmutter-0556138b9f731048f2c7c31c9e3a00d431ea7d9a.tar.gz
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
-rw-r--r--cogl/cogl/cogl-framebuffer-private.h5
-rw-r--r--cogl/cogl/cogl-framebuffer.c25
-rw-r--r--cogl/cogl/cogl-journal-private.h1
-rw-r--r--cogl/cogl/cogl-journal.c72
4 files changed, 84 insertions, 19 deletions
diff --git a/cogl/cogl/cogl-framebuffer-private.h b/cogl/cogl/cogl-framebuffer-private.h
index eada73577..1f5b31e51 100644
--- a/cogl/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl/cogl-framebuffer-private.h
@@ -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,
diff --git a/cogl/cogl/cogl-framebuffer.c b/cogl/cogl/cogl-framebuffer.c
index fb46b569b..f4d131315 100644
--- a/cogl/cogl/cogl-framebuffer.c
+++ b/cogl/cogl/cogl-framebuffer.c
@@ -482,14 +482,29 @@ _cogl_framebuffer_set_clip_stack (CoglFramebuffer *framebuffer,
}
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,
float y,
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
diff --git a/cogl/cogl/cogl-journal-private.h b/cogl/cogl/cogl-journal-private.h
index 5d38877d4..4b83e3bf2 100644
--- a/cogl/cogl/cogl-journal-private.h
+++ b/cogl/cogl/cogl-journal-private.h
@@ -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;
diff --git a/cogl/cogl/cogl-journal.c b/cogl/cogl/cogl-journal.c
index 083f4a3d4..4f7cb0f05 100644
--- a/cogl/cogl/cogl-journal.c
+++ b/cogl/cogl/cogl-journal.c
@@ -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. */