1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
mod ScInternal {
    #![allow(dead_code)]
    #![allow(non_upper_case_globals)]
    #![allow(non_camel_case_types)]
    #![allow(non_snake_case)]
    include!(concat!("bindings.rs"));
}

macro_rules! check {
    ($check:expr) => {{
        let result = $check;
        if ScInternalResult::Success != result {
            return match result {
                _ => Err(ErrorCode::Unhandled)
            }
        }
    }}
}

pub mod compile {
    use ScInternal::root::*;
    use std::ptr;
    use std::ffi::CStr;
    use std::os::raw::c_void;

    #[derive(Debug)]
    pub enum ErrorCode {
        Unhandled = 1,
    }

    pub struct SpirvModule<'a> {
        ir: &'a [u32],
    }

    impl<'a> SpirvModule<'a> {
        pub fn new(ir: &[u32]) -> SpirvModule {
            SpirvModule { ir }
        }
    }

    pub struct ParsedSpirvModule {
        // TODO: Currently parsing and compilation must occur with the same compiler instance
        // (i.e. as opposed to splitting the parser/compiler which would be the ideal)
        // So temporarily we create the compiler instance during parse and reuse it during compilation
        // See https://github.com/KhronosGroup/SPIRV-Cross/issues/287
        internal_compiler: *mut c_void,
        internal_delete_compiler: fn(*mut c_void),
    }

    impl Drop for ParsedSpirvModule {
        fn drop(&mut self) {
            (self.internal_delete_compiler)(self.internal_compiler);
        }
    }

    pub struct HlslParseOptions;

    impl HlslParseOptions {
        pub fn new() -> HlslParseOptions {
            HlslParseOptions
        }
    }

    pub struct HlslCompileOptions;

    impl HlslCompileOptions {
        pub fn new() -> HlslCompileOptions {
            HlslCompileOptions
        }
    }

    pub struct HlslCompiler;

    fn internal_delete_compiler_hlsl(internal_compiler: *mut c_void) {
        unsafe {
            if ScInternalResult::Success != sc_internal_compiler_hlsl_delete(internal_compiler) {
                panic!("Cannot delete compiler");
            }
        }
    }

    impl HlslCompiler {
        pub fn new() -> HlslCompiler {
            HlslCompiler
        }

        pub fn parse(
            &self,
            module: &SpirvModule,
            _options: &HlslParseOptions,
        ) -> Result<ParsedSpirvModule, ErrorCode> {
            let ptr = module.ir.as_ptr() as *const u32;
            let mut compiler = ptr::null_mut();
            unsafe {
                check!(sc_internal_compiler_hlsl_new(
                    &mut compiler,
                    ptr,
                    module.ir.len() as usize
                ));

                Ok(ParsedSpirvModule {
                    internal_compiler: compiler,
                    internal_delete_compiler: internal_delete_compiler_hlsl,
                })
            }
        }

        pub fn compile(
            &self,
            module: &ParsedSpirvModule,
            _options: &HlslCompileOptions,
        ) -> Result<String, ErrorCode> {
            let compiler = module.internal_compiler;
            unsafe {
                let mut hlsl_ptr = ptr::null_mut();
                check!(sc_internal_compiler_hlsl_compile(compiler, &mut hlsl_ptr));
                let hlsl = match CStr::from_ptr(hlsl_ptr).to_owned().into_string() {
                    Err(_) => return Err(ErrorCode::Unhandled),
                    Ok(v) => v,
                };
                check!(sc_internal_deallocate_string(hlsl_ptr));
                Ok(hlsl)
            }
        }
    }
}