1use std::ffi::{CStr, CString};
11use std::os::raw::c_char;
12
13mod glslang_c_interface;
14
15use glslang_c_interface::*;
16
17pub type SpirvOutput = Vec<u32>;
18
19pub fn compile(
20 code: &str,
21 ty: ShaderType,
22 shader_defs: Option<&[String]>,
23) -> Result<SpirvOutput, String> {
24 compile_inner(Some((code, ty)), shader_defs)
25}
26
27fn compile_inner<'a, I>(shaders: I, shader_defs: Option<&[String]>) -> Result<SpirvOutput, String>
30where
31 I: IntoIterator<Item = (&'a str, ShaderType)>,
32{
33 let mut preamble = String::new();
34 if let Some(defs) = shader_defs {
35 for def in defs {
36 preamble.push_str("#define ");
37
38 let mut def = def.clone();
39 if let Some(end) = def.find('\n') {
40 def.truncate(end);
41 }
42
43 let def = def.replacen('=', " ", 1);
44
45 preamble.push_str(&def);
46 preamble.push('\n');
47 }
48 }
49
50 let mut data = Vec::new();
51
52 unsafe {
53 glslang_initialize_process();
54
55 for (source, ty) in shaders.into_iter() {
56 let stage = match ty {
57 ShaderType::Vertex => glslang_stage_t_GLSLANG_STAGE_VERTEX,
58 ShaderType::Fragment => glslang_stage_t_GLSLANG_STAGE_FRAGMENT,
59 ShaderType::Geometry => glslang_stage_t_GLSLANG_STAGE_GEOMETRY,
60 ShaderType::TessellationControl => glslang_stage_t_GLSLANG_STAGE_TESSCONTROL,
61 ShaderType::TessellationEvaluation => glslang_stage_t_GLSLANG_STAGE_TESSEVALUATION,
62 ShaderType::Compute => glslang_stage_t_GLSLANG_STAGE_COMPUTE,
63 };
64
65 let mut source = String::from(source);
66 if shader_defs.is_some() {
67 if let Some(version) = source.find(r##"#version"##) {
68 if let Some(newline) = &source[version..].find('\n') {
69 source.insert_str(version + newline + 1, &preamble);
70 }
71 }
72 }
73
74 let c_str = CString::new(source.as_str()).unwrap();
75 let code: *const c_char = c_str.as_ptr();
76
77 let input = &glslang_input_t {
78 language: glslang_source_t_GLSLANG_SOURCE_GLSL,
79 stage,
80 client: glslang_client_t_GLSLANG_CLIENT_VULKAN,
81 client_version: glslang_target_client_version_t_GLSLANG_TARGET_VULKAN_1_0,
82 target_language: glslang_target_language_t_GLSLANG_TARGET_SPV,
83 target_language_version: glslang_target_language_version_t_GLSLANG_TARGET_SPV_1_0,
84 code,
85 default_version: 100,
86 default_profile: glslang_profile_t_GLSLANG_NO_PROFILE,
87 force_default_version_and_profile: 0,
88 forward_compatible: 0,
89 messages: glslang_messages_t_GLSLANG_MSG_DEFAULT_BIT
90 | glslang_messages_t_GLSLANG_MSG_SPV_RULES_BIT
91 | glslang_messages_t_GLSLANG_MSG_VULKAN_RULES_BIT,
92 resource: DEFAULT_RESOURCE_LIMITS,
93 };
94
95 let shader = glslang_shader_create(input);
96
97 if glslang_shader_preprocess(shader, input) == 0 {
98 let c_info: &CStr = CStr::from_ptr(glslang_shader_get_info_log(shader));
99 let c_debug: &CStr = CStr::from_ptr(glslang_shader_get_info_debug_log(shader));
100
101 let mut error = String::from("glslang_shader_preprocess:\n");
102 error.push_str(&format!("Info log:\n{}\n", c_info.to_str().unwrap()));
103 error.push_str(&format!("Debug log:\n{}\n", c_debug.to_str().unwrap()));
104
105 return Err(error);
106 }
107 if glslang_shader_parse(shader, input) == 0 {
108 let c_info: &CStr = CStr::from_ptr(glslang_shader_get_info_log(shader));
109 let c_debug: &CStr = CStr::from_ptr(glslang_shader_get_info_debug_log(shader));
110
111 let mut error = String::from("glslang_shader_parse:\n");
112 error.push_str(&format!("Info log:\n{}\n", c_info.to_str().unwrap()));
113 error.push_str(&format!("Debug log:\n{}\n", c_debug.to_str().unwrap()));
114
115 return Err(error);
116 }
117
118 let program = glslang_program_create();
119 glslang_program_add_shader(program, shader);
120
121 if glslang_program_link(
122 program,
123 glslang_messages_t_GLSLANG_MSG_SPV_RULES_BIT
124 | glslang_messages_t_GLSLANG_MSG_VULKAN_RULES_BIT,
125 ) == 0
126 {
127 let c_info: &CStr = CStr::from_ptr(glslang_program_get_info_log(program));
128 let c_debug: &CStr = CStr::from_ptr(glslang_program_get_info_debug_log(program));
129
130 let mut error = String::from("glslang_program_link:\n");
131 error.push_str(&format!("Info log:\n{}\n", c_info.to_str().unwrap()));
132 error.push_str(&format!("Debug log:\n{}\n", c_debug.to_str().unwrap()));
133
134 return Err(error);
135 }
136
137 glslang_program_SPIRV_generate(program, input.stage);
138
139 if glslang_program_SPIRV_get_messages(program) != std::ptr::null() {
140 let c_messages: &CStr = CStr::from_ptr(glslang_program_SPIRV_get_messages(program));
141
142 println!("{:?}", c_messages);
143 }
144
145 let size = glslang_program_SPIRV_get_size(program) as usize;
146 let ptr = glslang_program_SPIRV_get_ptr(program) as *mut u32;
147 data = std::slice::from_raw_parts(ptr, size).to_vec();
148
149 glslang_program_delete(program);
150 glslang_shader_delete(shader);
151 }
152
153 glslang_finalize_process();
154 }
155
156 return Ok(data);
157}
158
159#[derive(Debug, Clone, PartialEq, Eq)]
161pub enum ShaderType {
162 Vertex,
163 Fragment,
164 Geometry,
165 TessellationControl,
166 TessellationEvaluation,
167 Compute,
168}
169
170const DEFAULT_RESOURCE_LIMITS: &glslang_resource_t = &glslang_resource_t {
172 max_lights: 32,
173 max_clip_planes: 6,
174 max_texture_units: 32,
175 max_texture_coords: 32,
176 max_vertex_attribs: 64,
177 max_vertex_uniform_components: 4096,
178 max_varying_floats: 64,
179 max_vertex_texture_image_units: 32,
180 max_combined_texture_image_units: 80,
181 max_texture_image_units: 32,
182 max_fragment_uniform_components: 4096,
183 max_draw_buffers: 32,
184 max_vertex_uniform_vectors: 128,
185 max_varying_vectors: 8,
186 max_fragment_uniform_vectors: 16,
187 max_vertex_output_vectors: 16,
188 max_fragment_input_vectors: 15,
189 min_program_texel_offset: -8,
190 max_program_texel_offset: 7,
191 max_clip_distances: 8,
192 max_compute_work_group_count_x: 65535,
193 max_compute_work_group_count_y: 65535,
194 max_compute_work_group_count_z: 65535,
195 max_compute_work_group_size_x: 1024,
196 max_compute_work_group_size_y: 1024,
197 max_compute_work_group_size_z: 64,
198 max_compute_uniform_components: 1024,
199 max_compute_texture_image_units: 16,
200 max_compute_image_uniforms: 8,
201 max_compute_atomic_counters: 8,
202 max_compute_atomic_counter_buffers: 1,
203 max_varying_components: 60,
204 max_vertex_output_components: 64,
205 max_geometry_input_components: 64,
206 max_geometry_output_components: 128,
207 max_fragment_input_components: 128,
208 max_image_units: 8,
209 max_combined_image_units_and_fragment_outputs: 8,
210 max_combined_shader_output_resources: 8,
211 max_image_samples: 0,
212 max_vertex_image_uniforms: 0,
213 max_tess_control_image_uniforms: 0,
214 max_tess_evaluation_image_uniforms: 0,
215 max_geometry_image_uniforms: 0,
216 max_fragment_image_uniforms: 8,
217 max_combined_image_uniforms: 8,
218 max_geometry_texture_image_units: 16,
219 max_geometry_output_vertices: 256,
220 max_geometry_total_output_components: 1024,
221 max_geometry_uniform_components: 1024,
222 max_geometry_varying_components: 64,
223 max_tess_control_input_components: 128,
224 max_tess_control_output_components: 128,
225 max_tess_control_texture_image_units: 16,
226 max_tess_control_uniform_components: 1024,
227 max_tess_control_total_output_components: 4096,
228 max_tess_evaluation_input_components: 128,
229 max_tess_evaluation_output_components: 128,
230 max_tess_evaluation_texture_image_units: 16,
231 max_tess_evaluation_uniform_components: 1024,
232 max_tess_patch_components: 120,
233 max_patch_vertices: 32,
234 max_tess_gen_level: 64,
235 max_viewports: 16,
236 max_vertex_atomic_counters: 0,
237 max_tess_control_atomic_counters: 0,
238 max_tess_evaluation_atomic_counters: 0,
239 max_geometry_atomic_counters: 0,
240 max_fragment_atomic_counters: 8,
241 max_combined_atomic_counters: 8,
242 max_atomic_counter_bindings: 1,
243 max_vertex_atomic_counter_buffers: 0,
244 max_tess_control_atomic_counter_buffers: 0,
245 max_tess_evaluation_atomic_counter_buffers: 0,
246 max_geometry_atomic_counter_buffers: 0,
247 max_fragment_atomic_counter_buffers: 1,
248 max_combined_atomic_counter_buffers: 1,
249 max_atomic_counter_buffer_size: 16384,
250 max_transform_feedback_buffers: 4,
251 max_transform_feedback_interleaved_components: 64,
252 max_cull_distances: 8,
253 max_combined_clip_and_cull_distances: 8,
254 max_samples: 4,
255 max_mesh_output_vertices_nv: 256,
256 max_mesh_output_primitives_nv: 512,
257 max_mesh_work_group_size_x_nv: 32,
258 max_mesh_work_group_size_y_nv: 1,
259 max_mesh_work_group_size_z_nv: 1,
260 max_task_work_group_size_x_nv: 32,
261 max_task_work_group_size_y_nv: 1,
262 max_task_work_group_size_z_nv: 1,
263 max_mesh_view_count_nv: 4,
264 limits: glslang_limits_s {
265 non_inductive_for_loops: true,
266 while_loops: true,
267 do_while_loops: true,
268 general_uniform_indexing: true,
269 general_attribute_matrix_vector_indexing: true,
270 general_varying_indexing: true,
271 general_sampler_indexing: true,
272 general_variable_indexing: true,
273 general_constant_matrix_vector_indexing: true,
274 },
275};