xref: /aosp_15_r20/external/mesa3d/src/compiler/nir/nir_lower_drawpixels.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2015 Red Hat
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  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #include "nir.h"
25 #include "nir_builder.h"
26 
27 /* Lower glDrawPixels().
28  *
29  * This is based on the logic in st_get_drawpix_shader() in TGSI compiler.
30  *
31  * Run before nir_lower_io.
32  */
33 
34 typedef struct {
35    const nir_lower_drawpixels_options *options;
36    nir_shader *shader;
37    nir_variable *texcoord, *texcoord_const, *scale, *bias, *tex, *pixelmap;
38 } lower_drawpixels_state;
39 
40 static nir_def *
get_texcoord(nir_builder * b,lower_drawpixels_state * state)41 get_texcoord(nir_builder *b, lower_drawpixels_state *state)
42 {
43    if (state->texcoord == NULL) {
44       state->texcoord = nir_get_variable_with_location(state->shader, nir_var_shader_in,
45                                                        VARYING_SLOT_TEX0, glsl_vec4_type());
46    }
47    return nir_load_var(b, state->texcoord);
48 }
49 
50 static nir_def *
get_scale(nir_builder * b,lower_drawpixels_state * state)51 get_scale(nir_builder *b, lower_drawpixels_state *state)
52 {
53    if (state->scale == NULL) {
54       state->scale = nir_state_variable_create(state->shader, glsl_vec4_type(), "gl_PTscale",
55                                                state->options->scale_state_tokens);
56    }
57    return nir_load_var(b, state->scale);
58 }
59 
60 static nir_def *
get_bias(nir_builder * b,lower_drawpixels_state * state)61 get_bias(nir_builder *b, lower_drawpixels_state *state)
62 {
63    if (state->bias == NULL) {
64       state->bias = nir_state_variable_create(state->shader, glsl_vec4_type(), "gl_PTbias",
65                                               state->options->bias_state_tokens);
66    }
67    return nir_load_var(b, state->bias);
68 }
69 
70 static nir_def *
get_texcoord_const(nir_builder * b,lower_drawpixels_state * state)71 get_texcoord_const(nir_builder *b, lower_drawpixels_state *state)
72 {
73    if (state->texcoord_const == NULL) {
74       state->texcoord_const = nir_state_variable_create(state->shader, glsl_vec4_type(),
75                                                         "gl_MultiTexCoord0",
76                                                         state->options->texcoord_state_tokens);
77    }
78    return nir_load_var(b, state->texcoord_const);
79 }
80 
81 static bool
lower_color(nir_builder * b,lower_drawpixels_state * state,nir_intrinsic_instr * intr)82 lower_color(nir_builder *b, lower_drawpixels_state *state, nir_intrinsic_instr *intr)
83 {
84    nir_def *texcoord;
85    nir_tex_instr *tex;
86    nir_def *def;
87 
88    b->cursor = nir_before_instr(&intr->instr);
89 
90    texcoord = get_texcoord(b, state);
91 
92    const struct glsl_type *sampler2D =
93       glsl_sampler_type(GLSL_SAMPLER_DIM_2D, false, false, GLSL_TYPE_FLOAT);
94 
95    if (!state->tex) {
96       state->tex =
97          nir_variable_create(b->shader, nir_var_uniform, sampler2D, "drawpix");
98       state->tex->data.binding = state->options->drawpix_sampler;
99       state->tex->data.explicit_binding = true;
100       state->tex->data.how_declared = nir_var_hidden;
101    }
102 
103    nir_deref_instr *tex_deref = nir_build_deref_var(b, state->tex);
104 
105    /* replace load_var(gl_Color) w/ texture sample:
106     *   TEX def, texcoord, drawpix_sampler, 2D
107     */
108    tex = nir_tex_instr_create(state->shader, 3);
109    tex->op = nir_texop_tex;
110    tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
111    tex->coord_components = 2;
112    tex->dest_type = nir_type_float32;
113    tex->src[0] = nir_tex_src_for_ssa(nir_tex_src_texture_deref,
114                                      &tex_deref->def);
115    tex->src[1] = nir_tex_src_for_ssa(nir_tex_src_sampler_deref,
116                                      &tex_deref->def);
117    tex->src[2] =
118       nir_tex_src_for_ssa(nir_tex_src_coord,
119                           nir_trim_vector(b, texcoord, tex->coord_components));
120 
121    nir_def_init(&tex->instr, &tex->def, 4, 32);
122    nir_builder_instr_insert(b, &tex->instr);
123    def = &tex->def;
124 
125    /* Apply the scale and bias. */
126    if (state->options->scale_and_bias) {
127       /* MAD def, def, scale, bias; */
128       def = nir_ffma(b, def, get_scale(b, state), get_bias(b, state));
129    }
130 
131    if (state->options->pixel_maps) {
132       if (!state->pixelmap) {
133          state->pixelmap = nir_variable_create(b->shader, nir_var_uniform,
134                                                sampler2D, "pixelmap");
135          state->pixelmap->data.binding = state->options->pixelmap_sampler;
136          state->pixelmap->data.explicit_binding = true;
137          state->pixelmap->data.how_declared = nir_var_hidden;
138       }
139 
140       nir_deref_instr *pixelmap_deref =
141          nir_build_deref_var(b, state->pixelmap);
142 
143       /* do four pixel map look-ups with two TEX instructions: */
144       nir_def *def_xy, *def_zw;
145 
146       /* TEX def.xy, def.xyyy, pixelmap_sampler, 2D; */
147       tex = nir_tex_instr_create(state->shader, 3);
148       tex->op = nir_texop_tex;
149       tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
150       tex->coord_components = 2;
151       tex->sampler_index = state->options->pixelmap_sampler;
152       tex->texture_index = state->options->pixelmap_sampler;
153       tex->dest_type = nir_type_float32;
154       tex->src[0] = nir_tex_src_for_ssa(nir_tex_src_texture_deref,
155                                         &pixelmap_deref->def);
156       tex->src[1] = nir_tex_src_for_ssa(nir_tex_src_sampler_deref,
157                                         &pixelmap_deref->def);
158       tex->src[2] = nir_tex_src_for_ssa(nir_tex_src_coord,
159                                         nir_trim_vector(b, def, 2));
160 
161       nir_def_init(&tex->instr, &tex->def, 4, 32);
162       nir_builder_instr_insert(b, &tex->instr);
163       def_xy = &tex->def;
164 
165       /* TEX def.zw, def.zwww, pixelmap_sampler, 2D; */
166       tex = nir_tex_instr_create(state->shader, 1);
167       tex->op = nir_texop_tex;
168       tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
169       tex->coord_components = 2;
170       tex->sampler_index = state->options->pixelmap_sampler;
171       tex->dest_type = nir_type_float32;
172       tex->src[0] = nir_tex_src_for_ssa(nir_tex_src_coord,
173                                         nir_channels(b, def, 0xc));
174 
175       nir_def_init(&tex->instr, &tex->def, 4, 32);
176       nir_builder_instr_insert(b, &tex->instr);
177       def_zw = &tex->def;
178 
179       /* def = vec4(def.xy, def.zw); */
180       def = nir_vec4(b,
181                      nir_channel(b, def_xy, 0),
182                      nir_channel(b, def_xy, 1),
183                      nir_channel(b, def_zw, 0),
184                      nir_channel(b, def_zw, 1));
185    }
186 
187    nir_def_rewrite_uses(&intr->def, def);
188    return true;
189 }
190 
191 static bool
lower_texcoord(nir_builder * b,lower_drawpixels_state * state,nir_intrinsic_instr * intr)192 lower_texcoord(nir_builder *b, lower_drawpixels_state *state, nir_intrinsic_instr *intr)
193 {
194    b->cursor = nir_before_instr(&intr->instr);
195 
196    nir_def *texcoord_const = get_texcoord_const(b, state);
197    nir_def_rewrite_uses(&intr->def, texcoord_const);
198    return true;
199 }
200 
201 static bool
lower_drawpixels_instr(nir_builder * b,nir_instr * instr,void * cb_data)202 lower_drawpixels_instr(nir_builder *b, nir_instr *instr, void *cb_data)
203 {
204    lower_drawpixels_state *state = cb_data;
205    if (instr->type != nir_instr_type_intrinsic)
206       return false;
207 
208    nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
209 
210    switch (intr->intrinsic) {
211    case nir_intrinsic_load_deref: {
212       nir_deref_instr *deref = nir_src_as_deref(intr->src[0]);
213       nir_variable *var = nir_deref_instr_get_variable(deref);
214 
215       if (var->data.location == VARYING_SLOT_COL0) {
216          /* gl_Color should not have array/struct derefs: */
217          assert(deref->deref_type == nir_deref_type_var);
218          return lower_color(b, state, intr);
219       } else if (var->data.location == VARYING_SLOT_TEX0) {
220          /* gl_TexCoord should not have array/struct derefs: */
221          assert(deref->deref_type == nir_deref_type_var);
222          return lower_texcoord(b, state, intr);
223       }
224       break;
225    }
226 
227    case nir_intrinsic_load_color0:
228       return lower_color(b, state, intr);
229 
230    case nir_intrinsic_load_interpolated_input:
231    case nir_intrinsic_load_input: {
232       if (nir_intrinsic_io_semantics(intr).location == VARYING_SLOT_TEX0)
233          return lower_texcoord(b, state, intr);
234       if (nir_intrinsic_io_semantics(intr).location == VARYING_SLOT_COL0)
235          return lower_color(b, state, intr);
236       break;
237    }
238    default:
239       break;
240    }
241 
242    return false;
243 }
244 
245 bool
nir_lower_drawpixels(nir_shader * shader,const nir_lower_drawpixels_options * options)246 nir_lower_drawpixels(nir_shader *shader,
247                      const nir_lower_drawpixels_options *options)
248 {
249    lower_drawpixels_state state = {
250       .options = options,
251       .shader = shader,
252    };
253 
254    assert(shader->info.stage == MESA_SHADER_FRAGMENT);
255 
256    return nir_shader_instructions_pass(shader, lower_drawpixels_instr,
257                                        nir_metadata_control_flow,
258                                        &state);
259 }
260