1/* 2 * This file is part of FFmpeg. 3 * 4 * FFmpeg is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * FFmpeg is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with FFmpeg; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include <shaderc/shaderc.h> 20 21#include "mem.h" 22 23static int shdc_shader_compile(FFVkSPIRVCompiler *ctx, void *avctx, 24 FFVkSPIRVShader *shd, uint8_t **data, 25 size_t *size, const char *entrypoint, 26 void **opaque) 27{ 28 int loglevel, err, warn, ret; 29 const char *status, *message; 30 shaderc_compilation_result_t res; 31 static const char *shdc_result[] = { 32 [shaderc_compilation_status_success] = "success", 33 [shaderc_compilation_status_invalid_stage] = "invalid stage", 34 [shaderc_compilation_status_compilation_error] = "error", 35 [shaderc_compilation_status_internal_error] = "internal error", 36 [shaderc_compilation_status_null_result_object] = "no result", 37 [shaderc_compilation_status_invalid_assembly] = "invalid assembly", 38 }; 39 static const shaderc_shader_kind shdc_kind[] = { 40 [VK_SHADER_STAGE_VERTEX_BIT] = shaderc_glsl_vertex_shader, 41 [VK_SHADER_STAGE_FRAGMENT_BIT] = shaderc_glsl_fragment_shader, 42 [VK_SHADER_STAGE_COMPUTE_BIT] = shaderc_glsl_compute_shader, 43 }; 44 45 shaderc_compile_options_t opts = shaderc_compile_options_initialize(); 46 if (!opts) 47 return AVERROR(ENOMEM); 48 49 shaderc_compile_options_set_target_env(opts, shaderc_target_env_vulkan, 50 shaderc_env_version_vulkan_1_2); 51 shaderc_compile_options_set_target_spirv(opts, shaderc_spirv_version_1_5); 52 shaderc_compile_options_set_optimization_level(opts, 53 shaderc_optimization_level_performance); 54 55 res = shaderc_compile_into_spv((shaderc_compiler_t)ctx->priv, 56 shd->src.str, strlen(shd->src.str), 57 shdc_kind[shd->shader.stage], 58 shd->name, entrypoint, opts); 59 shaderc_compile_options_release(opts); 60 61 ret = shaderc_result_get_compilation_status(res); 62 err = shaderc_result_get_num_errors(res); 63 warn = shaderc_result_get_num_warnings(res); 64 message = shaderc_result_get_error_message(res); 65 66 loglevel = err ? AV_LOG_ERROR : warn ? AV_LOG_WARNING : AV_LOG_VERBOSE; 67 68 ff_vk_print_shader(avctx, shd, loglevel); 69 if (message && (err || warn)) 70 av_log(avctx, loglevel, "%s\n", message); 71 status = ret < FF_ARRAY_ELEMS(shdc_result) ? shdc_result[ret] : "unknown"; 72 av_log(avctx, loglevel, "shaderc compile status '%s' (%d errors, %d warnings)\n", 73 status, err, warn); 74 75 if (err > 0) 76 return AVERROR(EINVAL); 77 78 *data = (uint8_t *)shaderc_result_get_bytes(res); 79 *size = shaderc_result_get_length(res); 80 *opaque = res; 81 82 return 0; 83} 84 85static void shdc_shader_free(FFVkSPIRVCompiler *ctx, void **opaque) 86{ 87 if (!opaque || !*opaque) 88 return; 89 90 shaderc_result_release((shaderc_compilation_result_t)*opaque); 91 *opaque = NULL; 92} 93 94static void shdc_uninit(FFVkSPIRVCompiler **ctx) 95{ 96 FFVkSPIRVCompiler *s; 97 98 if (!ctx || !*ctx) 99 return; 100 101 s = *ctx; 102 103 shaderc_compiler_release((shaderc_compiler_t)s->priv); 104 av_freep(ctx); 105} 106 107static FFVkSPIRVCompiler *ff_vk_shaderc_init(void) 108{ 109 FFVkSPIRVCompiler *ret = av_mallocz(sizeof(*ret)); 110 if (!ret) 111 return NULL; 112 113 ret->compile_shader = shdc_shader_compile; 114 ret->free_shader = shdc_shader_free; 115 ret->uninit = shdc_uninit; 116 117 ret->priv = (void *)shaderc_compiler_initialize(); 118 if (!ret->priv) 119 av_freep(&ret); 120 121 return ret; 122} 123