From: Timur Kristóf Date: Tue, 5 Mar 2019 17:59:47 +0000 (+0100) Subject: tgsi_to_nir: Produce optimized NIR for a given pipe_screen. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=9a834447d652ea50864bb6c32f4ff99ac10d39bf;p=mesa.git tgsi_to_nir: Produce optimized NIR for a given pipe_screen. With this patch, tgsi_to_nir will output NIR that is tailored to the given pipe, by reading its capabilities and adjusting the NIR code to those capabilities similarly to how glsl_to_nir works. It also adds an optimization loop that brings the output NIR in line with what glsl_to_nir outputs. This is necessary for the same reason why glsl_to_nir has its own optimization loop: currently not every driver does these optimizations yet. For uses which cannot pass a pipe_screen we also keep a variant called tgsi_to_nir_noscreen which keeps the old behavior. Signed-Off-By: Timur Kristóf Tested-by: Andre Heider Tested-by: Rob Clark Acked-By: Eric Anholt --- diff --git a/src/gallium/auxiliary/meson.build b/src/gallium/auxiliary/meson.build index 6e5109eb97e..ca72e81e51d 100644 --- a/src/gallium/auxiliary/meson.build +++ b/src/gallium/auxiliary/meson.build @@ -534,6 +534,9 @@ libgallium = static_library( idep_nir_headers, ], build_by_default : false, + link_with: [ + libglsl + ] ) libgalliumvl_stub = static_library( diff --git a/src/gallium/auxiliary/nir/tgsi_to_nir.c b/src/gallium/auxiliary/nir/tgsi_to_nir.c index 1260752f0f6..11c16d43615 100644 --- a/src/gallium/auxiliary/nir/tgsi_to_nir.c +++ b/src/gallium/auxiliary/nir/tgsi_to_nir.c @@ -23,9 +23,12 @@ */ #include "util/ralloc.h" +#include "pipe/p_screen.h" + #include "compiler/nir/nir.h" #include "compiler/nir/nir_control_flow.h" #include "compiler/nir/nir_builder.h" +#include "compiler/glsl/gl_nir.h" #include "compiler/glsl/list.h" #include "compiler/shader_enums.h" @@ -91,6 +94,12 @@ struct ttn_compile { /* How many TGSI_FILE_IMMEDIATE vec4s have been parsed so far. */ unsigned next_imm; + + bool cap_scalar; + bool cap_face_is_sysval; + bool cap_position_is_sysval; + bool cap_packed_uniforms; + bool cap_samplers_as_deref; }; #define ttn_swizzle(b, src, x, y, z, w) \ @@ -1813,28 +1822,54 @@ ttn_parse_tgsi(struct ttn_compile *c, const void *tgsi_tokens) tgsi_parse_free(&parser); } +static void +ttn_read_pipe_caps(struct ttn_compile *c, + struct pipe_screen *screen) +{ + c->cap_scalar = screen->get_shader_param(screen, c->scan->processor, PIPE_SHADER_CAP_SCALAR_ISA); + c->cap_packed_uniforms = screen->get_param(screen, PIPE_CAP_PACKED_UNIFORMS); + c->cap_samplers_as_deref = screen->get_param(screen, PIPE_CAP_NIR_SAMPLERS_AS_DEREF); + c->cap_face_is_sysval = screen->get_param(screen, PIPE_CAP_TGSI_FS_FACE_IS_INTEGER_SYSVAL); + c->cap_position_is_sysval = screen->get_param(screen, PIPE_CAP_TGSI_FS_POSITION_IS_SYSVAL); +} + /** * Initializes a TGSI-to-NIR compiler. */ static struct ttn_compile * ttn_compile_init(const void *tgsi_tokens, - const nir_shader_compiler_options *options) + const nir_shader_compiler_options *options, + struct pipe_screen *screen) { struct ttn_compile *c; struct nir_shader *s; struct tgsi_shader_info scan; + assert(options || screen); c = rzalloc(NULL, struct ttn_compile); tgsi_scan_shader(tgsi_tokens, &scan); c->scan = &scan; + if (!options) { + options = + screen->get_compiler_options(screen, PIPE_SHADER_IR_NIR, scan.processor); + } + nir_builder_init_simple_shader(&c->build, NULL, tgsi_processor_to_shader_stage(scan.processor), options); s = c->build.shader; + if (screen) { + ttn_read_pipe_caps(c, screen); + } else { + /* TTN used to be hard coded to always make FACE a sysval, + * so it makes sense to preserve that behavior so users don't break. */ + c->cap_face_is_sysval = true; + } + if (s->info.stage == MESA_SHADER_FRAGMENT) s->info.fs.untyped_color_outputs = true; @@ -1872,14 +1907,105 @@ ttn_compile_init(const void *tgsi_tokens, return c; } +static void +ttn_optimize_nir(nir_shader *nir, bool scalar) +{ + bool progress; + do { + progress = false; + + NIR_PASS_V(nir, nir_lower_vars_to_ssa); + + if (scalar) { + NIR_PASS_V(nir, nir_lower_alu_to_scalar); + NIR_PASS_V(nir, nir_lower_phis_to_scalar); + } + + NIR_PASS_V(nir, nir_lower_alu); + NIR_PASS_V(nir, nir_lower_pack); + NIR_PASS(progress, nir, nir_copy_prop); + NIR_PASS(progress, nir, nir_opt_remove_phis); + NIR_PASS(progress, nir, nir_opt_dce); + + if (nir_opt_trivial_continues(nir)) { + progress = true; + NIR_PASS(progress, nir, nir_copy_prop); + NIR_PASS(progress, nir, nir_opt_dce); + } + + NIR_PASS(progress, nir, nir_opt_if); + NIR_PASS(progress, nir, nir_opt_dead_cf); + NIR_PASS(progress, nir, nir_opt_cse); + NIR_PASS(progress, nir, nir_opt_peephole_select, 8, true, true); + + NIR_PASS(progress, nir, nir_opt_algebraic); + NIR_PASS(progress, nir, nir_opt_constant_folding); + + NIR_PASS(progress, nir, nir_opt_undef); + NIR_PASS(progress, nir, nir_opt_conditional_discard); + + if (nir->options->max_unroll_iterations) { + NIR_PASS(progress, nir, nir_opt_loop_unroll, (nir_variable_mode)0); + } + + } while (progress); + +} + +/** + * Finalizes the NIR in a similar way as st_glsl_to_nir does. + * + * Drivers expect that these passes are already performed, + * so we have to do it here too. + */ +static void +ttn_finalize_nir(struct ttn_compile *c) +{ + struct nir_shader *nir = c->build.shader; + + NIR_PASS_V(nir, nir_lower_vars_to_ssa); + NIR_PASS_V(nir, nir_lower_regs_to_ssa); + + NIR_PASS_V(nir, nir_lower_global_vars_to_local); + NIR_PASS_V(nir, nir_split_var_copies); + NIR_PASS_V(nir, nir_lower_var_copies); + + if (c->cap_packed_uniforms) + NIR_PASS_V(nir, nir_lower_uniforms_to_ubo, 16); + + if (c->cap_samplers_as_deref) + NIR_PASS_V(nir, gl_nir_lower_samplers_as_deref, NULL); + else + NIR_PASS_V(nir, gl_nir_lower_samplers, NULL); + + ttn_optimize_nir(nir, c->cap_scalar); + nir_shader_gather_info(nir, c->build.impl); + nir_validate_shader(nir, "TTN: after all optimizations"); +} + struct nir_shader * tgsi_to_nir(const void *tgsi_tokens, - const nir_shader_compiler_options *options) + struct pipe_screen *screen) +{ + struct ttn_compile *c; + struct nir_shader *s; + + c = ttn_compile_init(tgsi_tokens, NULL, screen); + s = c->build.shader; + ttn_finalize_nir(c); + ralloc_free(c); + + return s; +} + +struct nir_shader * +tgsi_to_nir_noscreen(const void *tgsi_tokens, + const nir_shader_compiler_options *options) { struct ttn_compile *c; struct nir_shader *s; - c = ttn_compile_init(tgsi_tokens, options); + c = ttn_compile_init(tgsi_tokens, options, NULL); s = c->build.shader; ralloc_free(c); diff --git a/src/gallium/auxiliary/nir/tgsi_to_nir.h b/src/gallium/auxiliary/nir/tgsi_to_nir.h index a7060bca610..551ee917c8a 100644 --- a/src/gallium/auxiliary/nir/tgsi_to_nir.h +++ b/src/gallium/auxiliary/nir/tgsi_to_nir.h @@ -22,7 +22,12 @@ */ #include "compiler/nir/nir.h" +#include "pipe/p_screen.h" struct nir_shader * tgsi_to_nir(const void *tgsi_tokens, - const struct nir_shader_compiler_options *options); + struct pipe_screen *screen); + +struct nir_shader * +tgsi_to_nir_noscreen(const void *tgsi_tokens, + const nir_shader_compiler_options *options); diff --git a/src/gallium/drivers/freedreno/a2xx/ir2_nir.c b/src/gallium/drivers/freedreno/a2xx/ir2_nir.c index ee27b8835a2..6aaff393167 100644 --- a/src/gallium/drivers/freedreno/a2xx/ir2_nir.c +++ b/src/gallium/drivers/freedreno/a2xx/ir2_nir.c @@ -46,9 +46,11 @@ struct nir_shader * ir2_tgsi_to_nir(const struct tgsi_token *tokens, struct pipe_screen *screen) { - /* TODO: pass screen to tgsi_to_nir when it needs that. */ - (void) screen; - return tgsi_to_nir(tokens, &options); + if (!screen) { + return tgsi_to_nir_noscreen(tokens, &options); + } + + return tgsi_to_nir(tokens, screen); } const nir_shader_compiler_options * diff --git a/src/gallium/drivers/freedreno/ir3/ir3_gallium.c b/src/gallium/drivers/freedreno/ir3/ir3_gallium.c index 726bd14ac6d..4481c544217 100644 --- a/src/gallium/drivers/freedreno/ir3/ir3_gallium.c +++ b/src/gallium/drivers/freedreno/ir3/ir3_gallium.c @@ -183,9 +183,13 @@ ir3_tgsi_to_nir(struct ir3_compiler *compiler, const struct tgsi_token *tokens, struct pipe_screen *screen) { - /* TODO: pass screen to tgsi_to_nir when it needs that. */ - (void) screen; - return tgsi_to_nir(tokens, ir3_get_compiler_options(compiler)); + if (!screen) { + const nir_shader_compiler_options *options = + ir3_get_compiler_options(compiler); + return tgsi_to_nir_noscreen(tokens, options); + } + + return tgsi_to_nir(tokens, screen); } /* This has to reach into the fd_context a bit more than the rest of diff --git a/src/gallium/drivers/panfrost/pan_assemble.c b/src/gallium/drivers/panfrost/pan_assemble.c index 4cbbecce0f7..f3b339d8184 100644 --- a/src/gallium/drivers/panfrost/pan_assemble.c +++ b/src/gallium/drivers/panfrost/pan_assemble.c @@ -48,7 +48,7 @@ panfrost_shader_compile(struct panfrost_context *ctx, struct mali_shader_meta *m } else { assert (cso->type == PIPE_SHADER_IR_TGSI); //tgsi_dump(cso->tokens, 0); - s = tgsi_to_nir(cso->tokens, &midgard_nir_options); + s = tgsi_to_nir(cso->tokens, &ctx->base.screen); } s->info.stage = type == JOB_TYPE_VERTEX ? MESA_SHADER_VERTEX : MESA_SHADER_FRAGMENT; diff --git a/src/gallium/drivers/v3d/v3d_program.c b/src/gallium/drivers/v3d/v3d_program.c index 0224df08d0b..fa4fa0b0b29 100644 --- a/src/gallium/drivers/v3d/v3d_program.c +++ b/src/gallium/drivers/v3d/v3d_program.c @@ -275,7 +275,7 @@ v3d_shader_state_create(struct pipe_context *pctx, tgsi_dump(cso->tokens, 0); fprintf(stderr, "\n"); } - s = tgsi_to_nir(cso->tokens, &v3d_nir_options); + s = tgsi_to_nir(cso->tokens, pctx->screen); } nir_variable_mode lower_mode = nir_var_all & ~nir_var_uniform; diff --git a/src/gallium/drivers/vc4/vc4_program.c b/src/gallium/drivers/vc4/vc4_program.c index 2d0a52bb5fb..eb8b3a2c377 100644 --- a/src/gallium/drivers/vc4/vc4_program.c +++ b/src/gallium/drivers/vc4/vc4_program.c @@ -2502,7 +2502,7 @@ vc4_shader_state_create(struct pipe_context *pctx, tgsi_dump(cso->tokens, 0); fprintf(stderr, "\n"); } - s = tgsi_to_nir(cso->tokens, &nir_options); + s = tgsi_to_nir(cso->tokens, pctx->screen); } NIR_PASS_V(s, nir_lower_io, nir_var_all & ~nir_var_uniform,