glsl: use NIR function inlining for drivers that use glsl_to_nir()
authorTimothy Arceri <tarceri@itsqueeze.com>
Wed, 20 Feb 2019 06:13:49 +0000 (17:13 +1100)
committerTimothy Arceri <tarceri@itsqueeze.com>
Wed, 6 Mar 2019 23:05:20 +0000 (23:05 +0000)
glsl_to_nir() is still missing support for converting certain
functions to NIR, so for those we use the GLSL IR optimisations
to remove the functions.

Reviewed-by: Eric Anholt <eric@anholt.net>
src/compiler/glsl/glsl_to_nir.cpp
src/compiler/glsl/glsl_to_nir.h
src/gallium/drivers/freedreno/ir3/ir3_cmdline.c
src/gallium/drivers/panfrost/midgard/cmdline.c
src/mesa/drivers/dri/i965/brw_program.c
src/mesa/state_tracker/st_glsl_to_nir.cpp

index 062434d066bb28bd7a373bd1a053224d08385f02..004a430d124feb4a3c26d25fbf8bb143f95323f7 100644 (file)
@@ -30,6 +30,7 @@
 #include "ir_visitor.h"
 #include "ir_hierarchical_visitor.h"
 #include "ir.h"
+#include "ir_optimization.h"
 #include "program.h"
 #include "compiler/nir/nir_control_flow.h"
 #include "compiler/nir/nir_builder.h"
@@ -133,15 +134,74 @@ private:
    nir_visitor *visitor;
 };
 
+/* glsl_to_nir can only handle converting certain function paramaters
+ * to NIR. This visitor checks for parameters it can't currently handle.
+ */
+class ir_function_param_visitor : public ir_hierarchical_visitor
+{
+public:
+   ir_function_param_visitor()
+      : unsupported(false)
+   {
+   }
+
+   virtual ir_visitor_status visit_enter(ir_function_signature *ir)
+   {
+
+      if (ir->is_intrinsic())
+         return visit_continue;
+
+      foreach_in_list(ir_variable, param, &ir->parameters) {
+         if (!param->type->is_vector() || !param->type->is_scalar()) {
+            unsupported = true;
+            return visit_stop;
+         }
+
+         if (param->data.mode == ir_var_function_inout) {
+            unsupported = true;
+            return visit_stop;
+         }
+      }
+
+      return visit_continue;
+   }
+
+   bool unsupported;
+};
+
 } /* end of anonymous namespace */
 
+
+static bool
+has_unsupported_function_param(exec_list *ir)
+{
+   ir_function_param_visitor visitor;
+   visit_list_elements(&visitor, ir);
+   return visitor.unsupported;
+}
+
 nir_shader *
-glsl_to_nir(const struct gl_shader_program *shader_prog,
+glsl_to_nir(struct gl_context *ctx,
+            const struct gl_shader_program *shader_prog,
             gl_shader_stage stage,
             const nir_shader_compiler_options *options)
 {
    struct gl_linked_shader *sh = shader_prog->_LinkedShaders[stage];
 
+   const struct gl_shader_compiler_options *gl_options =
+      &ctx->Const.ShaderCompilerOptions[stage];
+
+   /* glsl_to_nir can only handle converting certain function paramaters
+    * to NIR. If we find something we can't handle then we get the GLSL IR
+    * opts to remove it before we continue on.
+    *
+    * TODO: add missing glsl ir to nir support and remove this loop.
+    */
+   while (has_unsupported_function_param(sh->ir)) {
+      do_common_optimization(sh->ir, true, true, gl_options,
+                             ctx->Const.NativeIntegers);
+   }
+
    nir_shader *shader = nir_shader_create(NULL, stage, options,
                                           &sh->Program->info);
 
@@ -150,7 +210,27 @@ glsl_to_nir(const struct gl_shader_program *shader_prog,
    v2.run(sh->ir);
    visit_exec_list(sh->ir, &v1);
 
+   nir_validate_shader(shader, "after glsl to nir, before function inline");
+
+   /* We have to lower away local constant initializers right before we
+    * inline functions.  That way they get properly initialized at the top
+    * of the function and not at the top of its caller.
+    */
    nir_lower_constant_initializers(shader, (nir_variable_mode)~0);
+   nir_lower_returns(shader);
+   nir_inline_functions(shader);
+   nir_opt_deref(shader);
+
+   nir_validate_shader(shader, "after function inlining and return lowering");
+
+   /* Now that we have inlined everything remove all of the functions except
+    * main().
+    */
+   foreach_list_typed_safe(nir_function, function, node, &(shader)->functions){
+      if (strcmp("main", function->name) != 0) {
+         exec_node_remove(&function->node);
+      }
+   }
 
    /* Remap the locations to slots so those requiring two slots will occupy
     * two locations. For instance, if we have in the IR code a dvec3 attr0 in
index 115c8e1270bfa8a31eb2113c11c49a52cb05f3e6..38728d3ff267764dbf313fff210205fb605bc23b 100644 (file)
@@ -36,7 +36,8 @@ extern "C" {
 
 struct gl_shader_program;
 
-nir_shader *glsl_to_nir(const struct gl_shader_program *shader_prog,
+nir_shader *glsl_to_nir(struct gl_context *ctx,
+                        const struct gl_shader_program *shader_prog,
                         gl_shader_stage stage,
                         const nir_shader_compiler_options *options);
 
index 0850618bc3ddb7996ed7e2ff6780c5f5d4de5cc8..a8120578283e9ce026262b8361e808f0189a4f6b 100644 (file)
@@ -116,7 +116,7 @@ load_glsl(unsigned num_files, char* const* files, gl_shader_stage stage)
        if (!prog)
                errx(1, "couldn't parse `%s'", files[0]);
 
-       nir_shader *nir = glsl_to_nir(prog, stage, nir_options);
+       nir_shader *nir = glsl_to_nir(&local_ctx, prog, stage, nir_options);
 
        /* required NIR passes: */
        if (nir_options->lower_all_io_to_temps ||
index 7326402dd09f1a19aded0ad20be04aac3f65888c..acd810b2f34241fa2b297dfddfc83f938fa9c980 100644 (file)
@@ -66,11 +66,11 @@ compile_shader(char **argv)
         }
 
         midgard_program compiled;
-        nir = glsl_to_nir(prog, MESA_SHADER_VERTEX, &midgard_nir_options);
+        nir = glsl_to_nir(&local_ctx, prog, MESA_SHADER_VERTEX, &midgard_nir_options);
         midgard_compile_shader_nir(nir, &compiled, false);
         finalise_to_disk("vertex.bin", &compiled.compiled);
 
-        nir = glsl_to_nir(prog, MESA_SHADER_FRAGMENT, &midgard_nir_options);
+        nir = glsl_to_nir(&local_ctx, prog, MESA_SHADER_FRAGMENT, &midgard_nir_options);
         midgard_compile_shader_nir(nir, &compiled, false);
         finalise_to_disk("fragment.bin", &compiled.compiled);
 }
@@ -91,7 +91,7 @@ compile_blend(char **argv)
         prog->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program->info.stage = MESA_SHADER_FRAGMENT;
 
         midgard_program program;
-        nir = glsl_to_nir(prog, MESA_SHADER_FRAGMENT, &midgard_nir_options);
+        nir = glsl_to_nir(&local_ctx, prog, MESA_SHADER_FRAGMENT, &midgard_nir_options);
         midgard_compile_shader_nir(nir, &program, true);
         finalise_to_disk("blend.bin", &program.compiled);
 }
index ffb49c35cd4ae1909ada437ff03d8bc39efc0620..e58ed7c8e48f7fa552cef413c1b816d9dd21fd33 100644 (file)
@@ -93,7 +93,7 @@ brw_create_nir(struct brw_context *brw,
       if (shader_prog->data->spirv) {
          nir = _mesa_spirv_to_nir(ctx, shader_prog, stage, options);
       } else {
-         nir = glsl_to_nir(shader_prog, stage, options);
+         nir = glsl_to_nir(ctx, shader_prog, stage, options);
       }
       assert (nir);
 
index fa0cdf771e414dc5ce495f85d30b9101b8d99202..7b339e9e0439ab294249b4a1aaed9743c4340687 100644 (file)
@@ -361,7 +361,7 @@ st_glsl_to_nir(struct st_context *st, struct gl_program *prog,
    if (prog->nir)
       return prog->nir;
 
-   nir_shader *nir = glsl_to_nir(shader_program, stage, options);
+   nir_shader *nir = glsl_to_nir(st->ctx, shader_program, stage, options);
 
    /* Set the next shader stage hint for VS and TES. */
    if (!nir->info.separate_shader &&