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
#![cfg(feature = "d3dcompiler")]

use crate::d3d::{Blob, ShaderMacro};
use crate::impl_bitflag_operators;
use crate::result::HResult;
use com_ptr::ComPtr;
use winapi::ctypes::c_void;
use winapi::um::d3dcompiler::*;

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct CompileFlags(u32);
impl_bitflag_operators!(CompileFlags);
#[allow(non_upper_case_globals)]
impl CompileFlags {
    pub const Debug: Self = Self(D3DCOMPILE_DEBUG);
    pub const SkipValidation: Self = Self(D3DCOMPILE_SKIP_VALIDATION);
    pub const SkipOptimization: Self = Self(D3DCOMPILE_SKIP_OPTIMIZATION);
    pub const PackMatrixRowMajor: Self = Self(D3DCOMPILE_PACK_MATRIX_ROW_MAJOR);
    pub const PackMatrixColumnMajor: Self = Self(D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR);
    pub const PartialPrecision: Self = Self(D3DCOMPILE_PARTIAL_PRECISION);
    pub const ForceVSSoftwareNoOpt: Self = Self(D3DCOMPILE_FORCE_VS_SOFTWARE_NO_OPT);
    pub const ForcePSSoftwareNoOpt: Self = Self(D3DCOMPILE_FORCE_PS_SOFTWARE_NO_OPT);
    pub const NoPreshader: Self = Self(D3DCOMPILE_NO_PRESHADER);
    pub const AvoidFlowControl: Self = Self(D3DCOMPILE_AVOID_FLOW_CONTROL);
    pub const EnableStrictness: Self = Self(D3DCOMPILE_ENABLE_STRICTNESS);
    pub const EnableBackwardsCompatiblity: Self = Self(D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY);
    pub const IEEEStrictness: Self = Self(D3DCOMPILE_IEEE_STRICTNESS);
    pub const OptimizationLevel0: Self = Self(D3DCOMPILE_OPTIMIZATION_LEVEL0);
    pub const OptimizationLevel1: Self = Self(D3DCOMPILE_OPTIMIZATION_LEVEL1);
    pub const OptimizationLevel2: Self = Self(D3DCOMPILE_OPTIMIZATION_LEVEL2);
    pub const OptimizationLevel3: Self = Self(D3DCOMPILE_OPTIMIZATION_LEVEL3);
    pub const WarningsAreErrors: Self = Self(D3DCOMPILE_WARNINGS_ARE_ERRORS);
    pub const ResourcesMayAlias: Self = Self(D3DCOMPILE_RESOURCES_MAY_ALIAS);
    pub const UnboundedDescriptorTables: Self = Self(D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES);
    pub const AllResourcesBound: Self = Self(D3DCOMPILE_ALL_RESOURCES_BOUND);
}

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct CompileEffectFlags(u32);
impl_bitflag_operators!(CompileEffectFlags);
#[allow(non_upper_case_globals)]
impl CompileEffectFlags {
    pub const ChildEfect: Self = Self(D3DCOMPILE_EFFECT_CHILD_EFFECT);
    pub const AllowSlowOps: Self = Self(D3DCOMPILE_EFFECT_ALLOW_SLOW_OPS);
}

pub fn compile(
    src_data: &[u8],
    src_name: Option<&str>,
    macros: Option<&[ShaderMacro]>,
    entry_point: &str,
    target: &str,
    flags1: Option<CompileFlags>,
    flags2: Option<CompileEffectFlags>,
) -> Result<Blob, (HResult, Blob)> {
    let c_src_name = src_name.map(|name| std::ffi::CString::new(name).unwrap());
    let c_macros: Option<(Vec<_>, Vec<_>)> =
        macros.map(|ms| ms.iter().map(|m| m.to_c_struct()).unzip());
    let c_entry_point = std::ffi::CString::new(entry_point).unwrap();
    let c_target = std::ffi::CString::new(target).unwrap();
    let mut blob = std::ptr::null_mut();
    let mut err_blob = std::ptr::null_mut();
    unsafe {
        let res = D3DCompile(
            src_data.as_ptr() as *const c_void,
            src_data.len(),
            c_src_name
                .as_ref()
                .map_or(std::ptr::null(), |name| name.as_ptr()),
            if let Some((ms, _tmp)) = c_macros.as_ref() {
                ms.as_ptr()
            } else {
                std::ptr::null()
            },
            D3D_COMPILE_STANDARD_FILE_INCLUDE,
            c_entry_point.as_ptr(),
            c_target.as_ptr(),
            flags1.map_or(0, |f| f.0),
            flags2.map_or(0, |f| f.0),
            &mut blob,
            &mut err_blob,
        );
        if res < 0 {
            Err((res.into(), Blob(ComPtr::from_raw(err_blob))))
        } else {
            Ok(Blob(ComPtr::from_raw(blob)))
        }
    }
}