spirv_tools_sys/
shared.rs

1use std::fmt;
2
3/// Certain target environments impose additional restrictions on SPIR-V, so it's
4/// often necessary to specify which one applies. `Universal_*` implies an
5/// environment-agnostic SPIR-V.
6///
7/// When an API method needs to derive a SPIR-V version from a target environment
8/// the method will choose the highest version of SPIR-V supported by the target
9/// environment. Examples:
10///
11/// ```text
12///    SPV_ENV_VULKAN_1_0           ->  SPIR-V 1.0
13///    SPV_ENV_VULKAN_1_1           ->  SPIR-V 1.3
14///    SPV_ENV_VULKAN_1_1_SPIRV_1_4 ->  SPIR-V 1.4
15///    SPV_ENV_VULKAN_1_2           ->  SPIR-V 1.5
16/// ```
17///
18/// Consult the description of API entry points for specific rules.
19#[derive(Copy, Clone, Debug, PartialEq)]
20#[repr(C)]
21#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
22pub enum TargetEnv {
23    /// SPIR-V 1.0 latest revision, no other restrictions.
24    Universal_1_0,
25    /// Vulkan 1.0 latest revision.
26    Vulkan_1_0,
27    /// SPIR-V 1.1 latest revision, no other restrictions.
28    Universal_1_1,
29    /// `OpenCL` Full Profile 2.1 latest revision.
30    OpenCL_2_1,
31    /// `OpenCL` Full Profile 2.2 latest revision.
32    OpenCL_2_2,
33    /// OpenGL 4.0 plus `GL_ARB_gl_spirv`, latest revisions.
34    OpenGL_4_0,
35    /// OpenGL 4.1 plus `GL_ARB_gl_spirv`, latest revisions.
36    OpenGL_4_1,
37    /// OpenGL 4.2 plus `GL_ARB_gl_spirv`, latest revisions.
38    OpenGL_4_2,
39    /// OpenGL 4.3 plus `GL_ARB_gl_spirv`, latest revisions.
40    OpenGL_4_3,
41    /// OpenGL 4.5 plus `GL_ARB_gl_spirv`, latest revisions.
42    OpenGL_4_5,
43    /// SPIR-V 1.2, latest revision, no other restrictions.
44    Universal_1_2,
45    /// `OpenCL` Full Profile 1.2 plus `cl_khr_il_program`, latest revision.
46    OpenCL_1_2,
47    /// `OpenCL` Embedded Profile 1.2 plus `cl_khr_il_program`, latest revision.
48    OpenCLEmbedded_1_2,
49    /// `OpenCL` Full Profile 2.0 plus `cl_khr_il_program`, latest revision.
50    OpenCL_2_0,
51    /// `OpenCL` Embedded Profile 2.0 plus `cl_khr_il_program`, latest revision.
52    OpenCLEmbedded_2_0,
53    /// `OpenCL` Embedded Profile 2.1 latest revision.
54    OpenCLEmbedded_2_1,
55    /// `OpenCL` Embedded Profile 2.2 latest revision.
56    OpenCLEmbedded_2_2,
57    /// SPIR-V 1.3 latest revision, no other restrictions.
58    Universal_1_3,
59    /// Vulkan 1.1 latest revision.
60    Vulkan_1_1,
61    /// Work in progress WebGPU 1.0.
62    WebGPU_0,
63    /// SPIR-V 1.4 latest revision, no other restrictions.
64    Universal_1_4,
65    /// Vulkan 1.1 with `VK_KHR_spirv_1_4`, i.e. SPIR-V 1.4 binary.
66    Vulkan_1_1_Spirv_1_4,
67    /// SPIR-V 1.5 latest revision, no other restrictions.
68    Universal_1_5,
69    /// Vulkan 1.2 latest revision.
70    Vulkan_1_2,
71    /// SPIR-V 1.6 latest revision, no other restrictions.
72    Universal_1_6,
73    /// Vulkan 1.3 latest revision.
74    Vulkan_1_3,
75    /// Vulkan 1.4 latest revision.
76    Vulkan_1_4,
77}
78
79impl TargetEnv {
80    /// Returns the `(mayor, minor)` version of spv this enum variant must at least support
81    ///
82    /// The spirv versions for vulkan targets have been pulled from the source of the vulkan spec:
83    /// <https://github.com/KhronosGroup/Vulkan-Docs/blob/main/appendices/spirvenv.adoc?plain=1#L21>
84    pub fn spirv_version(&self) -> (u8, u8) {
85        #[allow(clippy::match_same_arms)]
86        match self {
87            TargetEnv::Universal_1_0 => (1, 0),
88            TargetEnv::Universal_1_1 => (1, 1),
89            TargetEnv::Universal_1_2 => (1, 2),
90            TargetEnv::Universal_1_3 => (1, 3),
91            TargetEnv::Universal_1_4 => (1, 4),
92            TargetEnv::Universal_1_5 => (1, 5),
93            TargetEnv::Universal_1_6 => (1, 6),
94
95            TargetEnv::OpenGL_4_0 => (1, 0),
96            TargetEnv::OpenGL_4_1 => (1, 0),
97            TargetEnv::OpenGL_4_2 => (1, 0),
98            TargetEnv::OpenGL_4_3 => (1, 0),
99            TargetEnv::OpenGL_4_5 => (1, 0),
100
101            TargetEnv::OpenCL_1_2 => (1, 0),
102            TargetEnv::OpenCL_2_0 => (1, 0),
103            TargetEnv::OpenCL_2_1 => (1, 0),
104            TargetEnv::OpenCL_2_2 => (1, 2),
105            TargetEnv::OpenCLEmbedded_1_2 => (1, 0),
106            TargetEnv::OpenCLEmbedded_2_0 => (1, 0),
107            TargetEnv::OpenCLEmbedded_2_1 => (1, 0),
108            TargetEnv::OpenCLEmbedded_2_2 => (1, 2),
109
110            TargetEnv::Vulkan_1_0 => (1, 0),
111            TargetEnv::Vulkan_1_1 => (1, 3),
112            TargetEnv::WebGPU_0 => (1, 3),
113            TargetEnv::Vulkan_1_1_Spirv_1_4 => (1, 4),
114            TargetEnv::Vulkan_1_2 => (1, 5),
115            TargetEnv::Vulkan_1_3 => (1, 6),
116            TargetEnv::Vulkan_1_4 => (1, 6),
117        }
118    }
119}
120
121impl Default for TargetEnv {
122    fn default() -> Self {
123        // This is the default target environment for (AFAICT) all spirv-tools
124        Self::Universal_1_5
125    }
126}
127
128impl std::str::FromStr for TargetEnv {
129    type Err = SpirvResult;
130
131    fn from_str(s: &str) -> Result<Self, Self::Err> {
132        Ok(match s {
133            "vulkan1.1spv1.4" => Self::Vulkan_1_1_Spirv_1_4,
134            "vulkan1.0" => Self::Vulkan_1_0,
135            "vulkan1.1" => Self::Vulkan_1_1,
136            "vulkan1.2" => Self::Vulkan_1_2,
137            "vulkan1.3" => Self::Vulkan_1_3,
138            "vulkan1.4" => Self::Vulkan_1_4,
139            "spv1.0" => Self::Universal_1_0,
140            "spv1.1" => Self::Universal_1_1,
141            "spv1.2" => Self::Universal_1_2,
142            "spv1.3" => Self::Universal_1_3,
143            "spv1.4" => Self::Universal_1_4,
144            "spv1.5" => Self::Universal_1_5,
145            "spv1.6" => Self::Universal_1_6,
146            "opencl1.2embedded" => Self::OpenCLEmbedded_1_2,
147            "opencl1.2" => Self::OpenCL_1_2,
148            "opencl2.0embedded" => Self::OpenCLEmbedded_2_0,
149            "opencl2.0" => Self::OpenCL_2_0,
150            "opencl2.1embedded" => Self::OpenCLEmbedded_2_1,
151            "opencl2.1" => Self::OpenCL_2_1,
152            "opencl2.2embedded" => Self::OpenCLEmbedded_2_2,
153            "opencl2.2" => Self::OpenCL_2_2,
154            "opengl4.0" => Self::OpenGL_4_0,
155            "opengl4.1" => Self::OpenGL_4_1,
156            "opengl4.2" => Self::OpenGL_4_2,
157            "opengl4.3" => Self::OpenGL_4_3,
158            "opengl4.5" => Self::OpenGL_4_5,
159            "webgpu0" => Self::WebGPU_0,
160            _ => return Err(SpirvResult::InvalidValue),
161        })
162    }
163}
164
165impl fmt::Display for TargetEnv {
166    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167        f.write_str(match self {
168            Self::Vulkan_1_1_Spirv_1_4 => "vulkan1.1spv1.4",
169            Self::Vulkan_1_0 => "vulkan1.0",
170            Self::Vulkan_1_1 => "vulkan1.1",
171            Self::Vulkan_1_2 => "vulkan1.2",
172            Self::Vulkan_1_3 => "vulkan1.3",
173            Self::Vulkan_1_4 => "vulkan1.4",
174            Self::Universal_1_0 => "spv1.0",
175            Self::Universal_1_1 => "spv1.1",
176            Self::Universal_1_2 => "spv1.2",
177            Self::Universal_1_3 => "spv1.3",
178            Self::Universal_1_4 => "spv1.4",
179            Self::Universal_1_5 => "spv1.5",
180            Self::Universal_1_6 => "spv1.6",
181            Self::OpenCLEmbedded_1_2 => "opencl1.2embedded",
182            Self::OpenCL_1_2 => "opencl1.2",
183            Self::OpenCLEmbedded_2_0 => "opencl2.0embedded",
184            Self::OpenCL_2_0 => "opencl2.0",
185            Self::OpenCLEmbedded_2_1 => "opencl2.1embedded",
186            Self::OpenCL_2_1 => "opencl2.1",
187            Self::OpenCLEmbedded_2_2 => "opencl2.2embedded",
188            Self::OpenCL_2_2 => "opencl2.2",
189            Self::OpenGL_4_0 => "opengl4.0",
190            Self::OpenGL_4_1 => "opengl4.1",
191            Self::OpenGL_4_2 => "opengl4.2",
192            Self::OpenGL_4_3 => "opengl4.3",
193            Self::OpenGL_4_5 => "opengl4.5",
194            Self::WebGPU_0 => "webgpu0",
195        })
196    }
197}
198
199#[derive(Copy, Clone, Debug, PartialEq)]
200#[repr(i32)] // SPV_FORCE_32_BIT_ENUM
201pub enum SpirvResult {
202    Success = 0,
203    Unsupported = 1,
204    EndOfStream = 2,
205    Warning = 3,
206    FailedMatch = 4,
207    /// Success, but signals early termination.
208    RequestedTermination = 5,
209    InternalError = -1,
210    OutOfMemory = -2,
211    InvalidPointer = -3,
212    InvalidBinary = -4,
213    InvalidText = -5,
214    InvalidTable = -6,
215    InvalidValue = -7,
216    InvalidDiagnostic = -8,
217    InvalidLookup = -9,
218    InvalidId = -10,
219    InvalidCfg = -11,
220    InvalidLayout = -12,
221    InvalidCapability = -13,
222    /// Indicates data rules validation failure.
223    InvalidData = -14,
224    MissingExtension = -15,
225    /// Indicates wrong SPIR-V version
226    WrongVersion = -16,
227}
228
229impl fmt::Display for SpirvResult {
230    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231        #[allow(clippy::enum_glob_use)]
232        use SpirvResult::*;
233
234        match self {
235            Success => f.write_str("success"),
236            Unsupported => f.write_str("unsupported"),
237            EndOfStream => f.write_str("end of stream"),
238            Warning => f.write_str("warning"),
239            FailedMatch => f.write_str("failed match"),
240            RequestedTermination => f.write_str("requested termination"),
241            InternalError => f.write_str("internal error"),
242            OutOfMemory => f.write_str("out of memory"),
243            InvalidPointer => f.write_str("invalid pointer"),
244            InvalidBinary => f.write_str("invalid binary"),
245            InvalidText => f.write_str("invalid text"),
246            InvalidTable => f.write_str("invalid table"),
247            InvalidValue => f.write_str("invalid value"),
248            InvalidDiagnostic => f.write_str("invalid diagnostic"),
249            InvalidLookup => f.write_str("invalid lookup"),
250            InvalidId => f.write_str("invalid id"),
251            InvalidCfg => f.write_str("invalid cfg"),
252            InvalidLayout => f.write_str("invalid layout"),
253            InvalidCapability => f.write_str("invalid capability"),
254            InvalidData => f.write_str("invalid data"),
255            MissingExtension => f.write_str("missing extension"),
256            WrongVersion => f.write_str("wrong SPIR-V version"),
257        }
258    }
259}
260
261impl std::error::Error for SpirvResult {}
262
263#[repr(C)]
264pub struct Binary {
265    pub code: *const u32,
266    pub size: usize,
267}
268
269#[repr(C)]
270pub struct ToolContext {
271    _unused: [u8; 0],
272}
273
274extern "C" {
275    /// Creates a context object for most of the SPIRV-Tools API.
276    /// Returns null if env is invalid.
277    ///
278    /// See specific API calls for how the target environment is interpeted
279    /// (particularly assembly and validation).
280    #[link_name = "spvContextCreate"]
281    pub fn context_create(env: TargetEnv) -> *mut ToolContext;
282    /// Destroys the given context object.
283    #[link_name = "spvContextDestroy"]
284    pub fn context_destroy(opt: *mut ToolContext);
285
286    /// Frees a binary stream from memory. This is a no-op if binary is a null
287    /// pointer.
288    #[link_name = "spvBinaryDestroy"]
289    pub fn binary_destroy(binary: *mut Binary);
290}