[Mesa-dev] [PATCH 08/12] anv/image: Support creating uncompressed views of compressed images

Jason Ekstrand jason at jlekstrand.net
Tue Sep 19 19:02:25 UTC 2017


On Tue, Sep 19, 2017 at 6:52 AM, Lionel Landwerlin <
lionel.g.landwerlin at intel.com> wrote:

> On 15/09/17 17:01, Jason Ekstrand wrote:
>
>> In order to get support everywhere, this gets a bit complicated.  On Sky
>> Lake and later, everything is fine because HALIGN/VALIGN are specified
>> in surface elements and are required to be at least 4 so any offsetting
>> we may need to do falls neatly within the heavy restrictions placed on
>> the X/Y Offset parameter of RENDER_SURFACE_STATE.  On Broadwell and
>> earlier, HALIGN/VALIGN are specified in pixels are are hard-coded to
>> align to exactly the block size of the compressed texture.  This meas
>> that, when reinterpreted as a non-compressed texture, the tile offsets
>> may be anything and we can't rely on X/Y Offset.
>>
>> In order to work around this issue, we fall back to linear where we can
>> trivially offset to whatever element we so choose.  However, since
>> linear texturing performance is terrible, we create a tiled shadow copy
>> of the image to use for texturing.  Whenever the user does a layout
>> transition from anything to SHADER_READ_ONLY_OPTIMAL, we use blorp to
>> copy the contents of the texture from the linear copy to the tiled
>> shadow copy.  This assumes that the client will use the image far more
>> for texturing than as a storage image or render target.
>>
>> Even though we don't need the shadow copy on Sky Lake, we implement it
>> this way first to make testing easier.  Due to the hardware restriction
>> that ASTC must not be linear, ASTC does not work yet.
>> ---
>>   src/intel/vulkan/anv_blorp.c       |  46 +++++++++++++++
>>   src/intel/vulkan/anv_image.c       | 111 ++++++++++++++++++++++++++++++
>> ++++++-
>>   src/intel/vulkan/anv_private.h     |  14 +++++
>>   src/intel/vulkan/genX_cmd_buffer.c |  21 ++++++-
>>   4 files changed, 187 insertions(+), 5 deletions(-)
>>
>> diff --git a/src/intel/vulkan/anv_blorp.c b/src/intel/vulkan/anv_blorp.c
>> index 7f51bed..95f8696 100644
>> --- a/src/intel/vulkan/anv_blorp.c
>> +++ b/src/intel/vulkan/anv_blorp.c
>> @@ -1489,6 +1489,52 @@ anv_cmd_buffer_resolve_subpass(struct
>> anv_cmd_buffer *cmd_buffer)
>>   }
>>     void
>> +anv_image_copy_to_shadow(struct anv_cmd_buffer *cmd_buffer,
>> +                         const struct anv_image *image,
>> +                         VkImageAspectFlagBits aspect,
>> +                         uint32_t base_level, uint32_t level_count,
>> +                         uint32_t base_layer, uint32_t layer_count)
>> +{
>> +   struct blorp_batch batch;
>> +   blorp_batch_init(&cmd_buffer->device->blorp, &batch, cmd_buffer, 0);
>> +
>> +   struct blorp_surf surf;
>> +   get_blorp_surf_for_anv_image(image, VK_IMAGE_ASPECT_DEPTH_BIT,
>> +                                ISL_AUX_USAGE_NONE, &surf);
>> +
>> +   struct blorp_surf shadow_surf = {
>> +      .surf = &image->shadow_surface.isl,
>> +      .addr = {
>> +         .buffer = image->bo,
>> +         .offset = image->offset + image->shadow_surface.offset,
>> +      },
>> +   };
>> +
>> +   for (uint32_t l = 0; l < level_count; l++) {
>> +      const uint32_t level = base_level + l;
>> +
>> +      const VkExtent3D extent = {
>> +         .width = anv_minify(image->extent.width, level),
>> +         .height = anv_minify(image->extent.height, level),
>> +         .depth = anv_minify(image->extent.depth, level),
>> +      };
>> +
>> +      if (image->type == VK_IMAGE_TYPE_3D)
>> +         layer_count = extent.depth;
>> +
>> +      for (uint32_t a = 0; a < layer_count; a++) {
>> +         const uint32_t layer = base_layer + a;
>> +
>> +         blorp_copy(&batch, &surf, level, layer,
>> +                    &shadow_surf, level, layer,
>> +                    0, 0, 0, 0, extent.width, extent.height);
>> +      }
>> +   }
>> +
>> +   blorp_batch_finish(&batch);
>> +}
>> +
>> +void
>>   anv_gen8_hiz_op_resolve(struct anv_cmd_buffer *cmd_buffer,
>>                           const struct anv_image *image,
>>                           enum blorp_hiz_op op)
>> diff --git a/src/intel/vulkan/anv_image.c b/src/intel/vulkan/anv_image.c
>> index 77ffa7d..e6e3250 100644
>> --- a/src/intel/vulkan/anv_image.c
>> +++ b/src/intel/vulkan/anv_image.c
>> @@ -235,6 +235,18 @@ make_surface(const struct anv_device *dev,
>>                                                  aspect, vk_info->tiling);
>>      assert(format != ISL_FORMAT_UNSUPPORTED);
>>   +   /* If an image is created as BLOCK_TEXEL_VIEW_COMPATIBLE, then we
>> need to
>> +    * fall back to linear because we aren't guaranteed that we can handle
>> +    * offsets correctly.
>> +    */
>> +   bool needs_shadow = false;
>> +   if ((vk_info->flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR)
>> &&
>> +       vk_info->tiling == VK_IMAGE_TILING_OPTIMAL) {
>> +      assert(isl_format_is_compressed(format));
>> +      tiling_flags = ISL_TILING_LINEAR_BIT;
>> +      needs_shadow = true;
>> +   }
>> +
>>      ok = isl_surf_init(&dev->isl_dev, &anv_surf->isl,
>>         .dim = vk_to_isl_surf_dim[vk_info->imageType],
>>         .format = format,
>> @@ -256,6 +268,36 @@ make_surface(const struct anv_device *dev,
>>        add_surface(image, anv_surf);
>>   +   /* If an image is created as BLOCK_TEXEL_VIEW_COMPATIBLE, then we
>> need to
>> +    * create an identical tiled shadow surface for use while texturing
>> so we
>> +    * don't get garbage performance.
>> +    */
>> +   if (needs_shadow) {
>> +      assert(aspect == VK_IMAGE_ASPECT_COLOR_BIT);
>> +      assert(tiling_flags == ISL_TILING_LINEAR_BIT);
>> +
>> +      ok = isl_surf_init(&dev->isl_dev, &image->shadow_surface.isl,
>> +         .dim = vk_to_isl_surf_dim[vk_info->imageType],
>> +         .format = format,
>> +         .width = image->extent.width,
>> +         .height = image->extent.height,
>> +         .depth = image->extent.depth,
>> +         .levels = vk_info->mipLevels,
>> +         .array_len = vk_info->arrayLayers,
>> +         .samples = vk_info->samples,
>> +         .min_alignment = 0,
>> +         .row_pitch = anv_info->stride,
>> +         .usage = choose_isl_surf_usage(image->usage, image->usage,
>> aspect),
>> +         .tiling_flags = ISL_TILING_ANY_MASK);
>> +
>> +      /* isl_surf_init() will fail only if provided invalid input.
>> Invalid input
>> +       * is illegal in Vulkan.
>> +       */
>> +      assert(ok);
>> +
>> +      add_surface(image, &image->shadow_surface);
>> +   }
>> +
>>      /* Add a HiZ surface to a depth buffer that will be used for
>> rendering.
>>       */
>>      if (aspect == VK_IMAGE_ASPECT_DEPTH_BIT) {
>> @@ -673,6 +715,20 @@ anv_image_fill_surface_state(struct anv_device
>> *device,
>>      struct isl_view view = *view_in;
>>      view.usage |= view_usage;
>>   +   /* For texturing with VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
>> from a
>> +    * compressed surface with a shadow surface, we use the shadow
>> instead of
>> +    * the primary surface.  The shadow surface will be tiled, unlike the
>> main
>> +    * surface, so it should get significantly better performance.
>> +    */
>> +   if (image->shadow_surface.isl.size > 0 &&
>> +       isl_format_is_compressed(view.format) &&
>> +       (flags & ANV_IMAGE_VIEW_STATE_TEXTURE_OPTIMAL)) {
>> +      assert(isl_format_is_compressed(surface->isl.format));
>> +      assert(surface->isl.tiling == ISL_TILING_LINEAR);
>> +      assert(image->shadow_surface.isl.tiling != ISL_TILING_LINEAR);
>>
>
> There is something odd here (I must misunderstand...).
> In make_surface() you always make the shadow_surface with linear tiling,
> yet here you're expecting it *not* to be linear?
>

No.  We set tiling to LINEAR and set needs_shadow.  When we actually create
the shadow, we explicitly use TILING_ANY.


> +      surface = &image->shadow_surface;
>> +   }
>> +
>>      if (view_usage == ISL_SURF_USAGE_RENDER_TARGET_BIT)
>>         view.swizzle = anv_swizzle_for_render(view.swizzle);
>>   @@ -718,16 +774,65 @@ anv_image_fill_surface_state(struct anv_device
>> *device,
>>                                                         view.format);
>>         }
>>   +      const struct isl_surf *isl_surf = &surface->isl;
>> +
>> +      struct isl_surf tmp_surf;
>> +      uint32_t offset_B = 0, tile_x_sa = 0, tile_y_sa = 0;
>> +      if (isl_format_is_compressed(surface->isl.format) &&
>> +          !isl_format_is_compressed(view.format)) {
>> +         /* We're creating an uncompressed view of a compressed
>> surface.  This
>> +          * is allowed but only for a single level/layer.
>> +          */
>> +         assert(surface->isl.samples == 1);
>> +         assert(view.levels == 1);
>> +         assert(view.array_len == 1);
>> +
>> +         isl_surf_get_image_surf(&device->isl_dev, isl_surf,
>> +                                 view.base_level,
>> +                                 surface->isl.dim == ISL_SURF_DIM_3D ?
>> +                                    0 : view.base_array_layer,
>> +                                 surface->isl.dim == ISL_SURF_DIM_3D ?
>> +                                    view.base_array_layer : 0,
>> +                                 &tmp_surf,
>> +                                 &offset_B, &tile_x_sa, &tile_y_sa);
>> +
>> +         /* The newly created image represents the one subimage we're
>> +          * referencing with this view so it only has one array slice and
>> +          * miplevel.
>> +          */
>> +         view.base_array_layer = 0;
>> +         view.base_level = 0;
>> +
>> +         /* We're making an uncompressed view here.  The image
>> dimensions need
>> +          * to be scaled down by the block size.
>> +          */
>> +         const struct isl_format_layout *fmtl =
>> +            isl_format_get_layout(surface->isl.format);
>> +         tmp_surf.format = view.format;
>> +         tmp_surf.logical_level0_px.width =
>> +            DIV_ROUND_UP(tmp_surf.logical_level0_px.width, fmtl->bw);
>> +         tmp_surf.logical_level0_px.height =
>> +            DIV_ROUND_UP(tmp_surf.logical_level0_px.height, fmtl->bh);
>> +         tmp_surf.phys_level0_sa.width /= fmtl->bw;
>> +         tmp_surf.phys_level0_sa.height /= fmtl->bh;
>> +
>> +         isl_surf = &tmp_surf;
>> +
>> +         assert(surface->isl.tiling == ISL_TILING_LINEAR);
>> +         assert(tile_x_sa == 0);
>> +         assert(tile_y_sa == 0);
>> +      }
>> +
>>         isl_surf_fill_state(&device->isl_dev, state_inout->state.map,
>> -                          .surf = &surface->isl,
>> +                          .surf = isl_surf,
>>                             .view = &view,
>> -                          .address = address,
>> +                          .address = address + offset_B,
>>                             .clear_color = *clear_color,
>>                             .aux_surf = &image->aux_surface.isl,
>>                             .aux_usage = aux_usage,
>>                             .aux_address = aux_address,
>>                             .mocs = device->default_mocs);
>> -      state_inout->address = address;
>> +      state_inout->address = address + offset_B;
>>         if (device->info.gen >= 8) {
>>            state_inout->aux_address = aux_address;
>>         } else {
>> diff --git a/src/intel/vulkan/anv_private.h
>> b/src/intel/vulkan/anv_private.h
>> index 85843b2..355adba 100644
>> --- a/src/intel/vulkan/anv_private.h
>> +++ b/src/intel/vulkan/anv_private.h
>> @@ -2266,6 +2266,13 @@ struct anv_image {
>>      };
>>        /**
>> +    * A surface which shadows the main surface and may have different
>> tiling.
>> +    * This is used for sampling using a tiling that isn't supported for
>> other
>> +    * operations.
>> +    */
>> +   struct anv_surface shadow_surface;
>> +
>> +   /**
>>       * For color images, this is the aux usage for this image when not
>> used as a
>>       * color attachment.
>>       *
>> @@ -2352,6 +2359,13 @@ anv_image_fast_clear(struct anv_cmd_buffer
>> *cmd_buffer,
>>                        const uint32_t base_level, const uint32_t
>> level_count,
>>                        const uint32_t base_layer, uint32_t layer_count);
>>   +void
>> +anv_image_copy_to_shadow(struct anv_cmd_buffer *cmd_buffer,
>> +                         const struct anv_image *image,
>> +                         VkImageAspectFlagBits aspect,
>> +                         uint32_t base_level, uint32_t level_count,
>> +                         uint32_t base_layer, uint32_t layer_count);
>> +
>>   enum isl_aux_usage
>>   anv_layout_to_aux_usage(const struct gen_device_info * const devinfo,
>>                           const struct anv_image *image,
>> diff --git a/src/intel/vulkan/genX_cmd_buffer.c
>> b/src/intel/vulkan/genX_cmd_buffer.c
>> index 7fb607f..fbc1995 100644
>> --- a/src/intel/vulkan/genX_cmd_buffer.c
>> +++ b/src/intel/vulkan/genX_cmd_buffer.c
>> @@ -627,8 +627,25 @@ transition_color_buffer(struct anv_cmd_buffer
>> *cmd_buffer,
>>      /* No work is necessary if the layout stays the same or if this
>> subresource
>>       * range lacks auxiliary data.
>>       */
>> -   if (initial_layout == final_layout ||
>> -       base_layer >= anv_image_aux_layers(image, base_level))
>> +   if (initial_layout == final_layout)
>> +      return;
>> +
>> +   if (image->shadow_surface.isl.size > 0 &&
>> +       final_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
>> +      /* This surface is a linear compressed image with a tiled shadow
>> surface
>> +       * for texturing.  The client is about to use it in
>> READ_ONLY_OPTIMAL so
>> +       * we need to ensure the shadow copy is up-to-date.
>> +       */
>> +      assert(image->aspects == VK_IMAGE_ASPECT_COLOR_BIT);
>> +      assert(image->color_surface.isl.tiling == ISL_TILING_LINEAR);
>> +      assert(image->shadow_surface.isl.tiling != ISL_TILING_LINEAR);
>> +      assert(isl_format_is_compressed(image->color_surface.isl.format));
>> +      anv_image_copy_to_shadow(cmd_buffer, image,
>> VK_IMAGE_ASPECT_COLOR_BIT,
>> +                               base_level, level_count,
>> +                               base_layer, layer_count);
>> +   }
>> +
>> +   if (base_layer >= anv_image_aux_layers(image, base_level))
>>         return;
>>        /* A transition of a 3D subresource works on all slices at a time.
>> */
>>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20170919/6220c3f7/attachment-0001.html>


More information about the mesa-dev mailing list