[mutter] cogl/gl-framebuffer: Split up into FBO and back drivers



commit 60e1516b1c5ba4ae6632007384e2f9b6d2d13ce5
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Mon Oct 19 21:19:15 2020 +0200

    cogl/gl-framebuffer: Split up into FBO and back drivers
    
    One is for when we're painting to the back buffer (onscreen), and the
    other when we're painting to an FBO (offscreen).
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1514>

 cogl/cogl/cogl-driver.h                            |   4 -
 cogl/cogl/cogl-framebuffer-driver.c                |   7 +
 cogl/cogl/cogl-framebuffer-driver.h                |   9 +
 cogl/cogl/cogl-framebuffer-private.h               |  10 +-
 cogl/cogl/cogl-framebuffer.c                       |  42 +-
 cogl/cogl/cogl-offscreen.c                         |   1 +
 cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h  |  27 +-
 cogl/cogl/driver/gl/cogl-framebuffer-gl.c          | 687 +--------------------
 cogl/cogl/driver/gl/cogl-gl-framebuffer-back.c     | 239 +++++++
 cogl/cogl/driver/gl/cogl-gl-framebuffer-back.h     |  41 ++
 cogl/cogl/driver/gl/cogl-gl-framebuffer-fbo.c      | 611 ++++++++++++++++++
 cogl/cogl/driver/gl/cogl-gl-framebuffer-fbo.h      |  41 ++
 cogl/cogl/driver/gl/cogl-util-gl-private.h         |  83 +++
 cogl/cogl/driver/gl/cogl-util-gl.c                 |  58 +-
 cogl/cogl/driver/gl/gl/cogl-driver-gl.c            |   1 -
 cogl/cogl/driver/gl/gles/cogl-driver-gles.c        |   1 -
 cogl/cogl/driver/nop/cogl-driver-nop.c             |   1 -
 .../cogl/driver/nop/cogl-framebuffer-nop-private.h |   4 -
 cogl/cogl/driver/nop/cogl-framebuffer-nop.c        |   7 -
 cogl/cogl/driver/nop/cogl-nop-framebuffer.c        |  13 +
 cogl/cogl/meson.build                              |   4 +
 cogl/cogl/winsys/cogl-onscreen-glx.c               |   6 +
 cogl/cogl/winsys/cogl-onscreen-xlib.c              |   6 +
 src/backends/native/meta-onscreen-native.c         |   5 +
 24 files changed, 1165 insertions(+), 743 deletions(-)
---
diff --git a/cogl/cogl/cogl-driver.h b/cogl/cogl/cogl-driver.h
index e2cf989279..5e698debd2 100644
--- a/cogl/cogl/cogl-driver.h
+++ b/cogl/cogl/cogl-driver.h
@@ -93,10 +93,6 @@ struct _CoglDriverVtable
                          float blue,
                          float alpha);
 
-  void
-  (* framebuffer_query_bits) (CoglFramebuffer *framebuffer,
-                              CoglFramebufferBits *bits);
-
   void
   (* framebuffer_finish) (CoglFramebuffer *framebuffer);
 
diff --git a/cogl/cogl/cogl-framebuffer-driver.c b/cogl/cogl/cogl-framebuffer-driver.c
index 1559de0f63..d1bbf82a0c 100644
--- a/cogl/cogl/cogl-framebuffer-driver.c
+++ b/cogl/cogl/cogl-framebuffer-driver.c
@@ -58,6 +58,13 @@ cogl_framebuffer_driver_get_framebuffer (CoglFramebufferDriver *driver)
   return priv->framebuffer;
 }
 
+void
+cogl_framebuffer_driver_query_bits (CoglFramebufferDriver *driver,
+                                    CoglFramebufferBits   *bits)
+{
+  COGL_FRAMEBUFFER_DRIVER_GET_CLASS (driver)->query_bits (driver, bits);
+}
+
 static void
 cogl_framebuffer_driver_get_property (GObject    *object,
                                       guint       prop_id,
diff --git a/cogl/cogl/cogl-framebuffer-driver.h b/cogl/cogl/cogl-framebuffer-driver.h
index 1ef6ce058c..8f06e9e055 100644
--- a/cogl/cogl/cogl-framebuffer-driver.h
+++ b/cogl/cogl/cogl-framebuffer-driver.h
@@ -30,6 +30,8 @@
 
 #include "cogl-framebuffer.h"
 
+typedef struct _CoglFramebufferBits CoglFramebufferBits;
+
 #define COGL_TYPE_FRAMEBUFFER_DRIVER (cogl_framebuffer_driver_get_type ())
 G_DECLARE_DERIVABLE_TYPE (CoglFramebufferDriver,
                           cogl_framebuffer_driver,
@@ -39,9 +41,16 @@ G_DECLARE_DERIVABLE_TYPE (CoglFramebufferDriver,
 struct _CoglFramebufferDriverClass
 {
   GObjectClass parent_cleass;
+
+  void (* query_bits) (CoglFramebufferDriver *driver,
+                       CoglFramebufferBits   *bits);
 };
 
 CoglFramebuffer *
 cogl_framebuffer_driver_get_framebuffer (CoglFramebufferDriver *driver);
 
+void
+cogl_framebuffer_driver_query_bits (CoglFramebufferDriver *driver,
+                                    CoglFramebufferBits   *bits);
+
 #endif /* COGL_FRAMEBUFFER_DRIVER_H */
diff --git a/cogl/cogl/cogl-framebuffer-private.h b/cogl/cogl/cogl-framebuffer-private.h
index f00a5bc4b8..0c9af2d92b 100644
--- a/cogl/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl/cogl-framebuffer-private.h
@@ -40,8 +40,16 @@
 #include "cogl-attribute-private.h"
 #include "cogl-clip-stack.h"
 
+typedef enum
+{
+  COGL_FRAMEBUFFER_DRIVER_TYPE_FBO,
+  COGL_FRAMEBUFFER_DRIVER_TYPE_BACK,
+} CoglFramebufferDriverType;
+
 struct _CoglFramebufferDriverConfig
 {
+  CoglFramebufferDriverType type;
+
   gboolean disable_depth_and_stencil;
 };
 
@@ -98,7 +106,7 @@ typedef enum
   COGL_READ_PIXELS_NO_FLIP = 1L << 30
 } CoglPrivateReadPixelsFlags;
 
-typedef struct
+typedef struct _CoglFramebufferBits
 {
   int red;
   int blue;
diff --git a/cogl/cogl/cogl-framebuffer.c b/cogl/cogl/cogl-framebuffer.c
index b83c3c19af..4bd4673da6 100644
--- a/cogl/cogl/cogl-framebuffer.c
+++ b/cogl/cogl/cogl-framebuffer.c
@@ -1126,15 +1126,24 @@ cogl_context_flush_framebuffer_state (CoglContext          *ctx,
                                                state);
 }
 
-int
-cogl_framebuffer_get_red_bits (CoglFramebuffer *framebuffer)
+static void
+cogl_framebuffer_query_bits (CoglFramebuffer     *framebuffer,
+                             CoglFramebufferBits *bits)
 {
   CoglFramebufferPrivate *priv =
     cogl_framebuffer_get_instance_private (framebuffer);
-  CoglContext *ctx = priv->context;
+
+  g_return_if_fail (priv->driver);
+
+  cogl_framebuffer_driver_query_bits (priv->driver, bits);
+}
+
+int
+cogl_framebuffer_get_red_bits (CoglFramebuffer *framebuffer)
+{
   CoglFramebufferBits bits;
 
-  ctx->driver_vtable->framebuffer_query_bits (framebuffer, &bits);
+  cogl_framebuffer_query_bits (framebuffer, &bits);
 
   return bits.red;
 }
@@ -1142,12 +1151,9 @@ cogl_framebuffer_get_red_bits (CoglFramebuffer *framebuffer)
 int
 cogl_framebuffer_get_green_bits (CoglFramebuffer *framebuffer)
 {
-  CoglFramebufferPrivate *priv =
-    cogl_framebuffer_get_instance_private (framebuffer);
-  CoglContext *ctx = priv->context;
   CoglFramebufferBits bits;
 
-  ctx->driver_vtable->framebuffer_query_bits (framebuffer, &bits);
+  cogl_framebuffer_query_bits (framebuffer, &bits);
 
   return bits.green;
 }
@@ -1155,12 +1161,9 @@ cogl_framebuffer_get_green_bits (CoglFramebuffer *framebuffer)
 int
 cogl_framebuffer_get_blue_bits (CoglFramebuffer *framebuffer)
 {
-  CoglFramebufferPrivate *priv =
-    cogl_framebuffer_get_instance_private (framebuffer);
-  CoglContext *ctx = priv->context;
   CoglFramebufferBits bits;
 
-  ctx->driver_vtable->framebuffer_query_bits (framebuffer, &bits);
+  cogl_framebuffer_query_bits (framebuffer, &bits);
 
   return bits.blue;
 }
@@ -1168,12 +1171,9 @@ cogl_framebuffer_get_blue_bits (CoglFramebuffer *framebuffer)
 int
 cogl_framebuffer_get_alpha_bits (CoglFramebuffer *framebuffer)
 {
-  CoglFramebufferPrivate *priv =
-    cogl_framebuffer_get_instance_private (framebuffer);
-  CoglContext *ctx = priv->context;
   CoglFramebufferBits bits;
 
-  ctx->driver_vtable->framebuffer_query_bits (framebuffer, &bits);
+  cogl_framebuffer_query_bits (framebuffer, &bits);
 
   return bits.alpha;
 }
@@ -1181,12 +1181,9 @@ cogl_framebuffer_get_alpha_bits (CoglFramebuffer *framebuffer)
 int
 cogl_framebuffer_get_depth_bits (CoglFramebuffer *framebuffer)
 {
-  CoglFramebufferPrivate *priv =
-    cogl_framebuffer_get_instance_private (framebuffer);
-  CoglContext *ctx = priv->context;
   CoglFramebufferBits bits;
 
-  ctx->driver_vtable->framebuffer_query_bits (framebuffer, &bits);
+  cogl_framebuffer_query_bits (framebuffer, &bits);
 
   return bits.depth;
 }
@@ -1194,12 +1191,9 @@ cogl_framebuffer_get_depth_bits (CoglFramebuffer *framebuffer)
 int
 _cogl_framebuffer_get_stencil_bits (CoglFramebuffer *framebuffer)
 {
-  CoglFramebufferPrivate *priv =
-    cogl_framebuffer_get_instance_private (framebuffer);
-  CoglContext *ctx = priv->context;
   CoglFramebufferBits bits;
 
-  ctx->driver_vtable->framebuffer_query_bits (framebuffer, &bits);
+  cogl_framebuffer_query_bits (framebuffer, &bits);
 
   return bits.stencil;
 }
diff --git a/cogl/cogl/cogl-offscreen.c b/cogl/cogl/cogl-offscreen.c
index ae05f73433..a9b25cc796 100644
--- a/cogl/cogl/cogl-offscreen.c
+++ b/cogl/cogl/cogl-offscreen.c
@@ -56,6 +56,7 @@ _cogl_offscreen_new_with_texture_full (CoglTexture       *texture,
   g_return_val_if_fail (cogl_is_texture (texture), NULL);
 
   driver_config = (CoglFramebufferDriverConfig) {
+    .type = COGL_FRAMEBUFFER_DRIVER_TYPE_FBO,
     .disable_depth_and_stencil =
       !!(flags & COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL),
   };
diff --git a/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h 
b/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h
index 2f96f6f8f7..3f0ddb5398 100644
--- a/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h
+++ b/cogl/cogl/driver/gl/cogl-framebuffer-gl-private.h
@@ -34,20 +34,22 @@
 #ifndef __COGL_FRAMEBUFFER_GL_PRIVATE_H__
 #define __COGL_FRAMEBUFFER_GL_PRIVATE_H__
 
+#include "cogl-attribute-private.h"
 #include "cogl-framebuffer-driver.h"
+#include "cogl-gl-header.h"
 
 #define COGL_TYPE_GL_FRAMEBUFFER (cogl_gl_framebuffer_get_type ())
-G_DECLARE_FINAL_TYPE (CoglGlFramebuffer, cogl_gl_framebuffer,
-                      COGL, GL_FRAMEBUFFER,
-                      CoglFramebufferDriver)
+G_DECLARE_DERIVABLE_TYPE (CoglGlFramebuffer, cogl_gl_framebuffer,
+                          COGL, GL_FRAMEBUFFER,
+                          CoglFramebufferDriver)
 
-gboolean
-_cogl_offscreen_gl_allocate (CoglOffscreen       *offscreen,
-                             CoglOffscreenFlags   flags,
-                             GError             **error);
+struct _CoglGlFramebufferClass
+{
+  CoglFramebufferDriverClass parent_class;
 
-void
-_cogl_offscreen_gl_free (CoglOffscreen *offscreen);
+  void (* bind) (CoglGlFramebuffer *gl_framebuffer,
+                 GLenum             target);
+};
 
 void
 _cogl_framebuffer_gl_clear (CoglFramebuffer *framebuffer,
@@ -57,10 +59,6 @@ _cogl_framebuffer_gl_clear (CoglFramebuffer *framebuffer,
                             float blue,
                             float alpha);
 
-void
-_cogl_framebuffer_gl_query_bits (CoglFramebuffer *framebuffer,
-                                 CoglFramebufferBits *bits);
-
 void
 _cogl_framebuffer_gl_finish (CoglFramebuffer *framebuffer);
 
@@ -72,7 +70,8 @@ _cogl_framebuffer_gl_discard_buffers (CoglFramebuffer *framebuffer,
                                       unsigned long buffers);
 
 void
-_cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target);
+cogl_gl_framebuffer_bind (CoglGlFramebuffer *gl_framebuffer,
+                          GLenum             target);
 
 void
 _cogl_framebuffer_gl_draw_attributes (CoglFramebuffer *framebuffer,
diff --git a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
index 95e4a39b6c..4700e449b6 100644
--- a/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
+++ b/cogl/cogl/driver/gl/cogl-framebuffer-gl.c
@@ -40,116 +40,12 @@
 #include "driver/gl/cogl-framebuffer-gl-private.h"
 #include "driver/gl/cogl-bitmap-gl-private.h"
 #include "driver/gl/cogl-buffer-gl-private.h"
-#include "driver/gl/cogl-texture-gl-private.h"
 
 #include <glib.h>
 #include <string.h>
 
-#ifndef GL_FRAMEBUFFER
-#define GL_FRAMEBUFFER         0x8D40
-#endif
-#ifndef GL_RENDERBUFFER
-#define GL_RENDERBUFFER                0x8D41
-#endif
-#ifndef GL_STENCIL_ATTACHMENT
-#define GL_STENCIL_ATTACHMENT  0x8D00
-#endif
-#ifndef GL_COLOR_ATTACHMENT0
-#define GL_COLOR_ATTACHMENT0   0x8CE0
-#endif
-#ifndef GL_FRAMEBUFFER_COMPLETE
-#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
-#endif
-#ifndef GL_STENCIL_INDEX8
-#define GL_STENCIL_INDEX8       0x8D48
-#endif
-#ifndef GL_DEPTH_STENCIL
-#define GL_DEPTH_STENCIL        0x84F9
-#endif
-#ifndef GL_DEPTH24_STENCIL8
-#define GL_DEPTH24_STENCIL8     0x88F0
-#endif
-#ifndef GL_DEPTH_ATTACHMENT
-#define GL_DEPTH_ATTACHMENT     0x8D00
-#endif
-#ifndef GL_DEPTH_STENCIL_ATTACHMENT
-#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
-#endif
-#ifndef GL_DEPTH_COMPONENT16
-#define GL_DEPTH_COMPONENT16    0x81A5
-#endif
-#ifndef GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE
-#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE      0x8212
-#endif
-#ifndef GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE
-#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE    0x8213
-#endif
-#ifndef GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE
-#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE     0x8214
-#endif
-#ifndef GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE
-#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE    0x8215
-#endif
-#ifndef GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE
-#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE    0x8216
-#endif
-#ifndef GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE
-#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE  0x8217
-#endif
-#ifndef GL_READ_FRAMEBUFFER
-#define GL_READ_FRAMEBUFFER               0x8CA8
-#endif
-#ifndef GL_DRAW_FRAMEBUFFER
-#define GL_DRAW_FRAMEBUFFER               0x8CA9
-#endif
-#ifndef GL_TEXTURE_SAMPLES_IMG
-#define GL_TEXTURE_SAMPLES_IMG            0x9136
-#endif
-#ifndef GL_PACK_INVERT_MESA
-#define GL_PACK_INVERT_MESA 0x8758
-#endif
-#ifndef GL_PACK_REVERSE_ROW_ORDER_ANGLE
-#define GL_PACK_REVERSE_ROW_ORDER_ANGLE 0x93A4
-#endif
-#ifndef GL_BACK_LEFT
-#define GL_BACK_LEFT                           0x0402
-#endif
-#ifndef GL_BACK_RIGHT
-#define GL_BACK_RIGHT                          0x0403
-#endif
-
-#ifndef GL_COLOR
-#define GL_COLOR 0x1800
-#endif
-#ifndef GL_DEPTH
-#define GL_DEPTH 0x1801
-#endif
-#ifndef GL_STENCIL
-#define GL_STENCIL 0x1802
-#endif
-
-typedef struct _CoglGlFbo
-{
-  GLuint fbo_handle;
-  GList *renderbuffers;
-  int samples_per_pixel;
-} CoglGlFbo;
-
-typedef struct _CoglGlFramebufferPrivate
-{
-  CoglGlFbo gl_fbo;
-
-  gboolean dirty_bitmasks;
-  CoglFramebufferBits bits;
-} CoglGlFramebufferPrivate;
-
-struct _CoglGlFramebuffer
-{
-  CoglFramebufferDriver parent;
-};
-
-G_DEFINE_TYPE_WITH_PRIVATE (CoglGlFramebuffer, cogl_gl_framebuffer,
-                            COGL_TYPE_FRAMEBUFFER_DRIVER)
+G_DEFINE_ABSTRACT_TYPE (CoglGlFramebuffer, cogl_gl_framebuffer,
+                        COGL_TYPE_FRAMEBUFFER_DRIVER)
 
 static void
 _cogl_framebuffer_gl_flush_viewport_state (CoglFramebuffer *framebuffer)
@@ -352,464 +248,12 @@ cogl_gl_framebuffer_flush_state_differences (CoglGlFramebuffer *gl_framebuffer,
   COGL_FLAGS_FOREACH_END;
 }
 
-static CoglGlFramebuffer *
-cogl_gl_framebuffer_from_framebuffer (CoglFramebuffer *framebuffer)
-{
-  CoglFramebufferDriver *driver = cogl_framebuffer_get_driver (framebuffer);
-
-  g_assert (driver);
-
-  return COGL_GL_FRAMEBUFFER (driver);
-}
-
 void
-_cogl_framebuffer_gl_bind (CoglFramebuffer *framebuffer, GLenum target)
-{
-  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
-
-  if (COGL_IS_OFFSCREEN (framebuffer))
-    {
-      CoglGlFramebuffer *gl_framebuffer =
-        cogl_gl_framebuffer_from_framebuffer (framebuffer);
-      CoglGlFramebufferPrivate *priv =
-        cogl_gl_framebuffer_get_instance_private (gl_framebuffer);
-
-      GE (ctx, glBindFramebuffer (target, priv->gl_fbo.fbo_handle));
-    }
-  else
-    {
-      const CoglWinsysVtable *winsys =
-        _cogl_framebuffer_get_winsys (framebuffer);
-      winsys->onscreen_bind (COGL_ONSCREEN (framebuffer));
-      GE (ctx, glBindFramebuffer (target, 0));
-
-      /* Initialise the glDrawBuffer state the first time the context
-       * is bound to the default framebuffer. If the winsys is using a
-       * surfaceless context for the initial make current then the
-       * default draw buffer will be GL_NONE so we need to correct
-       * that. We can't do it any earlier because binding GL_BACK when
-       * there is no default framebuffer won't work */
-      if (!ctx->was_bound_to_onscreen)
-        {
-          if (ctx->glDrawBuffer)
-            {
-              GE (ctx, glDrawBuffer (GL_BACK));
-            }
-          else if (ctx->glDrawBuffers)
-            {
-              /* glDrawBuffer isn't available on GLES 3.0 so we need
-               * to be able to use glDrawBuffers as well. On GLES 2
-               * neither is available but the state should always be
-               * GL_BACK anyway so we don't need to set anything. On
-               * desktop GL this must be GL_BACK_LEFT instead of
-               * GL_BACK but as this code path will only be hit for
-               * GLES we can just use GL_BACK. */
-              static const GLenum buffers[] = { GL_BACK };
-
-              GE (ctx, glDrawBuffers (G_N_ELEMENTS (buffers), buffers));
-            }
-
-          ctx->was_bound_to_onscreen = TRUE;
-        }
-    }
-}
-
-static GList *
-try_creating_renderbuffers (CoglContext *ctx,
-                            int width,
-                            int height,
-                            CoglOffscreenAllocateFlags flags,
-                            int n_samples)
-{
-  GList *renderbuffers = NULL;
-  GLuint gl_depth_stencil_handle;
-
-  if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL)
-    {
-      GLenum format;
-
-      /* WebGL adds a GL_DEPTH_STENCIL_ATTACHMENT and requires that we
-       * use the GL_DEPTH_STENCIL format. */
-      /* Although GL_OES_packed_depth_stencil is mostly equivalent to
-       * GL_EXT_packed_depth_stencil, one notable difference is that
-       * GL_OES_packed_depth_stencil doesn't allow GL_DEPTH_STENCIL to
-       * be passed as an internal format to glRenderbufferStorage.
-       */
-      if (_cogl_has_private_feature
-          (ctx, COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL))
-        format = GL_DEPTH_STENCIL;
-      else
-        {
-          g_return_val_if_fail (
-            _cogl_has_private_feature (ctx,
-              COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL),
-            NULL);
-          format = GL_DEPTH24_STENCIL8;
-        }
-
-      /* Create a renderbuffer for depth and stenciling */
-      GE (ctx, glGenRenderbuffers (1, &gl_depth_stencil_handle));
-      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_stencil_handle));
-      if (n_samples)
-        GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
-                                                      n_samples,
-                                                      format,
-                                                      width, height));
-      else
-        GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, format,
-                                        width, height));
-      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
-
-
-      GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
-                                          GL_STENCIL_ATTACHMENT,
-                                          GL_RENDERBUFFER,
-                                          gl_depth_stencil_handle));
-      GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
-                                          GL_DEPTH_ATTACHMENT,
-                                          GL_RENDERBUFFER,
-                                          gl_depth_stencil_handle));
-      renderbuffers =
-        g_list_prepend (renderbuffers,
-                        GUINT_TO_POINTER (gl_depth_stencil_handle));
-    }
-
-  if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH)
-    {
-      GLuint gl_depth_handle;
-
-      GE (ctx, glGenRenderbuffers (1, &gl_depth_handle));
-      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_handle));
-      /* For now we just ask for GL_DEPTH_COMPONENT16 since this is all that's
-       * available under GLES */
-      if (n_samples)
-        GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
-                                                      n_samples,
-                                                      GL_DEPTH_COMPONENT16,
-                                                      width, height));
-      else
-        GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
-                                        width, height));
-      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
-      GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
-                                          GL_DEPTH_ATTACHMENT,
-                                          GL_RENDERBUFFER, gl_depth_handle));
-      renderbuffers =
-        g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_depth_handle));
-    }
-
-  if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL)
-    {
-      GLuint gl_stencil_handle;
-
-      GE (ctx, glGenRenderbuffers (1, &gl_stencil_handle));
-      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle));
-      if (n_samples)
-        GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
-                                                      n_samples,
-                                                      GL_STENCIL_INDEX8,
-                                                      width, height));
-      else
-        GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8,
-                                        width, height));
-      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
-      GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
-                                          GL_STENCIL_ATTACHMENT,
-                                          GL_RENDERBUFFER, gl_stencil_handle));
-      renderbuffers =
-        g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_stencil_handle));
-    }
-
-  return renderbuffers;
-}
-
-static void
-delete_renderbuffers (CoglContext *ctx, GList *renderbuffers)
-{
-  GList *l;
-
-  for (l = renderbuffers; l; l = l->next)
-    {
-      GLuint renderbuffer = GPOINTER_TO_UINT (l->data);
-      GE (ctx, glDeleteRenderbuffers (1, &renderbuffer));
-    }
-
-  g_list_free (renderbuffers);
-}
-
-/*
- * NB: This function may be called with a standalone GLES2 context
- * bound so we can create a shadow framebuffer that wraps the same
- * CoglTexture as the given CoglOffscreen. This function shouldn't
- * modify anything in
- */
-static gboolean
-try_creating_fbo (CoglContext                 *ctx,
-                  CoglTexture                 *texture,
-                  int                          texture_level,
-                  int                          texture_level_width,
-                  int                          texture_level_height,
-                  const CoglFramebufferConfig *config,
-                  CoglOffscreenAllocateFlags   flags,
-                  CoglGlFbo                   *gl_fbo)
-{
-  GLuint tex_gl_handle;
-  GLenum tex_gl_target;
-  GLenum status;
-  int n_samples;
-
-  if (!cogl_texture_get_gl_texture (texture, &tex_gl_handle, &tex_gl_target))
-    return FALSE;
-
-  if (tex_gl_target != GL_TEXTURE_2D
-#ifdef HAVE_COGL_GL
-      && tex_gl_target != GL_TEXTURE_RECTANGLE_ARB
-#endif
-      )
-    return FALSE;
-
-  if (config->samples_per_pixel)
-    {
-      if (!ctx->glFramebufferTexture2DMultisampleIMG)
-        return FALSE;
-      n_samples = config->samples_per_pixel;
-    }
-  else
-    n_samples = 0;
-
-  /* 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->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND;
-
-  /* Generate framebuffer */
-  ctx->glGenFramebuffers (1, &gl_fbo->fbo_handle);
-  GE (ctx, glBindFramebuffer (GL_FRAMEBUFFER, gl_fbo->fbo_handle));
-
-  if (n_samples)
-    {
-      GE (ctx, glFramebufferTexture2DMultisampleIMG (GL_FRAMEBUFFER,
-                                                     GL_COLOR_ATTACHMENT0,
-                                                     tex_gl_target, tex_gl_handle,
-                                                     n_samples,
-                                                     texture_level));
-    }
-  else
-    GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                                     tex_gl_target, tex_gl_handle,
-                                     texture_level));
-
-  if (flags)
-    {
-      gl_fbo->renderbuffers =
-        try_creating_renderbuffers (ctx,
-                                    texture_level_width,
-                                    texture_level_height,
-                                    flags,
-                                    n_samples);
-    }
-
-  /* Make sure it's complete */
-  status = ctx->glCheckFramebufferStatus (GL_FRAMEBUFFER);
-
-  if (status != GL_FRAMEBUFFER_COMPLETE)
-    {
-      GE (ctx, glDeleteFramebuffers (1, &gl_fbo->fbo_handle));
-
-      delete_renderbuffers (ctx, gl_fbo->renderbuffers);
-      gl_fbo->renderbuffers = NULL;
-
-      return FALSE;
-    }
-
-  /* Update the real number of samples_per_pixel now that we have a
-   * complete framebuffer */
-  if (n_samples)
-    {
-      GLenum attachment = GL_COLOR_ATTACHMENT0;
-      GLenum pname = GL_TEXTURE_SAMPLES_IMG;
-      int texture_samples;
-
-      GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
-                                                      attachment,
-                                                      pname,
-                                                      &texture_samples) );
-      gl_fbo->samples_per_pixel = texture_samples;
-    }
-
-  return TRUE;
-}
-
-CoglFramebufferDriver *
-_cogl_driver_gl_create_framebuffer_driver (CoglContext                        *context,
-                                           CoglFramebuffer                    *framebuffer,
-                                           const CoglFramebufferDriverConfig  *driver_config,
-                                           GError                            **error)
+cogl_gl_framebuffer_bind (CoglGlFramebuffer *gl_framebuffer,
+                          GLenum             target)
 {
-  CoglOffscreenAllocateFlags allocate_flags;
-  CoglOffscreen *offscreen;
-  CoglGlFramebuffer *gl_framebuffer;
-  CoglGlFramebufferPrivate *priv;
-  CoglGlFbo *gl_fbo;
-  const CoglFramebufferConfig *config;
-  CoglTexture *texture;
-  int texture_level;
-  int level_width;
-  int level_height;
-
-  if (COGL_IS_ONSCREEN (framebuffer))
-    {
-      return g_object_new (COGL_TYPE_GL_FRAMEBUFFER,
-                           "framebuffer", framebuffer,
-                           NULL);
-    }
-
-  offscreen = COGL_OFFSCREEN (framebuffer);
-  texture = cogl_offscreen_get_texture (offscreen);
-  texture_level = cogl_offscreen_get_texture_level (offscreen);
-
-  g_return_val_if_fail (texture_level < _cogl_texture_get_n_levels (texture),
-                        FALSE);
-
-  _cogl_texture_get_level_size (texture,
-                                texture_level,
-                                &level_width,
-                                &level_height,
-                                NULL);
-
-  /* XXX: The framebuffer_object spec isn't clear in defining whether attaching
-   * a texture as a renderbuffer with mipmap filtering enabled while the
-   * mipmaps have not been uploaded should result in an incomplete framebuffer
-   * object. (different drivers make different decisions)
-   *
-   * To avoid an error with drivers that do consider this a problem we
-   * explicitly set non mipmapped filters here. These will later be reset when
-   * the texture is actually used for rendering according to the filters set on
-   * the corresponding CoglPipeline.
-   */
-  _cogl_texture_gl_flush_legacy_texobj_filters (texture,
-                                                GL_NEAREST, GL_NEAREST);
-
-  config = cogl_framebuffer_get_config (framebuffer);
-
-  gl_framebuffer = g_object_new (COGL_TYPE_GL_FRAMEBUFFER,
-                                 "framebuffer", framebuffer,
-                                 NULL);
-  priv = cogl_gl_framebuffer_get_instance_private (gl_framebuffer);
-  gl_fbo = &priv->gl_fbo;
-
-  if ((driver_config->disable_depth_and_stencil &&
-       try_creating_fbo (context,
-                         texture,
-                         texture_level,
-                         level_width,
-                         level_height,
-                         config,
-                         allocate_flags = 0,
-                         gl_fbo)) ||
-
-      (context->have_last_offscreen_allocate_flags &&
-       try_creating_fbo (context,
-                         texture,
-                         texture_level,
-                         level_width,
-                         level_height,
-                         config,
-                         allocate_flags = context->last_offscreen_allocate_flags,
-                         gl_fbo)) ||
-
-      (
-       /* NB: WebGL introduces a DEPTH_STENCIL_ATTACHMENT and doesn't
-        * need an extension to handle _FLAG_DEPTH_STENCIL */
-       (_cogl_has_private_feature
-        (context, COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL) ||
-        _cogl_has_private_feature
-        (context, COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL)) &&
-       try_creating_fbo (context,
-                         texture,
-                         texture_level,
-                         level_width,
-                         level_height,
-                         config,
-                         allocate_flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL,
-                         gl_fbo)) ||
-
-      try_creating_fbo (context,
-                        texture,
-                        texture_level,
-                        level_width,
-                        level_height,
-                        config,
-                        allocate_flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH |
-                        COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL,
-                        gl_fbo) ||
-
-      try_creating_fbo (context,
-                        texture,
-                        texture_level,
-                        level_width,
-                        level_height,
-                        config,
-                        allocate_flags = COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL,
-                        gl_fbo) ||
-
-      try_creating_fbo (context,
-                        texture,
-                        texture_level,
-                        level_width,
-                        level_height,
-                        config,
-                        allocate_flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH,
-                        gl_fbo) ||
-
-      try_creating_fbo (context,
-                        texture,
-                        texture_level,
-                        level_width,
-                        level_height,
-                        config,
-                        allocate_flags = 0,
-                        gl_fbo))
-    {
-      cogl_framebuffer_update_samples_per_pixel (framebuffer,
-                                                 gl_fbo->samples_per_pixel);
-
-      if (!driver_config->disable_depth_and_stencil)
-        {
-          /* Record that the last set of flags succeeded so that we can
-             try that set first next time */
-          context->last_offscreen_allocate_flags = allocate_flags;
-          context->have_last_offscreen_allocate_flags = TRUE;
-        }
-
-      return COGL_FRAMEBUFFER_DRIVER (gl_framebuffer);
-    }
-  else
-    {
-      g_object_unref (gl_framebuffer);
-      g_set_error (error, COGL_FRAMEBUFFER_ERROR,
-                   COGL_FRAMEBUFFER_ERROR_ALLOCATE,
-                   "Failed to create an OpenGL framebuffer object");
-      return NULL;
-    }
-}
-
-static void
-cogl_gl_framebuffer_dispose (GObject *object)
-{
-  CoglGlFramebuffer *gl_framebuffer = COGL_GL_FRAMEBUFFER (object);
-  CoglGlFramebufferPrivate *priv =
-    cogl_gl_framebuffer_get_instance_private (gl_framebuffer);
-  CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (object);
-  CoglFramebuffer *framebuffer =
-    cogl_framebuffer_driver_get_framebuffer (driver);
-  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
-
-  G_OBJECT_CLASS (cogl_gl_framebuffer_parent_class)->dispose (object);
-
-  delete_renderbuffers (ctx, priv->gl_fbo.renderbuffers);
-
-  GE (ctx, glDeleteFramebuffers (1, &priv->gl_fbo.fbo_handle));
+  COGL_GL_FRAMEBUFFER_GET_CLASS (gl_framebuffer)->bind (gl_framebuffer,
+                                                        target);
 }
 
 void
@@ -857,118 +301,6 @@ _cogl_framebuffer_gl_clear (CoglFramebuffer *framebuffer,
   GE (ctx, glClear (gl_buffers));
 }
 
-static inline void
-_cogl_framebuffer_init_bits (CoglFramebuffer *framebuffer)
-{
-  CoglGlFramebuffer *gl_framebuffer =
-    cogl_gl_framebuffer_from_framebuffer (framebuffer);
-  CoglGlFramebufferPrivate *priv =
-    cogl_gl_framebuffer_get_instance_private (gl_framebuffer);
-  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
-
-  if (!priv->dirty_bitmasks)
-    return;
-
-  cogl_framebuffer_allocate (framebuffer, NULL);
-
-  cogl_context_flush_framebuffer_state (ctx,
-                                        framebuffer,
-                                        framebuffer,
-                                        COGL_FRAMEBUFFER_STATE_BIND);
-
-#ifdef HAVE_COGL_GL
-  if ((ctx->driver == COGL_DRIVER_GL3 &&
-       COGL_IS_ONSCREEN (framebuffer)) ||
-      (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS) &&
-       COGL_IS_OFFSCREEN (framebuffer)))
-    {
-      gboolean is_offscreen = COGL_IS_OFFSCREEN (framebuffer);
-      const struct {
-        GLenum attachment, pname;
-        size_t offset;
-      } params[] = {
-        { is_offscreen ? GL_COLOR_ATTACHMENT0 : GL_BACK_LEFT,
-          GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE,
-          offsetof (CoglFramebufferBits, red) },
-        { is_offscreen ? GL_COLOR_ATTACHMENT0 : GL_BACK_LEFT,
-          GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE,
-          offsetof (CoglFramebufferBits, green) },
-        { is_offscreen ? GL_COLOR_ATTACHMENT0 : GL_BACK_LEFT,
-          GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE,
-          offsetof (CoglFramebufferBits, blue) },
-        { is_offscreen ? GL_COLOR_ATTACHMENT0 : GL_BACK_LEFT,
-          GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
-          offsetof (CoglFramebufferBits, alpha) },
-        { is_offscreen ? GL_DEPTH_ATTACHMENT : GL_DEPTH,
-          GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE,
-          offsetof (CoglFramebufferBits, depth) },
-        { is_offscreen ? GL_STENCIL_ATTACHMENT : GL_STENCIL,
-          GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE,
-          offsetof (CoglFramebufferBits, stencil) },
-      };
-      int i;
-
-      for (i = 0; i < G_N_ELEMENTS (params); i++)
-        {
-          int *value =
-            (int *) ((uint8_t *) &priv->bits + params[i].offset);
-          GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
-                                                          params[i].attachment,
-                                                          params[i].pname,
-                                                          value) );
-        }
-    }
-  else
-#endif /* HAVE_COGL_GL */
-    {
-      GE (ctx, glGetIntegerv (GL_RED_BITS, &priv->bits.red));
-      GE (ctx, glGetIntegerv (GL_GREEN_BITS, &priv->bits.green));
-      GE (ctx, glGetIntegerv (GL_BLUE_BITS, &priv->bits.blue));
-      GE (ctx, glGetIntegerv (GL_ALPHA_BITS, &priv->bits.alpha));
-      GE (ctx, glGetIntegerv (GL_DEPTH_BITS, &priv->bits.depth));
-      GE (ctx, glGetIntegerv (GL_STENCIL_BITS, &priv->bits.stencil));
-    }
-
-  /* If we don't have alpha textures then the alpha bits are actually
-   * stored in the red component */
-  if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) &&
-      COGL_IS_OFFSCREEN (framebuffer) &&
-      cogl_framebuffer_get_internal_format (framebuffer) == COGL_PIXEL_FORMAT_A_8)
-    {
-      priv->bits.alpha = priv->bits.red;
-      priv->bits.red = 0;
-    }
-
-  COGL_NOTE (OFFSCREEN,
-             "RGBA/D/S Bits for framebuffer[%p, %s]: %d, %d, %d, %d, %d, %d",
-             framebuffer,
-             COGL_IS_OFFSCREEN (framebuffer) ? "offscreen" : "onscreen",
-             priv->bits.red,
-             priv->bits.blue,
-             priv->bits.green,
-             priv->bits.alpha,
-             priv->bits.depth,
-             priv->bits.stencil);
-
-  priv->dirty_bitmasks = FALSE;
-}
-
-void
-_cogl_framebuffer_gl_query_bits (CoglFramebuffer *framebuffer,
-                                 CoglFramebufferBits *bits)
-{
-  CoglGlFramebuffer *gl_framebuffer =
-    cogl_gl_framebuffer_from_framebuffer (framebuffer);
-  CoglGlFramebufferPrivate *priv =
-    cogl_gl_framebuffer_get_instance_private (gl_framebuffer);
-
-  _cogl_framebuffer_init_bits (framebuffer);
-
-  /* TODO: cache these in some driver specific location not
-   * directly as part of CoglFramebuffer. */
-  *bits = priv->bits;
-}
-
 void
 _cogl_framebuffer_gl_finish (CoglFramebuffer *framebuffer)
 {
@@ -1365,16 +697,9 @@ EXIT:
 static void
 cogl_gl_framebuffer_init (CoglGlFramebuffer *gl_framebuffer)
 {
-  CoglGlFramebufferPrivate *priv =
-    cogl_gl_framebuffer_get_instance_private (gl_framebuffer);
-
-  priv->dirty_bitmasks = TRUE;
 }
 
 static void
 cogl_gl_framebuffer_class_init (CoglGlFramebufferClass *klass)
 {
-  GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-  object_class->dispose = cogl_gl_framebuffer_dispose;
 }
diff --git a/cogl/cogl/driver/gl/cogl-gl-framebuffer-back.c b/cogl/cogl/driver/gl/cogl-gl-framebuffer-back.c
new file mode 100644
index 0000000000..8a49d6f80f
--- /dev/null
+++ b/cogl/cogl/driver/gl/cogl-gl-framebuffer-back.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2007,2008,2009,2012 Intel Corporation.
+ * Copyright (C) 2018 DisplayLink (UK) Ltd.
+ * Copyright (C) 2020 Red Hat
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include "cogl-config.h"
+
+#include "driver/gl/cogl-gl-framebuffer-back.h"
+
+#include <gio/gio.h>
+
+#include "cogl-context-private.h"
+#include "cogl-framebuffer-private.h"
+#include "cogl-offscreen-private.h"
+#include "driver/gl/cogl-util-gl-private.h"
+
+struct _CoglGlFramebufferBack
+{
+  CoglGlFramebuffer parent;
+
+  gboolean dirty_bitmasks;
+  CoglFramebufferBits bits;
+};
+
+G_DEFINE_TYPE (CoglGlFramebufferBack, cogl_gl_framebuffer_back,
+               COGL_TYPE_GL_FRAMEBUFFER)
+
+static gboolean
+ensure_bits_initialized (CoglGlFramebufferBack *gl_framebuffer_back)
+{
+  CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer_back);
+  CoglFramebuffer *framebuffer =
+    cogl_framebuffer_driver_get_framebuffer (driver);
+  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
+  CoglFramebufferBits *bits = &gl_framebuffer_back->bits;
+  g_autoptr (GError) error = NULL;
+
+  if (!gl_framebuffer_back->dirty_bitmasks)
+    return TRUE;
+
+  cogl_context_flush_framebuffer_state (ctx,
+                                        framebuffer,
+                                        framebuffer,
+                                        COGL_FRAMEBUFFER_STATE_BIND);
+
+#ifdef HAVE_COGL_GL
+  if (ctx->driver == COGL_DRIVER_GL3)
+    {
+      const struct {
+        GLenum attachment, pname;
+        size_t offset;
+      } params[] = {
+        { 
+          .attachment = GL_BACK_LEFT,
+          .pname = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE,
+          .offset = offsetof (CoglFramebufferBits, red),
+        },
+        { 
+          .attachment = GL_BACK_LEFT,
+          .pname = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE,
+          .offset = offsetof (CoglFramebufferBits, green),
+        },
+        { 
+          .attachment = GL_BACK_LEFT,
+          .pname = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE,
+          .offset = offsetof (CoglFramebufferBits, blue),
+        },
+        { 
+          .attachment = GL_BACK_LEFT,
+          .pname = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
+          .offset = offsetof (CoglFramebufferBits, alpha),
+        },
+        { 
+          .attachment = GL_DEPTH,
+          .pname = GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE,
+          .offset = offsetof (CoglFramebufferBits, depth),
+        },
+        { 
+          .attachment = GL_STENCIL,
+          .pname = GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE,
+          .offset = offsetof (CoglFramebufferBits, stencil),
+        },
+      };
+      int i;
+
+      for (i = 0; i < G_N_ELEMENTS (params); i++)
+        {
+          int *value =
+            (int *) ((uint8_t *) bits + params[i].offset);
+
+          GE (ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
+                                                          params[i].attachment,
+                                                          params[i].pname,
+                                                          value));
+        }
+    }
+  else
+#endif /* HAVE_COGL_GL */
+    {
+      GE (ctx, glGetIntegerv (GL_RED_BITS, &bits->red));
+      GE (ctx, glGetIntegerv (GL_GREEN_BITS, &bits->green));
+      GE (ctx, glGetIntegerv (GL_BLUE_BITS, &bits->blue));
+      GE (ctx, glGetIntegerv (GL_ALPHA_BITS, &bits->alpha));
+      GE (ctx, glGetIntegerv (GL_DEPTH_BITS, &bits->depth));
+      GE (ctx, glGetIntegerv (GL_STENCIL_BITS, &bits->stencil));
+    }
+
+  COGL_NOTE (FRAMEBUFFER,
+             "RGBA/D/S Bits for framebuffer[%p, %s]: %d, %d, %d, %d, %d, %d",
+             framebuffer,
+             COGL_IS_OFFSCREEN (framebuffer) ? "offscreen" : "onscreen",
+             bits->red,
+             bits->blue,
+             bits->green,
+             bits->alpha,
+             bits->depth,
+             bits->stencil);
+
+  gl_framebuffer_back->dirty_bitmasks = FALSE;
+
+  return TRUE;
+}
+
+static void
+cogl_gl_framebuffer_back_query_bits (CoglFramebufferDriver *driver,
+                                     CoglFramebufferBits   *bits)
+{
+  CoglGlFramebufferBack *gl_framebuffer_back = COGL_GL_FRAMEBUFFER_BACK (driver);
+
+  if (!ensure_bits_initialized (gl_framebuffer_back))
+    return;
+
+  *bits = gl_framebuffer_back->bits;
+}
+
+static void
+cogl_gl_framebuffer_back_bind (CoglGlFramebuffer *gl_framebuffer,
+                               GLenum             target)
+{
+  CoglGlFramebufferBack *gl_framebuffer_back =
+    COGL_GL_FRAMEBUFFER_BACK (gl_framebuffer);
+  CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer_back);
+  CoglFramebuffer *framebuffer =
+    cogl_framebuffer_driver_get_framebuffer (driver);
+  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
+  const CoglWinsysVtable *winsys =
+    _cogl_framebuffer_get_winsys (framebuffer);
+
+  winsys->onscreen_bind (COGL_ONSCREEN (framebuffer));
+
+  GE (ctx, glBindFramebuffer (target, 0));
+
+  /* Initialise the glDrawBuffer state the first time the context
+   * is bound to the default framebuffer. If the winsys is using a
+   * surfaceless context for the initial make current then the
+   * default draw buffer will be GL_NONE so we need to correct
+   * that. We can't do it any earlier because binding GL_BACK when
+   * there is no default framebuffer won't work */
+  if (!ctx->was_bound_to_onscreen)
+    {
+      if (ctx->glDrawBuffer)
+        {
+          GE (ctx, glDrawBuffer (GL_BACK));
+        }
+      else if (ctx->glDrawBuffers)
+        {
+          /* glDrawBuffer isn't available on GLES 3.0 so we need
+           * to be able to use glDrawBuffers as well. On GLES 2
+           * neither is available but the state should always be
+           * GL_BACK anyway so we don't need to set anything. On
+           * desktop GL this must be GL_BACK_LEFT instead of
+           * GL_BACK but as this code path will only be hit for
+           * GLES we can just use GL_BACK. */
+          static const GLenum buffers[] = { GL_BACK };
+
+          GE (ctx, glDrawBuffers (G_N_ELEMENTS (buffers), buffers));
+        }
+
+      ctx->was_bound_to_onscreen = TRUE;
+    }
+}
+
+CoglGlFramebufferBack *
+cogl_gl_framebuffer_back_new (CoglFramebuffer                    *framebuffer,
+                              const CoglFramebufferDriverConfig  *driver_config,
+                              GError                            **error)
+{
+  if (!COGL_IS_ONSCREEN (framebuffer))
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Incompatible framebuffer");
+      return NULL;
+    }
+
+  return g_object_new (COGL_TYPE_GL_FRAMEBUFFER_BACK,
+                       "framebuffer", framebuffer,
+                       NULL);
+}
+
+static void
+cogl_gl_framebuffer_back_init (CoglGlFramebufferBack *gl_framebuffer_back)
+{
+  gl_framebuffer_back->dirty_bitmasks = TRUE;
+}
+
+static void
+cogl_gl_framebuffer_back_class_init (CoglGlFramebufferBackClass *klass)
+{
+  CoglFramebufferDriverClass *driver_class =
+    COGL_FRAMEBUFFER_DRIVER_CLASS (klass);
+  CoglGlFramebufferClass *gl_framebuffer_class =
+    COGL_GL_FRAMEBUFFER_CLASS (klass);
+
+  driver_class->query_bits = cogl_gl_framebuffer_back_query_bits;
+
+  gl_framebuffer_class->bind = cogl_gl_framebuffer_back_bind;
+}
diff --git a/cogl/cogl/driver/gl/cogl-gl-framebuffer-back.h b/cogl/cogl/driver/gl/cogl-gl-framebuffer-back.h
new file mode 100644
index 0000000000..417f8a7388
--- /dev/null
+++ b/cogl/cogl/driver/gl/cogl-gl-framebuffer-back.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 Red Hat
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef COGL_GL_FRAMEBUFFER_BACK_H
+#define COGL_GL_FRAMEBUFFER_BACK_H
+
+#include "cogl-framebuffer-gl-private.h"
+
+#define COGL_TYPE_GL_FRAMEBUFFER_BACK (cogl_gl_framebuffer_back_get_type ())
+G_DECLARE_FINAL_TYPE (CoglGlFramebufferBack, cogl_gl_framebuffer_back,
+                      COGL, GL_FRAMEBUFFER_BACK,
+                      CoglGlFramebuffer)
+
+CoglGlFramebufferBack *
+cogl_gl_framebuffer_back_new (CoglFramebuffer                    *framebuffer,
+                              const CoglFramebufferDriverConfig  *driver_config,
+                              GError                            **error);
+
+#endif /* COGL_GL_FRAMEBUFFER_BACK_H */
diff --git a/cogl/cogl/driver/gl/cogl-gl-framebuffer-fbo.c b/cogl/cogl/driver/gl/cogl-gl-framebuffer-fbo.c
new file mode 100644
index 0000000000..368e04b6fb
--- /dev/null
+++ b/cogl/cogl/driver/gl/cogl-gl-framebuffer-fbo.c
@@ -0,0 +1,611 @@
+/*
+ * Copyright (C) 2007,2008,2009,2012 Intel Corporation.
+ * Copyright (C) 2018 DisplayLink (UK) Ltd.
+ * Copyright (C) 2020 Red Hat
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include "cogl-config.h"
+
+#include "driver/gl/cogl-gl-framebuffer-fbo.h"
+
+#include <gio/gio.h>
+
+#include "cogl-context-private.h"
+#include "cogl-framebuffer-private.h"
+#include "cogl-offscreen-private.h"
+#include "driver/gl/cogl-texture-gl-private.h"
+#include "driver/gl/cogl-util-gl-private.h"
+
+typedef struct _CoglGlFbo
+{
+  GLuint fbo_handle;
+  GList *renderbuffers;
+  int samples_per_pixel;
+} CoglGlFbo;
+
+struct _CoglGlFramebufferFbo
+{
+  CoglGlFramebuffer parent;
+
+  CoglGlFbo gl_fbo;
+
+  gboolean dirty_bitmasks;
+  CoglFramebufferBits bits;
+};
+
+G_DEFINE_TYPE (CoglGlFramebufferFbo, cogl_gl_framebuffer_fbo,
+               COGL_TYPE_GL_FRAMEBUFFER)
+
+static gboolean
+ensure_bits_initialized (CoglGlFramebufferFbo *gl_framebuffer_fbo)
+{
+  CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer_fbo);
+  CoglFramebuffer *framebuffer =
+    cogl_framebuffer_driver_get_framebuffer (driver);
+  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
+  CoglFramebufferBits *bits = &gl_framebuffer_fbo->bits;
+  g_autoptr (GError) error = NULL;
+
+  if (!gl_framebuffer_fbo->dirty_bitmasks)
+    return TRUE;
+
+  cogl_context_flush_framebuffer_state (ctx,
+                                        framebuffer,
+                                        framebuffer,
+                                        COGL_FRAMEBUFFER_STATE_BIND);
+
+#ifdef HAVE_COGL_GL
+  if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_QUERY_FRAMEBUFFER_BITS))
+    {
+      const struct {
+        GLenum attachment, pname;
+        size_t offset;
+      } params[] = {
+        { 
+          .attachment = GL_COLOR_ATTACHMENT0,
+          .pname = GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE,
+          .offset = offsetof (CoglFramebufferBits, red),
+        },
+        { 
+          .attachment = GL_COLOR_ATTACHMENT0,
+          .pname = GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE,
+          .offset = offsetof (CoglFramebufferBits, green),
+        },
+        { 
+          .attachment = GL_COLOR_ATTACHMENT0,
+          .pname = GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE,
+          .offset = offsetof (CoglFramebufferBits, blue),
+        },
+        { 
+          .attachment = GL_COLOR_ATTACHMENT0,
+          .pname = GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE,
+          .offset = offsetof (CoglFramebufferBits, alpha),
+        },
+        { 
+          .attachment = GL_DEPTH_ATTACHMENT,
+          .pname = GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE,
+          .offset = offsetof (CoglFramebufferBits, depth),
+        },
+        { 
+          .attachment = GL_STENCIL_ATTACHMENT,
+          .pname = GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE,
+          .offset = offsetof (CoglFramebufferBits, stencil),
+        },
+      };
+      int i;
+
+      for (i = 0; i < G_N_ELEMENTS (params); i++)
+        {
+          int *value =
+            (int *) ((uint8_t *) bits + params[i].offset);
+
+          GE (ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
+                                                          params[i].attachment,
+                                                          params[i].pname,
+                                                          value));
+        }
+    }
+  else
+#endif /* HAVE_COGL_GL */
+    {
+      GE (ctx, glGetIntegerv (GL_RED_BITS, &bits->red));
+      GE (ctx, glGetIntegerv (GL_GREEN_BITS, &bits->green));
+      GE (ctx, glGetIntegerv (GL_BLUE_BITS, &bits->blue));
+      GE (ctx, glGetIntegerv (GL_ALPHA_BITS, &bits->alpha));
+      GE (ctx, glGetIntegerv (GL_DEPTH_BITS, &bits->depth));
+      GE (ctx, glGetIntegerv (GL_STENCIL_BITS, &bits->stencil));
+    }
+
+  if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES) &&
+      (cogl_framebuffer_get_internal_format (framebuffer) ==
+       COGL_PIXEL_FORMAT_A_8))
+    {
+      bits->alpha = bits->red;
+      bits->red = 0;
+    }
+
+  COGL_NOTE (FRAMEBUFFER,
+             "RGBA/D/S Bits for framebuffer[%p, %s]: %d, %d, %d, %d, %d, %d",
+             framebuffer,
+             COGL_IS_OFFSCREEN (framebuffer) ? "offscreen" : "onscreen",
+             bits->red,
+             bits->blue,
+             bits->green,
+             bits->alpha,
+             bits->depth,
+             bits->stencil);
+
+  gl_framebuffer_fbo->dirty_bitmasks = FALSE;
+
+  return TRUE;
+}
+
+static void
+cogl_gl_framebuffer_fbo_query_bits (CoglFramebufferDriver *driver,
+                                    CoglFramebufferBits   *bits)
+{
+  CoglGlFramebufferFbo *gl_framebuffer_fbo = COGL_GL_FRAMEBUFFER_FBO (driver);
+
+  if (!ensure_bits_initialized (gl_framebuffer_fbo))
+    return;
+
+  *bits = gl_framebuffer_fbo->bits;
+}
+
+static void
+cogl_gl_framebuffer_fbo_bind (CoglGlFramebuffer *gl_framebuffer,
+                              GLenum             target)
+{
+  CoglGlFramebufferFbo *gl_framebuffer_fbo =
+    COGL_GL_FRAMEBUFFER_FBO (gl_framebuffer);
+  CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer_fbo);
+  CoglFramebuffer *framebuffer =
+    cogl_framebuffer_driver_get_framebuffer (driver);
+  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
+
+  GE (ctx, glBindFramebuffer (target, gl_framebuffer_fbo->gl_fbo.fbo_handle));
+}
+
+static GList *
+try_creating_renderbuffers (CoglContext                *ctx,
+                            int                         width,
+                            int                         height,
+                            CoglOffscreenAllocateFlags  flags,
+                            int                         n_samples)
+{
+  GList *renderbuffers = NULL;
+  GLuint gl_depth_stencil_handle;
+
+  if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL)
+    {
+      GLenum format;
+
+      /* WebGL adds a GL_DEPTH_STENCIL_ATTACHMENT and requires that we
+       * use the GL_DEPTH_STENCIL format. */
+      /* Although GL_OES_packed_depth_stencil is mostly equivalent to
+       * GL_EXT_packed_depth_stencil, one notable difference is that
+       * GL_OES_packed_depth_stencil doesn't allow GL_DEPTH_STENCIL to
+       * be passed as an internal format to glRenderbufferStorage.
+       */
+      if (_cogl_has_private_feature
+          (ctx, COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL))
+        format = GL_DEPTH_STENCIL;
+      else
+        {
+          g_return_val_if_fail (
+            _cogl_has_private_feature (ctx,
+              COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL),
+            NULL);
+          format = GL_DEPTH24_STENCIL8;
+        }
+
+      /* Create a renderbuffer for depth and stenciling */
+      GE (ctx, glGenRenderbuffers (1, &gl_depth_stencil_handle));
+      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_stencil_handle));
+      if (n_samples)
+        GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
+                                                      n_samples,
+                                                      format,
+                                                      width, height));
+      else
+        GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, format,
+                                        width, height));
+      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
+
+
+      GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
+                                          GL_STENCIL_ATTACHMENT,
+                                          GL_RENDERBUFFER,
+                                          gl_depth_stencil_handle));
+      GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
+                                          GL_DEPTH_ATTACHMENT,
+                                          GL_RENDERBUFFER,
+                                          gl_depth_stencil_handle));
+      renderbuffers =
+        g_list_prepend (renderbuffers,
+                        GUINT_TO_POINTER (gl_depth_stencil_handle));
+    }
+
+  if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH)
+    {
+      GLuint gl_depth_handle;
+
+      GE (ctx, glGenRenderbuffers (1, &gl_depth_handle));
+      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_depth_handle));
+      /* For now we just ask for GL_DEPTH_COMPONENT16 since this is all that's
+       * available under GLES */
+      if (n_samples)
+        GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
+                                                      n_samples,
+                                                      GL_DEPTH_COMPONENT16,
+                                                      width, height));
+      else
+        GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
+                                        width, height));
+      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
+      GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
+                                          GL_DEPTH_ATTACHMENT,
+                                          GL_RENDERBUFFER, gl_depth_handle));
+      renderbuffers =
+        g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_depth_handle));
+    }
+
+  if (flags & COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL)
+    {
+      GLuint gl_stencil_handle;
+
+      GE (ctx, glGenRenderbuffers (1, &gl_stencil_handle));
+      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle));
+      if (n_samples)
+        GE (ctx, glRenderbufferStorageMultisampleIMG (GL_RENDERBUFFER,
+                                                      n_samples,
+                                                      GL_STENCIL_INDEX8,
+                                                      width, height));
+      else
+        GE (ctx, glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8,
+                                        width, height));
+      GE (ctx, glBindRenderbuffer (GL_RENDERBUFFER, 0));
+      GE (ctx, glFramebufferRenderbuffer (GL_FRAMEBUFFER,
+                                          GL_STENCIL_ATTACHMENT,
+                                          GL_RENDERBUFFER, gl_stencil_handle));
+      renderbuffers =
+        g_list_prepend (renderbuffers, GUINT_TO_POINTER (gl_stencil_handle));
+    }
+
+  return renderbuffers;
+}
+
+static void
+delete_renderbuffers (CoglContext *ctx,
+                      GList       *renderbuffers)
+{
+  GList *l;
+
+  for (l = renderbuffers; l; l = l->next)
+    {
+      GLuint renderbuffer = GPOINTER_TO_UINT (l->data);
+      GE (ctx, glDeleteRenderbuffers (1, &renderbuffer));
+    }
+
+  g_list_free (renderbuffers);
+}
+
+/*
+ * NB: This function may be called with a standalone GLES2 context
+ * bound so we can create a shadow framebuffer that wraps the same
+ * CoglTexture as the given CoglOffscreen. This function shouldn't
+ * modify anything in
+ */
+static gboolean
+try_creating_fbo (CoglContext                 *ctx,
+                  CoglTexture                 *texture,
+                  int                          texture_level,
+                  int                          texture_level_width,
+                  int                          texture_level_height,
+                  const CoglFramebufferConfig *config,
+                  CoglOffscreenAllocateFlags   flags,
+                  CoglGlFbo                   *gl_fbo)
+{
+  GLuint tex_gl_handle;
+  GLenum tex_gl_target;
+  GLenum status;
+  int n_samples;
+
+  if (!cogl_texture_get_gl_texture (texture, &tex_gl_handle, &tex_gl_target))
+    return FALSE;
+
+  if (tex_gl_target != GL_TEXTURE_2D
+#ifdef HAVE_COGL_GL
+      && tex_gl_target != GL_TEXTURE_RECTANGLE_ARB
+#endif
+      )
+    return FALSE;
+
+  if (config->samples_per_pixel)
+    {
+      if (!ctx->glFramebufferTexture2DMultisampleIMG)
+        return FALSE;
+      n_samples = config->samples_per_pixel;
+    }
+  else
+    n_samples = 0;
+
+  /* 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->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_BIND;
+
+  /* Generate framebuffer */
+  ctx->glGenFramebuffers (1, &gl_fbo->fbo_handle);
+  GE (ctx, glBindFramebuffer (GL_FRAMEBUFFER, gl_fbo->fbo_handle));
+
+  if (n_samples)
+    {
+      GE (ctx, glFramebufferTexture2DMultisampleIMG (GL_FRAMEBUFFER,
+                                                     GL_COLOR_ATTACHMENT0,
+                                                     tex_gl_target, tex_gl_handle,
+                                                     n_samples,
+                                                     texture_level));
+    }
+  else
+    GE (ctx, glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                     tex_gl_target, tex_gl_handle,
+                                     texture_level));
+
+  if (flags)
+    {
+      gl_fbo->renderbuffers =
+        try_creating_renderbuffers (ctx,
+                                    texture_level_width,
+                                    texture_level_height,
+                                    flags,
+                                    n_samples);
+    }
+
+  /* Make sure it's complete */
+  status = ctx->glCheckFramebufferStatus (GL_FRAMEBUFFER);
+
+  if (status != GL_FRAMEBUFFER_COMPLETE)
+    {
+      GE (ctx, glDeleteFramebuffers (1, &gl_fbo->fbo_handle));
+
+      delete_renderbuffers (ctx, gl_fbo->renderbuffers);
+      gl_fbo->renderbuffers = NULL;
+
+      return FALSE;
+    }
+
+  /* Update the real number of samples_per_pixel now that we have a
+   * complete framebuffer */
+  if (n_samples)
+    {
+      GLenum attachment = GL_COLOR_ATTACHMENT0;
+      GLenum pname = GL_TEXTURE_SAMPLES_IMG;
+      int texture_samples;
+
+      GE( ctx, glGetFramebufferAttachmentParameteriv (GL_FRAMEBUFFER,
+                                                      attachment,
+                                                      pname,
+                                                      &texture_samples) );
+      gl_fbo->samples_per_pixel = texture_samples;
+    }
+
+  return TRUE;
+}
+
+CoglGlFramebufferFbo *
+cogl_gl_framebuffer_fbo_new (CoglFramebuffer                    *framebuffer,
+                             const CoglFramebufferDriverConfig  *driver_config,
+                             GError                            **error)
+{
+  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
+  CoglOffscreen *offscreen;
+  CoglTexture *texture;
+  int texture_level;
+  int level_width;
+  int level_height;
+  const CoglFramebufferConfig *config;
+  CoglGlFbo *gl_fbo;
+  CoglGlFramebufferFbo *gl_framebuffer_fbo;
+  CoglOffscreenAllocateFlags allocate_flags;
+
+  if (!COGL_IS_OFFSCREEN (framebuffer))
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "Incompatible framebuffer");
+      return NULL;
+    }
+
+  offscreen = COGL_OFFSCREEN (framebuffer);
+  texture = cogl_offscreen_get_texture (offscreen);
+  texture_level = cogl_offscreen_get_texture_level (offscreen);
+
+  g_return_val_if_fail (texture_level < _cogl_texture_get_n_levels (texture),
+                        NULL);
+
+  _cogl_texture_get_level_size (texture,
+                                texture_level,
+                                &level_width,
+                                &level_height,
+                                NULL);
+
+  /* XXX: The framebuffer_object spec isn't clear in defining whether attaching
+   * a texture as a renderbuffer with mipmap filtering enabled while the
+   * mipmaps have not been uploaded should result in an incomplete framebuffer
+   * object. (different drivers make different decisions)
+   *
+   * To avoid an error with drivers that do consider this a problem we
+   * explicitly set non mipmapped filters here. These will later be reset when
+   * the texture is actually used for rendering according to the filters set on
+   * the corresponding CoglPipeline.
+   */
+  _cogl_texture_gl_flush_legacy_texobj_filters (texture,
+                                                GL_NEAREST, GL_NEAREST);
+
+  config = cogl_framebuffer_get_config (framebuffer);
+
+  gl_framebuffer_fbo = g_object_new (COGL_TYPE_GL_FRAMEBUFFER_FBO,
+                                     "framebuffer", framebuffer,
+                                     NULL);
+  gl_fbo = &gl_framebuffer_fbo->gl_fbo;
+
+  if ((driver_config->disable_depth_and_stencil &&
+       try_creating_fbo (context,
+                         texture,
+                         texture_level,
+                         level_width,
+                         level_height,
+                         config,
+                         allocate_flags = 0,
+                         gl_fbo)) ||
+
+      (context->have_last_offscreen_allocate_flags &&
+       try_creating_fbo (context,
+                         texture,
+                         texture_level,
+                         level_width,
+                         level_height,
+                         config,
+                         allocate_flags = context->last_offscreen_allocate_flags,
+                         gl_fbo)) ||
+
+      (
+       /* NB: WebGL introduces a DEPTH_STENCIL_ATTACHMENT and doesn't
+        * need an extension to handle _FLAG_DEPTH_STENCIL */
+       (_cogl_has_private_feature
+        (context, COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL) ||
+        _cogl_has_private_feature
+        (context, COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL)) &&
+       try_creating_fbo (context,
+                         texture,
+                         texture_level,
+                         level_width,
+                         level_height,
+                         config,
+                         allocate_flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH_STENCIL,
+                         gl_fbo)) ||
+
+      try_creating_fbo (context,
+                        texture,
+                        texture_level,
+                        level_width,
+                        level_height,
+                        config,
+                        allocate_flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH |
+                        COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL,
+                        gl_fbo) ||
+
+      try_creating_fbo (context,
+                        texture,
+                        texture_level,
+                        level_width,
+                        level_height,
+                        config,
+                        allocate_flags = COGL_OFFSCREEN_ALLOCATE_FLAG_STENCIL,
+                        gl_fbo) ||
+
+      try_creating_fbo (context,
+                        texture,
+                        texture_level,
+                        level_width,
+                        level_height,
+                        config,
+                        allocate_flags = COGL_OFFSCREEN_ALLOCATE_FLAG_DEPTH,
+                        gl_fbo) ||
+
+      try_creating_fbo (context,
+                        texture,
+                        texture_level,
+                        level_width,
+                        level_height,
+                        config,
+                        allocate_flags = 0,
+                        gl_fbo))
+    {
+      cogl_framebuffer_update_samples_per_pixel (framebuffer,
+                                                 gl_fbo->samples_per_pixel);
+
+      if (!driver_config->disable_depth_and_stencil)
+        {
+          /* Record that the last set of flags succeeded so that we can
+             try that set first next time */
+          context->last_offscreen_allocate_flags = allocate_flags;
+          context->have_last_offscreen_allocate_flags = TRUE;
+        }
+
+      return gl_framebuffer_fbo;
+    }
+  else
+    {
+      g_object_unref (gl_framebuffer_fbo);
+      g_set_error (error, COGL_FRAMEBUFFER_ERROR,
+                   COGL_FRAMEBUFFER_ERROR_ALLOCATE,
+                   "Failed to create an OpenGL framebuffer object");
+      return NULL;
+    }
+}
+
+static void
+cogl_gl_framebuffer_fbo_dispose (GObject *object)
+{
+  CoglGlFramebufferFbo *gl_framebuffer_fbo = COGL_GL_FRAMEBUFFER_FBO (object);
+  CoglFramebufferDriver *driver = COGL_FRAMEBUFFER_DRIVER (gl_framebuffer_fbo);
+  CoglFramebuffer *framebuffer =
+    cogl_framebuffer_driver_get_framebuffer (driver);
+  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
+
+  delete_renderbuffers (ctx, gl_framebuffer_fbo->gl_fbo.renderbuffers);
+  gl_framebuffer_fbo->gl_fbo.renderbuffers = NULL;
+
+  if (gl_framebuffer_fbo->gl_fbo.fbo_handle)
+    {
+      GE (ctx, glDeleteFramebuffers (1,
+                                     &gl_framebuffer_fbo->gl_fbo.fbo_handle));
+      gl_framebuffer_fbo->gl_fbo.fbo_handle = 0;
+    }
+
+  G_OBJECT_CLASS (cogl_gl_framebuffer_fbo_parent_class)->dispose (object);
+}
+
+static void
+cogl_gl_framebuffer_fbo_init (CoglGlFramebufferFbo *gl_framebuffer_fbo)
+{
+  gl_framebuffer_fbo->dirty_bitmasks = TRUE;
+}
+
+static void
+cogl_gl_framebuffer_fbo_class_init (CoglGlFramebufferFboClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  CoglFramebufferDriverClass *driver_class =
+    COGL_FRAMEBUFFER_DRIVER_CLASS (klass);
+  CoglGlFramebufferClass *gl_framebuffer_class =
+    COGL_GL_FRAMEBUFFER_CLASS (klass);
+
+  object_class->dispose = cogl_gl_framebuffer_fbo_dispose;
+
+  driver_class->query_bits = cogl_gl_framebuffer_fbo_query_bits;
+
+  gl_framebuffer_class->bind = cogl_gl_framebuffer_fbo_bind;
+}
diff --git a/cogl/cogl/driver/gl/cogl-gl-framebuffer-fbo.h b/cogl/cogl/driver/gl/cogl-gl-framebuffer-fbo.h
new file mode 100644
index 0000000000..896847cf89
--- /dev/null
+++ b/cogl/cogl/driver/gl/cogl-gl-framebuffer-fbo.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 Red Hat
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef COGL_GL_FRAMEBUFFER_FBO_H
+#define COGL_GL_FRAMEBUFFER_FBO_H
+
+#include "driver/gl/cogl-framebuffer-gl-private.h"
+
+#define COGL_TYPE_GL_FRAMEBUFFER_FBO (cogl_gl_framebuffer_fbo_get_type ())
+G_DECLARE_FINAL_TYPE (CoglGlFramebufferFbo, cogl_gl_framebuffer_fbo,
+                      COGL, GL_FRAMEBUFFER_FBO,
+                      CoglGlFramebuffer)
+
+CoglGlFramebufferFbo *
+cogl_gl_framebuffer_fbo_new (CoglFramebuffer                    *framebuffer,
+                             const CoglFramebufferDriverConfig  *driver_config,
+                             GError                            **error);
+
+#endif /* COGL_GL_FRAMEBUFFER_FBO_H */
diff --git a/cogl/cogl/driver/gl/cogl-util-gl-private.h b/cogl/cogl/driver/gl/cogl-util-gl-private.h
index 6bada2cd02..0b7eaa772e 100644
--- a/cogl/cogl/driver/gl/cogl-util-gl-private.h
+++ b/cogl/cogl/driver/gl/cogl-util-gl-private.h
@@ -146,4 +146,87 @@ _cogl_gl_util_parse_gl_version (const char *version_string,
 CoglGraphicsResetStatus
 _cogl_gl_get_graphics_reset_status (CoglContext *context);
 
+#ifndef GL_FRAMEBUFFER
+#define GL_FRAMEBUFFER         0x8D40
+#endif
+#ifndef GL_RENDERBUFFER
+#define GL_RENDERBUFFER                0x8D41
+#endif
+#ifndef GL_STENCIL_ATTACHMENT
+#define GL_STENCIL_ATTACHMENT  0x8D00
+#endif
+#ifndef GL_COLOR_ATTACHMENT0
+#define GL_COLOR_ATTACHMENT0   0x8CE0
+#endif
+#ifndef GL_FRAMEBUFFER_COMPLETE
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#endif
+#ifndef GL_STENCIL_INDEX8
+#define GL_STENCIL_INDEX8       0x8D48
+#endif
+#ifndef GL_DEPTH_STENCIL
+#define GL_DEPTH_STENCIL        0x84F9
+#endif
+#ifndef GL_DEPTH24_STENCIL8
+#define GL_DEPTH24_STENCIL8     0x88F0
+#endif
+#ifndef GL_DEPTH_ATTACHMENT
+#define GL_DEPTH_ATTACHMENT     0x8D00
+#endif
+#ifndef GL_DEPTH_STENCIL_ATTACHMENT
+#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+#endif
+#ifndef GL_DEPTH_COMPONENT16
+#define GL_DEPTH_COMPONENT16    0x81A5
+#endif
+#ifndef GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE
+#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE      0x8212
+#endif
+#ifndef GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE
+#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE    0x8213
+#endif
+#ifndef GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE
+#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE     0x8214
+#endif
+#ifndef GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE
+#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE    0x8215
+#endif
+#ifndef GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE
+#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE    0x8216
+#endif
+#ifndef GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE
+#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE  0x8217
+#endif
+#ifndef GL_READ_FRAMEBUFFER
+#define GL_READ_FRAMEBUFFER               0x8CA8
+#endif
+#ifndef GL_DRAW_FRAMEBUFFER
+#define GL_DRAW_FRAMEBUFFER               0x8CA9
+#endif
+#ifndef GL_TEXTURE_SAMPLES_IMG
+#define GL_TEXTURE_SAMPLES_IMG            0x9136
+#endif
+#ifndef GL_PACK_INVERT_MESA
+#define GL_PACK_INVERT_MESA 0x8758
+#endif
+#ifndef GL_PACK_REVERSE_ROW_ORDER_ANGLE
+#define GL_PACK_REVERSE_ROW_ORDER_ANGLE 0x93A4
+#endif
+#ifndef GL_BACK_LEFT
+#define GL_BACK_LEFT                           0x0402
+#endif
+#ifndef GL_BACK_RIGHT
+#define GL_BACK_RIGHT                          0x0403
+#endif
+
+#ifndef GL_COLOR
+#define GL_COLOR 0x1800
+#endif
+#ifndef GL_DEPTH
+#define GL_DEPTH 0x1801
+#endif
+#ifndef GL_STENCIL
+#define GL_STENCIL 0x1802
+#endif
+
 #endif /* _COGL_UTIL_GL_PRIVATE_H_ */
diff --git a/cogl/cogl/driver/gl/cogl-util-gl.c b/cogl/cogl/driver/gl/cogl-util-gl.c
index 2c1c4e5441..9b59bef1d6 100644
--- a/cogl/cogl/driver/gl/cogl-util-gl.c
+++ b/cogl/cogl/driver/gl/cogl-util-gl.c
@@ -35,6 +35,8 @@
 #include "cogl-types.h"
 #include "cogl-context-private.h"
 #include "driver/gl/cogl-framebuffer-gl-private.h"
+#include "driver/gl/cogl-gl-framebuffer-fbo.h"
+#include "driver/gl/cogl-gl-framebuffer-back.h"
 #include "driver/gl/cogl-pipeline-opengl-private.h"
 #include "driver/gl/cogl-util-gl-private.h"
 
@@ -131,6 +133,46 @@ _cogl_driver_gl_context_deinit (CoglContext *context)
   g_free (context->driver_context);
 }
 
+CoglFramebufferDriver *
+_cogl_driver_gl_create_framebuffer_driver (CoglContext                        *context,
+                                           CoglFramebuffer                    *framebuffer,
+                                           const CoglFramebufferDriverConfig  *driver_config,
+                                           GError                            **error)
+{
+  g_return_val_if_fail (driver_config, NULL);
+
+  switch (driver_config->type)
+    {
+    case COGL_FRAMEBUFFER_DRIVER_TYPE_FBO:
+      {
+        CoglGlFramebufferFbo *gl_framebuffer_fbo;
+
+        gl_framebuffer_fbo = cogl_gl_framebuffer_fbo_new (framebuffer,
+                                                          driver_config,
+                                                          error);
+        if (!gl_framebuffer_fbo)
+          return NULL;
+
+        return COGL_FRAMEBUFFER_DRIVER (gl_framebuffer_fbo);
+      }
+    case COGL_FRAMEBUFFER_DRIVER_TYPE_BACK:
+      {
+        CoglGlFramebufferBack *gl_framebuffer_back;
+
+        gl_framebuffer_back = cogl_gl_framebuffer_back_new (framebuffer,
+                                                            driver_config,
+                                                            error);
+        if (!gl_framebuffer_back)
+          return NULL;
+
+        return COGL_FRAMEBUFFER_DRIVER (gl_framebuffer_back);
+      }
+    }
+
+  g_assert_not_reached ();
+  return NULL;
+}
+
 void
 _cogl_driver_gl_flush_framebuffer_state (CoglContext          *ctx,
                                          CoglFramebuffer      *draw_buffer,
@@ -138,6 +180,7 @@ _cogl_driver_gl_flush_framebuffer_state (CoglContext          *ctx,
                                          CoglFramebufferState  state)
 {
   CoglGlFramebuffer *draw_gl_framebuffer;
+  CoglGlFramebuffer *read_gl_framebuffer;
   unsigned long differences;
 
   /* We can assume that any state that has changed for the current
@@ -193,13 +236,20 @@ _cogl_driver_gl_flush_framebuffer_state (CoglContext          *ctx,
   if (G_UNLIKELY (!cogl_framebuffer_is_allocated (read_buffer)))
     cogl_framebuffer_allocate (read_buffer, NULL);
 
+  draw_gl_framebuffer =
+    COGL_GL_FRAMEBUFFER (cogl_framebuffer_get_driver (draw_buffer));
+  read_gl_framebuffer =
+    COGL_GL_FRAMEBUFFER (cogl_framebuffer_get_driver (read_buffer));
+
   /* 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);
+        {
+          cogl_gl_framebuffer_bind (draw_gl_framebuffer, GL_FRAMEBUFFER);
+        }
       else
         {
           /* NB: Currently we only take advantage of binding separate
@@ -207,15 +257,13 @@ _cogl_driver_gl_flush_framebuffer_state (CoglContext          *ctx,
           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);
+          cogl_gl_framebuffer_bind (draw_gl_framebuffer, GL_DRAW_FRAMEBUFFER);
+          cogl_gl_framebuffer_bind (read_gl_framebuffer, GL_READ_FRAMEBUFFER);
         }
 
       differences &= ~COGL_FRAMEBUFFER_STATE_BIND;
     }
 
-  draw_gl_framebuffer =
-    COGL_GL_FRAMEBUFFER (cogl_framebuffer_get_driver (draw_buffer));
   cogl_gl_framebuffer_flush_state_differences (draw_gl_framebuffer,
                                                differences);
 
diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
index 31f6c898f7..bcb7f566ed 100644
--- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -572,7 +572,6 @@ _cogl_driver_gl =
     _cogl_driver_gl_create_framebuffer_driver,
     _cogl_driver_gl_flush_framebuffer_state,
     _cogl_framebuffer_gl_clear,
-    _cogl_framebuffer_gl_query_bits,
     _cogl_framebuffer_gl_finish,
     _cogl_framebuffer_gl_flush,
     _cogl_framebuffer_gl_discard_buffers,
diff --git a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
index 506d5250b6..a0688bd51e 100644
--- a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -460,7 +460,6 @@ _cogl_driver_gles =
     _cogl_driver_gl_create_framebuffer_driver,
     _cogl_driver_gl_flush_framebuffer_state,
     _cogl_framebuffer_gl_clear,
-    _cogl_framebuffer_gl_query_bits,
     _cogl_framebuffer_gl_finish,
     _cogl_framebuffer_gl_flush,
     _cogl_framebuffer_gl_discard_buffers,
diff --git a/cogl/cogl/driver/nop/cogl-driver-nop.c b/cogl/cogl/driver/nop/cogl-driver-nop.c
index 7dfc1c5bcc..c52a2c2996 100644
--- a/cogl/cogl/driver/nop/cogl-driver-nop.c
+++ b/cogl/cogl/driver/nop/cogl-driver-nop.c
@@ -100,7 +100,6 @@ _cogl_driver_nop =
     _cogl_driver_nop_create_framebuffer_driver,
     _cogl_driver_nop_flush_framebuffer_state,
     _cogl_framebuffer_nop_clear,
-    _cogl_framebuffer_nop_query_bits,
     _cogl_framebuffer_nop_finish,
     _cogl_framebuffer_nop_flush,
     _cogl_framebuffer_nop_discard_buffers,
diff --git a/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h 
b/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h
index 19013c7528..a1cf77c894 100644
--- a/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h
+++ b/cogl/cogl/driver/nop/cogl-framebuffer-nop-private.h
@@ -45,10 +45,6 @@ _cogl_framebuffer_nop_clear (CoglFramebuffer *framebuffer,
                             float blue,
                             float alpha);
 
-void
-_cogl_framebuffer_nop_query_bits (CoglFramebuffer *framebuffer,
-                                  CoglFramebufferBits *bits);
-
 void
 _cogl_framebuffer_nop_finish (CoglFramebuffer *framebuffer);
 
diff --git a/cogl/cogl/driver/nop/cogl-framebuffer-nop.c b/cogl/cogl/driver/nop/cogl-framebuffer-nop.c
index d7fc293f23..70488a1b50 100644
--- a/cogl/cogl/driver/nop/cogl-framebuffer-nop.c
+++ b/cogl/cogl/driver/nop/cogl-framebuffer-nop.c
@@ -45,13 +45,6 @@ _cogl_framebuffer_nop_clear (CoglFramebuffer *framebuffer,
 {
 }
 
-void
-_cogl_framebuffer_nop_query_bits (CoglFramebuffer *framebuffer,
-                                  CoglFramebufferBits *bits)
-{
-  memset (bits, 0, sizeof (CoglFramebufferBits));
-}
-
 void
 _cogl_framebuffer_nop_finish (CoglFramebuffer *framebuffer)
 {
diff --git a/cogl/cogl/driver/nop/cogl-nop-framebuffer.c b/cogl/cogl/driver/nop/cogl-nop-framebuffer.c
index 85bed95a7c..3e155f3c3d 100644
--- a/cogl/cogl/driver/nop/cogl-nop-framebuffer.c
+++ b/cogl/cogl/driver/nop/cogl-nop-framebuffer.c
@@ -27,6 +27,8 @@
 
 #include "cogl-nop-framebuffer.h"
 
+#include "cogl-framebuffer-private.h"
+
 struct _CoglNopFramebuffer
 {
   CoglFramebufferDriver parent;
@@ -35,6 +37,13 @@ struct _CoglNopFramebuffer
 G_DEFINE_TYPE (CoglNopFramebuffer, cogl_nop_framebuffer,
                COGL_TYPE_FRAMEBUFFER_DRIVER)
 
+static void
+cogl_nop_framebuffer_query_bits (CoglFramebufferDriver *driver,
+                                 CoglFramebufferBits   *bits)
+{
+  memset (bits, 0, sizeof (CoglFramebufferBits));
+}
+
 static void
 cogl_nop_framebuffer_init (CoglNopFramebuffer *nop_framebuffer)
 {
@@ -43,4 +52,8 @@ cogl_nop_framebuffer_init (CoglNopFramebuffer *nop_framebuffer)
 static void
 cogl_nop_framebuffer_class_init (CoglNopFramebufferClass *klass)
 {
+  CoglFramebufferDriverClass *driver_class =
+    COGL_FRAMEBUFFER_DRIVER_CLASS (klass);
+
+  driver_class->query_bits = cogl_nop_framebuffer_query_bits;
 }
diff --git a/cogl/cogl/meson.build b/cogl/cogl/meson.build
index 638f5a8273..27ad72b2d4 100644
--- a/cogl/cogl/meson.build
+++ b/cogl/cogl/meson.build
@@ -155,6 +155,10 @@ cogl_common_driver_sources = [
   'driver/gl/cogl-util-gl.c',
   'driver/gl/cogl-framebuffer-gl-private.h',
   'driver/gl/cogl-framebuffer-gl.c',
+  'driver/gl/cogl-gl-framebuffer-back.c',
+  'driver/gl/cogl-gl-framebuffer-back.h',
+  'driver/gl/cogl-gl-framebuffer-fbo.c',
+  'driver/gl/cogl-gl-framebuffer-fbo.h',
   'driver/gl/cogl-texture-gl-private.h',
   'driver/gl/cogl-texture-gl.c',
   'driver/gl/cogl-texture-2d-gl-private.h',
diff --git a/cogl/cogl/winsys/cogl-onscreen-glx.c b/cogl/cogl/winsys/cogl-onscreen-glx.c
index b578494b09..24ee9cddcb 100644
--- a/cogl/cogl/winsys/cogl-onscreen-glx.c
+++ b/cogl/cogl/winsys/cogl-onscreen-glx.c
@@ -1131,8 +1131,14 @@ cogl_onscreen_glx_new (CoglContext *context,
                        int          width,
                        int          height)
 {
+  CoglFramebufferDriverConfig driver_config;
+
+  driver_config = (CoglFramebufferDriverConfig) {
+    .type = COGL_FRAMEBUFFER_DRIVER_TYPE_BACK,
+  };
   return g_object_new (COGL_TYPE_ONSCREEN_GLX,
                        "context", context,
+                       "driver-config", &driver_config,
                        "width", width,
                        "height", height,
                        NULL);
diff --git a/cogl/cogl/winsys/cogl-onscreen-xlib.c b/cogl/cogl/winsys/cogl-onscreen-xlib.c
index 97540639a1..8eaf1976dd 100644
--- a/cogl/cogl/winsys/cogl-onscreen-xlib.c
+++ b/cogl/cogl/winsys/cogl-onscreen-xlib.c
@@ -338,8 +338,14 @@ cogl_onscreen_xlib_new (CoglContext *context,
                         int          width,
                         int          height)
 {
+  CoglFramebufferDriverConfig driver_config;
+
+  driver_config = (CoglFramebufferDriverConfig) {
+    .type = COGL_FRAMEBUFFER_DRIVER_TYPE_BACK,
+  };
   return g_object_new (COGL_TYPE_ONSCREEN_XLIB,
                        "context", context,
+                       "driver-config", &driver_config,
                        "width", width,
                        "height", height,
                        NULL);
diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c
index 45bd769bcb..e21d905450 100644
--- a/src/backends/native/meta-onscreen-native.c
+++ b/src/backends/native/meta-onscreen-native.c
@@ -1979,9 +1979,14 @@ meta_onscreen_native_new (MetaRendererNative *renderer_native,
                           int                 height)
 {
   MetaOnscreenNative *onscreen_native;
+  CoglFramebufferDriverConfig driver_config;
 
+  driver_config = (CoglFramebufferDriverConfig) {
+    .type = COGL_FRAMEBUFFER_DRIVER_TYPE_BACK,
+  };
   onscreen_native = g_object_new (META_TYPE_ONSCREEN_NATIVE,
                                   "context", cogl_context,
+                                  "driver-config", &driver_config,
                                   "width", width,
                                   "height", height,
                                   NULL);


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