From 90d011de8ee16e954a4da0dde8c072cbbf3bafcc Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Mon, 6 Jun 2022 15:19:59 -0600 Subject: [PATCH] llvmpipe: fix texcoord analysis in llvmpipe_nir_fn_is_linear_compat() For the linear rendering fast path, we need to know whether the texcoord argument to tex instructions comes directly from an FS input (swizzling OK, but no arithmetic, etc). Use the input register info to fill in the tex_info object. This is part of a fix for some linear rendering bugs. Signed-off-by: Brian Paul Reviewed-by: Roland Scheidegger cc: mesa-stable Part-of: --- .../drivers/llvmpipe/lp_state_fs_analysis.c | 124 +++++++++++++++--- 1 file changed, 107 insertions(+), 17 deletions(-) diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs_analysis.c b/src/gallium/drivers/llvmpipe/lp_state_fs_analysis.c index 93660b016ee..9498a0b216f 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_fs_analysis.c +++ b/src/gallium/drivers/llvmpipe/lp_state_fs_analysis.c @@ -174,6 +174,98 @@ finished: } +/* + * Determine whether the given alu src comes directly from an input + * register. If so, return true and the input register index and + * component. Return false otherwise. + */ +static bool +get_nir_input_info(const nir_alu_src *src, + unsigned *input_index, + int *input_component) +{ + if (!src->src.is_ssa) { + return false; + } + + // The parent instr should be a nir_intrinsic_load_deref. + const nir_instr *parent = src->src.ssa[0].parent_instr; + if (!parent || parent->type != nir_instr_type_intrinsic) { + return false; + } + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(parent); + if (!intrin || + intrin->intrinsic != nir_intrinsic_load_deref || + !intrin->src[0].is_ssa) { + return false; + } + + // The parent of the load should be a type_deref. + parent = intrin->src->ssa->parent_instr; + if (!parent || parent->type != nir_instr_type_deref) { + return false; + } + + // The var being deref'd should be a shader input register. + nir_deref_instr *deref = nir_instr_as_deref(parent); + if (!deref || deref->deref_type != nir_deref_type_var || + deref->modes != nir_var_shader_in) { + return false; + } + + *input_index = deref->var->data.driver_location; + *input_component = src->swizzle[0]; + assert(*input_component >= 0); + assert(*input_component <= 3); + + return true; +} + + +/* + * Examine the texcoord argument to a texture instruction to determine + * if the texcoord comes directly from a fragment shader input. If so + * return true and return the FS input register index for the coordinate + * and the (2-component) swizzle. Return false otherwise. + */ +static bool +get_texcoord_provenance(const nir_tex_src *texcoord, + unsigned *coord_fs_input_index, // out + int swizzle[4]) // out +{ + assert(texcoord->src_type == nir_tex_src_coord); + + // The parent instr of the coord should be an nir_op_vec2 alu op + const nir_instr *parent = texcoord->src.ssa->parent_instr; + if (!parent || parent->type != nir_instr_type_alu) { + return false; + } + const nir_alu_instr *alu = nir_instr_as_alu(parent); + if (!alu || alu->op != nir_op_vec2) { + return false; + } + + // Loop over nir_op_vec2 instruction arguments to find the + // input register index and component. + unsigned input_reg_indexes[2]; + for (unsigned comp = 0; comp < 2; comp++) { + if (!get_nir_input_info(&alu->src[comp], + &input_reg_indexes[comp], &swizzle[comp])) { + return false; + } + } + + // Both texcoord components should come from the same input register. + if (input_reg_indexes[0] != input_reg_indexes[1]) { + return false; + } + + *coord_fs_input_index = input_reg_indexes[0]; + + return true; +} + + /* * Examine the NIR shader to determine if it's "linear". */ @@ -208,24 +300,17 @@ llvmpipe_nir_fn_is_linear_compat(const struct nir_shader *shader, case nir_instr_type_tex: { nir_tex_instr *tex = nir_instr_as_tex(instr); struct lp_tgsi_texture_info *tex_info = &info->tex[info->num_texs]; + int texcoord_swizzle[4] = {-1, -1, -1, -1}; + unsigned coord_fs_input_index; for (unsigned i = 0; i < tex->num_srcs; i++) { - switch (tex->src[i].src_type) { - case nir_tex_src_coord: { - nir_ssa_scalar scalar = nir_ssa_scalar_resolved(tex->src[i].src.ssa, 0); - if (scalar.def->parent_instr->type != nir_instr_type_intrinsic) + if (tex->src[i].src_type == nir_tex_src_coord) { + if (!get_texcoord_provenance(&tex->src[i], + &coord_fs_input_index, + texcoord_swizzle)) { + //debug nir_print_shader((nir_shader *) shader, stdout); return false; - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(scalar.def->parent_instr); - if (intrin->intrinsic != nir_intrinsic_load_deref) - return false; - nir_deref_instr *deref = nir_instr_as_deref(intrin->src[0].ssa->parent_instr); - nir_variable *var = nir_deref_instr_get_variable(deref); - if (var->data.mode != nir_var_shader_in) - return false; - break; - } - default: - continue; + } } } @@ -253,9 +338,14 @@ llvmpipe_nir_fn_is_linear_compat(const struct nir_shader *shader, /* this is enforced in the scanner previously. */ tex_info->coord[0].file = TGSI_FILE_INPUT; // S - tex_info->coord[0].swizzle = 0; tex_info->coord[1].file = TGSI_FILE_INPUT; // T - tex_info->coord[1].swizzle = 1; + assert(texcoord_swizzle[0] >= 0); + assert(texcoord_swizzle[1] >= 0); + tex_info->coord[0].swizzle = texcoord_swizzle[0]; // S + tex_info->coord[1].swizzle = texcoord_swizzle[1]; // T + tex_info->coord[0].u.index = coord_fs_input_index; + tex_info->coord[1].u.index = coord_fs_input_index; + info->num_texs++; break; }