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
25 #include "pan_wallpaper.h"
26 #include "pan_context.h"
27 #include "pan_screen.h"
28 //#include "include/panfrost-job.h"
29 #include "midgard/midgard_compile.h"
30 #include "compiler/nir/nir_builder.h"
32 /* Creates the special-purpose fragment shader for wallpapering. A
33 * pseudo-vertex shader sets us up for a fullscreen quad render, with a texture
34 * coordinate varying */
37 panfrost_build_wallpaper_program()
39 nir_shader
*shader
= nir_shader_create(NULL
, MESA_SHADER_FRAGMENT
, &midgard_nir_options
, NULL
);
40 nir_function
*fn
= nir_function_create(shader
, "main");
41 nir_function_impl
*impl
= nir_function_impl_create(fn
);
43 /* Create the variables variables */
45 nir_variable
*c_texcoord
= nir_variable_create(shader
, nir_var_shader_in
, glsl_vector_type(GLSL_TYPE_FLOAT
, 4), "gl_TexCoord");
46 nir_variable
*c_out
= nir_variable_create(shader
, nir_var_shader_out
, glsl_vector_type(GLSL_TYPE_FLOAT
, 4), "gl_FragColor");
48 c_texcoord
->data
.location
= VARYING_SLOT_VAR0
;
49 c_out
->data
.location
= FRAG_RESULT_COLOR
;
51 /* Setup nir_builder */
55 nir_builder_init(b
, impl
);
56 b
->cursor
= nir_before_block(nir_start_block(impl
));
60 nir_ssa_def
*s_src
= nir_load_var(b
, c_texcoord
);
62 /* Build the passthrough texture shader */
64 nir_tex_instr
*tx
= nir_tex_instr_create(shader
, 1);
65 tx
->op
= nir_texop_tex
;
66 tx
->texture_index
= tx
->sampler_index
= 0;
67 tx
->sampler_dim
= GLSL_SAMPLER_DIM_2D
;
68 tx
->dest_type
= nir_type_float
;
70 nir_src src
= nir_src_for_ssa(s_src
);
71 nir_src_copy(&tx
->src
[0].src
, &src
, tx
);
72 tx
->src
[0].src_type
= nir_tex_src_coord
;
74 nir_ssa_dest_init(&tx
->instr
, &tx
->dest
, nir_tex_instr_dest_size(tx
), 32, NULL
);
75 nir_builder_instr_insert(b
, &tx
->instr
);
77 nir_ssa_def
*texel
= &tx
->dest
.ssa
;
79 nir_store_var(b
, c_out
, texel
, 0xFF);
81 nir_print_shader(shader
, stdout
);
86 /* Creates the CSO corresponding to the wallpaper program */
88 static struct panfrost_shader_variants
*
89 panfrost_create_wallpaper_program(struct pipe_context
*pctx
)
91 nir_shader
*built_nir_shader
= panfrost_build_wallpaper_program();
93 struct pipe_shader_state so
= {
94 .type
= PIPE_SHADER_IR_NIR
,
96 .nir
= built_nir_shader
100 return pctx
->create_fs_state(pctx
, &so
);
103 static struct panfrost_shader_variants
*wallpaper_program
= NULL
;
104 static struct panfrost_shader_variants
*wallpaper_saved_program
= NULL
;
107 panfrost_enable_wallpaper_program(struct pipe_context
*pctx
)
109 struct panfrost_context
*ctx
= pan_context(pctx
);
111 if (!wallpaper_program
) {
112 wallpaper_program
= panfrost_create_wallpaper_program(pctx
);
115 /* Push the shader state */
116 wallpaper_saved_program
= ctx
->fs
;
118 /* Bind the program */
119 pctx
->bind_fs_state(pctx
, wallpaper_program
);
123 panfrost_disable_wallpaper_program(struct pipe_context
*pctx
)
125 /* Pop off the shader state */
126 pctx
->bind_fs_state(pctx
, wallpaper_saved_program
);
129 /* Essentially, we insert a fullscreen textured quad, reading from the
130 * previous frame's framebuffer */
133 panfrost_draw_wallpaper(struct pipe_context
*pipe
)
135 /* Disable wallpapering for now, but still exercise the shader generation to minimise bit rot */
137 panfrost_enable_wallpaper_program(pipe
);
138 panfrost_disable_wallpaper_program(pipe
);
143 struct panfrost_context
*ctx
= pan_context(pipe
);
145 /* Setup payload for elided quad. TODO: Refactor draw_vbo so this can
146 * be a little more DRY */
148 ctx
->payload_tiler
.draw_start
= 0;
149 ctx
->payload_tiler
.prefix
.draw_mode
= MALI_TRIANGLE_STRIP
;
150 ctx
->vertex_count
= 4;
151 ctx
->payload_tiler
.prefix
.invocation_count
= MALI_POSITIVE(4);
152 ctx
->payload_tiler
.prefix
.unknown_draw
&= ~(0x3000 | 0x18000);
153 ctx
->payload_tiler
.prefix
.unknown_draw
|= 0x18000;
154 ctx
->payload_tiler
.prefix
.negative_start
= 0;
155 ctx
->payload_tiler
.prefix
.index_count
= MALI_POSITIVE(4);
156 ctx
->payload_tiler
.prefix
.unknown_draw
&= ~MALI_DRAW_INDEXED_UINT32
;
157 ctx
->payload_tiler
.prefix
.indices
= (uintptr_t) NULL
;
159 /* Setup the wallpapering program. We need to build the program via
162 panfrost_enable_wallpaper_program(pipe
);
164 /* Setup the texture/sampler pair */
166 struct pipe_sampler_view tmpl
= {
167 .target
= PIPE_TEXTURE_2D
,
168 .swizzle_r
= PIPE_SWIZZLE_X
,
169 .swizzle_g
= PIPE_SWIZZLE_Y
,
170 .swizzle_b
= PIPE_SWIZZLE_Z
,
171 .swizzle_a
= PIPE_SWIZZLE_W
174 struct pipe_sampler_state state
= {
175 .min_mip_filter
= PIPE_TEX_MIPFILTER_NONE
,
176 .min_img_filter
= PIPE_TEX_MIPFILTER_LINEAR
,
177 .mag_img_filter
= PIPE_TEX_MIPFILTER_LINEAR
,
178 .wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
,
179 .wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
,
180 .wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
,
181 .normalized_coords
= 1
184 struct pipe_resource
*rsrc
= panfrost_screen(pipe
->screen
)->display_target
;
185 struct pipe_sampler_state
*sampler_state
= pipe
->create_sampler_state(pipe
, &state
);
186 struct pipe_sampler_view
*sampler_view
= pipe
->create_sampler_view(pipe
, rsrc
, &tmpl
);
188 /* Bind texture/sampler. TODO: push/pop */
189 pipe
->bind_sampler_states(pipe
, PIPE_SHADER_FRAGMENT
, 0, 1, &sampler_state
);
190 pipe
->set_sampler_views(pipe
, PIPE_SHADER_FRAGMENT
, 0, 1, &sampler_view
);
192 panfrost_emit_for_draw(ctx
, false);
194 /* Elision occurs by essential precomputing the results of the
195 * implied vertex shader. Insert these results for fullscreen. The
196 * first two channels are ~screenspace coordinates, whereas the latter
197 * two are fixed 0.0/1.0 after perspective division. See the vertex
198 * shader epilogue for more context */
200 float implied_position_varying
[] = {
201 /* The following is correct for scissored clears whose scissor deals with cutoff appropriately */
203 // -1.0, -1.0, 0.0, 1.0,
204 // -1.0, 65535.0, 0.0, 1.0,
205 // 65536.0, 1.0, 0.0, 1.0,
206 // 65536.0, 65536.0, 0.0, 1.0
208 /* The following output is correct for a fullscreen quad with screen size 2048x1600 */
210 0.0, 1600.0, 0.0, 1.0,
211 2048.0, 0.0, 0.0, 1.0,
212 2048.0, 1280.0, 0.0, 1.0,
215 ctx
->payload_tiler
.postfix
.position_varying
= panfrost_upload_transient(ctx
, implied_position_varying
, sizeof(implied_position_varying
));
217 /* Similarly, setup the texture coordinate varying, hardcoded to match
218 * the corners of the screen */
220 float texture_coordinates
[] = {
227 union mali_attr varyings
[1] = {
229 .elements
= panfrost_upload_transient(ctx
, texture_coordinates
, sizeof(texture_coordinates
)) | 1,
230 .stride
= sizeof(float) * 4,
231 .size
= sizeof(texture_coordinates
)
235 ctx
->payload_tiler
.postfix
.varyings
= panfrost_upload_transient(ctx
, varyings
, sizeof(varyings
));
237 struct mali_attr_meta varying_meta
[1] = {
239 .type
= MALI_ATYPE_FLOAT
,
240 .nr_components
= MALI_POSITIVE(4),
242 .unknown1
= /*0x2c22 - nr_comp=2*/ 0x2a22,
247 mali_ptr saved_varying_meta
= ctx
->payload_tiler
.postfix
.varying_meta
;
248 ctx
->payload_tiler
.postfix
.varying_meta
= panfrost_upload_transient(ctx
, varying_meta
, sizeof(varying_meta
));
250 /* Emit the tiler job */
251 struct panfrost_transfer tiler
= panfrost_vertex_tiler_job(ctx
, true, true);
252 struct mali_job_descriptor_header
*jd
= (struct mali_job_descriptor_header
*) tiler
.cpu
;
253 ctx
->u_tiler_jobs
[ctx
->tiler_job_count
] = jd
;
254 ctx
->tiler_jobs
[ctx
->tiler_job_count
++] = tiler
.gpu
;
257 /* Okay, so we have the tiler job emitted. Since we set elided_tiler
258 * mode, no dependencies will be set automatically. We don't actually
259 * want any dependencies, since we go first and we don't need a vertex
260 * first. That said, we do need the first tiler job to depend on us.
261 * Its second dep slot will be free (see the panfrost_vertex_tiler_job
262 * dependency setting algorithm), so fill us in with that
265 if (ctx
->tiler_job_count
> 1) {
266 ctx
->u_tiler_jobs
[0]->job_dependency_index_2
= jd
->job_index
;
269 printf("Wallpaper boop\n");
272 panfrost_disable_wallpaper_program(pipe
);
273 ctx
->payload_tiler
.postfix
.varying_meta
= saved_varying_meta
;