panfrost: Break out fragment to SFBD/MFBD files
[mesa.git] / src / gallium / drivers / panfrost / pan_wallpaper.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 "pan_wallpaper.h"
26 #include "pan_context.h"
27 #include "pan_screen.h"
28 #include "pan_util.h"
29 //#include "include/panfrost-job.h"
30 #include "midgard/midgard_compile.h"
31 #include "compiler/nir/nir_builder.h"
32
33 /* Creates the special-purpose fragment shader for wallpapering. A
34 * pseudo-vertex shader sets us up for a fullscreen quad render, with a texture
35 * coordinate varying */
36
37 static nir_shader *
38 panfrost_build_wallpaper_program()
39 {
40 nir_shader *shader = nir_shader_create(NULL, MESA_SHADER_FRAGMENT, &midgard_nir_options, NULL);
41 nir_function *fn = nir_function_create(shader, "main");
42 nir_function_impl *impl = nir_function_impl_create(fn);
43
44 /* Create the variables variables */
45
46 nir_variable *c_texcoord = nir_variable_create(shader, nir_var_shader_in, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_TexCoord");
47 nir_variable *c_out = nir_variable_create(shader, nir_var_shader_out, glsl_vector_type(GLSL_TYPE_FLOAT, 4), "gl_FragColor");
48
49 c_texcoord->data.location = VARYING_SLOT_VAR0;
50 c_out->data.location = FRAG_RESULT_COLOR;
51
52 /* Setup nir_builder */
53
54 nir_builder _b;
55 nir_builder *b = &_b;
56 nir_builder_init(b, impl);
57 b->cursor = nir_before_block(nir_start_block(impl));
58
59 /* Setup inputs */
60
61 nir_ssa_def *s_src = nir_load_var(b, c_texcoord);
62
63 /* Build the passthrough texture shader */
64
65 nir_tex_instr *tx = nir_tex_instr_create(shader, 1);
66 tx->op = nir_texop_tex;
67 tx->texture_index = tx->sampler_index = 0;
68 tx->sampler_dim = GLSL_SAMPLER_DIM_2D;
69 tx->dest_type = nir_type_float;
70
71 nir_src src = nir_src_for_ssa(s_src);
72 nir_src_copy(&tx->src[0].src, &src, tx);
73 tx->src[0].src_type = nir_tex_src_coord;
74
75 nir_ssa_dest_init(&tx->instr, &tx->dest, nir_tex_instr_dest_size(tx), 32, NULL);
76 nir_builder_instr_insert(b, &tx->instr);
77
78 nir_ssa_def *texel = &tx->dest.ssa;
79
80 nir_store_var(b, c_out, texel, 0xFF);
81
82 if (pan_debug & PAN_DBG_SHADERS)
83 nir_print_shader(shader, stdout);
84
85 return shader;
86 }
87
88 /* Creates the CSO corresponding to the wallpaper program */
89
90 static struct panfrost_shader_variants *
91 panfrost_create_wallpaper_program(struct pipe_context *pctx)
92 {
93 nir_shader *built_nir_shader = panfrost_build_wallpaper_program();
94
95 struct pipe_shader_state so = {
96 .type = PIPE_SHADER_IR_NIR,
97 .ir = {
98 .nir = built_nir_shader
99 }
100 };
101
102 return pctx->create_fs_state(pctx, &so);
103 }
104
105 static struct panfrost_shader_variants *wallpaper_program = NULL;
106 static struct panfrost_shader_variants *wallpaper_saved_program = NULL;
107
108 static void
109 panfrost_enable_wallpaper_program(struct pipe_context *pctx)
110 {
111 struct panfrost_context *ctx = pan_context(pctx);
112
113 if (!wallpaper_program) {
114 wallpaper_program = panfrost_create_wallpaper_program(pctx);
115 }
116
117 /* Push the shader state */
118 wallpaper_saved_program = ctx->fs;
119
120 /* Bind the program */
121 pctx->bind_fs_state(pctx, wallpaper_program);
122 }
123
124 static void
125 panfrost_disable_wallpaper_program(struct pipe_context *pctx)
126 {
127 /* Pop off the shader state */
128 pctx->bind_fs_state(pctx, wallpaper_saved_program);
129 }
130
131 /* Essentially, we insert a fullscreen textured quad, reading from the
132 * previous frame's framebuffer */
133
134 void
135 panfrost_draw_wallpaper(struct pipe_context *pipe)
136 {
137 /* Disable wallpapering for now, but still exercise the shader generation to minimise bit rot */
138
139 panfrost_enable_wallpaper_program(pipe);
140 panfrost_disable_wallpaper_program(pipe);
141
142 return;
143
144 #if 0
145 struct panfrost_context *ctx = pan_context(pipe);
146
147 /* Setup payload for elided quad. TODO: Refactor draw_vbo so this can
148 * be a little more DRY */
149
150 ctx->payload_tiler.draw_start = 0;
151 ctx->payload_tiler.prefix.draw_mode = MALI_TRIANGLE_STRIP;
152 ctx->vertex_count = 4;
153 ctx->payload_tiler.prefix.invocation_count = MALI_POSITIVE(4);
154 ctx->payload_tiler.prefix.unknown_draw &= ~(0x3000 | 0x18000);
155 ctx->payload_tiler.prefix.unknown_draw |= 0x18000;
156 ctx->payload_tiler.prefix.negative_start = 0;
157 ctx->payload_tiler.prefix.index_count = MALI_POSITIVE(4);
158 ctx->payload_tiler.prefix.unknown_draw &= ~MALI_DRAW_INDEXED_UINT32;
159 ctx->payload_tiler.prefix.indices = (uintptr_t) NULL;
160
161 /* Setup the wallpapering program. We need to build the program via
162 * NIR. */
163
164 panfrost_enable_wallpaper_program(pipe);
165
166 /* Setup the texture/sampler pair */
167
168 struct pipe_sampler_view tmpl = {
169 .target = PIPE_TEXTURE_2D,
170 .swizzle_r = PIPE_SWIZZLE_X,
171 .swizzle_g = PIPE_SWIZZLE_Y,
172 .swizzle_b = PIPE_SWIZZLE_Z,
173 .swizzle_a = PIPE_SWIZZLE_W
174 };
175
176 struct pipe_sampler_state state = {
177 .min_mip_filter = PIPE_TEX_MIPFILTER_NONE,
178 .min_img_filter = PIPE_TEX_MIPFILTER_LINEAR,
179 .mag_img_filter = PIPE_TEX_MIPFILTER_LINEAR,
180 .wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE,
181 .wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE,
182 .wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE,
183 .normalized_coords = 1
184 };
185
186 struct pipe_resource *rsrc = pan_screen(pipe->screen)->display_target;
187 struct pipe_sampler_state *sampler_state = pipe->create_sampler_state(pipe, &state);
188 struct pipe_sampler_view *sampler_view = pipe->create_sampler_view(pipe, rsrc, &tmpl);
189
190 /* Bind texture/sampler. TODO: push/pop */
191 pipe->bind_sampler_states(pipe, PIPE_SHADER_FRAGMENT, 0, 1, &sampler_state);
192 pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, 1, &sampler_view);
193
194 panfrost_emit_for_draw(ctx, false);
195
196 /* Elision occurs by essential precomputing the results of the
197 * implied vertex shader. Insert these results for fullscreen. The
198 * first two channels are ~screenspace coordinates, whereas the latter
199 * two are fixed 0.0/1.0 after perspective division. See the vertex
200 * shader epilogue for more context */
201
202 float implied_position_varying[] = {
203 /* The following is correct for scissored clears whose scissor deals with cutoff appropriately */
204
205 // -1.0, -1.0, 0.0, 1.0,
206 // -1.0, 65535.0, 0.0, 1.0,
207 // 65536.0, 1.0, 0.0, 1.0,
208 // 65536.0, 65536.0, 0.0, 1.0
209
210 /* The following output is correct for a fullscreen quad with screen size 2048x1600 */
211 0.0, 0.0, 0.0, 1.0,
212 0.0, 1600.0, 0.0, 1.0,
213 2048.0, 0.0, 0.0, 1.0,
214 2048.0, 1280.0, 0.0, 1.0,
215 };
216
217 ctx->payload_tiler.postfix.position_varying = panfrost_upload_transient(ctx, implied_position_varying, sizeof(implied_position_varying));
218
219 /* Similarly, setup the texture coordinate varying, hardcoded to match
220 * the corners of the screen */
221
222 float texture_coordinates[] = {
223 0.0, 0.0, 0.0, 0.0,
224 0.0, 1.0, 0.0, 0.0,
225 1.0, 0.0, 0.0, 0.0,
226 1.0, 1.0, 0.0, 0.0
227 };
228
229 union mali_attr varyings[1] = {
230 {
231 .elements = panfrost_upload_transient(ctx, texture_coordinates, sizeof(texture_coordinates)) | 1,
232 .stride = sizeof(float) * 4,
233 .size = sizeof(texture_coordinates)
234 }
235 };
236
237 ctx->payload_tiler.postfix.varyings = panfrost_upload_transient(ctx, varyings, sizeof(varyings));
238
239 struct mali_attr_meta varying_meta[1] = {
240 {
241 .type = MALI_ATYPE_FLOAT,
242 .nr_components = MALI_POSITIVE(4),
243 .not_normalised = 1,
244 .unknown1 = /*0x2c22 - nr_comp=2*/ 0x2a22,
245 .unknown2 = 0x1
246 }
247 };
248
249 mali_ptr saved_varying_meta = ctx->payload_tiler.postfix.varying_meta;
250 ctx->payload_tiler.postfix.varying_meta = panfrost_upload_transient(ctx, varying_meta, sizeof(varying_meta));
251
252 /* Emit the tiler job */
253 struct panfrost_transfer tiler = panfrost_vertex_tiler_job(ctx, true, true);
254 struct mali_job_descriptor_header *jd = (struct mali_job_descriptor_header *) tiler.cpu;
255 ctx->u_tiler_jobs[ctx->tiler_job_count] = jd;
256 ctx->tiler_jobs[ctx->tiler_job_count++] = tiler.gpu;
257 ctx->draw_count++;
258
259 /* Okay, so we have the tiler job emitted. Since we set elided_tiler
260 * mode, no dependencies will be set automatically. We don't actually
261 * want any dependencies, since we go first and we don't need a vertex
262 * first. That said, we do need the first tiler job to depend on us.
263 * Its second dep slot will be free (see the panfrost_vertex_tiler_job
264 * dependency setting algorithm), so fill us in with that
265 */
266
267 if (ctx->tiler_job_count > 1) {
268 ctx->u_tiler_jobs[0]->job_dependency_index_2 = jd->job_index;
269 }
270
271 printf("Wallpaper boop\n");
272
273 /* Cleanup */
274 panfrost_disable_wallpaper_program(pipe);
275 ctx->payload_tiler.postfix.varying_meta = saved_varying_meta;
276 #endif
277 }