1#[allow(dead_code)]
2#[allow(non_upper_case_globals)]
3#[allow(non_camel_case_types)]
4#[allow(non_snake_case)]
5pub mod ffi {
6 include!(concat!(env!("OUT_DIR"), "/glslang_glue_bindings.rs"));
7}
8
9use self::ffi::ShShaderOutput::*;
10use self::ffi::ShShaderSpec::*;
11use self::ffi::*;
12
13use std::collections::HashMap;
14use std::default;
15use std::ffi::CStr;
16use std::ffi::CString;
17use std::mem::MaybeUninit;
18use std::os::raw::c_char;
19use std::os::raw::c_void;
20use std::slice;
21use std::str;
22use std::sync::Mutex;
23
24static CONSTRUCT_COMPILER_LOCK: Mutex<()> = Mutex::new(());
25
26pub fn initialize() -> Result<(), &'static str> {
27 if unsafe { GLSLangInitialize() } == 0 {
28 Err("Couldn't initialize GLSLang")
29 } else {
30 Ok(())
31 }
32}
33
34pub fn finalize() -> Result<(), &'static str> {
35 if unsafe { GLSLangFinalize() } == 0 {
36 Err("Couldn't finalize GLSLang")
37 } else {
38 Ok(())
39 }
40}
41
42pub trait AsAngleEnum {
43 fn as_angle_enum(&self) -> u32;
44}
45
46pub enum ShaderSpec {
47 Gles2,
48 WebGL,
49 Gles3,
50 WebGL2,
51 WebGL3,
52}
53
54impl AsAngleEnum for ShaderSpec {
55 #[inline]
56 fn as_angle_enum(&self) -> u32 {
57 (match *self {
58 ShaderSpec::Gles2 => SH_GLES2_SPEC,
59 ShaderSpec::WebGL => SH_WEBGL_SPEC,
60 ShaderSpec::Gles3 => SH_GLES3_SPEC,
61 ShaderSpec::WebGL2 => SH_WEBGL2_SPEC,
62 ShaderSpec::WebGL3 => SH_WEBGL3_SPEC,
63 }) as u32
64 }
65}
66
67pub enum Output {
68 Essl,
69 Glsl,
70 GlslCompat,
71 GlslCore,
72 Glsl130,
73 Glsl140,
74 Glsl150Core,
75 Glsl330Core,
76 Glsl400Core,
77 Glsl410Core,
78 Glsl420Core,
79 Glsl430Core,
80 Glsl440Core,
81 Glsl450Core,
82}
83
84impl AsAngleEnum for Output {
85 #[inline]
86 fn as_angle_enum(&self) -> u32 {
87 (match *self {
88 Output::Essl => SH_ESSL_OUTPUT,
89 Output::Glsl => SH_GLSL_COMPATIBILITY_OUTPUT,
90 Output::GlslCompat => SH_GLSL_COMPATIBILITY_OUTPUT,
91 Output::GlslCore => SH_GLSL_130_OUTPUT,
92 Output::Glsl130 => SH_GLSL_130_OUTPUT,
93 Output::Glsl140 => SH_GLSL_140_OUTPUT,
94 Output::Glsl150Core => SH_GLSL_150_CORE_OUTPUT,
95 Output::Glsl330Core => SH_GLSL_330_CORE_OUTPUT,
96 Output::Glsl400Core => SH_GLSL_400_CORE_OUTPUT,
97 Output::Glsl410Core => SH_GLSL_410_CORE_OUTPUT,
98 Output::Glsl420Core => SH_GLSL_420_CORE_OUTPUT,
99 Output::Glsl430Core => SH_GLSL_430_CORE_OUTPUT,
100 Output::Glsl440Core => SH_GLSL_440_CORE_OUTPUT,
101 Output::Glsl450Core => SH_GLSL_450_CORE_OUTPUT,
102 }) as u32
103 }
104}
105
106pub type BuiltInResources = ShBuiltInResources;
107
108impl default::Default for BuiltInResources {
109 fn default() -> BuiltInResources {
110 unsafe {
111 let mut ret: BuiltInResources = Self::empty();
112 GLSLangInitBuiltInResources(&mut ret);
113 ret
114 }
115 }
116}
117
118impl BuiltInResources {
119 #[inline]
120 pub fn empty() -> BuiltInResources {
121 unsafe { MaybeUninit::zeroed().assume_init() }
122 }
123}
124
125pub type CompileOptions = ShCompileOptions;
126
127impl CompileOptions {
128 pub fn mozangle() -> Self {
129 let mut options = unsafe { CompileOptions::new() };
130 options.set_objectCode(1);
131 options.set_variables(1); options.set_emulateAbsIntFunction(1); options.set_emulateIsnanFloatFunction(1); options.set_emulateAtan2FloatFunction(1); options.set_clampIndirectArrayBounds(1);
136 options.set_initGLPosition(1);
137 options.set_enforcePackingRestrictions(1);
138 options.set_limitExpressionComplexity(1);
139 options.set_limitCallStackDepth(1);
140 options
144 }
145}
146
147pub struct ShaderValidator {
148 handle: ShHandle,
149}
150
151impl ShaderValidator {
152 pub fn new(
156 shader_type: u32,
157 spec: ShaderSpec,
158 output: Output,
159 resources: &BuiltInResources,
160 ) -> Option<ShaderValidator> {
161 let _guard = CONSTRUCT_COMPILER_LOCK.lock().unwrap();
164 let handle = unsafe {
165 GLSLangConstructCompiler(
166 shader_type,
167 spec.as_angle_enum(),
168 output.as_angle_enum(),
169 resources,
170 )
171 };
172
173 if handle.is_null() {
174 return None;
175 }
176
177 Some(ShaderValidator { handle: handle })
178 }
179
180 #[inline]
181 pub fn for_webgl(
182 shader_type: u32,
183 output: Output,
184 resources: &BuiltInResources,
185 ) -> Option<ShaderValidator> {
186 Self::new(shader_type, ShaderSpec::WebGL, output, resources)
187 }
188
189 #[inline]
190 pub fn for_webgl2(
191 shader_type: u32,
192 output: Output,
193 resources: &BuiltInResources,
194 ) -> Option<ShaderValidator> {
195 Self::new(shader_type, ShaderSpec::WebGL2, output, resources)
196 }
197
198 pub fn compile(&self, strings: &[&str], options: ShCompileOptions) -> Result<(), &'static str> {
199 let mut cstrings = Vec::with_capacity(strings.len());
200
201 for s in strings.iter() {
202 cstrings.push(CString::new(*s).map_err(|_| "Found invalid characters")?)
203 }
204
205 let cptrs: Vec<_> = cstrings.iter().map(|s| s.as_ptr()).collect();
206
207 if unsafe {
208 GLSLangCompile(
209 self.handle,
210 cptrs.as_ptr() as *const *const c_char,
211 cstrings.len(),
212 &options as *const _,
213 )
214 } == 0
215 {
216 return Err("Couldn't compile shader");
217 }
218 Ok(())
219 }
220
221 pub fn object_code(&self) -> String {
222 unsafe {
223 let c_str = CStr::from_ptr(GLSLangGetObjectCode(self.handle));
224 c_str.to_string_lossy().into_owned()
225 }
226 }
227
228 pub fn info_log(&self) -> String {
229 unsafe {
230 let c_str = CStr::from_ptr(GLSLangGetInfoLog(self.handle));
231 c_str.to_string_lossy().into_owned()
232 }
233 }
234
235 pub fn compile_and_translate(&self, strings: &[&str]) -> Result<String, &'static str> {
236 let options = CompileOptions::mozangle();
237 self.compile(strings, options)?;
238 Ok(self.object_code())
239 }
240
241 pub fn uniform_name_map(&self) -> HashMap<String, String> {
246 struct Closure {
247 map: HashMap<String, String>,
248 error: Option<str::Utf8Error>,
249 }
250
251 unsafe extern "C" fn each_c(
252 closure: *mut c_void,
253 first: *const c_char,
254 first_len: usize,
255 second: *const c_char,
256 second_len: usize,
257 ) {
258 let closure = closure as *mut Closure;
262 let closure = &mut *closure;
263 if closure.error.is_none() {
264 macro_rules! to_string {
265 ($ptr: expr, $len: expr) => {
266 match str::from_utf8(slice::from_raw_parts($ptr as *const u8, $len)) {
267 Ok(s) => s.to_owned(),
268 Err(e) => {
269 closure.error = Some(e);
270 return;
271 }
272 }
273 };
274 }
275 closure
276 .map
277 .insert(to_string!(first, first_len), to_string!(second, second_len));
278 }
279 }
280
281 let mut closure = Closure {
282 map: HashMap::new(),
283 error: None,
284 };
285 let closure_ptr: *mut Closure = &mut closure;
286 unsafe {
287 GLSLangIterUniformNameMapping(self.handle, Some(each_c), closure_ptr as *mut c_void)
288 }
289 if let Some(err) = closure.error {
290 panic!("Non-UTF-8 uniform name in ANGLE shader: {}", err)
291 }
292 closure.map
293 }
294
295 pub fn get_num_unpacked_varying_vectors(&self) -> i32 {
296 unsafe { GLSLangGetNumUnpackedVaryingVectors(self.handle) }
297 }
298}
299
300impl Drop for ShaderValidator {
301 fn drop(&mut self) {
302 unsafe { GLSLangDestructCompiler(self.handle) }
303 }
304}