diff --git a/src/gallium/drivers/lima/ci/lima-fails.txt b/src/gallium/drivers/lima/ci/lima-fails.txt index ec9b634fc1e..5e36f9cfe87 100644 --- a/src/gallium/drivers/lima/ci/lima-fails.txt +++ b/src/gallium/drivers/lima/ci/lima-fails.txt @@ -41,6 +41,7 @@ dEQP-GLES2.functional.shaders.indexing.varying_array.vec4_dynamic_loop_write_dyn dEQP-GLES2.functional.shaders.indexing.varying_array.vec4_dynamic_loop_write_static_loop_read,Fail dEQP-GLES2.functional.shaders.indexing.varying_array.vec4_dynamic_loop_write_static_read,Fail dEQP-GLES2.functional.shaders.texture_functions.fragment.texture2d_bias,Fail +dEQP-GLES2.functional.shaders.texture_functions.fragment.texture2dproj_vec3_bias,Fail dEQP-GLES2.functional.shaders.texture_functions.fragment.texture2dproj_vec4_bias,Fail dEQP-GLES2.functional.texture.filtering.2d.linear_mipmap_linear_linear_clamp_rgba8888,Fail dEQP-GLES2.functional.texture.filtering.2d.linear_mipmap_linear_linear_mirror_rgba8888,Fail diff --git a/src/gallium/drivers/lima/ir/lima_ir.h b/src/gallium/drivers/lima/ir/lima_ir.h index 41d363a5550..573c745c026 100644 --- a/src/gallium/drivers/lima/ir/lima_ir.h +++ b/src/gallium/drivers/lima/ir/lima_ir.h @@ -73,4 +73,6 @@ void lima_nir_duplicate_load_consts(nir_shader *shader); void lima_nir_duplicate_load_inputs(nir_shader *shader); void lima_nir_duplicate_load_uniforms(nir_shader *shader); +bool lima_nir_lower_txp(nir_shader *shader); + #endif diff --git a/src/gallium/drivers/lima/ir/lima_nir_lower_txp.c b/src/gallium/drivers/lima/ir/lima_nir_lower_txp.c new file mode 100644 index 00000000000..b0109074bba --- /dev/null +++ b/src/gallium/drivers/lima/ir/lima_nir_lower_txp.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2021 Lima Project + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "nir.h" +#include "nir_builder.h" +#include "lima_ir.h" + +static nir_ssa_def * +get_proj_index(nir_instr *coord_instr, nir_instr *proj_instr, + int coord_components, int *proj_idx) +{ + *proj_idx = -1; + if (coord_instr->type != nir_instr_type_alu || + proj_instr->type != nir_instr_type_alu) + return NULL; + + nir_alu_instr *coord_alu = nir_instr_as_alu(coord_instr); + nir_alu_instr *proj_alu = nir_instr_as_alu(proj_instr); + + if (coord_alu->op != nir_op_mov || + proj_alu->op != nir_op_mov) + return NULL; + + if (!coord_alu->dest.dest.is_ssa || + !proj_alu->dest.dest.is_ssa) + return NULL; + + if (!coord_alu->src[0].src.is_ssa || + !proj_alu->src[0].src.is_ssa) + return NULL; + + nir_ssa_def *coord_src_ssa = coord_alu->src[0].src.ssa; + nir_ssa_def *proj_src_ssa = proj_alu->src[0].src.ssa; + + if (coord_src_ssa != proj_src_ssa) + return NULL; + + if (coord_src_ssa->parent_instr->type != nir_instr_type_intrinsic) + return NULL; + + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(coord_src_ssa->parent_instr); + if (intrin->intrinsic != nir_intrinsic_load_input) + return NULL; + + if (nir_dest_num_components(intrin->dest) != 4) + return NULL; + + /* Coords must be in .xyz */ + for (int i = 0; i < coord_components; i++) { + if (coord_alu->src[0].swizzle[i] != i) + return NULL; + } + + *proj_idx = proj_alu->src[0].swizzle[0]; + + return coord_src_ssa; +} + +static bool +lima_nir_lower_txp_instr(nir_builder *b, nir_instr *instr, + UNUSED void *cb_data) +{ + if (instr->type != nir_instr_type_tex) + return false; + + nir_tex_instr *tex = nir_instr_as_tex(instr); + + int proj_idx = nir_tex_instr_src_index(tex, nir_tex_src_projector); + int coords_idx = nir_tex_instr_src_index(tex, nir_tex_src_coord); + + if (proj_idx < 0) + return false; + + switch (tex->sampler_dim) { + case GLSL_SAMPLER_DIM_RECT: + case GLSL_SAMPLER_DIM_1D: + case GLSL_SAMPLER_DIM_2D: + case GLSL_SAMPLER_DIM_3D: + break; + default: + return false; + } + + b->cursor = nir_before_instr(&tex->instr); + + /* Merge coords and projector into single backend-specific source. + * It's easy if texture2DProj argument is vec3, it's more tricky with + * vec4 since NIR just drops Z component that we need, so we have to + * step back and use load_input SSA instead of mov as a source for + * newly constructed vec4 + */ + nir_ssa_def *proj_ssa = nir_ssa_for_src(b, tex->src[proj_idx].src, 1); + nir_ssa_def *coords_ssa = nir_ssa_for_src(b, tex->src[coords_idx].src, + nir_tex_instr_src_size(tex, coords_idx)); + + int proj_idx_in_vec = -1; + nir_ssa_def *load_input = get_proj_index(coords_ssa->parent_instr, + proj_ssa->parent_instr, + tex->coord_components, + &proj_idx_in_vec); + nir_ssa_def *combined; + if (load_input && proj_idx_in_vec == 3) { + unsigned xyzw[] = { 0, 1, 2, 3 }; + combined = nir_swizzle(b, load_input, xyzw, 4); + tex->coord_components = 4; + } else if (load_input && proj_idx_in_vec == 2) { + unsigned xyz[] = { 0, 1, 2 }; + combined = nir_swizzle(b, load_input, xyz, 3); + tex->coord_components = 3; + } else { + switch (tex->coord_components) { + default: + case 1: + /* We still need vec3 for 1D textures, so duplicate coordinate */ + combined = nir_vec3(b, + nir_channel(b, coords_ssa, 0), + nir_channel(b, coords_ssa, 0), + nir_channel(b, proj_ssa, 0)); + tex->coord_components = 3; + break; + case 2: + combined = nir_vec3(b, + nir_channel(b, coords_ssa, 0), + nir_channel(b, coords_ssa, 1), + nir_channel(b, proj_ssa, 0)); + tex->coord_components = 3; + break; + case 3: + combined = nir_vec4(b, + nir_channel(b, coords_ssa, 0), + nir_channel(b, coords_ssa, 1), + nir_channel(b, coords_ssa, 2), + nir_channel(b, proj_ssa, 0)); + tex->coord_components = 4; + } + } + + nir_tex_instr_remove_src(tex, nir_tex_instr_src_index(tex, nir_tex_src_coord)); + nir_tex_instr_remove_src(tex, nir_tex_instr_src_index(tex, nir_tex_src_projector)); + nir_tex_instr_add_src(tex, nir_tex_src_backend1, nir_src_for_ssa(combined)); + + return true; +} + +bool +lima_nir_lower_txp(nir_shader *shader) +{ + return nir_shader_instructions_pass(shader, lima_nir_lower_txp_instr, + nir_metadata_block_index | + nir_metadata_dominance, + NULL); +} diff --git a/src/gallium/drivers/lima/ir/pp/codegen.c b/src/gallium/drivers/lima/ir/pp/codegen.c index 63ac9c0935d..8c39c688148 100644 --- a/src/gallium/drivers/lima/ir/pp/codegen.c +++ b/src/gallium/drivers/lima/ir/pp/codegen.c @@ -91,8 +91,25 @@ static void ppir_codegen_encode_varying(ppir_node *node, void *code) f->imm.perspective = 1; break; case ppir_op_load_coords: - /* num_components == 3 implies cubemap as we don't support 3D textures */ - f->imm.source_type = num_components == 3 ? 2 : 0; + /* num_components == 3 and no perspective implies cubemap + * as we don't support 3D textures */ + if (num_components == 3 && + load->perspective == ppir_perspective_none) + f->imm.source_type = 2; + else + f->imm.source_type = 0; + + switch (load->perspective) { + case ppir_perspective_none: + f->imm.perspective = 0; + break; + case ppir_perspective_z: + f->imm.perspective = 2; + break; + case ppir_perspective_w: + f->imm.perspective = 3; + break; + } break; default: break; @@ -103,12 +120,25 @@ static void ppir_codegen_encode_varying(ppir_node *node, void *code) f->reg.mask = dest->write_mask << (index & 0x3); if (load->num_src) { - /* num_components == 3 implies cubemap as we don't support 3D textures */ - if (num_components == 3) { + /* num_components == 3 and no perspective implies cubemap + * as we don't support 3D textures */ + if (num_components == 3 && + load->perspective == ppir_perspective_none) { f->reg.source_type = 2; f->reg.perspective = 1; } else { f->reg.source_type = 1; + switch (load->perspective) { + case ppir_perspective_none: + f->reg.perspective = 0; + break; + case ppir_perspective_z: + f->reg.perspective = 2; + break; + case ppir_perspective_w: + f->reg.perspective = 3; + break; + } } ppir_src *src = &load->src; index = ppir_target_get_src_reg_index(src); diff --git a/src/gallium/drivers/lima/ir/pp/nir.c b/src/gallium/drivers/lima/ir/pp/nir.c index 5d2d2282233..14f848d175d 100644 --- a/src/gallium/drivers/lima/ir/pp/nir.c +++ b/src/gallium/drivers/lima/ir/pp/nir.c @@ -473,8 +473,13 @@ static bool ppir_emit_tex(ppir_block *block, nir_instr *ni) for (int i = 0; i < instr->coord_components; i++) node->src[0].swizzle[i] = i; + bool perspective = false; + for (int i = 0; i < instr->num_srcs; i++) { switch (instr->src[i].src_type) { + case nir_tex_src_backend1: + perspective = true; + FALLTHROUGH; case nir_tex_src_coord: { nir_src *ns = &instr->src[i].src; if (ns->is_ssa) { @@ -482,7 +487,8 @@ static bool ppir_emit_tex(ppir_block *block, nir_instr *ni) if (child->op == ppir_op_load_varying) { /* If the successor is load_texture, promote it to load_coords */ nir_tex_src *nts = (nir_tex_src *)ns; - if (nts->src_type == nir_tex_src_coord) + if (nts->src_type == nir_tex_src_coord || + nts->src_type == nir_tex_src_backend1) child->op = ppir_op_load_coords; } } @@ -543,6 +549,14 @@ static bool ppir_emit_tex(ppir_block *block, nir_instr *ni) } assert(load); + + if (perspective) { + if (instr->coord_components == 3) + load->perspective = ppir_perspective_z; + else + load->perspective = ppir_perspective_w; + } + node->src[0].type = load->dest.type = ppir_target_pipeline; node->src[0].pipeline = load->dest.pipeline = ppir_pipeline_reg_discard; diff --git a/src/gallium/drivers/lima/ir/pp/ppir.h b/src/gallium/drivers/lima/ir/pp/ppir.h index 480fca9e689..62ffb0fc2d9 100644 --- a/src/gallium/drivers/lima/ir/pp/ppir.h +++ b/src/gallium/drivers/lima/ir/pp/ppir.h @@ -252,6 +252,12 @@ typedef struct { ppir_dest dest; } ppir_const_node; +typedef enum { + ppir_perspective_none = 0, + ppir_perspective_z, + ppir_perspective_w, +} ppir_perspective; + typedef struct { ppir_node node; int index; @@ -259,6 +265,7 @@ typedef struct { ppir_dest dest; ppir_src src; int num_src; + ppir_perspective perspective; } ppir_load_node; typedef struct { diff --git a/src/gallium/drivers/lima/lima_program.c b/src/gallium/drivers/lima/lima_program.c index a4d9b8a0ef9..a07c7251bef 100644 --- a/src/gallium/drivers/lima/lima_program.c +++ b/src/gallium/drivers/lima/lima_program.c @@ -216,6 +216,7 @@ lima_program_optimize_fs_nir(struct nir_shader *s, nir_var_shader_in | nir_var_shader_out, type_size, 0); NIR_PASS_V(s, nir_lower_regs_to_ssa); NIR_PASS_V(s, nir_lower_tex, tex_options); + NIR_PASS_V(s, lima_nir_lower_txp); do { progress = false; @@ -283,7 +284,6 @@ lima_fs_compile_shader(struct lima_context *ctx, nir_shader *nir = nir_shader_clone(fs, ufs->base.ir.nir); struct nir_lower_tex_options tex_options = { - .lower_txp = ~0u, .swizzle_result = ~0u, }; diff --git a/src/gallium/drivers/lima/meson.build b/src/gallium/drivers/lima/meson.build index 5bc6fbbf869..c7b9a8b099b 100644 --- a/src/gallium/drivers/lima/meson.build +++ b/src/gallium/drivers/lima/meson.build @@ -51,6 +51,7 @@ files_lima = files( 'ir/lima_nir_lower_uniform_to_scalar.c', 'ir/lima_nir_split_load_input.c', 'ir/lima_nir_split_loads.c', + 'ir/lima_nir_lower_txp.c', 'ir/lima_ir.h',