anv: Add softtp64 workaround
authorMykhailo Skorokhodov <mykhailo.skorokhodov@globallogic.com>
Wed, 28 Sep 2022 02:12:19 +0000 (05:12 +0300)
committerMarge Bot <emma+marge@anholt.net>
Fri, 28 Oct 2022 10:08:50 +0000 (10:08 +0000)
Pass float64.glsl into nir_lower_doubles() resolves the problem on
ICL/TGL when the shader uses float64, but the device doesn't support
that type.

Signed-off-by: Mykhailo Skorokhodov <mykhailo.skorokhodov@globallogic.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/18854>

src/intel/vulkan/anv_device.c
src/intel/vulkan/anv_pipeline.c
src/intel/vulkan/anv_pipeline_cache.c
src/intel/vulkan/anv_private.h

index 337045b..b49e1e8 100644 (file)
@@ -3588,6 +3588,11 @@ VkResult anv_CreateDevice(
       goto fail_default_pipeline_cache;
    }
 
+   /* The device (currently is ICL/TGL) does not have float64 support. */
+   if (!device->info->has_64bit_float &&
+      device->physical->instance->fp64_workaround_enabled)
+      anv_load_fp64_shader(device);
+
    result = anv_device_init_rt_shaders(device);
    if (result != VK_SUCCESS) {
       result = vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
index 82c1a10..ef9b1f9 100644 (file)
@@ -176,6 +176,29 @@ anv_nir_lower_mesh_ext(nir_shader *nir)
                                        &state);
 }
 
+static bool
+nir_shader_uses_64bit_alu(nir_shader *shader)
+{
+   nir_foreach_function(function, shader) {
+      if (!function->impl)
+         continue;
+
+      nir_foreach_block(block, function->impl) {
+         nir_foreach_instr(instr, block) {
+            if (instr->type != nir_instr_type_alu)
+               continue;
+            nir_alu_instr *alu = nir_instr_as_alu(instr);
+            if (nir_alu_type_get_base_type(nir_op_infos[alu->op].output_type) != nir_type_float)
+               continue;
+            if (alu->dest.dest.ssa.bit_size == 64)
+               return true;
+         }
+      }
+   }
+
+   return false;
+}
+
 /* Eventually, this will become part of anv_CreateShader.  Unfortunately,
  * we can't do that yet because we don't have the ability to copy nir.
  */
@@ -297,7 +320,10 @@ anv_shader_stage_to_nir(struct anv_device *device,
    /* Vulkan uses the separate-shader linking model */
    nir->info.separate_shader = true;
 
-   brw_preprocess_nir(compiler, nir, NULL);
+   assert(device->info->has_64bit_float || instance->fp64_workaround_enabled ||
+          !nir_shader_uses_64bit_alu(nir));
+
+   brw_preprocess_nir(compiler, nir, device->fp64_nir);
 
    if (nir->info.stage == MESA_SHADER_MESH && !nir->info.mesh.nv) {
       bool progress = false;
index 25458e1..b94eea7 100644 (file)
@@ -30,6 +30,8 @@
 #include "anv_private.h"
 #include "nir/nir_xfb_info.h"
 #include "vulkan/util/vk_util.h"
+#include "compiler/spirv/nir_spirv.h"
+#include "float64_spv.h"
 
 static bool
 anv_shader_bin_serialize(struct vk_pipeline_cache_object *object,
@@ -414,3 +416,68 @@ anv_device_upload_nir(struct anv_device *device,
 
    vk_pipeline_cache_add_nir(cache, sha1_key, SHA1_KEY_SIZE, nir);
 }
+
+void
+anv_load_fp64_shader(struct anv_device *device)
+{
+   const nir_shader_compiler_options *nir_options =
+      device->physical->compiler->nir_options[MESA_SHADER_VERTEX];
+
+   const char* shader_name = "float64_spv_lib";
+   struct mesa_sha1 sha1_ctx;
+   uint8_t sha1[20];
+   _mesa_sha1_init(&sha1_ctx);
+   _mesa_sha1_update(&sha1_ctx, shader_name, strlen(shader_name));
+   _mesa_sha1_final(&sha1_ctx, sha1);
+
+   device->fp64_nir =
+      anv_device_search_for_nir(device, device->internal_cache,
+                                   nir_options, sha1, NULL);
+
+   /* The shader found, no need to call spirv_to_nir() again. */
+   if (device->fp64_nir)
+      return;
+
+   struct spirv_to_nir_options spirv_options = {
+      .caps = {
+         .address = true,
+         .float64 = true,
+         .int8 = true,
+         .int16 = true,
+         .int64 = true,
+      },
+      .environment = MESA_SHADER_VERTEX,
+      .create_library = true
+   };
+
+   nir_shader* nir =
+      spirv_to_nir(float64_spv_source, sizeof(float64_spv_source) / 4,
+                   NULL, 0, PIPE_SHADER_VERTEX, "main",
+                   &spirv_options, nir_options);
+
+   assert(nir != NULL);
+
+   nir_validate_shader(nir, "after spirv_to_nir");
+   nir_validate_ssa_dominance(nir, "after spirv_to_nir");
+
+   NIR_PASS_V(nir, nir_lower_variable_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);
+
+   NIR_PASS_V(nir, nir_lower_vars_to_ssa);
+   NIR_PASS_V(nir, nir_copy_prop);
+   NIR_PASS_V(nir, nir_opt_dce);
+   NIR_PASS_V(nir, nir_opt_cse);
+   NIR_PASS_V(nir, nir_opt_gcm, true);
+   NIR_PASS_V(nir, nir_opt_peephole_select, 1, false, false);
+   NIR_PASS_V(nir, nir_opt_dce);
+
+   NIR_PASS_V(nir, nir_lower_explicit_io, nir_var_function_temp,
+              nir_address_format_62bit_generic);
+
+   anv_device_upload_nir(device, device->internal_cache,
+                         nir, sha1);
+
+   device->fp64_nir = nir;
+}
\ No newline at end of file
index 1eb16d7..2b27e01 100644 (file)
@@ -1145,6 +1145,9 @@ anv_device_upload_nir(struct anv_device *device,
                       const struct nir_shader *nir,
                       unsigned char sha1_key[20]);
 
+void
+anv_load_fp64_shader(struct anv_device *device);
+
 enum anv_rt_bvh_build_method {
    ANV_BVH_BUILD_METHOD_TRIVIAL,
    ANV_BVH_BUILD_METHOD_NEW_SAH,
@@ -1262,6 +1265,8 @@ struct anv_device {
     struct intel_debug_block_frame              *debug_frame_desc;
 
     struct intel_ds_device                       ds;
+
+    nir_shader                                  *fp64_nir;
 };
 
 static inline struct anv_state