[cogl/wip/virtual-framebuffer: 19/37] framebuffer: Optimize _cogl_framebuffer_flush_state()



commit be2a957d861f5e42942a917442a59fdb679575de
Author: Robert Bragg <robert linux intel com>
Date:   Mon Nov 21 15:53:40 2011 +0000

    framebuffer: Optimize _cogl_framebuffer_flush_state()
    
    Previously the cost of _cogl_framebuffer_state_flush() would always
    scale by the total amount of state that is tracked by CoglFramebuffer
    even in cases where we knew up-front that we only want to flush
    a subset of the state or in cases where we request to flush the same
    framebuffer multiple times with no changes being made to the
    framebuffer.
    
    We now track a set of state changed flags with each framebuffer and
    track the current read/draw buffers as part of the CoglContext so that
    we can quickly bail out when asked to flush the same framebuffer
    multiple times with no changes.
    
    _cogl_framebuffer_flush_state() now takes a mask of the state that we
    want to flush and the implementation has been redesigned so that the
    cost of checking what needs to be flushed and flushing those changes
    scales by the number of state bits we are requested to flush.

 cogl/cogl-attribute.c           |    2 +-
 cogl/cogl-context-private.h     |    8 +-
 cogl/cogl-context.c             |    7 +-
 cogl/cogl-framebuffer-private.h |   29 +++
 cogl/cogl-framebuffer.c         |  423 ++++++++++++++++++++++++++++++++-------
 cogl/cogl-journal.c             |   11 +-
 cogl/cogl-texture-2d.c          |    3 +-
 cogl/cogl.c                     |    4 +-
 cogl/winsys/cogl-winsys-glx.c   |    4 +-
 9 files changed, 404 insertions(+), 87 deletions(-)
---
diff --git a/cogl/cogl-attribute.c b/cogl/cogl-attribute.c
index 853d989..ad525f6 100644
--- a/cogl/cogl-attribute.c
+++ b/cogl/cogl-attribute.c
@@ -1101,7 +1101,7 @@ flush_state (CoglDrawFlags flags,
   if (!(flags & COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH))
     _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (),
                                    _cogl_get_read_framebuffer (),
-                                   0);
+                                   COGL_FRAMEBUFFER_STATE_ALL);
 }
 
 /* This can be called directly by the CoglJournal to draw attributes
diff --git a/cogl/cogl-context-private.h b/cogl/cogl-context-private.h
index f0d1655..8137a9f 100644
--- a/cogl/cogl-context-private.h
+++ b/cogl/cogl-context-private.h
@@ -155,9 +155,11 @@ struct _CoglContext
 
   /* Framebuffers */
   GSList           *framebuffer_stack;
-  CoglHandle        window_buffer;
-  gboolean          dirty_bound_framebuffer;
-  gboolean          dirty_gl_viewport;
+  CoglFramebuffer  *window_buffer;
+  unsigned long     current_draw_buffer_state_flushed;
+  unsigned long     current_draw_buffer_changes;
+  CoglFramebuffer  *current_draw_buffer;
+  CoglFramebuffer  *current_read_buffer;
 
   /* Primitives */
   CoglPath         *current_path;
diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c
index 62a0483..f474538 100644
--- a/cogl/cogl-context.c
+++ b/cogl/cogl-context.c
@@ -269,6 +269,10 @@ cogl_context_new (CoglDisplay *display,
   context->default_gl_texture_rect_tex = NULL;
 
   context->framebuffers = NULL;
+  context->current_draw_buffer = NULL;
+  context->current_read_buffer = NULL;
+  context->current_draw_buffer_state_flushed = 0;
+  context->current_draw_buffer_changes = COGL_FRAMEBUFFER_STATE_ALL;
 
   context->journal_flush_attributes_array =
     g_array_new (TRUE, FALSE, sizeof (CoglAttribute *));
@@ -327,9 +331,6 @@ cogl_context_new (CoglDisplay *display,
       cogl_object_unref (COGL_FRAMEBUFFER (window));
     }
 
-  context->dirty_bound_framebuffer = TRUE;
-  context->dirty_gl_viewport = TRUE;
-
   context->current_path = cogl2_path_new ();
   context->stencil_pipeline = cogl_pipeline_new ();
 
diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h
index 041d3d1..232edca 100644
--- a/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl-framebuffer-private.h
@@ -57,6 +57,35 @@ typedef enum
   COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL = 1
 } CoglOffscreenFlags;
 
+/* XXX: The order of these indices determines the order they are
+ * flushed.
+ *
+ * Flushing clip state may trash the modelview and projection matrices
+ * so we must do it before flushing the matrices.
+ */
+typedef enum _CoglFramebufferStateIndex
+{
+  COGL_FRAMEBUFFER_STATE_INDEX_BIND       = 0,
+  COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT   = 1,
+  COGL_FRAMEBUFFER_STATE_INDEX_CLIP       = 2,
+  COGL_FRAMEBUFFER_STATE_INDEX_DITHER     = 3,
+  COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW  = 4,
+  COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION = 5,
+  COGL_FRAMEBUFFER_STATE_INDEX_MAX        = 6
+} CoglFramebufferStateIndex;
+
+typedef enum _CoglFramebufferState
+{
+  COGL_FRAMEBUFFER_STATE_BIND       = 1<<0,
+  COGL_FRAMEBUFFER_STATE_VIEWPORT   = 1<<1,
+  COGL_FRAMEBUFFER_STATE_CLIP       = 1<<2,
+  COGL_FRAMEBUFFER_STATE_DITHER     = 1<<3,
+  COGL_FRAMEBUFFER_STATE_MODELVIEW  = 1<<4,
+  COGL_FRAMEBUFFER_STATE_PROJECTION = 1<<5
+} CoglFramebufferState;
+
+#define COGL_FRAMEBUFFER_STATE_ALL ((1<<COGL_FRAMEBUFFER_STATE_INDEX_MAX) - 1)
+
 struct _CoglFramebuffer
 {
   CoglObject          _parent;
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index 436e3b1..6886243 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -401,7 +401,8 @@ cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer,
   /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
    * as the pipeline state) when flushing the clip stack, so should
    * always be done first when preparing to draw. */
-  _cogl_framebuffer_flush_state (framebuffer, framebuffer, 0);
+  _cogl_framebuffer_flush_state (framebuffer, framebuffer,
+                                 COGL_FRAMEBUFFER_STATE_ALL);
 
   _cogl_framebuffer_clear_without_flush4f (framebuffer, buffers,
                                            red, green, blue, alpha);
@@ -525,8 +526,9 @@ cogl_framebuffer_set_viewport (CoglFramebuffer *framebuffer,
   framebuffer->viewport_width = width;
   framebuffer->viewport_height = height;
 
-  if (framebuffer->context && cogl_get_draw_framebuffer () == framebuffer)
-    framebuffer->context->dirty_gl_viewport = TRUE;
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_VIEWPORT;
 }
 
 float
@@ -834,7 +836,7 @@ try_creating_fbo (CoglOffscreen *offscreen,
   /* We are about to generate and bind a new fbo, so we pretend to
    * change framebuffer state so that the old framebuffer will be
    * rebound again before drawing. */
-  ctx->dirty_bound_framebuffer = 1;
+  ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND;
 
   /* Generate framebuffer */
   ctx->glGenFramebuffers (1, &fbo_gl_handle);
@@ -1098,9 +1100,6 @@ notify_buffers_changed (CoglFramebuffer *old_draw_buffer,
 {
   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
-  ctx->dirty_bound_framebuffer = 1;
-  ctx->dirty_gl_viewport = 1;
-
   if (old_draw_buffer && new_draw_buffer)
     {
       /* If the two draw framebuffers have a different color mask then
@@ -1366,18 +1365,229 @@ bind_gl_framebuffer (CoglContext *ctx,
     }
 }
 
+static unsigned long
+_cogl_framebuffer_compare_viewport (CoglFramebuffer *a,
+                                    CoglFramebuffer *b)
+{
+  if (a->viewport_x != b->viewport_x ||
+      a->viewport_y != b->viewport_y ||
+      a->viewport_width != b->viewport_width ||
+      a->viewport_height != b->viewport_height)
+    return COGL_FRAMEBUFFER_STATE_VIEWPORT;
+  else
+    return 0;
+}
+
+static unsigned long
+_cogl_framebuffer_compare_clip_state (CoglFramebuffer *a,
+                                      CoglFramebuffer *b)
+{
+  if (((a->clip_state->stacks == NULL || b->clip_state->stacks == NULL) &&
+       a->clip_state->stacks != b->clip_state->stacks)
+      ||
+      a->clip_state->stacks->data != b->clip_state->stacks->data)
+    return COGL_FRAMEBUFFER_STATE_CLIP;
+  else
+    return 0;
+}
+
+static unsigned long
+_cogl_framebuffer_compare_dither_state (CoglFramebuffer *a,
+                                        CoglFramebuffer *b)
+{
+  return a->dither_enabled != b->dither_enabled ?
+    COGL_FRAMEBUFFER_STATE_DITHER : 0;
+}
+
+static unsigned long
+_cogl_framebuffer_compare_modelview_state (CoglFramebuffer *a,
+                                           CoglFramebuffer *b)
+{
+  if (!_cogl_matrix_stack_equal (a->modelview_stack, b->modelview_stack))
+    return COGL_FRAMEBUFFER_STATE_MODELVIEW;
+  else
+    return 0;
+}
+
+static unsigned long
+_cogl_framebuffer_compare_projection_state (CoglFramebuffer *a,
+                                            CoglFramebuffer *b)
+{
+  if (!_cogl_matrix_stack_equal (a->projection_stack, b->projection_stack))
+    return COGL_FRAMEBUFFER_STATE_MODELVIEW;
+  else
+    return 0;
+}
+
+static unsigned long
+_cogl_framebuffer_compare (CoglFramebuffer *a,
+                           CoglFramebuffer *b,
+                           CoglFramebufferState state)
+{
+  unsigned long differences = 0;
+
+  if (state & COGL_FRAMEBUFFER_STATE_BIND)
+    differences |= COGL_FRAMEBUFFER_STATE_BIND;
+
+  COGL_FLAGS_FOREACH_START (differences,
+                            COGL_FRAMEBUFFER_STATE_INDEX_MAX, index)
+    {
+      /* XXX: We considered having an array of callbacks for each state index
+       * that we'd call here but decided that this way the compiler is more
+       * likely going to be able to in-line the comparison functions and use
+       * the index to jump straight to the required code. */
+      switch (index)
+        {
+        case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT:
+          differences |=
+            _cogl_framebuffer_compare_viewport_state (draw_buffer);
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_CLIP:
+          differences |= _cogl_framebuffer_compare_clip_state (draw_buffer);
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_DITHER:
+          differences |= _cogl_framebuffer_compare_dither_state (draw_buffer);
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW:
+          differences |=
+            _cogl_framebuffer_compare_modelview_state (draw_buffer);
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION:
+          differences |=
+            _cogl_framebuffer_compare_projection_state (draw_buffer);
+          break;
+        default:
+          g_warn_if_reached ();
+        }
+    }
+  COGL_FLAGS_FOREACH_END;
+
+  return differences;
+}
+
+static void
+_cogl_framebuffer_flush_viewport_state (CoglFramebuffer *framebuffer)
+{
+  float gl_viewport_y;
+
+  g_assert (framebuffer->viewport_width >=0 &&
+            framebuffer->viewport_height >=0);
+
+  /* Convert the Cogl viewport y offset to an OpenGL viewport y offset
+   * NB: OpenGL defines its window and viewport origins to be bottom
+   * left, while Cogl defines them to be top left.
+   * NB: We render upside down to offscreen framebuffers so we don't
+   * need to convert the y offset in this case. */
+  if (cogl_is_offscreen (framebuffer))
+    gl_viewport_y = framebuffer->viewport_y;
+  else
+    gl_viewport_y = framebuffer->height -
+      (framebuffer->viewport_y + framebuffer->viewport_height);
+
+  COGL_NOTE (OPENGL, "Calling glViewport(%f, %f, %f, %f)",
+             framebuffer->viewport_x,
+             gl_viewport_y,
+             framebuffer->viewport_width,
+             framebuffer->viewport_height);
+
+  GE (ctx, glViewport (framebuffer->viewport_x,
+                  gl_viewport_y,
+                  framebuffer->viewport_width,
+                  framebuffer->viewport_height));
+}
+
+static void
+_cogl_framebuffer_flush_clip_state (CoglFramebuffer *framebuffer)
+{
+  _cogl_clip_state_flush (&framebuffer->clip_state,
+                          framebuffer);
+}
+
+static void
+_cogl_framebuffer_flush_dither_state (CoglFramebuffer *framebuffer)
+{
+  CoglContext *ctx = framebuffer->context;
+
+  if (ctx->current_gl_dither_enabled != framebuffer->dither_enabled)
+    {
+      if (framebuffer->dither_enabled)
+        GE (ctx, glEnable (GL_DITHER));
+      else
+        GE (ctx, glDisable (GL_DITHER));
+      ctx->current_gl_dither_enabled = framebuffer->dither_enabled;
+    }
+}
+
+static void
+_cogl_framebuffer_flush_modelview_state (CoglFramebuffer *framebuffer)
+{
+  _cogl_matrix_stack_flush_to_gl (framebuffer->modelview_stack,
+                                  COGL_MATRIX_MODELVIEW);
+}
+
+static void
+_cogl_framebuffer_flush_projection_state (CoglFramebuffer *framebuffer)
+{
+  _cogl_matrix_stack_flush_to_gl (framebuffer->projection_stack,
+                                  COGL_MATRIX_PROJECTION);
+}
+
 void
 _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
                                CoglFramebuffer *read_buffer,
-                               CoglFramebufferFlushFlags flags)
+                               CoglFramebufferState state)
 {
   CoglContext *ctx = draw_buffer->context;
 
-  /* Lazily ensure the framebuffer has been allocated */
-  cogl_framebuffer_allocate (draw_buffer, NULL);
-  cogl_framebuffer_allocate (read_buffer, NULL);
+  _COGL_RETURN_IF_FAIL (!cogl_is_virtual_framebuffer (framebuffer));
+
+  /* We can assume that any state that has changed for the current
+   * framebuffer is different to the currently flushed value. */
+  differences |= ctx->current_draw_buffer_changes;
+
+  /* Any state of the current framebuffer that hasn't already been
+   * flushed is assumed to be unknown so we will always flush that
+   * state if asked. */
+  differences |= ~ctx->current_draw_buffer_state_flushed;
+
+  /* We only need to consider the state we've been asked to flush */
+  differences &= state;
 
-  if (ctx->dirty_bound_framebuffer)
+  if (ctx->current_draw_buffer != draw_buffer)
+    {
+      /* NB: we only need to compare the state we're being asked to flush
+       * and we don't need to compare the state we've already decided
+       * we will definitely flush... */
+      differences |= _cogl_framebuffer_compare (ctx->current_draw_buffer,
+                                                draw_buffer,
+                                                state & ~differences);
+      if (ctx->current_draw_buffer)
+        cogl_object_unref (ctx->current_draw_buffer);
+      ctx->current_draw_buffer = cogl_object_ref (draw_buffer);
+      ctx->current_draw_buffer_state_flushed = 0;
+    }
+
+  if (ctx->current_read_buffer != read_buffer &&
+      state & COGL_FRAMEBUFFER_STATE_BIND)
+    {
+      differences |= COGL_FRAMEBUFFER_STATE_BIND;
+      cogl_object_unref (ctx->current_read_buffer);
+      ctx->current_read_buffer = cogl_object_ref (read_buffer);
+    }
+
+  if (!differences)
+    return;
+
+  /* Lazily ensure the framebuffers have been allocated */
+  if (G_UNLIKELY (!draw_buffer->allocated))
+    cogl_framebuffer_allocate (draw_buffer, NULL);
+  if (G_UNLIKELY (!read_buffer->allocated))
+    cogl_framebuffer_allocate (read_buffer, NULL);
+
+  /* We handle buffer binding separately since the method depends on whether
+   * we are binding the same buffer for read and write or not unlike all
+   * other state that only relates to the draw_buffer. */
+  if (differences & COGL_FRAMEBUFFER_STATE_BIND)
     {
       if (draw_buffer == read_buffer)
         bind_gl_framebuffer (ctx, GL_FRAMEBUFFER, draw_buffer);
@@ -1394,69 +1604,45 @@ _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
           bind_gl_framebuffer (ctx, GL_DRAW_FRAMEBUFFER, draw_buffer);
           bind_gl_framebuffer (ctx, GL_READ_FRAMEBUFFER, read_buffer);
         }
-    }
 
-  ctx->dirty_bound_framebuffer = FALSE;
+      differences &= ~COGL_FRAMEBUFFER_STATE_BIND;
 
-  if (flags & COGL_FRAMEBUFFER_FLUSH_BIND_ONLY)
-    return;
-
-  if (ctx->dirty_gl_viewport)
-    {
-      float gl_viewport_y;
-
-      g_assert (draw_buffer->viewport_width >=0 &&
-                draw_buffer->viewport_height >=0);
-
-      /* Convert the Cogl viewport y offset to an OpenGL viewport y offset
-       * NB: OpenGL defines its window and viewport origins to be bottom
-       * left, while Cogl defines them to be top left.
-       * NB: We render upside down to offscreen framebuffers so we don't
-       * need to convert the y offset in this case. */
-      if (cogl_is_offscreen (draw_buffer))
-        gl_viewport_y = draw_buffer->viewport_y;
-      else
-        gl_viewport_y = draw_buffer->height -
-          (draw_buffer->viewport_y + draw_buffer->viewport_height);
-
-      COGL_NOTE (OPENGL, "Calling glViewport(%f, %f, %f, %f)",
-                 draw_buffer->viewport_x,
-                 gl_viewport_y,
-                 draw_buffer->viewport_width,
-                 draw_buffer->viewport_height);
-
-      GE (ctx, glViewport (draw_buffer->viewport_x,
-                      gl_viewport_y,
-                      draw_buffer->viewport_width,
-                      draw_buffer->viewport_height));
-      ctx->dirty_gl_viewport = FALSE;
+      if (state == COGL_FRAMEBUFFER_STATE_BIND)
+        return;
     }
 
-  if (ctx->current_gl_dither_enabled != draw_buffer->dither_enabled)
+  COGL_FLAGS_FOREACH_START (differences,
+                            COGL_FRAMEBUFFER_STATE_INDEX_MAX, index)
     {
-      if (draw_buffer->dither_enabled)
-        GE (ctx, glEnable (GL_DITHER));
-      else
-        GE (ctx, glDisable (GL_DITHER));
-      ctx->current_gl_dither_enabled = draw_buffer->dither_enabled;
-    }
-
-  /* XXX: Flushing clip state may trash the modelview and projection
-   * matrices so we must do it before flushing the matrices...
-   */
-  if (!(flags & COGL_FRAMEBUFFER_FLUSH_SKIP_CLIP_STATE))
-    {
-      CoglClipStack *stack =
-        _cogl_clip_state_get_stack (&draw_buffer->clip_state);
-      _cogl_clip_stack_flush (stack);
+      /* XXX: We considered having an array of callbacks for each state index
+       * that we'd call here but decided that this way the compiler is more
+       * likely going to be able to in-line the flush functions and use the
+       * index to jump straight to the required code. */
+      switch (index)
+        {
+        case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT:
+          _cogl_framebuffer_flush_viewport_state (draw_buffer);
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_CLIP:
+          _cogl_framebuffer_flush_clip_state (draw_buffer);
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_DITHER:
+          _cogl_framebuffer_flush_dither_state (draw_buffer);
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW:
+          _cogl_framebuffer_flush_modelview_state (draw_buffer);
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION:
+          _cogl_framebuffer_flush_projection_state (draw_buffer);
+          break;
+        default:
+          g_warn_if_reached ();
+        }
     }
+  COGL_FLAGS_FOREACH_END;
 
-  if (!(flags & COGL_FRAMEBUFFER_FLUSH_SKIP_MODELVIEW))
-    _cogl_matrix_stack_flush_to_gl (draw_buffer->modelview_stack,
-                                    COGL_MATRIX_MODELVIEW);
-
-  _cogl_matrix_stack_flush_to_gl (draw_buffer->projection_stack,
-                                  COGL_MATRIX_PROJECTION);
+  ctx->current_draw_buffer_state_flushed |= state;
+  ctx->current_draw_buffer_changes &= ~state;
 }
 
 int
@@ -1527,6 +1713,10 @@ cogl_framebuffer_set_dither_enabled (CoglFramebuffer *framebuffer,
 
   cogl_flush (); /* Currently dithering changes aren't tracked in the journal */
   framebuffer->dither_enabled = dither_enabled;
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_DITHER;
 }
 
 CoglPixelFormat
@@ -1703,7 +1893,8 @@ _cogl_blit_framebuffer (unsigned int src_x,
      flushing the clip state so we can bind our own empty state */
   _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (),
                                  _cogl_get_read_framebuffer (),
-                                 COGL_FRAMEBUFFER_FLUSH_SKIP_CLIP_STATE);
+                                 COGL_FRAMEBUFFER_STATE_ALL &
+                                 ~COGL_FRAMEBUFFER_STATE_CLIP);
 
   /* Flush any empty clip stack because glBlitFramebuffer is affected
      by the scissor and we want to hide this feature for the Cogl API
@@ -1711,6 +1902,12 @@ _cogl_blit_framebuffer (unsigned int src_x,
      the scissor */
   _cogl_clip_stack_flush (NULL, draw_buffer);
 
+  /* XXX: Because we are manually flushing clip state here we need to
+   * make sure that the clip state gets updated the next time we flush
+   * framebuffer state by marking the current framebuffer's clip state
+   * as changed */
+  ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP;
+
   ctx->glBlitFramebuffer (src_x, src_y,
                      src_x + width, src_y + height,
                      dst_x, dst_y,
@@ -1777,6 +1974,10 @@ cogl_framebuffer_push_matrix (CoglFramebuffer *framebuffer)
   CoglMatrixStack *modelview_stack =
     _cogl_framebuffer_get_modelview_stack (framebuffer);
   _cogl_matrix_stack_push (modelview_stack);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_MODELVIEW;
 }
 
 void
@@ -1785,6 +1986,10 @@ cogl_framebuffer_pop_matrix (CoglFramebuffer *framebuffer)
   CoglMatrixStack *modelview_stack =
     _cogl_framebuffer_get_modelview_stack (framebuffer);
   _cogl_matrix_stack_pop (modelview_stack);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_MODELVIEW;
 }
 
 void
@@ -1793,6 +1998,10 @@ cogl_framebuffer_identity_matrix (CoglFramebuffer *framebuffer)
   CoglMatrixStack *modelview_stack =
     _cogl_framebuffer_get_modelview_stack (framebuffer);
   _cogl_matrix_stack_load_identity (modelview_stack);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_MODELVIEW;
 }
 
 void
@@ -1804,6 +2013,10 @@ cogl_framebuffer_scale (CoglFramebuffer *framebuffer,
   CoglMatrixStack *modelview_stack =
     _cogl_framebuffer_get_modelview_stack (framebuffer);
   _cogl_matrix_stack_scale (modelview_stack, x, y, z);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_MODELVIEW;
 }
 
 void
@@ -1815,6 +2028,10 @@ cogl_framebuffer_translate (CoglFramebuffer *framebuffer,
   CoglMatrixStack *modelview_stack =
     _cogl_framebuffer_get_modelview_stack (framebuffer);
   _cogl_matrix_stack_translate (modelview_stack, x, y, z);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_MODELVIEW;
 }
 
 void
@@ -1827,6 +2044,10 @@ cogl_framebuffer_rotate (CoglFramebuffer *framebuffer,
   CoglMatrixStack *modelview_stack =
     _cogl_framebuffer_get_modelview_stack (framebuffer);
   _cogl_matrix_stack_rotate (modelview_stack, angle, x, y, z);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_MODELVIEW;
 }
 
 void
@@ -1836,6 +2057,10 @@ cogl_framebuffer_transform (CoglFramebuffer *framebuffer,
   CoglMatrixStack *modelview_stack =
     _cogl_framebuffer_get_modelview_stack (framebuffer);
   _cogl_matrix_stack_multiply (modelview_stack, matrix);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_MODELVIEW;
 }
 
 void
@@ -1854,6 +2079,10 @@ cogl_framebuffer_perspective (CoglFramebuffer *framebuffer,
                             ymax,            /* top */
                             z_near,
                             z_far);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_PROJECTION;
 }
 
 void
@@ -1881,6 +2110,10 @@ cogl_framebuffer_frustum (CoglFramebuffer *framebuffer,
                               top,
                               z_near,
                               z_far);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_PROJECTION;
 }
 
 void
@@ -1903,6 +2136,10 @@ cogl_framebuffer_orthographic (CoglFramebuffer *framebuffer,
   cogl_matrix_init_identity (&ortho);
   cogl_matrix_orthographic (&ortho, x_1, y_1, x_2, y_2, near, far);
   _cogl_matrix_stack_set (projection_stack, &ortho);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_PROJECTION;
 }
 
 void
@@ -1923,8 +2160,9 @@ _cogl_framebuffer_push_orthographic (CoglFramebuffer *framebuffer,
                             near,
                             far);
 
-  framebuffer->context->current_draw_buffer_changes |=
-    COGL_FRAMEBUFFER_STATE_PROJECTION;
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_PROJECTION;
 }
 
 void
@@ -1933,8 +2171,10 @@ _cogl_framebuffer_pop_orthographic (CoglFramebuffer *framebuffer)
   CoglMatrixStack *projection_stack =
     _cogl_framebuffer_get_projection_stack (framebuffer);
   _cogl_matrix_stack_pop (projection_stack);
-  framebuffer->context->current_draw_buffer_changes |=
-    COGL_FRAMEBUFFER_STATE_PROJECTION;
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_PROJECTION;
 }
 
 void
@@ -1954,6 +2194,11 @@ cogl_framebuffer_set_modelview_matrix (CoglFramebuffer *framebuffer,
   CoglMatrixStack *modelview_stack =
     _cogl_framebuffer_get_modelview_stack (framebuffer);
   _cogl_matrix_stack_set (modelview_stack, matrix);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_MODELVIEW;
+
   _COGL_MATRIX_DEBUG_PRINT (matrix);
 }
 
@@ -1980,6 +2225,10 @@ cogl_framebuffer_set_projection_matrix (CoglFramebuffer *framebuffer,
 
   _cogl_matrix_stack_set (projection_stack, matrix);
 
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_PROJECTION;
+
   _COGL_MATRIX_DEBUG_PRINT (matrix);
 }
 
@@ -1996,6 +2245,10 @@ cogl_framebuffer_push_scissor_clip (CoglFramebuffer *framebuffer,
     _cogl_clip_stack_push_window_rectangle (clip_state->stacks->data,
                                             x_offset, y_offset,
                                             width, height);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_CLIP;
 }
 
 void
@@ -2014,6 +2267,10 @@ cogl_framebuffer_push_rectangle_clip (CoglFramebuffer *framebuffer,
     _cogl_clip_stack_push_rectangle (clip_state->stacks->data,
                                      x_1, y_1, x_2, y_2,
                                      &modelview_matrix);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_CLIP;
 }
 
 void
@@ -2029,6 +2286,10 @@ cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer,
     _cogl_clip_stack_push_from_path (clip_state->stacks->data,
                                      path,
                                      &modelview_matrix);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_CLIP;
 }
 
 void
@@ -2050,6 +2311,10 @@ cogl_framebuffer_push_primitive_clip (CoglFramebuffer *framebuffer,
                                      bounds_x1, bounds_y1,
                                      bounds_x2, bounds_y2,
                                      &modelview_matrix);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_CLIP;
 }
 
 void
@@ -2058,6 +2323,10 @@ cogl_framebuffer_pop_clip (CoglFramebuffer *framebuffer)
   CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
 
   clip_state->stacks->data = _cogl_clip_stack_pop (clip_state->stacks->data);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_CLIP;
 }
 
 void
@@ -2065,6 +2334,10 @@ _cogl_framebuffer_save_clip_stack (CoglFramebuffer *framebuffer)
 {
   CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
   _cogl_clip_state_save_clip_stack (clip_state);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_CLIP;
 }
 
 void
@@ -2072,4 +2345,8 @@ _cogl_framebuffer_restore_clip_stack (CoglFramebuffer *framebuffer)
 {
   CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
   _cogl_clip_state_restore_clip_stack (clip_state);
+
+  if (framebuffer->context->current_draw_buffer == framebuffer)
+    framebuffer->context->current_draw_buffer_changes |=
+      COGL_FRAMEBUFFER_STATE_CLIP;
 }
diff --git a/cogl/cogl-journal.c b/cogl/cogl-journal.c
index ad64675..e04bf1c 100644
--- a/cogl/cogl-journal.c
+++ b/cogl/cogl-journal.c
@@ -710,6 +710,12 @@ _cogl_journal_flush_clip_stacks_and_entries (CoglJournalEntry *batch_start,
 
   _cogl_clip_stack_flush (batch_start->clip_stack, state->framebuffer);
 
+  /* XXX: Because we are manually flushing clip state here we need to
+   * make sure that the clip state gets updated the next time we flush
+   * framebuffer state by marking the current framebuffer's clip state
+   * as changed. */
+  ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP;
+
   _cogl_matrix_stack_push (state->modelview_stack);
 
   /* If we have transformed all our quads at log time then we ensure
@@ -1373,8 +1379,9 @@ _cogl_journal_flush (CoglJournal *journal,
      state manually */
   _cogl_framebuffer_flush_state (framebuffer,
                                  framebuffer,
-                                 COGL_FRAMEBUFFER_FLUSH_SKIP_MODELVIEW |
-                                 COGL_FRAMEBUFFER_FLUSH_SKIP_CLIP_STATE);
+                                 COGL_FRAMEBUFFER_STATE_ALL &
+                                 ~(COGL_FRAMEBUFFER_STATE_MODELVIEW |
+                                   COGL_FRAMEBUFFER_STATE_CLIP));
 
   state.journal = journal;
 
diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c
index d83570d..ea4f462 100644
--- a/cogl/cogl-texture-2d.c
+++ b/cogl/cogl-texture-2d.c
@@ -586,7 +586,8 @@ _cogl_texture_2d_copy_from_framebuffer (CoglHandle handle,
    * framebuffer. */
   _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (),
                                  _cogl_get_read_framebuffer (),
-                                 COGL_FRAMEBUFFER_FLUSH_SKIP_CLIP_STATE);
+                                 COGL_FRAMEBUFFER_STATE_ALL &
+                                 ~COGL_FRAMEBUFFER_STATE_CLIP);
 
   _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
                                    tex_2d->gl_texture,
diff --git a/cogl/cogl.c b/cogl/cogl.c
index d29885f..46fd45e 100644
--- a/cogl/cogl.c
+++ b/cogl/cogl.c
@@ -484,7 +484,7 @@ _cogl_read_pixels_with_rowstride (int x,
 
   _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (),
                                  framebuffer,
-                                 0);
+                                 COGL_FRAMEBUFFER_STATE_BIND);
 
   framebuffer_height = cogl_framebuffer_get_height (framebuffer);
 
@@ -671,7 +671,7 @@ cogl_begin_gl (void)
    * always be done first when preparing to draw. */
   _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (),
                                  _cogl_get_read_framebuffer (),
-                                 0);
+                                 COGL_FRAMEBUFFER_STATE_ALL);
 
   /* Setup the state for the current pipeline */
 
diff --git a/cogl/winsys/cogl-winsys-glx.c b/cogl/winsys/cogl-winsys-glx.c
index 0dce474..58640af 100644
--- a/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/winsys/cogl-winsys-glx.c
@@ -1219,7 +1219,7 @@ _cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
 
   _cogl_framebuffer_flush_state (framebuffer,
                                  framebuffer,
-                                 COGL_FRAMEBUFFER_FLUSH_BIND_ONLY);
+                                 COGL_FRAMEBUFFER_STATE_BIND);
 
   if (onscreen->swap_throttled)
     {
@@ -1351,7 +1351,7 @@ _cogl_winsys_onscreen_swap_buffers (CoglOnscreen *onscreen)
    * we get a BadDrawable error from the X server. */
   _cogl_framebuffer_flush_state (framebuffer,
                                  framebuffer,
-                                 COGL_FRAMEBUFFER_FLUSH_BIND_ONLY);
+                                 COGL_FRAMEBUFFER_STATE_BIND);
 
   drawable = glx_onscreen->glxwin ? glx_onscreen->glxwin : xlib_onscreen->xwin;
 



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