summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gallium/frontends/clover/core/device.cpp23
-rw-r--r--src/gallium/frontends/clover/core/device.hpp11
-rw-r--r--src/gallium/frontends/clover/meson.build8
-rw-r--r--src/gallium/frontends/clover/nir/invocation.cpp91
-rw-r--r--src/gallium/frontends/clover/nir/invocation.hpp10
-rw-r--r--src/gallium/frontends/clover/spirv/invocation.cpp39
-rw-r--r--src/gallium/frontends/clover/spirv/invocation.hpp8
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 &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.
@@ -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);
}
}