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