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 hoist;
81mod keywords;
82mod mesh_shader;
83mod ray;
84pub mod sampler;
85mod writer;
86
87pub use writer::Writer;
88
89pub type Slot = u8;
90pub type InlineSamplerIndex = u8;
91
92#[derive(Clone, Debug, PartialEq, Eq, Hash)]
93#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
94#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
95pub enum BindSamplerTarget {
96 Resource(Slot),
97 Inline(InlineSamplerIndex),
98}
99
100#[derive(Clone, Debug, PartialEq, Eq, Hash)]
106#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
107#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
108pub struct BindExternalTextureTarget {
109 pub planes: [Slot; 3],
110 pub params: Slot,
111}
112
113#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
114#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
115#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
116#[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(default))]
117pub struct BindTarget {
118 pub buffer: Option<Slot>,
119 pub texture: Option<Slot>,
120 pub sampler: Option<BindSamplerTarget>,
121 pub external_texture: Option<BindExternalTextureTarget>,
122 pub mutable: bool,
123}
124
125#[cfg(feature = "deserialize")]
126#[derive(serde::Deserialize)]
127struct BindingMapSerialization {
128 resource_binding: crate::ResourceBinding,
129 bind_target: BindTarget,
130}
131
132#[cfg(feature = "deserialize")]
133fn deserialize_binding_map<'de, D>(deserializer: D) -> Result<BindingMap, D::Error>
134where
135 D: serde::Deserializer<'de>,
136{
137 use serde::Deserialize;
138
139 let vec = Vec::<BindingMapSerialization>::deserialize(deserializer)?;
140 let mut map = BindingMap::default();
141 for item in vec {
142 map.insert(item.resource_binding, item.bind_target);
143 }
144 Ok(map)
145}
146
147pub type BindingMap = alloc::collections::BTreeMap<crate::ResourceBinding, BindTarget>;
149
150#[derive(Clone, Debug, Default, Hash, Eq, PartialEq)]
151#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
152#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
153#[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(default))]
154pub struct EntryPointResources {
155 #[cfg_attr(
156 feature = "deserialize",
157 serde(deserialize_with = "deserialize_binding_map")
158 )]
159 pub resources: BindingMap,
160
161 pub immediates_buffer: Option<Slot>,
162
163 pub sizes_buffer: Option<Slot>,
167}
168
169pub type EntryPointResourceMap = alloc::collections::BTreeMap<String, EntryPointResources>;
170
171enum ResolvedBinding {
172 BuiltIn(crate::BuiltIn),
173 Attribute(u32),
174 Color {
175 location: u32,
176 blend_src: Option<u32>,
177 },
178 User {
179 prefix: &'static str,
180 index: u32,
181 interpolation: Option<ResolvedInterpolation>,
182 },
183 Resource(BindTarget),
184 Payload,
185 ConservativeDepth(crate::ConservativeDepth),
188}
189
190#[derive(Copy, Clone)]
191enum ResolvedInterpolation {
192 CenterPerspective,
193 CenterNoPerspective,
194 CentroidPerspective,
195 CentroidNoPerspective,
196 SamplePerspective,
197 SampleNoPerspective,
198 Flat,
199 PerVertex,
200}
201
202#[derive(Debug, thiserror::Error)]
205pub enum Error {
206 #[error(transparent)]
207 Format(#[from] FmtError),
208 #[error("bind target {0:?} is empty")]
209 UnimplementedBindTarget(BindTarget),
210 #[error("composing of {0:?} is not implemented yet")]
211 UnsupportedCompose(Handle<crate::Type>),
212 #[error("operation {0:?} is not implemented yet")]
213 UnsupportedBinaryOp(crate::BinaryOperator),
214 #[error("standard function '{0}' is not implemented yet")]
215 UnsupportedCall(String),
216 #[error("feature '{0}' is not implemented yet")]
217 FeatureNotImplemented(String),
218 #[error("internal naga error: module should not have validated: {0}")]
219 GenericValidation(String),
220 #[error("BuiltIn {0:?} is not supported")]
221 UnsupportedBuiltIn(crate::BuiltIn),
222 #[error("capability {0:?} is not supported")]
223 CapabilityNotSupported(crate::valid::Capabilities),
224 #[error("attribute '{0}' is not supported for target MSL version")]
225 UnsupportedAttribute(String),
226 #[error("function '{0}' is not supported for target MSL version")]
227 UnsupportedFunction(String),
228 #[error("can not use writable storage buffers in fragment stage prior to MSL 1.2")]
229 UnsupportedWritableStorageBuffer,
230 #[error("can not use writable storage textures in {0:?} stage prior to MSL 1.2")]
231 UnsupportedWritableStorageTexture(ir::ShaderStage),
232 #[error("can not use read-write storage textures prior to MSL 1.2")]
233 UnsupportedRWStorageTexture,
234 #[error("array of '{0}' is not supported for target MSL version")]
235 UnsupportedArrayOf(String),
236 #[error("array of type '{0:?}' is not supported")]
237 UnsupportedArrayOfType(Handle<crate::Type>),
238 #[error("ray tracing is not supported prior to MSL 2.4")]
239 UnsupportedRayTracing,
240 #[error("cooperative matrix is not supported prior to MSL 2.3")]
241 UnsupportedCooperativeMatrix,
242 #[error("debugPrintf is not supported prior to MSL 3.2")]
243 UnsupportedDebugPrintf,
244 #[error("overrides should not be present at this stage")]
245 Override,
246 #[error("bitcasting to {0:?} is not supported")]
247 UnsupportedBitCast(crate::TypeInner),
248 #[error(transparent)]
249 ResolveArraySizeError(#[from] crate::proc::ResolveArraySizeError),
250 #[error("entry point with stage {0:?} and name '{1}' not found")]
251 EntryPointNotFound(ir::ShaderStage, String),
252 #[error("Cannot use mesh shader syntax prior to MSL 3.0")]
253 UnsupportedMeshShader,
254 #[error("Per vertex fragment inputs are not supported prior to MSL 4.0")]
255 PerVertexNotSupported,
256}
257
258#[derive(Clone, Debug, PartialEq, thiserror::Error)]
259#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
260#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
261pub enum EntryPointError {
262 #[error("global '{0}' doesn't have a binding")]
263 MissingBinding(String),
264 #[error("mapping of {0:?} is missing")]
265 MissingBindTarget(crate::ResourceBinding),
266 #[error("mapping for immediates is missing")]
267 MissingImmediateData,
268 #[error("mapping for sizes buffer is missing")]
269 MissingSizesBuffer,
270}
271
272#[derive(Clone, Copy, Debug)]
281enum LocationMode {
282 VertexInput,
284
285 VertexOutput,
287
288 FragmentInput,
290
291 FragmentOutput,
293
294 MeshOutput,
296
297 Uniform,
299}
300
301#[derive(Clone, Debug, Hash, PartialEq, Eq)]
302#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
303#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
304#[cfg_attr(feature = "deserialize", serde(default))]
305pub struct Options {
306 pub lang_version: (u8, u8),
308 pub per_entry_point_map: EntryPointResourceMap,
310 pub inline_samplers: Vec<sampler::InlineSampler>,
312 pub spirv_cross_compatibility: bool,
314 pub fake_missing_bindings: bool,
316 pub bounds_check_policies: index::BoundsCheckPolicies,
318 pub zero_initialize_workgroup_memory: bool,
320 pub force_loop_bounding: bool,
323 pub task_dispatch_limits: Option<TaskDispatchLimits>,
326 pub mesh_shader_primitive_indices_clamp: bool,
328 pub emit_int_div_checks: bool,
333 pub ray_query_initialization_tracking: bool,
335}
336
337impl Default for Options {
338 fn default() -> Self {
339 Options {
340 lang_version: (1, 0),
341 per_entry_point_map: EntryPointResourceMap::default(),
342 inline_samplers: Vec::new(),
343 spirv_cross_compatibility: false,
344 fake_missing_bindings: true,
345 bounds_check_policies: index::BoundsCheckPolicies::default(),
346 zero_initialize_workgroup_memory: true,
347 force_loop_bounding: true,
348 task_dispatch_limits: None,
349 mesh_shader_primitive_indices_clamp: true,
350 ray_query_initialization_tracking: true,
351 emit_int_div_checks: true,
352 }
353 }
354}
355
356#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
358#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
359#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
360pub enum VertexBufferStepMode {
361 Constant,
362 #[default]
363 ByVertex,
364 ByInstance,
365}
366
367#[derive(Debug, Clone, PartialEq, Eq, Hash)]
370#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
371#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
372pub struct AttributeMapping {
373 pub shader_location: u32,
375 pub offset: u32,
377 pub format: nt::VertexFormat,
383}
384
385#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
388#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
389#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
390pub struct VertexBufferMapping {
391 pub id: u32,
393 pub stride: u32,
395 pub step_mode: VertexBufferStepMode,
397 pub attributes: Vec<AttributeMapping>,
399}
400
401#[derive(Debug, Default, Clone)]
403#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
404#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
405#[cfg_attr(feature = "deserialize", serde(default))]
406pub struct PipelineOptions {
407 pub entry_point: Option<(ir::ShaderStage, String)>,
415
416 pub allow_and_force_point_size: bool,
423
424 pub vertex_pulling_transform: bool,
432
433 pub vertex_buffer_mappings: Vec<VertexBufferMapping>,
436
437 #[cfg_attr(
441 feature = "deserialize",
442 serde(deserialize_with = "deserialize_binding_array_length_map")
443 )]
444 pub binding_array_length_map: crate::FastHashMap<crate::ResourceBinding, u32>,
445}
446
447#[cfg(feature = "deserialize")]
448#[derive(serde::Deserialize)]
449struct BindingArrayLengthMapSerialization {
450 resource_binding: crate::ResourceBinding,
451 count: u32,
452}
453
454#[cfg(feature = "deserialize")]
455fn deserialize_binding_array_length_map<'de, D>(
456 deserializer: D,
457) -> Result<crate::FastHashMap<crate::ResourceBinding, u32>, D::Error>
458where
459 D: serde::Deserializer<'de>,
460{
461 use serde::Deserialize;
462
463 let vec = Vec::<BindingArrayLengthMapSerialization>::deserialize(deserializer)?;
464 let mut map = crate::FastHashMap::default();
465 for item in vec {
466 map.insert(item.resource_binding, item.count);
467 }
468 Ok(map)
469}
470
471impl Options {
472 fn resolve_local_binding(
473 &self,
474 binding: &crate::Binding,
475 mode: LocationMode,
476 ) -> Result<ResolvedBinding, Error> {
477 match *binding {
478 crate::Binding::BuiltIn(mut built_in) => {
479 match built_in {
480 crate::BuiltIn::Position { ref mut invariant } => {
481 if *invariant && self.lang_version < (2, 1) {
482 return Err(Error::UnsupportedAttribute("invariant".to_string()));
483 }
484
485 if !matches!(mode, LocationMode::VertexOutput) {
488 *invariant = false;
489 }
490 }
491 crate::BuiltIn::BaseInstance if self.lang_version < (1, 2) => {
492 return Err(Error::UnsupportedAttribute("base_instance".to_string()));
493 }
494 crate::BuiltIn::InstanceIndex if self.lang_version < (1, 2) => {
495 return Err(Error::UnsupportedAttribute("instance_id".to_string()));
496 }
497 crate::BuiltIn::PrimitiveIndex if self.lang_version < (2, 3) => {
500 return Err(Error::UnsupportedAttribute("primitive_id".to_string()));
501 }
502 crate::BuiltIn::ViewIndex if self.lang_version < (2, 2) => {
506 return Err(Error::UnsupportedAttribute("amplification_id".to_string()));
507 }
508 crate::BuiltIn::Barycentric { .. } if self.lang_version < (2, 3) => {
511 return Err(Error::UnsupportedAttribute("barycentric_coord".to_string()));
512 }
513 _ => {}
514 }
515
516 Ok(ResolvedBinding::BuiltIn(built_in))
517 }
518 crate::Binding::Location {
519 location,
520 interpolation,
521 sampling,
522 blend_src,
523 per_primitive,
524 } => match mode {
525 LocationMode::VertexInput => Ok(ResolvedBinding::Attribute(location)),
526 LocationMode::FragmentOutput => {
527 if blend_src.is_some() && self.lang_version < (1, 2) {
528 return Err(Error::UnsupportedAttribute("blend_src".to_string()));
529 }
530 Ok(ResolvedBinding::Color {
531 location,
532 blend_src,
533 })
534 }
535 LocationMode::VertexOutput
536 | LocationMode::FragmentInput
537 | LocationMode::MeshOutput => {
538 Ok(ResolvedBinding::User {
539 prefix: if self.spirv_cross_compatibility {
540 "locn"
541 } else {
542 "loc"
543 },
544 index: location,
545 interpolation: {
546 let interpolation = interpolation.unwrap();
550 let sampling = sampling.unwrap_or(crate::Sampling::Center);
551 Some(ResolvedInterpolation::from_binding(
552 interpolation,
553 sampling,
554 per_primitive,
555 ))
556 },
557 })
558 }
559 LocationMode::Uniform => Err(Error::GenericValidation(format!(
560 "Unexpected Binding::Location({location}) for the Uniform mode"
561 ))),
562 },
563 }
564 }
565
566 fn get_entry_point_resources(&self, ep: &crate::EntryPoint) -> Option<&EntryPointResources> {
567 self.per_entry_point_map.get(&ep.name)
568 }
569
570 fn get_resource_binding_target(
571 &self,
572 ep: &crate::EntryPoint,
573 res_binding: &crate::ResourceBinding,
574 ) -> Option<&BindTarget> {
575 self.get_entry_point_resources(ep)
576 .and_then(|res| res.resources.get(res_binding))
577 }
578
579 fn resolve_resource_binding(
580 &self,
581 ep: &crate::EntryPoint,
582 res_binding: &crate::ResourceBinding,
583 ) -> Result<ResolvedBinding, EntryPointError> {
584 let target = self.get_resource_binding_target(ep, res_binding);
585 match target {
586 Some(target) => Ok(ResolvedBinding::Resource(target.clone())),
587 None if self.fake_missing_bindings => Ok(ResolvedBinding::User {
588 prefix: "fake",
589 index: 0,
590 interpolation: None,
591 }),
592 None => Err(EntryPointError::MissingBindTarget(*res_binding)),
593 }
594 }
595
596 fn resolve_immediates(
597 &self,
598 ep: &crate::EntryPoint,
599 ) -> Result<ResolvedBinding, EntryPointError> {
600 let slot = self
601 .get_entry_point_resources(ep)
602 .and_then(|res| res.immediates_buffer);
603 match slot {
604 Some(slot) => Ok(ResolvedBinding::Resource(BindTarget {
605 buffer: Some(slot),
606 ..Default::default()
607 })),
608 None if self.fake_missing_bindings => Ok(ResolvedBinding::User {
609 prefix: "fake",
610 index: 0,
611 interpolation: None,
612 }),
613 None => Err(EntryPointError::MissingImmediateData),
614 }
615 }
616
617 fn resolve_sizes_buffer(
618 &self,
619 ep: &crate::EntryPoint,
620 ) -> Result<ResolvedBinding, EntryPointError> {
621 let slot = self
622 .get_entry_point_resources(ep)
623 .and_then(|res| res.sizes_buffer);
624 match slot {
625 Some(slot) => Ok(ResolvedBinding::Resource(BindTarget {
626 buffer: Some(slot),
627 ..Default::default()
628 })),
629 None if self.fake_missing_bindings => Ok(ResolvedBinding::User {
630 prefix: "fake",
631 index: 0,
632 interpolation: None,
633 }),
634 None => Err(EntryPointError::MissingSizesBuffer),
635 }
636 }
637}
638
639impl ResolvedBinding {
640 fn as_inline_sampler<'a>(&self, options: &'a Options) -> Option<&'a sampler::InlineSampler> {
641 match *self {
642 Self::Resource(BindTarget {
643 sampler: Some(BindSamplerTarget::Inline(index)),
644 ..
645 }) => Some(&options.inline_samplers[index as usize]),
646 _ => None,
647 }
648 }
649
650 fn try_fmt<W: Write>(&self, out: &mut W) -> Result<(), Error> {
651 write!(out, " [[")?;
652 match *self {
653 Self::BuiltIn(built_in) => {
654 use crate::BuiltIn as Bi;
655 let name = match built_in {
656 Bi::Position { invariant: false } => "position",
657 Bi::Position { invariant: true } => "position, invariant",
658 Bi::ViewIndex => "amplification_id",
659 Bi::BaseInstance => "base_instance",
661 Bi::BaseVertex => "base_vertex",
662 Bi::ClipDistances => "clip_distance",
663 Bi::InstanceIndex => "instance_id",
664 Bi::PointSize => "point_size",
665 Bi::VertexIndex => "vertex_id",
666 Bi::FragDepth => "depth(any)",
668 Bi::PointCoord => "point_coord",
669 Bi::FrontFacing => "front_facing",
670 Bi::PrimitiveIndex => "primitive_id",
671 Bi::Barycentric { perspective: true } => "barycentric_coord",
672 Bi::Barycentric { perspective: false } => {
673 "barycentric_coord, center_no_perspective"
674 }
675 Bi::SampleIndex => "sample_id",
676 Bi::SampleMask => "sample_mask",
677 Bi::GlobalInvocationId => "thread_position_in_grid",
679 Bi::LocalInvocationId => "thread_position_in_threadgroup",
680 Bi::LocalInvocationIndex => "thread_index_in_threadgroup",
681 Bi::WorkGroupId => "threadgroup_position_in_grid",
682 Bi::WorkGroupSize => "dispatch_threads_per_threadgroup",
683 Bi::NumWorkGroups => "threadgroups_per_grid",
684 Bi::NumSubgroups => "simdgroups_per_threadgroup",
686 Bi::SubgroupId => "simdgroup_index_in_threadgroup",
687 Bi::SubgroupSize => "threads_per_simdgroup",
688 Bi::SubgroupInvocationId => "thread_index_in_simdgroup",
689 Bi::CullDistance | Bi::DrawIndex => {
690 return Err(Error::UnsupportedBuiltIn(built_in))
691 }
692 Bi::CullPrimitive => "primitive_culled",
693 Bi::PointIndex | Bi::LineIndices | Bi::TriangleIndices => unimplemented!(),
695 Bi::MeshTaskSize
698 | Bi::VertexCount
699 | Bi::PrimitiveCount
700 | Bi::Vertices
701 | Bi::Primitives
702 | Bi::RayInvocationId
703 | Bi::NumRayInvocations
704 | Bi::InstanceCustomData
705 | Bi::GeometryIndex
706 | Bi::WorldRayOrigin
707 | Bi::WorldRayDirection
708 | Bi::ObjectRayOrigin
709 | Bi::ObjectRayDirection
710 | Bi::RayTmin
711 | Bi::RayTCurrentMax
712 | Bi::ObjectToWorld
713 | Bi::WorldToObject
714 | Bi::HitKind
715 | Bi::HitBarycentrics => unreachable!(),
716 };
717 write!(out, "{name}")?;
718 }
719 Self::Attribute(index) => write!(out, "attribute({index})")?,
720 Self::ConservativeDepth(conservative) => {
721 use crate::ConservativeDepth as Cd;
722 let qualifier = match conservative {
723 Cd::GreaterEqual => "greater",
724 Cd::LessEqual => "less",
725 Cd::Unchanged => "any",
726 };
727 write!(out, "depth({qualifier})")?
728 }
729 Self::Color {
730 location,
731 blend_src,
732 } => {
733 if let Some(blend_src) = blend_src {
734 write!(out, "color({location}) index({blend_src})")?
735 } else {
736 write!(out, "color({location})")?
737 }
738 }
739 Self::User {
740 prefix,
741 index,
742 interpolation,
743 } => {
744 write!(out, "user({prefix}{index})")?;
745 if let Some(interpolation) = interpolation {
746 write!(out, ", ")?;
747 interpolation.try_fmt(out)?;
748 }
749 }
750 Self::Resource(ref target) => {
751 if let Some(id) = target.buffer {
752 write!(out, "buffer({id})")?;
753 } else if let Some(id) = target.texture {
754 write!(out, "texture({id})")?;
755 } else if let Some(BindSamplerTarget::Resource(id)) = target.sampler {
756 write!(out, "sampler({id})")?;
757 } else {
758 return Err(Error::UnimplementedBindTarget(target.clone()));
759 }
760 }
761 Self::Payload => write!(out, "payload")?,
762 }
763 write!(out, "]]")?;
764 Ok(())
765 }
766}
767
768impl ResolvedInterpolation {
769 const fn from_binding(
770 interpolation: crate::Interpolation,
771 sampling: crate::Sampling,
772 per_primitive: bool,
773 ) -> Self {
774 use crate::Interpolation as I;
775 use crate::Sampling as S;
776
777 if per_primitive {
778 return Self::Flat;
779 }
780
781 match (interpolation, sampling) {
782 (I::Perspective, S::Center) => Self::CenterPerspective,
783 (I::Perspective, S::Centroid) => Self::CentroidPerspective,
784 (I::Perspective, S::Sample) => Self::SamplePerspective,
785 (I::Linear, S::Center) => Self::CenterNoPerspective,
786 (I::Linear, S::Centroid) => Self::CentroidNoPerspective,
787 (I::Linear, S::Sample) => Self::SampleNoPerspective,
788 (I::Flat, _) => Self::Flat,
789 (I::PerVertex, S::Center) => Self::PerVertex,
790 _ => unreachable!(),
791 }
792 }
793
794 fn try_fmt<W: Write>(self, out: &mut W) -> Result<(), Error> {
795 let identifier = match self {
796 Self::CenterPerspective => "center_perspective",
797 Self::CenterNoPerspective => "center_no_perspective",
798 Self::CentroidPerspective => "centroid_perspective",
799 Self::CentroidNoPerspective => "centroid_no_perspective",
800 Self::SamplePerspective => "sample_perspective",
801 Self::SampleNoPerspective => "sample_no_perspective",
802 Self::Flat => "flat",
803 Self::PerVertex => unreachable!(),
804 };
805 out.write_str(identifier)?;
806 Ok(())
807 }
808}
809
810struct EntryPointArgument {
811 ty_name: String,
812 name: String,
813 binding: String,
814 init: Option<Handle<crate::Expression>>,
815}
816
817type BackendResult = Result<(), Error>;
819
820const NAMESPACE: &str = "metal";
821
822const WRAPPED_ARRAY_FIELD: &str = "inner";
826
827#[derive(Debug)]
830pub struct TranslationInfo {
831 pub entry_point_names: Vec<Result<String, EntryPointError>>,
836}
837
838pub fn write_string(
839 module: &crate::Module,
840 info: &ModuleInfo,
841 options: &Options,
842 pipeline_options: &PipelineOptions,
843) -> Result<(String, TranslationInfo), Error> {
844 let mut w = Writer::new(String::new());
845 let info = w.write(module, info, options, pipeline_options)?;
846 Ok((w.finish(), info))
847}
848
849pub fn supported_capabilities() -> crate::valid::Capabilities {
850 use crate::valid::Capabilities as Caps;
851 Caps::IMMEDIATES
852 | Caps::PRIMITIVE_INDEX
854 | Caps::TEXTURE_AND_SAMPLER_BINDING_ARRAY
855 | Caps::STORAGE_TEXTURE_BINDING_ARRAY
857 | Caps::STORAGE_BUFFER_BINDING_ARRAY
858 | Caps::CLIP_DISTANCES
859 | Caps::STORAGE_TEXTURE_16BIT_NORM_FORMATS
861 | Caps::MULTIVIEW
862 | Caps::EARLY_DEPTH_TEST
863 | Caps::MULTISAMPLED_SHADING
864 | Caps::RAY_QUERY
865 | Caps::DUAL_SOURCE_BLENDING
866 | Caps::CUBE_ARRAY_TEXTURES
867 | Caps::SHADER_INT64
868 | Caps::SUBGROUP
869 | Caps::SUBGROUP_BARRIER
870 | Caps::SHADER_INT64_ATOMIC_MIN_MAX
872 | Caps::SHADER_FLOAT32_ATOMIC
874 | Caps::TEXTURE_ATOMIC
875 | Caps::TEXTURE_INT64_ATOMIC
876 | Caps::SHADER_FLOAT16
878 | Caps::SHADER_INT16
879 | Caps::TEXTURE_EXTERNAL
880 | Caps::SHADER_FLOAT16_IN_FLOAT32
881 | Caps::SHADER_BARYCENTRICS
882 | Caps::MESH_SHADER
883 | Caps::MESH_SHADER_POINT_TOPOLOGY
884 | Caps::TEXTURE_AND_SAMPLER_BINDING_ARRAY_NON_UNIFORM_INDEXING
885 | Caps::STORAGE_TEXTURE_BINDING_ARRAY_NON_UNIFORM_INDEXING
887 | Caps::STORAGE_BUFFER_BINDING_ARRAY_NON_UNIFORM_INDEXING
888 | Caps::COOPERATIVE_MATRIX
889 | Caps::PER_VERTEX
890 | Caps::MEMORY_DECORATION_COHERENT
894 | Caps::LINEAR_INTERPOLATION
895 | Caps::DEBUG_PRINTF
896}
897
898#[test]
899fn test_error_size() {
900 assert_eq!(size_of::<Error>(), 40);
901}