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
23 * Authors (Collabora):
24 * Alyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
29 /* Derivatives in Midgard are implemented on the texture pipe, rather than the
30 * ALU pipe as suggested by NIR. The rationale is that normal texture
31 * instructions require (implicit) derivatives to be calculated anyway, so it
32 * makes sense to reuse the derivative logic. Thus, in addition to the usual
33 * texturing ops that calculate derivatives, there are two explicit texture ops
34 * dFdx/dFdy that perform differencing across helper invocations in either
35 * horizontal or vertical directions.
37 * One major caveat is that derivatives can only be calculated on up to a vec2
38 * at a time. This restriction presumably is to save some silicon, as 99% of
39 * derivatives will be vec2 (autocalculating mip levels of 2D texture
40 * coordinates). Admittedly I'm not sure why 3D textures can have their levels
41 * calculated automatically, umm... Pressing on.
43 * This caveat is handled in two steps. During the first pass (code
44 * generation), we generate texture ops 1:1 to the incoming NIR derivatives.
45 * This works for float/vec2 but not for vec3/vec4. A later lowering pass will
46 * scan for vec3/vec4 derivatives and lower (split) to multiple instructions.
47 * This pass is separated as we'll have to rewrite th e destination into a
48 * register (rather than SSA) and we'd rather do this after we have the whole
49 * IR in front of us to do it at once.
53 mir_derivative_op(nir_op op
)
57 case nir_op_fddx_fine
:
58 case nir_op_fddx_coarse
:
59 return TEXTURE_OP_DFDX
;
62 case nir_op_fddy_fine
:
63 case nir_op_fddy_coarse
:
64 return TEXTURE_OP_DFDY
;
67 unreachable("Invalid derivative op");
71 /* Returns true if a texturing op computes derivatives either explicitly or
75 mir_op_computes_derivatives(unsigned op
)
78 case TEXTURE_OP_NORMAL
:
88 midgard_emit_derivatives(compiler_context
*ctx
, nir_alu_instr
*instr
)
90 /* Create texture instructions */
92 unsigned nr_components
= nir_dest_num_components(instr
->dest
.dest
);
94 midgard_instruction ins
= {
95 .type
= TAG_TEXTURE_4
,
96 .mask
= mask_of(nr_components
),
98 .dest
= nir_dest_index(ctx
, &instr
->dest
.dest
),
99 .src
= { nir_alu_src_index(ctx
, &instr
->src
[0]), -1, -1 },
102 .op
= mir_derivative_op(instr
->op
),
103 .format
= MALI_TEX_2D
,
104 .swizzle
= SWIZZLE_XYXX
,
105 .in_reg_swizzle
= SWIZZLE_XYXX
,
109 .sampler_type
= MALI_SAMPLER_FLOAT
,
113 if (!instr
->dest
.dest
.is_ssa
)
114 ins
.mask
&= instr
->dest
.write_mask
;
116 emit_mir_instruction(ctx
, ins
);
118 /* TODO: Set .cont/.last automatically via dataflow analysis */
119 ctx
->texture_op_count
++;
123 midgard_lower_derivatives(compiler_context
*ctx
, midgard_block
*block
)
125 mir_foreach_instr_in_block_safe(block
, ins
) {
126 if (ins
->type
!= TAG_TEXTURE_4
) continue;
127 if (!OP_IS_DERIVATIVE(ins
->texture
.op
)) continue;
129 /* Check if we need to split */
131 bool upper
= ins
->mask
& 0b1100;
132 bool lower
= ins
->mask
& 0b0011;
134 if (!(upper
&& lower
)) continue;
136 /* Duplicate for dedicated upper instruction */
138 midgard_instruction dup
;
139 memcpy(&dup
, ins
, sizeof(dup
));
141 /* Fixup masks. Make original just lower and dupe just upper */
147 assert(ins
->texture
.swizzle
== SWIZZLE_XYXX
);
148 assert(ins
->texture
.in_reg_swizzle
== SWIZZLE_XYXX
);
149 dup
.texture
.swizzle
= SWIZZLE_XXXY
;
150 dup
.texture
.in_reg_swizzle
= SWIZZLE_ZWWW
;
152 /* Insert the new instruction */
153 mir_insert_instruction_before(mir_next_op(ins
), dup
);
155 /* TODO: Set .cont/.last automatically via dataflow analysis */
156 ctx
->texture_op_count
++;
158 /* We'll need both instructions to write to the same index, so
159 * rewrite to use a register */
161 unsigned new = make_compiler_temp_reg(ctx
);
162 mir_rewrite_index(ctx
, ins
->ssa_args
.dest
, new);