[Cogl] [PATCH] texture-2d: factor out all GL specific code

Robert Bragg robert at sixbynine.org
Mon Sep 24 07:48:08 PDT 2012


From: Robert Bragg <robert at linux.intel.com>

This factors out all of the OpenGL specific code in cogl-texture-2d.c
into cogl-texture-2d-gl.c and where necessary adds indirection through
the CoglDriver vtable so that we can eventually start to experiment with
non-OpenGL backends for Cogl.
---
 cogl/Makefile.am                            |    3 +
 cogl/cogl-driver.h                          |  108 +++++
 cogl/cogl-gles2-context.c                   |   13 +-
 cogl/cogl-texture-2d-gl.h                   |   75 ++++
 cogl/cogl-texture-2d-private.h              |   10 +
 cogl/cogl-texture-2d-sliced.c               |   13 +-
 cogl/cogl-texture-2d.c                      |  521 ++++---------------------
 cogl/cogl-texture-2d.h                      |   34 +--
 cogl/cogl-texture.c                         |   13 +-
 cogl/cogl.h                                 |    1 +
 cogl/driver/gl/cogl-texture-2d-gl-private.h |  112 ++++++
 cogl/driver/gl/cogl-texture-2d-gl.c         |  575 +++++++++++++++++++++++++++
 cogl/driver/gl/gl/cogl-driver-gl.c          |   14 +
 cogl/driver/gl/gles/cogl-driver-gles.c      |   14 +
 14 files changed, 1012 insertions(+), 494 deletions(-)
 create mode 100644 cogl/cogl-texture-2d-gl.h
 create mode 100644 cogl/driver/gl/cogl-texture-2d-gl-private.h
 create mode 100644 cogl/driver/gl/cogl-texture-2d-gl.c

diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 654d10b..6c43b96 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -97,6 +97,7 @@ cogl_experimental_h = \
 	$(srcdir)/cogl-poll.h			\
 	$(srcdir)/cogl-texture-3d.h             \
 	$(srcdir)/cogl-texture-2d.h             \
+	$(srcdir)/cogl-texture-2d-gl.h 		\
 	$(srcdir)/cogl-texture-rectangle.h      \
 	$(srcdir)/cogl-texture-2d-sliced.h      \
 	$(srcdir)/cogl-sub-texture.h            \
@@ -124,6 +125,8 @@ cogl_gl_prototypes_h = \
 # driver sources
 cogl_driver_sources = \
 	$(srcdir)/driver/gl/cogl-framebuffer-gl.c \
+	$(srcdir)/driver/gl/cogl-texture-2d-gl-private.h \
+	$(srcdir)/driver/gl/cogl-texture-2d-gl.c \
 	$(srcdir)/driver/gl/cogl-pipeline-opengl.c \
 	$(srcdir)/driver/gl/cogl-pipeline-opengl-private.h \
 	$(srcdir)/driver/gl/cogl-pipeline-fragend-glsl.c \
diff --git a/cogl/cogl-driver.h b/cogl/cogl-driver.h
index 63b737d..bfedbff 100644
--- a/cogl/cogl-driver.h
+++ b/cogl/cogl-driver.h
@@ -32,11 +32,15 @@ typedef struct _CoglDriverVtable CoglDriverVtable;
 
 struct _CoglDriverVtable
 {
+  /* TODO: factor this out since this is OpenGL specific and
+   * so can be ignored by non-OpenGL drivers. */
   CoglBool
   (* pixel_format_from_gl_internal) (CoglContext *context,
                                      GLenum gl_int_format,
                                      CoglPixelFormat *out_format);
 
+  /* TODO: factor this out since this is OpenGL specific and
+   * so can be ignored by non-OpenGL drivers. */
   CoglPixelFormat
   (* pixel_format_to_gl) (CoglContext *context,
                           CoglPixelFormat format,
@@ -102,6 +106,110 @@ struct _CoglDriverVtable
                                            CoglAttribute **attributes,
                                            int n_attributes,
                                            CoglDrawFlags flags);
+
+  /* Destroys any driver specific resources associated with the given
+   * 2D texture. */
+  void
+  (* texture_2d_free) (CoglTexture2D *tex_2d);
+
+  /* Returns TRUE if the driver can support creating a 2D texture with
+   * the given geometry and specified internal format.
+   */
+  CoglBool
+  (* texture_2d_can_create) (CoglContext *ctx,
+                             int width,
+                             int height,
+                             CoglPixelFormat internal_format);
+
+  /* Initializes driver private state before allocating any specific
+   * storage for a 2D texture, where base texture and texture 2D
+   * members will already be initialized before passing control to
+   * the driver.
+   */
+  void
+  (* texture_2d_init) (CoglTexture2D *tex_2d);
+
+  /* Instantiates a new CoglTexture2D object with un-initialized
+   * storage for a given size and internal format */
+  CoglTexture2D *
+  (* texture_2d_new_with_size) (CoglContext *ctx,
+                                int width,
+                                int height,
+                                CoglPixelFormat internal_format,
+                                CoglError **error);
+
+  /* Instantiates a new CoglTexture2D object with storage initialized
+   * with the contents of the given bitmap, using the specified
+   * internal format.
+   */
+  CoglTexture2D *
+  (* texture_2d_new_from_bitmap) (CoglBitmap *bmp,
+                                  CoglPixelFormat internal_format,
+                                  CoglError **error);
+
+#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
+  /* Instantiates a new CoglTexture2D object with storage initialized
+   * with the contents of the given EGL image.
+   *
+   * This is optional for drivers to support
+   */
+  CoglTexture2D *
+  (* egl_texture_2d_new_from_image) (CoglContext *ctx,
+                                     int width,
+                                     int height,
+                                     CoglPixelFormat format,
+                                     EGLImageKHR image,
+                                     CoglError **error);
+#endif
+
+  /* Initialize the specified region of storage of the given texture
+   * with the contents of the specified framebuffer region
+   */
+  void
+  (* texture_2d_copy_from_framebuffer) (CoglTexture2D *tex_2d,
+                                        CoglFramebuffer *src_fb,
+                                        int dst_x,
+                                        int dst_y,
+                                        int src_x,
+                                        int src_y,
+                                        int width,
+                                        int height);
+
+  /* If the given texture has a corresponding OpenGL texture handle
+   * then return that.
+   *
+   * This is optional
+   */
+  unsigned int
+  (* texture_2d_get_gl_handle) (CoglTexture2D *tex_2d);
+
+  /* Update all mipmap levels > 0 */
+  void
+  (* texture_2d_generate_mipmap) (CoglTexture2D *tex_2d);
+
+  /* Initialize the specified region of storage of the given texture
+   * with the contents of the specified bitmap region
+   */
+  void
+  (* texture_2d_copy_from_bitmap) (CoglTexture2D *tex_2d,
+                                   CoglBitmap *bitmap,
+                                   int dst_x,
+                                   int dst_y,
+                                   int src_x,
+                                   int src_y,
+                                   int width,
+                                   int height);
+
+  /* Reads back the full contents of the given texture and write it to
+   * @data in the given @format and with the given @rowstride.
+   *
+   * This is optional
+   */
+  void
+  (* texture_2d_get_data) (CoglTexture2D *tex_2d,
+                           CoglPixelFormat format,
+                           unsigned int rowstride,
+                           uint8_t *data);
 };
 
 #endif /* __COGL_DRIVER_H */
diff --git a/cogl/cogl-gles2-context.c b/cogl/cogl-gles2-context.c
index 7bb7ff3..65e7598 100644
--- a/cogl/cogl-gles2-context.c
+++ b/cogl/cogl-gles2-context.c
@@ -43,6 +43,7 @@
 #include "cogl-onscreen-template-private.h"
 #include "cogl-renderer-private.h"
 #include "cogl-swap-chain-private.h"
+#include "cogl-texture-2d-gl.h"
 #include "cogl-texture-2d-private.h"
 #include "cogl-pipeline-opengl-private.h"
 #include "cogl-error-private.h"
@@ -1932,12 +1933,12 @@ cogl_gles2_texture_2d_new_from_handle (CoglContext *ctx,
                                        CoglPixelFormat internal_format,
                                        CoglError **error)
 {
-  return cogl_texture_2d_new_from_foreign (ctx,
-                                           handle,
-                                           width,
-                                           height,
-                                           internal_format,
-                                           error);
+  return cogl_texture_2d_gl_new_from_foreign (ctx,
+                                              handle,
+                                              width,
+                                              height,
+                                              internal_format,
+                                              error);
 }
 
 CoglBool
diff --git a/cogl/cogl-texture-2d-gl.h b/cogl/cogl-texture-2d-gl.h
new file mode 100644
index 0000000..5136a35
--- /dev/null
+++ b/cogl/cogl-texture-2d-gl.h
@@ -0,0 +1,75 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Authors:
+ *   Robert Bragg <robert at linux.intel.com>
+ */
+
+#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
+#error "Only <cogl/cogl.h> can be included directly."
+#endif
+
+#ifndef _COGL_TEXTURE_2D_GL_H_
+#define _COGL_TEXTURE_2D_GL_H_
+
+#include "cogl-context.h"
+#include "cogl-texture-2d.h"
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/**
+ * cogl_texture_2d_gl_new_from_foreign:
+ * @ctx: A #CoglContext
+ * @gl_handle: A GL handle for a GL_TEXTURE_2D texture object
+ * @width: Width of the foreign GL texture
+ * @height: Height of the foreign GL texture
+ * @internal_format: The format of the texture
+ * @error: A #CoglError for exceptions
+ *
+ * Wraps an existing GL_TEXTURE_2D texture object as a #CoglTexture2D.
+ * This can be used for integrating Cogl with software using OpenGL
+ * directly.
+ *
+ * <note>The results are undefined for passing an invalid @gl_handle
+ * or if @width or @height don't have the correct texture
+ * geometry.</note>
+ *
+ * Returns: A newly allocated #CoglTexture2D, or if Cogl could not
+ *          validate the @gl_handle in some way (perhaps because of
+ *          an unsupported format) it will return %NULL and set
+ *          @error.
+ *
+ * Since: 2.0
+ */
+CoglTexture2D *
+cogl_texture_2d_gl_new_from_foreign (CoglContext *ctx,
+                                     unsigned int gl_handle,
+                                     int width,
+                                     int height,
+                                     CoglPixelFormat format,
+                                     CoglError **error);
+
+G_END_DECLS
+
+#endif /* _COGL_TEXTURE_2D_GL_H_ */
diff --git a/cogl/cogl-texture-2d-private.h b/cogl/cogl-texture-2d-private.h
index 3180a3f..2a57081 100644
--- a/cogl/cogl-texture-2d-private.h
+++ b/cogl/cogl-texture-2d-private.h
@@ -74,6 +74,16 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
                                      CoglError **error);
 #endif
 
+CoglTexture2D *
+_cogl_texture_2d_create_base (CoglContext *ctx,
+                              int width,
+                              int height,
+                              CoglPixelFormat internal_format);
+
+void
+_cogl_texture_2d_set_auto_mipmap (CoglTexture *tex,
+                                  CoglBool value);
+
 /*
  * _cogl_texture_2d_externally_modified:
  * @texture: A #CoglTexture2D object
diff --git a/cogl/cogl-texture-2d-sliced.c b/cogl/cogl-texture-2d-sliced.c
index e988a4a..b03f41f 100644
--- a/cogl/cogl-texture-2d-sliced.c
+++ b/cogl/cogl-texture-2d-sliced.c
@@ -36,6 +36,7 @@
 #include "cogl-bitmap.h"
 #include "cogl-bitmap-private.h"
 #include "cogl-texture-private.h"
+#include "cogl-texture-2d-gl.h"
 #include "cogl-texture-2d-private.h"
 #include "cogl-texture-2d-sliced-private.h"
 #include "cogl-texture-driver.h"
@@ -982,12 +983,12 @@ _cogl_texture_2d_sliced_new_from_foreign (GLuint           gl_handle,
       y_pot_waste < 0 || y_pot_waste >= height)
     return NULL;
 
-  tex_2d = cogl_texture_2d_new_from_foreign (ctx,
-                                             gl_target,
-                                             gl_width,
-                                             gl_height,
-                                             format,
-                                             NULL);
+  tex_2d = cogl_texture_2d_gl_new_from_foreign (ctx,
+                                                gl_target,
+                                                gl_width,
+                                                gl_height,
+                                                format,
+                                                NULL);
 
   if (!tex_2d)
     return NULL;
diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c
index c170490..6b902fb 100644
--- a/cogl/cogl-texture-2d.c
+++ b/cogl/cogl-texture-2d.c
@@ -32,6 +32,7 @@
 #include "cogl-util.h"
 #include "cogl-texture-private.h"
 #include "cogl-texture-2d-private.h"
+#include "cogl-texture-2d-gl-private.h"
 #include "cogl-texture-driver.h"
 #include "cogl-context-private.h"
 #include "cogl-object-private.h"
@@ -64,40 +65,11 @@ typedef struct _CoglTexture2DManualRepeatData
 } CoglTexture2DManualRepeatData;
 
 static void
-_cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex,
-                                                    GLenum wrap_mode_s,
-                                                    GLenum wrap_mode_t,
-                                                    GLenum wrap_mode_p)
-{
-  CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
-  CoglContext *ctx = tex->context;
-
-  /* Only set the wrap mode if it's different from the current value
-     to avoid too many GL calls. Texture 2D doesn't make use of the r
-     coordinate so we can ignore its wrap mode */
-  if (tex_2d->gl_legacy_texobj_wrap_mode_s != wrap_mode_s ||
-      tex_2d->gl_legacy_texobj_wrap_mode_t != wrap_mode_t)
-    {
-      _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
-                                       tex_2d->gl_texture,
-                                       tex_2d->is_foreign);
-      GE( ctx, glTexParameteri (GL_TEXTURE_2D,
-                                GL_TEXTURE_WRAP_S,
-                                wrap_mode_s) );
-      GE( ctx, glTexParameteri (GL_TEXTURE_2D,
-                                GL_TEXTURE_WRAP_T,
-                                wrap_mode_t) );
-
-      tex_2d->gl_legacy_texobj_wrap_mode_s = wrap_mode_s;
-      tex_2d->gl_legacy_texobj_wrap_mode_t = wrap_mode_t;
-    }
-}
-
-static void
 _cogl_texture_2d_free (CoglTexture2D *tex_2d)
 {
-  if (!tex_2d->is_foreign)
-    _cogl_delete_gl_texture (tex_2d->gl_texture);
+  CoglContext *ctx = COGL_TEXTURE (tex_2d)->context;
+
+  ctx->driver_vtable->texture_2d_free (tex_2d);
 
   /* Chain up */
   _cogl_texture_free (COGL_TEXTURE (tex_2d));
@@ -109,10 +81,6 @@ _cogl_texture_2d_can_create (CoglContext *ctx,
                              unsigned int height,
                              CoglPixelFormat internal_format)
 {
-  GLenum gl_intformat;
-  GLenum gl_format;
-  GLenum gl_type;
-
   /* If NPOT textures aren't supported then the size must be a power
      of two */
   if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT_BASIC) &&
@@ -120,26 +88,13 @@ _cogl_texture_2d_can_create (CoglContext *ctx,
        !_cogl_util_is_pot (height)))
     return FALSE;
 
-  ctx->driver_vtable->pixel_format_to_gl (ctx,
-                                          internal_format,
-                                          &gl_intformat,
-                                          &gl_format,
-                                          &gl_type);
-
-  /* Check that the driver can create a texture with that size */
-  if (!ctx->texture_driver->size_supported (ctx,
-                                            GL_TEXTURE_2D,
-                                            gl_intformat,
-                                            gl_format,
-                                            gl_type,
-                                            width,
-                                            height))
-    return FALSE;
-
-  return TRUE;
+  return ctx->driver_vtable->texture_2d_can_create (ctx,
+                                                    width,
+                                                    height,
+                                                    internal_format);
 }
 
-static void
+void
 _cogl_texture_2d_set_auto_mipmap (CoglTexture *tex,
                                   CoglBool value)
 {
@@ -148,7 +103,7 @@ _cogl_texture_2d_set_auto_mipmap (CoglTexture *tex,
   tex_2d->auto_mipmap = value;
 }
 
-static CoglTexture2D *
+CoglTexture2D *
 _cogl_texture_2d_create_base (CoglContext *ctx,
                               int width,
                               int height,
@@ -164,19 +119,13 @@ _cogl_texture_2d_create_base (CoglContext *ctx,
   tex_2d->mipmaps_dirty = TRUE;
   tex_2d->auto_mipmap = TRUE;
 
-  /* We default to GL_LINEAR for both filters */
-  tex_2d->gl_legacy_texobj_min_filter = GL_LINEAR;
-  tex_2d->gl_legacy_texobj_mag_filter = GL_LINEAR;
-
-  /* Wrap mode not yet set */
-  tex_2d->gl_legacy_texobj_wrap_mode_s = GL_FALSE;
-  tex_2d->gl_legacy_texobj_wrap_mode_t = GL_FALSE;
-
   tex_2d->is_foreign = FALSE;
 
   tex_2d->format = internal_format;
 
-  return tex_2d;
+  ctx->driver_vtable->texture_2d_init (tex_2d);
+
+  return _cogl_texture_2d_object_new (tex_2d);
 }
 
 CoglTexture2D *
@@ -186,11 +135,6 @@ cogl_texture_2d_new_with_size (CoglContext *ctx,
                                CoglPixelFormat internal_format,
                                CoglError **error)
 {
-  CoglTexture2D         *tex_2d;
-  GLenum                 gl_intformat;
-  GLenum                 gl_format;
-  GLenum                 gl_type;
-
   /* Since no data, we need some internal format */
   if (internal_format == COGL_PIXEL_FORMAT_ANY)
     internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
@@ -204,24 +148,11 @@ cogl_texture_2d_new_with_size (CoglContext *ctx,
       return NULL;
     }
 
-  internal_format = ctx->driver_vtable->pixel_format_to_gl (ctx,
-                                                            internal_format,
-                                                            &gl_intformat,
-                                                            &gl_format,
-                                                            &gl_type);
-
-  tex_2d = _cogl_texture_2d_create_base (ctx,
-                                         width, height,
-                                         internal_format);
-
-  ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
-  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
-                                   tex_2d->gl_texture,
-                                   tex_2d->is_foreign);
-  GE( ctx, glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat,
-                         width, height, 0, gl_format, gl_type, NULL) );
-
-  return _cogl_texture_2d_object_new (tex_2d);
+  return ctx->driver_vtable->texture_2d_new_with_size (ctx,
+                                                       width,
+                                                       height,
+                                                       internal_format,
+                                                       error);
 }
 
 CoglTexture2D *
@@ -229,12 +160,6 @@ cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp,
                                  CoglPixelFormat internal_format,
                                  CoglError **error)
 {
-  CoglTexture2D *tex_2d;
-  CoglBitmap *dst_bmp;
-  GLenum gl_intformat;
-  GLenum gl_format;
-  GLenum gl_type;
-  uint8_t *data;
   CoglContext *ctx;
 
   _COGL_RETURN_VAL_IF_FAIL (bmp != NULL, NULL);
@@ -258,54 +183,9 @@ cogl_texture_2d_new_from_bitmap (CoglBitmap *bmp,
 
     }
 
-  if ((dst_bmp = _cogl_texture_prepare_for_upload (bmp,
-                                                   internal_format,
-                                                   &internal_format,
-                                                   &gl_intformat,
-                                                   &gl_format,
-                                                   &gl_type)) == NULL)
-    {
-      _cogl_set_error (error, COGL_TEXTURE_ERROR,
-                       COGL_TEXTURE_ERROR_FORMAT,
-                       "Failed to prepare texture upload due to format");
-      return NULL;
-    }
-
-  tex_2d = _cogl_texture_2d_create_base (ctx,
-                                         cogl_bitmap_get_width (bmp),
-                                         cogl_bitmap_get_height (bmp),
-                                         internal_format);
-
-  /* Keep a copy of the first pixel so that if glGenerateMipmap isn't
-     supported we can fallback to using GL_GENERATE_MIPMAP */
-  if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) &&
-      (data = _cogl_bitmap_map (dst_bmp,
-                                COGL_BUFFER_ACCESS_READ, 0)))
-    {
-      CoglPixelFormat format = cogl_bitmap_get_format (dst_bmp);
-      tex_2d->first_pixel.gl_format = gl_format;
-      tex_2d->first_pixel.gl_type = gl_type;
-      memcpy (tex_2d->first_pixel.data, data,
-              _cogl_pixel_format_get_bytes_per_pixel (format));
-
-      _cogl_bitmap_unmap (dst_bmp);
-    }
-
-  ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
-  ctx->texture_driver->upload_to_gl (ctx,
-                                     GL_TEXTURE_2D,
-                                     tex_2d->gl_texture,
-                                     FALSE,
-                                     dst_bmp,
-                                     gl_intformat,
-                                     gl_format,
-                                     gl_type);
-
-  tex_2d->gl_format = gl_intformat;
-
-  cogl_object_unref (dst_bmp);
-
-  return _cogl_texture_2d_object_new (tex_2d);
+  return ctx->driver_vtable->texture_2d_new_from_bitmap (bmp,
+                                                         internal_format,
+                                                         error);
 }
 
 CoglTexture2D *
@@ -344,149 +224,6 @@ cogl_texture_2d_new_from_data (CoglContext *ctx,
   return tex_2d;
 }
 
-CoglTexture2D *
-cogl_texture_2d_new_from_foreign (CoglContext *ctx,
-                                  unsigned int gl_handle,
-                                  int width,
-                                  int height,
-                                  CoglPixelFormat format,
-                                  CoglError **error)
-{
-  /* NOTE: width, height and internal format are not queriable
-   * in GLES, hence such a function prototype.
-   */
-
-  GLenum gl_error = 0;
-  GLint gl_compressed = GL_FALSE;
-  GLenum gl_int_format = 0;
-  CoglTexture2D *tex_2d;
-
-  /* Assert it is a valid GL texture object */
-  g_return_val_if_fail (ctx->glIsTexture (gl_handle), NULL);
-
-  if (!ctx->texture_driver->allows_foreign_gl_target (ctx, GL_TEXTURE_2D))
-    {
-      _cogl_set_error (error,
-                       COGL_SYSTEM_ERROR,
-                       COGL_SYSTEM_ERROR_UNSUPPORTED,
-                       "Foreign GL_TEXTURE_2D textures are not "
-                       "supported by your system");
-      return NULL;
-    }
-
-
-  /* Make sure binding succeeds */
-  while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
-    ;
-
-  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, gl_handle, TRUE);
-  if (ctx->glGetError () != GL_NO_ERROR)
-    {
-      _cogl_set_error (error,
-                       COGL_SYSTEM_ERROR,
-                       COGL_SYSTEM_ERROR_UNSUPPORTED,
-                       "Failed to bind foreign GL_TEXTURE_2D texture");
-      return NULL;
-    }
-
-  /* Obtain texture parameters
-     (only level 0 we are interested in) */
-
-#if HAVE_COGL_GL
-  if (ctx->driver == COGL_DRIVER_GL)
-    {
-      GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
-                                         GL_TEXTURE_COMPRESSED,
-                                         &gl_compressed) );
-
-      {
-        GLint val;
-
-        GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
-                                           GL_TEXTURE_INTERNAL_FORMAT,
-                                           &val) );
-
-        gl_int_format = val;
-      }
-
-      /* If we can query GL for the actual pixel format then we'll ignore
-         the passed in format and use that. */
-      if (!ctx->driver_vtable->pixel_format_from_gl_internal (ctx,
-                                                              gl_int_format,
-                                                              &format))
-        {
-          _cogl_set_error (error,
-                           COGL_SYSTEM_ERROR,
-                           COGL_SYSTEM_ERROR_UNSUPPORTED,
-                           "Unsupported internal format for foreign texture");
-          return NULL;
-        }
-    }
-  else
-#endif
-    {
-      /* Otherwise we'll assume we can derive the GL format from the
-         passed in format */
-      ctx->driver_vtable->pixel_format_to_gl (ctx,
-                                              format,
-                                              &gl_int_format,
-                                              NULL,
-                                              NULL);
-    }
-
-  /* Note: We always trust the given width and height without querying
-   * the texture object because the user may be creating a Cogl
-   * texture for a texture_from_pixmap object where glTexImage2D may
-   * not have been called and the texture_from_pixmap spec doesn't
-   * clarify that it is reliable to query back the size from OpenGL.
-   */
-
-  /* Validate width and height */
-  g_return_val_if_fail (width > 0 && height > 0, NULL);
-
-  /* Compressed texture images not supported */
-  if (gl_compressed == GL_TRUE)
-    {
-      _cogl_set_error (error,
-                       COGL_SYSTEM_ERROR,
-                       COGL_SYSTEM_ERROR_UNSUPPORTED,
-                       "Compressed foreign textures aren't currently supported");
-      return NULL;
-    }
-
-  /* Note: previously this code would query the texture object for
-     whether it has GL_GENERATE_MIPMAP enabled to determine whether to
-     auto-generate the mipmap. This doesn't make much sense any more
-     since Cogl switch to using glGenerateMipmap. Ideally I think
-     cogl_texture_2d_new_from_foreign should take a flags parameter so
-     that the application can decide whether it wants
-     auto-mipmapping. To be compatible with existing code, Cogl now
-     disables its own auto-mipmapping but leaves the value of
-     GL_GENERATE_MIPMAP alone so that it would still work but without
-     the dirtiness tracking that Cogl would do. */
-
-  /* Create new texture */
-  tex_2d = _cogl_texture_2d_create_base (ctx,
-                                         width, height,
-                                         format);
-  _cogl_texture_2d_set_auto_mipmap (COGL_TEXTURE (tex_2d), FALSE);
-
-  /* Setup bitmap info */
-  tex_2d->is_foreign = TRUE;
-  tex_2d->mipmaps_dirty = TRUE;
-
-  tex_2d->format = format;
-
-  tex_2d->gl_texture = gl_handle;
-  tex_2d->gl_format = gl_int_format;
-
-  /* Unknown filter */
-  tex_2d->gl_legacy_texobj_min_filter = GL_FALSE;
-  tex_2d->gl_legacy_texobj_mag_filter = GL_FALSE;
-
-  return _cogl_texture_2d_object_new (tex_2d);
-}
-
 #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
 /* NB: The reason we require the width, height and format to be passed
  * even though they may seem redundant is because GLES 1/2 don't
@@ -499,9 +236,6 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
                                      EGLImageKHR image,
                                      CoglError **error)
 {
-  CoglTexture2D *tex_2d;
-  GLenum gl_error;
-
   _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints &
                             COGL_RENDERER_CONSTRAINT_USES_EGL,
                             NULL);
@@ -510,29 +244,22 @@ _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
                         COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE,
                         NULL);
 
-  tex_2d = _cogl_texture_2d_create_base (ctx,
-                                         width, height,
-                                         format);
-
-  ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
-  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
-                                   tex_2d->gl_texture,
-                                   FALSE);
-
-  while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
-    ;
-  ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, image);
-  if (ctx->glGetError () != GL_NO_ERROR)
+  if (ctx->driver_vtable->egl_texture_2d_new_from_image)
+    return ctx->driver_vtable->egl_texture_2d_new_from_image (ctx,
+                                                              width,
+                                                              height,
+                                                              format,
+                                                              image,
+                                                              error);
+  else
     {
       _cogl_set_error (error,
-                       COGL_TEXTURE_ERROR,
-                       COGL_TEXTURE_ERROR_BAD_PARAMETER,
-                       "Could not create a CoglTexture2D from a given "
-                       "EGLImage");
+                       COGL_SYSTEM_ERROR,
+                       COGL_SYSTEM_ERROR_UNSUPPORTED,
+                       "Creating 2D textures from EGL images is not "
+                       "supported by the current driver");
       return NULL;
     }
-
-  return _cogl_texture_2d_object_new (tex_2d);
 }
 #endif /* defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) */
 
@@ -624,28 +351,20 @@ _cogl_texture_2d_copy_from_framebuffer (CoglTexture2D *tex_2d,
                                         int height)
 {
   CoglContext *ctx;
+  CoglFramebuffer *read_fb = _cogl_get_read_framebuffer ();
 
   _COGL_RETURN_IF_FAIL (cogl_is_texture_2d (tex_2d));
 
   ctx = COGL_TEXTURE (tex_2d)->context;
 
-  /* 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 (cogl_get_draw_framebuffer (),
-                                 _cogl_get_read_framebuffer (),
-                                 COGL_FRAMEBUFFER_STATE_ALL &
-                                 ~COGL_FRAMEBUFFER_STATE_CLIP);
-
-  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
-                                   tex_2d->gl_texture,
-                                   tex_2d->is_foreign);
-
-  ctx->glCopyTexSubImage2D (GL_TEXTURE_2D,
-                            0, /* level */
-                            dst_x, dst_y,
-                            src_x, src_y,
-                            width, height);
+  ctx->driver_vtable->texture_2d_copy_from_framebuffer (tex_2d,
+                                                        read_fb,
+                                                        dst_x,
+                                                        dst_y,
+                                                        src_x,
+                                                        src_y,
+                                                        width,
+                                                        height);
 
   tex_2d->mipmaps_dirty = TRUE;
 }
@@ -712,75 +431,39 @@ _cogl_texture_2d_get_gl_texture (CoglTexture *tex,
                                  GLuint *out_gl_handle,
                                  GLenum *out_gl_target)
 {
+  CoglContext *ctx = tex->context;
   CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
 
-  if (out_gl_handle)
-    *out_gl_handle = tex_2d->gl_texture;
+  if (ctx->driver_vtable->texture_2d_get_gl_handle)
+    {
+      GLuint handle;
 
-  if (out_gl_target)
-    *out_gl_target = GL_TEXTURE_2D;
+      if (out_gl_target)
+        *out_gl_target = GL_TEXTURE_2D;
 
-  return TRUE;
-}
+      handle = ctx->driver_vtable->texture_2d_get_gl_handle (tex_2d);
 
-static void
-_cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex,
-                                                 GLenum min_filter,
-                                                 GLenum mag_filter)
-{
-  CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
-  CoglContext *ctx = tex->context;
-
-  if (min_filter == tex_2d->gl_legacy_texobj_min_filter
-      && mag_filter == tex_2d->gl_legacy_texobj_mag_filter)
-    return;
+      if (out_gl_handle)
+        *out_gl_handle = handle;
 
-  /* Store new values */
-  tex_2d->gl_legacy_texobj_min_filter = min_filter;
-  tex_2d->gl_legacy_texobj_mag_filter = mag_filter;
-
-  /* Apply new filters to the texture */
-  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
-                                   tex_2d->gl_texture,
-                                   tex_2d->is_foreign);
-  GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter) );
-  GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter) );
+      return handle ? TRUE : FALSE;
+    }
+  else
+    return FALSE;
 }
 
 static void
 _cogl_texture_2d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags)
 {
   CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
-  CoglContext *ctx = tex->context;
 
   /* Only update if the mipmaps are dirty */
   if ((flags & COGL_TEXTURE_NEEDS_MIPMAP) &&
       tex_2d->auto_mipmap && tex_2d->mipmaps_dirty)
     {
-      _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
-                                       tex_2d->gl_texture,
-                                       tex_2d->is_foreign);
-
-      /* glGenerateMipmap is defined in the FBO extension. If it's not
-         available we'll fallback to temporarily enabling
-         GL_GENERATE_MIPMAP and reuploading the first pixel */
-      if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
-        ctx->texture_driver->gl_generate_mipmaps (ctx, GL_TEXTURE_2D);
-#if defined(HAVE_COGL_GLES) || defined(HAVE_COGL_GL)
-      else
-        {
-          GE( ctx, glTexParameteri (GL_TEXTURE_2D,
-                                    GL_GENERATE_MIPMAP,
-                                    GL_TRUE) );
-          GE( ctx, glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 1, 1,
-                                    tex_2d->first_pixel.gl_format,
-                                    tex_2d->first_pixel.gl_type,
-                                    tex_2d->first_pixel.data) );
-          GE( ctx, glTexParameteri (GL_TEXTURE_2D,
-                                    GL_GENERATE_MIPMAP,
-                                    GL_FALSE) );
-        }
-#endif
+      CoglContext *ctx = tex->context;
+
+      ctx->driver_vtable->texture_2d_generate_mipmap (tex_2d);
 
       tex_2d->mipmaps_dirty = FALSE;
     }
@@ -798,55 +481,24 @@ _cogl_texture_2d_set_region (CoglTexture    *tex,
                              int             src_y,
                              int             dst_x,
                              int             dst_y,
-                             unsigned int    dst_width,
-                             unsigned int    dst_height,
+                             unsigned int    width,
+                             unsigned int    height,
                              CoglBitmap     *bmp)
 {
-  CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
   CoglContext *ctx = tex->context;
-  GLenum gl_format;
-  GLenum gl_type;
-  uint8_t *data;
-
-  bmp = _cogl_texture_prepare_for_upload (bmp,
-                                          cogl_texture_get_format (tex),
-                                          NULL,
-                                          NULL,
-                                          &gl_format,
-                                          &gl_type);
-
-  /* If this touches the first pixel then we'll update our copy */
-  if (dst_x == 0 && dst_y == 0 &&
-      !cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) &&
-      (data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 0)))
-    {
-      CoglPixelFormat bpp =
-        _cogl_pixel_format_get_bytes_per_pixel (cogl_bitmap_get_format (bmp));
-      tex_2d->first_pixel.gl_format = gl_format;
-      tex_2d->first_pixel.gl_type = gl_type;
-      memcpy (tex_2d->first_pixel.data,
-              data + cogl_bitmap_get_rowstride (bmp) * src_y + bpp * src_x,
-              bpp);
-
-      _cogl_bitmap_unmap (bmp);
-    }
+  CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
 
-  /* Send data to GL */
-  ctx->texture_driver->upload_subregion_to_gl (ctx,
-                                               GL_TEXTURE_2D,
-                                               tex_2d->gl_texture,
-                                               FALSE,
-                                               src_x, src_y,
-                                               dst_x, dst_y,
-                                               dst_width, dst_height,
-                                               bmp,
-                                               gl_format,
-                                               gl_type);
+  ctx->driver_vtable->texture_2d_copy_from_bitmap (tex_2d,
+                                                   bmp,
+                                                   dst_x,
+                                                   dst_y,
+                                                   src_x,
+                                                   src_y,
+                                                   width,
+                                                   height);
 
   tex_2d->mipmaps_dirty = TRUE;
 
-  cogl_object_unref (bmp);
-
   return TRUE;
 }
 
@@ -856,33 +508,16 @@ _cogl_texture_2d_get_data (CoglTexture *tex,
                            unsigned int rowstride,
                            uint8_t *data)
 {
-  CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
   CoglContext *ctx = tex->context;
-  int bpp;
-  GLenum gl_format;
-  GLenum gl_type;
-
-  bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
-
-  ctx->driver_vtable->pixel_format_to_gl (ctx,
-                                          format,
-                                          NULL, /* internal format */
-                                          &gl_format,
-                                          &gl_type);
-
-  ctx->texture_driver->prep_gl_for_pixels_download (ctx,
-                                                    rowstride,
-                                                    tex_2d->width,
-                                                    bpp);
-
-  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
-                                   tex_2d->gl_texture,
-                                   tex_2d->is_foreign);
-  return ctx->texture_driver->gl_get_tex_image (ctx,
-                                                GL_TEXTURE_2D,
-                                                gl_format,
-                                                gl_type,
-                                                data);
+
+  if (ctx->driver_vtable->texture_2d_get_data)
+    {
+      CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
+      ctx->driver_vtable->texture_2d_get_data (tex_2d, format, rowstride, data);
+      return TRUE;
+    }
+  else
+    return FALSE;
 }
 
 static CoglPixelFormat
diff --git a/cogl/cogl-texture-2d.h b/cogl/cogl-texture-2d.h
index 1fc3d12..d07cdef 100644
--- a/cogl/cogl-texture-2d.h
+++ b/cogl/cogl-texture-2d.h
@@ -32,6 +32,7 @@
 #define __COGL_TEXTURE_2D_H
 
 #include "cogl-context.h"
+#include "cogl-bitmap.h"
 
 #include <glib.h>
 
@@ -186,39 +187,6 @@ cogl_texture_2d_new_from_bitmap (CoglBitmap *bitmap,
                                  CoglPixelFormat internal_format,
                                  CoglError **error);
 
-
-/**
- * cogl_texture_2d_new_from_foreign:
- * @ctx: A #CoglContext
- * @gl_handle: A GL handle for a GL_TEXTURE_2D texture object
- * @width: Width of the foreign GL texture
- * @height: Height of the foreign GL texture
- * @internal_format: The format of the texture
- * @error: A #CoglError for exceptions
- *
- * Wraps an existing GL_TEXTURE_2D texture object as a #CoglTexture2D.
- * This can be used for integrating Cogl with software using OpenGL
- * directly.
- *
- * <note>The results are undefined for passing an invalid @gl_handle
- * or if @width or @height don't have the correct texture
- * geometry.</note>
- *
- * Returns: A newly allocated #CoglTexture2D, or if Cogl could not
- *          validate the @gl_handle in some way (perhaps because of
- *          an unsupported format) it will return %NULL and set
- *          @error.
- *
- * Since: 2.0
- */
-CoglTexture2D *
-cogl_texture_2d_new_from_foreign (CoglContext *ctx,
-                                  unsigned int gl_handle,
-                                  int width,
-                                  int height,
-                                  CoglPixelFormat format,
-                                  CoglError **error);
-
 G_END_DECLS
 
 #endif /* __COGL_TEXTURE_2D_H */
diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c
index 67a696b..2d54216 100644
--- a/cogl/cogl-texture.c
+++ b/cogl/cogl-texture.c
@@ -42,6 +42,7 @@
 #include "cogl-texture-driver.h"
 #include "cogl-texture-2d-sliced-private.h"
 #include "cogl-texture-2d-private.h"
+#include "cogl-texture-2d-gl.h"
 #include "cogl-texture-rectangle-private.h"
 #include "cogl-sub-texture-private.h"
 #include "cogl-atlas-texture-private.h"
@@ -489,12 +490,12 @@ cogl_texture_new_from_foreign (GLuint           gl_handle,
   else
     {
       _COGL_GET_CONTEXT (ctx, NULL);
-      return COGL_TEXTURE (cogl_texture_2d_new_from_foreign (ctx,
-                                                             gl_handle,
-                                                             width,
-                                                             height,
-                                                             format,
-                                                             NULL));
+      return COGL_TEXTURE (cogl_texture_2d_gl_new_from_foreign (ctx,
+                                                                gl_handle,
+                                                                width,
+                                                                height,
+                                                                format,
+                                                                NULL));
     }
 }
 
diff --git a/cogl/cogl.h b/cogl/cogl.h
index 8291bc2..875f32a 100644
--- a/cogl/cogl.h
+++ b/cogl/cogl.h
@@ -65,6 +65,7 @@
 #include <cogl/cogl-euler.h>
 #include <cogl/cogl-quaternion.h>
 #include <cogl/cogl-texture-2d.h>
+#include <cogl/cogl-texture-2d-gl.h>
 #include <cogl/cogl-texture-rectangle.h>
 #include <cogl/cogl-texture-3d.h>
 #include <cogl/cogl-texture-2d-sliced.h>
diff --git a/cogl/driver/gl/cogl-texture-2d-gl-private.h b/cogl/driver/gl/cogl-texture-2d-gl-private.h
new file mode 100644
index 0000000..492c314
--- /dev/null
+++ b/cogl/driver/gl/cogl-texture-2d-gl-private.h
@@ -0,0 +1,112 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *   Robert Bragg <robert at linux.intel.com>
+ */
+
+#ifndef _COGL_TEXTURE_2D_GL_PRIVATE_H_
+#define _COGL_TEXTURE_2D_GL_PRIVATE_H_
+
+#include "cogl-types.h"
+#include "cogl-context-private.h"
+#include "cogl-texture.h"
+
+void
+_cogl_texture_2d_gl_free (CoglTexture2D *tex_2d);
+
+CoglBool
+_cogl_texture_2d_gl_can_create (CoglContext *ctx,
+                                int width,
+                                int height,
+                                CoglPixelFormat internal_format);
+
+void
+_cogl_texture_2d_gl_init (CoglTexture2D *tex_2d);
+
+CoglTexture2D *
+_cogl_texture_2d_gl_new_with_size (CoglContext *ctx,
+                                   int width,
+                                   int height,
+                                   CoglPixelFormat internal_format,
+                                   CoglError **error);
+
+CoglTexture2D *
+_cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
+                                     CoglPixelFormat internal_format,
+                                     CoglError **error);
+
+#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
+CoglTexture2D *
+_cogl_egl_texture_2d_gl_new_from_image (CoglContext *ctx,
+                                        int width,
+                                        int height,
+                                        CoglPixelFormat format,
+                                        EGLImageKHR image,
+                                        CoglError **error);
+#endif
+
+void
+_cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex,
+                                                 GLenum min_filter,
+                                                 GLenum mag_filter);
+
+void
+_cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex,
+                                                    GLenum wrap_mode_s,
+                                                    GLenum wrap_mode_t,
+                                                    GLenum wrap_mode_p);
+
+void
+_cogl_texture_2d_gl_copy_from_framebuffer (CoglTexture2D *tex_2d,
+                                           CoglFramebuffer *src_fb,
+                                           int dst_x,
+                                           int dst_y,
+                                           int src_x,
+                                           int src_y,
+                                           int width,
+                                           int height);
+
+unsigned int
+_cogl_texture_2d_gl_get_gl_handle (CoglTexture2D *tex_2d);
+
+void
+_cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d);
+
+void
+_cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
+                                      CoglBitmap *bitmap,
+                                      int dst_x,
+                                      int dst_y,
+                                      int src_x,
+                                      int src_y,
+                                      int width,
+                                      int height);
+
+void
+_cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d,
+                              CoglPixelFormat format,
+                              size_t rowstride,
+                              uint8_t *data);
+
+#endif /* _COGL_TEXTURE_2D_GL_PRIVATE_H_ */
diff --git a/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/driver/gl/cogl-texture-2d-gl.c
new file mode 100644
index 0000000..653405c
--- /dev/null
+++ b/cogl/driver/gl/cogl-texture-2d-gl.c
@@ -0,0 +1,575 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2009,2010,2011,2012 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ *
+ * Authors:
+ *  Neil Roberts   <neil at linux.intel.com>
+ *  Robert Bragg   <robert at linux.intel.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+
+#include "cogl-private.h"
+#include "cogl-texture-2d-gl.h"
+#include "cogl-texture-2d-gl-private.h"
+#include "cogl-texture-2d-private.h"
+#include "cogl-pipeline-opengl-private.h"
+#include "cogl-error-private.h"
+
+void
+_cogl_texture_2d_gl_free (CoglTexture2D *tex_2d)
+{
+  if (!tex_2d->is_foreign)
+    _cogl_delete_gl_texture (tex_2d->gl_texture);
+}
+
+CoglBool
+_cogl_texture_2d_gl_can_create (CoglContext *ctx,
+                                int width,
+                                int height,
+                                CoglPixelFormat internal_format)
+{
+  GLenum gl_intformat;
+  GLenum gl_format;
+  GLenum gl_type;
+
+  ctx->driver_vtable->pixel_format_to_gl (ctx,
+                                          internal_format,
+                                          &gl_intformat,
+                                          &gl_format,
+                                          &gl_type);
+
+  /* Check that the driver can create a texture with that size */
+  if (!ctx->texture_driver->size_supported (ctx,
+                                            GL_TEXTURE_2D,
+                                            gl_intformat,
+                                            gl_format,
+                                            gl_type,
+                                            width,
+                                            height))
+    return FALSE;
+
+  return TRUE;
+}
+
+void
+_cogl_texture_2d_gl_init (CoglTexture2D *tex_2d)
+{
+  /* We default to GL_LINEAR for both filters */
+  tex_2d->gl_legacy_texobj_min_filter = GL_LINEAR;
+  tex_2d->gl_legacy_texobj_mag_filter = GL_LINEAR;
+
+  /* Wrap mode not yet set */
+  tex_2d->gl_legacy_texobj_wrap_mode_s = GL_FALSE;
+  tex_2d->gl_legacy_texobj_wrap_mode_t = GL_FALSE;
+}
+
+CoglTexture2D *
+_cogl_texture_2d_gl_new_with_size (CoglContext *ctx,
+                                   int width,
+                                   int height,
+                                   CoglPixelFormat internal_format,
+                                   CoglError **error)
+{
+  CoglTexture2D *tex_2d;
+  GLenum gl_intformat;
+  GLenum gl_format;
+  GLenum gl_type;
+
+  internal_format = ctx->driver_vtable->pixel_format_to_gl (ctx,
+                                                            internal_format,
+                                                            &gl_intformat,
+                                                            &gl_format,
+                                                            &gl_type);
+
+  tex_2d = _cogl_texture_2d_create_base (ctx,
+                                         width, height,
+                                         internal_format);
+
+  ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
+  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+                                   tex_2d->gl_texture,
+                                   tex_2d->is_foreign);
+  GE( ctx, glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat,
+                         width, height, 0, gl_format, gl_type, NULL) );
+
+  return tex_2d;
+}
+
+CoglTexture2D *
+_cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
+                                     CoglPixelFormat internal_format,
+                                     CoglError **error)
+{
+  CoglContext *ctx = _cogl_bitmap_get_context (bmp);
+  CoglTexture2D *tex_2d;
+  CoglBitmap *dst_bmp;
+  GLenum gl_intformat;
+  GLenum gl_format;
+  GLenum gl_type;
+  uint8_t *data;
+
+  if ((dst_bmp = _cogl_texture_prepare_for_upload (bmp,
+                                                   internal_format,
+                                                   &internal_format,
+                                                   &gl_intformat,
+                                                   &gl_format,
+                                                   &gl_type)) == NULL)
+    {
+      _cogl_set_error (error, COGL_TEXTURE_ERROR,
+                       COGL_TEXTURE_ERROR_FORMAT,
+                       "Failed to prepare texture upload due to format");
+      return NULL;
+    }
+
+  tex_2d = _cogl_texture_2d_create_base (ctx,
+                                         cogl_bitmap_get_width (bmp),
+                                         cogl_bitmap_get_height (bmp),
+                                         internal_format);
+
+  /* Keep a copy of the first pixel so that if glGenerateMipmap isn't
+     supported we can fallback to using GL_GENERATE_MIPMAP */
+  if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) &&
+      (data = _cogl_bitmap_map (dst_bmp,
+                                COGL_BUFFER_ACCESS_READ, 0)))
+    {
+      CoglPixelFormat format = cogl_bitmap_get_format (dst_bmp);
+      tex_2d->first_pixel.gl_format = gl_format;
+      tex_2d->first_pixel.gl_type = gl_type;
+      memcpy (tex_2d->first_pixel.data, data,
+              _cogl_pixel_format_get_bytes_per_pixel (format));
+
+      _cogl_bitmap_unmap (dst_bmp);
+    }
+
+  ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
+  ctx->texture_driver->upload_to_gl (ctx,
+                                     GL_TEXTURE_2D,
+                                     tex_2d->gl_texture,
+                                     FALSE,
+                                     dst_bmp,
+                                     gl_intformat,
+                                     gl_format,
+                                     gl_type);
+
+  tex_2d->gl_format = gl_intformat;
+
+  cogl_object_unref (dst_bmp);
+
+  return tex_2d;
+
+}
+
+#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
+CoglTexture2D *
+_cogl_egl_texture_2d_gl_new_from_image (CoglContext *ctx,
+                                        int width,
+                                        int height,
+                                        CoglPixelFormat format,
+                                        EGLImageKHR image,
+                                        CoglError **error)
+{
+  CoglTexture2D *tex_2d;
+  GLenum gl_error;
+
+  tex_2d = _cogl_texture_2d_create_base (ctx,
+                                         width, height,
+                                         format);
+
+  ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
+  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+                                   tex_2d->gl_texture,
+                                   FALSE);
+
+  while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
+    ;
+  ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, image);
+  if (ctx->glGetError () != GL_NO_ERROR)
+    {
+      _cogl_set_error (error,
+                       COGL_TEXTURE_ERROR,
+                       COGL_TEXTURE_ERROR_BAD_PARAMETER,
+                       "Could not create a CoglTexture2D from a given "
+                       "EGLImage");
+      return NULL;
+    }
+
+  return tex_2d;
+}
+#endif
+
+void
+_cogl_texture_2d_gl_flush_legacy_texobj_filters (CoglTexture *tex,
+                                                 GLenum min_filter,
+                                                 GLenum mag_filter)
+{
+  CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
+  CoglContext *ctx = tex->context;
+
+  if (min_filter == tex_2d->gl_legacy_texobj_min_filter
+      && mag_filter == tex_2d->gl_legacy_texobj_mag_filter)
+    return;
+
+  /* Store new values */
+  tex_2d->gl_legacy_texobj_min_filter = min_filter;
+  tex_2d->gl_legacy_texobj_mag_filter = mag_filter;
+
+  /* Apply new filters to the texture */
+  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+                                   tex_2d->gl_texture,
+                                   tex_2d->is_foreign);
+  GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter) );
+  GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter) );
+}
+
+void
+_cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex,
+                                                    GLenum wrap_mode_s,
+                                                    GLenum wrap_mode_t,
+                                                    GLenum wrap_mode_p)
+{
+  CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
+  CoglContext *ctx = tex->context;
+
+  /* Only set the wrap mode if it's different from the current value
+     to avoid too many GL calls. Texture 2D doesn't make use of the r
+     coordinate so we can ignore its wrap mode */
+  if (tex_2d->gl_legacy_texobj_wrap_mode_s != wrap_mode_s ||
+      tex_2d->gl_legacy_texobj_wrap_mode_t != wrap_mode_t)
+    {
+      _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+                                       tex_2d->gl_texture,
+                                       tex_2d->is_foreign);
+      GE( ctx, glTexParameteri (GL_TEXTURE_2D,
+                                GL_TEXTURE_WRAP_S,
+                                wrap_mode_s) );
+      GE( ctx, glTexParameteri (GL_TEXTURE_2D,
+                                GL_TEXTURE_WRAP_T,
+                                wrap_mode_t) );
+
+      tex_2d->gl_legacy_texobj_wrap_mode_s = wrap_mode_s;
+      tex_2d->gl_legacy_texobj_wrap_mode_t = wrap_mode_t;
+    }
+}
+
+CoglTexture2D *
+cogl_texture_2d_gl_new_from_foreign (CoglContext *ctx,
+                                     unsigned int gl_handle,
+                                     int width,
+                                     int height,
+                                     CoglPixelFormat format,
+                                     CoglError **error)
+{
+  /* NOTE: width, height and internal format are not queriable
+   * in GLES, hence such a function prototype.
+   */
+
+  GLenum gl_error = 0;
+  GLint gl_compressed = GL_FALSE;
+  GLenum gl_int_format = 0;
+  CoglTexture2D *tex_2d;
+
+  /* Assert it is a valid GL texture object */
+  g_return_val_if_fail (ctx->glIsTexture (gl_handle), NULL);
+
+  if (!ctx->texture_driver->allows_foreign_gl_target (ctx, GL_TEXTURE_2D))
+    {
+      _cogl_set_error (error,
+                       COGL_SYSTEM_ERROR,
+                       COGL_SYSTEM_ERROR_UNSUPPORTED,
+                       "Foreign GL_TEXTURE_2D textures are not "
+                       "supported by your system");
+      return NULL;
+    }
+
+
+  /* Make sure binding succeeds */
+  while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
+    ;
+
+  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, gl_handle, TRUE);
+  if (ctx->glGetError () != GL_NO_ERROR)
+    {
+      _cogl_set_error (error,
+                       COGL_SYSTEM_ERROR,
+                       COGL_SYSTEM_ERROR_UNSUPPORTED,
+                       "Failed to bind foreign GL_TEXTURE_2D texture");
+      return NULL;
+    }
+
+  /* Obtain texture parameters
+     (only level 0 we are interested in) */
+
+#if HAVE_COGL_GL
+  if (ctx->driver == COGL_DRIVER_GL)
+    {
+      GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
+                                         GL_TEXTURE_COMPRESSED,
+                                         &gl_compressed) );
+
+      {
+        GLint val;
+
+        GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
+                                           GL_TEXTURE_INTERNAL_FORMAT,
+                                           &val) );
+
+        gl_int_format = val;
+      }
+
+      /* If we can query GL for the actual pixel format then we'll ignore
+         the passed in format and use that. */
+      if (!ctx->driver_vtable->pixel_format_from_gl_internal (ctx,
+                                                              gl_int_format,
+                                                              &format))
+        {
+          _cogl_set_error (error,
+                           COGL_SYSTEM_ERROR,
+                           COGL_SYSTEM_ERROR_UNSUPPORTED,
+                           "Unsupported internal format for foreign texture");
+          return NULL;
+        }
+    }
+  else
+#endif
+    {
+      /* Otherwise we'll assume we can derive the GL format from the
+         passed in format */
+      ctx->driver_vtable->pixel_format_to_gl (ctx,
+                                              format,
+                                              &gl_int_format,
+                                              NULL,
+                                              NULL);
+    }
+
+  /* Note: We always trust the given width and height without querying
+   * the texture object because the user may be creating a Cogl
+   * texture for a texture_from_pixmap object where glTexImage2D may
+   * not have been called and the texture_from_pixmap spec doesn't
+   * clarify that it is reliable to query back the size from OpenGL.
+   */
+
+  /* Validate width and height */
+  g_return_val_if_fail (width > 0 && height > 0, NULL);
+
+  /* Compressed texture images not supported */
+  if (gl_compressed == GL_TRUE)
+    {
+      _cogl_set_error (error,
+                       COGL_SYSTEM_ERROR,
+                       COGL_SYSTEM_ERROR_UNSUPPORTED,
+                       "Compressed foreign textures aren't currently supported");
+      return NULL;
+    }
+
+  /* Note: previously this code would query the texture object for
+     whether it has GL_GENERATE_MIPMAP enabled to determine whether to
+     auto-generate the mipmap. This doesn't make much sense any more
+     since Cogl switch to using glGenerateMipmap. Ideally I think
+     cogl_texture_2d_new_from_foreign should take a flags parameter so
+     that the application can decide whether it wants
+     auto-mipmapping. To be compatible with existing code, Cogl now
+     disables its own auto-mipmapping but leaves the value of
+     GL_GENERATE_MIPMAP alone so that it would still work but without
+     the dirtiness tracking that Cogl would do. */
+
+  /* Create new texture */
+  tex_2d = _cogl_texture_2d_create_base (ctx,
+                                         width, height,
+                                         format);
+  _cogl_texture_2d_set_auto_mipmap (COGL_TEXTURE (tex_2d), FALSE);
+
+  /* Setup bitmap info */
+  tex_2d->is_foreign = TRUE;
+  tex_2d->mipmaps_dirty = TRUE;
+
+  tex_2d->format = format;
+
+  tex_2d->gl_texture = gl_handle;
+  tex_2d->gl_format = gl_int_format;
+
+  /* Unknown filter */
+  tex_2d->gl_legacy_texobj_min_filter = GL_FALSE;
+  tex_2d->gl_legacy_texobj_mag_filter = GL_FALSE;
+
+  return tex_2d;
+}
+
+void
+_cogl_texture_2d_gl_copy_from_framebuffer (CoglTexture2D *tex_2d,
+                                           CoglFramebuffer *src_fb,
+                                           int dst_x,
+                                           int dst_y,
+                                           int src_x,
+                                           int src_y,
+                                           int width,
+                                           int height)
+{
+  CoglContext *ctx = COGL_TEXTURE (tex_2d)->context;
+
+  /* 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 (cogl_get_draw_framebuffer (),
+                                 src_fb,
+                                 COGL_FRAMEBUFFER_STATE_ALL &
+                                 ~COGL_FRAMEBUFFER_STATE_CLIP);
+
+  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+                                   tex_2d->gl_texture,
+                                   tex_2d->is_foreign);
+
+  ctx->glCopyTexSubImage2D (GL_TEXTURE_2D,
+                            0, /* level */
+                            dst_x, dst_y,
+                            src_x, src_y,
+                            width, height);
+}
+
+unsigned int
+_cogl_texture_2d_gl_get_gl_handle (CoglTexture2D *tex_2d)
+{
+    return tex_2d->gl_texture;
+}
+
+void
+_cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d)
+{
+  CoglContext *ctx = COGL_TEXTURE (tex_2d)->context;
+
+  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+                                   tex_2d->gl_texture,
+                                   tex_2d->is_foreign);
+
+  /* glGenerateMipmap is defined in the FBO extension. If it's not
+     available we'll fallback to temporarily enabling
+     GL_GENERATE_MIPMAP and reuploading the first pixel */
+  if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
+    ctx->texture_driver->gl_generate_mipmaps (ctx, GL_TEXTURE_2D);
+#if defined(HAVE_COGL_GLES) || defined(HAVE_COGL_GL)
+  else
+    {
+      GE( ctx, glTexParameteri (GL_TEXTURE_2D,
+                                GL_GENERATE_MIPMAP,
+                                GL_TRUE) );
+      GE( ctx, glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 1, 1,
+                                tex_2d->first_pixel.gl_format,
+                                tex_2d->first_pixel.gl_type,
+                                tex_2d->first_pixel.data) );
+      GE( ctx, glTexParameteri (GL_TEXTURE_2D,
+                                GL_GENERATE_MIPMAP,
+                                GL_FALSE) );
+    }
+#endif
+}
+
+void
+_cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
+                                      CoglBitmap *bmp,
+                                      int dst_x,
+                                      int dst_y,
+                                      int src_x,
+                                      int src_y,
+                                      int width,
+                                      int height)
+{
+  CoglTexture *tex = COGL_TEXTURE (tex_2d);
+  CoglContext *ctx = tex->context;
+  GLenum gl_format;
+  GLenum gl_type;
+  uint8_t *data;
+
+  bmp = _cogl_texture_prepare_for_upload (bmp,
+                                          cogl_texture_get_format (tex),
+                                          NULL,
+                                          NULL,
+                                          &gl_format,
+                                          &gl_type);
+
+  /* If this touches the first pixel then we'll update our copy */
+  if (dst_x == 0 && dst_y == 0 &&
+      !cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) &&
+      (data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 0)))
+    {
+      CoglPixelFormat bpp =
+        _cogl_pixel_format_get_bytes_per_pixel (cogl_bitmap_get_format (bmp));
+      tex_2d->first_pixel.gl_format = gl_format;
+      tex_2d->first_pixel.gl_type = gl_type;
+      memcpy (tex_2d->first_pixel.data,
+              data + cogl_bitmap_get_rowstride (bmp) * src_y + bpp * src_x,
+              bpp);
+
+      _cogl_bitmap_unmap (bmp);
+    }
+
+  /* Send data to GL */
+  ctx->texture_driver->upload_subregion_to_gl (ctx,
+                                               GL_TEXTURE_2D,
+                                               tex_2d->gl_texture,
+                                               FALSE,
+                                               src_x, src_y,
+                                               dst_x, dst_y,
+                                               width, height,
+                                               bmp,
+                                               gl_format,
+                                               gl_type);
+
+  cogl_object_unref (bmp);
+}
+
+void
+_cogl_texture_2d_gl_get_data (CoglTexture2D *tex_2d,
+                              CoglPixelFormat format,
+                              size_t rowstride,
+                              uint8_t *data)
+{
+  CoglContext *ctx = COGL_TEXTURE (tex_2d)->context;
+  int bpp;
+  GLenum gl_format;
+  GLenum gl_type;
+
+  bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
+
+  ctx->driver_vtable->pixel_format_to_gl (ctx,
+                                          format,
+                                          NULL, /* internal format */
+                                          &gl_format,
+                                          &gl_type);
+
+  ctx->texture_driver->prep_gl_for_pixels_download (ctx,
+                                                    rowstride,
+                                                    tex_2d->width,
+                                                    bpp);
+
+  _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+                                   tex_2d->gl_texture,
+                                   tex_2d->is_foreign);
+
+  ctx->texture_driver->gl_get_tex_image (ctx,
+                                         GL_TEXTURE_2D,
+                                         gl_format,
+                                         gl_type,
+                                         data);
+}
diff --git a/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/driver/gl/gl/cogl-driver-gl.c
index 06d0024..32bd294 100644
--- a/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -34,6 +34,7 @@
 #include "cogl-renderer-private.h"
 #include "cogl-error-private.h"
 #include "cogl-framebuffer-gl-private.h"
+#include "cogl-texture-2d-gl-private.h"
 
 static CoglBool
 _cogl_driver_pixel_format_from_gl_internal (CoglContext *context,
@@ -533,4 +534,17 @@ _cogl_driver_gl =
     _cogl_framebuffer_gl_discard_buffers,
     _cogl_framebuffer_gl_draw_attributes,
     _cogl_framebuffer_gl_draw_indexed_attributes,
+    _cogl_texture_2d_gl_free,
+    _cogl_texture_2d_gl_can_create,
+    _cogl_texture_2d_gl_init,
+    _cogl_texture_2d_gl_new_with_size,
+    _cogl_texture_2d_gl_new_from_bitmap,
+#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
+    _cogl_egl_texture_2d_gl_new_from_image,
+#endif
+    _cogl_texture_2d_gl_copy_from_framebuffer,
+    _cogl_texture_2d_gl_get_gl_handle,
+    _cogl_texture_2d_gl_generate_mipmap,
+    _cogl_texture_2d_gl_copy_from_bitmap,
+    _cogl_texture_2d_gl_get_data,
   };
diff --git a/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/driver/gl/gles/cogl-driver-gles.c
index 8948d73..eb799a9 100644
--- a/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -33,6 +33,7 @@
 #include "cogl-renderer-private.h"
 #include "cogl-private.h"
 #include "cogl-framebuffer-gl-private.h"
+#include "cogl-texture-2d-gl-private.h"
 
 #ifndef GL_UNSIGNED_INT_24_8
 #define GL_UNSIGNED_INT_24_8 0x84FA
@@ -351,4 +352,17 @@ _cogl_driver_gles =
     _cogl_framebuffer_gl_discard_buffers,
     _cogl_framebuffer_gl_draw_attributes,
     _cogl_framebuffer_gl_draw_indexed_attributes,
+    _cogl_texture_2d_gl_free,
+    _cogl_texture_2d_gl_can_create,
+    _cogl_texture_2d_gl_init,
+    _cogl_texture_2d_gl_new_with_size,
+    _cogl_texture_2d_gl_new_from_bitmap,
+#if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
+    _cogl_egl_texture_2d_gl_new_from_image,
+#endif
+    _cogl_texture_2d_gl_copy_from_framebuffer,
+    _cogl_texture_2d_gl_get_gl_handle,
+    _cogl_texture_2d_gl_generate_mipmap,
+    _cogl_texture_2d_gl_copy_from_bitmap,
+    NULL, /* texture_2d_get_data */
   };
-- 
1.7.7.6



More information about the Cogl mailing list