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"
29 //#include "include/panfrost-job.h"
30 #include "midgard/midgard_compile.h"
31 #include "compiler/nir/nir_builder.h"
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 */
38 panfrost_build_wallpaper_program()
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
);
44 /* Create the variables variables */
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");
49 c_texcoord
->data
.location
= VARYING_SLOT_VAR0
;
50 c_out
->data
.location
= FRAG_RESULT_COLOR
;
52 /* Setup nir_builder */
56 nir_builder_init(b
, impl
);
57 b
->cursor
= nir_before_block(nir_start_block(impl
));
61 nir_ssa_def
*s_src
= nir_load_var(b
, c_texcoord
);
63 /* Build the passthrough texture shader */
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
;
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
;
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
);
78 nir_ssa_def
*texel
= &tx
->dest
.ssa
;
80 nir_store_var(b
, c_out
, texel
, 0xFF);
82 if (pan_debug
& PAN_DBG_SHADERS
)
83 nir_print_shader(shader
, stdout
);
88 /* Creates the CSO corresponding to the wallpaper program */
90 static struct panfrost_shader_variants
*
91 panfrost_create_wallpaper_program(struct pipe_context
*pctx
)
93 nir_shader
*built_nir_shader
= panfrost_build_wallpaper_program();
95 struct pipe_shader_state so
= {
96 .type
= PIPE_SHADER_IR_NIR
,
98 .nir
= built_nir_shader
102 return pctx
->create_fs_state(pctx
, &so
);
105 static struct panfrost_shader_variants
*wallpaper_program
= NULL
;
106 static struct panfrost_shader_variants
*wallpaper_saved_program
= NULL
;
109 panfrost_enable_wallpaper_program(struct pipe_context
*pctx
)
111 struct panfrost_context
*ctx
= pan_context(pctx
);
113 if (!wallpaper_program
) {
114 wallpaper_program
= panfrost_create_wallpaper_program(pctx
);
117 /* Push the shader state */
118 wallpaper_saved_program
= ctx
->fs
;
120 /* Bind the program */
121 pctx
->bind_fs_state(pctx
, wallpaper_program
);
125 panfrost_disable_wallpaper_program(struct pipe_context
*pctx
)
127 /* Pop off the shader state */
128 pctx
->bind_fs_state(pctx
, wallpaper_saved_program
);
131 /* Essentially, we insert a fullscreen textured quad, reading from the
132 * previous frame's framebuffer */
135 panfrost_draw_wallpaper(struct pipe_context
*pipe
)
137 /* Disable wallpapering for now, but still exercise the shader generation to minimise bit rot */
139 panfrost_enable_wallpaper_program(pipe
);
140 panfrost_disable_wallpaper_program(pipe
);
145 struct panfrost_context
*ctx
= pan_context(pipe
);
147 /* Setup payload for elided quad. TODO: Refactor draw_vbo so this can
148 * be a little more DRY */
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
;
161 /* Setup the wallpapering program. We need to build the program via
164 panfrost_enable_wallpaper_program(pipe
);
166 /* Setup the texture/sampler pair */
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
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
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
);
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
);
194 panfrost_emit_for_draw(ctx
, false);
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 */
202 float implied_position_varying
[] = {
203 /* The following is correct for scissored clears whose scissor deals with cutoff appropriately */
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
210 /* The following output is correct for a fullscreen quad with screen size 2048x1600 */
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,
217 ctx
->payload_tiler
.postfix
.position_varying
= panfrost_upload_transient(ctx
, implied_position_varying
, sizeof(implied_position_varying
));
219 /* Similarly, setup the texture coordinate varying, hardcoded to match
220 * the corners of the screen */
222 float texture_coordinates
[] = {
229 union mali_attr varyings
[1] = {
231 .elements
= panfrost_upload_transient(ctx
, texture_coordinates
, sizeof(texture_coordinates
)) | 1,
232 .stride
= sizeof(float) * 4,
233 .size
= sizeof(texture_coordinates
)
237 ctx
->payload_tiler
.postfix
.varyings
= panfrost_upload_transient(ctx
, varyings
, sizeof(varyings
));
239 struct mali_attr_meta varying_meta
[1] = {
241 .type
= MALI_ATYPE_FLOAT
,
242 .nr_components
= MALI_POSITIVE(4),
244 .unknown1
= /*0x2c22 - nr_comp=2*/ 0x2a22,
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
));
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
;
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
267 if (ctx
->tiler_job_count
> 1) {
268 ctx
->u_tiler_jobs
[0]->job_dependency_index_2
= jd
->job_index
;
271 printf("Wallpaper boop\n");
274 panfrost_disable_wallpaper_program(pipe
);
275 ctx
->payload_tiler
.postfix
.varying_meta
= saved_varying_meta
;