cogl-atlas-texture: Remove textures from the atlas when mipmapping is required
authorNeil Roberts <neil@linux.intel.com>
Sat, 5 Dec 2009 13:48:03 +0000 (13:48 +0000)
committerNeil Roberts <neil@linux.intel.com>
Sat, 5 Dec 2009 14:11:57 +0000 (14:11 +0000)
Mipmaps don't work very well in the current atlas because there is not
enough padding between the textures. If ensure_mipmaps is called it
will now create a new texture and migrate the atlased texture to
it. It will use the same blit mechanism as when migrating so it will
try to use an FBO for a fast blit. However if this is not possible it
will end up downloading the data for the entire atlas which is not
ideal.

clutter/cogl/cogl/cogl-atlas-texture.c

index 8fb9ae9..4d7bf6f 100644 (file)
@@ -237,16 +237,17 @@ _cogl_atlas_texture_set_wrap_mode_parameter (CoglTexture *tex,
 }
 
 static void
-_cogl_atlas_texture_free (CoglAtlasTexture *atlas_tex)
+_cogl_atlas_texture_remove_from_atlas (CoglAtlasTexture *atlas_tex)
 {
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
-
-  /* Remove the texture from the atlas */
   if (atlas_tex->in_atlas)
     {
-      CoglAtlas *atlas = ((atlas_tex->format & COGL_A_BIT) ?
-                          ctx->atlas_alpha :
-                          ctx->atlas_no_alpha);
+      CoglAtlas *atlas;
+
+      _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+      atlas = ((atlas_tex->format & COGL_A_BIT) ?
+               ctx->atlas_alpha :
+               ctx->atlas_no_alpha);
 
       cogl_atlas_remove_rectangle (atlas, &atlas_tex->rectangle);
 
@@ -260,7 +261,15 @@ _cogl_atlas_texture_free (CoglAtlasTexture *atlas_tex)
                  cogl_atlas_get_remaining_space (atlas) * 100 /
                  (cogl_atlas_get_width (atlas) *
                   cogl_atlas_get_height (atlas)));
+
+      atlas_tex->in_atlas = FALSE;
     }
+}
+
+static void
+_cogl_atlas_texture_free (CoglAtlasTexture *atlas_tex)
+{
+  _cogl_atlas_texture_remove_from_atlas (atlas_tex);
 
   cogl_handle_unref (atlas_tex->sub_texture);
 }
@@ -332,8 +341,47 @@ _cogl_atlas_texture_ensure_mipmaps (CoglTexture *tex)
 {
   CoglAtlasTexture *atlas_tex = COGL_ATLAS_TEXTURE (tex);
 
-  /* FIXME: If mipmaps are required then we need to migrate the
-     texture out of the atlas because it will show artifacts */
+  /* Mipmaps do not work well with the current atlas so instead we'll
+     just migrate the texture out and use a regular texture */
+  if (atlas_tex->in_atlas)
+    {
+      CoglHandle atlas_texture;
+      CoglAtlasTextureBlitData blit_data;
+
+      _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+
+      COGL_NOTE (ATLAS, "Migrating texture out of the atlas");
+
+      cogl_handle_unref (atlas_tex->sub_texture);
+
+      if ((atlas_tex->format & COGL_A_BIT))
+        atlas_texture = ctx->atlas_alpha_texture;
+      else
+        atlas_texture = ctx->atlas_no_alpha_texture;
+
+      /* Create a new texture at the right size, not including the
+         border */
+      atlas_tex->sub_texture =
+        cogl_texture_new_with_size (atlas_tex->rectangle.width - 2,
+                                    atlas_tex->rectangle.height - 2,
+                                    COGL_TEXTURE_NO_ATLAS,
+                                    atlas_tex->format);
+
+      /* Blit the data out of the atlas to the new texture. If FBOs
+         aren't available this will end up having to copy the entire
+         atlas texture */
+      _cogl_atlas_texture_blit_begin (&blit_data, atlas_tex->sub_texture,
+                                      atlas_texture);
+      _cogl_atlas_texture_blit (&blit_data,
+                                atlas_tex->rectangle.x + 1,
+                                atlas_tex->rectangle.y + 1,
+                                0, 0,
+                                atlas_tex->rectangle.width - 2,
+                                atlas_tex->rectangle.height - 2);
+      _cogl_atlas_texture_blit_end (&blit_data);
+
+      _cogl_atlas_texture_remove_from_atlas (atlas_tex);
+    }
 
   /* Forward on to the sub texture */
   _cogl_texture_ensure_mipmaps (atlas_tex->sub_texture);