1use {
97 super::{DescriptorSetLayout, DriverError, VertexInputState, device::Device},
98 ash::vk,
99 derive_builder::{Builder, UninitializedFieldError},
100 log::{debug, error, trace, warn},
101 ordered_float::OrderedFloat,
102 spirq::{
103 ReflectConfig,
104 entry_point::EntryPoint,
105 parse::SpirvBinary,
106 spirv::ExecutionModel,
107 ty::{DescriptorType, ScalarType, Type, VectorType},
108 var::Variable,
109 },
110 std::{
111 collections::{BTreeMap, HashMap},
112 fmt::{Debug, Formatter},
113 iter::repeat_n,
114 ops::Deref,
115 panic::{AssertUnwindSafe, catch_unwind},
116 thread::panicking,
117 },
118};
119
120pub(crate) type DescriptorBindingMap = HashMap<Descriptor, (DescriptorInfo, vk::ShaderStageFlags)>;
121
122#[profiling::function]
123fn guess_immutable_sampler(binding_name: &str) -> SamplerInfo {
124 const INVALID_ERR: &str = "Invalid sampler specification";
125
126 let (texel_filter, mipmap_mode, address_modes) = if binding_name.contains("_sampler_") {
127 let spec = &binding_name[binding_name.len() - 3..];
128 let texel_filter = match &spec[0..1] {
129 "n" => vk::Filter::NEAREST,
130 "l" => vk::Filter::LINEAR,
131 _ => panic!("{INVALID_ERR}: {}", &spec[0..1]),
132 };
133
134 let mipmap_mode = match &spec[1..2] {
135 "n" => vk::SamplerMipmapMode::NEAREST,
136 "l" => vk::SamplerMipmapMode::LINEAR,
137 _ => panic!("{INVALID_ERR}: {}", &spec[1..2]),
138 };
139
140 let address_modes = match &spec[2..3] {
141 "b" => vk::SamplerAddressMode::CLAMP_TO_BORDER,
142 "e" => vk::SamplerAddressMode::CLAMP_TO_EDGE,
143 "m" => vk::SamplerAddressMode::MIRRORED_REPEAT,
144 "r" => vk::SamplerAddressMode::REPEAT,
145 _ => panic!("{INVALID_ERR}: {}", &spec[2..3]),
146 };
147
148 (texel_filter, mipmap_mode, address_modes)
149 } else {
150 debug!("image binding {binding_name} using default sampler");
151
152 (
153 vk::Filter::LINEAR,
154 vk::SamplerMipmapMode::LINEAR,
155 vk::SamplerAddressMode::REPEAT,
156 )
157 };
158 let anisotropy_enable = texel_filter == vk::Filter::LINEAR;
159 let mut info = SamplerInfoBuilder::default()
160 .mag_filter(texel_filter)
161 .min_filter(texel_filter)
162 .mipmap_mode(mipmap_mode)
163 .address_mode_u(address_modes)
164 .address_mode_v(address_modes)
165 .address_mode_w(address_modes)
166 .max_lod(vk::LOD_CLAMP_NONE)
167 .anisotropy_enable(anisotropy_enable);
168
169 if anisotropy_enable {
170 info = info.max_anisotropy(16.0);
171 }
172
173 info.build()
174}
175
176#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
181pub struct Descriptor {
182 pub set: u32,
184
185 pub binding: u32,
187}
188
189impl From<u32> for Descriptor {
190 fn from(binding: u32) -> Self {
191 Self { set: 0, binding }
192 }
193}
194
195impl From<(u32, u32)> for Descriptor {
196 fn from((set, binding): (u32, u32)) -> Self {
197 Self { set, binding }
198 }
199}
200
201#[derive(Clone, Copy, Debug)]
202pub(crate) enum DescriptorInfo {
203 AccelerationStructure(u32),
204 CombinedImageSampler(u32, SamplerInfo, bool), InputAttachment(u32, u32), SampledImage(u32),
207 Sampler(u32, SamplerInfo, bool), StorageBuffer(u32),
209 StorageImage(u32),
210 StorageTexelBuffer(u32),
211 UniformBuffer(u32),
212 UniformTexelBuffer(u32),
213}
214
215impl DescriptorInfo {
216 pub fn binding_count(self) -> u32 {
217 match self {
218 Self::AccelerationStructure(binding_count) => binding_count,
219 Self::CombinedImageSampler(binding_count, ..) => binding_count,
220 Self::InputAttachment(binding_count, _) => binding_count,
221 Self::SampledImage(binding_count) => binding_count,
222 Self::Sampler(binding_count, ..) => binding_count,
223 Self::StorageBuffer(binding_count) => binding_count,
224 Self::StorageImage(binding_count) => binding_count,
225 Self::StorageTexelBuffer(binding_count) => binding_count,
226 Self::UniformBuffer(binding_count) => binding_count,
227 Self::UniformTexelBuffer(binding_count) => binding_count,
228 }
229 }
230
231 pub fn descriptor_type(self) -> vk::DescriptorType {
232 match self {
233 Self::AccelerationStructure(_) => vk::DescriptorType::ACCELERATION_STRUCTURE_KHR,
234 Self::CombinedImageSampler(..) => vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
235 Self::InputAttachment(..) => vk::DescriptorType::INPUT_ATTACHMENT,
236 Self::SampledImage(_) => vk::DescriptorType::SAMPLED_IMAGE,
237 Self::Sampler(..) => vk::DescriptorType::SAMPLER,
238 Self::StorageBuffer(_) => vk::DescriptorType::STORAGE_BUFFER,
239 Self::StorageImage(_) => vk::DescriptorType::STORAGE_IMAGE,
240 Self::StorageTexelBuffer(_) => vk::DescriptorType::STORAGE_TEXEL_BUFFER,
241 Self::UniformBuffer(_) => vk::DescriptorType::UNIFORM_BUFFER,
242 Self::UniformTexelBuffer(_) => vk::DescriptorType::UNIFORM_TEXEL_BUFFER,
243 }
244 }
245
246 fn sampler_info(self) -> Option<SamplerInfo> {
247 match self {
248 Self::CombinedImageSampler(_, sampler_info, _) | Self::Sampler(_, sampler_info, _) => {
249 Some(sampler_info)
250 }
251 _ => None,
252 }
253 }
254
255 pub fn set_binding_count(&mut self, binding_count: u32) {
256 *match self {
257 Self::AccelerationStructure(binding_count) => binding_count,
258 Self::CombinedImageSampler(binding_count, ..) => binding_count,
259 Self::InputAttachment(binding_count, _) => binding_count,
260 Self::SampledImage(binding_count) => binding_count,
261 Self::Sampler(binding_count, ..) => binding_count,
262 Self::StorageBuffer(binding_count) => binding_count,
263 Self::StorageImage(binding_count) => binding_count,
264 Self::StorageTexelBuffer(binding_count) => binding_count,
265 Self::UniformBuffer(binding_count) => binding_count,
266 Self::UniformTexelBuffer(binding_count) => binding_count,
267 } = binding_count;
268 }
269}
270
271#[derive(Debug)]
272pub(crate) struct PipelineDescriptorInfo {
273 pub layouts: BTreeMap<u32, DescriptorSetLayout>,
274 pub pool_sizes: HashMap<u32, HashMap<vk::DescriptorType, u32>>,
275
276 #[allow(dead_code)]
277 samplers: Box<[Sampler]>,
278}
279
280impl PipelineDescriptorInfo {
281 #[profiling::function]
282 pub fn create(
283 device: &Device,
284 descriptor_bindings: &DescriptorBindingMap,
285 ) -> Result<Self, DriverError> {
286 let descriptor_set_count = descriptor_bindings
287 .keys()
288 .map(|descriptor| descriptor.set)
289 .max()
290 .map(|set| set + 1)
291 .unwrap_or_default();
292 let mut layouts = BTreeMap::new();
293 let mut pool_sizes = HashMap::new();
294
295 let mut sampler_info_binding_count = HashMap::<_, u32>::with_capacity(
298 descriptor_bindings
299 .values()
300 .filter(|(descriptor_info, _)| descriptor_info.sampler_info().is_some())
301 .count(),
302 );
303
304 for (sampler_info, binding_count) in
305 descriptor_bindings
306 .values()
307 .filter_map(|(descriptor_info, _)| {
308 descriptor_info
309 .sampler_info()
310 .map(|sampler_info| (sampler_info, descriptor_info.binding_count()))
311 })
312 {
313 sampler_info_binding_count
314 .entry(sampler_info)
315 .and_modify(|sampler_info_binding_count| {
316 *sampler_info_binding_count = binding_count.max(*sampler_info_binding_count);
317 })
318 .or_insert(binding_count);
319 }
320
321 let mut samplers = sampler_info_binding_count
322 .keys()
323 .copied()
324 .map(|sampler_info| {
325 Sampler::create(device, sampler_info).map(|sampler| (sampler_info, sampler))
326 })
327 .collect::<Result<HashMap<_, _>, _>>()?;
328 let immutable_samplers = sampler_info_binding_count
329 .iter()
330 .map(|(sampler_info, &binding_count)| {
331 (
332 *sampler_info,
333 repeat_n(*samplers[sampler_info], binding_count as _).collect::<Box<_>>(),
334 )
335 })
336 .collect::<HashMap<_, _>>();
337
338 for descriptor_set_idx in 0..descriptor_set_count {
339 let mut binding_counts = HashMap::<vk::DescriptorType, u32>::new();
340 let mut bindings = vec![];
341
342 for (descriptor, (descriptor_info, stage_flags)) in descriptor_bindings
343 .iter()
344 .filter(|(descriptor, _)| descriptor.set == descriptor_set_idx)
345 {
346 let descriptor_ty = descriptor_info.descriptor_type();
347 *binding_counts.entry(descriptor_ty).or_default() +=
348 descriptor_info.binding_count();
349 let mut binding = vk::DescriptorSetLayoutBinding::default()
350 .binding(descriptor.binding)
351 .descriptor_count(descriptor_info.binding_count())
352 .descriptor_type(descriptor_ty)
353 .stage_flags(*stage_flags);
354
355 if let Some(immutable_samplers) =
356 descriptor_info.sampler_info().map(|sampler_info| {
357 &immutable_samplers[&sampler_info]
358 [0..descriptor_info.binding_count() as usize]
359 })
360 {
361 binding = binding.immutable_samplers(immutable_samplers);
362 }
363
364 bindings.push(binding);
365 }
366
367 let pool_size = pool_sizes
368 .entry(descriptor_set_idx)
369 .or_insert_with(HashMap::new);
370
371 for (descriptor_ty, binding_count) in binding_counts.into_iter() {
372 *pool_size.entry(descriptor_ty).or_default() += binding_count;
373 }
374
375 let mut create_info = vk::DescriptorSetLayoutCreateInfo::default().bindings(&bindings);
378
379 let bindless_flags = vec![vk::DescriptorBindingFlags::PARTIALLY_BOUND; bindings.len()];
385 let mut bindless_flags = if device
386 .physical
387 .features_v1_2
388 .descriptor_binding_partially_bound
389 {
390 let bindless_flags = vk::DescriptorSetLayoutBindingFlagsCreateInfo::default()
391 .binding_flags(&bindless_flags);
392 Some(bindless_flags)
393 } else {
394 None
395 };
396
397 if let Some(bindless_flags) = bindless_flags.as_mut() {
398 create_info = create_info.push_next(bindless_flags);
399 }
400
401 layouts.insert(
402 descriptor_set_idx,
403 DescriptorSetLayout::create(device, &create_info)?,
404 );
405 }
406
407 let samplers = samplers
408 .drain()
409 .map(|(_, sampler)| sampler)
410 .collect::<Box<_>>();
411
412 Ok(Self {
416 layouts,
417 pool_sizes,
418 samplers,
419 })
420 }
421}
422
423pub(crate) struct Sampler {
424 device: Device,
425 sampler: vk::Sampler,
426}
427
428impl Sampler {
429 #[profiling::function]
430 pub fn create(device: &Device, info: impl Into<SamplerInfo>) -> Result<Self, DriverError> {
431 let device = device.clone();
432 let info = info.into();
433
434 let sampler = unsafe {
435 device
436 .create_sampler(
437 &vk::SamplerCreateInfo::default()
438 .flags(info.flags)
439 .mag_filter(info.mag_filter)
440 .min_filter(info.min_filter)
441 .mipmap_mode(info.mipmap_mode)
442 .address_mode_u(info.address_mode_u)
443 .address_mode_v(info.address_mode_v)
444 .address_mode_w(info.address_mode_w)
445 .mip_lod_bias(info.mip_lod_bias.0)
446 .anisotropy_enable(info.anisotropy_enable)
447 .max_anisotropy(info.max_anisotropy.0)
448 .compare_enable(info.compare_enable)
449 .compare_op(info.compare_op)
450 .min_lod(info.min_lod.0)
451 .max_lod(info.max_lod.0)
452 .border_color(info.border_color)
453 .unnormalized_coordinates(info.unnormalized_coordinates)
454 .push_next(
455 &mut vk::SamplerReductionModeCreateInfo::default()
456 .reduction_mode(info.reduction_mode),
457 ),
458 None,
459 )
460 .map_err(|err| match err {
461 vk::Result::ERROR_OUT_OF_HOST_MEMORY
462 | vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => {
463 warn!("unable to create sampler: {err}");
464 DriverError::OutOfMemory
465 }
466 _ => {
467 warn!("unsupported sampler creation: {err}");
468 DriverError::Unsupported
469 }
470 })?
471 };
472
473 Ok(Self { device, sampler })
474 }
475}
476
477impl Debug for Sampler {
478 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
479 f.debug_struct(stringify!(Sampler))
480 .field("handle", &self.sampler)
481 .finish_non_exhaustive()
482 }
483}
484
485impl Deref for Sampler {
486 type Target = vk::Sampler;
487
488 fn deref(&self) -> &Self::Target {
489 &self.sampler
490 }
491}
492
493impl Drop for Sampler {
494 #[profiling::function]
495 fn drop(&mut self) {
496 if panicking() {
497 return;
498 }
499
500 unsafe {
501 self.device.destroy_sampler(self.sampler, None);
502 }
503 }
504}
505
506#[derive(Builder, Clone, Copy, Debug, Eq, Hash, PartialEq)]
510#[builder(
511 build_fn(private, name = "fallible_build", error = "SamplerInfoBuilderError"),
512 derive(Clone, Copy, Debug),
513 pattern = "owned"
514)]
515pub struct SamplerInfo {
516 #[builder(default)]
518 pub flags: vk::SamplerCreateFlags,
519
520 #[builder(default)]
524 pub mag_filter: vk::Filter,
525
526 #[builder(default)]
530 pub min_filter: vk::Filter,
531
532 #[builder(default)]
536 pub mipmap_mode: vk::SamplerMipmapMode,
537
538 #[builder(default)]
542 pub address_mode_u: vk::SamplerAddressMode,
543
544 #[builder(default)]
548 pub address_mode_v: vk::SamplerAddressMode,
549
550 #[builder(default)]
554 pub address_mode_w: vk::SamplerAddressMode,
555
556 #[builder(default, setter(into))]
559 pub mip_lod_bias: OrderedFloat<f32>,
560
561 #[builder(default)]
563 pub anisotropy_enable: bool,
564
565 #[builder(default, setter(into))]
569 pub max_anisotropy: OrderedFloat<f32>,
570
571 #[builder(default)]
573 pub compare_enable: bool,
574
575 #[builder(default)]
577 pub compare_op: vk::CompareOp,
578
579 #[builder(default, setter(into))]
581 pub min_lod: OrderedFloat<f32>,
582
583 #[builder(default, setter(into))]
587 pub max_lod: OrderedFloat<f32>,
588
589 #[builder(default)]
593 pub border_color: vk::BorderColor,
594
595 #[builder(default)]
605 pub unnormalized_coordinates: bool,
606
607 #[builder(default)]
616 pub reduction_mode: vk::SamplerReductionMode,
617}
618
619impl SamplerInfo {
620 pub const LINEAR: SamplerInfoBuilder = SamplerInfoBuilder {
622 flags: None,
623 mag_filter: Some(vk::Filter::LINEAR),
624 min_filter: Some(vk::Filter::LINEAR),
625 mipmap_mode: Some(vk::SamplerMipmapMode::LINEAR),
626 address_mode_u: None,
627 address_mode_v: None,
628 address_mode_w: None,
629 mip_lod_bias: None,
630 anisotropy_enable: None,
631 max_anisotropy: None,
632 compare_enable: None,
633 compare_op: None,
634 min_lod: None,
635 max_lod: None,
636 border_color: None,
637 unnormalized_coordinates: None,
638 reduction_mode: None,
639 };
640
641 pub const NEAREST: SamplerInfoBuilder = SamplerInfoBuilder {
644 flags: None,
645 mag_filter: Some(vk::Filter::NEAREST),
646 min_filter: Some(vk::Filter::NEAREST),
647 mipmap_mode: Some(vk::SamplerMipmapMode::NEAREST),
648 address_mode_u: None,
649 address_mode_v: None,
650 address_mode_w: None,
651 mip_lod_bias: None,
652 anisotropy_enable: None,
653 max_anisotropy: None,
654 compare_enable: None,
655 compare_op: None,
656 min_lod: None,
657 max_lod: None,
658 border_color: None,
659 unnormalized_coordinates: None,
660 reduction_mode: None,
661 };
662
663 pub fn builder() -> SamplerInfoBuilder {
665 Default::default()
666 }
667
668 pub fn into_builder(self) -> SamplerInfoBuilder {
670 SamplerInfoBuilder {
671 flags: Some(self.flags),
672 mag_filter: Some(self.mag_filter),
673 min_filter: Some(self.min_filter),
674 mipmap_mode: Some(self.mipmap_mode),
675 address_mode_u: Some(self.address_mode_u),
676 address_mode_v: Some(self.address_mode_v),
677 address_mode_w: Some(self.address_mode_w),
678 mip_lod_bias: Some(self.mip_lod_bias),
679 anisotropy_enable: Some(self.anisotropy_enable),
680 max_anisotropy: Some(self.max_anisotropy),
681 compare_enable: Some(self.compare_enable),
682 compare_op: Some(self.compare_op),
683 min_lod: Some(self.min_lod),
684 max_lod: Some(self.max_lod),
685 border_color: Some(self.border_color),
686 unnormalized_coordinates: Some(self.unnormalized_coordinates),
687 reduction_mode: Some(self.reduction_mode),
688 }
689 }
690}
691
692impl Default for SamplerInfo {
693 fn default() -> Self {
694 Self {
695 flags: vk::SamplerCreateFlags::empty(),
696 mag_filter: vk::Filter::NEAREST,
697 min_filter: vk::Filter::NEAREST,
698 mipmap_mode: vk::SamplerMipmapMode::NEAREST,
699 address_mode_u: vk::SamplerAddressMode::REPEAT,
700 address_mode_v: vk::SamplerAddressMode::REPEAT,
701 address_mode_w: vk::SamplerAddressMode::REPEAT,
702 mip_lod_bias: OrderedFloat(0.0),
703 anisotropy_enable: false,
704 max_anisotropy: OrderedFloat(0.0),
705 compare_enable: false,
706 compare_op: vk::CompareOp::NEVER,
707 min_lod: OrderedFloat(0.0),
708 max_lod: OrderedFloat(0.0),
709 border_color: vk::BorderColor::FLOAT_TRANSPARENT_BLACK,
710 unnormalized_coordinates: false,
711 reduction_mode: vk::SamplerReductionMode::WEIGHTED_AVERAGE,
712 }
713 }
714}
715
716impl SamplerInfoBuilder {
717 #[inline(always)]
719 pub fn build(self) -> SamplerInfo {
720 self.fallible_build().expect("invalid sampler info")
721 }
722}
723
724impl From<SamplerInfoBuilder> for SamplerInfo {
725 fn from(info: SamplerInfoBuilder) -> Self {
726 info.build()
727 }
728}
729
730#[derive(Debug)]
731struct SamplerInfoBuilderError;
732
733impl From<UninitializedFieldError> for SamplerInfoBuilderError {
734 fn from(_: UninitializedFieldError) -> Self {
735 Self
736 }
737}
738
739#[allow(missing_docs)]
744#[derive(Builder, Clone)]
745#[builder(
746 build_fn(private, name = "fallible_build", error = "ShaderBuilderError"),
747 derive(Clone, Debug),
748 pattern = "owned"
749)]
750pub struct Shader {
751 #[builder(default = "\"main\".to_owned()", setter(into))]
755 pub entry_name: String,
756
757 #[builder(default, setter(strip_option))]
800 pub specialization: Option<SpecializationMap>,
801
802 #[builder(setter(into))]
810 pub spirv: SpirvBinary,
811
812 pub stage: vk::ShaderStageFlags,
816
817 #[builder(private)]
818 entry_point: EntryPoint,
819
820 #[builder(default, private)]
821 image_samplers: HashMap<Descriptor, SamplerInfo>,
822
823 #[builder(default, private, setter(strip_option))]
824 vertex_input_state: Option<VertexInputState>,
825}
826
827macro_rules! shader_ctors {
828 ($(($name:ident, $flag:ident, $desc:literal),)*) => {
829 paste::paste! {
830 $(
831 #[doc = $desc]
832 pub fn [<new_ $name>](spirv: impl Into<SpirvBinary>) -> ShaderBuilder {
838 ShaderBuilder::default().spirv(spirv).stage(vk::ShaderStageFlags::$flag)
839 }
840
841 #[doc = "Creates a "]
842 #[doc = $desc]
843 #[doc = ", returning an error if the SPIR-V is invalid."]
844 pub fn [<try_new_ $name>](spirv: impl Into<SpirvBinary>) -> Result<Shader, DriverError> {
845 ShaderBuilder::default()
846 .spirv(spirv)
847 .stage(vk::ShaderStageFlags::$flag)
848 .try_build()
849 }
850 )*
851 }
852 }
853}
854
855impl Shader {
856 #[allow(clippy::new_ret_no_self)]
860 pub fn new(stage: vk::ShaderStageFlags, spirv: impl Into<SpirvBinary>) -> ShaderBuilder {
861 ShaderBuilder::default().spirv(spirv).stage(stage)
862 }
863
864 shader_ctors! {
865 (any_hit, ANY_HIT_KHR, "Creates a new ray tracing any-hit shader."),
866 (callable, CALLABLE_KHR, "Creates a new ray tracing callable shader."),
867 (closest_hit, CLOSEST_HIT_KHR, "Creates a new ray tracing closest-hit shader."),
868 (compute, COMPUTE, "Creates a new compute shader."),
869 (fragment, FRAGMENT, "Creates a new fragment shader."),
870 (geometry, GEOMETRY, "Creates a new geometry shader."),
871 (intersection, INTERSECTION_KHR, "Creates a new ray tracing intersection shader."),
872 (mesh, MESH_EXT, "Creates a new mesh shader."),
873 (miss, MISS_KHR, "Creates a new ray tracing miss shader."),
874 (ray_gen, RAYGEN_KHR, "Creates a new ray tracing ray-generation shader."),
875 (task, TASK_EXT, "Creates a new task shader."),
876 (tessellation_ctrl, TESSELLATION_CONTROL, "Creates a new tessellation control shader."),
877 (tessellation_eval, TESSELLATION_EVALUATION, "Creates a new tessellation evaluation shader."),
878 (vertex, VERTEX, "Creates a new vertex shader."),
879 }
880
881 #[profiling::function]
883 pub(super) fn attachments(
884 &self,
885 ) -> (
886 impl Iterator<Item = u32> + '_,
887 impl Iterator<Item = u32> + '_,
888 ) {
889 (
890 self.entry_point.vars.iter().filter_map(|var| match var {
891 Variable::Descriptor {
892 desc_ty: DescriptorType::InputAttachment(attachment),
893 ..
894 } => Some(*attachment),
895 _ => None,
896 }),
897 self.entry_point.vars.iter().filter_map(|var| match var {
898 Variable::Output { location, .. } => Some(location.loc()),
899 _ => None,
900 }),
901 )
902 }
903
904 pub fn builder() -> ShaderBuilder {
906 Default::default()
907 }
908
909 #[profiling::function]
910 pub(super) fn descriptor_bindings(&self) -> DescriptorBindingMap {
911 let mut res = DescriptorBindingMap::default();
912
913 for (name, descriptor, desc_ty, binding_count) in
914 self.entry_point.vars.iter().filter_map(|var| match var {
915 Variable::Descriptor {
916 name,
917 desc_bind,
918 desc_ty,
919 nbind,
920 ..
921 } => Some((
922 name,
923 Descriptor {
924 set: desc_bind.set(),
925 binding: desc_bind.bind(),
926 },
927 desc_ty,
928 *nbind,
929 )),
930 _ => None,
931 })
932 {
933 trace!(
934 "descriptor {}: {}.{} = {:?}[{}]",
935 name.as_deref().unwrap_or_default(),
936 descriptor.set,
937 descriptor.binding,
938 *desc_ty,
939 binding_count
940 );
941
942 let descriptor_info = match desc_ty {
943 DescriptorType::AccelStruct() => {
944 DescriptorInfo::AccelerationStructure(binding_count)
945 }
946 DescriptorType::CombinedImageSampler() => {
947 let (sampler_info, is_manually_defined) =
948 self.image_sampler(descriptor, name.as_deref().unwrap_or_default());
949
950 DescriptorInfo::CombinedImageSampler(
951 binding_count,
952 sampler_info,
953 is_manually_defined,
954 )
955 }
956 DescriptorType::InputAttachment(attachment) => {
957 DescriptorInfo::InputAttachment(binding_count, *attachment)
958 }
959 DescriptorType::SampledImage() => DescriptorInfo::SampledImage(binding_count),
960 DescriptorType::Sampler() => {
961 let (sampler_info, is_manually_defined) =
962 self.image_sampler(descriptor, name.as_deref().unwrap_or_default());
963
964 DescriptorInfo::Sampler(binding_count, sampler_info, is_manually_defined)
965 }
966 DescriptorType::StorageBuffer(_access_ty) => {
967 DescriptorInfo::StorageBuffer(binding_count)
968 }
969 DescriptorType::StorageImage(_access_ty) => {
970 DescriptorInfo::StorageImage(binding_count)
971 }
972 DescriptorType::StorageTexelBuffer(_access_ty) => {
973 DescriptorInfo::StorageTexelBuffer(binding_count)
974 }
975 DescriptorType::UniformBuffer() => DescriptorInfo::UniformBuffer(binding_count),
976 DescriptorType::UniformTexelBuffer() => {
977 DescriptorInfo::UniformTexelBuffer(binding_count)
978 }
979 };
980 res.insert(descriptor, (descriptor_info, self.stage));
981 }
982
983 res
984 }
985
986 pub fn from_spirv(spirv: impl Into<SpirvBinary>) -> ShaderBuilder {
990 ShaderBuilder::default().spirv(spirv)
991 }
992
993 fn image_sampler(&self, descriptor: Descriptor, name: &str) -> (SamplerInfo, bool) {
994 self.image_samplers
995 .get(&descriptor)
996 .copied()
997 .map(|sampler_info| (sampler_info, true))
998 .unwrap_or_else(|| (guess_immutable_sampler(name), false))
999 }
1000
1001 #[profiling::function]
1002 pub(super) fn merge_descriptor_bindings(
1003 descriptor_bindings: impl IntoIterator<Item = DescriptorBindingMap>,
1004 ) -> Result<DescriptorBindingMap, DriverError> {
1005 fn merge_info(lhs: &mut DescriptorInfo, rhs: DescriptorInfo) -> bool {
1006 let (lhs_count, rhs_count) = match lhs {
1007 DescriptorInfo::AccelerationStructure(lhs) => {
1008 if let DescriptorInfo::AccelerationStructure(rhs) = rhs {
1009 (lhs, rhs)
1010 } else {
1011 return false;
1012 }
1013 }
1014 DescriptorInfo::CombinedImageSampler(lhs, lhs_sampler, lhs_is_manually_defined) => {
1015 if let DescriptorInfo::CombinedImageSampler(
1016 rhs,
1017 rhs_sampler,
1018 rhs_is_manually_defined,
1019 ) = rhs
1020 {
1021 if *lhs_is_manually_defined && rhs_is_manually_defined {
1023 return false;
1024 } else if rhs_is_manually_defined {
1025 *lhs_sampler = rhs_sampler;
1026 }
1027
1028 (lhs, rhs)
1029 } else {
1030 return false;
1031 }
1032 }
1033 DescriptorInfo::InputAttachment(lhs, lhs_idx) => {
1034 if let DescriptorInfo::InputAttachment(rhs, rhs_idx) = rhs {
1035 if *lhs_idx != rhs_idx {
1036 return false;
1037 }
1038
1039 (lhs, rhs)
1040 } else {
1041 return false;
1042 }
1043 }
1044 DescriptorInfo::SampledImage(lhs) => {
1045 if let DescriptorInfo::SampledImage(rhs) = rhs {
1046 (lhs, rhs)
1047 } else {
1048 return false;
1049 }
1050 }
1051 DescriptorInfo::Sampler(lhs, lhs_sampler, lhs_is_manually_defined) => {
1052 if let DescriptorInfo::Sampler(rhs, rhs_sampler, rhs_is_manually_defined) = rhs
1053 {
1054 if *lhs_is_manually_defined && rhs_is_manually_defined {
1056 return false;
1057 } else if rhs_is_manually_defined {
1058 *lhs_sampler = rhs_sampler;
1059 }
1060
1061 (lhs, rhs)
1062 } else {
1063 return false;
1064 }
1065 }
1066 DescriptorInfo::StorageBuffer(lhs) => {
1067 if let DescriptorInfo::StorageBuffer(rhs) = rhs {
1068 (lhs, rhs)
1069 } else {
1070 return false;
1071 }
1072 }
1073 DescriptorInfo::StorageImage(lhs) => {
1074 if let DescriptorInfo::StorageImage(rhs) = rhs {
1075 (lhs, rhs)
1076 } else {
1077 return false;
1078 }
1079 }
1080 DescriptorInfo::StorageTexelBuffer(lhs) => {
1081 if let DescriptorInfo::StorageTexelBuffer(rhs) = rhs {
1082 (lhs, rhs)
1083 } else {
1084 return false;
1085 }
1086 }
1087 DescriptorInfo::UniformBuffer(lhs) => {
1088 if let DescriptorInfo::UniformBuffer(rhs) = rhs {
1089 (lhs, rhs)
1090 } else {
1091 return false;
1092 }
1093 }
1094 DescriptorInfo::UniformTexelBuffer(lhs) => {
1095 if let DescriptorInfo::UniformTexelBuffer(rhs) = rhs {
1096 (lhs, rhs)
1097 } else {
1098 return false;
1099 }
1100 }
1101 };
1102
1103 *lhs_count = rhs_count.max(*lhs_count);
1104
1105 true
1106 }
1107
1108 #[profiling::function]
1109 fn merge_pair(
1110 src: DescriptorBindingMap,
1111 dst: &mut DescriptorBindingMap,
1112 ) -> Result<(), DriverError> {
1113 for (descriptor_binding, (descriptor_info, descriptor_flags)) in src.into_iter() {
1114 if let Some((existing_info, existing_flags)) = dst.get_mut(&descriptor_binding) {
1115 if !merge_info(existing_info, descriptor_info) {
1116 warn!("inconsistent shader descriptors ({descriptor_binding:?})");
1117
1118 return Err(DriverError::InvalidData);
1119 }
1120
1121 *existing_flags |= descriptor_flags;
1122 } else {
1123 dst.insert(descriptor_binding, (descriptor_info, descriptor_flags));
1124 }
1125 }
1126
1127 Ok(())
1128 }
1129
1130 let mut descriptor_bindings = descriptor_bindings.into_iter();
1131 let mut res = descriptor_bindings.next().unwrap_or_default();
1132 for descriptor_binding in descriptor_bindings {
1133 merge_pair(descriptor_binding, &mut res)?;
1134 }
1135
1136 Ok(res)
1137 }
1138
1139 #[profiling::function]
1140 pub(super) fn push_constant_range(&self) -> Option<vk::PushConstantRange> {
1141 self.entry_point
1142 .vars
1143 .iter()
1144 .filter_map(|var| match var {
1145 Variable::PushConstant {
1146 ty: Type::Struct(ty),
1147 ..
1148 } => Some(ty.members.clone()),
1149 _ => None,
1150 })
1151 .flatten()
1152 .map(|push_const| {
1153 let offset = push_const.offset.unwrap_or_default();
1154 let size = push_const
1155 .ty
1156 .nbyte()
1157 .unwrap_or_default()
1158 .next_multiple_of(4);
1159 offset..offset + size
1160 })
1161 .reduce(|a, b| a.start.min(b.start)..a.end.max(b.end))
1162 .map(|push_const| vk::PushConstantRange {
1163 stage_flags: self.stage,
1164 size: (push_const.end - push_const.start) as _,
1165 offset: push_const.start as _,
1166 })
1167 }
1168
1169 #[profiling::function]
1170 fn reflect_entry_point(
1171 entry_name: &str,
1172 spirv: impl Into<SpirvBinary>,
1173 specialization: Option<&SpecializationMap>,
1174 ) -> Result<EntryPoint, DriverError> {
1175 catch_unwind(AssertUnwindSafe(|| {
1180 Self::reflect_entry_point_unchecked(entry_name, spirv, specialization)
1181 }))
1182 .map_err(|_| {
1183 warn!("invalid shader reflection entry point: panic");
1184
1185 DriverError::InvalidData
1186 })?
1187 .map_err(|err| {
1188 warn!("invalid shader reflection entry point: {err}");
1189
1190 DriverError::InvalidData
1191 })
1192 }
1193
1194 #[profiling::function]
1195 fn reflect_entry_point_unchecked(
1196 entry_name: &str,
1197 spirv: impl Into<SpirvBinary>,
1198 specialization: Option<&SpecializationMap>,
1199 ) -> Result<EntryPoint, DriverError> {
1200 let mut config = ReflectConfig::new();
1201 config.ref_all_rscs(true).spv(spirv);
1202
1203 if let Some(specialization) = specialization {
1204 for &vk::SpecializationMapEntry {
1205 constant_id,
1206 offset,
1207 size,
1208 } in &specialization.entries
1209 {
1210 config.specialize(
1211 constant_id,
1212 specialization.data[offset as usize..offset as usize + size].into(),
1213 );
1214 }
1215 }
1216
1217 let entry_points = config.reflect().map_err(|err| {
1218 error!("invalid SPIR-V reflection data: {err}");
1219
1220 DriverError::InvalidData
1221 })?;
1222 let entry_point = entry_points
1223 .into_iter()
1224 .find(|entry_point| entry_point.name == entry_name)
1225 .ok_or_else(|| {
1226 error!("invalid shader entry point: not found");
1227
1228 DriverError::InvalidData
1229 })?;
1230
1231 Ok(entry_point)
1232 }
1233
1234 #[profiling::function]
1235 pub(super) fn try_vertex_input(&self) -> Result<VertexInputState, DriverError> {
1236 if let Some(vertex_input) = &self.vertex_input_state {
1238 return Ok(vertex_input.clone());
1239 }
1240
1241 fn scalar_format(ty: &ScalarType) -> Option<vk::Format> {
1242 match *ty {
1243 ScalarType::Float { bits } => match bits {
1244 u8::BITS => Some(vk::Format::R8_SNORM),
1245 u16::BITS => Some(vk::Format::R16_SFLOAT),
1246 u32::BITS => Some(vk::Format::R32_SFLOAT),
1247 u64::BITS => Some(vk::Format::R64_SFLOAT),
1248 _ => None,
1249 },
1250 ScalarType::Integer {
1251 bits,
1252 is_signed: false,
1253 } => match bits {
1254 u8::BITS => Some(vk::Format::R8_UINT),
1255 u16::BITS => Some(vk::Format::R16_UINT),
1256 u32::BITS => Some(vk::Format::R32_UINT),
1257 u64::BITS => Some(vk::Format::R64_UINT),
1258 _ => None,
1259 },
1260 ScalarType::Integer {
1261 bits,
1262 is_signed: true,
1263 } => match bits {
1264 u8::BITS => Some(vk::Format::R8_SINT),
1265 u16::BITS => Some(vk::Format::R16_SINT),
1266 u32::BITS => Some(vk::Format::R32_SINT),
1267 u64::BITS => Some(vk::Format::R64_SINT),
1268 _ => None,
1269 },
1270 _ => None,
1271 }
1272 }
1273
1274 fn vector_format(ty: &VectorType) -> Option<vk::Format> {
1275 match *ty {
1276 VectorType {
1277 scalar_ty: ScalarType::Float { bits },
1278 nscalar,
1279 } => match (bits, nscalar) {
1280 (u8::BITS, 2) => Some(vk::Format::R8G8_SNORM),
1281 (u8::BITS, 3) => Some(vk::Format::R8G8B8_SNORM),
1282 (u8::BITS, 4) => Some(vk::Format::R8G8B8A8_SNORM),
1283 (u16::BITS, 2) => Some(vk::Format::R16G16_SFLOAT),
1284 (u16::BITS, 3) => Some(vk::Format::R16G16B16_SFLOAT),
1285 (u16::BITS, 4) => Some(vk::Format::R16G16B16A16_SFLOAT),
1286 (u32::BITS, 2) => Some(vk::Format::R32G32_SFLOAT),
1287 (u32::BITS, 3) => Some(vk::Format::R32G32B32_SFLOAT),
1288 (u32::BITS, 4) => Some(vk::Format::R32G32B32A32_SFLOAT),
1289 (u64::BITS, 2) => Some(vk::Format::R64G64_SFLOAT),
1290 (u64::BITS, 3) => Some(vk::Format::R64G64B64_SFLOAT),
1291 (u64::BITS, 4) => Some(vk::Format::R64G64B64A64_SFLOAT),
1292 _ => None,
1293 },
1294 VectorType {
1295 scalar_ty:
1296 ScalarType::Integer {
1297 bits,
1298 is_signed: false,
1299 },
1300 nscalar,
1301 } => match (bits, nscalar) {
1302 (u8::BITS, 2) => Some(vk::Format::R8G8_UINT),
1303 (u8::BITS, 3) => Some(vk::Format::R8G8B8_UINT),
1304 (u8::BITS, 4) => Some(vk::Format::R8G8B8A8_UINT),
1305 (u16::BITS, 2) => Some(vk::Format::R16G16_UINT),
1306 (u16::BITS, 3) => Some(vk::Format::R16G16B16_UINT),
1307 (u16::BITS, 4) => Some(vk::Format::R16G16B16A16_UINT),
1308 (u32::BITS, 2) => Some(vk::Format::R32G32_UINT),
1309 (u32::BITS, 3) => Some(vk::Format::R32G32B32_UINT),
1310 (u32::BITS, 4) => Some(vk::Format::R32G32B32A32_UINT),
1311 (u64::BITS, 2) => Some(vk::Format::R64G64_UINT),
1312 (u64::BITS, 3) => Some(vk::Format::R64G64B64_UINT),
1313 (u64::BITS, 4) => Some(vk::Format::R64G64B64A64_UINT),
1314 _ => None,
1315 },
1316 VectorType {
1317 scalar_ty:
1318 ScalarType::Integer {
1319 bits,
1320 is_signed: true,
1321 },
1322 nscalar,
1323 } => match (bits, nscalar) {
1324 (u8::BITS, 2) => Some(vk::Format::R8G8_SINT),
1325 (u8::BITS, 3) => Some(vk::Format::R8G8B8_SINT),
1326 (u8::BITS, 4) => Some(vk::Format::R8G8B8A8_SINT),
1327 (u16::BITS, 2) => Some(vk::Format::R16G16_SINT),
1328 (u16::BITS, 3) => Some(vk::Format::R16G16B16_SINT),
1329 (u16::BITS, 4) => Some(vk::Format::R16G16B16A16_SINT),
1330 (u32::BITS, 2) => Some(vk::Format::R32G32_SINT),
1331 (u32::BITS, 3) => Some(vk::Format::R32G32B32_SINT),
1332 (u32::BITS, 4) => Some(vk::Format::R32G32B32A32_SINT),
1333 (u64::BITS, 2) => Some(vk::Format::R64G64_SINT),
1334 (u64::BITS, 3) => Some(vk::Format::R64G64B64_SINT),
1335 (u64::BITS, 4) => Some(vk::Format::R64G64B64A64_SINT),
1336 _ => None,
1337 },
1338 _ => None,
1339 }
1340 }
1341
1342 let mut input_rates_strides = HashMap::new();
1343 let mut vertex_attribute_descriptions = vec![];
1344
1345 for (name, location, ty) in self.entry_point.vars.iter().filter_map(|var| match var {
1346 Variable::Input { name, location, ty } => Some((name, location, ty)),
1347 _ => None,
1348 }) {
1349 let (binding, guessed_rate) = name
1350 .as_ref()
1351 .filter(|name| name.contains("_ibind") || name.contains("_vbind"))
1352 .map(|name| {
1353 let binding = name[name.rfind("bind").expect("missing bind suffix")..]
1354 .parse()
1355 .unwrap_or_default();
1356 let rate = if name.contains("_ibind") {
1357 vk::VertexInputRate::INSTANCE
1358 } else {
1359 vk::VertexInputRate::VERTEX
1360 };
1361
1362 (binding, rate)
1363 })
1364 .unwrap_or_default();
1365 let (location, _) = location.into_inner();
1366 if let Some((input_rate, _)) = input_rates_strides.get(&binding) {
1367 assert_eq!(*input_rate, guessed_rate);
1368 }
1369
1370 let byte_stride = ty.nbyte().unwrap_or_default() as u32;
1371 let (input_rate, stride) = input_rates_strides.entry(binding).or_default();
1372 *input_rate = guessed_rate;
1373 *stride += byte_stride;
1374
1375 let format = match ty {
1378 Type::Scalar(ty) => scalar_format(ty),
1379 Type::Vector(ty) => vector_format(ty),
1380 _ => None,
1381 }
1382 .ok_or_else(|| {
1383 warn!("unsupported reflected vertex input type: {ty:?}");
1384
1385 DriverError::Unsupported
1386 })?;
1387
1388 vertex_attribute_descriptions.push(vk::VertexInputAttributeDescription {
1389 location,
1390 binding,
1391 format,
1392 offset: byte_stride,
1393 });
1394 }
1395
1396 vertex_attribute_descriptions.sort_unstable_by(|lhs, rhs| {
1397 let binding = lhs.binding.cmp(&rhs.binding);
1398 if binding.is_lt() {
1399 return binding;
1400 }
1401
1402 lhs.location.cmp(&rhs.location)
1403 });
1404
1405 let mut offset = 0;
1406 let mut offset_binding = 0;
1407
1408 for vertex_attribute_description in &mut vertex_attribute_descriptions {
1409 if vertex_attribute_description.binding != offset_binding {
1410 offset_binding = vertex_attribute_description.binding;
1411 offset = 0;
1412 }
1413
1414 let stride = vertex_attribute_description.offset;
1415 vertex_attribute_description.offset = offset;
1416 offset += stride;
1417
1418 debug!(
1419 "vertex attribute {}.{}: {:?} (offset={})",
1420 vertex_attribute_description.binding,
1421 vertex_attribute_description.location,
1422 vertex_attribute_description.format,
1423 vertex_attribute_description.offset,
1424 );
1425 }
1426
1427 let mut vertex_binding_descriptions = vec![];
1428 for (binding, (input_rate, stride)) in input_rates_strides.into_iter() {
1429 vertex_binding_descriptions.push(vk::VertexInputBindingDescription {
1430 binding,
1431 input_rate,
1432 stride,
1433 });
1434 }
1435
1436 Ok(VertexInputState {
1437 vertex_attribute_descriptions,
1438 vertex_binding_descriptions,
1439 })
1440 }
1441
1442 #[profiling::function]
1443 pub(super) fn vertex_input(&self) -> VertexInputState {
1444 self.try_vertex_input()
1445 .expect("unsupported reflected vertex input layout")
1446 }
1447}
1448
1449impl Debug for Shader {
1450 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1451 f.debug_struct(stringify!(Shader))
1453 .field("entry_name", &self.entry_name)
1454 .field("stage", &self.stage)
1455 .field("specialization", &self.specialization)
1456 .field("reflected_vars", &self.entry_point.vars.len())
1457 .finish_non_exhaustive()
1458 }
1459}
1460
1461impl TryFrom<ShaderBuilder> for Shader {
1462 type Error = DriverError;
1463
1464 fn try_from(shader: ShaderBuilder) -> Result<Self, Self::Error> {
1465 shader.try_build()
1466 }
1467}
1468
1469impl TryFrom<&[u8]> for Shader {
1470 type Error = DriverError;
1471
1472 fn try_from(spirv: &[u8]) -> Result<Self, Self::Error> {
1473 Shader::from_spirv(spirv).try_build()
1474 }
1475}
1476
1477impl TryFrom<&[u32]> for Shader {
1478 type Error = DriverError;
1479
1480 fn try_from(spirv: &[u32]) -> Result<Self, Self::Error> {
1481 Shader::from_spirv(spirv).try_build()
1482 }
1483}
1484
1485impl TryFrom<Vec<u8>> for Shader {
1486 type Error = DriverError;
1487
1488 fn try_from(spirv: Vec<u8>) -> Result<Self, Self::Error> {
1489 Shader::from_spirv(spirv).try_build()
1490 }
1491}
1492
1493impl TryFrom<Vec<u32>> for Shader {
1494 type Error = DriverError;
1495
1496 fn try_from(spirv: Vec<u32>) -> Result<Self, Self::Error> {
1497 Shader::from_spirv(spirv).try_build()
1498 }
1499}
1500
1501impl ShaderBuilder {
1503 pub fn new(stage: vk::ShaderStageFlags, spirv: Vec<u8>) -> Self {
1505 Self::default().stage(stage).spirv(spirv)
1506 }
1507
1508 pub fn build(self) -> Shader {
1514 self.try_build()
1515 .unwrap_or_else(|err| panic!("invalid or unsupported shader code: {err}"))
1516 }
1517
1518 #[profiling::function]
1538 pub fn image_sampler(
1539 mut self,
1540 descriptor: impl Into<Descriptor>,
1541 info: impl Into<SamplerInfo>,
1542 ) -> Self {
1543 let descriptor = descriptor.into();
1544 let info = info.into();
1545
1546 if self.image_samplers.is_none() {
1547 self.image_samplers = Some(Default::default());
1548 }
1549
1550 self.image_samplers
1551 .as_mut()
1552 .expect("missing image samplers")
1553 .insert(descriptor, info);
1554
1555 self
1556 }
1557
1558 pub fn try_build(mut self) -> Result<Shader, DriverError> {
1560 let entry_name = self.entry_name.as_deref().unwrap_or("main");
1561 let spirv = self
1562 .spirv
1563 .as_ref()
1564 .map(|spirv| spirv.words())
1565 .ok_or(DriverError::InvalidData)?;
1566 let specialization = self
1567 .specialization
1568 .as_ref()
1569 .map(|opt| opt.as_ref())
1570 .unwrap_or_default();
1571 let entry_point = Shader::reflect_entry_point(entry_name, spirv, specialization)?;
1572
1573 if self.stage.unwrap_or_default().is_empty() {
1574 self.stage = Some(match entry_point.exec_model {
1575 ExecutionModel::Vertex => vk::ShaderStageFlags::VERTEX,
1576 ExecutionModel::TessellationControl => vk::ShaderStageFlags::TESSELLATION_CONTROL,
1577 ExecutionModel::TessellationEvaluation => {
1578 vk::ShaderStageFlags::TESSELLATION_EVALUATION
1579 }
1580 ExecutionModel::Geometry => vk::ShaderStageFlags::GEOMETRY,
1581 ExecutionModel::Fragment => vk::ShaderStageFlags::FRAGMENT,
1582 ExecutionModel::GLCompute => vk::ShaderStageFlags::COMPUTE,
1583 ExecutionModel::Kernel => {
1584 warn!("unsupported shader execution model: kernel");
1585
1586 return Err(DriverError::Unsupported);
1587 }
1588 ExecutionModel::TaskNV => vk::ShaderStageFlags::TASK_EXT,
1589 ExecutionModel::MeshNV => vk::ShaderStageFlags::MESH_EXT,
1590 ExecutionModel::RayGenerationNV => vk::ShaderStageFlags::RAYGEN_KHR,
1591 ExecutionModel::IntersectionNV => vk::ShaderStageFlags::INTERSECTION_KHR,
1592 ExecutionModel::AnyHitNV => vk::ShaderStageFlags::ANY_HIT_KHR,
1593 ExecutionModel::ClosestHitNV => vk::ShaderStageFlags::CLOSEST_HIT_KHR,
1594 ExecutionModel::MissNV => vk::ShaderStageFlags::MISS_KHR,
1595 ExecutionModel::CallableNV => vk::ShaderStageFlags::CALLABLE_KHR,
1596 ExecutionModel::TaskEXT => vk::ShaderStageFlags::TASK_EXT,
1597 ExecutionModel::MeshEXT => vk::ShaderStageFlags::MESH_EXT,
1598 })
1599 }
1600
1601 self.entry_point = Some(entry_point);
1602
1603 self.fallible_build().map_err(|err| {
1604 warn!("invalid shader builder state: {err:?}");
1605
1606 DriverError::InvalidData
1607 })
1608 }
1609
1610 #[profiling::function]
1622 pub fn vertex_input(
1623 mut self,
1624 bindings: impl Into<Vec<vk::VertexInputBindingDescription>>,
1625 attributes: impl Into<Vec<vk::VertexInputAttributeDescription>>,
1626 ) -> Self {
1627 self.vertex_input_state = Some(Some(VertexInputState {
1628 vertex_binding_descriptions: bindings.into(),
1629 vertex_attribute_descriptions: attributes.into(),
1630 }));
1631 self
1632 }
1633}
1634
1635#[derive(Debug)]
1636struct ShaderBuilderError;
1637
1638impl From<UninitializedFieldError> for ShaderBuilderError {
1639 fn from(_: UninitializedFieldError) -> Self {
1640 Self
1641 }
1642}
1643
1644#[derive(Clone, Debug, Default)]
1646pub struct SpecializationMap {
1647 pub data: Vec<u8>,
1649
1650 pub entries: Vec<vk::SpecializationMapEntry>,
1653}
1654
1655impl SpecializationMap {
1656 pub fn new(data: impl Into<Vec<u8>>) -> Self {
1658 Self {
1659 data: data.into(),
1660 entries: Default::default(),
1661 }
1662 }
1663
1664 pub fn constant(mut self, constant_id: u32, offset: u32, size: usize) -> Self {
1666 self.set_constant(constant_id, offset, size);
1667 self
1668 }
1669
1670 pub fn set_constant(&mut self, constant_id: u32, offset: u32, size: usize) {
1672 self.entries.push(vk::SpecializationMapEntry {
1673 constant_id,
1674 offset,
1675 size,
1676 });
1677 }
1678}
1679
1680impl<'a> From<&'a SpecializationMap> for vk::SpecializationInfo<'a> {
1681 fn from(value: &'a SpecializationMap) -> Self {
1682 vk::SpecializationInfo::default()
1683 .map_entries(&value.entries)
1684 .data(&value.data)
1685 }
1686}
1687
1688#[cfg(test)]
1689mod test {
1690 use super::*;
1691
1692 type Info = SamplerInfo;
1693 type Builder = SamplerInfoBuilder;
1694
1695 #[test]
1696 pub fn sampler_info() {
1697 let info = Info::default();
1698 let builder = info.into_builder().build();
1699
1700 assert_eq!(info, builder);
1701 }
1702
1703 #[test]
1704 pub fn sampler_info_builder() {
1705 let info = Info::default();
1706 let builder = Builder::default().build();
1707
1708 assert_eq!(info, builder);
1709 }
1710
1711 #[test]
1712 pub fn invalid_spirv_try_into_driver_value() {
1713 assert!(Shader::try_from(vec![0u32]).is_err());
1714 }
1715
1716 #[test]
1717 pub fn merge_descriptor_bindings_rejects_mismatched_descriptors() {
1718 let mut lhs = DescriptorBindingMap::default();
1719 lhs.insert(
1720 Descriptor::from(0),
1721 (
1722 DescriptorInfo::UniformBuffer(1),
1723 vk::ShaderStageFlags::VERTEX,
1724 ),
1725 );
1726
1727 let mut rhs = DescriptorBindingMap::default();
1728 rhs.insert(
1729 Descriptor::from(0),
1730 (
1731 DescriptorInfo::StorageBuffer(1),
1732 vk::ShaderStageFlags::FRAGMENT,
1733 ),
1734 );
1735
1736 assert!(matches!(
1737 Shader::merge_descriptor_bindings([lhs, rhs]),
1738 Err(DriverError::InvalidData)
1739 ));
1740 }
1741}