xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/lima/ir/lima_nir_lower_txp.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright (c) 2021 Lima Project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "nir.h"
25 #include "nir_builder.h"
26 #include "lima_ir.h"
27 
28 static nir_def *
get_proj_index(nir_instr * coord_instr,nir_instr * proj_instr,int coord_components,int * proj_idx)29 get_proj_index(nir_instr *coord_instr, nir_instr *proj_instr,
30                int coord_components, int *proj_idx)
31 {
32    *proj_idx = -1;
33    if (coord_instr->type != nir_instr_type_alu ||
34        proj_instr->type != nir_instr_type_alu)
35       return NULL;
36 
37    nir_alu_instr *coord_alu = nir_instr_as_alu(coord_instr);
38    nir_alu_instr *proj_alu = nir_instr_as_alu(proj_instr);
39 
40    if (coord_alu->op != nir_op_mov ||
41        proj_alu->op != nir_op_mov)
42       return NULL;
43 
44    nir_def *coord_src_ssa = coord_alu->src[0].src.ssa;
45    nir_def *proj_src_ssa = proj_alu->src[0].src.ssa;
46 
47    if (coord_src_ssa != proj_src_ssa)
48       return NULL;
49 
50    if (coord_src_ssa->parent_instr->type != nir_instr_type_intrinsic)
51       return NULL;
52 
53    nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(coord_src_ssa->parent_instr);
54    if (intrin->intrinsic != nir_intrinsic_load_input)
55       return NULL;
56 
57    if (intrin->def.num_components != 4)
58       return NULL;
59 
60    /* Coords must be in .xyz */
61    for (int i = 0; i < coord_components; i++) {
62       if (coord_alu->src[0].swizzle[i] != i)
63          return NULL;
64    }
65 
66    *proj_idx = proj_alu->src[0].swizzle[0];
67 
68    return coord_src_ssa;
69 }
70 
71 static bool
lima_nir_lower_txp_instr(nir_builder * b,nir_instr * instr,UNUSED void * cb_data)72 lima_nir_lower_txp_instr(nir_builder *b, nir_instr *instr,
73                          UNUSED void *cb_data)
74 {
75    if (instr->type != nir_instr_type_tex)
76       return false;
77 
78    nir_tex_instr *tex = nir_instr_as_tex(instr);
79 
80    int proj_idx = nir_tex_instr_src_index(tex, nir_tex_src_projector);
81    int coords_idx = nir_tex_instr_src_index(tex, nir_tex_src_coord);
82 
83    if (proj_idx < 0)
84       return false;
85 
86    switch (tex->sampler_dim) {
87    case GLSL_SAMPLER_DIM_RECT:
88    case GLSL_SAMPLER_DIM_1D:
89    case GLSL_SAMPLER_DIM_2D:
90    case GLSL_SAMPLER_DIM_3D:
91       break;
92    default:
93       return false;
94    }
95 
96    b->cursor = nir_before_instr(&tex->instr);
97 
98    /* Merge coords and projector into single backend-specific source.
99     * It's easy if texture2DProj argument is vec3, it's more tricky with
100     * vec4 since NIR just drops Z component that we need, so we have to
101     * step back and use load_input SSA instead of mov as a source for
102     * newly constructed vec4
103     */
104    nir_def *proj_ssa = tex->src[proj_idx].src.ssa;
105    nir_def *coords_ssa = tex->src[coords_idx].src.ssa;
106 
107    int proj_idx_in_vec = -1;
108    nir_def *load_input = get_proj_index(coords_ssa->parent_instr,
109                                             proj_ssa->parent_instr,
110                                             tex->coord_components,
111                                             &proj_idx_in_vec);
112    nir_def *combined;
113    if (load_input && proj_idx_in_vec == 3) {
114       unsigned xyzw[] = { 0, 1, 2, 3 };
115       combined = nir_swizzle(b, load_input, xyzw, 4);
116       tex->coord_components = 4;
117    } else if (load_input && proj_idx_in_vec == 2) {
118       unsigned xyz[] = { 0, 1, 2 };
119       combined = nir_swizzle(b, load_input, xyz, 3);
120       tex->coord_components = 3;
121    } else {
122       switch (tex->coord_components) {
123       default:
124       case 1:
125          /* We still need vec3 for 1D textures, so duplicate coordinate */
126          combined = nir_vec3(b,
127                              nir_channel(b, coords_ssa, 0),
128                              nir_channel(b, coords_ssa, 0),
129                              nir_channel(b, proj_ssa, 0));
130          tex->coord_components = 3;
131          break;
132       case 2:
133          combined = nir_vec3(b,
134                              nir_channel(b, coords_ssa, 0),
135                              nir_channel(b, coords_ssa, 1),
136                              nir_channel(b, proj_ssa, 0));
137          tex->coord_components = 3;
138          break;
139       case 3:
140          combined = nir_vec4(b,
141                              nir_channel(b, coords_ssa, 0),
142                              nir_channel(b, coords_ssa, 1),
143                              nir_channel(b, coords_ssa, 2),
144                              nir_channel(b, proj_ssa, 0));
145          tex->coord_components = 4;
146       }
147    }
148 
149    nir_tex_instr_remove_src(tex, nir_tex_instr_src_index(tex, nir_tex_src_coord));
150    nir_tex_instr_remove_src(tex, nir_tex_instr_src_index(tex, nir_tex_src_projector));
151    nir_tex_instr_add_src(tex, nir_tex_src_backend1, combined);
152 
153    return true;
154 }
155 
156 bool
lima_nir_lower_txp(nir_shader * shader)157 lima_nir_lower_txp(nir_shader *shader)
158 {
159    return nir_shader_instructions_pass(shader, lima_nir_lower_txp_instr,
160                                        nir_metadata_control_flow,
161                                        NULL);
162 }
163