• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mesa-c++  -*-
2  * Copyright 2021 Collabora LTD
3  * Author: Gert Wollny <gert.wollny@collabora.com>
4  * SPDX-License-Identifier: MIT
5  */
6 
7 #include "nir.h"
8 #include "nir_builder.h"
9 #include "nir_intrinsics.h"
10 #include "nir_intrinsics_indices.h"
11 #include "sfn_nir.h"
12 
13 static nir_def *
r600_legalize_image_load_store_impl(nir_builder * b,nir_instr * instr,UNUSED void * _options)14 r600_legalize_image_load_store_impl(nir_builder *b,
15                                     nir_instr *instr,
16                                     UNUSED void *_options)
17 {
18    b->cursor = nir_before_instr(instr);
19    auto ir = nir_instr_as_intrinsic(instr);
20 
21    nir_def *default_value = nir_imm_vec4(b, 0.0, 0.0, 0.0, 0.0);
22 
23    nir_def *result = NIR_LOWER_INSTR_PROGRESS_REPLACE;
24 
25    bool load_value = ir->intrinsic != nir_intrinsic_image_store;
26 
27    if (load_value)
28       default_value =
29          nir_imm_zero(b, ir->def.num_components, ir->def.bit_size);
30 
31    auto image_exists =
32       nir_ult_imm(b, ir->src[0].ssa, b->shader->info.num_images);
33 
34    nir_if *if_exists = nir_push_if(b, image_exists);
35 
36    nir_if *load_if = nullptr;
37 
38    if (ir->intrinsic != nir_intrinsic_image_size) {
39 
40       /*  Image exists start */
41       auto new_index =
42          nir_umin(b,
43                   ir->src[0].ssa,
44                   nir_imm_int(b, b->shader->info.num_images - 1));
45       nir_src_rewrite(&ir->src[0], new_index);
46 
47       enum glsl_sampler_dim dim = nir_intrinsic_image_dim(ir);
48 
49       unsigned num_components = 2;
50       switch (dim) {
51       case GLSL_SAMPLER_DIM_BUF:
52       case GLSL_SAMPLER_DIM_1D:
53          num_components = 1;
54          break;
55       case GLSL_SAMPLER_DIM_2D:
56       case GLSL_SAMPLER_DIM_MS:
57       case GLSL_SAMPLER_DIM_RECT:
58       case GLSL_SAMPLER_DIM_CUBE:
59          num_components = 2;
60          break;
61       case GLSL_SAMPLER_DIM_3D:
62          num_components = 3;
63          break;
64       default:
65          unreachable("Unexpected image size");
66       }
67 
68       if (num_components < 3 && nir_intrinsic_image_array(ir))
69          num_components++;
70 
71       auto img_size = nir_image_size(b,
72                                      num_components,
73                                      32,
74                                      ir->src[0].ssa,
75                                      nir_imm_int(b, 0),
76                                      dim,
77                                      nir_intrinsic_image_array(ir),
78                                      nir_intrinsic_format(ir),
79                                      nir_intrinsic_access(ir),
80                                      nir_intrinsic_range_base(ir));
81 
82       unsigned mask = (1 << num_components) - 1;
83       unsigned num_src1_comp = MIN2(ir->src[1].ssa->num_components, num_components);
84       unsigned src1_mask = (1 << num_src1_comp) - 1;
85 
86       if (num_components == 3 && dim == GLSL_SAMPLER_DIM_CUBE) {
87          img_size = nir_vec3(b,
88                              nir_channel(b, img_size, 0),
89                              nir_channel(b, img_size, 1),
90                              nir_imul_imm(b, nir_channel(b, img_size, 2), 6));
91       }
92 
93       auto in_range = nir_ult(b,
94                               nir_channels(b, ir->src[1].ssa, src1_mask),
95                               nir_channels(b, img_size, mask));
96 
97       switch (num_components) {
98       case 2:
99          in_range = nir_iand(b, nir_channel(b, in_range, 0), nir_channel(b, in_range, 1));
100          break;
101       case 3: {
102          auto tmp = nir_iand(b, nir_channel(b, in_range, 0), nir_channel(b, in_range, 1));
103          in_range = nir_iand(b, tmp, nir_channel(b, in_range, 2));
104          break;
105       }
106       }
107 
108       /*  Access is in range start */
109       load_if = nir_push_if(b, in_range);
110    }
111 
112    auto new_load = nir_instr_clone(b->shader, instr);
113    auto new_load_ir = nir_instr_as_intrinsic(new_load);
114 
115    nir_builder_instr_insert(b, new_load);
116 
117    if (load_value)
118       result = &new_load_ir->def;
119 
120    if (ir->intrinsic != nir_intrinsic_image_size) {
121       /*  Access is out of range start */
122       nir_if *load_else = nir_push_else(b, load_if);
123 
124       nir_pop_if(b, load_else);
125       /* End range check */
126 
127       if (load_value)
128          result = nir_if_phi(b, result, default_value);
129    }
130 
131    /* Start image doesn't exists */
132    nir_if *else_exists = nir_push_else(b, if_exists);
133 
134    /* Nothing to do, default is already set */
135    nir_pop_if(b, else_exists);
136 
137    if (load_value)
138       result = nir_if_phi(b, result, default_value);
139 
140    if (load_value)
141       b->cursor = nir_after_instr(result->parent_instr);
142    else
143       b->cursor = nir_after_cf_node(&else_exists->cf_node);
144 
145    return result;
146 }
147 
148 static bool
r600_legalize_image_load_store_filter(const nir_instr * instr,UNUSED const void * _options)149 r600_legalize_image_load_store_filter(const nir_instr *instr, UNUSED const void *_options)
150 {
151    if (instr->type != nir_instr_type_intrinsic)
152       return false;
153 
154    auto ir = nir_instr_as_intrinsic(instr);
155    switch (ir->intrinsic) {
156    case nir_intrinsic_image_store:
157    case nir_intrinsic_image_load:
158    case nir_intrinsic_image_atomic:
159    case nir_intrinsic_image_atomic_swap:
160    case nir_intrinsic_image_size:
161       return true;
162    default:
163       return false;
164    }
165 }
166 
167 /* This pass makes sure only existing images are accessd and
168  * the access is within range, if not zero is returned by all
169  * image ops that return a value.
170  */
171 bool
r600_legalize_image_load_store(nir_shader * shader)172 r600_legalize_image_load_store(nir_shader *shader)
173 {
174    bool progress = nir_shader_lower_instructions(shader,
175                                         r600_legalize_image_load_store_filter,
176                                         r600_legalize_image_load_store_impl,
177                                         nullptr);
178    return progress;
179 };
180