[cogl/wip/cogl-1.14: 100/177] texture: expose mipmap level in set region apis



commit 71f3b0bdfe677f212f0a882ddfa84abfcd0e47a2
Author: Robert Bragg <robert linux intel com>
Date:   Fri Nov 9 17:55:54 2012 +0000

    texture: expose mipmap level in set region apis
    
    cogl_texture_set_region() and cogl_texture_set_region_from_bitmap() now
    have a level argument so image data can be uploaded to a specific mipmap
    level.
    
    The prototype for cogl_texture_set_region was also updated to simplify
    the arguments.
    
    The arguments for cogl_texture_set_region_from_bitmap were reordered to
    be consistent with cogl_texture_set_region with the source related
    arguments listed first followed by the destination arguments.
    
    Reviewed-by: Neil Roberts <neil linux intel com>
    
    (cherry picked from commit 3a336a8adcd406b53731a6de0e7d97ba7932c1a8)
    
    Note: Public API changes were reverted in cherry-picking this patch

 cogl/cogl-atlas-texture.c                      |   35 ++++---
 cogl/cogl-blit.c                               |   25 +++--
 cogl/cogl-driver.h                             |   16 ++-
 cogl/cogl-pipeline-layer-state.c               |    3 +
 cogl/cogl-pipeline-layer-state.h               |    5 +
 cogl/cogl-sub-texture.c                        |   19 +++-
 cogl/cogl-texture-2d-private.h                 |   18 ++--
 cogl/cogl-texture-2d-sliced.c                  |   30 +++--
 cogl/cogl-texture-2d.c                         |   28 +++--
 cogl/cogl-texture-3d.c                         |   11 +-
 cogl/cogl-texture-driver.h                     |   13 +--
 cogl/cogl-texture-private.h                    |   31 +++++-
 cogl/cogl-texture-rectangle.c                  |    6 +-
 cogl/cogl-texture.c                            |  146 +++++++++++++++++-------
 cogl/cogl-util.h                               |   19 +++
 cogl/driver/gl/cogl-texture-2d-gl-private.h    |   16 ++-
 cogl/driver/gl/cogl-texture-2d-gl.c            |   41 ++++---
 cogl/driver/gl/cogl-texture-gl-private.h       |    7 +
 cogl/driver/gl/cogl-texture-gl.c               |   43 +++++++
 cogl/driver/gl/gl/cogl-texture-driver-gl.c     |   84 +++++++++++---
 cogl/driver/gl/gles/cogl-texture-driver-gles.c |   84 +++++++++++---
 cogl/driver/nop/cogl-texture-2d-nop-private.h  |   16 ++-
 cogl/driver/nop/cogl-texture-2d-nop.c          |   16 ++-
 cogl/winsys/cogl-texture-pixmap-x11.c          |   25 +++--
 24 files changed, 529 insertions(+), 208 deletions(-)
---
diff --git a/cogl/cogl-atlas-texture.c b/cogl/cogl-atlas-texture.c
index a7098b6..da4041f 100644
--- a/cogl/cogl-atlas-texture.c
+++ b/cogl/cogl-atlas-texture.c
@@ -361,14 +361,11 @@ static void
 _cogl_atlas_texture_migrate_out_of_atlas (CoglAtlasTexture *atlas_tex)
 {
   CoglTexture *standalone_tex;
-  CoglContext *ctx;
 
   /* Make sure this texture is not in the atlas */
   if (!atlas_tex->atlas)
     return;
 
-  ctx = COGL_TEXTURE (atlas_tex)->context;
-
   COGL_NOTE (ATLAS, "Migrating texture out of the atlas");
 
   /* We don't know if any journal entries currently depend on
@@ -457,11 +454,12 @@ _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex,
   /* Copy the central data */
   if (!_cogl_texture_set_region_from_bitmap (atlas->texture,
                                              src_x, src_y,
-                                             dst_x + atlas_tex->rectangle.x + 1,
-                                             dst_y + atlas_tex->rectangle.y + 1,
                                              dst_width,
                                              dst_height,
                                              bmp,
+                                             dst_x + atlas_tex->rectangle.x + 1,
+                                             dst_y + atlas_tex->rectangle.y + 1,
+                                             0, /* level 0 */
                                              error))
     return FALSE;
 
@@ -469,42 +467,46 @@ _cogl_atlas_texture_set_region_with_border (CoglAtlasTexture *atlas_tex,
   if (dst_x == 0 &&
       !_cogl_texture_set_region_from_bitmap (atlas->texture,
                                              src_x, src_y,
-                                             atlas_tex->rectangle.x,
-                                             dst_y + atlas_tex->rectangle.y + 1,
                                              1, dst_height,
                                              bmp,
+                                             atlas_tex->rectangle.x,
+                                             dst_y + atlas_tex->rectangle.y + 1,
+                                             0, /* level 0 */
                                              error))
     return FALSE;
   /* Update the right edge pixels */
   if (dst_x + dst_width == atlas_tex->rectangle.width - 2 &&
       !_cogl_texture_set_region_from_bitmap (atlas->texture,
                                              src_x + dst_width - 1, src_y,
+                                             1, dst_height,
+                                             bmp,
                                              atlas_tex->rectangle.x +
                                              atlas_tex->rectangle.width - 1,
                                              dst_y + atlas_tex->rectangle.y + 1,
-                                             1, dst_height,
-                                             bmp,
+                                             0, /* level 0 */
                                              error))
     return FALSE;
   /* Update the top edge pixels */
   if (dst_y == 0 &&
       !_cogl_texture_set_region_from_bitmap (atlas->texture,
                                              src_x, src_y,
-                                             dst_x + atlas_tex->rectangle.x + 1,
-                                             atlas_tex->rectangle.y,
                                              dst_width, 1,
                                              bmp,
+                                             dst_x + atlas_tex->rectangle.x + 1,
+                                             atlas_tex->rectangle.y,
+                                             0, /* level 0 */
                                              error))
     return FALSE;
   /* Update the bottom edge pixels */
   if (dst_y + dst_height == atlas_tex->rectangle.height - 2 &&
       !_cogl_texture_set_region_from_bitmap (atlas->texture,
                                              src_x, src_y + dst_height - 1,
+                                             dst_width, 1,
+                                             bmp,
                                              dst_x + atlas_tex->rectangle.x + 1,
                                              atlas_tex->rectangle.y +
                                              atlas_tex->rectangle.height - 1,
-                                             dst_width, 1,
-                                             bmp,
+                                             0, /* level 0 */
                                              error))
     return FALSE;
 
@@ -567,11 +569,15 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
                                 int dst_y,
                                 int dst_width,
                                 int dst_height,
+                                int level,
                                 CoglBitmap *bmp,
                                 CoglError **error)
 {
   CoglAtlasTexture  *atlas_tex = COGL_ATLAS_TEXTURE (tex);
 
+  if (level != 0 && atlas_tex->atlas)
+    _cogl_atlas_texture_migrate_out_of_atlas (atlas_tex);
+
   /* If the texture is in the atlas then we need to copy the edge
      pixels to the border */
   if (atlas_tex->atlas)
@@ -600,9 +606,10 @@ _cogl_atlas_texture_set_region (CoglTexture *tex,
     /* Otherwise we can just forward on to the sub texture */
     return _cogl_texture_set_region_from_bitmap (atlas_tex->sub_texture,
                                                  src_x, src_y,
-                                                 dst_x, dst_y,
                                                  dst_width, dst_height,
                                                  bmp,
+                                                 dst_x, dst_y,
+                                                 level,
                                                  error);
 }
 
diff --git a/cogl/cogl-blit.c b/cogl/cogl-blit.c
index e86f5ad..5cb5ea4 100644
--- a/cogl/cogl-blit.c
+++ b/cogl/cogl-blit.c
@@ -253,10 +253,11 @@ _cogl_blit_copy_tex_sub_image_blit (CoglBlitData *data,
                                     int height)
 {
   _cogl_texture_2d_copy_from_framebuffer (COGL_TEXTURE_2D (data->dst_tex),
+                                          src_x, src_y,
+                                          width, height,
                                           data->src_fb,
                                           dst_x, dst_y,
-                                          src_x, src_y,
-                                          width, height);
+                                          0); /* level */
 }
 
 static void
@@ -288,14 +289,18 @@ _cogl_blit_get_tex_data_blit (CoglBlitData *data,
                               int width,
                               int height)
 {
-  cogl_texture_set_region (data->dst_tex,
-                           src_x, src_y,
-                           dst_x, dst_y,
-                           width, height,
-                           data->src_width, data->src_height,
-                           data->format,
-                           data->src_width * data->bpp,
-                           data->image_data);
+  CoglError *ignore = NULL;
+  int rowstride = data->src_width * data->bpp;
+  int offset = rowstride * src_y + src_x * data->bpp;
+
+  _cogl_texture_set_region (data->dst_tex,
+                            width, height,
+                            data->format,
+                            rowstride,
+                            data->image_data + offset,
+                            dst_x, dst_y,
+                            0, /* level */
+                            &ignore);
   /* TODO: support chaining up errors during the blit */
 }
 
diff --git a/cogl/cogl-driver.h b/cogl/cogl-driver.h
index 6bfdcd6..ba6e030 100644
--- a/cogl/cogl-driver.h
+++ b/cogl/cogl-driver.h
@@ -168,13 +168,14 @@ struct _CoglDriverVtable
    */
   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);
+                                        int height,
+                                        CoglFramebuffer *src_fb,
+                                        int dst_x,
+                                        int dst_y,
+                                        int level);
 
   /* If the given texture has a corresponding OpenGL texture handle
    * then return that.
@@ -196,13 +197,14 @@ struct _CoglDriverVtable
    */
   CoglBool
   (* 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,
+                                   CoglBitmap *bitmap,
+                                   int dst_x,
+                                   int dst_y,
+                                   int level,
                                    CoglError **error);
 
   /* Reads back the full contents of the given texture and write it to
diff --git a/cogl/cogl-pipeline-layer-state.c b/cogl/cogl-pipeline-layer-state.c
index b69ff46..606d121 100644
--- a/cogl/cogl-pipeline-layer-state.c
+++ b/cogl/cogl-pipeline-layer-state.c
@@ -1595,6 +1595,9 @@ cogl_pipeline_set_layer_filters (CoglPipeline      *pipeline,
 
   _COGL_RETURN_IF_FAIL (cogl_is_pipeline (pipeline));
 
+  _COGL_RETURN_IF_FAIL (mag_filter == COGL_PIPELINE_FILTER_NEAREST ||
+                        mag_filter == COGL_PIPELINE_FILTER_LINEAR);
+
   /* Note: this will ensure that the layer exists, creating one if it
    * doesn't already.
    *
diff --git a/cogl/cogl-pipeline-layer-state.h b/cogl/cogl-pipeline-layer-state.h
index 220995b..25a0b65 100644
--- a/cogl/cogl-pipeline-layer-state.h
+++ b/cogl/cogl-pipeline-layer-state.h
@@ -359,6 +359,11 @@ cogl_pipeline_get_n_layers (CoglPipeline *pipeline);
  * Changes the decimation and interpolation filters used when a texture is
  * drawn at other scales than 100%.
  *
+ * <note>It is an error to pass anything other than
+ * %COGL_PIPELINE_FILTER_NEAREST or %COGL_PIPELINE_FILTER_LINEAR as
+ * magnification filters since magnification doesn't ever need to
+ * reference values stored in the mipmap chain.</note>
+ *
  * Since: 1.10
  * Stability: unstable
  */
diff --git a/cogl/cogl-sub-texture.c b/cogl/cogl-sub-texture.c
index 1f56f48..6263245 100644
--- a/cogl/cogl-sub-texture.c
+++ b/cogl/cogl-sub-texture.c
@@ -374,17 +374,32 @@ _cogl_sub_texture_set_region (CoglTexture *tex,
                               int dst_y,
                               int dst_width,
                               int dst_height,
+                              int level,
                               CoglBitmap *bmp,
                               CoglError **error)
 {
   CoglSubTexture  *sub_tex = COGL_SUB_TEXTURE (tex);
 
+  if (level != 0)
+    {
+      int full_width = cogl_texture_get_width (sub_tex->full_texture);
+      int full_height = cogl_texture_get_width (sub_tex->full_texture);
+
+      _COGL_RETURN_VAL_IF_FAIL (sub_tex->sub_x == 0 &&
+                                cogl_texture_get_width (tex) == full_width,
+                                FALSE);
+      _COGL_RETURN_VAL_IF_FAIL (sub_tex->sub_y == 0 &&
+                                cogl_texture_get_height (tex) == full_height,
+                                FALSE);
+    }
+
   return _cogl_texture_set_region_from_bitmap (sub_tex->full_texture,
                                                src_x, src_y,
-                                               dst_x + sub_tex->sub_x,
-                                               dst_y + sub_tex->sub_y,
                                                dst_width, dst_height,
                                                bmp,
+                                               dst_x + sub_tex->sub_x,
+                                               dst_y + sub_tex->sub_y,
+                                               level,
                                                error);
 }
 
diff --git a/cogl/cogl-texture-2d-private.h b/cogl/cogl-texture-2d-private.h
index aa5a35e..39c9f25 100644
--- a/cogl/cogl-texture-2d-private.h
+++ b/cogl/cogl-texture-2d-private.h
@@ -51,7 +51,7 @@ struct _CoglTexture2D
    * of driver private state. */
 
   /* The internal format of the GL texture represented as a GL enum */
-  GLenum gl_format;
+  GLenum gl_internal_format;
   /* The texture object number */
   GLuint gl_texture;
   GLenum gl_legacy_texobj_min_filter;
@@ -98,25 +98,27 @@ _cogl_texture_2d_externally_modified (CoglTexture *texture);
 /*
  * _cogl_texture_2d_copy_from_framebuffer:
  * @texture: A #CoglTexture2D pointer
- * @src_fb: A source #CoglFramebuffer to copy from
- * @dst_x: X-position to store the image within the texture
- * @dst_y: Y-position to store the image within the texture
  * @src_x: X-position to within the framebuffer to read from
  * @src_y: Y-position to within the framebuffer to read from
  * @width: width of the rectangle to copy
  * @height: height of the rectangle to copy
+ * @src_fb: A source #CoglFramebuffer to copy from
+ * @dst_x: X-position to store the image within the texture
+ * @dst_y: Y-position to store the image within the texture
+ * @level: The mipmap level of @texture to copy too
  *
  * This copies a portion of the given @src_fb into the
  * texture.
  */
 void
 _cogl_texture_2d_copy_from_framebuffer (CoglTexture2D *texture,
-                                        CoglFramebuffer *src_fb,
-                                        int dst_x,
-                                        int dst_y,
                                         int src_x,
                                         int src_y,
                                         int width,
-                                        int height);
+                                        int height,
+                                        CoglFramebuffer *src_fb,
+                                        int dst_x,
+                                        int dst_y,
+                                        int level);
 
 #endif /* __COGL_TEXTURE_2D_PRIVATE_H */
diff --git a/cogl/cogl-texture-2d-sliced.c b/cogl/cogl-texture-2d-sliced.c
index 0bd29cb..a1f68b2 100644
--- a/cogl/cogl-texture-2d-sliced.c
+++ b/cogl/cogl-texture-2d-sliced.c
@@ -48,6 +48,7 @@
 #include "cogl-pipeline-opengl-private.h"
 #include "cogl-primitive-texture.h"
 #include "cogl-error-private.h"
+#include "cogl-texture-gl-private.h"
 
 #include <string.h>
 #include <stdlib.h>
@@ -238,15 +239,16 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds,
           if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex),
                                                      0, /* src_x */
                                                      0, /* src_y */
+                                                     x_span->waste, /* width */
+                                                     /* height */
+                                                     y_iter->intersect_end -
+                                                     y_iter->intersect_start,
+                                                     waste_bmp,
                                                      /* dst_x */
                                                      x_span->size - x_span->waste,
                                                      y_iter->intersect_start -
                                                      y_span->start, /* dst_y */
-                                                     x_span->waste, /* dst_width */
-                                                     /* dst_height */
-                                                     y_iter->intersect_end -
-                                                     y_iter->intersect_start,
-                                                     waste_bmp,
+                                                     0, /* level */
                                                      error))
             {
               cogl_object_unref (waste_bmp);
@@ -298,14 +300,15 @@ _cogl_texture_2d_sliced_set_waste (CoglTexture2DSliced *tex_2ds,
           if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex),
                                                      0, /* src_x */
                                                      0, /* src_y */
+                                                     copy_width, /* width */
+                                                     y_span->waste, /* height */
+                                                     waste_bmp,
                                                      /* dst_x */
                                                      x_iter->intersect_start -
                                                      x_iter->pos,
                                                      /* dst_y */
                                                      y_span->size - y_span->waste,
-                                                     copy_width, /* dst_width */
-                                                     y_span->waste, /* dst_height */
-                                                     waste_bmp,
+                                                     0, /* level */
                                                      error))
             {
               cogl_object_unref (waste_bmp);
@@ -359,13 +362,14 @@ _cogl_texture_2d_sliced_upload_to_gl (CoglTexture2DSliced *tex_2ds,
           if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex),
                                                      x_span->start, /* src x */
                                                      y_span->start, /* src y */
-                                                     0, /* dst x */
-                                                     0, /* dst y */
                                                      x_span->size -
                                                      x_span->waste, /* width */
                                                      y_span->size -
                                                      y_span->waste, /* height */
                                                      bmp,
+                                                     0, /* dst x */
+                                                     0, /* dst y */
+                                                     0, /* level */
                                                      error))
             {
               if (waste_buf)
@@ -495,11 +499,12 @@ _cogl_texture_2d_sliced_upload_subregion_to_gl (CoglTexture2DSliced *tex_2ds,
           if (!_cogl_texture_set_region_from_bitmap (COGL_TEXTURE (slice_tex),
                                                      source_x,
                                                      source_y,
-                                                     local_x, /* dst x */
-                                                     local_y, /* dst y */
                                                      inter_w, /* width */
                                                      inter_h, /* height */
                                                      source_bmp,
+                                                     local_x, /* dst x */
+                                                     local_y, /* dst y */
+                                                     0, /* level */
                                                      error))
             {
               if (waste_buf)
@@ -1286,6 +1291,7 @@ _cogl_texture_2d_sliced_set_region (CoglTexture *tex,
                                     int dst_y,
                                     int dst_width,
                                     int dst_height,
+                                    int level,
                                     CoglBitmap *bmp,
                                     CoglError **error)
 {
diff --git a/cogl/cogl-texture-2d.c b/cogl/cogl-texture-2d.c
index 853e646..9df370d 100644
--- a/cogl/cogl-texture-2d.c
+++ b/cogl/cogl-texture-2d.c
@@ -343,24 +343,26 @@ _cogl_texture_2d_externally_modified (CoglTexture *texture)
 
 void
 _cogl_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)
+                                        int height,
+                                        CoglFramebuffer *src_fb,
+                                        int dst_x,
+                                        int dst_y,
+                                        int level)
 {
   CoglContext *ctx = COGL_TEXTURE (tex_2d)->context;
 
   ctx->driver_vtable->texture_2d_copy_from_framebuffer (tex_2d,
-                                                        src_fb,
-                                                        dst_x,
-                                                        dst_y,
                                                         src_x,
                                                         src_y,
                                                         width,
-                                                        height);
+                                                        height,
+                                                        src_fb,
+                                                        dst_x,
+                                                        dst_y,
+                                                        level);
 
   tex_2d->mipmaps_dirty = TRUE;
 }
@@ -479,6 +481,7 @@ _cogl_texture_2d_set_region (CoglTexture *tex,
                              int dst_y,
                              int width,
                              int height,
+                             int level,
                              CoglBitmap *bmp,
                              CoglError **error)
 {
@@ -486,13 +489,14 @@ _cogl_texture_2d_set_region (CoglTexture *tex,
   CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
 
   if (!ctx->driver_vtable->texture_2d_copy_from_bitmap (tex_2d,
-                                                        bmp,
-                                                        dst_x,
-                                                        dst_y,
                                                         src_x,
                                                         src_y,
                                                         width,
                                                         height,
+                                                        bmp,
+                                                        dst_x,
+                                                        dst_y,
+                                                        level,
                                                         error))
     {
       return FALSE;
@@ -530,7 +534,7 @@ _cogl_texture_2d_get_format (CoglTexture *tex)
 static GLenum
 _cogl_texture_2d_get_gl_format (CoglTexture *tex)
 {
-  return COGL_TEXTURE_2D (tex)->gl_format;
+  return COGL_TEXTURE_2D (tex)->gl_internal_format;
 }
 
 static int
diff --git a/cogl/cogl-texture-3d.c b/cogl/cogl-texture-3d.c
index 0b3fa81..e7a9051 100644
--- a/cogl/cogl-texture-3d.c
+++ b/cogl/cogl-texture-3d.c
@@ -31,6 +31,7 @@
 #include "cogl-texture-private.h"
 #include "cogl-texture-3d-private.h"
 #include "cogl-texture-3d.h"
+#include "cogl-texture-gl-private.h"
 #include "cogl-texture-driver.h"
 #include "cogl-context-private.h"
 #include "cogl-object-private.h"
@@ -547,17 +548,18 @@ _cogl_texture_3d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags)
   if ((flags & COGL_TEXTURE_NEEDS_MIPMAP) &&
       tex_3d->auto_mipmap && tex_3d->mipmaps_dirty)
     {
-      _cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
-                                       tex_3d->gl_texture,
-                                       FALSE);
       /* 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_3D);
+        _cogl_texture_gl_generate_mipmaps (tex);
 #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
       else if (ctx->driver != COGL_DRIVER_GLES2)
         {
+          _cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
+                                           tex_3d->gl_texture,
+                                           FALSE);
+
           GE( ctx, glTexParameteri (GL_TEXTURE_3D,
                                     GL_GENERATE_MIPMAP,
                                     GL_TRUE) );
@@ -596,6 +598,7 @@ _cogl_texture_3d_set_region (CoglTexture *tex,
                              int dst_y,
                              int dst_width,
                              int dst_height,
+                             int level,
                              CoglBitmap *bmp,
                              CoglError **error)
 {
diff --git a/cogl/cogl-texture-driver.h b/cogl/cogl-texture-driver.h
index 780f40d..8ab8655 100644
--- a/cogl/cogl-texture-driver.h
+++ b/cogl/cogl-texture-driver.h
@@ -65,8 +65,7 @@ struct _CoglTextureDriver
    */
   CoglBool
   (* upload_subregion_to_gl) (CoglContext *ctx,
-                              GLenum gl_target,
-                              GLuint gl_handle,
+                              CoglTexture *texture,
                               CoglBool is_foreign,
                               int src_x,
                               int src_y,
@@ -74,6 +73,7 @@ struct _CoglTextureDriver
                               int dst_y,
                               int width,
                               int height,
+                              int level,
                               CoglBitmap *source_bmp,
                               GLuint source_gl_format,
                               GLuint source_gl_type,
@@ -183,15 +183,6 @@ struct _CoglTextureDriver
                                 GLenum gl_target);
 
   /*
-   * glGenerateMipmap semantics may need to be emulated for some
-   * drivers. E.g. by enabling auto mipmap generation an re-loading a
-   * number of known texels.
-   */
-  void
-  (* gl_generate_mipmaps) (CoglContext *ctx,
-                           GLenum texture_target);
-
-  /*
    * The driver may impose constraints on what formats can be used to store
    * texture data read from textures. For example GLES currently only supports
    * RGBA_8888, and so we need to manually convert the data if the final
diff --git a/cogl/cogl-texture-private.h b/cogl/cogl-texture-private.h
index 05c16d4..c25883e 100644
--- a/cogl/cogl-texture-private.h
+++ b/cogl/cogl-texture-private.h
@@ -72,6 +72,7 @@ struct _CoglTextureVtable
                            int dst_y,
                            int dst_width,
                            int dst_height,
+                           int level,
                            CoglBitmap *bitmap,
                            CoglError **error);
 
@@ -142,6 +143,7 @@ struct _CoglTexture
   CoglObject _parent;
   CoglContext *context;
   GList *framebuffers;
+  int max_level;
   const CoglTextureVtable *vtable;
 };
 
@@ -276,6 +278,18 @@ _cogl_texture_spans_foreach_in_region (CoglSpan *x_spans,
 CoglTextureType
 _cogl_texture_get_type (CoglTexture *texture);
 
+CoglBool
+_cogl_texture_set_region (CoglTexture *texture,
+                          int width,
+                          int height,
+                          CoglPixelFormat format,
+                          int rowstride,
+                          const uint8_t *data,
+                          int dst_x,
+                          int dst_y,
+                          int level,
+                          CoglError **error);
+
 CoglTexture *
 _cogl_texture_new_from_bitmap (CoglBitmap *bitmap,
                                CoglTextureFlags flags,
@@ -286,15 +300,26 @@ CoglBool
 _cogl_texture_set_region_from_bitmap (CoglTexture *texture,
                                       int src_x,
                                       int src_y,
+                                      int width,
+                                      int height,
+                                      CoglBitmap *bmp,
                                       int dst_x,
                                       int dst_y,
-                                      unsigned int dst_width,
-                                      unsigned int dst_height,
-                                      CoglBitmap *bmp,
+                                      int level,
                                       CoglError **error);
 
 CoglBool
 _cogl_texture_needs_premult_conversion (CoglPixelFormat src_format,
                                         CoglPixelFormat dst_format);
 
+int
+_cogl_texture_get_n_levels (CoglTexture *texture);
+
+void
+_cogl_texture_get_level_size (CoglTexture *texture,
+                              int level,
+                              int *width,
+                              int *height,
+                              int *depth);
+
 #endif /* __COGL_TEXTURE_PRIVATE_H */
diff --git a/cogl/cogl-texture-rectangle.c b/cogl/cogl-texture-rectangle.c
index e8bb965..28dcd57 100644
--- a/cogl/cogl-texture-rectangle.c
+++ b/cogl/cogl-texture-rectangle.c
@@ -554,10 +554,10 @@ _cogl_texture_rectangle_set_region (CoglTexture *tex,
                                     int dst_y,
                                     int dst_width,
                                     int dst_height,
+                                    int level,
                                     CoglBitmap *bmp,
                                     CoglError **error)
 {
-  CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
   GLenum gl_format;
   GLenum gl_type;
   CoglContext *ctx = tex->context;
@@ -576,12 +576,12 @@ _cogl_texture_rectangle_set_region (CoglTexture *tex,
   /* Send data to GL */
   status =
     ctx->texture_driver->upload_subregion_to_gl (ctx,
-                                                 GL_TEXTURE_RECTANGLE_ARB,
-                                                 tex_rect->gl_texture,
+                                                 tex,
                                                  FALSE,
                                                  src_x, src_y,
                                                  dst_x, dst_y,
                                                  dst_width, dst_height,
+                                                 level,
                                                  bmp,
                                                  gl_format,
                                                  gl_type,
diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c
index 14eb5f8..2fbd5ba 100644
--- a/cogl/cogl-texture.c
+++ b/cogl/cogl-texture.c
@@ -43,6 +43,7 @@
 #include "cogl-texture-2d-sliced-private.h"
 #include "cogl-texture-2d-private.h"
 #include "cogl-texture-2d-gl.h"
+#include "cogl-texture-3d-private.h"
 #include "cogl-texture-rectangle-private.h"
 #include "cogl-sub-texture-private.h"
 #include "cogl-atlas-texture-private.h"
@@ -134,6 +135,7 @@ _cogl_texture_init (CoglTexture *texture,
                     const CoglTextureVtable *vtable)
 {
   texture->context = context;
+  texture->max_level = 0;
   texture->vtable = vtable;
   texture->framebuffers = NULL;
 }
@@ -328,6 +330,61 @@ cogl_texture_get_max_waste (CoglTexture *texture)
   return texture->vtable->get_max_waste (texture);
 }
 
+int
+_cogl_texture_get_n_levels (CoglTexture *texture)
+{
+  int width = cogl_texture_get_width (texture);
+  int height = cogl_texture_get_height (texture);
+  int max_dimension = MAX (width, height);
+
+  if (cogl_is_texture_3d (texture))
+    {
+      CoglTexture3D *tex_3d = COGL_TEXTURE_3D (texture);
+      max_dimension = MAX (max_dimension, tex_3d->depth);
+    }
+
+  return _cogl_util_fls (max_dimension);
+}
+
+void
+_cogl_texture_get_level_size (CoglTexture *texture,
+                              int level,
+                              int *width,
+                              int *height,
+                              int *depth)
+{
+  int current_width = cogl_texture_get_width (texture);
+  int current_height = cogl_texture_get_height (texture);
+  int current_depth;
+  int i;
+
+  if (cogl_is_texture_3d (texture))
+    {
+      CoglTexture3D *tex_3d = COGL_TEXTURE_3D (texture);
+      current_depth = tex_3d->depth;
+    }
+  else
+    current_depth = 0;
+
+  /* NB: The OpenGL spec (like D3D) uses a floor() convention to
+   * round down the size of a mipmap level when dividing the size
+   * of the previous level results in a fraction...
+   */
+  for (i = 0; i < level; i++)
+    {
+      current_width = MAX (1, current_width >> 1);
+      current_height = MAX (1, current_height >> 1);
+      current_depth = MAX (1, current_depth >> 1);
+    }
+
+  if (width)
+    *width = current_width;
+  if (height)
+    *height = current_height;
+  if (depth)
+    *depth = current_depth;
+}
+
 CoglBool
 cogl_texture_is_sliced (CoglTexture *texture)
 {
@@ -399,22 +456,21 @@ CoglBool
 _cogl_texture_set_region_from_bitmap (CoglTexture *texture,
                                       int src_x,
                                       int src_y,
+                                      int width,
+                                      int height,
+                                      CoglBitmap *bmp,
                                       int dst_x,
                                       int dst_y,
-                                      unsigned int dst_width,
-                                      unsigned int dst_height,
-                                      CoglBitmap *bmp,
+                                      int level,
                                       CoglError **error)
 {
-  CoglBool ret;
-
   _COGL_RETURN_VAL_IF_FAIL ((cogl_bitmap_get_width (bmp) - src_x)
-                            >= dst_width, FALSE);
+                            >= width, FALSE);
   _COGL_RETURN_VAL_IF_FAIL ((cogl_bitmap_get_height (bmp) - src_y)
-                            >= dst_height, FALSE);
+                            >= height, FALSE);
 
   /* Shortcut out early if the image is empty */
-  if (dst_width == 0 || dst_height == 0)
+  if (width == 0 || height == 0)
     return TRUE;
 
   /* Note that we don't prepare the bitmap for upload here because
@@ -424,14 +480,13 @@ _cogl_texture_set_region_from_bitmap (CoglTexture *texture,
      always stored in an RGBA texture even if the texture format is
      advertised as RGB. */
 
-  ret = texture->vtable->set_region (texture,
-                                     src_x, src_y,
-                                     dst_x, dst_y,
-                                     dst_width, dst_height,
-                                     bmp,
-                                     error);
-
-  return ret;
+  return texture->vtable->set_region (texture,
+                                      src_x, src_y,
+                                      dst_x, dst_y,
+                                      width, height,
+                                      level,
+                                      bmp,
+                                      error);
 }
 
 CoglBool
@@ -448,9 +503,10 @@ cogl_texture_set_region_from_bitmap (CoglTexture *texture,
   CoglBool status =
     _cogl_texture_set_region_from_bitmap (texture,
                                           src_x, src_y,
-                                          dst_x, dst_y,
                                           dst_width, dst_height,
                                           bitmap,
+                                          dst_x, dst_y,
+                                          0, /* level */
                                           &ignore_error);
 
   if (!status)
@@ -458,31 +514,23 @@ cogl_texture_set_region_from_bitmap (CoglTexture *texture,
   return status;
 }
 
-static CoglBool
+CoglBool
 _cogl_texture_set_region (CoglTexture *texture,
-                          int src_x,
-                          int src_y,
-                          int dst_x,
-                          int dst_y,
-                          unsigned int dst_width,
-                          unsigned int dst_height,
                           int width,
                           int height,
                           CoglPixelFormat format,
-                          unsigned int rowstride,
+                          int rowstride,
                           const uint8_t *data,
+                          int dst_x,
+                          int dst_y,
+                          int level,
                           CoglError **error)
 {
   CoglContext *ctx = texture->context;
   CoglBitmap *source_bmp;
   CoglBool ret;
 
-  _COGL_RETURN_VAL_IF_FAIL ((width - src_x) >= dst_width, FALSE);
-  _COGL_RETURN_VAL_IF_FAIL ((height - src_y) >= dst_height, FALSE);
-
-  /* Check for valid format */
-  if (format == COGL_PIXEL_FORMAT_ANY)
-    return FALSE;
+  _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, FALSE);
 
   /* Rowstride from width if none specified */
   if (rowstride == 0)
@@ -496,10 +544,11 @@ _cogl_texture_set_region (CoglTexture *texture,
                                          (uint8_t *) data);
 
   ret = _cogl_texture_set_region_from_bitmap (texture,
-                                              src_x, src_y,
-                                              dst_x, dst_y,
-                                              dst_width, dst_height,
+                                              0, 0,
+                                              width, height,
                                               source_bmp,
+                                              dst_x, dst_y,
+                                              level,
                                               error);
 
   cogl_object_unref (source_bmp);
@@ -522,15 +571,26 @@ cogl_texture_set_region (CoglTexture *texture,
 			 const uint8_t *data)
 {
   CoglError *ignore_error = NULL;
-  CoglBool status = _cogl_texture_set_region (texture,
-                                              src_x, src_y,
-                                              dst_x, dst_y,
-                                              dst_width, dst_height,
-                                              width, height,
-                                              format,
-                                              rowstride,
-                                              data,
-                                              &ignore_error);
+  const uint8_t *first_pixel;
+  int bytes_per_pixel = _cogl_pixel_format_get_bytes_per_pixel (format);
+  CoglBool status;
+
+  /* Rowstride from width if none specified */
+  if (rowstride == 0)
+    rowstride = bytes_per_pixel * width;
+
+  first_pixel = data + rowstride * src_y + bytes_per_pixel * src_x;
+
+  status = _cogl_texture_set_region (texture,
+                                     dst_width,
+                                     dst_height,
+                                     format,
+                                     rowstride,
+                                     first_pixel,
+                                     dst_x,
+                                     dst_y,
+                                     0,
+                                     &ignore_error);
   if (!status)
     cogl_error_free (ignore_error);
   return status;
diff --git a/cogl/cogl-util.h b/cogl/cogl-util.h
index 1f3d266..6e02ad7 100644
--- a/cogl/cogl-util.h
+++ b/cogl/cogl-util.h
@@ -124,6 +124,7 @@ _cogl_util_one_at_a_time_mix (unsigned int hash);
 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
 #define COGL_UTIL_HAVE_BUILTIN_FFSL
 #define COGL_UTIL_HAVE_BUILTIN_POPCOUNTL
+#define COGL_UTIL_HAVE_BUILTIN_CLZ
 #endif
 
 /* The 'ffs' function is part of C99 so it isn't always available */
@@ -148,6 +149,24 @@ int
 _cogl_util_ffsl_wrapper (long int num);
 #endif /* COGL_UTIL_HAVE_BUILTIN_FFSL */
 
+static inline unsigned int
+_cogl_util_fls (unsigned int n)
+{
+#ifdef COGL_UTIL_HAVE_BUILTIN_CLZ
+   return n == 0 ? 0 : sizeof (unsigned int) * 8 - __builtin_clz (n);
+#else
+   unsigned int v = 1;
+
+   if (n == 0)
+      return 0;
+
+   while (n >>= 1)
+       v++;
+
+   return v;
+#endif
+}
+
 #ifdef COGL_UTIL_HAVE_BUILTIN_POPCOUNTL
 #define _cogl_util_popcountl __builtin_popcountl
 #else
diff --git a/cogl/driver/gl/cogl-texture-2d-gl-private.h b/cogl/driver/gl/cogl-texture-2d-gl-private.h
index ac0c89f..d77f460 100644
--- a/cogl/driver/gl/cogl-texture-2d-gl-private.h
+++ b/cogl/driver/gl/cogl-texture-2d-gl-private.h
@@ -79,13 +79,14 @@ _cogl_texture_2d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex,
 
 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);
+                                           int height,
+                                           CoglFramebuffer *src_fb,
+                                           int dst_x,
+                                           int dst_y,
+                                           int level);
 
 unsigned int
 _cogl_texture_2d_gl_get_gl_handle (CoglTexture2D *tex_2d);
@@ -95,13 +96,14 @@ _cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d);
 
 CoglBool
 _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,
+                                      CoglBitmap *bitmap,
+                                      int dst_x,
+                                      int dst_y,
+                                      int level,
                                       CoglError **error);
 
 void
diff --git a/cogl/driver/gl/cogl-texture-2d-gl.c b/cogl/driver/gl/cogl-texture-2d-gl.c
index d6855aa..cf46492 100644
--- a/cogl/driver/gl/cogl-texture-2d-gl.c
+++ b/cogl/driver/gl/cogl-texture-2d-gl.c
@@ -35,6 +35,7 @@
 #include "cogl-texture-2d-gl.h"
 #include "cogl-texture-2d-gl-private.h"
 #include "cogl-texture-2d-private.h"
+#include "cogl-texture-gl-private.h"
 #include "cogl-pipeline-opengl-private.h"
 #include "cogl-error-private.h"
 #include "cogl-util-gl-private.h"
@@ -112,6 +113,9 @@ _cogl_texture_2d_gl_new_with_size (CoglContext *ctx,
 
   tex_2d->gl_texture =
     ctx->texture_driver->gen (ctx, GL_TEXTURE_2D, internal_format);
+
+  tex_2d->gl_internal_format = gl_intformat;
+
   _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
                                    tex_2d->gl_texture,
                                    tex_2d->is_foreign);
@@ -205,7 +209,7 @@ _cogl_texture_2d_gl_new_from_bitmap (CoglBitmap *bmp,
       return NULL;
     }
 
-  tex_2d->gl_format = gl_intformat;
+  tex_2d->gl_internal_format = gl_intformat;
 
   cogl_object_unref (dst_bmp);
 
@@ -441,7 +445,7 @@ cogl_texture_2d_new_from_foreign (CoglContext *ctx,
   tex_2d->format = format;
 
   tex_2d->gl_texture = gl_handle;
-  tex_2d->gl_format = gl_int_format;
+  tex_2d->gl_internal_format = gl_int_format;
 
   /* Unknown filter */
   tex_2d->gl_legacy_texobj_min_filter = GL_FALSE;
@@ -452,13 +456,14 @@ cogl_texture_2d_new_from_foreign (CoglContext *ctx,
 
 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)
+                                           int height,
+                                           CoglFramebuffer *src_fb,
+                                           int dst_x,
+                                           int dst_y,
+                                           int level)
 {
   CoglContext *ctx = COGL_TEXTURE (tex_2d)->context;
 
@@ -492,18 +497,18 @@ _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);
+    _cogl_texture_gl_generate_mipmaps (COGL_TEXTURE (tex_2d));
 #if defined(HAVE_COGL_GLES) || defined(HAVE_COGL_GL)
   else
     {
+      _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
+                                       tex_2d->gl_texture,
+                                       tex_2d->is_foreign);
+
       GE( ctx, glTexParameteri (GL_TEXTURE_2D,
                                 GL_GENERATE_MIPMAP,
                                 GL_TRUE) );
@@ -520,13 +525,14 @@ _cogl_texture_2d_gl_generate_mipmap (CoglTexture2D *tex_2d)
 
 CoglBool
 _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,
+                                      CoglBitmap *bmp,
+                                      int dst_x,
+                                      int dst_y,
+                                      int level,
                                       CoglError **error)
 {
   CoglTexture *tex = COGL_TEXTURE (tex_2d);
@@ -574,14 +580,13 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
         }
     }
 
-  /* Send data to GL */
   status = ctx->texture_driver->upload_subregion_to_gl (ctx,
-                                                        GL_TEXTURE_2D,
-                                                        tex_2d->gl_texture,
+                                                        tex,
                                                         FALSE,
                                                         src_x, src_y,
                                                         dst_x, dst_y,
                                                         width, height,
+                                                        level,
                                                         bmp,
                                                         gl_format,
                                                         gl_type,
@@ -589,6 +594,8 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
 
   cogl_object_unref (bmp);
 
+  _cogl_texture_gl_maybe_update_max_level (tex, level);
+
   return status;
 }
 
diff --git a/cogl/driver/gl/cogl-texture-gl-private.h b/cogl/driver/gl/cogl-texture-gl-private.h
index b44861c..4ed671b 100644
--- a/cogl/driver/gl/cogl-texture-gl-private.h
+++ b/cogl/driver/gl/cogl-texture-gl-private.h
@@ -46,4 +46,11 @@ _cogl_texture_gl_flush_legacy_texobj_filters (CoglTexture *texture,
                                               unsigned int min_filter,
                                               unsigned int mag_filter);
 
+void
+_cogl_texture_gl_maybe_update_max_level (CoglTexture *texture,
+                                         int max_level);
+
+void
+_cogl_texture_gl_generate_mipmaps (CoglTexture *texture);
+
 #endif /* _COGL_TEXTURE_GL_PRIVATE_H_ */
diff --git a/cogl/driver/gl/cogl-texture-gl.c b/cogl/driver/gl/cogl-texture-gl.c
index a9f0d32..7572fcb 100644
--- a/cogl/driver/gl/cogl-texture-gl.c
+++ b/cogl/driver/gl/cogl-texture-gl.c
@@ -29,7 +29,9 @@
 #include "cogl-internal.h"
 #include "cogl-context-private.h"
 #include "cogl-texture-gl-private.h"
+#include "cogl-texture-3d-private.h"
 #include "cogl-util.h"
+#include "cogl-pipeline-opengl-private.h"
 
 static inline int
 calculate_alignment (int rowstride)
@@ -92,3 +94,44 @@ _cogl_texture_gl_flush_legacy_texobj_filters (CoglTexture *texture,
   texture->vtable->gl_flush_legacy_texobj_filters (texture,
                                                    min_filter, mag_filter);
 }
+
+void
+_cogl_texture_gl_maybe_update_max_level (CoglTexture *texture,
+                                         int max_level)
+{
+  if (texture->max_level < max_level)
+    {
+      CoglContext *ctx = texture->context;
+      GLuint gl_handle;
+      GLenum gl_target;
+
+      cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target);
+
+      texture->max_level = max_level;
+
+      _cogl_bind_gl_texture_transient (gl_target,
+                                       gl_handle,
+                                       _cogl_texture_is_foreign (texture));
+
+      GE( ctx, glTexParameteri (gl_target,
+                                GL_TEXTURE_MAX_LEVEL, texture->max_level));
+    }
+}
+
+void
+_cogl_texture_gl_generate_mipmaps (CoglTexture *texture)
+{
+  CoglContext *ctx = texture->context;
+  int n_levels = _cogl_texture_get_n_levels (texture);
+  GLuint gl_handle;
+  GLenum gl_target;
+
+  _cogl_texture_gl_maybe_update_max_level (texture, n_levels - 1);
+
+  cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target);
+
+  _cogl_bind_gl_texture_transient (gl_target,
+                                   gl_handle,
+                                   _cogl_texture_is_foreign (texture));
+  GE( ctx, glGenerateMipmap (gl_target) );
+}
diff --git a/cogl/driver/gl/gl/cogl-texture-driver-gl.c b/cogl/driver/gl/gl/cogl-texture-driver-gl.c
index 905f58a..ca0ea40 100644
--- a/cogl/driver/gl/gl/cogl-texture-driver-gl.c
+++ b/cogl/driver/gl/gl/cogl-texture-driver-gl.c
@@ -67,6 +67,14 @@ _cogl_texture_driver_gen (CoglContext *ctx,
     {
     case GL_TEXTURE_2D:
     case GL_TEXTURE_3D:
+      /* In case automatic mipmap generation gets disabled for this
+       * texture but a minification filter depending on mipmap
+       * interpolation is selected then we initialize the max mipmap
+       * level to 0 so OpenGL will consider the texture storage to be
+       * "complete".
+       */
+      GE( ctx, glTexParameteri (gl_target, GL_TEXTURE_MAX_LEVEL, 0));
+
       /* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set it */
       GE( ctx, glTexParameteri (gl_target,
                                 GL_TEXTURE_MIN_FILTER,
@@ -170,8 +178,7 @@ _cogl_texture_driver_prep_gl_for_pixels_download (CoglContext *ctx,
 
 static CoglBool
 _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
-                                             GLenum gl_target,
-                                             GLuint gl_handle,
+                                             CoglTexture *texture,
                                              CoglBool is_foreign,
                                              int src_x,
                                              int src_y,
@@ -179,17 +186,24 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
                                              int dst_y,
                                              int width,
                                              int height,
+                                             int level,
                                              CoglBitmap  *source_bmp,
 				             GLuint source_gl_format,
 				             GLuint source_gl_type,
                                              CoglError **error)
 {
+  GLenum gl_target;
+  GLuint gl_handle;
   uint8_t *data;
   CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
   int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
   GLenum gl_error;
   CoglBool status = TRUE;
   CoglError *internal_error = NULL;
+  int level_width;
+  int level_height;
+
+  cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target);
 
   data = _cogl_bitmap_gl_bind (source_bmp, COGL_BUFFER_ACCESS_READ, 0, &internal_error);
 
@@ -216,12 +230,58 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
   while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
     ;
 
-  ctx->glTexSubImage2D (gl_target, 0,
-                        dst_x, dst_y,
-                        width, height,
-                        source_gl_format,
-                        source_gl_type,
-                        data);
+  _cogl_texture_get_level_size (texture,
+                                level,
+                                &level_width,
+                                &level_height,
+                                NULL);
+
+  if (level_width == width && level_height == height)
+    {
+      /* GL gets upset if you use glTexSubImage2D to initialize the
+       * contents of a mipmap level so we make sure to use
+       * glTexImage2D if we are uploading a full mipmap level.
+       */
+      ctx->glTexImage2D (gl_target,
+                         level,
+                         _cogl_texture_get_gl_format (texture),
+                         width,
+                         height,
+                         0,
+                         source_gl_format,
+                         source_gl_type,
+                         data);
+
+    }
+  else
+    {
+      /* GL gets upset if you use glTexSubImage2D to initialize the
+       * contents of a mipmap level so if this is the first time
+       * we've seen a request to upload to this level we call
+       * glTexImage2D first to assert that the storage for this
+       * level exists.
+       */
+      if (texture->max_level < level)
+        {
+          ctx->glTexImage2D (gl_target,
+                             level,
+                             _cogl_texture_get_gl_format (texture),
+                             level_width,
+                             level_height,
+                             0,
+                             source_gl_format,
+                             source_gl_type,
+                             NULL);
+        }
+
+      ctx->glTexSubImage2D (gl_target,
+                            level,
+                            dst_x, dst_y,
+                            width, height,
+                            source_gl_format,
+                            source_gl_type,
+                            data);
+    }
 
   if (_cogl_gl_util_catch_out_of_memory (ctx, error))
     status = FALSE;
@@ -442,13 +502,6 @@ _cogl_texture_driver_allows_foreign_gl_target (CoglContext *ctx,
   return TRUE;
 }
 
-static void
-_cogl_texture_driver_gl_generate_mipmaps (CoglContext *ctx,
-                                          GLenum gl_target)
-{
-  GE( ctx, glGenerateMipmap (gl_target) );
-}
-
 static CoglPixelFormat
 _cogl_texture_driver_find_best_gl_get_data_format
                                             (CoglContext *context,
@@ -477,6 +530,5 @@ _cogl_texture_driver_gl =
     _cogl_texture_driver_size_supported_3d,
     _cogl_texture_driver_try_setting_gl_border_color,
     _cogl_texture_driver_allows_foreign_gl_target,
-    _cogl_texture_driver_gl_generate_mipmaps,
     _cogl_texture_driver_find_best_gl_get_data_format
   };
diff --git a/cogl/driver/gl/gles/cogl-texture-driver-gles.c b/cogl/driver/gl/gles/cogl-texture-driver-gles.c
index 94e5222..20b4192 100644
--- a/cogl/driver/gl/gles/cogl-texture-driver-gles.c
+++ b/cogl/driver/gl/gles/cogl-texture-driver-gles.c
@@ -82,6 +82,14 @@ _cogl_texture_driver_gen (CoglContext *ctx,
     {
     case GL_TEXTURE_2D:
     case GL_TEXTURE_3D:
+      /* In case automatic mipmap generation gets disabled for this
+       * texture but a minification filter depending on mipmap
+       * interpolation is selected then we initialize the max mipmap
+       * level to 0 so OpenGL will consider the texture storage to be
+       * "complete".
+       */
+      GE( ctx, glTexParameteri (gl_target, GL_TEXTURE_MAX_LEVEL, 0));
+
       /* GL_TEXTURE_MAG_FILTER defaults to GL_LINEAR, no need to set it */
       GE( ctx, glTexParameteri (gl_target,
                                 GL_TEXTURE_MIN_FILTER,
@@ -173,8 +181,7 @@ prepare_bitmap_alignment_for_upload (CoglContext *ctx,
 
 static CoglBool
 _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
-                                             GLenum gl_target,
-                                             GLuint gl_handle,
+                                             CoglTexture *texture,
                                              CoglBool is_foreign,
                                              int src_x,
                                              int src_y,
@@ -182,11 +189,14 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
                                              int dst_y,
                                              int width,
                                              int height,
+                                             int level,
                                              CoglBitmap *source_bmp,
 				             GLuint source_gl_format,
 				             GLuint source_gl_type,
                                              CoglError **error)
 {
+  GLenum gl_target;
+  GLuint gl_handle;
   uint8_t *data;
   CoglPixelFormat source_format = cogl_bitmap_get_format (source_bmp);
   int bpp = _cogl_pixel_format_get_bytes_per_pixel (source_format);
@@ -195,6 +205,10 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
   GLenum gl_error;
   CoglBool status = TRUE;
   CoglError *internal_error = NULL;
+  int level_width;
+  int level_height;
+
+  cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target);
 
   /* If we have the GL_EXT_unpack_subimage extension then we can
      upload from subregions directly. Otherwise we may need to copy
@@ -255,12 +269,57 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
   while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
     ;
 
-  ctx->glTexSubImage2D (gl_target, 0,
-                        dst_x, dst_y,
-                        width, height,
-                        source_gl_format,
-                        source_gl_type,
-                        data);
+  _cogl_texture_get_level_size (texture,
+                                level,
+                                &level_width,
+                                &level_height,
+                                NULL);
+
+  if (level_width == width && level_height == height)
+    {
+      /* GL gets upset if you use glTexSubImage2D to define the
+       * contents of a mipmap level so we make sure to use
+       * glTexImage2D if we are uploading a full mipmap level.
+       */
+      ctx->glTexImage2D (gl_target,
+                         level,
+                         _cogl_texture_get_gl_format (texture),
+                         width,
+                         height,
+                         0,
+                         source_gl_format,
+                         source_gl_type,
+                         data);
+    }
+  else
+    {
+      /* GL gets upset if you use glTexSubImage2D to initialize the
+       * contents of a mipmap level so if this is the first time
+       * we've seen a request to upload to this level we call
+       * glTexImage2D first to assert that the storage for this
+       * level exists.
+       */
+      if (texture->max_level < level)
+        {
+          ctx->glTexImage2D (gl_target,
+                             level,
+                             _cogl_texture_get_gl_format (texture),
+                             level_width,
+                             level_height,
+                             0,
+                             source_gl_format,
+                             source_gl_type,
+                             NULL);
+        }
+
+      ctx->glTexSubImage2D (gl_target,
+                            level,
+                            dst_x, dst_y,
+                            width, height,
+                            source_gl_format,
+                            source_gl_type,
+                            data);
+    }
 
   if (_cogl_gl_util_catch_out_of_memory (ctx, error))
     status = FALSE;
@@ -552,14 +611,6 @@ _cogl_texture_driver_allows_foreign_gl_target (CoglContext *ctx,
   return TRUE;
 }
 
-static void
-_cogl_texture_driver_gl_generate_mipmaps (CoglContext *ctx,
-                                          GLenum gl_target)
-{
-  if (ctx->driver == COGL_DRIVER_GLES2)
-    GE( ctx, glGenerateMipmap (gl_target) );
-}
-
 static CoglPixelFormat
 _cogl_texture_driver_find_best_gl_get_data_format
                                             (CoglContext *context,
@@ -589,6 +640,5 @@ _cogl_texture_driver_gles =
     _cogl_texture_driver_size_supported_3d,
     _cogl_texture_driver_try_setting_gl_border_color,
     _cogl_texture_driver_allows_foreign_gl_target,
-    _cogl_texture_driver_gl_generate_mipmaps,
     _cogl_texture_driver_find_best_gl_get_data_format
   };
diff --git a/cogl/driver/nop/cogl-texture-2d-nop-private.h b/cogl/driver/nop/cogl-texture-2d-nop-private.h
index 957a194..2e79e66 100644
--- a/cogl/driver/nop/cogl-texture-2d-nop-private.h
+++ b/cogl/driver/nop/cogl-texture-2d-nop-private.h
@@ -79,13 +79,14 @@ _cogl_texture_2d_nop_flush_legacy_texobj_wrap_modes (CoglTexture *tex,
 
 void
 _cogl_texture_2d_nop_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);
+                                            int height,
+                                            CoglFramebuffer *src_fb,
+                                            int dst_x,
+                                            int dst_y,
+                                            int level);
 
 unsigned int
 _cogl_texture_2d_nop_get_gl_handle (CoglTexture2D *tex_2d);
@@ -95,13 +96,14 @@ _cogl_texture_2d_nop_generate_mipmap (CoglTexture2D *tex_2d);
 
 CoglBool
 _cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d,
-                                       CoglBitmap *bitmap,
-                                       int dst_x,
-                                       int dst_y,
                                        int src_x,
                                        int src_y,
                                        int width,
                                        int height,
+                                       CoglBitmap *bitmap,
+                                       int dst_x,
+                                       int dst_y,
+                                       int level,
                                        CoglError **error);
 
 void
diff --git a/cogl/driver/nop/cogl-texture-2d-nop.c b/cogl/driver/nop/cogl-texture-2d-nop.c
index 5118e26..948d620 100644
--- a/cogl/driver/nop/cogl-texture-2d-nop.c
+++ b/cogl/driver/nop/cogl-texture-2d-nop.c
@@ -114,13 +114,14 @@ _cogl_texture_2d_nop_flush_legacy_texobj_wrap_modes (CoglTexture *tex,
 
 void
 _cogl_texture_2d_nop_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)
+                                            int height,
+                                            CoglFramebuffer *src_fb,
+                                            int dst_x,
+                                            int dst_y,
+                                            int level)
 {
 }
 
@@ -137,13 +138,14 @@ _cogl_texture_2d_nop_generate_mipmap (CoglTexture2D *tex_2d)
 
 CoglBool
 _cogl_texture_2d_nop_copy_from_bitmap (CoglTexture2D *tex_2d,
-                                       CoglBitmap *bitmap,
-                                       int dst_x,
-                                       int dst_y,
                                        int src_x,
                                        int src_y,
                                        int width,
                                        int height,
+                                       CoglBitmap *bitmap,
+                                       int dst_x,
+                                       int dst_y,
+                                       int level,
                                        CoglError **error)
 {
   return TRUE;
diff --git a/cogl/winsys/cogl-texture-pixmap-x11.c b/cogl/winsys/cogl-texture-pixmap-x11.c
index cf5de19..acaa1fc 100644
--- a/cogl/winsys/cogl-texture-pixmap-x11.c
+++ b/cogl/winsys/cogl-texture-pixmap-x11.c
@@ -49,6 +49,7 @@
 #include "cogl-xlib.h"
 #include "cogl-error-private.h"
 #include "cogl-texture-gl-private.h"
+#include "cogl-private.h"
 
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
@@ -481,6 +482,9 @@ _cogl_texture_pixmap_x11_update_image_texture (CoglTexturePixmapX11 *tex_pixmap)
   XImage *image;
   int src_x, src_y;
   int x, y, width, height;
+  int bpp;
+  int offset;
+  CoglError *ignore = NULL;
 
   display = cogl_xlib_get_display ();
   visual = tex_pixmap->visual;
@@ -585,14 +589,18 @@ _cogl_texture_pixmap_x11_update_image_texture (CoglTexturePixmapX11 *tex_pixmap)
                                         image->bits_per_pixel,
                                         image->byte_order == LSBFirst);
 
-  cogl_texture_set_region (tex_pixmap->tex,
-                           src_x, src_y,
-                           x, y, width, height,
-                           image->width,
-                           image->height,
-                           image_format,
-                           image->bytes_per_line,
-                           (const uint8_t *) image->data);
+  bpp = _cogl_pixel_format_get_bytes_per_pixel (image_format);
+  offset = image->bytes_per_line * src_y + bpp * src_x;
+
+  _cogl_texture_set_region (tex_pixmap->tex,
+                            width,
+                            height,
+                            image_format,
+                            image->bytes_per_line,
+                            ((const uint8_t *) image->data) + offset,
+                            x, y,
+                            0, /* level */
+                            &ignore);
 
   /* If we have a shared memory segment then the XImage would be a
      temporary one with no data allocated so we can just XFree it */
@@ -685,6 +693,7 @@ _cogl_texture_pixmap_x11_set_region (CoglTexture *tex,
                                      int dst_y,
                                      int dst_width,
                                      int dst_height,
+                                     int level,
                                      CoglBitmap *bmp,
                                      CoglError **error)
 {



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