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 static bool
apply_attr_wa_instr(nir_builder * b,nir_instr * instr,void * cb_data)34 apply_attr_wa_instr(nir_builder *b, nir_instr *instr, void *cb_data)
35 {
36 const uint8_t *attrib_wa_flags = cb_data;
37
38 if (instr->type != nir_instr_type_intrinsic)
39 return false;
40
41 nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
42 if (intrin->intrinsic != nir_intrinsic_load_input)
43 return false;
44
45 uint8_t wa_flags = attrib_wa_flags[intrin->const_index[0]];
46 if (wa_flags == 0)
47 return false;
48
49 b->cursor = nir_after_instr(instr);
50
51 nir_ssa_def *val = &intrin->dest.ssa;
52
53 /* Do GL_FIXED rescaling for GLES2.0. Our GL_FIXED attributes
54 * come in as floating point conversions of the integer values.
55 */
56 if (wa_flags & BRW_ATTRIB_WA_COMPONENT_MASK) {
57 nir_ssa_def *scaled =
58 nir_fmul(b, val, nir_imm_float(b, 1.0f / 65536.0f));
59 nir_ssa_def *comps[4];
60 for (int i = 0; i < val->num_components; i++) {
61 bool rescale = i < (wa_flags & BRW_ATTRIB_WA_COMPONENT_MASK);
62 comps[i] = nir_channel(b, rescale ? scaled : val, i);
63 }
64 val = nir_vec(b, comps, val->num_components);
65 }
66
67 /* Do sign recovery for 2101010 formats if required. */
68 if (wa_flags & BRW_ATTRIB_WA_SIGN) {
69 /* sign recovery shift: <22, 22, 22, 30> */
70 nir_ssa_def *shift = nir_imm_ivec4(b, 22, 22, 22, 30);
71 val = nir_ishr(b, nir_ishl(b, val, shift), shift);
72 }
73
74 /* Apply BGRA swizzle if required. */
75 if (wa_flags & BRW_ATTRIB_WA_BGRA) {
76 val = nir_swizzle(b, val, (unsigned[4]){2,1,0,3}, 4);
77 }
78
79 if (wa_flags & BRW_ATTRIB_WA_NORMALIZE) {
80 /* ES 3.0 has different rules for converting signed normalized
81 * fixed-point numbers than desktop GL.
82 */
83 if (wa_flags & BRW_ATTRIB_WA_SIGN) {
84 /* According to equation 2.2 of the ES 3.0 specification,
85 * signed normalization conversion is done by:
86 *
87 * f = c / (2^(b-1)-1)
88 *
89 * OpenGL 4.2+ uses this equation as well. Since most contexts
90 * promote to the new higher version, and this is what Haswell+
91 * hardware does anyway, we just always use this formula.
92 */
93 nir_ssa_def *es3_normalize_factor =
94 nir_imm_vec4(b, 1.0f / ((1 << 9) - 1), 1.0f / ((1 << 9) - 1),
95 1.0f / ((1 << 9) - 1), 1.0f / ((1 << 1) - 1));
96 val = nir_fmax(b,
97 nir_fmul(b, nir_i2f32(b, val), es3_normalize_factor),
98 nir_imm_float(b, -1.0f));
99 } else {
100 /* The following equation is from the OpenGL 3.2 specification:
101 *
102 * 2.1 unsigned normalization
103 * f = c/(2^n-1)
104 */
105 nir_ssa_def *normalize_factor =
106 nir_imm_vec4(b, 1.0f / ((1 << 10) - 1), 1.0f / ((1 << 10) - 1),
107 1.0f / ((1 << 10) - 1), 1.0f / ((1 << 2) - 1));
108
109 val = nir_fmul(b, nir_u2f32(b, val), normalize_factor);
110 }
111 }
112
113 if (wa_flags & BRW_ATTRIB_WA_SCALE) {
114 val = (wa_flags & BRW_ATTRIB_WA_SIGN) ? nir_i2f32(b, val)
115 : nir_u2f32(b, val);
116 }
117
118 nir_ssa_def_rewrite_uses_after(&intrin->dest.ssa, val,
119 val->parent_instr);
120
121 return true;
122 }
123
124 bool
brw_nir_apply_attribute_workarounds(nir_shader * shader,const uint8_t * attrib_wa_flags)125 brw_nir_apply_attribute_workarounds(nir_shader *shader,
126 const uint8_t *attrib_wa_flags)
127 {
128 return nir_shader_instructions_pass(shader, apply_attr_wa_instr,
129 nir_metadata_block_index |
130 nir_metadata_dominance,
131 (void *)attrib_wa_flags);
132 }
133