[mutter] cogl: Move "flush framebuffers" under the context scope



commit e3de0be678360eb946de5edf47dfc9409d19652a
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Mon Oct 19 17:42:43 2020 +0200

    cogl: Move "flush framebuffers" under the context scope
    
    It was namespaced as a CoglFramebuffer function, but was passed two
    framebuffers, and operated on state kept in CoglContext. Move and rename
    accordingly.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1514>

 cogl/cogl/cogl-attribute.c                         |  11 +-
 cogl/cogl/cogl-driver.h                            |   7 +-
 cogl/cogl/cogl-framebuffer-private.h               |   7 +-
 cogl/cogl/cogl-framebuffer.c                       |  29 +--
 cogl/cogl/cogl-journal.c                           |  29 +--
 cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h  |   9 +-
 cogl/cogl/driver/gl/cogl-framebuffer-gl.c          | 202 +++++++--------------
 cogl/cogl/driver/gl/cogl-texture-2d-gl.c           |   9 +-
 cogl/cogl/driver/gl/cogl-util-gl-private.h         |   6 +
 cogl/cogl/driver/gl/cogl-util-gl.c                 |  92 ++++++++++
 cogl/cogl/driver/gl/gl/cogl-driver-gl.c            |   2 +-
 cogl/cogl/driver/gl/gles/cogl-driver-gles.c        |   2 +-
 cogl/cogl/driver/nop/cogl-driver-nop.c             |  10 +-
 .../cogl/driver/nop/cogl-framebuffer-nop-private.h |   5 -
 cogl/cogl/driver/nop/cogl-framebuffer-nop.c        |   7 -
 cogl/cogl/winsys/cogl-onscreen-egl.c               |  14 +-
 cogl/cogl/winsys/cogl-onscreen-glx.c               |  14 +-
 17 files changed, 248 insertions(+), 207 deletions(-)
---
diff --git a/cogl/cogl/cogl-attribute.c b/cogl/cogl/cogl-attribute.c
index a31906739a..a872739d71 100644
--- a/cogl/cogl/cogl-attribute.c
+++ b/cogl/cogl/cogl-attribute.c
@@ -603,16 +603,19 @@ _cogl_flush_attributes_state (CoglFramebuffer *framebuffer,
                                  validate_layer_cb,
                                  &layers_state);
 
-  /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
+  /* NB: cogl_context_flush_framebuffer_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. We need to do this
    * before setting up the array pointers because setting up the clip
    * stack can cause some drawing which would change the array
    * pointers. */
   if (!(flags & COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH))
-    _cogl_framebuffer_flush_state (framebuffer,
-                                   framebuffer,
-                                   COGL_FRAMEBUFFER_STATE_ALL);
+    {
+      cogl_context_flush_framebuffer_state (ctx,
+                                            framebuffer,
+                                            framebuffer,
+                                            COGL_FRAMEBUFFER_STATE_ALL);
+    }
 
   /* In cogl_read_pixels we have a fast-path when reading a single
    * pixel and the scene is just comprised of simple rectangles still
diff --git a/cogl/cogl/cogl-driver.h b/cogl/cogl/cogl-driver.h
index 6cf8f7b73c..5e07eb5b87 100644
--- a/cogl/cogl/cogl-driver.h
+++ b/cogl/cogl/cogl-driver.h
@@ -82,9 +82,10 @@ struct _CoglDriverVtable
   (* offscreen_free) (CoglOffscreen *offscreen);
 
   void
-  (* framebuffer_flush_state) (CoglFramebuffer *draw_buffer,
-                               CoglFramebuffer *read_buffer,
-                               CoglFramebufferState state);
+  (* flush_framebuffer_state) (CoglContext          *context,
+                               CoglFramebuffer      *draw_buffer,
+                               CoglFramebuffer      *read_buffer,
+                               CoglFramebufferState  state);
 
   void
   (* framebuffer_clear) (CoglFramebuffer *framebuffer,
diff --git a/cogl/cogl/cogl-framebuffer-private.h b/cogl/cogl/cogl-framebuffer-private.h
index a7241f3257..1d8f471d3d 100644
--- a/cogl/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl/cogl-framebuffer-private.h
@@ -189,9 +189,10 @@ void
 _cogl_framebuffer_flush_dependency_journals (CoglFramebuffer *framebuffer);
 
 void
-_cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
-                               CoglFramebuffer *read_buffer,
-                               CoglFramebufferState state);
+cogl_context_flush_framebuffer_state (CoglContext          *context,
+                                      CoglFramebuffer      *draw_buffer,
+                                      CoglFramebuffer      *read_buffer,
+                                      CoglFramebufferState  state);
 
 CoglFramebuffer *
 _cogl_get_read_framebuffer (void);
diff --git a/cogl/cogl/cogl-framebuffer.c b/cogl/cogl/cogl-framebuffer.c
index 6b793cd28a..cf73551033 100644
--- a/cogl/cogl/cogl-framebuffer.c
+++ b/cogl/cogl/cogl-framebuffer.c
@@ -477,6 +477,7 @@ cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer,
 {
   CoglFramebufferPrivate *priv =
     cogl_framebuffer_get_instance_private (framebuffer);
+  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
   CoglClipStack *clip_stack = _cogl_framebuffer_get_clip_stack (framebuffer);
   gboolean had_depth_and_color_buffer_bits;
   int scissor_x0;
@@ -580,11 +581,12 @@ cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer,
 
   _cogl_framebuffer_flush_journal (framebuffer);
 
-  /* NB: _cogl_framebuffer_flush_state may disrupt various state (such
+  /* NB: cogl_context_flush_framebuffer_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,
-                                 COGL_FRAMEBUFFER_STATE_ALL);
+  cogl_context_flush_framebuffer_state (context,
+                                        framebuffer, framebuffer,
+                                        COGL_FRAMEBUFFER_STATE_ALL);
 
   _cogl_framebuffer_clear_without_flush4f (framebuffer, buffers,
                                            red, green, blue, alpha);
@@ -1074,13 +1076,13 @@ _cogl_framebuffer_compare (CoglFramebuffer *a,
 }
 
 void
-_cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
-                               CoglFramebuffer *read_buffer,
-                               CoglFramebufferState state)
+cogl_context_flush_framebuffer_state (CoglContext          *ctx,
+                                      CoglFramebuffer      *draw_buffer,
+                                      CoglFramebuffer      *read_buffer,
+                                      CoglFramebufferState  state)
 {
-  CoglContext *ctx = cogl_framebuffer_get_context (draw_buffer);
-
-  ctx->driver_vtable->framebuffer_flush_state (draw_buffer,
+  ctx->driver_vtable->flush_framebuffer_state (ctx,
+                                               draw_buffer,
                                                read_buffer,
                                                state);
 }
@@ -1593,10 +1595,11 @@ cogl_blit_framebuffer (CoglFramebuffer *framebuffer,
 
   /* Make sure the current framebuffers are bound. We explicitly avoid
      flushing the clip state so we can bind our own empty state */
-  _cogl_framebuffer_flush_state (dst,
-                                 framebuffer,
-                                 COGL_FRAMEBUFFER_STATE_ALL &
-                                 ~COGL_FRAMEBUFFER_STATE_CLIP);
+  cogl_context_flush_framebuffer_state (ctx,
+                                        dst,
+                                        framebuffer,
+                                        (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
diff --git a/cogl/cogl/cogl-journal.c b/cogl/cogl/cogl-journal.c
index 2edb8e9f0c..f9acfb18fa 100644
--- a/cogl/cogl/cogl-journal.c
+++ b/cogl/cogl/cogl-journal.c
@@ -1051,9 +1051,10 @@ _cogl_journal_flush_dither_and_entries (CoglJournalEntry *batch_start,
   cogl_framebuffer_set_dither_enabled (framebuffer, batch_start->dither_enabled);
   ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_DITHER;
 
-  _cogl_framebuffer_flush_state (framebuffer,
-                                 framebuffer,
-                                 COGL_FRAMEBUFFER_STATE_DITHER);
+  cogl_context_flush_framebuffer_state (ctx,
+                                        framebuffer,
+                                        framebuffer,
+                                        COGL_FRAMEBUFFER_STATE_DITHER);
 
   batch_and_call (batch_start,
                   batch_len,
@@ -1097,9 +1098,10 @@ _cogl_journal_flush_viewport_and_entries (CoglJournalEntry *batch_start,
   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);
+  cogl_context_flush_framebuffer_state (ctx,
+                                        framebuffer,
+                                        framebuffer,
+                                        COGL_FRAMEBUFFER_STATE_VIEWPORT);
 
   batch_and_call (batch_start,
                   batch_len,
@@ -1402,13 +1404,14 @@ _cogl_journal_flush (CoglJournal *journal)
 
   /* 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_DITHER |
-                                   COGL_FRAMEBUFFER_STATE_VIEWPORT |
-                                   COGL_FRAMEBUFFER_STATE_MODELVIEW |
-                                   COGL_FRAMEBUFFER_STATE_CLIP));
+  cogl_context_flush_framebuffer_state (ctx,
+                                        framebuffer,
+                                        framebuffer,
+                                        COGL_FRAMEBUFFER_STATE_ALL &
+                                        ~(COGL_FRAMEBUFFER_STATE_DITHER |
+                                          COGL_FRAMEBUFFER_STATE_VIEWPORT |
+                                          COGL_FRAMEBUFFER_STATE_MODELVIEW |
+                                          COGL_FRAMEBUFFER_STATE_CLIP));
 
   /* We need to mark the current modelview state of the framebuffer as
    * dirty because we are going to manually replace it */
diff --git a/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h 
b/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h
index 10fb7fff9d..6fe059d30d 100644
--- a/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h
+++ b/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h
@@ -52,11 +52,6 @@ _cogl_offscreen_gl_allocate (CoglOffscreen       *offscreen,
 void
 _cogl_offscreen_gl_free (CoglOffscreen *offscreen);
 
-void
-_cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer,
-                                  CoglFramebuffer *read_buffer,
-                                  CoglFramebufferState state);
-
 void
 _cogl_framebuffer_gl_clear (CoglFramebuffer *framebuffer,
                             unsigned long buffers,
@@ -111,6 +106,10 @@ _cogl_framebuffer_gl_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
                                               CoglBitmap *bitmap,
                                               GError **error);
 
+void
+cogl_gl_framebuffer_flush_state_differences (CoglGlFramebuffer *gl_framebuffer,
+                                             unsigned long      differences);
+
 #endif /* __COGL_FRAMEBUFFER_GL_PRIVATE_H__ */
 
 
diff --git a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
index 9aaca0d2cd..fdb3dcd4e5 100644
--- a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
+++ b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
@@ -303,6 +303,55 @@ _cogl_framebuffer_gl_flush_stereo_mode_state (CoglFramebuffer *framebuffer)
     }
 }
 
+void
+cogl_gl_framebuffer_flush_state_differences (CoglGlFramebuffer *gl_framebuffer,
+                                             unsigned long      differences)
+{
+  CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer);
+  CoglFramebuffer *framebuffer =
+    cogl_framebuffer_driver_get_framebuffer (driver);
+  int bit;
+
+  COGL_FLAGS_FOREACH_START (&differences, 1, bit)
+    {
+      /* 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 (bit)
+        {
+        case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT:
+          _cogl_framebuffer_gl_flush_viewport_state (framebuffer);
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_CLIP:
+          _cogl_framebuffer_gl_flush_clip_state (framebuffer);
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_DITHER:
+          _cogl_framebuffer_gl_flush_dither_state (framebuffer);
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW:
+          _cogl_framebuffer_gl_flush_modelview_state (framebuffer);
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION:
+          _cogl_framebuffer_gl_flush_projection_state (framebuffer);
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING:
+          _cogl_framebuffer_gl_flush_front_face_winding_state (framebuffer);
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_DEPTH_WRITE:
+          /* Nothing to do for depth write state change; the state will always
+           * be taken into account when flushing the pipeline's depth state. */
+          break;
+        case COGL_FRAMEBUFFER_STATE_INDEX_STEREO_MODE:
+          _cogl_framebuffer_gl_flush_stereo_mode_state (framebuffer);
+          break;
+        default:
+          g_warn_if_reached ();
+        }
+    }
+  COGL_FLAGS_FOREACH_END;
+}
+
 void
 _cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target)
 {
@@ -354,132 +403,6 @@ _cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target)
     }
 }
 
-void
-_cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer,
-                                  CoglFramebuffer *read_buffer,
-                                  CoglFramebufferState state)
-{
-  CoglContext *ctx = cogl_framebuffer_get_context (draw_buffer);
-  unsigned long differences;
-  int bit;
-
-  /* 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->current_draw_buffer != draw_buffer)
-    {
-      /* If the previous draw buffer is NULL then we'll assume
-         everything has changed. This can happen if a framebuffer is
-         destroyed while it is the last flushed draw buffer. In that
-         case the framebuffer destructor will set
-         ctx->current_draw_buffer to NULL */
-      if (ctx->current_draw_buffer == NULL)
-        differences |= state;
-      else
-        /* 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);
-
-      /* NB: we don't take a reference here, to avoid a circular
-       * reference. */
-      ctx->current_draw_buffer = 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;
-      /* NB: we don't take a reference here, to avoid a circular
-       * reference. */
-      ctx->current_read_buffer = read_buffer;
-    }
-
-  if (!differences)
-    return;
-
-  /* Lazily ensure the framebuffers have been allocated */
-  if (G_UNLIKELY (!cogl_framebuffer_is_allocated (draw_buffer)))
-    cogl_framebuffer_allocate (draw_buffer, NULL);
-  if (G_UNLIKELY (!cogl_framebuffer_is_allocated (read_buffer)))
-    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)
-        _cogl_framebuffer_gl_bind (draw_buffer, GL_FRAMEBUFFER);
-      else
-        {
-          /* NB: Currently we only take advantage of binding separate
-           * read/write buffers for framebuffer blit purposes. */
-          g_return_if_fail (cogl_has_feature
-                            (ctx, COGL_FEATURE_ID_BLIT_FRAMEBUFFER));
-
-          _cogl_framebuffer_gl_bind (draw_buffer, GL_DRAW_FRAMEBUFFER);
-          _cogl_framebuffer_gl_bind (read_buffer, GL_READ_FRAMEBUFFER);
-        }
-
-      differences &= ~COGL_FRAMEBUFFER_STATE_BIND;
-    }
-
-  COGL_FLAGS_FOREACH_START (&differences, 1, bit)
-    {
-      /* 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 (bit)
-        {
-        case COGL_FRAMEBUFFER_STATE_INDEX_VIEWPORT:
-          _cogl_framebuffer_gl_flush_viewport_state (draw_buffer);
-          break;
-        case COGL_FRAMEBUFFER_STATE_INDEX_CLIP:
-          _cogl_framebuffer_gl_flush_clip_state (draw_buffer);
-          break;
-        case COGL_FRAMEBUFFER_STATE_INDEX_DITHER:
-          _cogl_framebuffer_gl_flush_dither_state (draw_buffer);
-          break;
-        case COGL_FRAMEBUFFER_STATE_INDEX_MODELVIEW:
-          _cogl_framebuffer_gl_flush_modelview_state (draw_buffer);
-          break;
-        case COGL_FRAMEBUFFER_STATE_INDEX_PROJECTION:
-          _cogl_framebuffer_gl_flush_projection_state (draw_buffer);
-          break;
-        case COGL_FRAMEBUFFER_STATE_INDEX_FRONT_FACE_WINDING:
-          _cogl_framebuffer_gl_flush_front_face_winding_state (draw_buffer);
-          break;
-        case COGL_FRAMEBUFFER_STATE_INDEX_DEPTH_WRITE:
-          /* Nothing to do for depth write state change; the state will always
-           * be taken into account when flushing the pipeline's depth state. */
-          break;
-        case COGL_FRAMEBUFFER_STATE_INDEX_STEREO_MODE:
-          _cogl_framebuffer_gl_flush_stereo_mode_state (draw_buffer);
-          break;
-        default:
-          g_warn_if_reached ();
-        }
-    }
-  COGL_FLAGS_FOREACH_END;
-
-  ctx->current_draw_buffer_state_flushed |= state;
-  ctx->current_draw_buffer_changes &= ~state;
-}
-
 static GList *
 try_creating_renderbuffers (CoglContext *ctx,
                             int width,
@@ -902,6 +825,12 @@ _cogl_framebuffer_gl_clear (CoglFramebuffer *framebuffer,
   GE (ctx, glClear (gl_buffers));
 }
 
+CoglGlFramebuffer *
+cogl_gl_framebuffer_from_framebuffer (CoglFramebuffer *framebuffer)
+{
+  return ensure_gl_framebuffer (framebuffer);
+}
+
 static CoglGlFramebuffer *
 ensure_gl_framebuffer (CoglFramebuffer *framebuffer)
 {
@@ -935,9 +864,10 @@ _cogl_framebuffer_init_bits (CoglFramebuffer *framebuffer)
 
   cogl_framebuffer_allocate (framebuffer, NULL);
 
-  _cogl_framebuffer_flush_state (framebuffer,
-                                 framebuffer,
-                                 COGL_FRAMEBUFFER_STATE_BIND);
+  cogl_context_flush_framebuffer_state (ctx,
+                                        framebuffer,
+                                        framebuffer,
+                                        COGL_FRAMEBUFFER_STATE_BIND);
 
 #ifdef HAVE_COGL_GL
   if ((ctx->driver == COGL_DRIVER_GL3 &&
@@ -1072,9 +1002,10 @@ _cogl_framebuffer_gl_discard_buffers (CoglFramebuffer *framebuffer,
             attachments[i++] = GL_STENCIL_ATTACHMENT;
         }
 
-      _cogl_framebuffer_flush_state (framebuffer,
-                                     framebuffer,
-                                     COGL_FRAMEBUFFER_STATE_BIND);
+      cogl_context_flush_framebuffer_state (ctx,
+                                            framebuffer,
+                                            framebuffer,
+                                            COGL_FRAMEBUFFER_STATE_BIND);
       GE (ctx, glDiscardFramebuffer (GL_FRAMEBUFFER, i, attachments));
     }
 }
@@ -1190,9 +1121,10 @@ _cogl_framebuffer_gl_read_pixels_into_bitmap (CoglFramebuffer *framebuffer,
 
   g_return_val_if_fail (cogl_pixel_format_get_n_planes (format) == 1, FALSE);
 
-  _cogl_framebuffer_flush_state (framebuffer,
-                                 framebuffer,
-                                 COGL_FRAMEBUFFER_STATE_BIND);
+  cogl_context_flush_framebuffer_state (ctx,
+                                        framebuffer,
+                                        framebuffer,
+                                        COGL_FRAMEBUFFER_STATE_BIND);
 
   /* The y coordinate should be given in OpenGL's coordinate system
    * so 0 is the bottom row
diff --git a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
index d602de2c87..4862dbe2e6 100644
--- a/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
+++ b/cogl/cogl/driver/gl/cogl-texture-2d-gl.c
@@ -499,10 +499,11 @@ _cogl_texture_2d_gl_copy_from_framebuffer (CoglTexture2D *tex_2d,
   /* Make sure the current framebuffers are bound, though we don't need to
    * flush the clip state here since we aren't going to draw to the
    * framebuffer. */
-  _cogl_framebuffer_flush_state (ctx->current_draw_buffer,
-                                 src_fb,
-                                 COGL_FRAMEBUFFER_STATE_ALL &
-                                 ~COGL_FRAMEBUFFER_STATE_CLIP);
+  cogl_context_flush_framebuffer_state (ctx,
+                                        ctx->current_draw_buffer,
+                                        src_fb,
+                                        (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/driver/gl/cogl-util-gl-private.h b/cogl/cogl/driver/gl/cogl-util-gl-private.h
index c5f432cc86..f72c741942 100644
--- a/cogl/cogl/driver/gl/cogl-util-gl-private.h
+++ b/cogl/cogl/driver/gl/cogl-util-gl-private.h
@@ -94,6 +94,12 @@ _cogl_driver_gl_context_init (CoglContext *context);
 void
 _cogl_driver_gl_context_deinit (CoglContext *context);
 
+void
+_cogl_driver_gl_flush_framebuffer_state (CoglContext          *context,
+                                         CoglFramebuffer      *draw_buffer,
+                                         CoglFramebuffer      *read_buffer,
+                                         CoglFramebufferState  state);
+
 GLenum
 _cogl_gl_util_get_error (CoglContext *ctx);
 
diff --git a/cogl/cogl/driver/gl/cogl-util-gl.c b/cogl/cogl/driver/gl/cogl-util-gl.c
index e41c17c93d..1ca513e8d7 100644
--- a/cogl/cogl/driver/gl/cogl-util-gl.c
+++ b/cogl/cogl/driver/gl/cogl-util-gl.c
@@ -34,6 +34,7 @@
 
 #include "cogl-types.h"
 #include "cogl-context-private.h"
+#include "driver/gl/cogl-framebuffer-gl-private.h"
 #include "driver/gl/cogl-pipeline-opengl-private.h"
 #include "driver/gl/cogl-util-gl-private.h"
 
@@ -130,6 +131,97 @@ _cogl_driver_gl_context_deinit (CoglContext *context)
   g_free (context->driver_context);
 }
 
+void
+_cogl_driver_gl_flush_framebuffer_state (CoglContext          *ctx,
+                                         CoglFramebuffer      *draw_buffer,
+                                         CoglFramebuffer      *read_buffer,
+                                         CoglFramebufferState  state)
+{
+  CoglGlFramebuffer *draw_gl_framebuffer;
+  unsigned long differences;
+
+  /* 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->current_draw_buffer != draw_buffer)
+    {
+      /* If the previous draw buffer is NULL then we'll assume
+         everything has changed. This can happen if a framebuffer is
+         destroyed while it is the last flushed draw buffer. In that
+         case the framebuffer destructor will set
+         ctx->current_draw_buffer to NULL */
+      if (ctx->current_draw_buffer == NULL)
+        differences |= state;
+      else
+        /* 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);
+
+      /* NB: we don't take a reference here, to avoid a circular
+       * reference. */
+      ctx->current_draw_buffer = 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;
+      /* NB: we don't take a reference here, to avoid a circular
+       * reference. */
+      ctx->current_read_buffer = read_buffer;
+    }
+
+  if (!differences)
+    return;
+
+  /* Lazily ensure the framebuffers have been allocated */
+  if (G_UNLIKELY (!cogl_framebuffer_is_allocated (draw_buffer)))
+    cogl_framebuffer_allocate (draw_buffer, NULL);
+  if (G_UNLIKELY (!cogl_framebuffer_is_allocated (read_buffer)))
+    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)
+        _cogl_framebuffer_gl_bind (draw_buffer, GL_FRAMEBUFFER);
+      else
+        {
+          /* NB: Currently we only take advantage of binding separate
+           * read/write buffers for framebuffer blit purposes. */
+          g_return_if_fail (cogl_has_feature
+                            (ctx, COGL_FEATURE_ID_BLIT_FRAMEBUFFER));
+
+          _cogl_framebuffer_gl_bind (draw_buffer, GL_DRAW_FRAMEBUFFER);
+          _cogl_framebuffer_gl_bind (read_buffer, GL_READ_FRAMEBUFFER);
+        }
+
+      differences &= ~COGL_FRAMEBUFFER_STATE_BIND;
+    }
+
+  draw_gl_framebuffer = cogl_gl_framebuffer_from_framebuffer (draw_buffer);
+  cogl_gl_framebuffer_flush_state_differences (draw_gl_framebuffer,
+                                               differences);
+
+  ctx->current_draw_buffer_state_flushed |= state;
+  ctx->current_draw_buffer_changes &= ~state;
+}
+
 GLenum
 _cogl_gl_util_get_error (CoglContext *ctx)
 {
diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
index 35e9897f74..77c7bbcf83 100644
--- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -571,7 +571,7 @@ _cogl_driver_gl =
     _cogl_driver_update_features,
     _cogl_offscreen_gl_allocate,
     _cogl_offscreen_gl_free,
-    _cogl_framebuffer_gl_flush_state,
+    _cogl_driver_gl_flush_framebuffer_state,
     _cogl_framebuffer_gl_clear,
     _cogl_framebuffer_gl_query_bits,
     _cogl_framebuffer_gl_finish,
diff --git a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
index 2d02589a40..3c652486e2 100644
--- a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -459,7 +459,7 @@ _cogl_driver_gles =
     _cogl_driver_update_features,
     _cogl_offscreen_gl_allocate,
     _cogl_offscreen_gl_free,
-    _cogl_framebuffer_gl_flush_state,
+    _cogl_driver_gl_flush_framebuffer_state,
     _cogl_framebuffer_gl_clear,
     _cogl_framebuffer_gl_query_bits,
     _cogl_framebuffer_gl_finish,
diff --git a/cogl/cogl/driver/nop/cogl-driver-nop.c b/cogl/cogl/driver/nop/cogl-driver-nop.c
index f7e6d948f6..8c6aab47c2 100644
--- a/cogl/cogl/driver/nop/cogl-driver-nop.c
+++ b/cogl/cogl/driver/nop/cogl-driver-nop.c
@@ -67,6 +67,14 @@ _cogl_driver_nop_is_hardware_accelerated (CoglContext *context)
   return FALSE;
 }
 
+static void
+_cogl_driver_nop_flush_framebuffer_state (CoglContext          *ctx,
+                                          CoglFramebuffer      *draw_buffer,
+                                          CoglFramebuffer      *read_buffer,
+                                          CoglFramebufferState  state)
+{
+}
+
 const CoglDriverVtable
 _cogl_driver_nop =
   {
@@ -79,7 +87,7 @@ _cogl_driver_nop =
     _cogl_driver_update_features,
     _cogl_offscreen_nop_allocate,
     _cogl_offscreen_nop_free,
-    _cogl_framebuffer_nop_flush_state,
+    _cogl_driver_nop_flush_framebuffer_state,
     _cogl_framebuffer_nop_clear,
     _cogl_framebuffer_nop_query_bits,
     _cogl_framebuffer_nop_finish,
diff --git a/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h 
b/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h
index 1397ebf693..788bde6cc4 100644
--- a/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h
+++ b/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h
@@ -45,11 +45,6 @@ _cogl_offscreen_nop_allocate (CoglOffscreen       *offscreen,
 void
 _cogl_offscreen_nop_free (CoglOffscreen *offscreen);
 
-void
-_cogl_framebuffer_nop_flush_state (CoglFramebuffer *draw_buffer,
-                                   CoglFramebuffer *read_buffer,
-                                   CoglFramebufferState state);
-
 void
 _cogl_framebuffer_nop_clear (CoglFramebuffer *framebuffer,
                             unsigned long buffers,
diff --git a/cogl/cogl/driver/nop/cogl-framebuffer-nop.c b/cogl/cogl/driver/nop/cogl-framebuffer-nop.c
index 602b80421c..6dc5e7e91c 100644
--- a/cogl/cogl/driver/nop/cogl-framebuffer-nop.c
+++ b/cogl/cogl/driver/nop/cogl-framebuffer-nop.c
@@ -35,13 +35,6 @@
 #include <glib.h>
 #include <string.h>
 
-void
-_cogl_framebuffer_nop_flush_state (CoglFramebuffer *draw_buffer,
-                                   CoglFramebuffer *read_buffer,
-                                   CoglFramebufferState state)
-{
-}
-
 gboolean
 _cogl_offscreen_nop_allocate (CoglOffscreen       *offscreen,
                               CoglOffscreenFlags   flags,
diff --git a/cogl/cogl/winsys/cogl-onscreen-egl.c b/cogl/cogl/winsys/cogl-onscreen-egl.c
index b23b48e297..6262c652e3 100644
--- a/cogl/cogl/winsys/cogl-onscreen-egl.c
+++ b/cogl/cogl/winsys/cogl-onscreen-egl.c
@@ -240,9 +240,10 @@ _cogl_winsys_onscreen_egl_swap_region (CoglOnscreen  *onscreen,
      swap must be bound to the current context. It looks like Mesa
      also validates that this is the case for eglSwapBuffersRegion so
      we must bind here too */
-  _cogl_framebuffer_flush_state (COGL_FRAMEBUFFER (onscreen),
-                                 COGL_FRAMEBUFFER (onscreen),
-                                 COGL_FRAMEBUFFER_STATE_BIND);
+  cogl_context_flush_framebuffer_state (context,
+                                        COGL_FRAMEBUFFER (onscreen),
+                                        COGL_FRAMEBUFFER (onscreen),
+                                        COGL_FRAMEBUFFER_STATE_BIND);
 
   if (egl_renderer->pf_eglSwapBuffersRegion (egl_renderer->edpy,
                                              priv->egl_surface,
@@ -274,9 +275,10 @@ _cogl_winsys_onscreen_egl_swap_buffers_with_damage (CoglOnscreen  *onscreen,
      although it may change in future. Mesa explicitly checks for this
      and just returns an error if this is not the case so we can't
      just pretend this isn't in the spec. */
-  _cogl_framebuffer_flush_state (COGL_FRAMEBUFFER (onscreen),
-                                 COGL_FRAMEBUFFER (onscreen),
-                                 COGL_FRAMEBUFFER_STATE_BIND);
+  cogl_context_flush_framebuffer_state (context,
+                                        COGL_FRAMEBUFFER (onscreen),
+                                        COGL_FRAMEBUFFER (onscreen),
+                                        COGL_FRAMEBUFFER_STATE_BIND);
 
   if (n_rectangles && egl_renderer->pf_eglSwapBuffersWithDamage)
     {
diff --git a/cogl/cogl/winsys/cogl-onscreen-glx.c b/cogl/cogl/winsys/cogl-onscreen-glx.c
index 7f9e566a08..b578494b09 100644
--- a/cogl/cogl/winsys/cogl-onscreen-glx.c
+++ b/cogl/cogl/winsys/cogl-onscreen-glx.c
@@ -721,9 +721,10 @@ _cogl_winsys_onscreen_glx_swap_region (CoglOnscreen  *onscreen,
 
     }
 
-  _cogl_framebuffer_flush_state (framebuffer,
-                                 framebuffer,
-                                 COGL_FRAMEBUFFER_STATE_BIND);
+  cogl_context_flush_framebuffer_state (context,
+                                        framebuffer,
+                                        framebuffer,
+                                        COGL_FRAMEBUFFER_STATE_BIND);
 
   have_counter = glx_display->have_vblank_counter;
   can_wait = glx_display->can_vblank_wait;
@@ -891,9 +892,10 @@ _cogl_winsys_onscreen_glx_swap_buffers_with_damage (CoglOnscreen  *onscreen,
    * the Intel drivers we have see that if we don't call
    * glXMakeContextCurrent for the drawable we are swapping then
    * we get a BadDrawable error from the X server. */
-  _cogl_framebuffer_flush_state (framebuffer,
-                                 framebuffer,
-                                 COGL_FRAMEBUFFER_STATE_BIND);
+  cogl_context_flush_framebuffer_state (context,
+                                        framebuffer,
+                                        framebuffer,
+                                        COGL_FRAMEBUFFER_STATE_BIND);
 
   drawable = onscreen_glx->glxwin ? onscreen_glx->glxwin : onscreen_glx->xwin;
 


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