2 * Copyright (C) 2019 Collabora, Ltd.
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:
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
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
24 /* Midgard has some accelerated support for perspective projection on the
25 * load/store pipes. So the first perspective projection pass looks for
26 * lowered/open-coded perspective projection of the form "fmul (A.xyz,
27 * frcp(A.w))" or "fmul (A.xy, frcp(A.z))" and rewrite with a native
28 * perspective division opcode (on the load/store pipe). Caveats apply: the
29 * frcp should be used only once to make this optimization worthwhile. And the
30 * source of the frcp ought to be a varying to make it worthwhile...
32 * The second pass in this file is a step #2 of sorts: fusing that load/store
33 * projection into a varying load instruction (they can be done together
34 * implicitly). This depends on the combination pass. Again caveat: the vary
35 * should only be used once to make this worthwhile.
41 is_swizzle_0(unsigned *swizzle
)
43 for (unsigned c
= 0; c
< MIR_VEC_COMPONENTS
; ++c
)
51 midgard_opt_combine_projection(compiler_context
*ctx
, midgard_block
*block
)
53 bool progress
= false;
55 mir_foreach_instr_in_block_safe(block
, ins
) {
56 /* First search for fmul */
57 if (ins
->type
!= TAG_ALU_4
) continue;
58 if (ins
->alu
.op
!= midgard_alu_op_fmul
) continue;
62 /* Check the swizzles */
64 if (!mir_is_simple_swizzle(ins
->swizzle
[0], ins
->mask
)) continue;
65 if (!is_swizzle_0(ins
->swizzle
[1])) continue;
67 /* Awesome, we're the right form. Now check where src2 is from */
68 unsigned frcp
= ins
->src
[1];
69 unsigned to
= ins
->dest
;
71 if (frcp
& PAN_IS_REG
) continue;
72 if (to
& PAN_IS_REG
) continue;
74 bool frcp_found
= false;
75 unsigned frcp_component
= 0;
76 unsigned frcp_from
= 0;
78 mir_foreach_instr_in_block_safe(block
, sub
) {
79 if (sub
->dest
!= frcp
) continue;
81 frcp_component
= sub
->swizzle
[0][0];
82 frcp_from
= sub
->src
[0];
85 (sub
->type
== TAG_ALU_4
) &&
86 (sub
->alu
.op
== midgard_alu_op_frcp
);
90 if (!frcp_found
) continue;
91 if (frcp_component
!= COMPONENT_W
&& frcp_component
!= COMPONENT_Z
) continue;
92 if (!mir_single_use(ctx
, frcp
)) continue;
94 /* Heuristic: check if the frcp is from a single-use varying */
98 /* One for frcp and one for fmul */
99 if (mir_use_count(ctx
, frcp_from
) > 2) continue;
101 mir_foreach_instr_in_block_safe(block
, v
) {
102 if (v
->dest
!= frcp_from
) continue;
103 if (v
->type
!= TAG_LOAD_STORE_4
) break;
104 if (!OP_IS_LOAD_VARY_F(v
->load_store
.op
)) break;
113 /* Nice, we got the form spot on. Let's convert! */
115 midgard_instruction accel
= {
116 .type
= TAG_LOAD_STORE_4
,
119 .dest_type
= nir_type_float32
,
120 .src
= { frcp_from
, ~0, ~0, ~0 },
121 .src_types
= { nir_type_float32
},
122 .swizzle
= SWIZZLE_IDENTITY_4
,
124 .op
= frcp_component
== COMPONENT_W
?
125 midgard_op_ldst_perspective_division_w
:
126 midgard_op_ldst_perspective_division_z
,
131 mir_insert_instruction_before(ctx
, ins
, accel
);
132 mir_remove_instruction(ins
);
141 midgard_opt_varying_projection(compiler_context
*ctx
, midgard_block
*block
)
143 bool progress
= false;
145 mir_foreach_instr_in_block_safe(block
, ins
) {
146 /* Search for a projection */
147 if (ins
->type
!= TAG_LOAD_STORE_4
) continue;
148 if (!OP_IS_PROJECTION(ins
->load_store
.op
)) continue;
150 unsigned vary
= ins
->src
[0];
151 unsigned to
= ins
->dest
;
153 if (vary
& PAN_IS_REG
) continue;
154 if (to
& PAN_IS_REG
) continue;
155 if (!mir_single_use(ctx
, vary
)) continue;
157 /* Check for a varying source. If we find it, we rewrite */
159 bool rewritten
= false;
161 mir_foreach_instr_in_block_safe(block
, v
) {
162 if (v
->dest
!= vary
) continue;
163 if (v
->type
!= TAG_LOAD_STORE_4
) break;
164 if (!OP_IS_LOAD_VARY_F(v
->load_store
.op
)) break;
166 /* We found it, so rewrite it to project. Grab the
169 unsigned param
= v
->load_store
.varying_parameters
;
170 midgard_varying_parameter p
;
171 memcpy(&p
, ¶m
, sizeof(p
));
173 if (p
.modifier
!= midgard_varying_mod_none
)
177 ins
->load_store
.op
== midgard_op_ldst_perspective_division_w
;
179 p
.modifier
= projects_w
?
180 midgard_varying_mod_perspective_w
:
181 midgard_varying_mod_perspective_z
;
183 /* Aliasing rules are annoying */
184 memcpy(¶m
, &p
, sizeof(p
));
185 v
->load_store
.varying_parameters
= param
;
187 /* Use the new destination */
195 mir_remove_instruction(ins
);
197 progress
|= rewritten
;