panfrost/midgard: Add umin/umax opcodes
[mesa.git] / src / gallium / drivers / panfrost / pan_blend_shaders.c
1 /*
2 * © Copyright 2018 Alyssa Rosenzweig
3 *
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:
10 *
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
13 * Software.
14 *
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
21 * SOFTWARE.
22 *
23 */
24
25 #include <stdio.h>
26 #include "pan_blend_shaders.h"
27 #include "pan_util.h"
28 #include "midgard/midgard_compile.h"
29 #include "compiler/nir/nir_builder.h"
30 //#include "gallium/auxiliary/nir/nir_lower_blend.h"
31
32 /*
33 * Implements the command stream portion of programmatic blend shaders.
34 *
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.
40 *
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
45 * framebuffer.
46 *
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
52 * execution.
53 *
54 * ---
55 *
56 * As for blend shaders, they use the standard ISA.
57 *
58 * The source pixel colour, including alpha, is preloaded into r0 as a vec4 of
59 * float32.
60 *
61 * The destination pixel colour must be loaded explicitly via load/store ops.
62 * TODO: Investigate.
63 *
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
69 * uint8.
70 *
71 * ---
72 *
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
78 * time.
79 *
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
82 * (compilation).
83 */
84
85 static nir_ssa_def *
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)
88 {
89 /* Stub, to be replaced by the real implementation when that is
90 * upstream (pending on a rewrite to be Gallium agnostic) */
91
92 return s_src;
93 }
94
95 void
96 panfrost_make_blend_shader(struct panfrost_context *ctx, struct panfrost_blend_state *cso, const struct pipe_blend_color *blend_color)
97 {
98 const struct pipe_rt_blend_state *blend = &cso->base.rt[0];
99 mali_ptr *out = &cso->blend_shader;
100
101 /* Build the shader */
102
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);
106
107 /* Create the blend variables */
108
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");
113
114 c_src->data.location = VARYING_SLOT_COL0;
115 c_dst->data.location = VARYING_SLOT_COL1;
116 c_out->data.location = FRAG_RESULT_COLOR;
117
118 /* Setup nir_builder */
119
120 nir_builder _b;
121 nir_builder *b = &_b;
122 nir_builder_init(b, impl);
123 b->cursor = nir_before_block(nir_start_block(impl));
124
125 /* Setup inputs */
126
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);
130
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);
133
134 if (pan_debug & PAN_DBG_SHADERS)
135 nir_print_shader(shader, stdout);
136
137 /* Compile the built shader */
138
139 midgard_program program;
140 midgard_compile_shader_nir(shader, &program, true);
141
142
143 /* Upload the shader */
144
145 int size = program.compiled.size;
146 uint8_t *dst = program.compiled.data;
147
148 /* Hot patch in constant color */
149
150 if (program.blend_patch_offset >= 0) {
151 float *hot_color = (float *) (dst + program.blend_patch_offset);
152
153 for (int c = 0; c < 4; ++c)
154 hot_color[c] = blend_color->color[c];
155 }
156
157 *out = panfrost_upload(&ctx->shaders, dst, size, true) | program.first_tag;
158
159 /* We need to switch to shader mode */
160 cso->has_blend_shader = true;
161
162 /* At least two work registers are needed due to an encoding quirk */
163 cso->blend_work_count = MAX2(program.work_register_count, 2);
164 }