On Thu, Feb 07, 2019 at 06:00:19PM +0200, Eleni Maria Stea wrote: > GPUs Gen < 8 cannot sample ETC2 formats. So far, they converted the > compressed EAC/ETC2 images to non-compressed RGBA images. When > GetCompressed* functions were called, the pixels were returned in this > RGBA format and not the compressed format that was expected. > > Trying to fix this problem, we use a secondary shadow miptree to store the > decompressed data for the rendering and the main miptree to store the > compressed for the Get functions to work. Each time that the main miptree > is written with compressed data, we decompress them to RGB and update the > shadow. Then we use the shadow for rendering. > > v2: > - Fixes in the commit message (Nanley Chery) > - Reversed the changes in brw_get_texture_swizzle and swapped the b, g > values at the time that we decompress the data in the function: > intel_miptree_update_etc_shadow of intel_mipmap_tree.c (Nanley Chery) > - Simplified the format checks in the miptree_create function of the > intel_mipmap_tree.c and reserved the call of the > intel_lower_compressed_format for the case that we are faking the ETC > support (Nanley Chery) > - Removed the check for the auxiliary usage for the shadow miptree at > creation (miptree_create of intel_mipmap_tree.c) as we won't use > auxiliary buffers with these types of trees (Nanley Chery) > - Set the etc_format of the non-ETC miptrees to MESA_FORMAT_NONE and > removed the unecessary checks (Nanley Chery) > - Fixed an unrelated indentation change (Nanley Chery) > - Modified the function intel_miptree_finish_write to set the > mt->shadow_needs_update to true to catch all the cases when we need to > update the miptree (Nanley Chery) > - In order to update the shadow miptree during the unmap of the > main and always map the main (Nanley Chery) the following change was > necessary: Splitted the previous update function that was updating all > the mipmap levels and use two functions instead: one that updates one > level and one that updates all of them. Used the first during unmap > and the second before the rendering. > - Removed the BRW_MAP_ETC_BIT flag and the mechanism to decide which > miptree should be mapped each time and reversed all the changes in the > higher level texture functions that upload data to textures as they > aren't needed anymore. > - Replaced the boolean needs_fake_etc with an inline function that > checks when we need to fake the ETC compression (Nanley Chery) > - Removed the initialization of the strides in the update function as > the values will be overwritten by the intel_miptree_map call (Nanley > Chery) > - Used minify instead of division in the new update function > intel_miptree_update_etc_shadow_levels in intel_mipmap_tree.c (Nanley > Chery) > - Removed the depth from the calculation of the number of slices in > the new update function (intel_miptree_update_etc_shadow_levels of > intel_mipmap_tree.c) as we don't need to support 3D ETC images. > (Nanley Chery) > > v3: > - Renamed the rgba_fmt in function miptree_create > (intel_mipmap_tree.c) to decomp_format as the format is not always in > rgba order. (Nanley Chery) > - Documented the new usage for the shadow miptree in the comment above > the field in the intel_miptree struct in intel_mipmap_tree.h (Nanley > Chery) > - Removed the redundant flags from the mapping of the miptrees in > intel_miptree_update_etc_shadow of intel_mipmap_tree.c (Nanley Chery) > - Fixed the switch from surface's logical level to physical level in > the intel_miptree_update_etc_shadow_levels of intel_mipmap_tree.c > (Nanley Chery) > - Excluded the Baytrail GPUs from the check for the ETC emulation as > they support the ETC formats natively. (Nanley Chery) > - Simplified the check if the format is BGRA in > intel_miptree_update_etc_shadow of intel_mipmap_tree.c (Nanley Chery) > --- > .../drivers/dri/i965/brw_wm_surface_state.c | 5 +- > src/mesa/drivers/dri/i965/intel_mipmap_tree.c | 130 ++++++++++++++++-- > src/mesa/drivers/dri/i965/intel_mipmap_tree.h | 24 ++++ > 3 files changed, 149 insertions(+), 10 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 618e2ab35bc..c2cf34aee71 100644 > --- a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c > +++ b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c > @@ -521,7 +521,7 @@ static void brw_update_texture_surface(struct gl_context > *ctx, > */ > mesa_fmt = mt->format; > } else if (mt->etc_format != MESA_FORMAT_NONE) { > - mesa_fmt = mt->format; > + mesa_fmt = mt->shadow_mt->format; > } else if (plane > 0) { > mesa_fmt = mt->format; > } else { > @@ -581,6 +581,9 @@ static void brw_update_texture_surface(struct gl_context > *ctx, > assert(mt->shadow_mt && !mt->shadow_needs_update); > mt = mt->shadow_mt; > format = ISL_FORMAT_R8_UINT; > + } else if (intel_miptree_needs_fake_etc(brw, mt)) { > + assert(mt->shadow_mt); > + mt = mt->shadow_mt; > } > > const int surf_index = surf_offset - &brw->wm.base.surf_offset[0]; > diff --git a/src/mesa/drivers/dri/i965/intel_mipmap_tree.c > b/src/mesa/drivers/dri/i965/intel_mipmap_tree.c > index 479188fd1c8..c7367fc385f 100644 > --- a/src/mesa/drivers/dri/i965/intel_mipmap_tree.c > +++ b/src/mesa/drivers/dri/i965/intel_mipmap_tree.c > @@ -57,6 +57,11 @@ static void *intel_miptree_map_raw(struct brw_context *brw, > GLbitfield mode); > > static void intel_miptree_unmap_raw(struct intel_mipmap_tree *mt); > +static void intel_miptree_update_etc_shadow(struct brw_context *brw, > + struct intel_mipmap_tree *mt, > + unsigned int level, > + unsigned int slice, > + int level_w, int level_h); > > static bool > intel_miptree_supports_mcs(struct brw_context *brw, > @@ -687,10 +692,8 @@ miptree_create(struct brw_context *brw, > if (devinfo->gen < 6 && _mesa_is_format_color_format(format)) > tiling_flags &= ~ISL_TILING_Y0_BIT; > > - mesa_format mt_fmt; > - if (_mesa_is_format_color_format(format)) { > - mt_fmt = intel_lower_compressed_format(brw, format); > - } else { > + mesa_format mt_fmt = format; > + if (!_mesa_is_format_color_format(format)) { > /* Fix up the Z miptree format for how we're splitting out separate > * stencil. Gen7 expects there to be no stencil bits in its depth > buffer. > */ > @@ -707,6 +710,25 @@ miptree_create(struct brw_context *brw, > if (mt == NULL) > return NULL; > > + if (intel_miptree_needs_fake_etc(brw, mt)) { > + mesa_format decomp_format = intel_lower_compressed_format(brw, format); > + mt->etc_format = format; > + mt->shadow_mt = make_surface(brw, target, decomp_format, first_level, > + last_level, width0, height0, depth0, > + num_samples, tiling_flags, > + mt_surf_usage(mt_fmt), > + alloc_flags, 0, NULL); > + > + if (mt->shadow_mt == NULL) { > + intel_miptree_release(&mt); > + return NULL; > + } > + > + mt->shadow_mt->etc_format = MESA_FORMAT_NONE; > + } else { > + mt->etc_format = MESA_FORMAT_NONE; > + } > + > if (needs_separate_stencil(brw, mt, format)) { > mt->stencil_mt = > make_surface(brw, target, MESA_FORMAT_S_UINT8, first_level, > last_level, > @@ -719,9 +741,6 @@ miptree_create(struct brw_context *brw, > } > } > > - mt->etc_format = (_mesa_is_format_color_format(format) && mt_fmt != > format) ? > - format : MESA_FORMAT_NONE; > - > if (!(flags & MIPTREE_CREATE_NO_AUX)) > intel_miptree_choose_aux_usage(brw, mt); > > @@ -2426,8 +2445,11 @@ intel_miptree_finish_write(struct brw_context *brw, > > switch (mt->aux_usage) { > case ISL_AUX_USAGE_NONE: > - if (mt->format == MESA_FORMAT_S_UINT8 && devinfo->gen <= 7) > + if (mt->format == MESA_FORMAT_S_UINT8 && devinfo->gen <= 7) { > + mt->shadow_needs_update = true; > + } else if (intel_miptree_has_etc_shadow(brw, mt)) { > mt->shadow_needs_update = true; > + } > break; > > case ISL_AUX_USAGE_MCS: > @@ -3782,7 +3804,8 @@ intel_miptree_map(struct brw_context *brw, > if (mt->format == MESA_FORMAT_S_UINT8) { > intel_miptree_map_s8(brw, mt, map, level, slice); > } else if (mt->etc_format != MESA_FORMAT_NONE && > - !(mode & BRW_MAP_DIRECT_BIT)) { > + !(mode & BRW_MAP_DIRECT_BIT) && > + !(intel_miptree_needs_fake_etc(brw, mt))) { > intel_miptree_map_etc(brw, mt, map, level, slice);
Out of curiosity, is there any reason you wait until patch 5 to delete this case? > } else if (mt->stencil_mt && !(mode & BRW_MAP_DIRECT_BIT)) { > intel_miptree_map_depthstencil(brw, mt, map, level, slice); > @@ -3816,6 +3839,7 @@ intel_miptree_unmap(struct brw_context *brw, > unsigned int slice) > { > struct intel_miptree_map *map = mt->level[level].slice[slice].map; > + int level_w, level_h; > > assert(mt->surf.samples == 1); > > @@ -3825,10 +3849,20 @@ intel_miptree_unmap(struct brw_context *brw, > DBG("%s: mt %p (%s) level %d slice %d\n", __func__, > mt, _mesa_get_format_name(mt->format), level, slice); > > + level_w = minify(mt->surf.phys_level0_sa.width, > + level - mt->first_level); > + level_h = minify(mt->surf.phys_level0_sa.height, > + level - mt->first_level); > + > if (map->unmap) > map->unmap(brw, mt, map, level, slice); > > intel_miptree_release_map(mt, level, slice); > + > + if (intel_miptree_has_etc_shadow(brw, mt) && mt->shadow_needs_update) { > + intel_miptree_update_etc_shadow(brw, mt, level, slice, level_w, > + level_h); > + } With the next patch applied, the change in this function becomes unnecessary. Is there any reason you're leaving it around? > } > > enum isl_surf_dim > @@ -3943,3 +3977,81 @@ intel_miptree_get_clear_color(const struct > gen_device_info *devinfo, > return mt->fast_clear_color; > } > } > + > +static void > +intel_miptree_update_etc_shadow(struct brw_context *brw, > + struct intel_mipmap_tree *mt, > + unsigned int level, > + unsigned int slice, > + int level_w, > + int level_h) > +{ > + struct intel_mipmap_tree *smt; > + ptrdiff_t etc_stride, shadow_stride; > + GLbitfield etc_mode, shadow_mode; > + void *mptr, *sptr; > + > + assert(intel_miptree_has_etc_shadow(brw, mt)); > + if (!mt->shadow_needs_update) > + return; > + > + mt->shadow_needs_update = false; > + smt = mt->shadow_mt; > + > + etc_mode = GL_MAP_READ_BIT; > + shadow_mode = GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT; > + > + intel_miptree_map(brw, mt, level, slice, 0, 0, level_w, level_h, > + etc_mode, &mptr, &etc_stride); > + intel_miptree_map(brw, smt, level, slice, 0, 0, level_w, level_h, > + shadow_mode, &sptr, &shadow_stride); > + > + if (mt->format == MESA_FORMAT_ETC1_RGB8) { > + _mesa_etc1_unpack_rgba8888(sptr, shadow_stride, mptr, etc_stride, > + level_w, level_h); > + } else { > + /* destination and source images must have the same swizzle */ > + bool is_bgra = (smt->format == MESA_FORMAT_B8G8R8A8_SRGB); > + _mesa_unpack_etc2_format(sptr, shadow_stride, mptr, etc_stride, > + level_w, level_h, mt->format, is_bgra); > + } > + > + intel_miptree_unmap(brw, mt, level, slice); > + intel_miptree_unmap(brw, smt, level, slice); > +} > + > +void > +intel_miptree_update_etc_shadow_levels(struct brw_context *brw, > + struct intel_mipmap_tree *mt) > +{ > + struct intel_mipmap_tree *smt; > + int num_slices; > + int level_w, level_h; > + > + assert(mt); > + assert(mt->surf.size_B > 0); > + > + assert(intel_miptree_has_etc_shadow(brw, mt)); > + > + smt = mt->shadow_mt; > + > + level_w = smt->surf.logical_level0_px.width; > + level_h = smt->surf.logical_level0_px.height; > + > + num_slices = smt->surf.logical_level0_px.array_len; > + > + for (int level = smt->first_level; level <= smt->last_level; level++) > + { > + for (unsigned int slice = 0; slice < num_slices; slice++) { > + intel_miptree_update_etc_shadow(brw, mt, level, slice, level_w, > + level_h); > + } > + > + level_w = minify(mt->surf.logical_level0_px.width, > + level - mt->first_level); > + level_h = minify(mt->surf.logical_level0_px.height, > + level - mt->first_level); This function goes from accessing the smt to the mt for the logical_level0_px field. It does work, but it is a little surprising. > + } > + > + mt->shadow_needs_update = false; > +} > diff --git a/src/mesa/drivers/dri/i965/intel_mipmap_tree.h > b/src/mesa/drivers/dri/i965/intel_mipmap_tree.h > index 1a7507023a1..752aeaaf9b7 100644 > --- a/src/mesa/drivers/dri/i965/intel_mipmap_tree.h > +++ b/src/mesa/drivers/dri/i965/intel_mipmap_tree.h > @@ -301,6 +301,8 @@ struct intel_mipmap_tree > * > * This miptree may be used for: > * - Stencil texturing (pre-BDW) as required by GL_ARB_stencil_texturing. > + * - To store the decompressed ETC/EAC data in case we emulate the ETC > + * compression on Gen 7 or earlier GPUs. > */ > struct intel_mipmap_tree *shadow_mt; > bool shadow_needs_update; > @@ -730,6 +732,28 @@ isl_memcpy_type > intel_miptree_get_memcpy_type(mesa_format tiledFormat, GLenum format, GLenum > type, > uint32_t *cpp); > > +static inline bool > +intel_miptree_needs_fake_etc(struct brw_context *brw, > + struct intel_mipmap_tree *mt) > +{ > + const struct gen_device_info *devinfo = &brw->screen->devinfo; > + bool is_etc = _mesa_is_format_etc2(mt->format) || > + (mt->format == MESA_FORMAT_ETC1_RGB8); > + > + return devinfo->gen < 8 && !devinfo->is_baytrail && is_etc; > +} > + > +static inline bool > +intel_miptree_has_etc_shadow(struct brw_context *brw, > + struct intel_mipmap_tree *mt) > +{ > + return intel_miptree_needs_fake_etc(brw, mt) && mt->shadow_mt; This function does the same work as the various mt->etc_format != MESA_FORMAT_NONE checks we have in i965, but I prefer the way you've implemented it here. > +} > + > +void > +intel_miptree_update_etc_shadow_levels(struct brw_context *brw, > + struct intel_mipmap_tree *mt); > + > #ifdef __cplusplus > } > #endif > -- > 2.20.1 > _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev