[Cogl] [PATCH 11/13] get_texture_bits_via_offscreen(): use meta texture format

Robert Bragg robert at sixbynine.org
Wed Dec 11 10:31:32 PST 2013


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

When reading a texture back by first wrapping it as an offscreen
framebuffer and using _read_pixels_into_bitmap() we now make sure the
offscreen framebuffer has an internal format that matches the
meta-texture being read not that of the current sub-texture being
iterated. In the case of atlas textures the subtexture is a shared
texture whose format doesn't reflect the premultipled alpha status of
individual atlas-textures, nor whether the alpha component is valid.
---
 cogl/cogl-framebuffer-private.h | 16 ++++++++++
 cogl/cogl-framebuffer.c         |  7 ++++
 cogl/cogl-texture.c             | 71 ++++++++++++++++++++++++++---------------
 3 files changed, 69 insertions(+), 25 deletions(-)

diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h
index 6476611..3cb056e 100644
--- a/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl-framebuffer-private.h
@@ -223,6 +223,22 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
                         int width,
                         int height);
 
+/* XXX: For a public api we might instead want a way to explicitly
+ * set the _premult status of a framebuffer or what components we
+ * care about instead of exposing the CoglPixelFormat
+ * internal_format.
+ *
+ * The current use case for this api is where we create an offscreen
+ * framebuffer for a shared atlas texture that has a format of
+ * RGBA_8888 disregarding the premultiplied alpha status for
+ * individual atlased textures or whether the alpha component is being
+ * discarded. We want to overried the internal_format that will be
+ * derived from the texture.
+ */
+void
+_cogl_framebuffer_set_internal_format (CoglFramebuffer *framebuffer,
+                                       CoglPixelFormat internal_format);
+
 void _cogl_framebuffer_free (CoglFramebuffer *framebuffer);
 
 const CoglWinsysVtable *
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index 8affe43..20b1b0b 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -157,6 +157,13 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
 }
 
 void
+_cogl_framebuffer_set_internal_format (CoglFramebuffer *framebuffer,
+                                       CoglPixelFormat internal_format)
+{
+  framebuffer->internal_format = internal_format;
+}
+
+void
 _cogl_framebuffer_free (CoglFramebuffer *framebuffer)
 {
   CoglContext *ctx = framebuffer->context;
diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c
index 6bc67c2..6f1641c 100644
--- a/cogl/cogl-texture.c
+++ b/cogl/cogl-texture.c
@@ -708,27 +708,29 @@ EXIT:
 }
 
 static CoglBool
-get_texture_bits_via_offscreen (CoglTexture    *texture,
-                                int             x,
-                                int             y,
-                                int             width,
-                                int             height,
-                                uint8_t         *dst_bits,
-                                unsigned int    dst_rowstride,
-                                CoglPixelFormat dst_format)
+get_texture_bits_via_offscreen (CoglTexture *meta_texture,
+                                CoglTexture *sub_texture,
+                                int x,
+                                int y,
+                                int width,
+                                int height,
+                                uint8_t *dst_bits,
+                                unsigned int dst_rowstride,
+                                CoglPixelFormat closest_format)
 {
-  CoglContext *ctx = texture->context;
+  CoglContext *ctx = sub_texture->context;
   CoglOffscreen *offscreen;
   CoglFramebuffer *framebuffer;
   CoglBitmap *bitmap;
   CoglBool ret;
   CoglError *ignore_error = NULL;
+  CoglPixelFormat real_format;
 
   if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
     return FALSE;
 
   offscreen = _cogl_offscreen_new_with_texture_full
-                                      (texture,
+                                      (sub_texture,
                                        COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL,
                                        0);
 
@@ -739,9 +741,23 @@ get_texture_bits_via_offscreen (CoglTexture    *texture,
       return FALSE;
     }
 
+  /* Currently the framebuffer's internal format corresponds to the
+   * internal format of @sub_texture but in the case of atlas textures
+   * it's possible that this format doesn't reflect the correct
+   * premultiplied alpha status or what components are valid since
+   * atlas textures are always stored in a shared texture with a
+   * format of _RGBA_8888.
+   *
+   * Here we override the internal format to make sure the
+   * framebuffer's internal format matches the internal format of the
+   * parent meta_texture instead.
+   */
+  real_format = _cogl_texture_get_format (meta_texture);
+  _cogl_framebuffer_set_internal_format (framebuffer, real_format);
+
   bitmap = cogl_bitmap_new_for_data (ctx,
                                      width, height,
-                                     dst_format,
+                                     closest_format,
                                      dst_rowstride,
                                      dst_bits);
   ret = cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
@@ -810,6 +826,7 @@ get_texture_bits_via_copy (CoglTexture *texture,
 
 typedef struct
 {
+  CoglTexture *meta_texture;
   int orig_width;
   int orig_height;
   CoglBitmap *target_bmp;
@@ -819,17 +836,18 @@ typedef struct
 } CoglTextureGetData;
 
 static void
-texture_get_cb (CoglTexture *texture,
+texture_get_cb (CoglTexture *subtexture,
                 const float *subtexture_coords,
                 const float *virtual_coords,
                 void        *user_data)
 {
   CoglTextureGetData *tg_data = user_data;
-  CoglPixelFormat format = cogl_bitmap_get_format (tg_data->target_bmp);
-  int bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
+  CoglTexture *meta_texture = tg_data->meta_texture;
+  CoglPixelFormat closest_format = cogl_bitmap_get_format (tg_data->target_bmp);
+  int bpp = _cogl_pixel_format_get_bytes_per_pixel (closest_format);
   unsigned int rowstride = cogl_bitmap_get_rowstride (tg_data->target_bmp);
-  int subtexture_width = cogl_texture_get_width (texture);
-  int subtexture_height = cogl_texture_get_height (texture);
+  int subtexture_width = cogl_texture_get_width (subtexture);
+  int subtexture_height = cogl_texture_get_height (subtexture);
 
   int x_in_subtexture = (int) (0.5 + subtexture_width * subtexture_coords[0]);
   int y_in_subtexture = (int) (0.5 + subtexture_height * subtexture_coords[1]);
@@ -850,33 +868,35 @@ texture_get_cb (CoglTexture *texture,
   /* If we can read everything as a single slice, then go ahead and do that
    * to avoid allocating an FBO. We'll leave it up to the GL implementation to
    * do glGetTexImage as efficiently as possible. (GLES doesn't have that,
-   * so we'll fall through) */
+   * so we'll fall through)
+   */
   if (x_in_subtexture == 0 && y_in_subtexture == 0 &&
       width == subtexture_width && height == subtexture_height)
     {
-      if (texture->vtable->get_data (texture,
-                                     format,
-                                     rowstride,
-                                     dst_bits))
+      if (subtexture->vtable->get_data (subtexture,
+                                        closest_format,
+                                        rowstride,
+                                        dst_bits))
         return;
     }
 
   /* Next best option is a FBO and glReadPixels */
-  if (get_texture_bits_via_offscreen (texture,
+  if (get_texture_bits_via_offscreen (meta_texture,
+                                      subtexture,
                                       x_in_subtexture, y_in_subtexture,
                                       width, height,
                                       dst_bits,
                                       rowstride,
-                                      format))
+                                      closest_format))
     return;
 
   /* Getting ugly: read the entire texture, copy out the part we want */
-  if (get_texture_bits_via_copy (texture,
+  if (get_texture_bits_via_copy (subtexture,
                                  x_in_subtexture, y_in_subtexture,
                                  width, height,
                                  dst_bits,
                                  rowstride,
-                                 format))
+                                 closest_format))
     return;
 
   /* No luck, the caller will fall back to the draw-to-backbuffer and
@@ -990,6 +1010,7 @@ cogl_texture_get_data (CoglTexture *texture,
                                           &ignore_error);
   if (tg_data.target_bits)
     {
+      tg_data.meta_texture = texture;
       tg_data.orig_width = tex_width;
       tg_data.orig_height = tex_height;
       tg_data.target_bmp = target_bmp;
-- 
1.8.3.1



More information about the Cogl mailing list