• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2023 Google LLC
3  * SPDX-License-Identifier: MIT
4  */
5 
6 #include "nir_builder.h"
7 #include "nir_builtin_builder.h"
8 #include "st_nir.h"
9 
10 static nir_def *
fog_result(nir_builder * b,nir_def * color,enum gl_fog_mode fog_mode,struct gl_program_parameter_list * paramList)11 fog_result(nir_builder *b, nir_def *color, enum gl_fog_mode fog_mode, struct gl_program_parameter_list *paramList)
12 {
13    nir_shader *s = b->shader;
14    nir_def *fogc;
15 
16    if (b->shader->info.io_lowered) {
17       nir_def *baryc = nir_load_barycentric_pixel(b, 32,
18                                                   .interp_mode = INTERP_MODE_SMOOTH);
19       fogc = nir_load_interpolated_input(b, 1, 32, baryc, nir_imm_int(b, 0),
20                                          .io_semantics.location = VARYING_SLOT_FOGC);
21    } else {
22       nir_variable *fogc_var =
23          nir_create_variable_with_location(s, nir_var_shader_in, VARYING_SLOT_FOGC, glsl_float_type());
24       s->info.inputs_read |= VARYING_BIT_FOGC;
25       fogc = nir_load_var(b, fogc_var);
26    }
27 
28    static const gl_state_index16 fog_params_tokens[STATE_LENGTH] = {STATE_FOG_PARAMS_OPTIMIZED};
29    static const gl_state_index16 fog_color_tokens[STATE_LENGTH] = {STATE_FOG_COLOR};
30 
31    nir_variable *fog_params_var = st_nir_state_variable_create(s, glsl_vec4_type(), fog_params_tokens);
32    fog_params_var->data.driver_location = _mesa_add_state_reference(paramList, fog_params_tokens);
33    nir_def *params = nir_load_var(b, fog_params_var);
34 
35    nir_variable *fog_color_var = st_nir_state_variable_create(s, glsl_vec4_type(), fog_color_tokens);
36    fog_color_var->data.driver_location = _mesa_add_state_reference(paramList, fog_color_tokens);
37    nir_def *fog_color = nir_load_var(b, fog_color_var);
38 
39    /* compute the 1 component fog factor f */
40    nir_def *f = NULL;
41    switch (fog_mode) {
42    case FOG_LINEAR:
43       /* f = (end - z) / (end - start)
44        *
45        * gl_MesaFogParamsOptimized gives us (-1 / (end - start)) and
46        * (end / (end - start)) so we can generate a single MAD.
47        */
48       f = nir_fmad(b, fogc,
49                    nir_channel(b, params, 0),
50                    nir_channel(b, params, 1));
51       break;
52   case FOG_EXP:
53       /* f = e^(-(density * fogcoord))
54        *
55        * gl_MesaFogParamsOptimized gives us density/ln(2) so we can
56        * use EXP2 which is generally the native instruction without
57        * having to do any further math on the fog density uniform.
58        */
59       f = nir_fmul(b, fogc, nir_channel(b, params, 2));
60       f = nir_fexp2(b, nir_fneg(b, f));
61       break;
62   case FOG_EXP2:
63       /* f = e^(-(density * fogcoord)^2)
64        *
65        * gl_MesaFogParamsOptimized gives us density/sqrt(ln(2)) so we
66        * can do this like FOG_EXP but with a squaring after the
67        * multiply by density.
68        */
69       f = nir_fmul(b, fogc, nir_channel(b, params, 3));
70       f = nir_fmul(b, f, f);
71       f = nir_fexp2(b, nir_fneg(b, f));
72       break;
73    default:
74       unreachable("unsupported fog mode");
75    }
76    f = nir_fsat(b, f);
77 
78    /* Not using flrp because we may end up lowering fog after driver lowering
79     * that meant to remove all lrps.
80     */
81    return nir_fmad(b, color, f, nir_fmul(b, fog_color, nir_fsub_imm(b, 1.0, f)));
82 }
83 
84 struct lower_fog_state {
85    enum gl_fog_mode fog_mode;
86    struct gl_program_parameter_list *paramList;
87 };
88 
89 static bool
st_nir_lower_fog_instr(nir_builder * b,nir_instr * instr,void * _state)90 st_nir_lower_fog_instr(nir_builder *b, nir_instr *instr, void *_state)
91 {
92    const struct lower_fog_state *state = _state;
93 
94    if (instr->type != nir_instr_type_intrinsic)
95       return false;
96    nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
97    if (intr->intrinsic != nir_intrinsic_store_output)
98       return false;
99 
100    int loc = nir_intrinsic_io_semantics(intr).location;
101    if (loc != FRAG_RESULT_COLOR && loc != FRAG_RESULT_DATA0)
102       return false;
103 
104    b->cursor = nir_before_instr(instr);
105 
106    nir_def *color = intr->src[0].ssa;
107    color = nir_resize_vector(b, color, 4);
108 
109    nir_def *fog = fog_result(b, color, state->fog_mode, state->paramList);
110 
111    /* retain the non-fog-blended alpha value for color */
112    color = nir_vector_insert_imm(b, fog, nir_channel(b, color, 3), 3);
113 
114    nir_src_rewrite(&intr->src[0],
115                    nir_resize_vector(b, color, intr->num_components));
116 
117    return true;
118 }
119 
120 bool
st_nir_lower_fog(nir_shader * s,enum gl_fog_mode fog_mode,struct gl_program_parameter_list * paramList)121 st_nir_lower_fog(nir_shader *s, enum gl_fog_mode fog_mode, struct gl_program_parameter_list *paramList)
122 {
123    if (s->info.io_lowered) {
124       struct lower_fog_state state = {
125          .fog_mode = fog_mode,
126          .paramList = paramList,
127       };
128       nir_shader_instructions_pass(s, st_nir_lower_fog_instr,
129                                    nir_metadata_control_flow,
130                                    &state);
131    } else {
132       nir_variable *color_var = nir_find_variable_with_location(s, nir_var_shader_out, FRAG_RESULT_COLOR);
133       if (!color_var) {
134          color_var = nir_find_variable_with_location(s, nir_var_shader_out, FRAG_RESULT_DATA0);
135          /* Fog result would be undefined if we had no output color (in ARB_fragment_program) */
136          if (!color_var)
137             return false;
138       }
139 
140       nir_function_impl *impl = nir_shader_get_entrypoint(s);
141       nir_builder b = nir_builder_at(nir_after_impl(impl));
142 
143       /* Note: while ARB_fragment_program plus ARB_draw_buffers allows an array
144        * of result colors, prog_to_nir generates separate vars per slot so we
145        * don't have to handle that.  Fog only applies to the first color result.
146        */
147       assert(!glsl_type_is_array(color_var->type));
148 
149       nir_def *color = nir_load_var(&b, color_var);
150       color = fog_result(&b, color, fog_mode, paramList);
151       nir_store_var(&b, color_var, color, 0x7);
152 
153       nir_metadata_preserve(b.impl, nir_metadata_control_flow);   }
154 
155    return true;
156 }
157