2 * This file is part of FFmpeg.
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.
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.
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
19 #include <glslang/build_info.h>
20 #include <glslang/Include/glslang_c_interface.h>
22 #include "vulkan_spirv.h"
23 #include "libavutil/mem.h"
24 #include "libavutil/avassert.h"
25 #include "libavutil/thread.h"
27 static AVMutex glslc_mutex
= AV_MUTEX_INITIALIZER
;
28 static int glslc_refcount
= 0;
30 static const glslang_resource_t glslc_resource_limits
= {
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,
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,
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,
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,
126 .non_inductive_for_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,
138 static int glslc_shader_compile(FFVulkanContext
*s
, FFVkSPIRVCompiler
*ctx
,
139 FFVulkanShader
*shd
, uint8_t **data
,
140 size_t *size
, const char *entrypoint
,
143 const char *messages
;
144 glslang_shader_t
*glslc_shader
;
145 glslang_program_t
*glslc_program
;
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
,
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
,
171 .client_version
= GLSLANG_TARGET_VULKAN_1_2
,
172 .target_language_version
= GLSLANG_TARGET_SPV_1_5
,
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
,
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
)),
194 /* .compile_only = 0, */
198 av_assert0(glslc_refcount
);
202 if (!(glslc_shader
= glslang_shader_create(&glslc_input
)))
203 return AVERROR(ENOMEM
);
205 if (!glslang_shader_preprocess(glslc_shader
, &glslc_input
)) {
206 ff_vk_shader_print(s
, shd
, AV_LOG_WARNING
);
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
);
214 if (!glslang_shader_parse(glslc_shader
, &glslc_input
)) {
215 ff_vk_shader_print(s
, shd
, AV_LOG_WARNING
);
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
);
223 if (!(glslc_program
= glslang_program_create())) {
224 glslang_shader_delete(glslc_shader
);
225 return AVERROR(EINVAL
);
228 glslang_program_add_shader(glslc_program
, glslc_shader
);
230 if (!glslang_program_link(glslc_program
, GLSLANG_MSG_SPV_RULES_BIT
|
231 GLSLANG_MSG_VULKAN_RULES_BIT
)) {
232 ff_vk_shader_print(s
, shd
, AV_LOG_WARNING
);
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
);
241 #if ((GLSLANG_VERSION_MAJOR) >= 12)
242 glslang_program_SPIRV_generate_with_options(glslc_program
, glslc_input
.stage
, &glslc_opts
);
244 glslang_program_SPIRV_generate(glslc_program
, glslc_input
.stage
);
247 messages
= glslang_program_SPIRV_get_messages(glslc_program
);
249 ff_vk_shader_print(s
, shd
, AV_LOG_WARNING
);
250 av_log(s
, AV_LOG_WARNING
, "%s\n", messages
);
252 ff_vk_shader_print(s
, shd
, AV_LOG_TRACE
);
255 glslang_shader_delete(glslc_shader
);
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
;
264 static void glslc_shader_free(FFVkSPIRVCompiler
*ctx
, void **opaque
)
266 if (!opaque
|| !*opaque
)
269 av_assert0(glslc_refcount
);
270 glslang_program_delete(*opaque
);
274 static void glslc_uninit(FFVkSPIRVCompiler
**ctx
)
279 ff_mutex_lock(&glslc_mutex
);
280 if (glslc_refcount
&& (--glslc_refcount
== 0))
281 glslang_finalize_process();
282 ff_mutex_unlock(&glslc_mutex
);
287 FFVkSPIRVCompiler
*ff_vk_glslang_init(void)
289 FFVkSPIRVCompiler
*ret
= av_mallocz(sizeof(*ret
));
293 ret
->compile_shader
= glslc_shader_compile
;
294 ret
->free_shader
= glslc_shader_free
;
295 ret
->uninit
= glslc_uninit
;
297 ff_mutex_lock(&glslc_mutex
);
298 if (!glslc_refcount
++) {
299 if (!glslang_initialize_process()) {
304 ff_mutex_unlock(&glslc_mutex
);