tgsi_to_nir: Produce optimized NIR for a given pipe_screen.
authorTimur Kristóf <timur.kristof@gmail.com>
Tue, 5 Mar 2019 17:59:47 +0000 (18:59 +0100)
committerEric Anholt <eric@anholt.net>
Tue, 5 Mar 2019 19:13:27 +0000 (19:13 +0000)
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 <timur.kristof@gmail.com>
Tested-by: Andre Heider <a.heider@gmail.com>
Tested-by: Rob Clark <robdclark@gmail.com>
Acked-By: Eric Anholt <eric@anholt.net>
src/gallium/auxiliary/meson.build
src/gallium/auxiliary/nir/tgsi_to_nir.c
src/gallium/auxiliary/nir/tgsi_to_nir.h
src/gallium/drivers/freedreno/a2xx/ir2_nir.c
src/gallium/drivers/freedreno/ir3/ir3_gallium.c
src/gallium/drivers/panfrost/pan_assemble.c
src/gallium/drivers/v3d/v3d_program.c
src/gallium/drivers/vc4/vc4_program.c

index 6e5109eb97ea0500e1732665bfd7b1fc02d67e4b..ca72e81e51dff2460ebe4c12787e4db8142f4ddd 100644 (file)
@@ -534,6 +534,9 @@ libgallium = static_library(
     idep_nir_headers,
   ],
   build_by_default : false,
+  link_with: [
+    libglsl
+  ]
 )
 
 libgalliumvl_stub = static_library(
index 1260752f0f6e7af832d7d4780f8f54703b877297..11c16d43615635c1f9223ffa40ca1bdfc079490b 100644 (file)
  */
 
 #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);
 
index a7060bca610b79af80f13c826cd7feb116c20965..551ee917c8ad0e7d72859bf0a214c718e9b29f12 100644 (file)
  */
 
 #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);
index ee27b8835a270f813b5ec9ec230e150b7223ccc3..6aaff393167c8098429c712a7899ad0fe50fc5dc 100644 (file)
@@ -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 *
index 726bd14ac6d83888c560574b298a8e375131edbc..4481c544217fa4f04626b0be1d55744697ce70d9 100644 (file)
@@ -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
index 4cbbecce0f7f5be4a6e9ac8bc356d807b51b5433..f3b339d8184548dde337f6f25e21eb7b4d1f0ad6 100644 (file)
@@ -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;
index 0224df08d0b513557d1b5c0a4110ccfed09b3619..fa4fa0b0b29e27b989c918c792520a4347875673 100644 (file)
@@ -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;
index 2d0a52bb5fb88a515f3081b1299b0e936d75c86a..eb8b3a2c377568690035a3589facd4c955e32834 100644 (file)
@@ -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,