1use alloc::{
72 format,
73 string::{String, ToString},
74 vec::Vec,
75};
76use core::fmt::{Error as FmtError, Write};
77
78use crate::{arena::Handle, back::TaskDispatchLimits, ir, proc::index, valid::ModuleInfo};
79
80mod keywords;
81mod mesh_shader;
82pub mod sampler;
83mod writer;
84
85pub use writer::Writer;
86
87pub type Slot = u8;
88pub type InlineSamplerIndex = u8;
89
90#[derive(Clone, Debug, PartialEq, Eq, Hash)]
91#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
92#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
93pub enum BindSamplerTarget {
94 Resource(Slot),
95 Inline(InlineSamplerIndex),
96}
97
98#[derive(Clone, Debug, PartialEq, Eq, Hash)]
104#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
105#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
106pub struct BindExternalTextureTarget {
107 pub planes: [Slot; 3],
108 pub params: Slot,
109}
110
111#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
112#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
113#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
114#[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(default))]
115pub struct BindTarget {
116 pub buffer: Option<Slot>,
117 pub texture: Option<Slot>,
118 pub sampler: Option<BindSamplerTarget>,
119 pub external_texture: Option<BindExternalTextureTarget>,
120 pub mutable: bool,
121}
122
123#[cfg(feature = "deserialize")]
124#[derive(serde::Deserialize)]
125struct BindingMapSerialization {
126 resource_binding: crate::ResourceBinding,
127 bind_target: BindTarget,
128}
129
130#[cfg(feature = "deserialize")]
131fn deserialize_binding_map<'de, D>(deserializer: D) -> Result<BindingMap, D::Error>
132where
133 D: serde::Deserializer<'de>,
134{
135 use serde::Deserialize;
136
137 let vec = Vec::<BindingMapSerialization>::deserialize(deserializer)?;
138 let mut map = BindingMap::default();
139 for item in vec {
140 map.insert(item.resource_binding, item.bind_target);
141 }
142 Ok(map)
143}
144
145pub type BindingMap = alloc::collections::BTreeMap<crate::ResourceBinding, BindTarget>;
147
148#[derive(Clone, Debug, Default, Hash, Eq, PartialEq)]
149#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
150#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
151#[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(default))]
152pub struct EntryPointResources {
153 #[cfg_attr(
154 feature = "deserialize",
155 serde(deserialize_with = "deserialize_binding_map")
156 )]
157 pub resources: BindingMap,
158
159 pub immediates_buffer: Option<Slot>,
160
161 pub sizes_buffer: Option<Slot>,
165}
166
167pub type EntryPointResourceMap = alloc::collections::BTreeMap<String, EntryPointResources>;
168
169enum ResolvedBinding {
170 BuiltIn(crate::BuiltIn),
171 Attribute(u32),
172 Color {
173 location: u32,
174 blend_src: Option<u32>,
175 },
176 User {
177 prefix: &'static str,
178 index: u32,
179 interpolation: Option<ResolvedInterpolation>,
180 },
181 Resource(BindTarget),
182 Payload,
183}
184
185#[derive(Copy, Clone)]
186enum ResolvedInterpolation {
187 CenterPerspective,
188 CenterNoPerspective,
189 CentroidPerspective,
190 CentroidNoPerspective,
191 SamplePerspective,
192 SampleNoPerspective,
193 Flat,
194 PerVertex,
195}
196
197#[derive(Debug, thiserror::Error)]
200pub enum Error {
201 #[error(transparent)]
202 Format(#[from] FmtError),
203 #[error("bind target {0:?} is empty")]
204 UnimplementedBindTarget(BindTarget),
205 #[error("composing of {0:?} is not implemented yet")]
206 UnsupportedCompose(Handle<crate::Type>),
207 #[error("operation {0:?} is not implemented yet")]
208 UnsupportedBinaryOp(crate::BinaryOperator),
209 #[error("standard function '{0}' is not implemented yet")]
210 UnsupportedCall(String),
211 #[error("feature '{0}' is not implemented yet")]
212 FeatureNotImplemented(String),
213 #[error("internal naga error: module should not have validated: {0}")]
214 GenericValidation(String),
215 #[error("BuiltIn {0:?} is not supported")]
216 UnsupportedBuiltIn(crate::BuiltIn),
217 #[error("capability {0:?} is not supported")]
218 CapabilityNotSupported(crate::valid::Capabilities),
219 #[error("attribute '{0}' is not supported for target MSL version")]
220 UnsupportedAttribute(String),
221 #[error("function '{0}' is not supported for target MSL version")]
222 UnsupportedFunction(String),
223 #[error("can not use writable storage buffers in fragment stage prior to MSL 1.2")]
224 UnsupportedWritableStorageBuffer,
225 #[error("can not use writable storage textures in {0:?} stage prior to MSL 1.2")]
226 UnsupportedWritableStorageTexture(ir::ShaderStage),
227 #[error("can not use read-write storage textures prior to MSL 1.2")]
228 UnsupportedRWStorageTexture,
229 #[error("array of '{0}' is not supported for target MSL version")]
230 UnsupportedArrayOf(String),
231 #[error("array of type '{0:?}' is not supported")]
232 UnsupportedArrayOfType(Handle<crate::Type>),
233 #[error("ray tracing is not supported prior to MSL 2.4")]
234 UnsupportedRayTracing,
235 #[error("cooperative matrix is not supported prior to MSL 2.3")]
236 UnsupportedCooperativeMatrix,
237 #[error("overrides should not be present at this stage")]
238 Override,
239 #[error("bitcasting to {0:?} is not supported")]
240 UnsupportedBitCast(crate::TypeInner),
241 #[error(transparent)]
242 ResolveArraySizeError(#[from] crate::proc::ResolveArraySizeError),
243 #[error("entry point with stage {0:?} and name '{1}' not found")]
244 EntryPointNotFound(ir::ShaderStage, String),
245 #[error("Cannot use mesh shader syntax prior to MSL 3.0")]
246 UnsupportedMeshShader,
247 #[error("Per vertex fragment inputs are not supported prior to MSL 4.0")]
248 PerVertexNotSupported,
249}
250
251#[derive(Clone, Debug, PartialEq, thiserror::Error)]
252#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
253#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
254pub enum EntryPointError {
255 #[error("global '{0}' doesn't have a binding")]
256 MissingBinding(String),
257 #[error("mapping of {0:?} is missing")]
258 MissingBindTarget(crate::ResourceBinding),
259 #[error("mapping for immediates is missing")]
260 MissingImmediateData,
261 #[error("mapping for sizes buffer is missing")]
262 MissingSizesBuffer,
263}
264
265#[derive(Clone, Copy, Debug)]
274enum LocationMode {
275 VertexInput,
277
278 VertexOutput,
280
281 FragmentInput,
283
284 FragmentOutput,
286
287 MeshOutput,
289
290 Uniform,
292}
293
294#[derive(Clone, Debug, Hash, PartialEq, Eq)]
295#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
296#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
297#[cfg_attr(feature = "deserialize", serde(default))]
298pub struct Options {
299 pub lang_version: (u8, u8),
301 pub per_entry_point_map: EntryPointResourceMap,
303 pub inline_samplers: Vec<sampler::InlineSampler>,
305 pub spirv_cross_compatibility: bool,
307 pub fake_missing_bindings: bool,
309 pub bounds_check_policies: index::BoundsCheckPolicies,
311 pub zero_initialize_workgroup_memory: bool,
313 pub force_loop_bounding: bool,
316 pub task_dispatch_limits: Option<TaskDispatchLimits>,
319 pub mesh_shader_primitive_indices_clamp: bool,
321}
322
323impl Default for Options {
324 fn default() -> Self {
325 Options {
326 lang_version: (1, 0),
327 per_entry_point_map: EntryPointResourceMap::default(),
328 inline_samplers: Vec::new(),
329 spirv_cross_compatibility: false,
330 fake_missing_bindings: true,
331 bounds_check_policies: index::BoundsCheckPolicies::default(),
332 zero_initialize_workgroup_memory: true,
333 force_loop_bounding: true,
334 task_dispatch_limits: None,
335 mesh_shader_primitive_indices_clamp: true,
336 }
337 }
338}
339
340#[repr(u32)]
343#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
344#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
345#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
346pub enum VertexFormat {
347 Uint8 = 0,
349 Uint8x2 = 1,
351 Uint8x4 = 2,
353 Sint8 = 3,
355 Sint8x2 = 4,
357 Sint8x4 = 5,
359 Unorm8 = 6,
361 Unorm8x2 = 7,
363 Unorm8x4 = 8,
365 Snorm8 = 9,
367 Snorm8x2 = 10,
369 Snorm8x4 = 11,
371 Uint16 = 12,
373 Uint16x2 = 13,
375 Uint16x4 = 14,
377 Sint16 = 15,
379 Sint16x2 = 16,
381 Sint16x4 = 17,
383 Unorm16 = 18,
385 Unorm16x2 = 19,
387 Unorm16x4 = 20,
389 Snorm16 = 21,
391 Snorm16x2 = 22,
393 Snorm16x4 = 23,
395 Float16 = 24,
397 Float16x2 = 25,
399 Float16x4 = 26,
401 Float32 = 27,
403 Float32x2 = 28,
405 Float32x3 = 29,
407 Float32x4 = 30,
409 Uint32 = 31,
411 Uint32x2 = 32,
413 Uint32x3 = 33,
415 Uint32x4 = 34,
417 Sint32 = 35,
419 Sint32x2 = 36,
421 Sint32x3 = 37,
423 Sint32x4 = 38,
425 #[cfg_attr(
427 any(feature = "serialize", feature = "deserialize"),
428 serde(rename = "unorm10-10-10-2")
429 )]
430 Unorm10_10_10_2 = 43,
431 #[cfg_attr(
433 any(feature = "serialize", feature = "deserialize"),
434 serde(rename = "unorm8x4-bgra")
435 )]
436 Unorm8x4Bgra = 44,
437}
438
439#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
441#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
442#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
443pub enum VertexBufferStepMode {
444 Constant,
445 #[default]
446 ByVertex,
447 ByInstance,
448}
449
450#[derive(Debug, Clone, PartialEq, Eq, Hash)]
453#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
454#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
455pub struct AttributeMapping {
456 pub shader_location: u32,
458 pub offset: u32,
460 pub format: VertexFormat,
466}
467
468#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
471#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
472#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
473pub struct VertexBufferMapping {
474 pub id: u32,
476 pub stride: u32,
478 pub step_mode: VertexBufferStepMode,
480 pub attributes: Vec<AttributeMapping>,
482}
483
484#[derive(Debug, Default, Clone)]
486#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
487#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
488#[cfg_attr(feature = "deserialize", serde(default))]
489pub struct PipelineOptions {
490 pub entry_point: Option<(ir::ShaderStage, String)>,
498
499 pub allow_and_force_point_size: bool,
506
507 pub vertex_pulling_transform: bool,
515
516 pub vertex_buffer_mappings: Vec<VertexBufferMapping>,
519}
520
521impl Options {
522 fn resolve_local_binding(
523 &self,
524 binding: &crate::Binding,
525 mode: LocationMode,
526 ) -> Result<ResolvedBinding, Error> {
527 match *binding {
528 crate::Binding::BuiltIn(mut built_in) => {
529 match built_in {
530 crate::BuiltIn::Position { ref mut invariant } => {
531 if *invariant && self.lang_version < (2, 1) {
532 return Err(Error::UnsupportedAttribute("invariant".to_string()));
533 }
534
535 if !matches!(mode, LocationMode::VertexOutput) {
538 *invariant = false;
539 }
540 }
541 crate::BuiltIn::BaseInstance if self.lang_version < (1, 2) => {
542 return Err(Error::UnsupportedAttribute("base_instance".to_string()));
543 }
544 crate::BuiltIn::InstanceIndex if self.lang_version < (1, 2) => {
545 return Err(Error::UnsupportedAttribute("instance_id".to_string()));
546 }
547 crate::BuiltIn::PrimitiveIndex if self.lang_version < (2, 3) => {
550 return Err(Error::UnsupportedAttribute("primitive_id".to_string()));
551 }
552 crate::BuiltIn::ViewIndex if self.lang_version < (2, 2) => {
556 return Err(Error::UnsupportedAttribute("amplification_id".to_string()));
557 }
558 crate::BuiltIn::Barycentric { .. } if self.lang_version < (2, 3) => {
561 return Err(Error::UnsupportedAttribute("barycentric_coord".to_string()));
562 }
563 _ => {}
564 }
565
566 Ok(ResolvedBinding::BuiltIn(built_in))
567 }
568 crate::Binding::Location {
569 location,
570 interpolation,
571 sampling,
572 blend_src,
573 per_primitive,
574 } => match mode {
575 LocationMode::VertexInput => Ok(ResolvedBinding::Attribute(location)),
576 LocationMode::FragmentOutput => {
577 if blend_src.is_some() && self.lang_version < (1, 2) {
578 return Err(Error::UnsupportedAttribute("blend_src".to_string()));
579 }
580 Ok(ResolvedBinding::Color {
581 location,
582 blend_src,
583 })
584 }
585 LocationMode::VertexOutput
586 | LocationMode::FragmentInput
587 | LocationMode::MeshOutput => {
588 Ok(ResolvedBinding::User {
589 prefix: if self.spirv_cross_compatibility {
590 "locn"
591 } else {
592 "loc"
593 },
594 index: location,
595 interpolation: {
596 let interpolation = interpolation.unwrap();
600 let sampling = sampling.unwrap_or(crate::Sampling::Center);
601 Some(ResolvedInterpolation::from_binding(
602 interpolation,
603 sampling,
604 per_primitive,
605 ))
606 },
607 })
608 }
609 LocationMode::Uniform => Err(Error::GenericValidation(format!(
610 "Unexpected Binding::Location({location}) for the Uniform mode"
611 ))),
612 },
613 }
614 }
615
616 fn get_entry_point_resources(&self, ep: &crate::EntryPoint) -> Option<&EntryPointResources> {
617 self.per_entry_point_map.get(&ep.name)
618 }
619
620 fn get_resource_binding_target(
621 &self,
622 ep: &crate::EntryPoint,
623 res_binding: &crate::ResourceBinding,
624 ) -> Option<&BindTarget> {
625 self.get_entry_point_resources(ep)
626 .and_then(|res| res.resources.get(res_binding))
627 }
628
629 fn resolve_resource_binding(
630 &self,
631 ep: &crate::EntryPoint,
632 res_binding: &crate::ResourceBinding,
633 ) -> Result<ResolvedBinding, EntryPointError> {
634 let target = self.get_resource_binding_target(ep, res_binding);
635 match target {
636 Some(target) => Ok(ResolvedBinding::Resource(target.clone())),
637 None if self.fake_missing_bindings => Ok(ResolvedBinding::User {
638 prefix: "fake",
639 index: 0,
640 interpolation: None,
641 }),
642 None => Err(EntryPointError::MissingBindTarget(*res_binding)),
643 }
644 }
645
646 fn resolve_immediates(
647 &self,
648 ep: &crate::EntryPoint,
649 ) -> Result<ResolvedBinding, EntryPointError> {
650 let slot = self
651 .get_entry_point_resources(ep)
652 .and_then(|res| res.immediates_buffer);
653 match slot {
654 Some(slot) => Ok(ResolvedBinding::Resource(BindTarget {
655 buffer: Some(slot),
656 ..Default::default()
657 })),
658 None if self.fake_missing_bindings => Ok(ResolvedBinding::User {
659 prefix: "fake",
660 index: 0,
661 interpolation: None,
662 }),
663 None => Err(EntryPointError::MissingImmediateData),
664 }
665 }
666
667 fn resolve_sizes_buffer(
668 &self,
669 ep: &crate::EntryPoint,
670 ) -> Result<ResolvedBinding, EntryPointError> {
671 let slot = self
672 .get_entry_point_resources(ep)
673 .and_then(|res| res.sizes_buffer);
674 match slot {
675 Some(slot) => Ok(ResolvedBinding::Resource(BindTarget {
676 buffer: Some(slot),
677 ..Default::default()
678 })),
679 None if self.fake_missing_bindings => Ok(ResolvedBinding::User {
680 prefix: "fake",
681 index: 0,
682 interpolation: None,
683 }),
684 None => Err(EntryPointError::MissingSizesBuffer),
685 }
686 }
687}
688
689impl ResolvedBinding {
690 fn as_inline_sampler<'a>(&self, options: &'a Options) -> Option<&'a sampler::InlineSampler> {
691 match *self {
692 Self::Resource(BindTarget {
693 sampler: Some(BindSamplerTarget::Inline(index)),
694 ..
695 }) => Some(&options.inline_samplers[index as usize]),
696 _ => None,
697 }
698 }
699
700 fn try_fmt<W: Write>(&self, out: &mut W) -> Result<(), Error> {
701 write!(out, " [[")?;
702 match *self {
703 Self::BuiltIn(built_in) => {
704 use crate::BuiltIn as Bi;
705 let name = match built_in {
706 Bi::Position { invariant: false } => "position",
707 Bi::Position { invariant: true } => "position, invariant",
708 Bi::ViewIndex => "amplification_id",
709 Bi::BaseInstance => "base_instance",
711 Bi::BaseVertex => "base_vertex",
712 Bi::ClipDistances => "clip_distance",
713 Bi::InstanceIndex => "instance_id",
714 Bi::PointSize => "point_size",
715 Bi::VertexIndex => "vertex_id",
716 Bi::FragDepth => "depth(any)",
718 Bi::PointCoord => "point_coord",
719 Bi::FrontFacing => "front_facing",
720 Bi::PrimitiveIndex => "primitive_id",
721 Bi::Barycentric { perspective: true } => "barycentric_coord",
722 Bi::Barycentric { perspective: false } => {
723 "barycentric_coord, center_no_perspective"
724 }
725 Bi::SampleIndex => "sample_id",
726 Bi::SampleMask => "sample_mask",
727 Bi::GlobalInvocationId => "thread_position_in_grid",
729 Bi::LocalInvocationId => "thread_position_in_threadgroup",
730 Bi::LocalInvocationIndex => "thread_index_in_threadgroup",
731 Bi::WorkGroupId => "threadgroup_position_in_grid",
732 Bi::WorkGroupSize => "dispatch_threads_per_threadgroup",
733 Bi::NumWorkGroups => "threadgroups_per_grid",
734 Bi::NumSubgroups => "simdgroups_per_threadgroup",
736 Bi::SubgroupId => "simdgroup_index_in_threadgroup",
737 Bi::SubgroupSize => "threads_per_simdgroup",
738 Bi::SubgroupInvocationId => "thread_index_in_simdgroup",
739 Bi::CullDistance | Bi::DrawIndex => {
740 return Err(Error::UnsupportedBuiltIn(built_in))
741 }
742 Bi::CullPrimitive => "primitive_culled",
743 Bi::PointIndex | Bi::LineIndices | Bi::TriangleIndices => unimplemented!(),
745 Bi::MeshTaskSize
748 | Bi::VertexCount
749 | Bi::PrimitiveCount
750 | Bi::Vertices
751 | Bi::Primitives
752 | Bi::RayInvocationId
753 | Bi::NumRayInvocations
754 | Bi::InstanceCustomData
755 | Bi::GeometryIndex
756 | Bi::WorldRayOrigin
757 | Bi::WorldRayDirection
758 | Bi::ObjectRayOrigin
759 | Bi::ObjectRayDirection
760 | Bi::RayTmin
761 | Bi::RayTCurrentMax
762 | Bi::ObjectToWorld
763 | Bi::WorldToObject
764 | Bi::HitKind => unreachable!(),
765 };
766 write!(out, "{name}")?;
767 }
768 Self::Attribute(index) => write!(out, "attribute({index})")?,
769 Self::Color {
770 location,
771 blend_src,
772 } => {
773 if let Some(blend_src) = blend_src {
774 write!(out, "color({location}) index({blend_src})")?
775 } else {
776 write!(out, "color({location})")?
777 }
778 }
779 Self::User {
780 prefix,
781 index,
782 interpolation,
783 } => {
784 write!(out, "user({prefix}{index})")?;
785 if let Some(interpolation) = interpolation {
786 write!(out, ", ")?;
787 interpolation.try_fmt(out)?;
788 }
789 }
790 Self::Resource(ref target) => {
791 if let Some(id) = target.buffer {
792 write!(out, "buffer({id})")?;
793 } else if let Some(id) = target.texture {
794 write!(out, "texture({id})")?;
795 } else if let Some(BindSamplerTarget::Resource(id)) = target.sampler {
796 write!(out, "sampler({id})")?;
797 } else {
798 return Err(Error::UnimplementedBindTarget(target.clone()));
799 }
800 }
801 Self::Payload => write!(out, "payload")?,
802 }
803 write!(out, "]]")?;
804 Ok(())
805 }
806}
807
808impl ResolvedInterpolation {
809 const fn from_binding(
810 interpolation: crate::Interpolation,
811 sampling: crate::Sampling,
812 per_primitive: bool,
813 ) -> Self {
814 use crate::Interpolation as I;
815 use crate::Sampling as S;
816
817 if per_primitive {
818 return Self::Flat;
819 }
820
821 match (interpolation, sampling) {
822 (I::Perspective, S::Center) => Self::CenterPerspective,
823 (I::Perspective, S::Centroid) => Self::CentroidPerspective,
824 (I::Perspective, S::Sample) => Self::SamplePerspective,
825 (I::Linear, S::Center) => Self::CenterNoPerspective,
826 (I::Linear, S::Centroid) => Self::CentroidNoPerspective,
827 (I::Linear, S::Sample) => Self::SampleNoPerspective,
828 (I::Flat, _) => Self::Flat,
829 (I::PerVertex, S::Center) => Self::PerVertex,
830 _ => unreachable!(),
831 }
832 }
833
834 fn try_fmt<W: Write>(self, out: &mut W) -> Result<(), Error> {
835 let identifier = match self {
836 Self::CenterPerspective => "center_perspective",
837 Self::CenterNoPerspective => "center_no_perspective",
838 Self::CentroidPerspective => "centroid_perspective",
839 Self::CentroidNoPerspective => "centroid_no_perspective",
840 Self::SamplePerspective => "sample_perspective",
841 Self::SampleNoPerspective => "sample_no_perspective",
842 Self::Flat => "flat",
843 Self::PerVertex => unreachable!(),
844 };
845 out.write_str(identifier)?;
846 Ok(())
847 }
848}
849
850struct EntryPointArgument {
851 ty_name: String,
852 name: String,
853 binding: String,
854 init: Option<Handle<crate::Expression>>,
855}
856
857type BackendResult = Result<(), Error>;
859
860const NAMESPACE: &str = "metal";
861
862const WRAPPED_ARRAY_FIELD: &str = "inner";
866
867pub struct TranslationInfo {
870 pub entry_point_names: Vec<Result<String, EntryPointError>>,
875}
876
877pub fn write_string(
878 module: &crate::Module,
879 info: &ModuleInfo,
880 options: &Options,
881 pipeline_options: &PipelineOptions,
882) -> Result<(String, TranslationInfo), Error> {
883 let mut w = Writer::new(String::new());
884 let info = w.write(module, info, options, pipeline_options)?;
885 Ok((w.finish(), info))
886}
887
888pub fn supported_capabilities() -> crate::valid::Capabilities {
889 use crate::valid::Capabilities as Caps;
890 Caps::IMMEDIATES
891 | Caps::PRIMITIVE_INDEX
893 | Caps::TEXTURE_AND_SAMPLER_BINDING_ARRAY
894 | Caps::STORAGE_TEXTURE_BINDING_ARRAY
896 | Caps::STORAGE_BUFFER_BINDING_ARRAY
897 | Caps::CLIP_DISTANCES
898 | Caps::STORAGE_TEXTURE_16BIT_NORM_FORMATS
900 | Caps::MULTIVIEW
901 | Caps::MULTISAMPLED_SHADING
903 | Caps::RAY_QUERY
904 | Caps::DUAL_SOURCE_BLENDING
905 | Caps::CUBE_ARRAY_TEXTURES
906 | Caps::SHADER_INT64
907 | Caps::SUBGROUP
908 | Caps::SUBGROUP_BARRIER
909 | Caps::SHADER_INT64_ATOMIC_MIN_MAX
911 | Caps::SHADER_FLOAT32_ATOMIC
913 | Caps::TEXTURE_ATOMIC
914 | Caps::TEXTURE_INT64_ATOMIC
915 | Caps::SHADER_FLOAT16
917 | Caps::TEXTURE_EXTERNAL
918 | Caps::SHADER_FLOAT16_IN_FLOAT32
919 | Caps::SHADER_BARYCENTRICS
920 | Caps::MESH_SHADER
921 | Caps::MESH_SHADER_POINT_TOPOLOGY
922 | Caps::TEXTURE_AND_SAMPLER_BINDING_ARRAY_NON_UNIFORM_INDEXING
923 | Caps::STORAGE_TEXTURE_BINDING_ARRAY_NON_UNIFORM_INDEXING
925 | Caps::STORAGE_BUFFER_BINDING_ARRAY_NON_UNIFORM_INDEXING
926 | Caps::COOPERATIVE_MATRIX
927 | Caps::PER_VERTEX
928 | Caps::MEMORY_DECORATION_COHERENT
932}
933
934#[test]
935fn test_error_size() {
936 assert_eq!(size_of::<Error>(), 40);
937}