1/* 2 * Copyright (c) 2017-2019 Lima Project 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, sub license, 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 12 * next paragraph) shall be included in all copies or substantial portions 13 * of the 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 NON-INFRINGEMENT. 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 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 * 23 */ 24 25#include "util/u_memory.h" 26#include "util/ralloc.h" 27#include "util/u_debug.h" 28 29#include "tgsi/tgsi_dump.h" 30#include "compiler/nir/nir.h" 31#include "nir/tgsi_to_nir.h" 32 33#include "pipe/p_state.h" 34 35#include "lima_screen.h" 36#include "lima_context.h" 37#include "lima_program.h" 38#include "lima_bo.h" 39#include "ir/lima_ir.h" 40 41static const nir_shader_compiler_options vs_nir_options = { 42 .lower_ffma = true, 43 .lower_fpow = true, 44 .lower_ffract = true, 45 .lower_fdiv = true, 46 .lower_fsqrt = true, 47 .lower_sub = true, 48 .lower_flrp32 = true, 49 .lower_flrp64 = true, 50 /* could be implemented by clamp */ 51 .lower_fsat = true, 52}; 53 54static const nir_shader_compiler_options fs_nir_options = { 55 .lower_fpow = true, 56 .lower_fdiv = true, 57 .lower_sub = true, 58 .lower_flrp32 = true, 59 .lower_flrp64 = true, 60 .lower_fsign = true, 61}; 62 63const void * 64lima_program_get_compiler_options(enum pipe_shader_type shader) 65{ 66 switch (shader) { 67 case PIPE_SHADER_VERTEX: 68 return &vs_nir_options; 69 case PIPE_SHADER_FRAGMENT: 70 return &fs_nir_options; 71 default: 72 return NULL; 73 } 74} 75 76static int 77type_size(const struct glsl_type *type, bool bindless) 78{ 79 return glsl_count_attribute_slots(type, false); 80} 81 82static void 83lima_program_optimize_vs_nir(struct nir_shader *s) 84{ 85 bool progress; 86 87 NIR_PASS_V(s, nir_lower_io, nir_var_all, type_size, 0); 88 NIR_PASS_V(s, nir_lower_regs_to_ssa); 89 NIR_PASS_V(s, nir_lower_load_const_to_scalar); 90 NIR_PASS_V(s, lima_nir_lower_uniform_to_scalar); 91 NIR_PASS_V(s, nir_lower_io_to_scalar, 92 nir_var_shader_in|nir_var_shader_out); 93 NIR_PASS_V(s, nir_lower_bool_to_float); 94 95 do { 96 progress = false; 97 98 NIR_PASS_V(s, nir_lower_vars_to_ssa); 99 NIR_PASS(progress, s, nir_lower_alu_to_scalar); 100 NIR_PASS(progress, s, nir_lower_phis_to_scalar); 101 NIR_PASS(progress, s, nir_copy_prop); 102 NIR_PASS(progress, s, nir_opt_remove_phis); 103 NIR_PASS(progress, s, nir_opt_dce); 104 NIR_PASS(progress, s, nir_opt_dead_cf); 105 NIR_PASS(progress, s, nir_opt_cse); 106 NIR_PASS(progress, s, nir_opt_peephole_select, 8, true, true); 107 NIR_PASS(progress, s, nir_opt_algebraic); 108 NIR_PASS(progress, s, nir_opt_constant_folding); 109 NIR_PASS(progress, s, nir_opt_undef); 110 NIR_PASS(progress, s, nir_opt_loop_unroll, 111 nir_var_shader_in | 112 nir_var_shader_out | 113 nir_var_function_temp); 114 } while (progress); 115 116 NIR_PASS_V(s, nir_lower_locals_to_regs); 117 NIR_PASS_V(s, nir_convert_from_ssa, true); 118 NIR_PASS_V(s, nir_remove_dead_variables, nir_var_function_temp); 119 nir_sweep(s); 120} 121 122static void 123lima_program_optimize_fs_nir(struct nir_shader *s) 124{ 125 bool progress; 126 127 NIR_PASS_V(s, nir_lower_fragcoord_wtrans); 128 NIR_PASS_V(s, nir_lower_io, nir_var_all, type_size, 0); 129 NIR_PASS_V(s, nir_lower_regs_to_ssa); 130 NIR_PASS_V(s, nir_lower_bool_to_float); 131 132 do { 133 progress = false; 134 135 NIR_PASS_V(s, nir_lower_vars_to_ssa); 136 //NIR_PASS(progress, s, nir_lower_alu_to_scalar); 137 NIR_PASS(progress, s, nir_lower_phis_to_scalar); 138 NIR_PASS(progress, s, nir_copy_prop); 139 NIR_PASS(progress, s, nir_opt_remove_phis); 140 NIR_PASS(progress, s, nir_opt_dce); 141 NIR_PASS(progress, s, nir_opt_dead_cf); 142 NIR_PASS(progress, s, nir_opt_cse); 143 NIR_PASS(progress, s, nir_opt_peephole_select, 8, true, true); 144 NIR_PASS(progress, s, nir_opt_algebraic); 145 NIR_PASS(progress, s, nir_opt_constant_folding); 146 NIR_PASS(progress, s, nir_opt_undef); 147 NIR_PASS(progress, s, nir_opt_loop_unroll, 148 nir_var_shader_in | 149 nir_var_shader_out | 150 nir_var_function_temp); 151 } while (progress); 152 153 /* Lower modifiers */ 154 NIR_PASS_V(s, nir_lower_to_source_mods, nir_lower_all_source_mods); 155 NIR_PASS_V(s, nir_copy_prop); 156 NIR_PASS_V(s, nir_opt_dce); 157 158 NIR_PASS_V(s, nir_lower_locals_to_regs); 159 NIR_PASS_V(s, nir_convert_from_ssa, true); 160 NIR_PASS_V(s, nir_remove_dead_variables, nir_var_function_temp); 161 162 NIR_PASS_V(s, nir_move_vec_src_uses_to_dest); 163 NIR_PASS_V(s, nir_lower_vec_to_movs); 164 165 nir_sweep(s); 166} 167 168static void * 169lima_create_fs_state(struct pipe_context *pctx, 170 const struct pipe_shader_state *cso) 171{ 172 struct lima_screen *screen = lima_screen(pctx->screen); 173 struct lima_fs_shader_state *so = rzalloc(NULL, struct lima_fs_shader_state); 174 175 if (!so) 176 return NULL; 177 178 nir_shader *nir; 179 if (cso->type == PIPE_SHADER_IR_NIR) 180 nir = cso->ir.nir; 181 else { 182 assert(cso->type == PIPE_SHADER_IR_TGSI); 183 184 nir = tgsi_to_nir(cso->tokens, pctx->screen); 185 } 186 187 lima_program_optimize_fs_nir(nir); 188 189 if (lima_debug & LIMA_DEBUG_PP) 190 nir_print_shader(nir, stdout); 191 192 if (!ppir_compile_nir(so, nir, screen->pp_ra)) { 193 ralloc_free(so); 194 return NULL; 195 } 196 197 return so; 198} 199 200static void 201lima_bind_fs_state(struct pipe_context *pctx, void *hwcso) 202{ 203 struct lima_context *ctx = lima_context(pctx); 204 205 ctx->fs = hwcso; 206 ctx->dirty |= LIMA_CONTEXT_DIRTY_SHADER_FRAG; 207} 208 209static void 210lima_delete_fs_state(struct pipe_context *pctx, void *hwcso) 211{ 212 struct lima_fs_shader_state *so = hwcso; 213 214 if (so->bo) 215 lima_bo_free(so->bo); 216 217 ralloc_free(so); 218} 219 220bool 221lima_update_vs_state(struct lima_context *ctx) 222{ 223 struct lima_vs_shader_state *vs = ctx->vs; 224 if (!vs->bo) { 225 struct lima_screen *screen = lima_screen(ctx->base.screen); 226 vs->bo = lima_bo_create(screen, vs->shader_size, 0); 227 if (!vs->bo) { 228 fprintf(stderr, "lima: create vs shader bo fail\n"); 229 return false; 230 } 231 232 memcpy(lima_bo_map(vs->bo), vs->shader, vs->shader_size); 233 ralloc_free(vs->shader); 234 vs->shader = NULL; 235 } 236 237 return true; 238} 239 240bool 241lima_update_fs_state(struct lima_context *ctx) 242{ 243 struct lima_fs_shader_state *fs = ctx->fs; 244 if (!fs->bo) { 245 struct lima_screen *screen = lima_screen(ctx->base.screen); 246 fs->bo = lima_bo_create(screen, fs->shader_size, 0); 247 if (!fs->bo) { 248 fprintf(stderr, "lima: create fs shader bo fail\n"); 249 return false; 250 } 251 252 memcpy(lima_bo_map(fs->bo), fs->shader, fs->shader_size); 253 ralloc_free(fs->shader); 254 fs->shader = NULL; 255 } 256 257 return true; 258} 259 260static void * 261lima_create_vs_state(struct pipe_context *pctx, 262 const struct pipe_shader_state *cso) 263{ 264 struct lima_vs_shader_state *so = rzalloc(NULL, struct lima_vs_shader_state); 265 266 if (!so) 267 return NULL; 268 269 nir_shader *nir; 270 if (cso->type == PIPE_SHADER_IR_NIR) 271 nir = cso->ir.nir; 272 else { 273 assert(cso->type == PIPE_SHADER_IR_TGSI); 274 275 nir = tgsi_to_nir(cso->tokens, pctx->screen); 276 } 277 278 lima_program_optimize_vs_nir(nir); 279 280 if (lima_debug & LIMA_DEBUG_GP) 281 nir_print_shader(nir, stdout); 282 283 if (!gpir_compile_nir(so, nir)) { 284 ralloc_free(so); 285 return NULL; 286 } 287 288 return so; 289} 290 291static void 292lima_bind_vs_state(struct pipe_context *pctx, void *hwcso) 293{ 294 struct lima_context *ctx = lima_context(pctx); 295 296 ctx->vs = hwcso; 297 ctx->dirty |= LIMA_CONTEXT_DIRTY_SHADER_VERT; 298} 299 300static void 301lima_delete_vs_state(struct pipe_context *pctx, void *hwcso) 302{ 303 struct lima_vs_shader_state *so = hwcso; 304 305 if (so->bo) 306 lima_bo_free(so->bo); 307 308 ralloc_free(so); 309} 310 311void 312lima_program_init(struct lima_context *ctx) 313{ 314 ctx->base.create_fs_state = lima_create_fs_state; 315 ctx->base.bind_fs_state = lima_bind_fs_state; 316 ctx->base.delete_fs_state = lima_delete_fs_state; 317 318 ctx->base.create_vs_state = lima_create_vs_state; 319 ctx->base.bind_vs_state = lima_bind_vs_state; 320 ctx->base.delete_vs_state = lima_delete_vs_state; 321} 322