If the glsl is something like this: in vec4 some_input; interpolateAtCentroid(some_input[idx])
then it now gets generated as if it were: interpolateAtCentroid(some_input)[idx] This is necessary because the index will get generated as a series of nir_bcsel instructions so it would no longer be an input variable. It is similar to what is done for GLSL in ca63a5ed3e9efb2bd645b42. Although I can’t find anything explicit in the Vulkan specs to say this should be allowed, the SPIR-V spec just says “the operand interpolant must be a pointer to the Input Storage Class”, which I guess doesn’t rule out any type of pointer to an input. This was found using the spec/glsl-4.40/execution/fs-interpolateAt* Piglit tests with the ARB_gl_spirv branch. --- I’ve made a bunch of tests for this for VkRunner. They can be tested with: git clone https://github.com/Igalia/vkrunner.git -b tests cd vkrunner && ./autogen.sh && make ./src/vkrunner examples/interpolation/*.shader_test src/compiler/spirv/vtn_glsl450.c | 56 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/src/compiler/spirv/vtn_glsl450.c b/src/compiler/spirv/vtn_glsl450.c index 6fa759b1bba..cd39fcf6efb 100644 --- a/src/compiler/spirv/vtn_glsl450.c +++ b/src/compiler/spirv/vtn_glsl450.c @@ -773,6 +773,23 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSLstd450 entrypoint, } } +static bool +has_vector_array_deref(nir_deref *deref) +{ + while (true) { + if (deref->child == NULL) + return false; + + if (glsl_type_is_vector(deref->type) && + deref->child->deref_type == nir_deref_type_array) { + assert(deref->child->child == NULL); + return true; + } + + deref = deref->child; + } +} + static void handle_glsl450_interpolation(struct vtn_builder *b, enum GLSLstd450 opcode, const uint32_t *w, unsigned count) @@ -799,10 +816,28 @@ handle_glsl450_interpolation(struct vtn_builder *b, enum GLSLstd450 opcode, } nir_intrinsic_instr *intrin = nir_intrinsic_instr_create(b->nb.shader, op); + const struct glsl_type *intrin_type; nir_deref_var *deref = vtn_nir_deref(b, w[5]); intrin->variables[0] = nir_deref_var_clone(deref, intrin); + /* If the value we are interpolating has an index into a vector then + * interpolate the vector and index the result of that instead. This is + * necessary because the index will get generated as a series of nir_bcsel + * instructions so it would no longer be an input variable. + */ + bool vec_array_deref = has_vector_array_deref(&deref->deref); + if (vec_array_deref) { + /* Remove the last deref */ + nir_deref *parent = &intrin->variables[0]->deref; + while (parent->child->child) + parent = parent->child; + parent->child = NULL; + intrin_type = parent->type; + } else { + intrin_type = dest_type; + } + switch (opcode) { case GLSLstd450InterpolateAtCentroid: break; @@ -814,13 +849,26 @@ handle_glsl450_interpolation(struct vtn_builder *b, enum GLSLstd450 opcode, vtn_fail("Invalid opcode"); } - intrin->num_components = glsl_get_vector_elements(dest_type); + intrin->num_components = glsl_get_vector_elements(intrin_type); nir_ssa_dest_init(&intrin->instr, &intrin->dest, - glsl_get_vector_elements(dest_type), - glsl_get_bit_size(dest_type), NULL); - val->ssa->def = &intrin->dest.ssa; + glsl_get_vector_elements(intrin_type), + glsl_get_bit_size(intrin_type), NULL); nir_builder_instr_insert(&b->nb, &intrin->instr); + + if (vec_array_deref) { + nir_deref_array *deref_array = + nir_deref_as_array(nir_deref_tail(&deref->deref)); + if (deref_array->deref_array_type == nir_deref_array_type_direct) { + val->ssa->def = vtn_vector_extract(b, &intrin->dest.ssa, + deref_array->base_offset); + } else { + val->ssa->def = vtn_vector_extract_dynamic(b, &intrin->dest.ssa, + deref_array->indirect.ssa); + } + } else { + val->ssa->def = &intrin->dest.ssa; + } } bool -- 2.14.3 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev