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

Anuj Phogat anuj.phogat at gmail.com
Tue Nov 13 13:28:49 PST 2012


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 flag (wraps_etc) for etc1 and etc2 formats.
Signed-off-by: Anuj Phogat <anuj.phogat at gmail.com>
---
Missed these changes in my updated series last night.

 src/mesa/drivers/dri/i965/brw_wm_surface_state.c |   15 ++++
 src/mesa/drivers/dri/intel/intel_mipmap_tree.c   |   99 +++++++++++++++++++--
 src/mesa/drivers/dri/intel/intel_mipmap_tree.h   |   25 ++++--
 3 files changed, 119 insertions(+), 20 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 25ee557..a07840e 100644
--- a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c
+++ b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c
@@ -557,6 +557,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 cd7299e..6fc1048 100644
--- a/src/mesa/drivers/dri/intel/intel_mipmap_tree.c
+++ b/src/mesa/drivers/dri/intel/intel_mipmap_tree.c
@@ -199,14 +199,40 @@ 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:
+   case MESA_FORMAT_ETC2_SIGNED_R11_EAC:
+      format = MESA_FORMAT_R16;
+      break;
+   case MESA_FORMAT_ETC2_RG11_EAC:
+   case MESA_FORMAT_ETC2_SIGNED_RG11_EAC:
+      format = MESA_FORMAT_RG1616;
+      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 +283,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,
@@ -1267,6 +1294,53 @@ intel_miptree_unmap_s8(struct intel_context *intel,
 }
 
 static void
+intel_miptree_map_etc2(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_etc.
+    */
+   assert(mt->wraps_etc);
+
+   /* intel_miptree_map_etc2() can be called from glCompressedTexImage2D
+    * and CompressedTexSubImage2D. Hence the assertions below hold.
+    */
+   assert(map->mode & GL_MAP_WRITE_BIT);
+   assert(map->mode & GL_MAP_INVALIDATE_RANGE_BIT);
+
+   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_etc2(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, 0, slice, &image_x, &image_y);
+
+   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_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);
+}
+
+static void
 intel_miptree_map_etc1(struct intel_context *intel,
                        struct intel_mipmap_tree *mt,
                        struct intel_miptree_map *map,
@@ -1274,9 +1348,10 @@ intel_miptree_map_etc1(struct intel_context *intel,
                        unsigned int slice)
 {
    /* For justification of these invariants,
-    * see intel_mipmap_tree:wraps_etc1.
+    * see intel_mipmap_tree:wraps_etc.
     */
-   assert(mt->wraps_etc1);
+   assert(mt->wraps_etc);
+   assert(mt->etc_format == MESA_FORMAT_ETC1_RGB8);
    assert(mt->format == MESA_FORMAT_RGBX8888_REV);
 
    /* From the GL_OES_compressed_ETC1_RGB8_texture spec:
@@ -1292,8 +1367,8 @@ intel_miptree_map_etc1(struct intel_context *intel,
    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;
 }
@@ -1537,8 +1612,10 @@ 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) {
+   } else if (mt->wraps_etc && mt->etc_format == MESA_FORMAT_ETC1_RGB8) {
       intel_miptree_map_etc1(intel, mt, map, level, slice);
+   } else if (mt->wraps_etc) {
+      intel_miptree_map_etc2(intel, mt, map, level, slice);
    } else if (mt->stencil_mt) {
       intel_miptree_map_depthstencil(intel, mt, map, level, slice);
    } else if (intel->has_llc &&
@@ -1575,8 +1652,10 @@ 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) {
+   } else if (mt->wraps_etc && mt->etc_format == MESA_FORMAT_ETC1_RGB8) {
       intel_miptree_unmap_etc1(intel, mt, map, level, slice);
+   } else if (mt->wraps_etc) {
+      intel_miptree_unmap_etc2(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 0d0e757..d1c7cb7 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.7.6



More information about the mesa-dev mailing list