nir,spirv: Add support for SPV_QCOM_image_processing.

Initial work was done by Mark Collins, which I significantly rewrote.

Signed-off-by: Mark Collins <mark@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38559>
This commit is contained in:
Emma Anholt 2025-02-06 20:22:37 +00:00 committed by Marge Bot
parent a70cb908e4
commit e922c2cabc
9 changed files with 185 additions and 5 deletions

View file

@ -3435,6 +3435,12 @@ nir_tex_instr_result_size(const nir_tex_instr *instr)
case nir_texop_custom_border_color_agx:
return 4;
case nir_texop_sample_weighted_qcom:
case nir_texop_box_filter_qcom:
case nir_texop_block_match_sad_qcom:
case nir_texop_block_match_ssd_qcom:
return 4;
default:
if (instr->is_shadow && instr->is_new_style_shadow)
return 1;
@ -3473,6 +3479,10 @@ nir_tex_instr_is_query(const nir_tex_instr *instr)
case nir_texop_samples_identical:
case nir_texop_fragment_mask_fetch_amd:
case nir_texop_fragment_fetch_amd:
case nir_texop_sample_weighted_qcom:
case nir_texop_box_filter_qcom:
case nir_texop_block_match_sad_qcom:
case nir_texop_block_match_ssd_qcom:
return false;
default:
UNREACHABLE("Invalid texture opcode");
@ -3499,6 +3509,7 @@ nir_tex_instr_src_type(const nir_tex_instr *instr, unsigned src)
{
switch (instr->src[src].src_type) {
case nir_tex_src_coord:
case nir_tex_src_ref_coord:
switch (instr->op) {
case nir_texop_txf:
case nir_texop_txf_ms:
@ -3507,6 +3518,8 @@ nir_tex_instr_src_type(const nir_tex_instr *instr, unsigned src)
case nir_texop_samples_identical:
case nir_texop_fragment_fetch_amd:
case nir_texop_fragment_mask_fetch_amd:
case nir_texop_block_match_sad_qcom:
case nir_texop_block_match_ssd_qcom:
return nir_type_int;
default:
@ -3535,6 +3548,7 @@ nir_tex_instr_src_type(const nir_tex_instr *instr, unsigned src)
case nir_tex_src_ddy:
case nir_tex_src_backend1:
case nir_tex_src_backend2:
case nir_tex_src_box_size:
return nir_type_float;
case nir_tex_src_offset:
@ -3552,6 +3566,11 @@ nir_tex_instr_src_type(const nir_tex_instr *instr, unsigned src)
case nir_tex_src_sampler_offset:
case nir_tex_src_texture_handle:
case nir_tex_src_sampler_handle:
case nir_tex_src_texture_2_deref:
case nir_tex_src_sampler_2_deref:
case nir_tex_src_texture_2_handle:
case nir_tex_src_sampler_2_handle:
case nir_tex_src_block_size:
return nir_type_uint;
case nir_num_tex_src_types:
@ -3564,13 +3583,24 @@ nir_tex_instr_src_type(const nir_tex_instr *instr, unsigned src)
unsigned
nir_tex_instr_src_size(const nir_tex_instr *instr, unsigned src)
{
if (instr->src[src].src_type == nir_tex_src_coord)
if (instr->src[src].src_type == nir_tex_src_coord )
return instr->coord_components;
/* The MCS value is expected to be a vec4 returned by a txf_ms_mcs_intel */
if (instr->src[src].src_type == nir_tex_src_ms_mcs_intel)
return 4;
if (instr->src[src].src_type == nir_tex_src_box_size)
return 2;
/* These are vec2s at the spirv level, but get lowered to 16_16 packed values
* in the backend, so they don't have a single known size
*/
if (instr->src[src].src_type == nir_tex_src_ref_coord ||
instr->src[src].src_type == nir_tex_src_block_size) {
return 0;
}
if (instr->src[src].src_type == nir_tex_src_ddx ||
instr->src[src].src_type == nir_tex_src_ddy) {

View file

@ -2384,6 +2384,15 @@ typedef enum nir_tex_src_type {
/** Second backend-specific vec4 tex src argument, see nir_tex_src_backend1. */
nir_tex_src_backend2,
/** VK_QCOM_image_processing sources */
nir_tex_src_ref_coord,
nir_tex_src_texture_2_deref,
nir_tex_src_sampler_2_deref,
nir_tex_src_texture_2_handle,
nir_tex_src_sampler_2_handle,
nir_tex_src_block_size,
nir_tex_src_box_size,
nir_num_tex_src_types
} nir_tex_src_type;
@ -2450,6 +2459,26 @@ typedef enum nir_texop {
nir_texop_tex_type_nv,
/** Maps to TXQ.SAMPLER_POS */
nir_texop_sample_pos_nv,
/**
* Returns the weighted average of a region of texels in the texture, using
* the filter kernel sampled from ref_texture. (VK_QCOM_image_processing)
*/
nir_texop_sample_weighted_qcom,
/**
* Returns the result of a weighted average of the texels in a box of size
* box_size centered at coord. (VK_QCOM_image_processing)
*/
nir_texop_box_filter_qcom,
/**
* Returns the result of SAD/SSD block matching on 2D textures.
* (VK_QCOM_image_processing)
*
* The textures are always 2D dim, and the coord and ref_coord texture
* sources are ivec2s. The size of the block is specified in the block_size
* texture source (uvec2 from SPIRV, packed u32 in the backend)
*/
nir_texop_block_match_sad_qcom,
nir_texop_block_match_ssd_qcom,
} nir_texop;
/** Represents a texture instruction */
@ -2493,7 +2522,10 @@ typedef struct nir_tex_instr {
/** Number of sources */
unsigned num_srcs;
/** Number of components in the coordinate, if any */
/** Number of components in the coordinate, if any.
*
* This applies to the nir_tex_src_coord and nir_tex_src_ref_coord src types.
*/
unsigned coord_components;
/** True if the texture instruction acts on an array texture */

View file

@ -1057,12 +1057,14 @@ visit_tex(nir_tex_instr *instr, struct divergence_state *state)
for (unsigned i = 0; i < instr->num_srcs; i++) {
switch (instr->src[i].src_type) {
case nir_tex_src_sampler_deref:
case nir_tex_src_sampler_2_deref:
case nir_tex_src_sampler_handle:
case nir_tex_src_sampler_offset:
is_divergent |= src_divergent(instr->src[i].src, state) &&
instr->sampler_non_uniform;
break;
case nir_tex_src_texture_deref:
case nir_tex_src_texture_2_deref:
case nir_tex_src_texture_handle:
case nir_tex_src_texture_offset:
is_divergent |= src_divergent(instr->src[i].src, state) &&

View file

@ -221,6 +221,7 @@ lower_non_uniform_tex_access(struct nu_state *state, nir_tex_instr *tex,
case nir_tex_src_texture_offset:
case nir_tex_src_texture_handle:
case nir_tex_src_texture_deref:
case nir_tex_src_texture_2_deref:
if (!tex->texture_non_uniform)
continue;
if (!(opts->types & nir_lower_non_uniform_texture_access))
@ -232,6 +233,7 @@ lower_non_uniform_tex_access(struct nu_state *state, nir_tex_instr *tex,
case nir_tex_src_sampler_offset:
case nir_tex_src_sampler_handle:
case nir_tex_src_sampler_deref:
case nir_tex_src_sampler_2_deref:
if (!tex->sampler_non_uniform)
continue;
if (!(opts->types & nir_lower_non_uniform_texture_access))

View file

@ -334,10 +334,12 @@ gcm_pin_instructions(nir_function_impl *impl, struct gcm_state *state)
nir_tex_src *src = &tex->src[i];
switch (src->src_type) {
case nir_tex_src_texture_deref:
case nir_tex_src_texture_2_deref:
if (!tex->texture_non_uniform && !is_binding_uniform(src->src))
instr->pass_flags = GCM_INSTR_PINNED;
break;
case nir_tex_src_sampler_deref:
case nir_tex_src_sampler_2_deref:
if (!tex->sampler_non_uniform && !is_binding_uniform(src->src))
instr->pass_flags = GCM_INSTR_PINNED;
break;

View file

@ -1188,6 +1188,10 @@ vulkan_descriptor_type_name(VkDescriptorType type)
return "inline-UBO";
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR:
return "accel-struct";
case VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM:
return "sample-weight-image";
case VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM:
return "block-match-image";
default:
return "unknown";
}
@ -1903,6 +1907,18 @@ print_tex_instr(nir_tex_instr *instr, print_state *state)
case nir_texop_sample_pos_nv:
fprintf(fp, "sample_pos_nv ");
break;
case nir_texop_sample_weighted_qcom:
fprintf(fp, "sample_weighted_qcom ");
break;
case nir_texop_box_filter_qcom:
fprintf(fp, "box_filter_qcom ");
break;
case nir_texop_block_match_sad_qcom:
fprintf(fp, "block_match_sad_qcom ");
break;
case nir_texop_block_match_ssd_qcom:
fprintf(fp, "block_match_ssd_qcom ");
break;
default:
UNREACHABLE("Invalid texture operation");
break;
@ -1927,6 +1943,9 @@ print_tex_instr(nir_tex_instr *instr, print_state *state)
case nir_tex_src_coord:
fprintf(fp, "(coord)");
break;
case nir_tex_src_ref_coord:
fprintf(fp, "(ref_coord)");
break;
case nir_tex_src_projector:
fprintf(fp, "(projector)");
break;
@ -1975,10 +1994,16 @@ print_tex_instr(nir_tex_instr *instr, print_state *state)
has_texture_deref = true;
fprintf(fp, "(texture_deref)");
break;
case nir_tex_src_texture_2_deref:
fprintf(fp, "(texture_2_deref)");
break;
case nir_tex_src_sampler_deref:
has_sampler_deref = true;
fprintf(fp, "(sampler_deref)");
break;
case nir_tex_src_sampler_2_deref:
fprintf(fp, "(sampler_2_deref)");
break;
case nir_tex_src_texture_offset:
fprintf(fp, "(texture_offset)");
break;
@ -1988,9 +2013,21 @@ print_tex_instr(nir_tex_instr *instr, print_state *state)
case nir_tex_src_texture_handle:
fprintf(fp, "(texture_handle)");
break;
case nir_tex_src_texture_2_handle:
fprintf(fp, "(texture_2_handle)");
break;
case nir_tex_src_sampler_handle:
fprintf(fp, "(sampler_handle)");
break;
case nir_tex_src_sampler_2_handle:
fprintf(fp, "(ref_sampler_handle)");
break;
case nir_tex_src_block_size:
fprintf(fp, "(block_size)");
break;
case nir_tex_src_box_size:
fprintf(fp, "(box_size)");
break;
case nir_tex_src_plane:
fprintf(fp, "(plane)");
break;

View file

@ -981,7 +981,8 @@ validate_tex_instr(nir_tex_instr *instr, validate_state *state)
validate_assert(state, instr->op == nir_texop_txd);
break;
case nir_tex_src_texture_deref: {
case nir_tex_src_texture_deref:
case nir_tex_src_texture_2_deref: {
nir_deref_instr *deref = nir_src_as_deref(instr->src[i].src);
if (!validate_assert(state, deref))
break;
@ -990,7 +991,8 @@ validate_tex_instr(nir_tex_instr *instr, validate_state *state)
break;
}
case nir_tex_src_sampler_deref: {
case nir_tex_src_sampler_deref:
case nir_tex_src_sampler_2_deref: {
nir_deref_instr *deref = nir_src_as_deref(instr->src[i].src);
if (!validate_assert(state, deref))
break;
@ -1016,7 +1018,18 @@ validate_tex_instr(nir_tex_instr *instr, validate_state *state)
break;
}
case nir_tex_src_block_size:
validate_assert(state,
instr->op == nir_texop_block_match_sad_qcom ||
instr->op == nir_texop_block_match_ssd_qcom);
break;
case nir_tex_src_box_size:
validate_assert(state, instr->op == nir_texop_box_filter_qcom);
break;
case nir_tex_src_coord:
case nir_tex_src_ref_coord:
case nir_tex_src_projector:
case nir_tex_src_offset:
case nir_tex_src_min_lod:
@ -1026,6 +1039,8 @@ validate_tex_instr(nir_tex_instr *instr, validate_state *state)
case nir_tex_src_plane:
case nir_tex_src_texture_handle:
case nir_tex_src_sampler_handle:
case nir_tex_src_texture_2_handle:
case nir_tex_src_sampler_2_handle:
break;
default:

View file

@ -203,6 +203,9 @@ static const struct spirv_capabilities implemented_capabilities = {
.SubgroupVoteKHR = true,
.Tessellation = true,
.TessellationPointSize = true,
.TextureBlockMatchQCOM = true,
.TextureBoxFilterQCOM = true,
.TextureSampleWeightedQCOM = true,
.TransformFeedback = true,
.UniformAndStorageBuffer8BitAccess = true,
.UniformBufferArrayDynamicIndexing = true,
@ -3565,6 +3568,22 @@ vtn_handle_texture(struct vtn_builder *b, SpvOp opcode,
dest_type = nir_type_uint32;
break;
case SpvOpImageSampleWeightedQCOM:
texop = nir_texop_sample_weighted_qcom;
break;
case SpvOpImageBoxFilterQCOM:
texop = nir_texop_box_filter_qcom;
break;
case SpvOpImageBlockMatchSADQCOM:
texop = nir_texop_block_match_sad_qcom;
break;
case SpvOpImageBlockMatchSSDQCOM:
texop = nir_texop_block_match_ssd_qcom;
break;
default:
vtn_fail_with_opcode("Unhandled opcode", opcode);
}
@ -3583,6 +3602,10 @@ vtn_handle_texture(struct vtn_builder *b, SpvOp opcode,
case nir_texop_txd:
case nir_texop_tg4:
case nir_texop_lod:
case nir_texop_sample_weighted_qcom:
case nir_texop_box_filter_qcom:
case nir_texop_block_match_sad_qcom:
case nir_texop_block_match_ssd_qcom:
vtn_fail_if(sampler == NULL,
"%s requires an image of type OpTypeSampledImage",
spirv_op_to_string(opcode));
@ -3653,7 +3676,11 @@ vtn_handle_texture(struct vtn_builder *b, SpvOp opcode,
case SpvOpImageSparseDrefGather:
case SpvOpImageQueryLod:
case SpvOpFragmentFetchAMD:
case SpvOpFragmentMaskFetchAMD: {
case SpvOpFragmentMaskFetchAMD:
case SpvOpImageSampleWeightedQCOM:
case SpvOpImageBoxFilterQCOM:
case SpvOpImageBlockMatchSADQCOM:
case SpvOpImageBlockMatchSSDQCOM: {
/* All these types have the coordinate as their first real argument */
coord_components = glsl_get_sampler_dim_coordinate_components(sampler_dim);
@ -3767,6 +3794,31 @@ vtn_handle_texture(struct vtn_builder *b, SpvOp opcode,
if (opcode == SpvOpFragmentFetchAMD)
(*p++) = vtn_tex_src(b, w[idx++], nir_tex_src_ms_index);
/* For SpvOpImageBoxFilterQCOM, we always have a box size */
if (opcode == SpvOpImageBoxFilterQCOM)
(*p++) = vtn_tex_src(b, w[idx++], nir_tex_src_box_size);
/* For SpvOpImageSampleWeightedQCOM and block matching, we have a secondary sampled image. */
if (opcode == SpvOpImageSampleWeightedQCOM ||
opcode == SpvOpImageBlockMatchSADQCOM ||
opcode == SpvOpImageBlockMatchSSDQCOM) {
struct vtn_value *sampled_val = vtn_untyped_value(b, w[idx]);
if (sampled_val->type->base_type == vtn_base_type_sampled_image) {
struct vtn_sampled_image si = vtn_get_sampled_image(b, w[idx]);
(*p++) = nir_tex_src_for_ssa(nir_tex_src_texture_2_deref, &si.image->def);
(*p++) = nir_tex_src_for_ssa(nir_tex_src_sampler_2_deref, &si.sampler->def);
} else {
vtn_err("Failed to look up sampled image for QCOM_image_processing");
}
idx++;
}
if (opcode == SpvOpImageBlockMatchSADQCOM ||
opcode == SpvOpImageBlockMatchSSDQCOM) {
(*p++) = vtn_tex_src(b, w[idx++], nir_tex_src_ref_coord);
(*p++) = vtn_tex_src(b, w[idx++], nir_tex_src_block_size);
}
/* Now we need to handle some number of optional arguments */
struct vtn_value *gather_offsets = NULL;
uint32_t operands = SpvImageOperandsMaskNone;
@ -6594,6 +6646,10 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
case SpvOpImageDrefGather:
case SpvOpImageSparseDrefGather:
case SpvOpImageQueryLod:
case SpvOpImageSampleWeightedQCOM:
case SpvOpImageBoxFilterQCOM:
case SpvOpImageBlockMatchSADQCOM:
case SpvOpImageBlockMatchSSDQCOM:
vtn_handle_texture(b, opcode, w, count);
break;

View file

@ -1561,6 +1561,10 @@ apply_var_decoration(struct vtn_builder *b,
"NodeMaxPayloadsAMDX decoration only allowed in compute shaders");
break;
case SpvDecorationWeightTextureQCOM:
case SpvDecorationBlockMatchTextureQCOM:
break;
default:
vtn_fail_with_decoration("Unhandled decoration", dec->decoration);
}