• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mesa-c++  -*-
2  *
3  * Copyright (c) 2021 Collabora LTD
4  *
5  * Author: Gert Wollny <gert.wollny@collabora.com>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * on the rights to use, copy, modify, merge, publish, distribute, sub
11  * license, and/or sell copies of the Software, and to permit persons to whom
12  * the Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the next
15  * paragraph) shall be included in all copies or substantial portions of the
16  * Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24  * USE OR OTHER DEALINGS IN THE SOFTWARE.
25  */
26 
27 
28 #include "sfn_nir.h"
29 
30 #include "nir.h"
31 #include "nir_builder.h"
32 
33 
34 static nir_ssa_def *
r600_legalize_image_load_store_impl(nir_builder * b,nir_instr * instr,UNUSED void * _options)35 r600_legalize_image_load_store_impl(nir_builder *b, nir_instr *instr,
36                                     UNUSED void *_options)
37 {
38    b->cursor = nir_before_instr(instr);
39    auto ir = nir_instr_as_intrinsic(instr);
40 
41    nir_ssa_def *default_value = nir_imm_vec4(b, 0.0, 0.0, 0.0, 0.0);
42 
43    nir_ssa_def *result = NIR_LOWER_INSTR_PROGRESS_REPLACE;
44 
45    bool load_value = ir->intrinsic != nir_intrinsic_image_store;
46 
47    if (load_value)
48       default_value = nir_imm_zero(b, nir_dest_num_components(ir->dest),
49                                    nir_dest_bit_size(ir->dest));
50 
51    auto image_exists = nir_ult(b, ir->src[0].ssa, nir_imm_int(b, b->shader->info.num_images));
52 
53    nir_if *if_exists = nir_push_if(b, image_exists);
54 
55    nir_if *load_if = nullptr;
56 
57    if (ir->intrinsic != nir_intrinsic_image_size) {
58 
59       /*  Image exists start */
60       auto new_index = nir_umin(b, ir->src[0].ssa,
61             nir_imm_int(b, b->shader->info.num_images - 1));
62       nir_instr_rewrite_src_ssa(instr, &ir->src[0], new_index);
63 
64       enum glsl_sampler_dim dim = nir_intrinsic_image_dim(ir);
65 
66       unsigned num_components = 2;
67       switch (dim) {
68       case GLSL_SAMPLER_DIM_BUF:
69       case GLSL_SAMPLER_DIM_1D:
70          num_components = 1; break;
71       case GLSL_SAMPLER_DIM_2D:
72       case GLSL_SAMPLER_DIM_RECT:
73       case GLSL_SAMPLER_DIM_CUBE:
74          num_components = 2; break;
75       case GLSL_SAMPLER_DIM_3D:
76          num_components = 3; break;
77       default:
78          unreachable("Unexpected image size");
79       }
80 
81       if (num_components < 3 && nir_intrinsic_image_array(ir))
82          num_components++;
83 
84       auto img_size = nir_image_size(b, num_components, 32, ir->src[0].ssa, nir_imm_int(b, 0),
85             dim, nir_intrinsic_image_array(ir),
86             nir_intrinsic_format(ir),
87             nir_intrinsic_access(ir));
88 
89       unsigned mask = (1 << num_components) - 1;
90       unsigned num_src1_comp = MIN2(ir->src[1].ssa->num_components, num_components);
91       unsigned src1_mask = (1 << num_src1_comp) - 1;
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: in_range = nir_iand(b, nir_channel(b, in_range, 0),  nir_channel(b, in_range, 1)); break;
99       case 3: {
100          auto tmp = nir_iand(b, nir_channel(b, in_range, 0),  nir_channel(b, in_range, 1));
101          in_range = nir_iand(b, tmp,  nir_channel(b, in_range, 2));
102          break;
103       }
104       }
105 
106       /*  Access is in range start */
107       load_if = nir_push_if(b, in_range);
108    }
109 
110    auto new_load = nir_instr_clone(b->shader, instr);
111    auto new_load_ir = nir_instr_as_intrinsic(new_load);
112 
113    nir_builder_instr_insert(b, new_load);
114 
115    if (load_value)
116       result = &new_load_ir->dest.ssa;
117 
118    if (ir->intrinsic != nir_intrinsic_image_size) {
119       /*  Access is out of range start */
120       nir_if *load_else = nir_push_else(b, load_if);
121 
122       nir_pop_if(b, load_else);
123       /* End range check */
124 
125       if (load_value)
126          result = nir_if_phi(b, result, default_value);
127    }
128 
129    /* Start image doesn't exists */
130    nir_if *else_exists = nir_push_else(b, if_exists);
131 
132    /* Nothing to do, default is already set */
133    nir_pop_if(b, else_exists);
134 
135    if (load_value)
136       result = nir_if_phi(b, result, default_value);
137 
138    if (load_value)
139       b->cursor = nir_after_instr(result->parent_instr);
140    else
141       b->cursor = nir_after_cf_node(&else_exists->cf_node);
142 
143    return result;
144 }
145 
146 static bool
r600_legalize_image_load_store_filter(const nir_instr * instr,UNUSED const void * _options)147 r600_legalize_image_load_store_filter(const nir_instr *instr,
148                                       UNUSED const void *_options)
149 {
150    if (instr->type != nir_instr_type_intrinsic)
151       return false;
152 
153    auto ir = nir_instr_as_intrinsic(instr);
154    switch (ir->intrinsic) {
155    case nir_intrinsic_image_store:
156    case nir_intrinsic_image_load:
157    case nir_intrinsic_image_atomic_add:
158    case nir_intrinsic_image_atomic_and:
159    case nir_intrinsic_image_atomic_or:
160    case nir_intrinsic_image_atomic_xor:
161    case nir_intrinsic_image_atomic_exchange:
162    case nir_intrinsic_image_atomic_comp_swap:
163    case nir_intrinsic_image_atomic_umin:
164    case nir_intrinsic_image_atomic_umax:
165    case nir_intrinsic_image_atomic_imin:
166    case nir_intrinsic_image_atomic_imax:
167    case nir_intrinsic_image_size:
168       return true;
169    default:
170       return false;
171    }
172 }
173 
174 /* This pass makes sure only existing images are accessd and
175  * the access is withing range, if not zero is returned by all
176  * image ops that return a value.
177  */
178 bool
r600_legalize_image_load_store(nir_shader * shader)179 r600_legalize_image_load_store(nir_shader *shader)
180 {
181    return nir_shader_lower_instructions(shader,
182                                         r600_legalize_image_load_store_filter,
183                                         r600_legalize_image_load_store_impl,
184                                         nullptr);
185 };
186