diff --git a/src/back/glsl/features.rs b/src/back/glsl/features.rs index 0d78558991..3f300ddf67 100644 --- a/src/back/glsl/features.rs +++ b/src/back/glsl/features.rs @@ -343,6 +343,8 @@ impl<'a, W> Writer<'a, W> { } } + let mut push_constant_used = false; + for (handle, global) in self.module.global_variables.iter() { if ep_info[handle].is_empty() { continue; @@ -350,7 +352,12 @@ impl<'a, W> Writer<'a, W> { match global.class { StorageClass::WorkGroup => self.features.request(Features::COMPUTE_SHADER), StorageClass::Storage { .. } => self.features.request(Features::BUFFER_STORAGE), - StorageClass::PushConstant => return Err(Error::PushConstantNotSupported), + StorageClass::PushConstant => { + if push_constant_used { + return Err(Error::MultiplePushConstants); + } + push_constant_used = true; + } _ => {} } } diff --git a/src/back/glsl/mod.rs b/src/back/glsl/mod.rs index 239cb0a159..1e6f65b861 100644 --- a/src/back/glsl/mod.rs +++ b/src/back/glsl/mod.rs @@ -86,7 +86,9 @@ impl crate::AtomicFunction { impl crate::StorageClass { fn is_buffer(&self) -> bool { match *self { - crate::StorageClass::Uniform | crate::StorageClass::Storage { .. } => true, + crate::StorageClass::PushConstant + | crate::StorageClass::Uniform + | crate::StorageClass::Storage { .. } => true, _ => false, } } @@ -96,6 +98,7 @@ impl crate::StorageClass { match *self { crate::StorageClass::WorkGroup | crate::StorageClass::Uniform + | crate::StorageClass::PushConstant | crate::StorageClass::Storage { .. } => false, _ => true, } @@ -227,6 +230,8 @@ pub struct Options { pub writer_flags: WriterFlags, /// Map of resources association to binding locations. pub binding_map: BindingMap, + /// The binding to give the push constant buffer if it's present + pub push_constant_binding: u32, } impl Default for Options { @@ -235,6 +240,7 @@ impl Default for Options { version: Version::Embedded(310), writer_flags: WriterFlags::ADJUST_COORDINATE_SPACE, binding_map: BindingMap::default(), + push_constant_binding: 0, } } } @@ -257,6 +263,7 @@ pub struct PipelineOptions { pub struct ReflectionInfo { pub texture_mapping: crate::FastHashMap, pub uniforms: crate::FastHashMap, String>, + pub push_constant: Option, } /// Structure that connects a texture to a sampler or not @@ -348,10 +355,10 @@ pub enum Error { /// Contains the missing [`Features`](Features) #[error("The selected version doesn't support {0:?}")] MissingFeatures(Features), - /// [`StorageClass::PushConstant`](crate::StorageClass::PushConstant) was used and isn't - /// supported in the glsl backend - #[error("Push constants aren't supported")] - PushConstantNotSupported, + /// [`StorageClass::PushConstant`](crate::StorageClass::PushConstant) was used more than + /// once in the entry point which isn't supported + #[error("Multiple push constants aren't supported")] + MultiplePushConstants, /// The specified [`Version`](Version) isn't supported #[error("The specified version isn't supported")] VersionNotSupported, @@ -887,7 +894,13 @@ impl<'a, W: Write> Writer<'a, W> { global: &crate::GlobalVariable, ) -> BackendResult { if self.options.version.supports_explicit_locations() { - if let Some(ref br) = global.binding { + if let crate::StorageClass::PushConstant = global.class { + write!( + self.out, + "layout(std140, binding = {}) ", + self.options.push_constant_binding + )? + } else if let Some(ref br) = global.binding { match self.options.binding_map.get(br) { Some(binding) => { let layout = match global.class { @@ -898,7 +911,9 @@ impl<'a, W: Write> Writer<'a, W> { "std140, " } } - crate::StorageClass::Uniform => "std140, ", + crate::StorageClass::Uniform | crate::StorageClass::PushConstant => { + "std140, " + } _ => "", }; write!(self.out, "layout({}binding = {}) ", layout, binding)? @@ -2852,15 +2867,12 @@ impl<'a, W: Write> Writer<'a, W> { } /// Helper method used to produce the reflection info that's returned to the user - /// - /// It takes an iterator of [`Function`](crate::Function) references instead of - /// [`Handle`](crate::arena::Handle) because [`EntryPoint`](crate::EntryPoint) isn't in any - /// [`Arena`](crate::arena::Arena) and we need to traverse it fn collect_reflection_info(&self) -> Result { use std::collections::hash_map::Entry; let info = self.info.get_entry_point(self.entry_point_idx as usize); let mut texture_mapping = crate::FastHashMap::default(); let mut uniforms = crate::FastHashMap::default(); + let mut push_constant = None; for sampling in info.sampling_set.iter() { let tex_name = self.reflection_names_globals[&sampling.image].clone(); @@ -2891,6 +2903,10 @@ impl<'a, W: Write> Writer<'a, W> { let name = self.reflection_names_globals[&handle].clone(); uniforms.insert(handle, name); } + crate::StorageClass::PushConstant => { + let name = self.reflection_names_globals[&handle].clone(); + push_constant = Some(name) + } _ => (), }, crate::TypeInner::Image { .. } => { @@ -2914,6 +2930,7 @@ impl<'a, W: Write> Writer<'a, W> { Ok(ReflectionInfo { texture_mapping, uniforms, + push_constant, }) } } @@ -3021,7 +3038,7 @@ fn glsl_storage_class(class: crate::StorageClass) -> Option<&'static str> { Sc::Uniform => Some("uniform"), Sc::Handle => Some("uniform"), Sc::WorkGroup => Some("shared"), - Sc::PushConstant => None, + Sc::PushConstant => Some("uniform"), } } diff --git a/tests/in/functions-webgl.param.ron b/tests/in/functions-webgl.param.ron index bc3dd4a8dd..1d84e945ba 100644 --- a/tests/in/functions-webgl.param.ron +++ b/tests/in/functions-webgl.param.ron @@ -3,5 +3,6 @@ version: Embedded(300), writer_flags: (bits: 0), binding_map: {}, + push_constant_binding: 0, ), ) diff --git a/tests/in/interpolate.param.ron b/tests/in/interpolate.param.ron index cb08368c87..bfea94342e 100644 --- a/tests/in/interpolate.param.ron +++ b/tests/in/interpolate.param.ron @@ -10,5 +10,6 @@ version: Desktop(400), writer_flags: (bits: 0), binding_map: {}, + push_constant_binding: 0, ), ) diff --git a/tests/in/quad.param.ron b/tests/in/quad.param.ron index acde3aed42..c969a84b2e 100644 --- a/tests/in/quad.param.ron +++ b/tests/in/quad.param.ron @@ -8,5 +8,6 @@ version: Embedded(300), writer_flags: (bits: 0), binding_map: {}, + push_constant_binding: 0, ), ) diff --git a/tests/in/skybox.param.ron b/tests/in/skybox.param.ron index 9c9bd1f30a..ea040e4fb6 100644 --- a/tests/in/skybox.param.ron +++ b/tests/in/skybox.param.ron @@ -43,6 +43,7 @@ (group: 0, binding: 0): 0, (group: 0, binding: 1): 0, }, + push_constant_binding: 0, ), hlsl: ( shader_model: V5_1,