• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_ssa_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    if (!coord_alu->dest.dest.is_ssa ||
45        !proj_alu->dest.dest.is_ssa)
46       return NULL;
47 
48    if (!coord_alu->src[0].src.is_ssa ||
49        !proj_alu->src[0].src.is_ssa)
50       return NULL;
51 
52    nir_ssa_def *coord_src_ssa = coord_alu->src[0].src.ssa;
53    nir_ssa_def *proj_src_ssa = proj_alu->src[0].src.ssa;
54 
55    if (coord_src_ssa != proj_src_ssa)
56       return NULL;
57 
58    if (coord_src_ssa->parent_instr->type != nir_instr_type_intrinsic)
59       return NULL;
60 
61    nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(coord_src_ssa->parent_instr);
62    if (intrin->intrinsic != nir_intrinsic_load_input)
63       return NULL;
64 
65    if (nir_dest_num_components(intrin->dest) != 4)
66       return NULL;
67 
68    /* Coords must be in .xyz */
69    for (int i = 0; i < coord_components; i++) {
70       if (coord_alu->src[0].swizzle[i] != i)
71          return NULL;
72    }
73 
74    *proj_idx = proj_alu->src[0].swizzle[0];
75 
76    return coord_src_ssa;
77 }
78 
79 static bool
lima_nir_lower_txp_instr(nir_builder * b,nir_instr * instr,UNUSED void * cb_data)80 lima_nir_lower_txp_instr(nir_builder *b, nir_instr *instr,
81                          UNUSED void *cb_data)
82 {
83    if (instr->type != nir_instr_type_tex)
84       return false;
85 
86    nir_tex_instr *tex = nir_instr_as_tex(instr);
87 
88    int proj_idx = nir_tex_instr_src_index(tex, nir_tex_src_projector);
89    int coords_idx = nir_tex_instr_src_index(tex, nir_tex_src_coord);
90 
91    if (proj_idx < 0)
92       return false;
93 
94    switch (tex->sampler_dim) {
95    case GLSL_SAMPLER_DIM_RECT:
96    case GLSL_SAMPLER_DIM_1D:
97    case GLSL_SAMPLER_DIM_2D:
98    case GLSL_SAMPLER_DIM_3D:
99       break;
100    default:
101       return false;
102    }
103 
104    b->cursor = nir_before_instr(&tex->instr);
105 
106    /* Merge coords and projector into single backend-specific source.
107     * It's easy if texture2DProj argument is vec3, it's more tricky with
108     * vec4 since NIR just drops Z component that we need, so we have to
109     * step back and use load_input SSA instead of mov as a source for
110     * newly constructed vec4
111     */
112    nir_ssa_def *proj_ssa = nir_ssa_for_src(b, tex->src[proj_idx].src, 1);
113    nir_ssa_def *coords_ssa = nir_ssa_for_src(b, tex->src[coords_idx].src,
114                                              nir_tex_instr_src_size(tex, coords_idx));
115 
116    int proj_idx_in_vec = -1;
117    nir_ssa_def *load_input = get_proj_index(coords_ssa->parent_instr,
118                                             proj_ssa->parent_instr,
119                                             tex->coord_components,
120                                             &proj_idx_in_vec);
121    nir_ssa_def *combined;
122    if (load_input && proj_idx_in_vec == 3) {
123       unsigned xyzw[] = { 0, 1, 2, 3 };
124       combined = nir_swizzle(b, load_input, xyzw, 4);
125       tex->coord_components = 4;
126    } else if (load_input && proj_idx_in_vec == 2) {
127       unsigned xyz[] = { 0, 1, 2 };
128       combined = nir_swizzle(b, load_input, xyz, 3);
129       tex->coord_components = 3;
130    } else {
131       switch (tex->coord_components) {
132       default:
133       case 1:
134          /* We still need vec3 for 1D textures, so duplicate coordinate */
135          combined = nir_vec3(b,
136                              nir_channel(b, coords_ssa, 0),
137                              nir_channel(b, coords_ssa, 0),
138                              nir_channel(b, proj_ssa, 0));
139          tex->coord_components = 3;
140          break;
141       case 2:
142          combined = nir_vec3(b,
143                              nir_channel(b, coords_ssa, 0),
144                              nir_channel(b, coords_ssa, 1),
145                              nir_channel(b, proj_ssa, 0));
146          tex->coord_components = 3;
147          break;
148       case 3:
149          combined = nir_vec4(b,
150                              nir_channel(b, coords_ssa, 0),
151                              nir_channel(b, coords_ssa, 1),
152                              nir_channel(b, coords_ssa, 2),
153                              nir_channel(b, proj_ssa, 0));
154          tex->coord_components = 4;
155       }
156    }
157 
158    nir_tex_instr_remove_src(tex, nir_tex_instr_src_index(tex, nir_tex_src_coord));
159    nir_tex_instr_remove_src(tex, nir_tex_instr_src_index(tex, nir_tex_src_projector));
160    nir_tex_instr_add_src(tex, nir_tex_src_backend1, nir_src_for_ssa(combined));
161 
162    return true;
163 }
164 
165 bool
lima_nir_lower_txp(nir_shader * shader)166 lima_nir_lower_txp(nir_shader *shader)
167 {
168    return nir_shader_instructions_pass(shader, lima_nir_lower_txp_instr,
169                                        nir_metadata_block_index |
170                                        nir_metadata_dominance,
171                                        NULL);
172 }
173