• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2016 Intel 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  * 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
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "compiler/nir/nir_builder.h"
25 #include "brw_nir.h"
26 
27 /**
28  * Prior to Haswell, the hardware can't natively support GL_FIXED or
29  * 2_10_10_10_REV vertex formats.  This pass inserts extra shader code
30  * to produce the correct values.
31  */
32 
33 struct attr_wa_state {
34    nir_builder builder;
35    bool impl_progress;
36    const uint8_t *wa_flags;
37 };
38 
39 static bool
apply_attr_wa_block(nir_block * block,struct attr_wa_state * state)40 apply_attr_wa_block(nir_block *block, struct attr_wa_state *state)
41 {
42    nir_builder *b = &state->builder;
43 
44    nir_foreach_instr_safe(instr, block) {
45       if (instr->type != nir_instr_type_intrinsic)
46          continue;
47 
48       nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
49       if (intrin->intrinsic != nir_intrinsic_load_input)
50          continue;
51 
52       uint8_t wa_flags = state->wa_flags[intrin->const_index[0]];
53       if (wa_flags == 0)
54          continue;
55 
56       b->cursor = nir_after_instr(instr);
57 
58       nir_ssa_def *val = &intrin->dest.ssa;
59 
60       /* Do GL_FIXED rescaling for GLES2.0.  Our GL_FIXED attributes
61        * come in as floating point conversions of the integer values.
62        */
63       if (wa_flags & BRW_ATTRIB_WA_COMPONENT_MASK) {
64          nir_ssa_def *scaled =
65             nir_fmul(b, val, nir_imm_float(b, 1.0f / 65536.0f));
66          nir_ssa_def *comps[4];
67          for (int i = 0; i < val->num_components; i++) {
68             bool rescale = i < (wa_flags & BRW_ATTRIB_WA_COMPONENT_MASK);
69             comps[i] = nir_channel(b, rescale ? scaled : val, i);
70          }
71          val = nir_vec(b, comps, val->num_components);
72       }
73 
74       /* Do sign recovery for 2101010 formats if required. */
75       if (wa_flags & BRW_ATTRIB_WA_SIGN) {
76          /* sign recovery shift: <22, 22, 22, 30> */
77          nir_ssa_def *shift = nir_imm_ivec4(b, 22, 22, 22, 30);
78          val = nir_ishr(b, nir_ishl(b, val, shift), shift);
79       }
80 
81       /* Apply BGRA swizzle if required. */
82       if (wa_flags & BRW_ATTRIB_WA_BGRA) {
83          val = nir_swizzle(b, val, (unsigned[4]){2,1,0,3}, 4, true);
84       }
85 
86       if (wa_flags & BRW_ATTRIB_WA_NORMALIZE) {
87          /* ES 3.0 has different rules for converting signed normalized
88           * fixed-point numbers than desktop GL.
89           */
90          if (wa_flags & BRW_ATTRIB_WA_SIGN) {
91             /* According to equation 2.2 of the ES 3.0 specification,
92              * signed normalization conversion is done by:
93              *
94              * f = c / (2^(b-1)-1)
95              *
96              * OpenGL 4.2+ uses this equation as well.  Since most contexts
97              * promote to the new higher version, and this is what Haswell+
98              * hardware does anyway, we just always use this formula.
99              */
100             nir_ssa_def *es3_normalize_factor =
101                nir_imm_vec4(b, 1.0f / ((1 << 9) - 1), 1.0f / ((1 << 9) - 1),
102                                1.0f / ((1 << 9) - 1), 1.0f / ((1 << 1) - 1));
103             val = nir_fmax(b,
104                            nir_fmul(b, nir_i2f32(b, val), es3_normalize_factor),
105                            nir_imm_float(b, -1.0f));
106          } else {
107             /* The following equation is from the OpenGL 3.2 specification:
108              *
109              * 2.1 unsigned normalization
110              * f = c/(2^n-1)
111              */
112             nir_ssa_def *normalize_factor =
113                nir_imm_vec4(b, 1.0f / ((1 << 10) - 1), 1.0f / ((1 << 10) - 1),
114                                1.0f / ((1 << 10) - 1), 1.0f / ((1 << 2)  - 1));
115 
116             val = nir_fmul(b, nir_u2f32(b, val), normalize_factor);
117          }
118       }
119 
120       if (wa_flags & BRW_ATTRIB_WA_SCALE) {
121          val = (wa_flags & BRW_ATTRIB_WA_SIGN) ? nir_i2f32(b, val)
122                                                : nir_u2f32(b, val);
123       }
124 
125       nir_ssa_def_rewrite_uses_after(&intrin->dest.ssa, nir_src_for_ssa(val),
126                                      val->parent_instr);
127       state->impl_progress = true;
128    }
129 
130    return true;
131 }
132 
133 bool
brw_nir_apply_attribute_workarounds(nir_shader * shader,const uint8_t * attrib_wa_flags)134 brw_nir_apply_attribute_workarounds(nir_shader *shader,
135                                     const uint8_t *attrib_wa_flags)
136 {
137    bool progress = false;
138    struct attr_wa_state state = {
139       .wa_flags = attrib_wa_flags,
140    };
141 
142    nir_foreach_function(func, shader) {
143       if (!func->impl)
144          continue;
145 
146       nir_builder_init(&state.builder, func->impl);
147       state.impl_progress = false;
148 
149       nir_foreach_block(block, func->impl) {
150          apply_attr_wa_block(block, &state);
151       }
152 
153       if (state.impl_progress) {
154          nir_metadata_preserve(func->impl, nir_metadata_block_index |
155                                            nir_metadata_dominance);
156          progress = true;
157       }
158    }
159 
160    return progress;
161 }
162