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 37static nir_shader * 38panfrost_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 return shader; 83} 84 85/* Creates the CSO corresponding to the wallpaper program */ 86 87static struct panfrost_shader_variants * 88panfrost_create_wallpaper_program(struct pipe_context *pctx) 89{ 90 nir_shader *built_nir_shader = panfrost_build_wallpaper_program(); 91 92 struct pipe_shader_state so = { 93 .type = PIPE_SHADER_IR_NIR, 94 .ir = { 95 .nir = built_nir_shader 96 } 97 }; 98 99 return pctx->create_fs_state(pctx, &so); 100} 101 102static struct panfrost_shader_variants *wallpaper_program = NULL; 103static struct panfrost_shader_variants *wallpaper_saved_program = NULL; 104 105static void 106panfrost_enable_wallpaper_program(struct pipe_context *pctx) 107{ 108 struct panfrost_context *ctx = pan_context(pctx); 109 110 if (!wallpaper_program) { 111 wallpaper_program = panfrost_create_wallpaper_program(pctx); 112 } 113 114 /* Push the shader state */ 115 wallpaper_saved_program = ctx->fs; 116 117 /* Bind the program */ 118 pctx->bind_fs_state(pctx, wallpaper_program); 119} 120 121static void 122panfrost_disable_wallpaper_program(struct pipe_context *pctx) 123{ 124 /* Pop off the shader state */ 125 pctx->bind_fs_state(pctx, wallpaper_saved_program); 126} 127 128/* Essentially, we insert a fullscreen textured quad, reading from the 129 * previous frame's framebuffer */ 130 131void 132panfrost_draw_wallpaper(struct pipe_context *pipe) 133{ 134 /* Disable wallpapering for now, but still exercise the shader generation to minimise bit rot */ 135 136 panfrost_enable_wallpaper_program(pipe); 137 panfrost_disable_wallpaper_program(pipe); 138 139 return; 140 141#if 0 142 struct panfrost_context *ctx = pan_context(pipe); 143 144 /* Setup payload for elided quad. TODO: Refactor draw_vbo so this can 145 * be a little more DRY */ 146 147 ctx->payload_tiler.draw_start = 0; 148 ctx->payload_tiler.prefix.draw_mode = MALI_TRIANGLE_STRIP; 149 ctx->vertex_count = 4; 150 ctx->payload_tiler.prefix.invocation_count = MALI_POSITIVE(4); 151 ctx->payload_tiler.prefix.unknown_draw &= ~(0x3000 | 0x18000); 152 ctx->payload_tiler.prefix.unknown_draw |= 0x18000; 153 ctx->payload_tiler.prefix.negative_start = 0; 154 ctx->payload_tiler.prefix.index_count = MALI_POSITIVE(4); 155 ctx->payload_tiler.prefix.unknown_draw &= ~MALI_DRAW_INDEXED_UINT32; 156 ctx->payload_tiler.prefix.indices = (uintptr_t) NULL; 157 158 /* Setup the wallpapering program. We need to build the program via 159 * NIR. */ 160 161 panfrost_enable_wallpaper_program(pipe); 162 163 /* Setup the texture/sampler pair */ 164 165 struct pipe_sampler_view tmpl = { 166 .target = PIPE_TEXTURE_2D, 167 .swizzle_r = PIPE_SWIZZLE_X, 168 .swizzle_g = PIPE_SWIZZLE_Y, 169 .swizzle_b = PIPE_SWIZZLE_Z, 170 .swizzle_a = PIPE_SWIZZLE_W 171 }; 172 173 struct pipe_sampler_state state = { 174 .min_mip_filter = PIPE_TEX_MIPFILTER_NONE, 175 .min_img_filter = PIPE_TEX_MIPFILTER_LINEAR, 176 .mag_img_filter = PIPE_TEX_MIPFILTER_LINEAR, 177 .wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE, 178 .wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE, 179 .wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE, 180 .normalized_coords = 1 181 }; 182 183 struct pipe_resource *rsrc = pan_screen(pipe->screen)->display_target; 184 struct pipe_sampler_state *sampler_state = pipe->create_sampler_state(pipe, &state); 185 struct pipe_sampler_view *sampler_view = pipe->create_sampler_view(pipe, rsrc, &tmpl); 186 187 /* Bind texture/sampler. TODO: push/pop */ 188 pipe->bind_sampler_states(pipe, PIPE_SHADER_FRAGMENT, 0, 1, &sampler_state); 189 pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, 1, &sampler_view); 190 191 panfrost_emit_for_draw(ctx, false); 192 193 /* Elision occurs by essential precomputing the results of the 194 * implied vertex shader. Insert these results for fullscreen. The 195 * first two channels are ~screenspace coordinates, whereas the latter 196 * two are fixed 0.0/1.0 after perspective division. See the vertex 197 * shader epilogue for more context */ 198 199 float implied_position_varying[] = { 200 /* The following is correct for scissored clears whose scissor deals with cutoff appropriately */ 201 202// -1.0, -1.0, 0.0, 1.0, 203// -1.0, 65535.0, 0.0, 1.0, 204// 65536.0, 1.0, 0.0, 1.0, 205// 65536.0, 65536.0, 0.0, 1.0 206 207 /* The following output is correct for a fullscreen quad with screen size 2048x1600 */ 208 0.0, 0.0, 0.0, 1.0, 209 0.0, 1600.0, 0.0, 1.0, 210 2048.0, 0.0, 0.0, 1.0, 211 2048.0, 1280.0, 0.0, 1.0, 212 }; 213 214 ctx->payload_tiler.postfix.position_varying = panfrost_upload_transient(ctx, implied_position_varying, sizeof(implied_position_varying)); 215 216 /* Similarly, setup the texture coordinate varying, hardcoded to match 217 * the corners of the screen */ 218 219 float texture_coordinates[] = { 220 0.0, 0.0, 0.0, 0.0, 221 0.0, 1.0, 0.0, 0.0, 222 1.0, 0.0, 0.0, 0.0, 223 1.0, 1.0, 0.0, 0.0 224 }; 225 226 union mali_attr varyings[1] = { 227 { 228 .elements = panfrost_upload_transient(ctx, texture_coordinates, sizeof(texture_coordinates)) | 1, 229 .stride = sizeof(float) * 4, 230 .size = sizeof(texture_coordinates) 231 } 232 }; 233 234 ctx->payload_tiler.postfix.varyings = panfrost_upload_transient(ctx, varyings, sizeof(varyings)); 235 236 struct mali_attr_meta varying_meta[1] = { 237 { 238 .type = MALI_ATYPE_FLOAT, 239 .nr_components = MALI_POSITIVE(4), 240 .not_normalised = 1, 241 .unknown1 = /*0x2c22 - nr_comp=2*/ 0x2a22, 242 .unknown2 = 0x1 243 } 244 }; 245 246 mali_ptr saved_varying_meta = ctx->payload_tiler.postfix.varying_meta; 247 ctx->payload_tiler.postfix.varying_meta = panfrost_upload_transient(ctx, varying_meta, sizeof(varying_meta)); 248 249 /* Emit the tiler job */ 250 struct panfrost_transfer tiler = panfrost_vertex_tiler_job(ctx, true, true); 251 struct mali_job_descriptor_header *jd = (struct mali_job_descriptor_header *) tiler.cpu; 252 ctx->u_tiler_jobs[ctx->tiler_job_count] = jd; 253 ctx->tiler_jobs[ctx->tiler_job_count++] = tiler.gpu; 254 ctx->draw_count++; 255 256 /* Okay, so we have the tiler job emitted. Since we set elided_tiler 257 * mode, no dependencies will be set automatically. We don't actually 258 * want any dependencies, since we go first and we don't need a vertex 259 * first. That said, we do need the first tiler job to depend on us. 260 * Its second dep slot will be free (see the panfrost_vertex_tiler_job 261 * dependency setting algorithm), so fill us in with that 262 */ 263 264 if (ctx->tiler_job_count > 1) { 265 ctx->u_tiler_jobs[0]->job_dependency_index_2 = jd->job_index; 266 } 267 268 printf("Wallpaper boop\n"); 269 270 /* Cleanup */ 271 panfrost_disable_wallpaper_program(pipe); 272 ctx->payload_tiler.postfix.varying_meta = saved_varying_meta; 273#endif 274} 275