[mutter/gbsneto/software-picking: 39/41] cogl/journal: Track viewport



commit c418ba8e0160fb57f96b8e351d638cc46bfbe7f3
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Tue Feb 5 10:11:37 2019 -0200

    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

 cogl/cogl/cogl-framebuffer-private.h |  5 +++
 cogl/cogl/cogl-framebuffer.c         | 30 +++++++++-------
 cogl/cogl/cogl-journal-private.h     |  1 +
 cogl/cogl/cogl-journal.c             | 69 ++++++++++++++++++++++++++++++------
 4 files changed, 81 insertions(+), 24 deletions(-)
---
diff --git a/cogl/cogl/cogl-framebuffer-private.h b/cogl/cogl/cogl-framebuffer-private.h
index 46a1d146d..8deb59e00 100644
--- a/cogl/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl/cogl-framebuffer-private.h
@@ -472,6 +472,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 40904df14..cfb0e1a06 100644
--- a/cogl/cogl/cogl-framebuffer.c
+++ b/cogl/cogl/cogl-framebuffer.c
@@ -523,6 +523,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,
@@ -530,8 +547,6 @@ cogl_framebuffer_set_viewport (CoglFramebuffer *framebuffer,
                                float width,
                                float height)
 {
-  CoglContext *context = framebuffer->context;
-
   _COGL_RETURN_IF_FAIL (width > 0 && height > 0);
 
   if (framebuffer->viewport_x == x &&
@@ -540,21 +555,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;
-
-      if (context->needs_viewport_scissor_workaround)
-        context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP;
-    }
 }
 
 float
diff --git a/cogl/cogl/cogl-journal-private.h b/cogl/cogl/cogl-journal-private.h
index 8211359fa..b24b5df3e 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 34d9bbbaf..0a21f4bb7 100644
--- a/cogl/cogl/cogl-journal.c
+++ b/cogl/cogl/cogl-journal.c
@@ -1044,6 +1044,52 @@ 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;
+
+  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;
+  if (ctx->needs_viewport_scissor_workaround)
+    ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP;
+
+  _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);
+
+  COGL_TIMER_STOP (_cogl_uprof_context, time_flush_viewport_and_entries);
+}
+
+static CoglBool
+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 +1377,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 +1442,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 +1600,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 +1631,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 +1680,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. */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]