st/mesa: add support for lowering fp64/int64 for nir drivers
authorDave Airlie <airlied@redhat.com>
Thu, 10 Jan 2019 06:24:57 +0000 (16:24 +1000)
committerJordan Justen <jordan.l.justen@intel.com>
Sat, 2 Mar 2019 22:33:44 +0000 (14:33 -0800)
This might enough for iris and possible r600 (when it gets NIR)

This appears to work for iris.

v2:
 * change cap return so DOUBLES == 2 means sw emu

v3:
 * Refactor using int64/doubles lowering options which were added
   into nir options
 * Remove DOUBLES == 2 added in v2

[jordan: Remove "2" value on PIPE_CAP_DOUBLES]
[jordan: Use lowering options added to nir options]
Signed-off-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Acked-by: Jason Ekstrand <jason@jlekstrand.net>
src/mesa/state_tracker/st_glsl_to_nir.cpp

index 89f7424e4dbc846cb0a275a258b55e7e29a3a4a7..a1e3b6233c6fe239fef706c2ec73d4a2a19aea15 100644 (file)
@@ -36,6 +36,7 @@
 #include "main/shaderapi.h"
 #include "main/uniforms.h"
 
+#include "main/shaderobj.h"
 #include "st_context.h"
 #include "st_glsl_types.h"
 #include "st_program.h"
@@ -47,7 +48,7 @@
 #include "compiler/glsl/ir.h"
 #include "compiler/glsl/ir_optimization.h"
 #include "compiler/glsl/string_to_uint_map.h"
-
+#include "compiler/glsl/float64_glsl.h"
 
 static int
 type_size(const struct glsl_type *type)
@@ -340,6 +341,50 @@ st_nir_opts(nir_shader *nir, bool scalar)
    } while (progress);
 }
 
+static nir_shader *
+compile_fp64_funcs(struct gl_context *ctx,
+                   const nir_shader_compiler_options *options,
+                   void *mem_ctx,
+                   gl_shader_stage stage)
+{
+   const GLuint name = ~0;
+   struct gl_shader *sh;
+
+   sh = _mesa_new_shader(name, stage);
+
+   sh->Source = float64_source;
+   sh->CompileStatus = COMPILE_FAILURE;
+   _mesa_compile_shader(ctx, sh);
+
+   if (!sh->CompileStatus) {
+      if (sh->InfoLog) {
+         _mesa_problem(ctx,
+                       "fp64 software impl compile failed:\n%s\nsource:\n%s\n",
+                       sh->InfoLog, float64_source);
+      }
+   }
+
+   struct gl_shader_program *sh_prog;
+   sh_prog = _mesa_new_shader_program(name);
+   sh_prog->Label = NULL;
+   sh_prog->NumShaders = 1;
+   sh_prog->Shaders = (struct gl_shader **)malloc(sizeof(struct gl_shader *));
+   sh_prog->Shaders[0] = sh;
+
+   struct gl_linked_shader *linked = rzalloc(NULL, struct gl_linked_shader);
+   linked->Stage = stage;
+   linked->Program =
+      ctx->Driver.NewProgram(ctx, _mesa_shader_stage_to_program(stage),
+                             name, false);
+
+   linked->ir = sh->ir;
+   sh_prog->_LinkedShaders[stage] = linked;
+
+   nir_shader *nir = glsl_to_nir(sh_prog, stage, options);
+
+   return nir_shader_clone(mem_ctx, nir);
+}
+
 /* First third of converting glsl_to_nir.. this leaves things in a pre-
  * nir_lower_io state, so that shader variants can more easily insert/
  * replace variables, etc.
@@ -355,6 +400,8 @@ st_glsl_to_nir(struct st_context *st, struct gl_program *prog,
    struct pipe_screen *screen = st->pipe->screen;
    bool is_scalar = screen->get_shader_param(screen, type, PIPE_SHADER_CAP_SCALAR_ISA);
    assert(options);
+   bool lower_64bit =
+      options->lower_int64_options || options->lower_doubles_options;
 
    if (prog->nir)
       return prog->nir;
@@ -376,6 +423,16 @@ st_glsl_to_nir(struct st_context *st, struct gl_program *prog,
       nir->info.next_stage = MESA_SHADER_FRAGMENT;
    }
 
+   nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir));
+   if (nir->info.uses_64bit &&
+       (options->lower_doubles_options & nir_lower_fp64_full_software) != 0) {
+      nir_shader *fp64 =
+         compile_fp64_funcs(st->ctx, options, ralloc_parent(nir),
+                            nir->info.stage);
+      nir_validate_shader(fp64, "fp64");
+      exec_list_append(&nir->functions, &fp64->functions);
+   }
+
    nir_variable_mode mask =
       (nir_variable_mode) (nir_var_shader_in | nir_var_shader_out);
    nir_remove_dead_variables(nir, mask);
@@ -396,6 +453,46 @@ st_glsl_to_nir(struct st_context *st, struct gl_program *prog,
    NIR_PASS_V(nir, nir_split_var_copies);
    NIR_PASS_V(nir, nir_lower_var_copies);
 
+   if (is_scalar) {
+     NIR_PASS_V(nir, nir_lower_alu_to_scalar);
+   }
+
+   if (lower_64bit) {
+      bool lowered_64bit_ops = false;
+      bool progress = false;
+
+      NIR_PASS_V(nir, nir_opt_algebraic);
+
+      do {
+         progress = false;
+         if (options->lower_int64_options) {
+            NIR_PASS(progress, nir, nir_lower_int64,
+                     options->lower_int64_options);
+         }
+         if (options->lower_doubles_options) {
+            NIR_PASS(progress, nir, nir_lower_doubles,
+                     options->lower_doubles_options);
+         }
+         NIR_PASS(progress, nir, nir_opt_algebraic);
+         lowered_64bit_ops |= progress;
+      } while (progress);
+
+      if (lowered_64bit_ops) {
+         NIR_PASS_V(nir, nir_lower_constant_initializers, nir_var_function_temp);
+         NIR_PASS_V(nir, nir_lower_returns);
+         NIR_PASS_V(nir, nir_inline_functions);
+         NIR_PASS_V(nir, nir_opt_deref);
+      }
+
+      const nir_function *entry_point = nir_shader_get_entrypoint(nir)->function;
+      foreach_list_typed_safe(nir_function, func, node, &nir->functions) {
+         if (func != entry_point) {
+            exec_node_remove(&func->node);
+         }
+      }
+      assert(exec_list_length(&nir->functions) == 1);
+   }
+
    st_nir_opts(nir, is_scalar);
 
    return nir;