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