[Mesa-dev] [PATCH 13/13] intel: Enable ETC2 support on intel hardware

Ian Romanick idr at freedesktop.org
Thu Dec 6 17:48:29 PST 2012


From: Anuj Phogat <anuj.phogat at gmail.com>

This patch enables support for ETC2 compressed textures on
all intel hardware. At present, ETC2 texture decoding is not
available on intel hardware. So, compressed ETC2 texture data
is decoded in software and stored in a suitable uncompressed
MESA_FORMAT at the time of glCompressedTexImage2D. Currently,
ETC2 formats are only exposed in OpenGL ES 3.0.

V2: Use single etc_wraps variable for both etc1 and etc2.
V3: Remove redundant code and use just one intel_miptree_map_etc()
    and intel_miptree_unmap_etc() function.
    Choose MESA_FORMAT_SIGNED_{R16, GR1616} for ETC2 signed-{r11, rg11}
    formats

Signed-off-by: Anuj Phogat <anuj.phogat at gmail.com>
Tested-by: Matt Turner <mattst88 at gmail.com>
Reviewed-by: Eric Anholt <eric at anholt.net>
Reviewed-by: Kenneth Graunke <kenneth at whitecape.org>
---
 src/mesa/drivers/dri/i965/brw_wm_surface_state.c |  15 ++++
 src/mesa/drivers/dri/intel/intel_mipmap_tree.c   | 108 ++++++++++++++---------
 src/mesa/drivers/dri/intel/intel_mipmap_tree.h   |  25 +++---
 3 files changed, 98 insertions(+), 50 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c
index 66301a9..298678a 100644
--- a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c
+++ b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c
@@ -568,6 +568,21 @@ brw_init_surface_formats(struct brw_context *brw)
     * during glCompressedTexImage2D(). See intel_mipmap_tree::wraps_etc1.
     */
    ctx->TextureFormatSupported[MESA_FORMAT_ETC1_RGB8] = true;
+
+   /* On hardware that lacks support for ETC2, we map ETC2 to a suitable
+    * MESA_FORMAT during glCompressedTexImage2D().
+    * See intel_mipmap_tree::wraps_etc2.
+    */
+   ctx->TextureFormatSupported[MESA_FORMAT_ETC2_RGB8] = true;
+   ctx->TextureFormatSupported[MESA_FORMAT_ETC2_SRGB8] = true;
+   ctx->TextureFormatSupported[MESA_FORMAT_ETC2_RGBA8_EAC] = true;
+   ctx->TextureFormatSupported[MESA_FORMAT_ETC2_SRGB8_ALPHA8_EAC] = true;
+   ctx->TextureFormatSupported[MESA_FORMAT_ETC2_R11_EAC] = true;
+   ctx->TextureFormatSupported[MESA_FORMAT_ETC2_RG11_EAC] = true;
+   ctx->TextureFormatSupported[MESA_FORMAT_ETC2_SIGNED_R11_EAC] = true;
+   ctx->TextureFormatSupported[MESA_FORMAT_ETC2_SIGNED_RG11_EAC] = true;
+   ctx->TextureFormatSupported[MESA_FORMAT_ETC2_RGB8_PUNCHTHROUGH_ALPHA1] = true;
+   ctx->TextureFormatSupported[MESA_FORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1] = true;
 }
 
 bool
diff --git a/src/mesa/drivers/dri/intel/intel_mipmap_tree.c b/src/mesa/drivers/dri/intel/intel_mipmap_tree.c
index 04be757..6096827 100644
--- a/src/mesa/drivers/dri/intel/intel_mipmap_tree.c
+++ b/src/mesa/drivers/dri/intel/intel_mipmap_tree.c
@@ -199,14 +199,44 @@ intel_miptree_create(struct intel_context *intel,
    struct intel_mipmap_tree *mt;
    uint32_t tiling = I915_TILING_NONE;
    GLenum base_format;
-   bool wraps_etc1 = false;
+   gl_format tex_format = format;
+   gl_format etc_format = MESA_FORMAT_NONE;
    GLuint total_width, total_height;
 
-   if (format == MESA_FORMAT_ETC1_RGB8) {
+   switch (format) {
+   case MESA_FORMAT_ETC1_RGB8:
       format = MESA_FORMAT_RGBX8888_REV;
-      wraps_etc1 = true;
+      break;
+   case MESA_FORMAT_ETC2_RGB8:
+      format = MESA_FORMAT_RGBX8888_REV;
+      break;
+   case MESA_FORMAT_ETC2_SRGB8:
+   case MESA_FORMAT_ETC2_SRGB8_ALPHA8_EAC:
+   case MESA_FORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1:
+      format = MESA_FORMAT_SARGB8;
+      break;
+   case MESA_FORMAT_ETC2_RGBA8_EAC:
+   case MESA_FORMAT_ETC2_RGB8_PUNCHTHROUGH_ALPHA1:
+      format = MESA_FORMAT_RGBA8888_REV;
+      break;
+   case MESA_FORMAT_ETC2_R11_EAC:
+      format = MESA_FORMAT_R16;
+      break;
+   case MESA_FORMAT_ETC2_SIGNED_R11_EAC:
+      format = MESA_FORMAT_SIGNED_R16;
+      break;
+   case MESA_FORMAT_ETC2_RG11_EAC:
+      format = MESA_FORMAT_RG1616;
+      break;
+   case MESA_FORMAT_ETC2_SIGNED_RG11_EAC:
+      format = MESA_FORMAT_SIGNED_GR1616;
+      break;
+   default:
+      /* Non ETC1 / ETC2 format */
+      break;
    }
 
+   etc_format = (format != tex_format) ? tex_format : MESA_FORMAT_NONE;
    base_format = _mesa_get_format_base_format(format);
 
    if (intel->use_texture_tiling && !_mesa_is_format_compressed(format)) {
@@ -257,7 +287,8 @@ intel_miptree_create(struct intel_context *intel,
       total_height = ALIGN(total_height, 64);
    }
 
-   mt->wraps_etc1 = wraps_etc1;
+   mt->wraps_etc = (etc_format != MESA_FORMAT_NONE) ? true : false;
+   mt->etc_format = etc_format;
    mt->region = intel_region_alloc(intel->intelScreen,
 				   tiling,
 				   mt->cpp,
@@ -1254,55 +1285,52 @@ intel_miptree_unmap_s8(struct intel_context *intel,
 }
 
 static void
-intel_miptree_map_etc1(struct intel_context *intel,
-                       struct intel_mipmap_tree *mt,
-                       struct intel_miptree_map *map,
-                       unsigned int level,
-                       unsigned int slice)
+intel_miptree_map_etc(struct intel_context *intel,
+                      struct intel_mipmap_tree *mt,
+                      struct intel_miptree_map *map,
+                      unsigned int level,
+                      unsigned int slice)
 {
-   /* For justification of these invariants,
-    * see intel_mipmap_tree:wraps_etc1.
+   /* For justification see intel_mipmap_tree:wraps_etc.
     */
-   assert(mt->wraps_etc1);
-   assert(mt->format == MESA_FORMAT_RGBX8888_REV);
+   assert(mt->wraps_etc);
+
+   if (mt->etc_format == MESA_FORMAT_ETC1_RGB8) {
+      assert(mt->format == MESA_FORMAT_RGBX8888_REV);
+   }
 
-   /* From the GL_OES_compressed_ETC1_RGB8_texture spec:
-    *   INVALID_OPERATION is generated by CompressedTexSubImage2D,
-    *   TexSubImage2D, or CopyTexSubImage2D if the texture image <level>
-    *   bound to <target> has internal format ETC1_RGB8_OES.
-    *
-    * This implies that intel_miptree_map_etc1() can only be called from
-    * glCompressedTexImage2D, and hence the assertions below hold.
-    */
    assert(map->mode & GL_MAP_WRITE_BIT);
    assert(map->mode & GL_MAP_INVALIDATE_RANGE_BIT);
-   assert(map->x == 0);
-   assert(map->y == 0);
 
-   map->stride = _mesa_format_row_stride(MESA_FORMAT_ETC1_RGB8, map->w);
-   map->buffer = malloc(_mesa_format_image_size(MESA_FORMAT_ETC1_RGB8,
+   map->stride = _mesa_format_row_stride(mt->etc_format, map->w);
+   map->buffer = malloc(_mesa_format_image_size(mt->etc_format,
                                                 map->w, map->h, 1));
    map->ptr = map->buffer;
 }
 
 static void
-intel_miptree_unmap_etc1(struct intel_context *intel,
-                         struct intel_mipmap_tree *mt,
-                         struct intel_miptree_map *map,
-                         unsigned int level,
-                         unsigned int slice)
+intel_miptree_unmap_etc(struct intel_context *intel,
+                        struct intel_mipmap_tree *mt,
+                        struct intel_miptree_map *map,
+                        unsigned int level,
+                        unsigned int slice)
 {
    uint32_t image_x;
    uint32_t image_y;
    intel_miptree_get_image_offset(mt, level, slice, &image_x, &image_y);
 
-   uint8_t *xbgr = intel_region_map(intel, mt->region, map->mode)
-                 + image_y * mt->region->pitch * mt->region->cpp
-                 + image_x * mt->region->cpp;
+   uint8_t *dst = intel_region_map(intel, mt->region, map->mode)
+                + image_y * mt->region->pitch * mt->region->cpp
+                + image_x * mt->region->cpp;
 
-   _mesa_etc1_unpack_rgba8888(xbgr, mt->region->pitch * mt->region->cpp,
-                              map->ptr, map->stride,
-                              map->w, map->h);
+   if (mt->etc_format == MESA_FORMAT_ETC1_RGB8)
+      _mesa_etc1_unpack_rgba8888(dst, mt->region->pitch * mt->region->cpp,
+                                 map->ptr, map->stride,
+                                 map->w, map->h);
+   else
+      _mesa_unpack_etc2_format(dst, mt->region->pitch * mt->region->cpp,
+                               map->ptr, map->stride,
+                               map->w, map->h, mt->etc_format);
 
    intel_region_unmap(intel, mt->region);
    free(map->buffer);
@@ -1524,8 +1552,8 @@ intel_miptree_map_singlesample(struct intel_context *intel,
 
    if (mt->format == MESA_FORMAT_S8) {
       intel_miptree_map_s8(intel, mt, map, level, slice);
-   } else if (mt->wraps_etc1) {
-      intel_miptree_map_etc1(intel, mt, map, level, slice);
+   } else if (mt->wraps_etc) {
+      intel_miptree_map_etc(intel, mt, map, level, slice);
    } else if (mt->stencil_mt) {
       intel_miptree_map_depthstencil(intel, mt, map, level, slice);
    } else if (intel->has_llc &&
@@ -1562,8 +1590,8 @@ intel_miptree_unmap_singlesample(struct intel_context *intel,
 
    if (mt->format == MESA_FORMAT_S8) {
       intel_miptree_unmap_s8(intel, mt, map, level, slice);
-   } else if (mt->wraps_etc1) {
-      intel_miptree_unmap_etc1(intel, mt, map, level, slice);
+   } else if (mt->wraps_etc) {
+      intel_miptree_unmap_etc(intel, mt, map, level, slice);
    } else if (mt->stencil_mt) {
       intel_miptree_unmap_depthstencil(intel, mt, map, level, slice);
    } else if (map->bo) {
diff --git a/src/mesa/drivers/dri/intel/intel_mipmap_tree.h b/src/mesa/drivers/dri/intel/intel_mipmap_tree.h
index 1a415fb..3a465da 100644
--- a/src/mesa/drivers/dri/intel/intel_mipmap_tree.h
+++ b/src/mesa/drivers/dri/intel/intel_mipmap_tree.h
@@ -197,11 +197,14 @@ struct intel_mipmap_tree
     * MESA_FORMAT_Z32_FLOAT, otherwise for MESA_FORMAT_S8_Z24 objects it will be
     * MESA_FORMAT_X8_Z24.
     *
-    * For ETC1 textures, this is MESA_FORMAT_RGBX8888_REV if the hardware
-    * lacks support for ETC1. See @ref wraps_etc1.
+    * For ETC1/ETC2 textures, this is one of the uncompressed mesa texture
+    * formats if the hardware lacks support for ETC1/ETC2. See @ref wraps_etc.
     */
    gl_format format;
 
+   /** This variable stores the value of ETC compressed texture format */
+   gl_format etc_format;
+
    /**
     * The X offset of each image in the miptree must be aligned to this. See
     * the "Alignment Unit Size" section of the BSpec.
@@ -351,16 +354,18 @@ struct intel_mipmap_tree
    struct intel_mipmap_tree *mcs_mt;
 
    /**
-    * \brief The miptree contains RGBX data that was originally ETC1 data.
+    * \brief The miptree contains uncompressed data that was originally
+    * ETC1/ETC2 data.
     *
-    * On hardware that lacks support for ETC1 textures, we do the
-    * following on calls to glCompressedTexImage2D(GL_ETC1_RGB8_OES):
-    *   1. Create a miptree whose format is MESA_FORMAT_RGBX8888_REV with
-    *      the wraps_etc1 flag set.
-    *   2. Translate the ETC1 data into RGBX.
-    *   3. Store the RGBX data into the miptree and discard the ETC1 data.
+    * On hardware that lacks support for ETC1/ETC2 textures, we do the following
+    * on calls to glCompressedTexImage2D() with an ETC1/ETC2 texture format:
+    *   1. Create a miptree whose format is a suitable uncompressed mesa format
+    *      with the wraps_etc flag set.
+    *   2. Translate the ETC1/ETC2 data into uncompressed mesa format.
+    *   3. Store the uncompressed  data into the miptree and discard the ETC1/ETC2
+    *      data.
     */
-   bool wraps_etc1;
+   bool wraps_etc;
 
    /* These are also refcounted:
     */
-- 
1.7.11.7



More information about the mesa-dev mailing list