diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gallium/frontends/clover/core/device.cpp | 23 | ||||
-rw-r--r-- | src/gallium/frontends/clover/core/device.hpp | 11 | ||||
-rw-r--r-- | src/gallium/frontends/clover/meson.build | 8 | ||||
-rw-r--r-- | src/gallium/frontends/clover/nir/invocation.cpp | 91 | ||||
-rw-r--r-- | src/gallium/frontends/clover/nir/invocation.hpp | 10 | ||||
-rw-r--r-- | src/gallium/frontends/clover/spirv/invocation.cpp | 39 | ||||
-rw-r--r-- | src/gallium/frontends/clover/spirv/invocation.hpp | 8 |
7 files changed, 176 insertions, 14 deletions
diff --git a/src/gallium/frontends/clover/core/device.cpp b/src/gallium/frontends/clover/core/device.cpp index 7f3d970ea5f..8ffc58fc2f2 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,17 @@ 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)) { + load_clc(); + 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,12 +67,25 @@ 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) pipe_loader_release(&ldev, 1); } +void +device::load_clc() { +#ifdef HAVE_CLOVER_SPIRV + if (supports_ir(PIPE_SHADER_IR_NIR_SERIALIZED)) { + std::string log; + clc_cache = nir::create_clc_disk_cache(); + clc = spirv::load_clc(*this); + } +#endif +} + bool device::operator==(const device &dev) const { return this == &dev; diff --git a/src/gallium/frontends/clover/core/device.hpp b/src/gallium/frontends/clover/core/device.hpp index 2cd3a54762e..38cd2646263 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; @@ -41,6 +46,9 @@ namespace clover { ~device(); device(const device &dev) = delete; + + void load_clc(); + device & operator=(const device &dev) = delete; @@ -101,6 +109,9 @@ namespace clover { return svm_support() & CL_DEVICE_SVM_FINE_GRAIN_SYSTEM; } + module clc; + lazy<std::shared_ptr<struct nir_shader>> clc_nir; + struct 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..5812d3447b4 100644 --- a/src/gallium/frontends/clover/meson.build +++ b/src/gallium/frontends/clover/meson.build @@ -78,7 +78,9 @@ libclspirv = static_library( 'clspirv', files('spirv/invocation.cpp', 'spirv/invocation.hpp'), include_directories : clover_incs, - cpp_args : [clover_opencl_cpp_args, clover_spirv_cpp_args], + cpp_args : [clover_opencl_cpp_args, clover_spirv_cpp_args, + '-DLIBCLC_LIBEXECDIR="@0@/"'.format(dep_clc.get_pkgconfig_variable('libexecdir')), + ], gnu_symbol_visibility : 'hidden', dependencies : [dep_spirv_tools], ) @@ -88,7 +90,9 @@ libclnir = static_library( files('nir/invocation.cpp', 'nir/invocation.hpp', 'nir/nir_lower_libclc.c', 'nir/nir_lower_libclc.h'), include_directories : [clover_incs, inc_mesa], dependencies : idep_nir, - cpp_args : [clover_opencl_cpp_args, clover_spirv_cpp_args], + cpp_args : [clover_opencl_cpp_args, clover_spirv_cpp_args, + '-DLIBCLC_LIBEXECDIR="@0@/"'.format(dep_clc.get_pkgconfig_variable('libexecdir')), + ], gnu_symbol_visibility : 'hidden', ) diff --git a/src/gallium/frontends/clover/nir/invocation.cpp b/src/gallium/frontends/clover/nir/invocation.cpp index 8ea6d3cf4d0..da9e62b2159 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 @@ -131,8 +135,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; @@ -156,6 +160,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 §ion = 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. @@ -189,6 +274,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..0aa848da514 100644 --- a/src/gallium/frontends/clover/nir/invocation.hpp +++ b/src/gallium/frontends/clover/nir/invocation.hpp @@ -24,12 +24,22 @@ #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..d86ff4cf905 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)) @@ -626,7 +627,6 @@ clover::spirv::link_program(const std::vector<module> &modules, const char *message) { r_log += format_validator_msg(level, source, position, message); }; - for (const auto &mod : modules) { const auto &msec = find([](const module::section &sec) { return sec.type == module::section::text_intermediate || @@ -675,7 +675,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 +688,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 +734,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 +770,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); } } |