2 * © Copyright 2018 Alyssa Rosenzweig
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
26 #include "pan_blend_shaders.h"
28 #include "midgard/midgard_compile.h"
29 #include "compiler/nir/nir_builder.h"
30 #include "nir/nir_lower_blend.h"
31 #include "panfrost/util/pan_lower_framebuffer.h"
32 #include "gallium/auxiliary/util/u_blend.h"
33 #include "util/u_memory.h"
36 * Implements the command stream portion of programmatic blend shaders.
38 * On Midgard, common blending operations are accelerated by the fixed-function
39 * blending pipeline. Panfrost supports this fast path via the code in
40 * pan_blending.c. Nevertheless, uncommon blend modes (including some seemingly
41 * simple modes present in ES2) require "blend shaders", a special internal
42 * shader type used for programmable blending.
44 * Blend shaders operate during the normal blending time, but they bypass the
45 * fixed-function blending pipeline and instead go straight to the Midgard
46 * shader cores. The shaders themselves are essentially just fragment shaders,
47 * making heavy use of uint8 arithmetic to manipulate RGB values for the
50 * As is typical with Midgard, shader binaries must be accompanied by
51 * information about the first tag (ORed with the bottom nibble of address,
52 * like usual) and work registers. Work register count is assumed to be less
53 * than or equal to the coresponding fragment shader's work count. This
54 * suggests that blend shader invocation is tied to fragment shader
57 * The shaders themselves use the standard ISA. The source pixel colour,
58 * including alpha, is preloaded into r0 as a vec4 of float32. The destination
59 * pixel colour must be loaded explicitly via load/store ops, possibly
60 * performing conversions in software. The blended colour must be stored with a
61 * fragment writeout in the correct framebuffer format, either in software or
62 * via conversion opcodes on the load/store pipe.
64 * Blend shaders hardcode constants. Naively, this requires recompilation each
65 * time the blend color changes, which is a performance risk. Accordingly, we
66 * 'cheat' a bit: instead of loading the constant, we compile a shader with a
67 * dummy constant, exporting the offset to the immediate in the shader binary,
68 * storing this generic binary and metadata in the CSO itself at CSO create
71 * We then hot patch in the color into this shader at attachment / color change
72 * time, allowing for CSO create to be the only expensive operation
76 static nir_lower_blend_options
77 nir_make_options(const struct pipe_blend_state
*blend
, unsigned i
)
79 nir_lower_blend_options options
= { 0 };
81 if (blend
->logicop_enable
) {
82 options
.logicop_enable
= true;
83 options
.logicop_func
= blend
->logicop_func
;
87 options
.logicop_enable
= false;
89 if (!blend
->independent_blend_enable
)
92 /* If blend is disabled, we just use replace mode */
94 nir_lower_blend_channel rgb
= {
95 .func
= BLEND_FUNC_ADD
,
96 .src_factor
= BLEND_FACTOR_ZERO
,
97 .invert_src_factor
= true,
98 .dst_factor
= BLEND_FACTOR_ZERO
,
99 .invert_dst_factor
= false
102 nir_lower_blend_channel alpha
= rgb
;
104 if (blend
->rt
[i
].blend_enable
) {
105 rgb
.func
= util_blend_func_to_shader(blend
->rt
[i
].rgb_func
);
106 rgb
.src_factor
= util_blend_factor_to_shader(blend
->rt
[i
].rgb_src_factor
);
107 rgb
.dst_factor
= util_blend_factor_to_shader(blend
->rt
[i
].rgb_dst_factor
);
108 rgb
.invert_src_factor
= util_blend_factor_is_inverted(blend
->rt
[i
].rgb_src_factor
);
109 rgb
.invert_dst_factor
= util_blend_factor_is_inverted(blend
->rt
[i
].rgb_dst_factor
);
111 alpha
.func
= util_blend_func_to_shader(blend
->rt
[i
].alpha_func
);
112 alpha
.src_factor
= util_blend_factor_to_shader(blend
->rt
[i
].alpha_src_factor
);
113 alpha
.dst_factor
= util_blend_factor_to_shader(blend
->rt
[i
].alpha_dst_factor
);
114 alpha
.invert_src_factor
= util_blend_factor_is_inverted(blend
->rt
[i
].alpha_src_factor
);
115 alpha
.invert_dst_factor
= util_blend_factor_is_inverted(blend
->rt
[i
].alpha_dst_factor
);
119 options
.alpha
= alpha
;
121 options
.colormask
= blend
->rt
[i
].colormask
;
127 nir_iclamp(nir_builder
*b
, nir_ssa_def
*v
, int32_t lo
, int32_t hi
)
129 return nir_imin(b
, nir_imax(b
, v
, nir_imm_int(b
, lo
)), nir_imm_int(b
, hi
));
132 struct panfrost_blend_shader
133 panfrost_compile_blend_shader(
134 struct panfrost_context
*ctx
,
135 struct pipe_blend_state
*cso
,
136 enum pipe_format format
,
139 struct panfrost_device
*dev
= pan_device(ctx
->base
.screen
);
140 struct panfrost_blend_shader res
;
144 /* Build the shader */
146 nir_shader
*shader
= nir_shader_create(NULL
, MESA_SHADER_FRAGMENT
, &midgard_nir_options
, NULL
);
147 nir_function
*fn
= nir_function_create(shader
, "main");
148 nir_function_impl
*impl
= nir_function_impl_create(fn
);
150 const struct util_format_description
*format_desc
=
151 util_format_description(format
);
153 nir_alu_type T
= pan_unpacked_type_for_format(format_desc
);
154 enum glsl_base_type g
=
155 (T
== nir_type_float16
) ? GLSL_TYPE_FLOAT16
:
156 (T
== nir_type_float32
) ? GLSL_TYPE_FLOAT
:
157 (T
== nir_type_int8
) ? GLSL_TYPE_INT8
:
158 (T
== nir_type_int16
) ? GLSL_TYPE_INT16
:
159 (T
== nir_type_int32
) ? GLSL_TYPE_INT
:
160 (T
== nir_type_uint8
) ? GLSL_TYPE_UINT8
:
161 (T
== nir_type_uint16
) ? GLSL_TYPE_UINT16
:
162 (T
== nir_type_uint32
) ? GLSL_TYPE_UINT
:
165 /* Create the blend variables */
167 nir_variable
*c_src
= nir_variable_create(shader
, nir_var_shader_in
, glsl_vector_type(GLSL_TYPE_FLOAT
, 4), "gl_Color");
168 nir_variable
*c_src1
= nir_variable_create(shader
, nir_var_shader_in
, glsl_vector_type(GLSL_TYPE_FLOAT
, 4), "gl_Color1");
169 nir_variable
*c_out
= nir_variable_create(shader
, nir_var_shader_out
, glsl_vector_type(g
, 4), "gl_FragColor");
171 c_src
->data
.location
= VARYING_SLOT_COL0
;
172 c_src1
->data
.location
= VARYING_SLOT_VAR0
;
173 c_out
->data
.location
= FRAG_RESULT_COLOR
;
175 c_src1
->data
.driver_location
= 1;
177 /* Setup nir_builder */
180 nir_builder
*b
= &_b
;
181 nir_builder_init(b
, impl
);
182 b
->cursor
= nir_before_block(nir_start_block(impl
));
186 nir_ssa_def
*s_src
[] = {nir_load_var(b
, c_src
), nir_load_var(b
, c_src1
)};
188 for (int i
= 0; i
< ARRAY_SIZE(s_src
); ++i
) {
189 if (T
== nir_type_float16
)
190 s_src
[i
] = nir_f2f16(b
, s_src
[i
]);
191 else if (T
== nir_type_int16
)
192 s_src
[i
] = nir_i2i16(b
, nir_iclamp(b
, s_src
[i
], -32768, 32767));
193 else if (T
== nir_type_uint16
)
194 s_src
[i
] = nir_u2u16(b
, nir_umin(b
, s_src
[i
], nir_imm_int(b
, 65535)));
195 else if (T
== nir_type_int8
)
196 s_src
[i
] = nir_i2i8(b
, nir_iclamp(b
, s_src
[i
], -128, 127));
197 else if (T
== nir_type_uint8
)
198 s_src
[i
] = nir_u2u8(b
, nir_umin(b
, s_src
[i
], nir_imm_int(b
, 255)));
201 /* Build a trivial blend shader */
202 nir_store_var(b
, c_out
, s_src
[0], 0xFF);
204 nir_lower_blend_options options
=
205 nir_make_options(cso
, rt
);
206 options
.format
= format
;
207 options
.src1
= s_src
[1];
209 if (T
== nir_type_float16
)
212 NIR_PASS_V(shader
, nir_lower_blend
, options
);
214 /* Compile the built shader */
216 panfrost_program program
= {
217 .rt_formats
= {format
}
220 midgard_compile_shader_nir(shader
, &program
, true, rt
, dev
->gpu_id
, false, false);
222 /* Allow us to patch later */
223 res
.patch_index
= program
.blend_patch_offset
;
224 res
.first_tag
= program
.first_tag
;
225 res
.size
= program
.compiled
.size
;
226 res
.buffer
= program
.compiled
.data
;
227 res
.work_count
= program
.work_register_count
;