<div dir="auto">On Sun, Feb 10, 2019 at 11:31:05PM +0200, Eleni Maria Stea wrote:<br>
> GPUs Gen < 8 cannot sample ETC2 formats. So far, they converted the<br>
> compressed EAC/ETC2 images to non-compressed RGBA images. When<br>
> GetCompressed* functions were called, the pixels were returned in this<br>
> RGBA format and not the compressed format that was expected.<br>
><br>
> Trying to fix this problem, we use a secondary shadow miptree to store the<br>
> decompressed data for the rendering and the main miptree to store the<br>
> compressed for the Get functions to work. Each time that the main miptree<br>
> is written with compressed data, we decompress them to RGB and update the<br>
> shadow. Then we use the shadow for rendering.<br>
><br>
> v2:<br>
>    - Fixes in the commit message (Nanley Chery)<br>
>    - Reversed the changes in brw_get_texture_swizzle and swapped the b, g<br>
>    values at the time that we decompress the data in the function:<br>
>    intel_miptree_update_etc_shadow of intel_mipmap_tree.c (Nanley Chery)<br>
>    - Simplified the format checks in the miptree_create function of the<br>
>    intel_mipmap_tree.c and reserved the call of the<br>
>    intel_lower_compressed_format for the case that we are faking the ETC<br>
>    support (Nanley Chery)<br>
>    - Removed the check for the auxiliary usage for the shadow miptree at<br>
>    creation (miptree_create of intel_mipmap_tree.c) as we won't use<br>
>    auxiliary buffers with these types of trees (Nanley Chery)<br>
>    - Set the etc_format of the non-ETC miptrees to MESA_FORMAT_NONE and<br>
>    removed the unecessary checks (Nanley Chery)<br>
>    - Fixed an unrelated indentation change (Nanley Chery)<br>
>    - Modified the function intel_miptree_finish_write to set the<br>
>    mt->shadow_needs_update to true to catch all the cases when we need to<br>
>    update the miptree (Nanley Chery)<br>
>    - In order to update the shadow miptree during the unmap of the<br>
>    main and always map the main (Nanley Chery) the following change was<br>
>    necessary: Splitted the previous update function that was updating all<br>
>    the mipmap levels and use two functions instead: one that updates one<br>
>    level and one that updates all of them. Used the first during unmap<br>
>    and the second before the rendering.<br>
>    - Removed the BRW_MAP_ETC_BIT flag and the mechanism to decide which<br>
>    miptree should be mapped each time and reversed all the changes in the<br>
>    higher level texture functions that upload data to textures as they<br>
>    aren't needed anymore.<br>
>    - Replaced the boolean needs_fake_etc with an inline function that<br>
>    checks when we need to fake the ETC compression (Nanley Chery)<br>
>    - Removed the initialization of the strides in the update function as<br>
>    the values will be overwritten by the intel_miptree_map call (Nanley<br>
>    Chery)<br>
>    - Used minify instead of division in the new update function<br>
>    intel_miptree_update_etc_shadow_levels in intel_mipmap_tree.c (Nanley<br>
>    Chery)<br>
>    - Removed the depth from the calculation of the number of slices in<br>
>    the new update function (intel_miptree_update_etc_shadow_levels of<br>
>    intel_mipmap_tree.c) as we don't need to support 3D ETC images.<br>
>    (Nanley Chery)<br>
><br>
> v3:<br>
>   - Renamed the rgba_fmt in function miptree_create<br>
>   (intel_mipmap_tree.c) to decomp_format as the format is not always in<br>
>   rgba order. (Nanley Chery)<br>
>   - Documented the new usage for the shadow miptree in the comment above<br>
>   the field in the intel_miptree struct in intel_mipmap_tree.h (Nanley<br>
>   Chery)<br>
>   - Removed the redundant flags from the mapping of the miptrees in<br>
>   intel_miptree_update_etc_shadow of intel_mipmap_tree.c (Nanley Chery)<br>
>   - Fixed the switch from surface's logical level to physical level in<br>
>   the intel_miptree_update_etc_shadow_levels of intel_mipmap_tree.c<br>
>   (Nanley Chery)<br>
>   - Excluded the Baytrail GPUs from the check for the ETC emulation as<br>
>   they support the ETC formats natively. (Nanley Chery)<br>
>   - Simplified the check if the format is BGRA in<br>
>   intel_miptree_update_etc_shadow of intel_mipmap_tree.c (Nanley Chery)<br>
><br>
> v4:<br>
>   - Removed the functions intel_miptree_(map|unmap)_etc and the check if<br>
>    we need to call them as with the new changes, they became unreachable.<br>
>    (Nanley Chery)<br>
>   - We'd rather calculate the level width and height using the shadow<br>
>   miptree instead of the main in intel_miptree_update_etc_shadow_levels of<br>
>   intel_mipmap_tree.c (Nanley Chery)<br>
> ---<br>
>  .../drivers/dri/i965/brw_wm_surface_state.c   |   5 +-<br>
>  src/mesa/drivers/dri/i965/intel_mipmap_tree.c | 185 +++++++++++-------<br>
>  src/mesa/drivers/dri/i965/intel_mipmap_tree.h |  24 +++<br>
>  3 files changed, 147 insertions(+), 67 deletions(-)<br>
><br>
> diff --git a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c<br>
> index 618e2ab35bc..c2cf34aee71 100644<br>
> --- a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c<br>
> +++ b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c<br>
> @@ -521,7 +521,7 @@ static void brw_update_texture_surface(struct gl_context *ctx,<br>
>            */<br>
>           mesa_fmt = mt->format;<br>
>        } else if (mt->etc_format != MESA_FORMAT_NONE) {<br>
> -         mesa_fmt = mt->format;<br>
> +         mesa_fmt = mt->shadow_mt->format;<br>
>        } else if (plane > 0) {<br>
>           mesa_fmt = mt->format;<br>
>        } else {<br>
> @@ -581,6 +581,9 @@ static void brw_update_texture_surface(struct gl_context *ctx,<br>
>           assert(mt->shadow_mt && !mt->shadow_needs_update);<br>
>           mt = mt->shadow_mt;<br>
>           format = ISL_FORMAT_R8_UINT;<br>
> +      } else if (intel_miptree_needs_fake_etc(brw, mt)) {<br>
> +         assert(mt->shadow_mt);<br>
> +         mt = mt->shadow_mt;<br>
>        }<br>
><br>
>        const int surf_index = surf_offset - &brw->wm.base.surf_offset[0];<br>
> diff --git a/src/mesa/drivers/dri/i965/intel_mipmap_tree.c b/src/mesa/drivers/dri/i965/intel_mipmap_tree.c<br>
> index 479188fd1c8..e50db649a23 100644<br>
> --- a/src/mesa/drivers/dri/i965/intel_mipmap_tree.c<br>
> +++ b/src/mesa/drivers/dri/i965/intel_mipmap_tree.c<br>
> @@ -57,6 +57,11 @@ static void *intel_miptree_map_raw(struct brw_context *brw,<br>
>                                     GLbitfield mode);<br>
><br>
>  static void intel_miptree_unmap_raw(struct intel_mipmap_tree *mt);<br>
> +static void intel_miptree_update_etc_shadow(struct brw_context *brw,<br>
> +                                            struct intel_mipmap_tree *mt,<br>
> +                                            unsigned int level,<br>
> +                                            unsigned int slice,<br>
> +                                            int level_w, int level_h);<br>
><br>
>  static bool<br>
>  intel_miptree_supports_mcs(struct brw_context *brw,<br>
> @@ -687,10 +692,8 @@ miptree_create(struct brw_context *brw,<br>
>     if (devinfo->gen < 6 && _mesa_is_format_color_format(format))<br>
>        tiling_flags &= ~ISL_TILING_Y0_BIT;<br>
><br>
> -   mesa_format mt_fmt;<br>
> -   if (_mesa_is_format_color_format(format)) {<br>
> -      mt_fmt = intel_lower_compressed_format(brw, format);<br>
> -   } else {<br>
> +   mesa_format mt_fmt = format;<br>
> +   if (!_mesa_is_format_color_format(format)) {<br>
>        /* Fix up the Z miptree format for how we're splitting out separate<br>
>         * stencil. Gen7 expects there to be no stencil bits in its depth buffer.<br>
>         */<br>
> @@ -707,6 +710,25 @@ miptree_create(struct brw_context *brw,<br>
>     if (mt == NULL)<br>
>        return NULL;<br>
><br>
> +   if (intel_miptree_needs_fake_etc(brw, mt)) {<br>
> +      mesa_format decomp_format = intel_lower_compressed_format(brw, format);<br>
> +      mt->etc_format = format;<br>
> +      mt->shadow_mt = make_surface(brw, target, decomp_format, first_level,<br>
> +                                   last_level, width0, height0, depth0,<br>
> +                                   num_samples, tiling_flags,<br>
> +                                   mt_surf_usage(mt_fmt),<br>
> +                                   alloc_flags, 0, NULL);<br>
> +<br>
> +      if (mt->shadow_mt == NULL) {<br>
> +         intel_miptree_release(&mt);<br>
> +         return NULL;<br>
> +      }<br>
> +<br>
> +      mt->shadow_mt->etc_format = MESA_FORMAT_NONE;<br>
> +   } else {<br>
> +      mt->etc_format = MESA_FORMAT_NONE;<br>
> +   }<br>
> +<br>
>     if (needs_separate_stencil(brw, mt, format)) {<br>
>        mt->stencil_mt =<br>
>           make_surface(brw, target, MESA_FORMAT_S_UINT8, first_level, last_level,<br>
> @@ -719,9 +741,6 @@ miptree_create(struct brw_context *brw,<br>
>        }<br>
>     }<br>
><br>
> -   mt->etc_format = (_mesa_is_format_color_format(format) && mt_fmt != format) ?<br>
> -                    format : MESA_FORMAT_NONE;<br>
> -<br>
>     if (!(flags & MIPTREE_CREATE_NO_AUX))<br>
>        intel_miptree_choose_aux_usage(brw, mt);<br>
><br>
> @@ -2426,8 +2445,11 @@ intel_miptree_finish_write(struct brw_context *brw,<br>
><br>
>     switch (mt->aux_usage) {<br>
>     case ISL_AUX_USAGE_NONE:<br>
> -      if (mt->format == MESA_FORMAT_S_UINT8 && devinfo->gen <= 7)<br>
> +      if (mt->format == MESA_FORMAT_S_UINT8 && devinfo->gen <= 7) {<br>
> +         mt->shadow_needs_update = true;<br>
> +      } else if (intel_miptree_has_etc_shadow(brw, mt)) {<br>
>           mt->shadow_needs_update = true;<br>
> +      }<br>
>        break;<br>
><br>
>     case ISL_AUX_USAGE_MCS:<br>
> @@ -3454,61 +3476,6 @@ intel_miptree_map_s8(struct brw_context *brw,<br>
>     map->unmap = intel_miptree_unmap_s8;<br>
>  }<br>
><br>
> -static void<br>
> -intel_miptree_unmap_etc(struct brw_context *brw,<br>
> -                        struct intel_mipmap_tree *mt,<br>
> -                        struct intel_miptree_map *map,<br>
> -                        unsigned int level,<br>
> -                        unsigned int slice)<br>
> -{<br>
> -   uint32_t image_x;<br>
> -   uint32_t image_y;<br>
> -   intel_miptree_get_image_offset(mt, level, slice, &image_x, &image_y);<br>
> -<br>
> -   image_x += map->x;<br>
> -   image_y += map->y;<br>
> -<br>
> -   uint8_t *dst = intel_miptree_map_raw(brw, mt, GL_MAP_WRITE_BIT)<br>
> -                + image_y * mt->surf.row_pitch_B<br>
> -                + image_x * mt->cpp;<br>
> -<br>
> -   if (mt->etc_format == MESA_FORMAT_ETC1_RGB8)<br>
> -      _mesa_etc1_unpack_rgba8888(dst, mt->surf.row_pitch_B,<br>
> -                                 map->ptr, map->stride,<br>
> -                                 map->w, map->h);<br>
> -   else<br>
> -      _mesa_unpack_etc2_format(dst, mt->surf.row_pitch_B,<br>
> -                               map->ptr, map->stride,<br>
> -                            map->w, map->h, mt->etc_format, true);<br>
> -<br>
> -   intel_miptree_unmap_raw(mt);<br>
> -   free(map->buffer);<br>
> -}<br>
> -<br>
> -static void<br>
> -intel_miptree_map_etc(struct brw_context *brw,<br>
> -                      struct intel_mipmap_tree *mt,<br>
> -                      struct intel_miptree_map *map,<br>
> -                      unsigned int level,<br>
> -                      unsigned int slice)<br>
> -{<br>
> -   assert(mt->etc_format != MESA_FORMAT_NONE);<br>
> -   if (mt->etc_format == MESA_FORMAT_ETC1_RGB8) {<br>
> -      assert(mt->format == MESA_FORMAT_R8G8B8X8_UNORM);<br>
> -   }<br>
> -<br>
> -   assert(map->mode & GL_MAP_WRITE_BIT);<br>
> -   assert(map->mode & GL_MAP_INVALIDATE_RANGE_BIT);<br>
> -<br>
> -   intel_miptree_access_raw(brw, mt, level, slice, true);<br>
> -<br>
> -   map->stride = _mesa_format_row_stride(mt->etc_format, map->w);<br>
> -   map->buffer = malloc(_mesa_format_image_size(mt->etc_format,<br>
> -                                                map->w, map->h, 1));<br>
> -   map->ptr = map->buffer;<br>
> -   map->unmap = intel_miptree_unmap_etc;<br>
> -}<br>
> -<br>
>  /**<br>
>   * Mapping functions for packed depth/stencil miptrees backed by real separate<br>
>   * miptrees for depth and stencil.<br>
> @@ -3781,9 +3748,6 @@ intel_miptree_map(struct brw_context *brw,<br>
><br>
>     if (mt->format == MESA_FORMAT_S_UINT8) {<br>
>        intel_miptree_map_s8(brw, mt, map, level, slice);<br>
> -   } else if (mt->etc_format != MESA_FORMAT_NONE &&<br>
> -              !(mode & BRW_MAP_DIRECT_BIT)) {<br>
> -      intel_miptree_map_etc(brw, mt, map, level, slice);<br>
>     } else if (mt->stencil_mt && !(mode & BRW_MAP_DIRECT_BIT)) {<br>
>        intel_miptree_map_depthstencil(brw, mt, map, level, slice);<br>
>     } else if (use_intel_mipree_map_blit(brw, mt, map)) {<br>
> @@ -3816,6 +3780,7 @@ intel_miptree_unmap(struct brw_context *brw,<br>
>                      unsigned int slice)<br>
>  {<br>
>     struct intel_miptree_map *map = mt->level[level].slice[slice].map;<br>
> +   int level_w, level_h;<br>
><br>
>     assert(mt->surf.samples == 1);<br>
><br>
> @@ -3825,10 +3790,20 @@ intel_miptree_unmap(struct brw_context *brw,<br>
>     DBG("%s: mt %p (%s) level %d slice %d\n", __func__,<br>
>         mt, _mesa_get_format_name(mt->format), level, slice);<br>
><br>
> +   level_w = minify(mt->surf.phys_level0_sa.width,<br>
> +                    level - mt->first_level);<br>
> +   level_h = minify(mt->surf.phys_level0_sa.height,<br>
> +                    level - mt->first_level);<br>
> +<br>
<br>
Oh okay, phys_level0_sa is equal to logical_level0_px aligned up to the<br>
block size (I misread it as a divided by earlier). This works fine.<br>
<br>
>     if (map->unmap)<br>
>          map->unmap(brw, mt, map, level, slice);<br>
><br>
>     intel_miptree_release_map(mt, level, slice);<br>
> +<br>
> +   if (intel_miptree_has_etc_shadow(brw, mt) && mt->shadow_needs_update) {<br>
> +      intel_miptree_update_etc_shadow(brw, mt, level, slice, level_w,<br>
> +                                      level_h);<br>
<br>
For the issue mentioned earlier about marking the shadow as updated, I'd<br>
prefer if it was fixed in this patch. As things are now,<br>
intel_miptree_update_etc_shadow_levels() is broken until the next patch.<br>
The solution I had in mind was to modify this patch in two places:<br>
<br>
A) We include the following line here:<br>
         mt->shadow_needs_update = false;<br>
<br>
> +   }<br>
>  }<br>
><br>
>  enum isl_surf_dim<br>
> @@ -3943,3 +3918,81 @@ intel_miptree_get_clear_color(const struct gen_device_info *devinfo,<br>
>        return mt->fast_clear_color;<br>
>     }<br>
>  }<br>
> +<br>
> +static void<br>
> +intel_miptree_update_etc_shadow(struct brw_context *brw,<br>
> +                                struct intel_mipmap_tree *mt,<br>
> +                                unsigned int level,<br>
> +                                unsigned int slice,<br>
> +                                int level_w,<br>
> +                                int level_h)<br>
> +{<br>
> +   struct intel_mipmap_tree *smt;<br>
> +   ptrdiff_t etc_stride, shadow_stride;<br>
> +   GLbitfield etc_mode, shadow_mode;<br>
> +   void *mptr, *sptr;<br>
> +<br>
> +   assert(intel_miptree_has_etc_shadow(brw, mt));<br>
> +   if (!mt->shadow_needs_update)<br>
> +      return;<br>
> +<br>
> +   mt->shadow_needs_update = false;<br>
<br>
B) We remove the line above.<br>
<br>
> +   smt = mt->shadow_mt;<br>
> +<br>
> +   etc_mode = GL_MAP_READ_BIT;<br>
> +   shadow_mode = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT;<br>
> +<br>
> +   intel_miptree_map(brw, mt, level, slice, 0, 0, level_w, level_h,<br>
> +                     etc_mode, &mptr, &etc_stride);<br>
> +   intel_miptree_map(brw, smt, level, slice, 0, 0, level_w, level_h,<br>
> +                     shadow_mode, &sptr, &shadow_stride);<br>
> +<br>
> +   if (mt->format == MESA_FORMAT_ETC1_RGB8) {<br>
> +      _mesa_etc1_unpack_rgba8888(sptr, shadow_stride, mptr, etc_stride,<br>
> +                                 level_w, level_h);<br>
> +   } else {<br>
> +      /* destination and source images must have the same swizzle */<br>
> +      bool is_bgra = (smt->format == MESA_FORMAT_B8G8R8A8_SRGB);<br>
> +      _mesa_unpack_etc2_format(sptr, shadow_stride, mptr, etc_stride,<br>
> +                               level_w, level_h, mt->format, is_bgra);<br>
> +   }<br>
> +<br>
> +   intel_miptree_unmap(brw, mt, level, slice);<br>
> +   intel_miptree_unmap(brw, smt, level, slice);<br>
> +}<br>
> +<br>
> +void<br>
> +intel_miptree_update_etc_shadow_levels(struct brw_context *brw,<br>
> +                                       struct intel_mipmap_tree *mt)<br>
> +{<br>
> +   struct intel_mipmap_tree *smt;<br>
> +   int num_slices;<br>
> +   int level_w, level_h;<br>
> +<br>
> +   assert(mt);<br>
> +   assert(mt->surf.size_B > 0);<br>
> +<br>
> +   assert(intel_miptree_has_etc_shadow(brw, mt));<br>
> +<br>
> +   smt = mt->shadow_mt;<br>
> +<br>
> +   level_w = smt->surf.logical_level0_px.width;<br>
> +   level_h = smt->surf.logical_level0_px.height;<br>
> +<br>
> +   num_slices = smt->surf.logical_level0_px.array_len;<br>
> +<br>
> +   for (int level = smt->first_level; level <= smt->last_level; level++)<br>
> +   {<br>
<br>
      ^<br>
The coding style is to have the brace on the same line as the for.<br>
<br>
> +      for (unsigned int slice = 0; slice < num_slices; slice++) {<br>
> +         intel_miptree_update_etc_shadow(brw, mt, level, slice, level_w,<br>
> +                                         level_h);<br>
> +      }<br>
> +<br>
> +      level_w = minify(smt->surf.logical_level0_px.width,<br>
> +                       level - smt->first_level);<br>
> +      level_h = minify(smt->surf.logical_level0_px.height,<br>
> +                       level - smt->first_level);<br>
<br>
This function still has the level_w/h bug mentioned earlier. Although<br>
it's fixed in the next patch, we generally try to avoid introducing<br>
functions with bugs.<br>
<br>
> +   }<br>
> +<br>
<br>
How about a simpler fix that looks something like this:<br>
<br>
   smt = mt->shadow_mt;<br>
   num_slices = smt->surf.logical_level0_px.array_len;<br>
<br>
   for (int level = smt->first_level; level <= smt->last_level; level++) {<br>
      for (unsigned int slice = 0; slice < num_slices; slice++) {<br>
         int level_w = minify(smt->surf.logical_level0_px.width,<br>
                              level - smt->first_level);<br>
         int level_h = minify(smt->surf.logical_level0_px.height,<br>
                              level - smt->first_level);<br>
<br>
         intel_miptree_update_etc_shadow(brw, mt, level, slice, level_w,<br>
                                         level_h);<br>
      }<br>
   }<br>
<br>
<br>
-Nanley<br>
<br>
> +   mt->shadow_needs_update = false;<br>
> +}<br>
> diff --git a/src/mesa/drivers/dri/i965/intel_mipmap_tree.h b/src/mesa/drivers/dri/i965/intel_mipmap_tree.h<br>
> index 1a7507023a1..752aeaaf9b7 100644<br>
> --- a/src/mesa/drivers/dri/i965/intel_mipmap_tree.h<br>
> +++ b/src/mesa/drivers/dri/i965/intel_mipmap_tree.h<br>
> @@ -301,6 +301,8 @@ struct intel_mipmap_tree<br>
>      *<br>
>      * This miptree may be used for:<br>
>      * - Stencil texturing (pre-BDW) as required by GL_ARB_stencil_texturing.<br>
> +    * - To store the decompressed ETC/EAC data in case we emulate the ETC<br>
> +    *   compression on Gen 7 or earlier GPUs.<br>
>      */<br>
>     struct intel_mipmap_tree *shadow_mt;<br>
>     bool shadow_needs_update;<br>
> @@ -730,6 +732,28 @@ isl_memcpy_type<br>
>  intel_miptree_get_memcpy_type(mesa_format tiledFormat, GLenum format, GLenum type,<br>
>                                uint32_t *cpp);<br>
> <br>
> +static inline bool<br>
> +intel_miptree_needs_fake_etc(struct brw_context *brw,<br>
> +                             struct intel_mipmap_tree *mt)<br>
> +{<br>
> +   const struct gen_device_info *devinfo = &brw->screen->devinfo;<br>
> +   bool is_etc = _mesa_is_format_etc2(mt->format) ||<br>
> +                 (mt->format == MESA_FORMAT_ETC1_RGB8);<br>
> +<br>
> +   return devinfo->gen < 8 && !devinfo->is_baytrail && is_etc;<br>
> +}<br>
> +<br>
> +static inline bool<br>
> +intel_miptree_has_etc_shadow(struct brw_context *brw,<br>
> +                             struct intel_mipmap_tree *mt)<br>
> +{<br>
> +   return intel_miptree_needs_fake_etc(brw, mt) && mt->shadow_mt;<br>
> +}<br>
> +<br>
> +void<br>
> +intel_miptree_update_etc_shadow_levels(struct brw_context *brw,<br>
> +                                       struct intel_mipmap_tree *mt);<br>
> +<br>
>  #ifdef __cplusplus<br>
>  }<br>
>  #endif<br>
> --<br>
> 2.20.1<br>
><br></div>