• 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 "dxil_nir_lower_int_cubemaps.h"
25 
26 #include "nir_builder.h"
27 #include "nir_builtin_builder.h"
28 
29 static bool
type_needs_lowering(const struct glsl_type * type)30 type_needs_lowering(const struct glsl_type *type)
31 {
32    type = glsl_without_array(type);
33    if (!glsl_type_is_image(type) && !glsl_type_is_sampler(type))
34       return false;
35    if (glsl_get_sampler_dim(type) != GLSL_SAMPLER_DIM_CUBE)
36       return false;
37    if (glsl_type_is_image(type))
38       return true;
39    return glsl_base_type_is_integer(glsl_get_sampler_result_type(type));
40 }
41 
42 static bool
lower_int_cubmap_to_array_filter(const nir_instr * instr,const void * options)43 lower_int_cubmap_to_array_filter(const nir_instr *instr,
44                                  const void *options)
45 {
46    bool lower_samplers = *(bool *)options;
47    if (instr->type == nir_instr_type_intrinsic) {
48       nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
49       switch (intr->intrinsic) {
50       case nir_intrinsic_image_atomic_add:
51       case nir_intrinsic_image_atomic_and:
52       case nir_intrinsic_image_atomic_comp_swap:
53       case nir_intrinsic_image_atomic_dec_wrap:
54       case nir_intrinsic_image_atomic_exchange:
55       case nir_intrinsic_image_atomic_fadd:
56       case nir_intrinsic_image_atomic_fmax:
57       case nir_intrinsic_image_atomic_fmin:
58       case nir_intrinsic_image_atomic_imax:
59       case nir_intrinsic_image_atomic_imin:
60       case nir_intrinsic_image_atomic_inc_wrap:
61       case nir_intrinsic_image_atomic_or:
62       case nir_intrinsic_image_atomic_umax:
63       case nir_intrinsic_image_atomic_umin:
64       case nir_intrinsic_image_atomic_xor:
65       case nir_intrinsic_image_load:
66       case nir_intrinsic_image_size:
67       case nir_intrinsic_image_store:
68       case nir_intrinsic_image_deref_atomic_add:
69       case nir_intrinsic_image_deref_atomic_and:
70       case nir_intrinsic_image_deref_atomic_comp_swap:
71       case nir_intrinsic_image_deref_atomic_dec_wrap:
72       case nir_intrinsic_image_deref_atomic_exchange:
73       case nir_intrinsic_image_deref_atomic_fadd:
74       case nir_intrinsic_image_deref_atomic_fmax:
75       case nir_intrinsic_image_deref_atomic_fmin:
76       case nir_intrinsic_image_deref_atomic_imax:
77       case nir_intrinsic_image_deref_atomic_imin:
78       case nir_intrinsic_image_deref_atomic_inc_wrap:
79       case nir_intrinsic_image_deref_atomic_or:
80       case nir_intrinsic_image_deref_atomic_umax:
81       case nir_intrinsic_image_deref_atomic_umin:
82       case nir_intrinsic_image_deref_atomic_xor:
83       case nir_intrinsic_image_deref_load:
84       case nir_intrinsic_image_deref_size:
85       case nir_intrinsic_image_deref_store:
86          return nir_intrinsic_image_dim(intr) == GLSL_SAMPLER_DIM_CUBE;
87       default:
88          return false;
89       }
90    } else if (instr->type == nir_instr_type_deref) {
91       nir_deref_instr *deref = nir_instr_as_deref(instr);
92       return type_needs_lowering(deref->type);
93    } else if (instr->type == nir_instr_type_tex && lower_samplers) {
94       nir_tex_instr *tex = nir_instr_as_tex(instr);
95 
96       if (tex->sampler_dim != GLSL_SAMPLER_DIM_CUBE)
97          return false;
98 
99       switch (tex->op) {
100       case nir_texop_tex:
101       case nir_texop_txb:
102       case nir_texop_txd:
103       case nir_texop_txl:
104       case nir_texop_txs:
105       case nir_texop_lod:
106       case nir_texop_tg4:
107          break;
108       default:
109          return false;
110       }
111 
112       int sampler_deref = nir_tex_instr_src_index(tex, nir_tex_src_sampler_deref);
113       assert(sampler_deref >= 0);
114       nir_deref_instr *deref = nir_instr_as_deref(tex->src[sampler_deref].src.ssa->parent_instr);
115       nir_variable *cube = nir_deref_instr_get_variable(deref);
116       return glsl_base_type_is_integer(glsl_get_sampler_result_type(cube->type));
117    }
118 
119    return false;
120 }
121 
122 typedef struct {
123    bool image;
124    nir_ssa_def *rx;
125    nir_ssa_def *ry;
126    nir_ssa_def *rz;
127    nir_ssa_def *arx;
128    nir_ssa_def *ary;
129    nir_ssa_def *arz;
130    nir_ssa_def *array;
131 } coord_t;
132 
133 
134 /* This is taken from from sp_tex_sample:convert_cube */
135 static nir_ssa_def *
evaluate_face_x(nir_builder * b,coord_t * coord)136 evaluate_face_x(nir_builder *b, coord_t *coord)
137 {
138    nir_ssa_def *sign = nir_fsign(b, coord->rx);
139    nir_ssa_def *positive = nir_fge(b, coord->rx, nir_imm_float(b, 0.0));
140    nir_ssa_def *ima = nir_fdiv(b, nir_imm_float(b, -0.5), coord->arx);
141 
142    nir_ssa_def *x = nir_fadd(b, nir_fmul(b, nir_fmul(b, sign, ima), coord->rz), nir_imm_float(b, 0.5));
143    nir_ssa_def *y = nir_fadd(b, nir_fmul(b, ima, coord->ry), nir_imm_float(b, 0.5));
144    nir_ssa_def *face = nir_bcsel(b, positive, nir_imm_float(b, 0.0), nir_imm_float(b, 1.0));
145 
146    if (coord->array)
147       face = nir_fadd(b, face, coord->array);
148 
149    return coord->image ?
150       nir_vec4(b, x,y, face, nir_ssa_undef(b, 1, 32)) :
151       nir_vec3(b, x,y, face);
152 }
153 
154 static nir_ssa_def *
evaluate_face_y(nir_builder * b,coord_t * coord)155 evaluate_face_y(nir_builder *b, coord_t *coord)
156 {
157    nir_ssa_def *sign = nir_fsign(b, coord->ry);
158    nir_ssa_def *positive = nir_fge(b, coord->ry, nir_imm_float(b, 0.0));
159    nir_ssa_def *ima = nir_fdiv(b, nir_imm_float(b, 0.5), coord->ary);
160 
161    nir_ssa_def *x = nir_fadd(b, nir_fmul(b, ima, coord->rx), nir_imm_float(b, 0.5));
162    nir_ssa_def *y = nir_fadd(b, nir_fmul(b, nir_fmul(b, sign, ima), coord->rz), nir_imm_float(b, 0.5));
163    nir_ssa_def *face = nir_bcsel(b, positive, nir_imm_float(b, 2.0), nir_imm_float(b, 3.0));
164 
165    if (coord->array)
166       face = nir_fadd(b, face, coord->array);
167 
168    return coord->image ?
169       nir_vec4(b, x,y, face, nir_ssa_undef(b, 1, 32)) :
170       nir_vec3(b, x,y, face);
171 }
172 
173 static nir_ssa_def *
evaluate_face_z(nir_builder * b,coord_t * coord)174 evaluate_face_z(nir_builder *b, coord_t *coord)
175 {
176    nir_ssa_def *sign = nir_fsign(b, coord->rz);
177    nir_ssa_def *positive = nir_fge(b, coord->rz, nir_imm_float(b, 0.0));
178    nir_ssa_def *ima = nir_fdiv(b, nir_imm_float(b, -0.5), coord->arz);
179 
180    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));
181    nir_ssa_def *y = nir_fadd(b, nir_fmul(b, ima, coord->ry), nir_imm_float(b, 0.5));
182    nir_ssa_def *face = nir_bcsel(b, positive, nir_imm_float(b, 4.0), nir_imm_float(b, 5.0));
183 
184    if (coord->array)
185       face = nir_fadd(b, face, coord->array);
186 
187    return coord->image ?
188       nir_vec4(b, x,y, face, nir_ssa_undef(b, 1, 32)) :
189       nir_vec3(b, x,y, face);
190 }
191 
192 static nir_ssa_def *
create_array_tex_from_cube_tex(nir_builder * b,nir_tex_instr * tex,nir_ssa_def * coord,nir_texop op)193 create_array_tex_from_cube_tex(nir_builder *b, nir_tex_instr *tex, nir_ssa_def *coord, nir_texop op)
194 {
195    nir_tex_instr *array_tex;
196 
197    array_tex = nir_tex_instr_create(b->shader, tex->num_srcs);
198    array_tex->op = op;
199    array_tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
200    array_tex->is_array = true;
201    array_tex->is_shadow = tex->is_shadow;
202    array_tex->is_new_style_shadow = tex->is_new_style_shadow;
203    array_tex->texture_index = tex->texture_index;
204    array_tex->sampler_index = tex->sampler_index;
205    array_tex->dest_type = tex->dest_type;
206    array_tex->coord_components = 3;
207 
208    nir_src coord_src = nir_src_for_ssa(coord);
209    for (unsigned i = 0; i < tex->num_srcs; i++) {
210       nir_src *psrc = (tex->src[i].src_type == nir_tex_src_coord) ?
211                          &coord_src : &tex->src[i].src;
212 
213       nir_src_copy(&array_tex->src[i].src, psrc);
214       array_tex->src[i].src_type = tex->src[i].src_type;
215    }
216 
217    nir_ssa_dest_init(&array_tex->instr, &array_tex->dest,
218                      nir_tex_instr_dest_size(array_tex), 32, NULL);
219    nir_builder_instr_insert(b, &array_tex->instr);
220    return &array_tex->dest.ssa;
221 }
222 
223 static nir_ssa_def *
handle_cube_edge(nir_builder * b,nir_ssa_def * x,nir_ssa_def * y,nir_ssa_def * face,nir_ssa_def * array_slice_cube_base,nir_ssa_def * tex_size)224 handle_cube_edge(nir_builder *b, nir_ssa_def *x, nir_ssa_def *y, nir_ssa_def *face, nir_ssa_def *array_slice_cube_base, nir_ssa_def *tex_size)
225 {
226    enum cube_remap
227    {
228       cube_remap_zero = 0,
229       cube_remap_x,
230       cube_remap_y,
231       cube_remap_tex_size,
232       cube_remap_tex_size_minus_x,
233       cube_remap_tex_size_minus_y,
234 
235       cube_remap_size,
236    };
237 
238    struct cube_remap_table
239    {
240       enum cube_remap remap_x;
241       enum cube_remap remap_y;
242       uint32_t        remap_face;
243    };
244 
245    static const struct cube_remap_table cube_remap_neg_x[6] =
246    {
247        {cube_remap_tex_size,         cube_remap_y,         4},
248        {cube_remap_tex_size,         cube_remap_y,         5},
249        {cube_remap_y,                cube_remap_zero,      1},
250        {cube_remap_tex_size_minus_y, cube_remap_tex_size,  1},
251        {cube_remap_tex_size,         cube_remap_y,         1},
252        {cube_remap_tex_size,         cube_remap_y,         0},
253    };
254 
255    static const struct cube_remap_table cube_remap_pos_x[6] =
256    {
257        {cube_remap_zero,             cube_remap_y,         5},
258        {cube_remap_zero,             cube_remap_y,         4},
259        {cube_remap_tex_size_minus_y, cube_remap_zero,      0},
260        {cube_remap_y,                cube_remap_tex_size,  0},
261        {cube_remap_zero,             cube_remap_y,         0},
262        {cube_remap_zero,             cube_remap_y,         1},
263    };
264 
265    static const struct cube_remap_table cube_remap_neg_y[6] =
266    {
267        {cube_remap_tex_size,         cube_remap_tex_size_minus_x, 2},
268        {cube_remap_zero,             cube_remap_x,                2},
269        {cube_remap_tex_size_minus_x, cube_remap_zero,             5},
270        {cube_remap_x,                cube_remap_tex_size,         4},
271        {cube_remap_x,                cube_remap_tex_size,         2},
272        {cube_remap_tex_size_minus_x, cube_remap_zero,             2},
273    };
274 
275    static const struct cube_remap_table cube_remap_pos_y[6] =
276    {
277        {cube_remap_tex_size,         cube_remap_x,                   3},
278        {cube_remap_zero,             cube_remap_tex_size_minus_x,    3},
279        {cube_remap_x,                cube_remap_zero,                4},
280        {cube_remap_tex_size_minus_x, cube_remap_tex_size,            5},
281        {cube_remap_x,                cube_remap_zero,                3},
282        {cube_remap_tex_size_minus_x, cube_remap_tex_size,            3},
283    };
284 
285    static const struct cube_remap_table* remap_tables[4] = {
286       cube_remap_neg_x,
287       cube_remap_pos_x,
288       cube_remap_neg_y,
289       cube_remap_pos_y
290    };
291 
292    nir_ssa_def *zero = nir_imm_int(b, 0);
293 
294    /* Doesn't matter since the texture is square */
295    tex_size = nir_channel(b, tex_size, 0);
296 
297    nir_ssa_def *x_on = nir_iand(b, nir_ige(b, x, zero), nir_ige(b, tex_size, x));
298    nir_ssa_def *y_on = nir_iand(b, nir_ige(b, y, zero), nir_ige(b, tex_size, y));
299    nir_ssa_def *one_on = nir_ixor(b, x_on, y_on);
300 
301    /* If the sample did not fall off the face in either dimension, then set output = input */
302    nir_ssa_def *x_result = x;
303    nir_ssa_def *y_result = y;
304    nir_ssa_def *face_result = face;
305 
306    /* otherwise, if the sample fell off the face in either the X or the Y direction, remap to the new face */
307    nir_ssa_def *remap_predicates[4] =
308    {
309       nir_iand(b, one_on, nir_ilt(b, x, zero)),
310       nir_iand(b, one_on, nir_ilt(b, tex_size, x)),
311       nir_iand(b, one_on, nir_ilt(b, y, zero)),
312       nir_iand(b, one_on, nir_ilt(b, tex_size, y)),
313    };
314 
315    nir_ssa_def *remap_array[cube_remap_size];
316 
317    remap_array[cube_remap_zero] = zero;
318    remap_array[cube_remap_x] = x;
319    remap_array[cube_remap_y] = y;
320    remap_array[cube_remap_tex_size] = tex_size;
321    remap_array[cube_remap_tex_size_minus_x] = nir_isub(b, tex_size, x);
322    remap_array[cube_remap_tex_size_minus_y] = nir_isub(b, tex_size, y);
323 
324    /* For each possible way the sample could have fallen off */
325    for (unsigned i = 0; i < 4; i++) {
326       const struct cube_remap_table* remap_table = remap_tables[i];
327 
328       /* For each possible original face */
329       for (unsigned j = 0; j < 6; j++) {
330          nir_ssa_def *predicate = nir_iand(b, remap_predicates[i], nir_ieq(b, face, nir_imm_int(b, j)));
331 
332          x_result = nir_bcsel(b, predicate, remap_array[remap_table[j].remap_x], x_result);
333          y_result = nir_bcsel(b, predicate, remap_array[remap_table[j].remap_y], y_result);
334          face_result = nir_bcsel(b, predicate, remap_array[remap_table[j].remap_face], face_result);
335       }
336    }
337 
338    return nir_vec3(b, x_result, y_result, nir_iadd(b, face_result, array_slice_cube_base));
339 }
340 
341 static nir_ssa_def *
handle_cube_gather(nir_builder * b,nir_tex_instr * tex,nir_ssa_def * coord)342 handle_cube_gather(nir_builder *b, nir_tex_instr *tex, nir_ssa_def *coord)
343 {
344    nir_ssa_def *tex_size = nir_get_texture_size(b, tex);
345 
346    /* nir_get_texture_size puts the cursor before the tex op */
347    b->cursor = nir_after_instr(coord->parent_instr);
348 
349    nir_ssa_def *const_05 = nir_imm_float(b, 0.5f);
350    nir_ssa_def *texel_coords = nir_fmul(b, nir_channels(b, coord, 3),
351       nir_i2f32(b, nir_channels(b, tex_size, 3)));
352 
353    nir_ssa_def *x_orig = nir_channel(b, texel_coords, 0);
354    nir_ssa_def *y_orig = nir_channel(b, texel_coords, 1);
355 
356    nir_ssa_def *x_pos = nir_f2i32(b, nir_fadd(b, x_orig, const_05));
357    nir_ssa_def *x_neg = nir_f2i32(b, nir_fsub(b, x_orig, const_05));
358    nir_ssa_def *y_pos = nir_f2i32(b, nir_fadd(b, y_orig, const_05));
359    nir_ssa_def *y_neg = nir_f2i32(b, nir_fsub(b, y_orig, const_05));
360    nir_ssa_def *coords[4][2] = {
361       { x_neg, y_pos },
362       { x_pos, y_pos },
363       { x_pos, y_neg },
364       { x_neg, y_neg },
365    };
366 
367    nir_ssa_def *array_slice_2d = nir_f2i32(b, nir_channel(b, coord, 2));
368    nir_ssa_def *face = nir_imod(b, array_slice_2d, nir_imm_int(b, 6));
369    nir_ssa_def *array_slice_cube_base = nir_isub(b, array_slice_2d, face);
370 
371    nir_ssa_def *channels[4];
372    for (unsigned i = 0; i < 4; ++i) {
373       nir_ssa_def *final_coord = handle_cube_edge(b, coords[i][0], coords[i][1], face, array_slice_cube_base, tex_size);
374       nir_ssa_def *sampled_val = create_array_tex_from_cube_tex(b, tex, final_coord, nir_texop_txf);
375       channels[i] = nir_channel(b, sampled_val, tex->component);
376    }
377 
378    return nir_vec(b, channels, 4);
379 }
380 
381 static nir_ssa_def *
lower_cube_coords(nir_builder * b,nir_ssa_def * coord,bool is_array,bool is_image)382 lower_cube_coords(nir_builder *b, nir_ssa_def *coord, bool is_array, bool is_image)
383 {
384    coord_t coords;
385    coords.image = is_image;
386    coords.rx = nir_channel(b, coord, 0);
387    coords.ry = nir_channel(b, coord, 1);
388    coords.rz = nir_channel(b, coord, 2);
389    coords.arx = nir_fabs(b, coords.rx);
390    coords.ary = nir_fabs(b, coords.ry);
391    coords.arz = nir_fabs(b, coords.rz);
392    coords.array = NULL;
393    if (is_array)
394       coords.array = nir_fmul(b, nir_channel(b, coord, 3), nir_imm_float(b, 6.0f));
395 
396    nir_ssa_def *use_face_x = nir_iand(b,
397                                       nir_fge(b, coords.arx, coords.ary),
398                                       nir_fge(b, coords.arx, coords.arz));
399 
400    nir_if *use_face_x_if = nir_push_if(b, use_face_x);
401    nir_ssa_def *face_x_coord = evaluate_face_x(b, &coords);
402    nir_if *use_face_x_else = nir_push_else(b, use_face_x_if);
403 
404    nir_ssa_def *use_face_y = nir_iand(b,
405                                       nir_fge(b, coords.ary, coords.arx),
406                                       nir_fge(b, coords.ary, coords.arz));
407 
408    nir_if *use_face_y_if = nir_push_if(b, use_face_y);
409    nir_ssa_def *face_y_coord = evaluate_face_y(b, &coords);
410    nir_if *use_face_y_else = nir_push_else(b, use_face_y_if);
411 
412    nir_ssa_def *face_z_coord = evaluate_face_z(b, &coords);
413 
414    nir_pop_if(b, use_face_y_else);
415    nir_ssa_def *face_y_or_z_coord = nir_if_phi(b, face_y_coord, face_z_coord);
416    nir_pop_if(b, use_face_x_else);
417 
418    // This contains in xy the normalized sample coordinates, and in z the face index
419    nir_ssa_def *coord_and_face = nir_if_phi(b, face_x_coord, face_y_or_z_coord);
420 
421    return coord_and_face;
422 }
423 
424 static nir_ssa_def *
lower_cube_sample(nir_builder * b,nir_tex_instr * tex)425 lower_cube_sample(nir_builder *b, nir_tex_instr *tex)
426 {
427    int coord_index = nir_tex_instr_src_index(tex, nir_tex_src_coord);
428    assert(coord_index >= 0);
429 
430    /* Evaluate the face and the xy coordinates for a 2D tex op */
431    nir_ssa_def *coord = tex->src[coord_index].src.ssa;
432    nir_ssa_def *coord_and_face = lower_cube_coords(b, coord, tex->is_array, false);
433 
434    if (tex->op == nir_texop_tg4)
435       return handle_cube_gather(b, tex, coord_and_face);
436    else
437       return create_array_tex_from_cube_tex(b, tex, coord_and_face, tex->op);
438 }
439 
440 static nir_ssa_def *
lower_cube_image_load_store_atomic(nir_builder * b,nir_intrinsic_instr * intr)441 lower_cube_image_load_store_atomic(nir_builder *b, nir_intrinsic_instr *intr)
442 {
443    b->cursor = nir_before_instr(&intr->instr);
444    nir_intrinsic_set_image_array(intr, true);
445    nir_intrinsic_set_image_dim(intr, GLSL_SAMPLER_DIM_2D);
446 
447    return NIR_LOWER_INSTR_PROGRESS;
448 }
449 
450 static nir_ssa_def *
lower_cube_txs(nir_builder * b,nir_tex_instr * tex)451 lower_cube_txs(nir_builder *b, nir_tex_instr *tex)
452 {
453    b->cursor = nir_after_instr(&tex->instr);
454    if (!tex->is_array)
455       return nir_channels(b, &tex->dest.ssa, 3);
456 
457    nir_ssa_def *array_dim = nir_channel(b, &tex->dest.ssa, 2);
458    nir_ssa_def *cube_array_dim = nir_idiv(b, array_dim, nir_imm_int(b, 6));
459    return nir_vec3(b, nir_channel(b, &tex->dest.ssa, 0),
460                       nir_channel(b, &tex->dest.ssa, 1),
461                       cube_array_dim);
462 }
463 
464 static nir_ssa_def *
lower_cube_image_size(nir_builder * b,nir_intrinsic_instr * intr)465 lower_cube_image_size(nir_builder *b, nir_intrinsic_instr *intr)
466 {
467    b->cursor = nir_after_instr(&intr->instr);
468    if (!nir_intrinsic_image_array(intr))
469       return nir_channels(b, &intr->dest.ssa, 3);
470 
471    nir_ssa_def *array_dim = nir_channel(b, &intr->dest.ssa, 2);
472    nir_ssa_def *cube_array_dim = nir_idiv(b, array_dim, nir_imm_int(b, 6));
473    return nir_vec3(b, nir_channel(b, &intr->dest.ssa, 0),
474                       nir_channel(b, &intr->dest.ssa, 1),
475                       cube_array_dim);
476 }
477 
478 static const struct glsl_type *
make_2darray_sampler_from_cubemap(const struct glsl_type * type)479 make_2darray_sampler_from_cubemap(const struct glsl_type *type)
480 {
481    return  glsl_get_sampler_dim(type) == GLSL_SAMPLER_DIM_CUBE ?
482             glsl_sampler_type(
483                GLSL_SAMPLER_DIM_2D,
484                false, true,
485                glsl_get_sampler_result_type(type)) : type;
486 }
487 
488 static const struct glsl_type *
make_2darray_image_from_cubemap(const struct glsl_type * type)489 make_2darray_image_from_cubemap(const struct glsl_type *type)
490 {
491    return  glsl_get_sampler_dim(type) == GLSL_SAMPLER_DIM_CUBE ?
492             glsl_image_type(
493                GLSL_SAMPLER_DIM_2D,
494                true,
495                glsl_get_sampler_result_type(type)) : type;
496 }
497 
498 static const struct glsl_type *
make_2darray_from_cubemap_with_array(const struct glsl_type * type,bool is_image)499 make_2darray_from_cubemap_with_array(const struct glsl_type *type, bool is_image)
500 {
501    if (glsl_type_is_array(type)) {
502       const struct glsl_type *new_type = glsl_without_array(type);
503       return new_type != type ? glsl_array_type(make_2darray_from_cubemap_with_array(glsl_without_array(type), is_image),
504                                                 glsl_get_length(type), 0) : type;
505    } else if (is_image)
506       return make_2darray_image_from_cubemap(type);
507    else
508       return make_2darray_sampler_from_cubemap(type);
509 }
510 
511 static nir_ssa_def *
lower_int_cubemap_to_array_tex(nir_builder * b,nir_tex_instr * tex)512 lower_int_cubemap_to_array_tex(nir_builder *b, nir_tex_instr *tex)
513 {
514    switch (tex->op) {
515    case nir_texop_tex:
516    case nir_texop_txb:
517    case nir_texop_txd:
518    case nir_texop_txl:
519    case nir_texop_lod:
520    case nir_texop_tg4:
521       return lower_cube_sample(b, tex);
522    case nir_texop_txs:
523       return lower_cube_txs(b, tex);
524    default:
525       unreachable("Unsupported cupe map texture operation");
526    }
527 }
528 
529 static nir_ssa_def *
lower_cube_image_intrinsic(nir_builder * b,nir_intrinsic_instr * intr)530 lower_cube_image_intrinsic(nir_builder *b, nir_intrinsic_instr *intr)
531 {
532    if (intr->intrinsic == nir_intrinsic_image_size ||
533       intr->intrinsic == nir_intrinsic_image_deref_size)
534       return lower_cube_image_size(b, intr);
535    else
536       return lower_cube_image_load_store_atomic(b, intr);
537 }
538 
539 static nir_ssa_def *
lower_cube_image_deref(nir_builder * b,nir_deref_instr * deref)540 lower_cube_image_deref(nir_builder *b, nir_deref_instr *deref)
541 {
542    deref->type = make_2darray_from_cubemap_with_array(
543       deref->type,
544       glsl_type_is_image(glsl_without_array(deref->type)));
545    return NIR_LOWER_INSTR_PROGRESS;
546 }
547 
548 static nir_ssa_def *
lower_int_cubmap_to_array_impl(nir_builder * b,nir_instr * instr,void * options)549 lower_int_cubmap_to_array_impl(nir_builder *b, nir_instr *instr,
550                                void *options)
551 {
552    bool lower_samplers = *(bool *)options;
553    if (instr->type == nir_instr_type_tex && lower_samplers)
554       return lower_int_cubemap_to_array_tex(b, nir_instr_as_tex(instr));
555    else if (instr->type == nir_instr_type_intrinsic)
556       return lower_cube_image_intrinsic(b, nir_instr_as_intrinsic(instr));
557    else if (instr->type == nir_instr_type_deref)
558       return lower_cube_image_deref(b, nir_instr_as_deref(instr));
559    return NULL;
560 }
561 
562 bool
dxil_nir_lower_int_cubemaps(nir_shader * s,bool lower_samplers)563 dxil_nir_lower_int_cubemaps(nir_shader *s, bool lower_samplers)
564 {
565    bool result =
566          nir_shader_lower_instructions(s,
567                                        lower_int_cubmap_to_array_filter,
568                                        lower_int_cubmap_to_array_impl,
569                                        &lower_samplers);
570 
571    if (result) {
572       nir_foreach_variable_with_modes_safe(var, s, nir_var_uniform | nir_var_image) {
573          if (!type_needs_lowering(var->type))
574             continue;
575          bool is_image = glsl_type_is_image(glsl_without_array(var->type));
576          var->type = make_2darray_from_cubemap_with_array(var->type, is_image);
577       }
578    }
579    return result;
580 
581 }
582