}
}
+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_COLOR_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,
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,
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) {
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);
+ surface = &image->shadow_surface;
+ }
+
if (view_usage == ISL_SURF_USAGE_RENDER_TARGET_BIT)
view.swizzle = anv_swizzle_for_render(view.swizzle);
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 {
/* 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. */