From 2e8c0a33e776383bd27e285504e8023b2c005338 Mon Sep 17 00:00:00 2001 From: Lionel Landwerlin Date: Sun, 25 Jun 2023 18:59:13 +0300 Subject: [PATCH] anv: implement storage image depth query using descriptor buffer read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HW not returning the depth value we would like for VK_EXT_sliced_view_of_3d, we can pull that value by reading the RENDER_SURFACE_STATE struct directly. Signed-off-by: Lionel Landwerlin Reviewed-by: José Roberto de Souza Part-of: --- src/intel/genxml/meson.build | 1 + src/intel/vulkan/anv_descriptor_set.c | 1 + .../vulkan/anv_nir_apply_pipeline_layout.c | 100 +++++++++++++++++- src/intel/vulkan/anv_private.h | 22 +++- 4 files changed, 122 insertions(+), 2 deletions(-) diff --git a/src/intel/genxml/meson.build b/src/intel/genxml/meson.build index ca814510216..bd889f1b1f8 100644 --- a/src/intel/genxml/meson.build +++ b/src/intel/genxml/meson.build @@ -78,6 +78,7 @@ genX_bits_included_symbols = [ 'RENDER_SURFACE_STATE::Height', 'RENDER_SURFACE_STATE::Depth', 'RENDER_SURFACE_STATE::Surface Type', + 'RENDER_SURFACE_STATE::Render Target View Extent', 'CLEAR_COLOR', 'VERTEX_BUFFER_STATE::Buffer Starting Address', 'CPS_STATE', diff --git a/src/intel/vulkan/anv_descriptor_set.c b/src/intel/vulkan/anv_descriptor_set.c index 9d32d7243fe..2c1bf9d3f4c 100644 --- a/src/intel/vulkan/anv_descriptor_set.c +++ b/src/intel/vulkan/anv_descriptor_set.c @@ -1676,6 +1676,7 @@ anv_descriptor_set_write_image_view(struct anv_device *device, .vanilla = anv_surface_state_to_handle( device->physical, image_view->planes[0].storage.state), + .image_depth = image_view->vk.storage.z_slice_count, }; memcpy(desc_map, &desc_data, sizeof(desc_data)); } else { diff --git a/src/intel/vulkan/anv_nir_apply_pipeline_layout.c b/src/intel/vulkan/anv_nir_apply_pipeline_layout.c index 86311db60b9..e8f4183edf5 100644 --- a/src/intel/vulkan/anv_nir_apply_pipeline_layout.c +++ b/src/intel/vulkan/anv_nir_apply_pipeline_layout.c @@ -436,6 +436,51 @@ build_load_render_surface_state_address(nir_builder *b, return nir_vec4(b, addr_ldw, addr_udw, length, nir_imm_int(b, 0)); } +/* Load the depth of a 3D storage image. + * + * Either by reading the indirect descriptor value, or reading the value from + * RENDER_SURFACE_STATE. + * + * This is necessary for VK_EXT_image_sliced_view_of_3d. + */ +static nir_ssa_def * +build_load_storage_3d_image_depth(nir_builder *b, + nir_ssa_def *desc_addr, + nir_ssa_def *resinfo_depth, + struct apply_pipeline_layout_state *state) + +{ + const struct intel_device_info *devinfo = &state->pdevice->info; + + if (state->layout->type == ANV_PIPELINE_DESCRIPTOR_SET_LAYOUT_TYPE_INDIRECT) { + return build_load_descriptor_mem( + b, desc_addr, + offsetof(struct anv_storage_image_descriptor, image_depth), + 1, 32, state); + } else { + nir_ssa_def *data = build_load_descriptor_mem( + b, desc_addr, + RENDER_SURFACE_STATE_RenderTargetViewExtent_start(devinfo) / 8, + 1, 32, state); + nir_ssa_def *depth = + nir_ushr_imm( + b, data, + RENDER_SURFACE_STATE_RenderTargetViewExtent_start(devinfo) % 32); + depth = nir_iand_imm( + b, depth, + (1u << RENDER_SURFACE_STATE_RenderTargetViewExtent_bits(devinfo)) - 1); + depth = nir_iadd_imm(b, depth, 1); + + /* Return the minimum between the RESINFO value and the + * RENDER_SURFACE_STATE::RenderTargetViewExtent value. + * + * Both are expressed for the current view LOD, but in the case of a + * SURFTYPE_NULL, RESINFO will return the right value, while the -1 + * value in RENDER_SURFACE_STATE should be ignored. + */ + return nir_umin(b, resinfo_depth, depth); + } +} /** Build a Vulkan resource index * * A "resource index" is the term used by our SPIR-V parser and the relevant @@ -1479,6 +1524,58 @@ lower_image_intrinsic(nir_builder *b, nir_intrinsic_instr *intrin, return true; } +static bool +lower_image_size_intrinsic(nir_builder *b, nir_intrinsic_instr *intrin, + struct apply_pipeline_layout_state *state) +{ + if (nir_intrinsic_image_dim(intrin) != GLSL_SAMPLER_DIM_3D) + return lower_image_intrinsic(b, intrin, state); + + nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); + + b->cursor = nir_before_instr(&intrin->instr); + + bool non_uniform = nir_intrinsic_access(intrin) & ACCESS_NON_UNIFORM; + bool is_bindless; + nir_ssa_def *handle = + build_load_var_deref_surface_handle(b, deref, non_uniform, + &is_bindless, state); + nir_rewrite_image_intrinsic(intrin, handle, is_bindless); + + nir_variable *var = nir_deref_instr_get_variable(deref); + const uint32_t set = var->data.descriptor_set; + const uint32_t binding = var->data.binding; + + nir_ssa_def *array_index; + if (deref->deref_type != nir_deref_type_var) { + assert(deref->deref_type == nir_deref_type_array); + assert(nir_deref_instr_parent(deref)->deref_type == nir_deref_type_var); + assert(deref->arr.index.is_ssa); + array_index = deref->arr.index.ssa; + } else { + array_index = nir_imm_int(b, 0); + } + + nir_ssa_def *desc_addr = build_desc_addr_for_binding( + b, set, binding, array_index, state); + + b->cursor = nir_after_instr(&intrin->instr); + + nir_ssa_def *image_depth = + build_load_storage_3d_image_depth(b, desc_addr, + nir_channel(b, &intrin->dest.ssa, 2), + state); + + nir_ssa_def *comps[4] = {}; + for (unsigned c = 0; c < intrin->dest.ssa.num_components; c++) + comps[c] = c == 2 ? image_depth : nir_channel(b, &intrin->dest.ssa, c); + + nir_ssa_def *vec = nir_vec(b, comps, intrin->dest.ssa.num_components); + nir_ssa_def_rewrite_uses_after(&intrin->dest.ssa, vec, vec->parent_instr); + + return true; +} + static bool lower_load_constant(nir_builder *b, nir_intrinsic_instr *intrin, struct apply_pipeline_layout_state *state) @@ -1675,12 +1772,13 @@ apply_pipeline_layout(nir_builder *b, nir_instr *instr, void *_state) case nir_intrinsic_image_deref_store: case nir_intrinsic_image_deref_atomic: case nir_intrinsic_image_deref_atomic_swap: - case nir_intrinsic_image_deref_size: case nir_intrinsic_image_deref_samples: case nir_intrinsic_image_deref_load_param_intel: case nir_intrinsic_image_deref_load_raw_intel: case nir_intrinsic_image_deref_store_raw_intel: return lower_image_intrinsic(b, intrin, state); + case nir_intrinsic_image_deref_size: + return lower_image_size_intrinsic(b, intrin, state); case nir_intrinsic_load_constant: return lower_load_constant(b, intrin, state); case nir_intrinsic_load_base_workgroup_id: diff --git a/src/intel/vulkan/anv_private.h b/src/intel/vulkan/anv_private.h index 68d3fd113a4..893c05d3d9c 100644 --- a/src/intel/vulkan/anv_private.h +++ b/src/intel/vulkan/anv_private.h @@ -1671,7 +1671,27 @@ struct anv_storage_image_descriptor { */ uint32_t vanilla; - uint32_t pad; + /** Image depth + * + * By default the HW RESINFO message allows us to query the depth of an image : + * + * From the Kaby Lake docs for the RESINFO message: + * + * "Surface Type | ... | Blue + * --------------+-----+---------------- + * SURFTYPE_3D | ... | (Depth+1)»LOD" + * + * With VK_EXT_sliced_view_of_3d, we have to support a slice of a 3D image, + * meaning at a depth offset with a new depth value potentially reduced + * from the original image. Unfortunately if we change the Depth value of + * the image, we then run into issues with Yf/Ys tilings where the HW fetch + * data at incorrect locations. + * + * To solve this, we put the slice depth in the descriptor and recompose + * the vec3 (width, height, depth) using this field for z and xy using the + * RESINFO result. + */ + uint32_t image_depth; }; /** Struct representing a address/range descriptor