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
use super::Builder;
use crate::builder_spirv::{SpirvValue, SpirvValueExt};
use crate::custom_insts;
use rspirv::spirv::{GLOp, Word};
use rspirv::{dr::Operand, spirv::Capability};

const GLSL_STD_450: &str = "GLSL.std.450";

/// Manager for OpExtInst/OpExtImport instructions
#[derive(Default)]
pub struct ExtInst {
    /// See `crate::custom_insts` for more details on what this entails.
    custom: Option<Word>,

    glsl: Option<Word>,
    integer_functions_2_intel: bool,
}

impl ExtInst {
    pub fn import_custom(&mut self, bx: &Builder<'_, '_>) -> Word {
        if let Some(id) = self.custom {
            id
        } else {
            let id = bx
                .emit_global()
                .ext_inst_import(custom_insts::CUSTOM_EXT_INST_SET.clone());
            self.custom = Some(id);
            id
        }
    }

    pub fn import_glsl(&mut self, bx: &Builder<'_, '_>) -> Word {
        if let Some(id) = self.glsl {
            id
        } else {
            let id = bx.emit_global().ext_inst_import(GLSL_STD_450);
            self.glsl = Some(id);
            id
        }
    }

    pub fn require_integer_functions_2_intel(&mut self, bx: &Builder<'_, '_>, to_zombie: Word) {
        if !self.integer_functions_2_intel {
            self.integer_functions_2_intel = true;
            if !bx
                .builder
                .has_capability(Capability::IntegerFunctions2INTEL)
            {
                bx.zombie(to_zombie, "capability IntegerFunctions2INTEL is required");
            }
            if !bx
                .builder
                .has_extension(bx.sym.spv_intel_shader_integer_functions2)
            {
                bx.zombie(
                    to_zombie,
                    "extension SPV_INTEL_shader_integer_functions2 is required",
                );
            }
        }
    }
}

impl<'a, 'tcx> Builder<'a, 'tcx> {
    pub fn custom_inst(
        &mut self,
        result_type: Word,
        inst: custom_insts::CustomInst<Operand>,
    ) -> SpirvValue {
        let custom_ext_inst_set = self.ext_inst.borrow_mut().import_custom(self);
        self.emit()
            .ext_inst(
                result_type,
                None,
                custom_ext_inst_set,
                inst.op() as u32,
                inst.into_operands(),
            )
            .unwrap()
            .with_type(result_type)
    }

    pub fn gl_op(
        &mut self,
        op: GLOp,
        result_type: Word,
        args: impl AsRef<[SpirvValue]>,
    ) -> SpirvValue {
        let args = args.as_ref();
        let glsl = self.ext_inst.borrow_mut().import_glsl(self);
        self.emit()
            .ext_inst(
                result_type,
                None,
                glsl,
                op as u32,
                args.iter().map(|a| Operand::IdRef(a.def(self))),
            )
            .unwrap()
            .with_type(result_type)
    }
}