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 "midgard/nir_lower_blend.h"
31 #include "gallium/auxiliary/util/u_blend.h"
34 * Implements the command stream portion of programmatic blend shaders.
36 * On Midgard, common blending operations are accelerated by the fixed-function
37 * blending pipeline. Panfrost supports this fast path via the code in
38 * pan_blending.c. Nevertheless, uncommon blend modes (including some seemingly
39 * simple modes present in ES2) require "blend shaders", a special internal
40 * shader type used for programmable blending.
42 * Blend shaders operate during the normal blending time, but they bypass the
43 * fixed-function blending pipeline and instead go straight to the Midgard
44 * shader cores. The shaders themselves are essentially just fragment shaders,
45 * making heavy use of uint8 arithmetic to manipulate RGB values for the
48 * As is typical with Midgard, shader binaries must be accompanied by
49 * information about the first tag (ORed with the bottom nibble of address,
50 * like usual) and work registers. Work register count is specified in the
51 * blend descriptor, as well as in the coresponding fragment shader's work
52 * count. This suggests that blend shader invocation is tied to fragment shader
57 * As for blend shaders, they use the standard ISA.
59 * The source pixel colour, including alpha, is preloaded into r0 as a vec4 of
62 * The destination pixel colour must be loaded explicitly via load/store ops.
65 * They use fragment shader writeout; however, instead of writing a vec4 of
66 * float32 for RGBA encoding, we writeout a vec4 of uint8, using 8-bit imov
67 * instead of 32-bit fmov. The net result is that r0 encodes a single uint32
68 * containing all four channels of the color. Accordingly, the blend shader
69 * epilogue has to scale all four channels by 255 and then type convert to a
74 * Blend shaders hardcode constants. Naively, this requires recompilation each
75 * time the blend color changes, which is a performance risk. Accordingly, we
76 * 'cheat' a bit: instead of loading the constant, we compile a shader with a
77 * dummy constant, exporting the offset to the immediate in the shader binary,
78 * storing this generic binary and metadata in the CSO itself at CSO create
81 * We then hot patch in the color into this shader at attachment / color change
82 * time, allowing for CSO create to be the only expensive operation
86 static nir_lower_blend_options
87 nir_make_options(const struct pipe_blend_state
*blend
, unsigned nr_cbufs
)
89 nir_lower_blend_options options
;
91 for (unsigned i
= 0; i
< nr_cbufs
; ++i
) {
92 nir_lower_blend_channel rgb
= {
93 .func
= util_blend_func_to_shader(blend
->rt
[i
].rgb_func
),
94 .src_factor
= util_blend_factor_to_shader(blend
->rt
[i
].rgb_src_factor
),
95 .dst_factor
= util_blend_factor_to_shader(blend
->rt
[i
].rgb_dst_factor
),
96 .invert_src_factor
= util_blend_factor_is_inverted(blend
->rt
[i
].rgb_src_factor
),
97 .invert_dst_factor
= util_blend_factor_is_inverted(blend
->rt
[i
].rgb_dst_factor
)
100 nir_lower_blend_channel alpha
= {
101 .func
= util_blend_func_to_shader(blend
->rt
[i
].alpha_func
),
102 .src_factor
= util_blend_factor_to_shader(blend
->rt
[i
].alpha_src_factor
),
103 .dst_factor
= util_blend_factor_to_shader(blend
->rt
[i
].alpha_dst_factor
),
104 .invert_src_factor
= util_blend_factor_is_inverted(blend
->rt
[i
].alpha_src_factor
),
105 .invert_dst_factor
= util_blend_factor_is_inverted(blend
->rt
[i
].alpha_dst_factor
)
108 options
.rt
[i
].rgb
= rgb
;
109 options
.rt
[i
].alpha
= alpha
;
111 options
.rt
[i
].colormask
= blend
->rt
[i
].colormask
;
118 panfrost_make_blend_shader(
119 struct panfrost_context
*ctx
,
120 struct panfrost_blend_state
*cso
,
121 const struct pipe_blend_color
*blend_color
,
122 enum pipe_format format
)
124 /* Build the shader */
126 nir_shader
*shader
= nir_shader_create(NULL
, MESA_SHADER_FRAGMENT
, &midgard_nir_options
, NULL
);
127 nir_function
*fn
= nir_function_create(shader
, "main");
128 nir_function_impl
*impl
= nir_function_impl_create(fn
);
130 /* Create the blend variables */
132 nir_variable
*c_src
= nir_variable_create(shader
, nir_var_shader_in
, glsl_vector_type(GLSL_TYPE_FLOAT
, 4), "gl_Color");
133 nir_variable
*c_out
= nir_variable_create(shader
, nir_var_shader_out
, glsl_vector_type(GLSL_TYPE_FLOAT
, 4), "gl_FragColor");
135 c_src
->data
.location
= VARYING_SLOT_COL0
;
136 c_out
->data
.location
= FRAG_RESULT_COLOR
;
138 /* Setup nir_builder */
141 nir_builder
*b
= &_b
;
142 nir_builder_init(b
, impl
);
143 b
->cursor
= nir_before_block(nir_start_block(impl
));
147 nir_ssa_def
*s_src
= nir_load_var(b
, c_src
);
149 /* Build a trivial blend shader */
150 nir_store_var(b
, c_out
, s_src
, 0xFF);
152 nir_lower_blend_options options
=
153 nir_make_options(&cso
->base
, 1);
154 NIR_PASS_V(shader
, nir_lower_blend
, options
);
156 NIR_PASS_V(shader
, nir_lower_framebuffer
, format
);
158 /* Compile the built shader */
160 midgard_program program
;
161 midgard_compile_shader_nir(shader
, &program
, true);
163 /* Upload the shader */
165 int size
= program
.compiled
.size
;
166 uint8_t *dst
= program
.compiled
.data
;
168 /* Hot patch in constant color */
170 if (program
.blend_patch_offset
>= 0) {
171 float *hot_color
= (float *) (dst
+ program
.blend_patch_offset
);
173 for (int c
= 0; c
< 4; ++c
)
174 hot_color
[c
] = blend_color
->color
[c
];
177 cso
->blend_shader
= panfrost_upload(&ctx
->shaders
, dst
, size
, true) | program
.first_tag
;
179 /* We need to switch to shader mode */
180 cso
->has_blend_shader
= true;
182 /* At least two work registers are needed due to an encoding quirk */
183 cso
->blend_work_count
= MAX2(program
.work_register_count
, 2);