diff options
author | Lynne <dev@lynne.ee> | 2021-11-19 13:45:21 +0100 |
---|---|---|
committer | Lynne <dev@lynne.ee> | 2021-11-19 16:47:30 +0100 |
commit | da72aca7b02503cdcdacd915dcf11929d29eecd1 (patch) | |
tree | 52a61164903e33c56d2d6701cda10909dc2c3bfd /libavutil | |
parent | 1d06084171604038ccae2d8a0a9c8fa99229ee52 (diff) | |
download | ffmpeg-da72aca7b02503cdcdacd915dcf11929d29eecd1.tar.gz |
lavu/vulkan: add support for using libshaderc as a GLSL compiler
It's got a much better API that's actually maintained, it eliminates
race conditions, it comes with a pkg-config file by default, and
unfortunately isn't currently packaged by Debian or other large
distributions.
Diffstat (limited to 'libavutil')
-rw-r--r-- | libavutil/vulkan.c | 4 | ||||
-rw-r--r-- | libavutil/vulkan_shaderc.c | 122 |
2 files changed, 126 insertions, 0 deletions
diff --git a/libavutil/vulkan.c b/libavutil/vulkan.c index 3a70afe6a5..a6463de622 100644 --- a/libavutil/vulkan.c +++ b/libavutil/vulkan.c @@ -23,6 +23,8 @@ #if CONFIG_LIBGLSLANG #include "vulkan_glslang.c" +#elif CONFIG_LIBSHADERC +#include "vulkan_shaderc.c" #endif /* Generic macro for creating contexts which need to keep their addresses @@ -859,6 +861,8 @@ int ff_vk_compile_shader(FFVulkanContext *s, FFVkSPIRVShader *shd, if (!s->spirv_compiler) { #if CONFIG_LIBGLSLANG s->spirv_compiler = ff_vk_glslang_init(); +#elif CONFIG_LIBSHADERC + s->spirv_compiler = ff_vk_shaderc_init(); #else return AVERROR(ENOSYS); #endif diff --git a/libavutil/vulkan_shaderc.c b/libavutil/vulkan_shaderc.c new file mode 100644 index 0000000000..bd40edf187 --- /dev/null +++ b/libavutil/vulkan_shaderc.c @@ -0,0 +1,122 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <shaderc/shaderc.h> + +#include "mem.h" + +static int shdc_shader_compile(FFVkSPIRVCompiler *ctx, void *avctx, + FFVkSPIRVShader *shd, uint8_t **data, + size_t *size, const char *entrypoint, + void **opaque) +{ + int loglevel, err, warn, ret; + const char *status, *message; + shaderc_compilation_result_t res; + static const char *shdc_result[] = { + [shaderc_compilation_status_success] = "success", + [shaderc_compilation_status_invalid_stage] = "invalid stage", + [shaderc_compilation_status_compilation_error] = "error", + [shaderc_compilation_status_internal_error] = "internal error", + [shaderc_compilation_status_null_result_object] = "no result", + [shaderc_compilation_status_invalid_assembly] = "invalid assembly", + }; + static const shaderc_shader_kind shdc_kind[] = { + [VK_SHADER_STAGE_VERTEX_BIT] = shaderc_glsl_vertex_shader, + [VK_SHADER_STAGE_FRAGMENT_BIT] = shaderc_glsl_fragment_shader, + [VK_SHADER_STAGE_COMPUTE_BIT] = shaderc_glsl_compute_shader, + }; + + shaderc_compile_options_t opts = shaderc_compile_options_initialize(); + if (!opts) + return AVERROR(ENOMEM); + + shaderc_compile_options_set_target_env(opts, shaderc_target_env_vulkan, + shaderc_env_version_vulkan_1_2); + shaderc_compile_options_set_target_spirv(opts, shaderc_spirv_version_1_5); + shaderc_compile_options_set_optimization_level(opts, + shaderc_optimization_level_performance); + + res = shaderc_compile_into_spv((shaderc_compiler_t)ctx->priv, + shd->src.str, strlen(shd->src.str), + shdc_kind[shd->shader.stage], + shd->name, entrypoint, opts); + shaderc_compile_options_release(opts); + + ret = shaderc_result_get_compilation_status(res); + err = shaderc_result_get_num_errors(res); + warn = shaderc_result_get_num_warnings(res); + message = shaderc_result_get_error_message(res); + + loglevel = err ? AV_LOG_ERROR : warn ? AV_LOG_WARNING : AV_LOG_VERBOSE; + + ff_vk_print_shader(avctx, shd, loglevel); + if (message && (err || warn)) + av_log(avctx, loglevel, "%s\n", message); + status = ret < FF_ARRAY_ELEMS(shdc_result) ? shdc_result[ret] : "unknown"; + av_log(avctx, loglevel, "shaderc compile status '%s' (%d errors, %d warnings)\n", + status, err, warn); + + if (err > 0) + return AVERROR(EINVAL); + + *data = (uint8_t *)shaderc_result_get_bytes(res); + *size = shaderc_result_get_length(res); + *opaque = res; + + return 0; +} + +static void shdc_shader_free(FFVkSPIRVCompiler *ctx, void **opaque) +{ + if (!opaque || !*opaque) + return; + + shaderc_result_release((shaderc_compilation_result_t)*opaque); + *opaque = NULL; +} + +static void shdc_uninit(FFVkSPIRVCompiler **ctx) +{ + FFVkSPIRVCompiler *s; + + if (!ctx || !*ctx) + return; + + s = *ctx; + + shaderc_compiler_release((shaderc_compiler_t)s->priv); + av_freep(ctx); +} + +static FFVkSPIRVCompiler *ff_vk_shaderc_init(void) +{ + FFVkSPIRVCompiler *ret = av_mallocz(sizeof(*ret)); + if (!ret) + return NULL; + + ret->compile_shader = shdc_shader_compile; + ret->free_shader = shdc_shader_free; + ret->uninit = shdc_uninit; + + ret->priv = (void *)shaderc_compiler_initialize(); + if (!ret->priv) + av_freep(&ret); + + return ret; +} |