summaryrefslogtreecommitdiffstats
path: root/src/intel/vulkan/anv_image.c
diff options
context:
space:
mode:
authorJason Ekstrand <[email protected]>2017-07-11 13:17:06 -0700
committerJason Ekstrand <[email protected]>2017-09-20 17:21:06 -0700
commit1e5fd2f839187c647b7cbb7256d6c950b219eba3 (patch)
treec1aa41f7489a113c7fde38d141785329470ae228 /src/intel/vulkan/anv_image.c
parent2c8058fb68a1e8cbc835272bd70c65eeac0779b9 (diff)
anv/image: Support creating uncompressed views of compressed images
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 and are hard-coded to align to exactly the block size of the compressed texture. This means 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. Reviewed-by: Lionel Landwerlin <[email protected]>
Diffstat (limited to 'src/intel/vulkan/anv_image.c')
-rw-r--r--src/intel/vulkan/anv_image.c111
1 files changed, 108 insertions, 3 deletions
diff --git a/src/intel/vulkan/anv_image.c b/src/intel/vulkan/anv_image.c
index b69f76cac36..837b6a4e8dd 100644
--- a/src/intel/vulkan/anv_image.c
+++ b/src/intel/vulkan/anv_image.c
@@ -268,6 +268,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,
@@ -289,6 +301,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) {
@@ -730,6 +772,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);
+ surface = &image->shadow_surface;
+ }
+
if (view_usage == ISL_SURF_USAGE_RENDER_TARGET_BIT)
view.swizzle = anv_swizzle_for_render(view.swizzle);
@@ -775,16 +831,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 {