diff --git a/CHANGELOG_VULKANO.md b/CHANGELOG_VULKANO.md index 9606eee7..53b3e325 100644 --- a/CHANGELOG_VULKANO.md +++ b/CHANGELOG_VULKANO.md @@ -37,6 +37,8 @@ - Traits that no longer make sense in this context have been removed: `FormatDesc`, the `Possible*FormatDesc` traits, `StrongStorage`. - In types that had a type parameter for the format type, it has been removed. - `AcceptsPixels` has been converted to `Pixel`, which is implemented on the pixel type rather than on the format type. +- **Breaking** `shader!` will generate descriptor information for all variables declared in the shader module, even if they are not used. *This reverts the default behavior from the last release.* + - **Breaking** Added the `exact_entrypoint_interface` option to `shader!` to force vulkano to only generate descriptor information for variables that are used. (the default behavior from the last release) - Added two methods to `Format`: `planes` to query the number of planes in the format, and `aspects` to query what aspects an image of this type has. - The deprecated `cause` trait function on Vulkano error types is replaced with `source`. - Fixed bug in descriptor array layers check when the image is a cubemap. diff --git a/vulkano-shaders/src/codegen.rs b/vulkano-shaders/src/codegen.rs index eb51b87c..c8d969d9 100644 --- a/vulkano-shaders/src/codegen.rs +++ b/vulkano-shaders/src/codegen.rs @@ -204,6 +204,7 @@ pub(super) fn reflect<'a, I>( spirv: &[u32], types_meta: TypesMeta, input_paths: I, + exact_entrypoint_interface: bool, dump: bool, ) -> Result where @@ -263,8 +264,12 @@ where let mut entry_points_outside_impl: Vec = vec![]; for instruction in doc.instructions.iter() { if let &Instruction::EntryPoint { .. } = instruction { - let (outside, entry_point, descriptor_sets) = - entry_point::write_entry_point(&doc, instruction, &types_meta); + let (outside, entry_point, descriptor_sets) = entry_point::write_entry_point( + &doc, + instruction, + &types_meta, + exact_entrypoint_interface, + ); entry_points_inside_impl.push(entry_point); entry_points_outside_impl.push(outside); entry_points_outside_impl.push(descriptor_sets); diff --git a/vulkano-shaders/src/descriptor_sets.rs b/vulkano-shaders/src/descriptor_sets.rs index 50a5cf53..7538b6ea 100644 --- a/vulkano-shaders/src/descriptor_sets.rs +++ b/vulkano-shaders/src/descriptor_sets.rs @@ -31,11 +31,12 @@ pub(super) fn write_descriptor_sets( entrypoint_id: u32, interface: &[u32], types_meta: &TypesMeta, + exact_entrypoint_interface: bool, ) -> TokenStream { // TODO: somewhat implemented correctly // Finding all the descriptors. - let descriptors = find_descriptors(doc, entrypoint_id, interface); + let descriptors = find_descriptors(doc, entrypoint_id, interface, exact_entrypoint_interface); // Looping to find all the push constant structs. let mut push_constants_size = 0; @@ -138,14 +139,19 @@ pub(super) fn write_descriptor_sets( } } -fn find_descriptors(doc: &Spirv, entrypoint_id: u32, interface: &[u32]) -> Vec { +fn find_descriptors( + doc: &Spirv, + entrypoint_id: u32, + interface: &[u32], + exact: bool, +) -> Vec { let mut descriptors = Vec::new(); // For SPIR-V 1.4+, the entrypoint interface can specify variables of all storage classes, // and most tools will put all used variables in the entrypoint interface. However, // SPIR-V 1.0-1.3 do not specify variables other than Input/Output ones in the interface, // and instead the function itself must be inspected. - let variables = { + let variables = if exact { let mut found_variables: HashSet = interface.iter().cloned().collect(); let mut inspected_functions: HashSet = HashSet::new(); find_variables_in_function( @@ -154,14 +160,16 @@ fn find_descriptors(doc: &Spirv, entrypoint_id: u32, interface: &[u32]) -> Vec (TokenStream, TokenStream, TokenStream) { let (execution, id, ep_name, interface) = match instruction { &Instruction::EntryPoint { @@ -67,6 +68,7 @@ pub(super) fn write_entry_point( id, interface, &types_meta, + exact_entrypoint_interface, ); let spec_consts_struct = if crate::spec_consts::has_specialization_constants(doc) { diff --git a/vulkano-shaders/src/lib.rs b/vulkano-shaders/src/lib.rs index adeb574c..ef7eb125 100644 --- a/vulkano-shaders/src/lib.rs +++ b/vulkano-shaders/src/lib.rs @@ -134,6 +134,8 @@ //! Provides the path to precompiled SPIR-V bytecode, relative to `Cargo.toml`. //! Cannot be used in conjunction with the `src` or `path` field. //! This allows using shaders compiled through a separate build system. +//! **Note**: If your shader contains multiple entrypoints with different +//! descriptor sets, you may also need to enable `exact_entrypoint_interface`. //! //! ## `include: ["...", "...", ..., "..."]` //! @@ -172,6 +174,19 @@ //! final output of generated code the user can also use `dump` macro //! option(see below). //! +//! ## `exact_entrypoint_interface: true` +//! +//! By default, the macro assumes that all resources (Uniforms, Storage Buffers, +//! Images, Samplers, etc) need to be bound into a descriptor set, even if they are +//! not used in the shader code. However, shaders with multiple entrypoints may have +//! conflicting descriptor sets for each entrypoint. Enabling this option will force +//! the macro to only generate descriptor information for resources that are used +//! in each entrypoint. +//! +//! The macro determines which resources are used by looking at each entrypoint's +//! interface and bytecode. See [`src/descriptor_sets.rs`][descriptor_sets] +//! for the exact logic. +//! //! ## `dump: true` //! //! The crate fails to compile but prints the generated rust code to stdout. @@ -186,6 +201,7 @@ //! [PipelineLayoutDesc]: https://docs.rs/vulkano/*/vulkano/descriptor/pipeline_layout/trait.PipelineLayoutDesc.html //! [SpecializationConstants]: https://docs.rs/vulkano/*/vulkano/pipeline/shader/trait.SpecializationConstants.html //! [pipeline]: https://docs.rs/vulkano/*/vulkano/pipeline/index.html +//! [descriptor_sets]: https://github.com/vulkano-rs/vulkano/blob/master/vulkano-shaders/src/descriptor_sets.rs#L142 #![doc(html_logo_url = "https://raw.githubusercontent.com/vulkano-rs/vulkano/master/logo.png")] #![recursion_limit = "1024"] @@ -276,6 +292,7 @@ struct MacroInput { include_directories: Vec, macro_defines: Vec<(String, String)>, types_meta: TypesMeta, + exact_entrypoint_interface: bool, dump: bool, } @@ -287,6 +304,7 @@ impl Parse for MacroInput { let mut include_directories = Vec::new(); let mut macro_defines = Vec::new(); let mut types_meta = None; + let mut exact_entrypoint_interface = None; while !input.is_empty() { let name: Ident = input.parse()?; @@ -504,6 +522,13 @@ impl Parse for MacroInput { types_meta = Some(meta); } + "exact_entrypoint_interface" => { + if exact_entrypoint_interface.is_some() { + panic!("Only one `dump` can be defined") + } + let lit: LitBool = input.parse()?; + exact_entrypoint_interface = Some(lit.value); + } "dump" => { if dump.is_some() { panic!("Only one `dump` can be defined") @@ -538,6 +563,7 @@ impl Parse for MacroInput { dump, macro_defines, types_meta: types_meta.unwrap_or_else(|| TypesMeta::default()), + exact_entrypoint_interface: exact_entrypoint_interface.unwrap_or(false), }) } } @@ -575,6 +601,7 @@ pub fn shader(input: proc_macro::TokenStream) -> proc_macro::TokenStream { unsafe { from_raw_parts(bytes.as_slice().as_ptr() as *const u32, bytes.len() / 4) }, input.types_meta, empty(), + input.exact_entrypoint_interface, input.dump, ) .unwrap() @@ -631,6 +658,7 @@ pub fn shader(input: proc_macro::TokenStream) -> proc_macro::TokenStream { content.as_binary(), input.types_meta, input_paths, + input.exact_entrypoint_interface, input.dump, ) .unwrap()