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
->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
->op
== midgard_alu_op_frcp
);
90 if (!frcp_found
) continue;
91 if (frcp_from
!= ins
->src
[0]) continue;
92 if (frcp_component
!= COMPONENT_W
&& frcp_component
!= COMPONENT_Z
) continue;
93 if (!mir_single_use(ctx
, frcp
)) continue;
95 /* Heuristic: check if the frcp is from a single-use varying */
99 /* One for frcp and one for fmul */
100 if (mir_use_count(ctx
, frcp_from
) > 2) continue;
102 mir_foreach_instr_in_block_safe(block
, v
) {
103 if (v
->dest
!= frcp_from
) continue;
104 if (v
->type
!= TAG_LOAD_STORE_4
) break;
105 if (!OP_IS_LOAD_VARY_F(v
->op
)) break;
114 /* Nice, we got the form spot on. Let's convert! */
116 midgard_instruction accel
= {
117 .type
= TAG_LOAD_STORE_4
,
120 .dest_type
= nir_type_float32
,
121 .src
= { frcp_from
, ~0, ~0, ~0 },
122 .src_types
= { nir_type_float32
},
123 .swizzle
= SWIZZLE_IDENTITY_4
,
124 .op
= frcp_component
== COMPONENT_W
?
125 midgard_op_ldst_perspective_division_w
:
126 midgard_op_ldst_perspective_division_z
,
132 mir_insert_instruction_before(ctx
, ins
, accel
);
133 mir_remove_instruction(ins
);
142 midgard_opt_varying_projection(compiler_context
*ctx
, midgard_block
*block
)
144 bool progress
= false;
146 mir_foreach_instr_in_block_safe(block
, ins
) {
147 /* Search for a projection */
148 if (ins
->type
!= TAG_LOAD_STORE_4
) continue;
149 if (!OP_IS_PROJECTION(ins
->op
)) continue;
151 unsigned vary
= ins
->src
[0];
152 unsigned to
= ins
->dest
;
154 if (vary
& PAN_IS_REG
) continue;
155 if (to
& PAN_IS_REG
) continue;
156 if (!mir_single_use(ctx
, vary
)) continue;
158 /* Check for a varying source. If we find it, we rewrite */
160 bool rewritten
= false;
162 mir_foreach_instr_in_block_safe(block
, v
) {
163 if (v
->dest
!= vary
) continue;
164 if (v
->type
!= TAG_LOAD_STORE_4
) break;
165 if (!OP_IS_LOAD_VARY_F(v
->op
)) break;
167 /* We found it, so rewrite it to project. Grab the
170 unsigned param
= v
->load_store
.varying_parameters
;
171 midgard_varying_parameter p
;
172 memcpy(&p
, ¶m
, sizeof(p
));
174 if (p
.modifier
!= midgard_varying_mod_none
)
178 ins
->op
== midgard_op_ldst_perspective_division_w
;
180 p
.modifier
= projects_w
?
181 midgard_varying_mod_perspective_w
:
182 midgard_varying_mod_perspective_z
;
184 /* Aliasing rules are annoying */
185 memcpy(¶m
, &p
, sizeof(p
));
186 v
->load_store
.varying_parameters
= param
;
188 /* Use the new destination */
196 mir_remove_instruction(ins
);
198 progress
|= rewritten
;