From da72aca7b02503cdcdacd915dcf11929d29eecd1 Mon Sep 17 00:00:00 2001 From: Lynne Date: Fri, 19 Nov 2021 13:45:21 +0100 Subject: [PATCH] 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. --- configure | 21 ++++--- libavutil/vulkan.c | 4 ++ libavutil/vulkan_shaderc.c | 122 +++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 7 deletions(-) create mode 100644 libavutil/vulkan_shaderc.c diff --git a/configure b/configure index 79252ac223..a5f5d15b04 100755 --- a/configure +++ b/configure @@ -262,6 +262,7 @@ External library support: --enable-librsvg enable SVG rasterization via librsvg [no] --enable-librubberband enable rubberband needed for rubberband filter [no] --enable-librtmp enable RTMP[E] support via librtmp [no] + --enable-libshaderc enable GLSL->SPIRV compilation via libshaderc [no] --enable-libshine enable fixed-point MP3 encoding via libshine [no] --enable-libsmbclient enable Samba protocol via libsmbclient [no] --enable-libsnappy enable Snappy compression, needed for hap encoding [no] @@ -1834,6 +1835,7 @@ EXTERNAL_LIBRARY_LIST=" librist librsvg librtmp + libshaderc libshine libsmbclient libsnappy @@ -3565,7 +3567,7 @@ ass_filter_deps="libass" atempo_filter_deps="avcodec" atempo_filter_select="rdft" avgblur_opencl_filter_deps="opencl" -avgblur_vulkan_filter_deps="vulkan libglslang" +avgblur_vulkan_filter_deps="vulkan spirv_compiler" azmq_filter_deps="libzmq" blackframe_filter_deps="gpl" bm3d_filter_deps="avcodec" @@ -3573,7 +3575,7 @@ bm3d_filter_select="dct" boxblur_filter_deps="gpl" boxblur_opencl_filter_deps="opencl gpl" bs2b_filter_deps="libbs2b" -chromaber_vulkan_filter_deps="vulkan libglslang" +chromaber_vulkan_filter_deps="vulkan spirv_compiler" colorkey_opencl_filter_deps="opencl" colormatrix_filter_deps="gpl" convolution_opencl_filter_deps="opencl" @@ -3613,7 +3615,7 @@ frei0r_deps_any="libdl LoadLibrary" frei0r_filter_deps="frei0r" frei0r_src_filter_deps="frei0r" fspp_filter_deps="gpl" -gblur_vulkan_filter_deps="vulkan libglslang" +gblur_vulkan_filter_deps="vulkan spirv_compiler" histeq_filter_deps="gpl" hqdn3d_filter_deps="gpl" interlace_filter_deps="gpl" @@ -3638,7 +3640,7 @@ openclsrc_filter_deps="opencl" overlay_opencl_filter_deps="opencl" overlay_qsv_filter_deps="libmfx" overlay_qsv_filter_select="qsvvpp" -overlay_vulkan_filter_deps="vulkan libglslang" +overlay_vulkan_filter_deps="vulkan spirv_compiler" owdenoise_filter_deps="gpl" pad_opencl_filter_deps="opencl" pan_filter_deps="swresample" @@ -3701,7 +3703,7 @@ zmq_filter_deps="libzmq" zoompan_filter_deps="swscale" zscale_filter_deps="libzimg const_nan" scale_vaapi_filter_deps="vaapi" -scale_vulkan_filter_deps="vulkan libglslang" +scale_vulkan_filter_deps="vulkan spirv_compiler" vpp_qsv_filter_deps="libmfx" vpp_qsv_filter_select="qsvvpp" xfade_opencl_filter_deps="opencl" @@ -6327,6 +6329,10 @@ if ! disabled ffnvcodec; then check_pkg_config ffnvcodec "ffnvcodec >= 8.1.24.11 ffnvcodec < 8.2" "$ffnv_hdr_list" "" fi +if enabled_all libglslang libshaderc; then + die "ERROR: libshaderc and libglslang are mutually exclusive, if in doubt, disable libglslang" +fi + check_cpp_condition winrt windows.h "!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)" if ! disabled w32threads && ! enabled pthreads; then @@ -6443,10 +6449,10 @@ enabled fontconfig && enable libfontconfig enabled libfontconfig && require_pkg_config libfontconfig fontconfig "fontconfig/fontconfig.h" FcInit enabled libfreetype && require_pkg_config libfreetype freetype2 "ft2build.h FT_FREETYPE_H" FT_Init_FreeType enabled libfribidi && require_pkg_config libfribidi fribidi fribidi.h fribidi_version_info -enabled libglslang && { check_lib libglslang glslang/Include/glslang_c_interface.h glslang_initialize_process \ +enabled libglslang && { check_lib spirv_compiler glslang/Include/glslang_c_interface.h glslang_initialize_process \ -lglslang -lMachineIndependent -lOSDependent -lHLSL -lOGLCompiler -lGenericCodeGen \ -lSPVRemapper -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lpthread -lstdc++ -lm || - require libglslang glslang/Include/glslang_c_interface.h glslang_initialize_process \ + require spirv_compiler glslang/Include/glslang_c_interface.h glslang_initialize_process \ -lglslang -lOSDependent -lHLSL -lOGLCompiler \ -lSPVRemapper -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lpthread -lstdc++ -lm; } enabled libgme && { check_pkg_config libgme libgme gme/gme.h gme_new_emu || @@ -6504,6 +6510,7 @@ enabled librist && require_pkg_config librist "librist >= 0.2" librist enabled librsvg && require_pkg_config librsvg librsvg-2.0 librsvg-2.0/librsvg/rsvg.h rsvg_handle_render_cairo enabled librtmp && require_pkg_config librtmp librtmp librtmp/rtmp.h RTMP_Socket enabled librubberband && require_pkg_config librubberband "rubberband >= 1.8.1" rubberband/rubberband-c.h rubberband_new -lstdc++ && append librubberband_extralibs "-lstdc++" +enabled libshaderc && require_pkg_config spirv_compiler "shaderc >= 2019.1" shaderc/shaderc.h shaderc_compiler_initialize enabled libshine && require_pkg_config libshine shine shine/layer3.h shine_encode_buffer enabled libsmbclient && { check_pkg_config libsmbclient smbclient libsmbclient.h smbc_init || require libsmbclient libsmbclient.h smbc_init -lsmbclient; } 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 + +#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; +}