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 "gallium/auxiliary/nir/nir_lower_blend.h"
33 * Implements the command stream portion of programmatic blend shaders.
35 * On Midgard, common blending operations are accelerated by the fixed-function
36 * blending pipeline. Panfrost supports this fast path via the code in
37 * pan_blending.c. Nevertheless, uncommon blend modes (including some seemingly
38 * simple modes present in ES2) require "blend shaders", a special internal
39 * shader type used for programmable blending.
41 * Blend shaders operate during the normal blending time, but they bypass the
42 * fixed-function blending pipeline and instead go straight to the Midgard
43 * shader cores. The shaders themselves are essentially just fragment shaders,
44 * making heavy use of uint8 arithmetic to manipulate RGB values for the
47 * As is typical with Midgard, shader binaries must be accompanied by
48 * information about the first tag (ORed with the bottom nibble of address,
49 * like usual) and work registers. Work register count is specified in the
50 * blend descriptor, as well as in the coresponding fragment shader's work
51 * count. This suggests that blend shader invocation is tied to fragment shader
56 * As for blend shaders, they use the standard ISA.
58 * The source pixel colour, including alpha, is preloaded into r0 as a vec4 of
61 * The destination pixel colour must be loaded explicitly via load/store ops.
64 * They use fragment shader writeout; however, instead of writing a vec4 of
65 * float32 for RGBA encoding, we writeout a vec4 of uint8, using 8-bit imov
66 * instead of 32-bit fmov. The net result is that r0 encodes a single uint32
67 * containing all four channels of the color. Accordingly, the blend shader
68 * epilogue has to scale all four channels by 255 and then type convert to a
73 * Blend shaders hardcode constants. Naively, this requires recompilation each
74 * time the blend color changes, which is a performance risk. Accordingly, we
75 * 'cheat' a bit: instead of loading the constant, we compile a shader with a
76 * dummy constant, exporting the offset to the immediate in the shader binary,
77 * storing this generic binary and metadata in the CSO itself at CSO create
80 * We then hot patch in the color into this shader at attachment / color change
81 * time, allowing for CSO create to be the only expensive operation
86 nir_blending_f(const struct pipe_rt_blend_state
*blend
, nir_builder
*b
,
87 nir_ssa_def
*s_src
, nir_ssa_def
*s_dst
, nir_ssa_def
*s_con
)
89 /* Stub, to be replaced by the real implementation when that is
90 * upstream (pending on a rewrite to be Gallium agnostic) */
96 panfrost_make_blend_shader(struct panfrost_context
*ctx
, struct panfrost_blend_state
*cso
, const struct pipe_blend_color
*blend_color
)
98 const struct pipe_rt_blend_state
*blend
= &cso
->base
.rt
[0];
99 mali_ptr
*out
= &cso
->blend_shader
;
101 /* Build the shader */
103 nir_shader
*shader
= nir_shader_create(NULL
, MESA_SHADER_FRAGMENT
, &midgard_nir_options
, NULL
);
104 nir_function
*fn
= nir_function_create(shader
, "main");
105 nir_function_impl
*impl
= nir_function_impl_create(fn
);
107 /* Create the blend variables */
109 nir_variable
*c_src
= nir_variable_create(shader
, nir_var_shader_in
, glsl_vector_type(GLSL_TYPE_FLOAT
, 4), "gl_Color");
110 nir_variable
*c_dst
= nir_variable_create(shader
, nir_var_shader_in
, glsl_vector_type(GLSL_TYPE_FLOAT
, 4), "gl_SecondaryColor");
111 nir_variable
*c_out
= nir_variable_create(shader
, nir_var_shader_out
, glsl_vector_type(GLSL_TYPE_FLOAT
, 4), "gl_FragColor");
112 nir_variable
*c_con
= nir_variable_create(shader
, nir_var_uniform
, glsl_vector_type(GLSL_TYPE_FLOAT
, 4), "constant");
114 c_src
->data
.location
= VARYING_SLOT_COL0
;
115 c_dst
->data
.location
= VARYING_SLOT_COL1
;
116 c_out
->data
.location
= FRAG_RESULT_COLOR
;
118 /* Setup nir_builder */
121 nir_builder
*b
= &_b
;
122 nir_builder_init(b
, impl
);
123 b
->cursor
= nir_before_block(nir_start_block(impl
));
127 nir_ssa_def
*s_src
= nir_load_var(b
, c_src
);
128 nir_ssa_def
*s_dst
= nir_load_var(b
, c_dst
);
129 nir_ssa_def
*s_con
= nir_load_var(b
, c_con
);
131 /* Build a trivial blend shader */
132 nir_store_var(b
, c_out
, nir_blending_f(blend
, b
, s_src
, s_dst
, s_con
), 0xFF);
134 if (pan_debug
& PAN_DBG_SHADERS
)
135 nir_print_shader(shader
, stdout
);
137 /* Compile the built shader */
139 midgard_program program
;
140 midgard_compile_shader_nir(shader
, &program
, true);
143 /* Upload the shader */
145 int size
= program
.compiled
.size
;
146 uint8_t *dst
= program
.compiled
.data
;
148 /* Hot patch in constant color */
150 if (program
.blend_patch_offset
>= 0) {
151 float *hot_color
= (float *) (dst
+ program
.blend_patch_offset
);
153 for (int c
= 0; c
< 4; ++c
)
154 hot_color
[c
] = blend_color
->color
[c
];
157 *out
= panfrost_upload(&ctx
->shaders
, dst
, size
, true) | program
.first_tag
;
159 /* We need to switch to shader mode */
160 cso
->has_blend_shader
= true;
162 /* At least two work registers are needed due to an encoding quirk */
163 cso
->blend_work_count
= MAX2(program
.work_register_count
, 2);