• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © Microsoft Corporation
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  * on the rights to use, copy, modify, merge, publish, distribute, sub
8  * license, and/or sell copies of the Software, and to permit persons to whom
9  * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21  * USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include "d3d12_nir_passes.h"
25 
26 #include "nir_builder.h"
27 #include "nir_builtin_builder.h"
28 
29 static bool
lower_int_cubmap_to_array_filter(const nir_instr * instr,UNUSED const void * _options)30 lower_int_cubmap_to_array_filter(const nir_instr *instr,
31                                  UNUSED const void *_options)
32 {
33    if (instr->type != nir_instr_type_tex)
34       return false;
35 
36    nir_tex_instr *tex = nir_instr_as_tex(instr);
37 
38    if (tex->sampler_dim != GLSL_SAMPLER_DIM_CUBE)
39       return false;
40 
41    switch (tex->op) {
42    case nir_texop_tex:
43    case nir_texop_txb:
44    case nir_texop_txd:
45    case nir_texop_txl:
46    case nir_texop_txs:
47    case nir_texop_lod:
48       break;
49    default:
50       return false;
51    }
52 
53    int sampler_deref = nir_tex_instr_src_index(tex, nir_tex_src_sampler_deref);
54    assert(sampler_deref >= 0);
55    nir_deref_instr *deref = nir_instr_as_deref(tex->src[sampler_deref].src.ssa->parent_instr);
56    nir_variable *cube = nir_deref_instr_get_variable(deref);
57    return glsl_base_type_is_integer(glsl_get_sampler_result_type(cube->type));
58 }
59 
60 typedef struct {
61    nir_ssa_def *rx;
62    nir_ssa_def *ry;
63    nir_ssa_def *rz;
64    nir_ssa_def *arx;
65    nir_ssa_def *ary;
66    nir_ssa_def *arz;
67 } coord_t;
68 
69 
70 /* This is taken from from sp_tex_sample:convert_cube */
71 static nir_ssa_def *
evaluate_face_x(nir_builder * b,coord_t * coord)72 evaluate_face_x(nir_builder *b, coord_t *coord)
73 {
74    nir_ssa_def *sign = nir_fsign(b, coord->rx);
75    nir_ssa_def *positive = nir_fge(b, coord->rx, nir_imm_float(b, 0.0));
76    nir_ssa_def *ima = nir_fdiv(b, nir_imm_float(b, -0.5), coord->arx);
77 
78    nir_ssa_def *x = nir_fadd(b, nir_fmul(b, nir_fmul(b, sign, ima), coord->rz), nir_imm_float(b, 0.5));
79    nir_ssa_def *y = nir_fadd(b, nir_fmul(b, ima, coord->ry), nir_imm_float(b, 0.5));
80    nir_ssa_def *face = nir_bcsel(b, positive, nir_imm_float(b, 0.0), nir_imm_float(b, 1.0));
81 
82    return nir_vec3(b, x,y, face);
83 }
84 
85 static nir_ssa_def *
evaluate_face_y(nir_builder * b,coord_t * coord)86 evaluate_face_y(nir_builder *b, coord_t *coord)
87 {
88    nir_ssa_def *sign = nir_fsign(b, coord->ry);
89    nir_ssa_def *positive = nir_fge(b, coord->ry, nir_imm_float(b, 0.0));
90    nir_ssa_def *ima = nir_fdiv(b, nir_imm_float(b, 0.5), coord->ary);
91 
92    nir_ssa_def *x = nir_fadd(b, nir_fmul(b, ima, coord->rx), nir_imm_float(b, 0.5));
93    nir_ssa_def *y = nir_fadd(b, nir_fmul(b, nir_fmul(b, sign, ima), coord->rz), nir_imm_float(b, 0.5));
94    nir_ssa_def *face = nir_bcsel(b, positive, nir_imm_float(b, 2.0), nir_imm_float(b, 3.0));
95 
96    return nir_vec3(b, x,y, face);
97 }
98 
99 static nir_ssa_def *
evaluate_face_z(nir_builder * b,coord_t * coord)100 evaluate_face_z(nir_builder *b, coord_t *coord)
101 {
102    nir_ssa_def *sign = nir_fsign(b, coord->rz);
103    nir_ssa_def *positive = nir_fge(b, coord->rz, nir_imm_float(b, 0.0));
104    nir_ssa_def *ima = nir_fdiv(b, nir_imm_float(b, -0.5), coord->arz);
105 
106    nir_ssa_def *x = nir_fadd(b, nir_fmul(b, nir_fmul(b, sign, ima), nir_fneg(b, coord->rx)), nir_imm_float(b, 0.5));
107    nir_ssa_def *y = nir_fadd(b, nir_fmul(b, ima, coord->ry), nir_imm_float(b, 0.5));
108    nir_ssa_def *face = nir_bcsel(b, positive, nir_imm_float(b, 4.0), nir_imm_float(b, 5.0));
109 
110    return nir_vec3(b, x,y, face);
111 }
112 
113 static nir_ssa_def *
create_array_tex_from_cube_tex(nir_builder * b,nir_tex_instr * tex,nir_ssa_def * coord)114 create_array_tex_from_cube_tex(nir_builder *b, nir_tex_instr *tex, nir_ssa_def *coord)
115 {
116    nir_tex_instr *array_tex;
117 
118    array_tex = nir_tex_instr_create(b->shader, tex->num_srcs);
119    array_tex->op = tex->op;
120    array_tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
121    array_tex->is_array = true;
122    array_tex->is_shadow = tex->is_shadow;
123    array_tex->is_new_style_shadow = tex->is_new_style_shadow;
124    array_tex->texture_index = tex->texture_index;
125    array_tex->sampler_index = tex->sampler_index;
126    array_tex->dest_type = tex->dest_type;
127    array_tex->coord_components = 3;
128 
129    nir_src coord_src = nir_src_for_ssa(coord);
130    for (unsigned i = 0; i < tex->num_srcs; i++) {
131       nir_src *psrc = (tex->src[i].src_type == nir_tex_src_coord) ?
132                          &coord_src : &tex->src[i].src;
133 
134       nir_src_copy(&array_tex->src[i].src, psrc);
135       array_tex->src[i].src_type = tex->src[i].src_type;
136    }
137 
138    nir_ssa_dest_init(&array_tex->instr, &array_tex->dest,
139                      nir_tex_instr_dest_size(array_tex), 32, NULL);
140    nir_builder_instr_insert(b, &array_tex->instr);
141    return &array_tex->dest.ssa;
142 }
143 
144 static nir_ssa_def *
lower_cube_sample(nir_builder * b,nir_tex_instr * tex)145 lower_cube_sample(nir_builder *b, nir_tex_instr *tex)
146 {
147    /* We don't support cube map arrays yet */
148    assert(!tex->is_array);
149 
150    int coord_index = nir_tex_instr_src_index(tex, nir_tex_src_coord);
151    assert(coord_index >= 0);
152 
153    /* Evaluate the face and the xy coordinates for a 2D tex op */
154    nir_ssa_def *coord = tex->src[coord_index].src.ssa;
155 
156    coord_t coords;
157    coords.rx = nir_channel(b, coord, 0);
158    coords.ry = nir_channel(b, coord, 1);
159    coords.rz = nir_channel(b, coord, 2);
160    coords.arx = nir_fabs(b, coords.rx);
161    coords.ary = nir_fabs(b, coords.ry);
162    coords.arz = nir_fabs(b, coords.rz);
163 
164    nir_ssa_def *use_face_x = nir_iand(b,
165                                       nir_fge(b, coords.arx, coords.ary),
166                                       nir_fge(b, coords.arx, coords.arz));
167 
168    nir_if *use_face_x_if = nir_push_if(b, use_face_x);
169    nir_ssa_def *face_x_coord = evaluate_face_x(b, &coords);
170    nir_if *use_face_x_else = nir_push_else(b, use_face_x_if);
171 
172    nir_ssa_def *use_face_y = nir_iand(b,
173                                       nir_fge(b, coords.ary, coords.arx),
174                                       nir_fge(b, coords.ary, coords.arz));
175 
176    nir_if *use_face_y_if = nir_push_if(b, use_face_y);
177    nir_ssa_def *face_y_coord = evaluate_face_y(b, &coords);
178    nir_if *use_face_y_else = nir_push_else(b, use_face_y_if);
179 
180    nir_ssa_def *face_z_coord = evaluate_face_z(b, &coords);
181 
182    nir_pop_if(b, use_face_y_else);
183    nir_ssa_def *face_y_or_z_coord = nir_if_phi(b, face_y_coord, face_z_coord);
184    nir_pop_if(b, use_face_x_else);
185 
186    // This contains in xy the normalized sample coordinates, and in z the face index
187    nir_ssa_def *coord_and_face = nir_if_phi(b, face_x_coord, face_y_or_z_coord);
188 
189    return create_array_tex_from_cube_tex(b, tex, coord_and_face);
190 }
191 
192 /* We don't expect the array size here */
193 static nir_ssa_def *
lower_cube_txs(nir_builder * b,nir_tex_instr * tex)194 lower_cube_txs(nir_builder *b, nir_tex_instr *tex)
195 {
196    b->cursor = nir_after_instr(&tex->instr);
197    return nir_channels(b, &tex->dest.ssa, 3);
198 }
199 
200 static const struct glsl_type *
make_2darray_from_cubemap(const struct glsl_type * type)201 make_2darray_from_cubemap(const struct glsl_type *type)
202 {
203    return  glsl_get_sampler_dim(type) == GLSL_SAMPLER_DIM_CUBE ?
204             glsl_sampler_type(
205                GLSL_SAMPLER_DIM_2D,
206                false, true,
207                glsl_get_sampler_result_type(type)) : type;
208 }
209 
210 static const struct glsl_type *
make_2darray_from_cubemap_with_array(const struct glsl_type * type)211 make_2darray_from_cubemap_with_array(const struct glsl_type *type)
212 {
213    /* While we don't (yet) support cube map arrays, there still may be arrays
214     * of cube maps */
215    if (glsl_type_is_array(type)) {
216       const struct glsl_type *new_type = glsl_without_array(type);
217       return new_type != type ? glsl_array_type(make_2darray_from_cubemap(glsl_without_array(type)),
218                                                 glsl_get_length(type), 0) : type;
219    } else
220       return make_2darray_from_cubemap(type);
221 }
222 
223 static nir_ssa_def *
lower_int_cubmap_to_array_impl(nir_builder * b,nir_instr * instr,UNUSED void * _options)224 lower_int_cubmap_to_array_impl(nir_builder *b, nir_instr *instr,
225                                UNUSED void *_options)
226 {
227    nir_tex_instr *tex = nir_instr_as_tex(instr);
228 
229    int sampler_index = nir_tex_instr_src_index(tex, nir_tex_src_sampler_deref);
230    assert(sampler_index >= 0);
231 
232    nir_deref_instr *sampler_deref = nir_instr_as_deref(tex->src[sampler_index].src.ssa->parent_instr);
233    nir_variable *sampler = nir_deref_instr_get_variable(sampler_deref);
234 
235    sampler->type = make_2darray_from_cubemap_with_array(sampler->type);
236    sampler_deref->type = sampler->type;
237 
238    switch (tex->op) {
239    case nir_texop_tex:
240    case nir_texop_txb:
241    case nir_texop_txd:
242    case nir_texop_txl:
243    case nir_texop_lod:
244       return lower_cube_sample(b, tex);
245    case nir_texop_txs:
246       return lower_cube_txs(b, tex);
247    default:
248       unreachable("Unsupported cupe map texture operation");
249    }
250 }
251 
252 bool
d3d12_lower_int_cubmap_to_array(nir_shader * s)253 d3d12_lower_int_cubmap_to_array(nir_shader *s)
254 {
255    bool result =
256          nir_shader_lower_instructions(s,
257                                        lower_int_cubmap_to_array_filter,
258                                        lower_int_cubmap_to_array_impl,
259                                        NULL);
260 
261    if (result) {
262       nir_foreach_variable_with_modes_safe(var, s, nir_var_uniform) {
263          if (glsl_type_is_sampler(var->type)) {
264             if (glsl_get_sampler_dim(var->type) == GLSL_SAMPLER_DIM_CUBE &&
265                 (glsl_base_type_is_integer(glsl_get_sampler_result_type(var->type)))) {
266                var->type = make_2darray_from_cubemap_with_array(var->type);
267             }
268          }
269       }
270    }
271    return result;
272 
273 }
274