Module: Mesa
Branch: master
Commit: f33b417652ceae711cc34601f51d62beec2d22f1
URL:    
http://cgit.freedesktop.org/mesa/mesa/commit/?id=f33b417652ceae711cc34601f51d62beec2d22f1

Author: Dave Airlie <[email protected]>
Date:   Wed Apr 10 10:24:46 2019 +1000

clover: handle libclc shader (v3)

This works by taking the spirv produced by libclc which contains
a lot of mangled function entrypoints identified with LinkageAttribute 
decorations.

This patch just sets up clover to load the libclc blob and convert it to
library nir, and support inlining application nir with calls to libclc.

v2: Add a disk cache support for this object, to avoid the spirv parsing
overheads each time. move spirv->nir to lazy instantiation to avoid
the mess with glsl types and constructor ordering.
v3: make disk cache optional

v1-Reviewed-by: Jesse Natalie <[email protected]>

Reviewed-by: Karol Herbst <[email protected]>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6035>

---

 src/gallium/frontends/clover/core/device.cpp      | 13 +++-
 src/gallium/frontends/clover/core/device.hpp      |  8 ++
 src/gallium/frontends/clover/meson.build          |  6 +-
 src/gallium/frontends/clover/nir/invocation.cpp   | 91 ++++++++++++++++++++++-
 src/gallium/frontends/clover/nir/invocation.hpp   |  9 +++
 src/gallium/frontends/clover/spirv/invocation.cpp | 38 ++++++++--
 src/gallium/frontends/clover/spirv/invocation.hpp |  8 +-
 7 files changed, 159 insertions(+), 14 deletions(-)

diff --git a/src/gallium/frontends/clover/core/device.cpp 
b/src/gallium/frontends/clover/core/device.cpp
index 7f3d970ea5f..dc0766c4243 100644
--- a/src/gallium/frontends/clover/core/device.cpp
+++ b/src/gallium/frontends/clover/core/device.cpp
@@ -28,6 +28,9 @@
 #include "pipe/p_state.h"
 #include "util/bitscan.h"
 #include "util/u_debug.h"
+#include "spirv/invocation.hpp"
+#include "nir/invocation.hpp"
+#include <fstream>
 
 using namespace clover;
 
@@ -45,14 +48,18 @@ namespace {
 }
 
 device::device(clover::platform &platform, pipe_loader_device *ldev) :
-   platform(platform), ldev(ldev) {
+   platform(platform), clc_cache(NULL), ldev(ldev) {
    pipe = pipe_loader_create_screen(ldev);
    if (pipe && pipe->get_param(pipe, PIPE_CAP_COMPUTE)) {
       if (supports_ir(PIPE_SHADER_IR_NATIVE))
          return;
 #ifdef HAVE_CLOVER_SPIRV
-      if (supports_ir(PIPE_SHADER_IR_NIR_SERIALIZED))
+      if (supports_ir(PIPE_SHADER_IR_NIR_SERIALIZED)) {
+         clc_cache = nir::create_clc_disk_cache();
+         clc = spirv::load_clc(*this);
+         clc_nir = lazy<std::shared_ptr<nir_shader>>([&] () { std::string log; 
return std::shared_ptr<nir_shader>(nir::libclc_spirv_to_nir(clc, *this, log), 
ralloc_free); });
          return;
+      }
 #endif
    }
    if (pipe)
@@ -61,6 +68,8 @@ device::device(clover::platform &platform, pipe_loader_device 
*ldev) :
 }
 
 device::~device() {
+   if (clc_cache)
+      disk_cache_destroy(clc_cache);
    if (pipe)
       pipe->destroy(pipe);
    if (ldev)
diff --git a/src/gallium/frontends/clover/core/device.hpp 
b/src/gallium/frontends/clover/core/device.hpp
index 2cd3a54762e..2599787716a 100644
--- a/src/gallium/frontends/clover/core/device.hpp
+++ b/src/gallium/frontends/clover/core/device.hpp
@@ -28,8 +28,13 @@
 
 #include "core/object.hpp"
 #include "core/format.hpp"
+#include "core/module.hpp"
+#include "util/lazy.hpp"
 #include "pipe-loader/pipe_loader.h"
 
+struct nir_shader;
+struct disk_cache;
+
 namespace clover {
    class platform;
    class root_resource;
@@ -101,6 +106,9 @@ namespace clover {
          return svm_support() & CL_DEVICE_SVM_FINE_GRAIN_SYSTEM;
       }
 
+      module clc;
+      lazy<std::shared_ptr<nir_shader>> clc_nir;
+      disk_cache *clc_cache;
    private:
       pipe_screen *pipe;
       pipe_loader_device *ldev;
diff --git a/src/gallium/frontends/clover/meson.build 
b/src/gallium/frontends/clover/meson.build
index 64c77f5f3ff..49ab9d5c04d 100644
--- a/src/gallium/frontends/clover/meson.build
+++ b/src/gallium/frontends/clover/meson.build
@@ -25,7 +25,9 @@ clover_opencl_cpp_args = [
   '-DCL_USE_DEPRECATED_OPENCL_1_1_APIS',
   '-DCL_USE_DEPRECATED_OPENCL_1_2_APIS',
   '-DCL_USE_DEPRECATED_OPENCL_2_0_APIS',
-  '-DCL_USE_DEPRECATED_OPENCL_2_1_APIS'
+  '-DCL_USE_DEPRECATED_OPENCL_2_1_APIS',
+  
'-DLIBCLC_INCLUDEDIR="@0@/"'.format(dep_clc.get_pkgconfig_variable('includedir')),
+  
'-DLIBCLC_LIBEXECDIR="@0@/"'.format(dep_clc.get_pkgconfig_variable('libexecdir'))
 ]
 clover_spirv_cpp_args = []
 clover_incs = [inc_include, inc_src, inc_gallium, inc_gallium_aux]
@@ -63,8 +65,6 @@ libclllvm = static_library(
     clover_cpp_args,
     clover_opencl_cpp_args,
     clover_spirv_cpp_args,
-    
'-DLIBCLC_INCLUDEDIR="@0@/"'.format(dep_clc.get_pkgconfig_variable('includedir')),
-    
'-DLIBCLC_LIBEXECDIR="@0@/"'.format(dep_clc.get_pkgconfig_variable('libexecdir')),
     '-DCLANG_RESOURCE_DIR="@0@"'.format(join_paths(
       dep_llvm.get_configtool_variable('libdir'), 'clang',
       dep_llvm.version(), 'include',
diff --git a/src/gallium/frontends/clover/nir/invocation.cpp 
b/src/gallium/frontends/clover/nir/invocation.cpp
index f2c53fc4b22..5d737d03c56 100644
--- a/src/gallium/frontends/clover/nir/invocation.cpp
+++ b/src/gallium/frontends/clover/nir/invocation.cpp
@@ -37,6 +37,10 @@
 #include <compiler/spirv/nir_spirv.h>
 #include <util/u_math.h>
 
+extern "C" {
+#include "nir_lower_libclc.h"
+}
+
 using namespace clover;
 
 #ifdef HAVE_CLOVER_SPIRV
@@ -132,8 +136,8 @@ clover_lower_nir(nir_shader *nir, 
std::vector<module::argument> &args, uint32_t
       clover_lower_nir_filter, clover_lower_nir_instr, &state);
 }
 
-module clover::nir::spirv_to_nir(const module &mod, const device &dev,
-                                 std::string &r_log)
+static spirv_to_nir_options
+create_spirv_options(const device &dev, std::string &r_log)
 {
    struct spirv_to_nir_options spirv_options = {};
    spirv_options.environment = NIR_SPIRV_OPENCL;
@@ -157,6 +161,87 @@ module clover::nir::spirv_to_nir(const module &mod, const 
device &dev,
    spirv_options.caps.int64_atomics = dev.has_int64_atomics();
    spirv_options.debug.func = &debug_function;
    spirv_options.debug.private_data = &r_log;
+   return spirv_options;
+}
+
+struct disk_cache *clover::nir::create_clc_disk_cache(void)
+{
+   struct mesa_sha1 ctx;
+   unsigned char sha1[20];
+   char cache_id[20 * 2 + 1];
+   _mesa_sha1_init(&ctx);
+
+   if (!disk_cache_get_function_identifier((void 
*)clover::nir::create_clc_disk_cache, &ctx))
+      return NULL;
+
+   _mesa_sha1_final(&ctx, sha1);
+
+   disk_cache_format_hex_id(cache_id, sha1, 20 * 2);
+   return disk_cache_create("clover-clc", cache_id, 0);
+}
+
+nir_shader *clover::nir::libclc_spirv_to_nir(const module &mod, const device 
&dev,
+                                             std::string &r_log)
+{
+   spirv_to_nir_options spirv_options = create_spirv_options(dev, r_log);
+   spirv_options.create_library = true;
+
+   auto &section = mod.secs[0];
+   const auto *binary =
+      reinterpret_cast<const pipe_binary_program_header 
*>(section.data.data());
+   const uint32_t *data = reinterpret_cast<const uint32_t *>(binary->blob);
+   const size_t num_words = binary->num_bytes / 4;
+   auto *compiler_options = dev_get_nir_compiler_options(dev);
+   unsigned char clc_cache_key[20];
+   unsigned char sha1[CACHE_KEY_SIZE];
+   /* caching ftw. */
+   struct mesa_sha1 ctx;
+
+   size_t binary_size = 0;
+   uint8_t *buffer = NULL;
+   if (dev.clc_cache) {
+      _mesa_sha1_init(&ctx);
+      _mesa_sha1_update(&ctx, data, num_words * 4);
+      _mesa_sha1_final(&ctx, clc_cache_key);
+
+      disk_cache_compute_key(dev.clc_cache, clc_cache_key, 20, sha1);
+
+      buffer = (uint8_t *)disk_cache_get(dev.clc_cache, sha1, &binary_size);
+   }
+
+   nir_shader *nir;
+   if (!buffer) {
+      nir = spirv_to_nir(data, num_words, nullptr, 0,
+                                     MESA_SHADER_KERNEL, "clcspirv",
+                                     &spirv_options, compiler_options);
+      nir_validate_shader(nir, "clover-libclc");
+      nir->info.internal = true;
+      NIR_PASS_V(nir, nir_lower_variable_initializers, nir_var_function_temp);
+      NIR_PASS_V(nir, nir_lower_returns);
+
+      if (dev.clc_cache) {
+         struct blob blob = { 0 };
+         blob_init(&blob);
+         nir_serialize(&blob, nir, true);
+         disk_cache_put(dev.clc_cache, sha1, blob.data, blob.size, NULL);
+         blob_finish(&blob);
+      }
+   } else {
+      struct blob_reader blob_read;
+      blob_reader_init(&blob_read, buffer, binary_size);
+      nir = nir_deserialize(NULL, compiler_options, &blob_read);
+      free(buffer);
+   }
+
+   return nir;
+}
+
+module clover::nir::spirv_to_nir(const module &mod, const device &dev,
+                                 std::string &r_log)
+{
+   spirv_to_nir_options spirv_options = create_spirv_options(dev, r_log);
+   std::shared_ptr<nir_shader> nir = dev.clc_nir;
+   spirv_options.clc_shader = nir.get();
 
    module m;
    // We only insert one section.
@@ -190,6 +275,8 @@ module clover::nir::spirv_to_nir(const module &mod, const 
device &dev,
       // according to the comment on nir_inline_functions
       NIR_PASS_V(nir, nir_lower_variable_initializers, nir_var_function_temp);
       NIR_PASS_V(nir, nir_lower_returns);
+      NIR_PASS_V(nir, nir_lower_libclc, spirv_options.clc_shader);
+
       NIR_PASS_V(nir, nir_inline_functions);
       NIR_PASS_V(nir, nir_copy_prop);
       NIR_PASS_V(nir, nir_opt_deref);
diff --git a/src/gallium/frontends/clover/nir/invocation.hpp 
b/src/gallium/frontends/clover/nir/invocation.hpp
index 41407a79765..62ae4ecd247 100644
--- a/src/gallium/frontends/clover/nir/invocation.hpp
+++ b/src/gallium/frontends/clover/nir/invocation.hpp
@@ -24,10 +24,19 @@
 #define CLOVER_NIR_INVOCATION_HPP
 
 #include "core/module.hpp"
+#include <util/disk_cache.h>
+
+struct nir_shader;
 
 namespace clover {
    class device;
    namespace nir {
+      // converts libclc spirv into nir
+      nir_shader *libclc_spirv_to_nir(const module &mod, const device &dev,
+                                      std::string &r_log);
+
+      struct disk_cache *create_clc_disk_cache(void);
+
       // converts a given spirv module to nir
       module spirv_to_nir(const module &mod, const device &dev, std::string 
&r_log);
    }
diff --git a/src/gallium/frontends/clover/spirv/invocation.cpp 
b/src/gallium/frontends/clover/spirv/invocation.cpp
index c3404f38b80..9b33e66d373 100644
--- a/src/gallium/frontends/clover/spirv/invocation.cpp
+++ b/src/gallium/frontends/clover/spirv/invocation.cpp
@@ -569,10 +569,11 @@ namespace {
 
 module
 clover::spirv::compile_program(const std::vector<char> &binary,
-                               const device &dev, std::string &r_log) {
+                               const device &dev, std::string &r_log,
+                               bool validate) {
    std::vector<char> source = spirv_to_cpu(binary);
 
-   if (!is_valid_spirv(source, dev.device_version(), r_log))
+   if (!is_valid_spirv(source, dev.device_version(), r_log, validate))
       throw build_error();
 
    if (!check_capabilities(dev, source, r_log))
@@ -675,7 +676,8 @@ clover::spirv::link_program(const std::vector<module> 
&modules,
 bool
 clover::spirv::is_valid_spirv(const std::vector<char> &binary,
                               const std::string &opencl_version,
-                              std::string &r_log) {
+                              std::string &r_log,
+                              bool validate) {
    auto const validator_consumer =
       [&r_log](spv_message_level_t level, const char *source,
                const spv_position_t &position, const char *message) {
@@ -687,6 +689,8 @@ clover::spirv::is_valid_spirv(const std::vector<char> 
&binary,
    spvtools::SpirvTools spvTool(target_env);
    spvTool.SetMessageConsumer(validator_consumer);
 
+   if (!validate)
+      return true;
    return spvTool.Validate(reinterpret_cast<const uint32_t *>(binary.data()),
                            binary.size() / 4u);
 }
@@ -731,13 +735,14 @@ clover::spirv::supported_versions() {
 bool
 clover::spirv::is_valid_spirv(const std::vector<char> &/*binary*/,
                               const std::string &/*opencl_version*/,
-                              std::string &/*r_log*/) {
+                              std::string &/*r_log*/, bool /*validate*/) {
    return false;
 }
 
 module
 clover::spirv::compile_program(const std::vector<char> &binary,
-                               const device &dev, std::string &r_log) {
+                               const device &dev, std::string &r_log,
+                               bool validate) {
    r_log += "SPIR-V support in clover is not enabled.\n";
    throw build_error();
 }
@@ -766,3 +771,26 @@ clover::spirv::supported_versions() {
    return {};
 }
 #endif
+
+module
+clover::spirv::load_clc(const device &dev)
+{
+   std::vector<char> ilfile;
+   std::ifstream file;
+   std::string name32 = "spirv-mesa3d-.spv";
+   std::string name64 = "spirv64-mesa3d-.spv";
+   file.open(LIBCLC_LIBEXECDIR + (dev.address_bits() == 64 ? name64 : name32), 
std::ifstream::in | std::ifstream::binary);
+   if (!file.good())
+      throw error(CL_COMPILER_NOT_AVAILABLE);
+
+   file.seekg(0, std::ios::end);
+   std::streampos length(file.tellg());
+   if (length) {
+      file.seekg(0, std::ios::beg);
+      ilfile.resize(static_cast<std::size_t>(length));
+      file.read(&ilfile.front(), static_cast<std::size_t>(length));
+   }
+
+   std::string log;
+   return spirv::compile_program(ilfile, dev, log, false);
+}
diff --git a/src/gallium/frontends/clover/spirv/invocation.hpp 
b/src/gallium/frontends/clover/spirv/invocation.hpp
index 27f8d8c1934..9d954671183 100644
--- a/src/gallium/frontends/clover/spirv/invocation.hpp
+++ b/src/gallium/frontends/clover/spirv/invocation.hpp
@@ -38,11 +38,12 @@ namespace clover {
       // warnings and errors are appended to |r_log|.
       bool is_valid_spirv(const std::vector<char> &binary,
                           const std::string &opencl_version,
-                          std::string &r_log);
+                          std::string &r_log, bool validate = true);
 
       // Creates a clover module out of the given SPIR-V binary.
       module compile_program(const std::vector<char> &binary,
-                             const device &dev, std::string &r_log);
+                             const device &dev, std::string &r_log,
+                             bool validate = true);
 
       // Combines multiple clover modules into a single one, resolving
       // link dependencies between them.
@@ -59,6 +60,9 @@ namespace clover {
       // Returns a vector (sorted in increasing order) of supported SPIR-V
       // versions.
       std::vector<uint32_t> supported_versions();
+
+      // Load the SPIR-V for the CLC module.
+      module load_clc(const device &dev);
    }
 }
 

_______________________________________________
mesa-commit mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/mesa-commit

Reply via email to