From 258487370fd840b018a404225277d74f74899c59 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Wed, 13 Sep 2017 03:09:48 +0200 Subject: vo_gpu: vulkan: generalize SPIR-V compiler In addition to the built-in nvidia compiler, we now also support a backend based on libshaderc. shaderc is sort of like glslang except it has a C API and is available as a dynamic library. The generated SPIR-V is now cached alongside the VkPipeline in the cached_program. We use a special cache header to ensure validity of this cache before passing it blindly to the vulkan implementation, since passing invalid SPIR-V can cause all sorts of nasty things. It's also designed to self-invalidate if the compiler gets better, by offering a catch-all `int compiler_version` that implementations can use as a cache invalidation marker. --- video/out/gpu/spirv.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 video/out/gpu/spirv.c (limited to 'video/out/gpu/spirv.c') diff --git a/video/out/gpu/spirv.c b/video/out/gpu/spirv.c new file mode 100644 index 0000000000..9375fd9508 --- /dev/null +++ b/video/out/gpu/spirv.c @@ -0,0 +1,78 @@ +#include "common/msg.h" +#include "options/m_config.h" + +#include "spirv.h" +#include "config.h" + +extern const struct spirv_compiler_fns spirv_shaderc; +extern const struct spirv_compiler_fns spirv_nvidia_builtin; + +// in probe-order +enum { + SPIRV_AUTO = 0, + SPIRV_SHADERC, // generally preferred, but not packaged everywhere + SPIRV_NVIDIA, // can be useful for testing, only available on nvidia +}; + +static const struct spirv_compiler_fns *compilers[] = { +#if HAVE_SHADERC + [SPIRV_SHADERC] = &spirv_shaderc, +#endif +#if HAVE_VULKAN + [SPIRV_NVIDIA] = &spirv_nvidia_builtin, +#endif +}; + +static const struct m_opt_choice_alternatives compiler_choices[] = { + {"auto", SPIRV_AUTO}, +#if HAVE_SHADERC + {"shaderc", SPIRV_SHADERC}, +#endif +#if HAVE_VULKAN + {"nvidia", SPIRV_NVIDIA}, +#endif + {0} +}; + +struct spirv_opts { + int compiler; +}; + +#define OPT_BASE_STRUCT struct spirv_opts +const struct m_sub_options spirv_conf = { + .opts = (const struct m_option[]) { + OPT_CHOICE_C("spirv-compiler", compiler, 0, compiler_choices), + {0} + }, + .size = sizeof(struct spirv_opts), +}; + +bool spirv_compiler_init(struct ra_ctx *ctx) +{ + void *tmp = talloc_new(NULL); + struct spirv_opts *opts = mp_get_config_group(tmp, ctx->global, &spirv_conf); + int compiler = opts->compiler; + talloc_free(tmp); + + for (int i = SPIRV_AUTO+1; i < MP_ARRAY_SIZE(compilers); i++) { + if (compiler != SPIRV_AUTO && i != compiler) + continue; + if (!compilers[i]) + continue; + + ctx->spirv = talloc_zero(NULL, struct spirv_compiler); + ctx->spirv->log = ctx->log, + ctx->spirv->fns = compilers[i]; + + const char *name = m_opt_choice_str(compiler_choices, i); + strncpy(ctx->spirv->name, name, sizeof(ctx->spirv->name)); + MP_VERBOSE(ctx, "Initializing SPIR-V compiler '%s'\n", name); + if (ctx->spirv->fns->init(ctx)) + return true; + talloc_free(ctx->spirv); + ctx->spirv = NULL; + } + + MP_ERR(ctx, "Failed initializing SPIR-V compiler!\n"); + return false; +} -- cgit v1.2.3