FFmpeg
vulkan_glslang.c
Go to the documentation of this file.
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 <glslang/build_info.h>
20 #include <glslang/Include/glslang_c_interface.h>
21 
22 #include "vulkan_spirv.h"
23 #include "libavutil/mem.h"
24 #include "libavutil/avassert.h"
25 #include "libavutil/thread.h"
26 
28 static int glslc_refcount = 0;
29 
30 static const glslang_resource_t glslc_resource_limits = {
31  .max_lights = 32,
32  .max_clip_planes = 6,
33  .max_texture_units = 32,
34  .max_texture_coords = 32,
35  .max_vertex_attribs = 64,
36  .max_vertex_uniform_components = 4096,
37  .max_varying_floats = 64,
38  .max_vertex_texture_image_units = 32,
39  .max_combined_texture_image_units = 80,
40  .max_texture_image_units = 32,
41  .max_fragment_uniform_components = 4096,
42  .max_draw_buffers = 32,
43  .max_vertex_uniform_vectors = 128,
44  .max_varying_vectors = 8,
45  .max_fragment_uniform_vectors = 16,
46  .max_vertex_output_vectors = 16,
47  .max_fragment_input_vectors = 15,
48  .min_program_texel_offset = -8,
49  .max_program_texel_offset = 7,
50  .max_clip_distances = 8,
51  .max_compute_work_group_count_x = 65535,
52  .max_compute_work_group_count_y = 65535,
53  .max_compute_work_group_count_z = 65535,
54  .max_compute_work_group_size_x = 1024,
55  .max_compute_work_group_size_y = 1024,
56  .max_compute_work_group_size_z = 64,
57  .max_compute_uniform_components = 1024,
58  .max_compute_texture_image_units = 16,
59  .max_compute_image_uniforms = 8,
60  .max_compute_atomic_counters = 8,
61  .max_compute_atomic_counter_buffers = 1,
62  .max_varying_components = 60,
63  .max_vertex_output_components = 64,
64  .max_geometry_input_components = 64,
65  .max_geometry_output_components = 128,
66  .max_fragment_input_components = 128,
67  .max_image_units = 8,
68  .max_combined_image_units_and_fragment_outputs = 8,
69  .max_combined_shader_output_resources = 8,
70  .max_image_samples = 0,
71  .max_vertex_image_uniforms = 0,
72  .max_tess_control_image_uniforms = 0,
73  .max_tess_evaluation_image_uniforms = 0,
74  .max_geometry_image_uniforms = 0,
75  .max_fragment_image_uniforms = 8,
76  .max_combined_image_uniforms = 8,
77  .max_geometry_texture_image_units = 16,
78  .max_geometry_output_vertices = 256,
79  .max_geometry_total_output_components = 1024,
80  .max_geometry_uniform_components = 1024,
81  .max_geometry_varying_components = 64,
82  .max_tess_control_input_components = 128,
83  .max_tess_control_output_components = 128,
84  .max_tess_control_texture_image_units = 16,
85  .max_tess_control_uniform_components = 1024,
86  .max_tess_control_total_output_components = 4096,
87  .max_tess_evaluation_input_components = 128,
88  .max_tess_evaluation_output_components = 128,
89  .max_tess_evaluation_texture_image_units = 16,
90  .max_tess_evaluation_uniform_components = 1024,
91  .max_tess_patch_components = 120,
92  .max_patch_vertices = 32,
93  .max_tess_gen_level = 64,
94  .max_viewports = 16,
95  .max_vertex_atomic_counters = 0,
96  .max_tess_control_atomic_counters = 0,
97  .max_tess_evaluation_atomic_counters = 0,
98  .max_geometry_atomic_counters = 0,
99  .max_fragment_atomic_counters = 8,
100  .max_combined_atomic_counters = 8,
101  .max_atomic_counter_bindings = 1,
102  .max_vertex_atomic_counter_buffers = 0,
103  .max_tess_control_atomic_counter_buffers = 0,
104  .max_tess_evaluation_atomic_counter_buffers = 0,
105  .max_geometry_atomic_counter_buffers = 0,
106  .max_fragment_atomic_counter_buffers = 1,
107  .max_combined_atomic_counter_buffers = 1,
108  .max_atomic_counter_buffer_size = 16384,
109  .max_transform_feedback_buffers = 4,
110  .max_transform_feedback_interleaved_components = 64,
111  .max_cull_distances = 8,
112  .max_combined_clip_and_cull_distances = 8,
113  .max_samples = 4,
114  .max_mesh_output_vertices_nv = 256,
115  .max_mesh_output_primitives_nv = 512,
116  .max_mesh_work_group_size_x_nv = 32,
117  .max_mesh_work_group_size_y_nv = 1,
118  .max_mesh_work_group_size_z_nv = 1,
119  .max_task_work_group_size_x_nv = 32,
120  .max_task_work_group_size_y_nv = 1,
121  .max_task_work_group_size_z_nv = 1,
122  .max_mesh_view_count_nv = 4,
123  .maxDualSourceDrawBuffersEXT = 1,
124 
125  .limits = {
126  .non_inductive_for_loops = 1,
127  .while_loops = 1,
128  .do_while_loops = 1,
129  .general_uniform_indexing = 1,
130  .general_attribute_matrix_vector_indexing = 1,
131  .general_varying_indexing = 1,
132  .general_sampler_indexing = 1,
133  .general_variable_indexing = 1,
134  .general_constant_matrix_vector_indexing = 1,
135  }
136 };
137 
139  FFVulkanShader *shd, uint8_t **data,
140  size_t *size, const char *entrypoint,
141  void **opaque)
142 {
143  const char *messages;
144  glslang_shader_t *glslc_shader;
145  glslang_program_t *glslc_program;
146 
147  static const glslang_stage_t glslc_stage[] = {
148  [VK_SHADER_STAGE_VERTEX_BIT] = GLSLANG_STAGE_VERTEX,
149  [VK_SHADER_STAGE_FRAGMENT_BIT] = GLSLANG_STAGE_FRAGMENT,
150  [VK_SHADER_STAGE_COMPUTE_BIT] = GLSLANG_STAGE_COMPUTE,
151 #if ((GLSLANG_VERSION_MAJOR) > 12)
152  [VK_SHADER_STAGE_TASK_BIT_EXT] = GLSLANG_STAGE_TASK,
153  [VK_SHADER_STAGE_MESH_BIT_EXT] = GLSLANG_STAGE_MESH,
154  [VK_SHADER_STAGE_RAYGEN_BIT_KHR] = GLSLANG_STAGE_RAYGEN,
155  [VK_SHADER_STAGE_INTERSECTION_BIT_KHR] = GLSLANG_STAGE_INTERSECT,
156  [VK_SHADER_STAGE_ANY_HIT_BIT_KHR] = GLSLANG_STAGE_ANYHIT,
157  [VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR] = GLSLANG_STAGE_CLOSESTHIT,
158  [VK_SHADER_STAGE_MISS_BIT_KHR] = GLSLANG_STAGE_MISS,
159  [VK_SHADER_STAGE_CALLABLE_BIT_KHR] = GLSLANG_STAGE_CALLABLE,
160 #endif
161  };
162 
163  const glslang_input_t glslc_input = {
164  .language = GLSLANG_SOURCE_GLSL,
165  .stage = glslc_stage[shd->stage],
166  .client = GLSLANG_CLIENT_VULKAN,
167 #if ((GLSLANG_VERSION_MAJOR) >= 12)
168  .client_version = GLSLANG_TARGET_VULKAN_1_3,
169  .target_language_version = GLSLANG_TARGET_SPV_1_6,
170 #else
171  .client_version = GLSLANG_TARGET_VULKAN_1_2,
172  .target_language_version = GLSLANG_TARGET_SPV_1_5,
173 #endif
174  .target_language = GLSLANG_TARGET_SPV,
175  .code = shd->src.str,
176  .default_version = 460,
177  .default_profile = GLSLANG_NO_PROFILE,
178  .force_default_version_and_profile = false,
179  .forward_compatible = false,
180  .messages = GLSLANG_MSG_DEFAULT_BIT,
181  .resource = &glslc_resource_limits,
182  };
183 
184 #if ((GLSLANG_VERSION_MAJOR) >= 12)
185  glslang_spv_options_t glslc_opts = {
186  .generate_debug_info = !!(s->extensions & (FF_VK_EXT_DEBUG_UTILS | FF_VK_EXT_RELAXED_EXTENDED_INSTR)),
187  .emit_nonsemantic_shader_debug_info = !!(s->extensions & FF_VK_EXT_RELAXED_EXTENDED_INSTR),
188  .emit_nonsemantic_shader_debug_source = !!(s->extensions & FF_VK_EXT_RELAXED_EXTENDED_INSTR),
189  .disable_optimizer = !!(s->extensions & FF_VK_EXT_DEBUG_UTILS),
190  .strip_debug_info = !(s->extensions & (FF_VK_EXT_DEBUG_UTILS | FF_VK_EXT_RELAXED_EXTENDED_INSTR)),
191  .optimize_size = 0,
192  .disassemble = 0,
193  .validate = 1,
194  /* .compile_only = 0, */
195  };
196 #endif
197 
199 
200  *opaque = NULL;
201 
202  if (!(glslc_shader = glslang_shader_create(&glslc_input)))
203  return AVERROR(ENOMEM);
204 
205  if (!glslang_shader_preprocess(glslc_shader, &glslc_input)) {
207  av_log(s, AV_LOG_ERROR, "Unable to preprocess shader: %s (%s)!\n",
208  glslang_shader_get_info_log(glslc_shader),
209  glslang_shader_get_info_debug_log(glslc_shader));
210  glslang_shader_delete(glslc_shader);
211  return AVERROR(EINVAL);
212  }
213 
214  if (!glslang_shader_parse(glslc_shader, &glslc_input)) {
216  av_log(s, AV_LOG_ERROR, "Unable to parse shader: %s (%s)!\n",
217  glslang_shader_get_info_log(glslc_shader),
218  glslang_shader_get_info_debug_log(glslc_shader));
219  glslang_shader_delete(glslc_shader);
220  return AVERROR(EINVAL);
221  }
222 
223  if (!(glslc_program = glslang_program_create())) {
224  glslang_shader_delete(glslc_shader);
225  return AVERROR(EINVAL);
226  }
227 
228  glslang_program_add_shader(glslc_program, glslc_shader);
229 
230  if (!glslang_program_link(glslc_program, GLSLANG_MSG_SPV_RULES_BIT |
231  GLSLANG_MSG_VULKAN_RULES_BIT)) {
233  av_log(s, AV_LOG_ERROR, "Unable to link shader: %s (%s)!\n",
234  glslang_program_get_info_log(glslc_program),
235  glslang_program_get_info_debug_log(glslc_program));
236  glslang_program_delete(glslc_program);
237  glslang_shader_delete(glslc_shader);
238  return AVERROR(EINVAL);
239  }
240 
241 #if ((GLSLANG_VERSION_MAJOR) >= 12)
242  glslang_program_SPIRV_generate_with_options(glslc_program, glslc_input.stage, &glslc_opts);
243 #else
244  glslang_program_SPIRV_generate(glslc_program, glslc_input.stage);
245 #endif
246 
247  messages = glslang_program_SPIRV_get_messages(glslc_program);
248  if (messages) {
250  av_log(s, AV_LOG_WARNING, "%s\n", messages);
251  } else {
253  }
254 
255  glslang_shader_delete(glslc_shader);
256 
257  *size = glslang_program_SPIRV_get_size(glslc_program) * sizeof(unsigned int);
258  *data = (void *)glslang_program_SPIRV_get_ptr(glslc_program);
259  *opaque = glslc_program;
260 
261  return 0;
262 }
263 
264 static void glslc_shader_free(FFVkSPIRVCompiler *ctx, void **opaque)
265 {
266  if (!opaque || !*opaque)
267  return;
268 
270  glslang_program_delete(*opaque);
271  *opaque = NULL;
272 }
273 
275 {
276  if (!ctx || !*ctx)
277  return;
278 
280  if (glslc_refcount && (--glslc_refcount == 0))
281  glslang_finalize_process();
283 
284  av_freep(ctx);
285 }
286 
288 {
289  FFVkSPIRVCompiler *ret = av_mallocz(sizeof(*ret));
290  if (!ret)
291  return NULL;
292 
293  ret->compile_shader = glslc_shader_compile;
294  ret->free_shader = glslc_shader_free;
295  ret->uninit = glslc_uninit;
296 
298  if (!glslc_refcount++) {
299  if (!glslang_initialize_process()) {
300  av_freep(&ret);
301  glslc_refcount--;
302  }
303  }
305 
306  return ret;
307 }
glslc_mutex
static AVMutex glslc_mutex
Definition: vulkan_glslang.c:27
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:216
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
thread.h
FFVulkanShader::src
AVBPrint src
Definition: vulkan.h:195
data
const char data[16]
Definition: mxf.c:149
glslc_shader_compile
static int glslc_shader_compile(FFVulkanContext *s, FFVkSPIRVCompiler *ctx, FFVulkanShader *shd, uint8_t **data, size_t *size, const char *entrypoint, void **opaque)
Definition: vulkan_glslang.c:138
ff_mutex_unlock
static int ff_mutex_unlock(AVMutex *mutex)
Definition: thread.h:189
avassert.h
AV_LOG_TRACE
#define AV_LOG_TRACE
Extremely verbose debugging, useful for libav* development.
Definition: log.h:236
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:210
AVMutex
#define AVMutex
Definition: thread.h:184
s
#define s(width, name)
Definition: cbs_vp9.c:198
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:41
FFVulkanShader::stage
VkPipelineStageFlags stage
Definition: vulkan.h:201
ctx
AVFormatContext * ctx
Definition: movenc.c:49
NULL
#define NULL
Definition: coverity.c:32
ff_vk_glslang_init
FFVkSPIRVCompiler * ff_vk_glslang_init(void)
Definition: vulkan_glslang.c:287
FFVulkanContext
Definition: vulkan.h:274
AV_MUTEX_INITIALIZER
#define AV_MUTEX_INITIALIZER
Definition: thread.h:185
size
int size
Definition: twinvq_data.h:10344
glslc_uninit
static void glslc_uninit(FFVkSPIRVCompiler **ctx)
Definition: vulkan_glslang.c:274
glslc_shader_free
static void glslc_shader_free(FFVkSPIRVCompiler *ctx, void **opaque)
Definition: vulkan_glslang.c:264
FFVulkanShader
Definition: vulkan.h:190
ff_mutex_lock
static int ff_mutex_lock(AVMutex *mutex)
Definition: thread.h:188
FFVkSPIRVCompiler
Definition: vulkan_spirv.h:26
FF_VK_EXT_RELAXED_EXTENDED_INSTR
#define FF_VK_EXT_RELAXED_EXTENDED_INSTR
Definition: vulkan_functions.h:49
glslc_refcount
static int glslc_refcount
Definition: vulkan_glslang.c:28
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:256
glslc_resource_limits
static const glslang_resource_t glslc_resource_limits
Definition: vulkan_glslang.c:30
vulkan_spirv.h
ret
ret
Definition: filter_design.txt:187
mem.h
ff_vk_shader_print
void ff_vk_shader_print(void *ctx, FFVulkanShader *shd, int prio)
Output the shader code as logging data, with a specific priority.
Definition: vulkan.c:2130
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
FF_VK_EXT_DEBUG_UTILS
#define FF_VK_EXT_DEBUG_UTILS
Definition: vulkan_functions.h:37
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27