Path: blob/main/crates/bevy_material/src/bind_group_layout_entries.rs
9357 views
use core::num::NonZero;1use variadics_please::all_tuples_with_size;2use wgpu_types::{BindGroupLayoutEntry, BindingType, ShaderStages};34/// Helper for constructing bind group layouts.5///6/// Allows constructing the layout's entries as:7/// ```ignore (render_device cannot be easily accessed)8/// let layout = render_device.create_bind_group_layout(9/// "my_bind_group_layout",10/// &BindGroupLayoutEntries::with_indices(11/// // The layout entries will only be visible in the fragment stage12/// ShaderStages::FRAGMENT,13/// (14/// // Screen texture15/// (2, texture_2d(TextureSampleType::Float { filterable: true })),16/// // Sampler17/// (3, sampler(SamplerBindingType::Filtering)),18/// ),19/// ),20/// );21/// ```22///23/// instead of24///25/// ```ignore (render_device cannot be easily accessed)26/// let layout = render_device.create_bind_group_layout(27/// "my_bind_group_layout",28/// &[29/// // Screen texture30/// BindGroupLayoutEntry {31/// binding: 2,32/// visibility: ShaderStages::FRAGMENT,33/// ty: BindingType::Texture {34/// sample_type: TextureSampleType::Float { filterable: true },35/// view_dimension: TextureViewDimension::D2,36/// multisampled: false,37/// },38/// count: None,39/// },40/// // Sampler41/// BindGroupLayoutEntry {42/// binding: 3,43/// visibility: ShaderStages::FRAGMENT,44/// ty: BindingType::Sampler(SamplerBindingType::Filtering),45/// count: None,46/// },47/// ],48/// );49/// ```50///51/// or52///53/// ```ignore (render_device cannot be easily accessed)54/// render_device.create_bind_group_layout(55/// "my_bind_group_layout",56/// &BindGroupLayoutEntries::sequential(57/// ShaderStages::FRAGMENT,58/// (59/// // Screen texture60/// texture_2d(TextureSampleType::Float { filterable: true }),61/// // Sampler62/// sampler(SamplerBindingType::Filtering),63/// ),64/// ),65/// );66/// ```67///68/// instead of69///70/// ```ignore (render_device cannot be easily accessed)71/// let layout = render_device.create_bind_group_layout(72/// "my_bind_group_layout",73/// &[74/// // Screen texture75/// BindGroupLayoutEntry {76/// binding: 0,77/// visibility: ShaderStages::FRAGMENT,78/// ty: BindingType::Texture {79/// sample_type: TextureSampleType::Float { filterable: true },80/// view_dimension: TextureViewDimension::D2,81/// multisampled: false,82/// },83/// count: None,84/// },85/// // Sampler86/// BindGroupLayoutEntry {87/// binding: 1,88/// visibility: ShaderStages::FRAGMENT,89/// ty: BindingType::Sampler(SamplerBindingType::Filtering),90/// count: None,91/// },92/// ],93/// );94/// ```95///96/// or97///98/// ```ignore (render_device cannot be easily accessed)99/// render_device.create_bind_group_layout(100/// "my_bind_group_layout",101/// &BindGroupLayoutEntries::single(102/// ShaderStages::FRAGMENT,103/// texture_2d(TextureSampleType::Float { filterable: true }),104/// ),105/// );106/// ```107///108/// instead of109///110/// ```ignore (render_device cannot be easily accessed)111/// let layout = render_device.create_bind_group_layout(112/// "my_bind_group_layout",113/// &[114/// BindGroupLayoutEntry {115/// binding: 0,116/// visibility: ShaderStages::FRAGMENT,117/// ty: BindingType::Texture {118/// sample_type: TextureSampleType::Float { filterable: true },119/// view_dimension: TextureViewDimension::D2,120/// multisampled: false,121/// },122/// count: None,123/// },124/// ],125/// );126/// ```127128#[derive(Clone, Copy)]129pub struct BindGroupLayoutEntryBuilder {130ty: BindingType,131visibility: Option<ShaderStages>,132count: Option<NonZero<u32>>,133}134135impl BindGroupLayoutEntryBuilder {136pub fn visibility(mut self, visibility: ShaderStages) -> Self {137self.visibility = Some(visibility);138self139}140141pub fn count(mut self, count: NonZero<u32>) -> Self {142self.count = Some(count);143self144}145146pub fn build(&self, binding: u32, default_visibility: ShaderStages) -> BindGroupLayoutEntry {147BindGroupLayoutEntry {148binding,149ty: self.ty,150visibility: self.visibility.unwrap_or(default_visibility),151count: self.count,152}153}154}155156pub struct BindGroupLayoutEntries<const N: usize> {157entries: [BindGroupLayoutEntry; N],158}159160impl<const N: usize> BindGroupLayoutEntries<N> {161#[inline]162pub fn sequential(163default_visibility: ShaderStages,164entries_ext: impl IntoBindGroupLayoutEntryBuilderArray<N>,165) -> Self {166let mut i = 0;167Self {168entries: entries_ext.into_array().map(|entry| {169let binding = i;170i += 1;171entry.build(binding, default_visibility)172}),173}174}175176#[inline]177pub fn with_indices(178default_visibility: ShaderStages,179indexed_entries: impl IntoIndexedBindGroupLayoutEntryBuilderArray<N>,180) -> Self {181Self {182entries: indexed_entries183.into_array()184.map(|(binding, entry)| entry.build(binding, default_visibility)),185}186}187}188189impl BindGroupLayoutEntries<1> {190pub fn single(191visibility: ShaderStages,192resource: impl IntoBindGroupLayoutEntryBuilder,193) -> [BindGroupLayoutEntry; 1] {194[resource195.into_bind_group_layout_entry_builder()196.build(0, visibility)]197}198}199200impl<const N: usize> core::ops::Deref for BindGroupLayoutEntries<N> {201type Target = [BindGroupLayoutEntry];202fn deref(&self) -> &[BindGroupLayoutEntry] {203&self.entries204}205}206207pub trait IntoBindGroupLayoutEntryBuilder {208fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder;209}210211impl IntoBindGroupLayoutEntryBuilder for BindingType {212fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder {213BindGroupLayoutEntryBuilder {214ty: self,215visibility: None,216count: None,217}218}219}220221impl IntoBindGroupLayoutEntryBuilder for BindGroupLayoutEntry {222fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder {223if self.binding != u32::MAX {224tracing::warn!("The BindGroupLayoutEntries api ignores the binding index when converting a raw wgpu::BindGroupLayoutEntry. You can ignore this warning by setting it to u32::MAX.");225}226BindGroupLayoutEntryBuilder {227ty: self.ty,228visibility: Some(self.visibility),229count: self.count,230}231}232}233234impl IntoBindGroupLayoutEntryBuilder for BindGroupLayoutEntryBuilder {235fn into_bind_group_layout_entry_builder(self) -> BindGroupLayoutEntryBuilder {236self237}238}239240pub trait IntoBindGroupLayoutEntryBuilderArray<const N: usize> {241fn into_array(self) -> [BindGroupLayoutEntryBuilder; N];242}243macro_rules! impl_to_binding_type_slice {244($N: expr, $(#[$meta:meta])* $(($T: ident, $I: ident)),*) => {245$(#[$meta])*246impl<$($T: IntoBindGroupLayoutEntryBuilder),*> IntoBindGroupLayoutEntryBuilderArray<$N> for ($($T,)*) {247#[inline]248fn into_array(self) -> [BindGroupLayoutEntryBuilder; $N] {249let ($($I,)*) = self;250[$($I.into_bind_group_layout_entry_builder(), )*]251}252}253}254}255all_tuples_with_size!(256#[doc(fake_variadic)]257impl_to_binding_type_slice,2581,25932,260T,261s262);263264pub trait IntoIndexedBindGroupLayoutEntryBuilderArray<const N: usize> {265fn into_array(self) -> [(u32, BindGroupLayoutEntryBuilder); N];266}267macro_rules! impl_to_indexed_binding_type_slice {268($N: expr, $(($T: ident, $S: ident, $I: ident)),*) => {269impl<$($T: IntoBindGroupLayoutEntryBuilder),*> IntoIndexedBindGroupLayoutEntryBuilderArray<$N> for ($((u32, $T),)*) {270#[inline]271fn into_array(self) -> [(u32, BindGroupLayoutEntryBuilder); $N] {272let ($(($S, $I),)*) = self;273[$(($S, $I.into_bind_group_layout_entry_builder())), *]274}275}276}277}278all_tuples_with_size!(impl_to_indexed_binding_type_slice, 1, 32, T, n, s);279280impl<const N: usize> IntoBindGroupLayoutEntryBuilderArray<N> for [BindGroupLayoutEntry; N] {281fn into_array(self) -> [BindGroupLayoutEntryBuilder; N] {282self.map(IntoBindGroupLayoutEntryBuilder::into_bind_group_layout_entry_builder)283}284}285286pub struct DynamicBindGroupLayoutEntries {287default_visibility: ShaderStages,288entries: Vec<BindGroupLayoutEntry>,289}290291impl DynamicBindGroupLayoutEntries {292pub fn sequential<const N: usize>(293default_visibility: ShaderStages,294entries: impl IntoBindGroupLayoutEntryBuilderArray<N>,295) -> Self {296Self {297default_visibility,298entries: entries299.into_array()300.into_iter()301.enumerate()302.map(|(ix, resource)| resource.build(ix as u32, default_visibility))303.collect(),304}305}306307pub fn extend_sequential<const N: usize>(308mut self,309entries: impl IntoBindGroupLayoutEntryBuilderArray<N>,310) -> Self {311let start = self.entries.last().unwrap().binding + 1;312self.entries.extend(313entries314.into_array()315.into_iter()316.enumerate()317.map(|(ix, resource)| resource.build(start + ix as u32, self.default_visibility)),318);319self320}321322pub fn new_with_indices<const N: usize>(323default_visibility: ShaderStages,324entries: impl IntoIndexedBindGroupLayoutEntryBuilderArray<N>,325) -> Self {326Self {327default_visibility,328entries: entries329.into_array()330.into_iter()331.map(|(binding, resource)| resource.build(binding, default_visibility))332.collect(),333}334}335336pub fn new(default_visibility: ShaderStages) -> Self {337Self {338default_visibility,339entries: Vec::new(),340}341}342343pub fn extend_with_indices<const N: usize>(344mut self,345entries: impl IntoIndexedBindGroupLayoutEntryBuilderArray<N>,346) -> Self {347self.entries.extend(348entries349.into_array()350.into_iter()351.map(|(binding, resource)| resource.build(binding, self.default_visibility)),352);353self354}355}356357impl core::ops::Deref for DynamicBindGroupLayoutEntries {358type Target = [BindGroupLayoutEntry];359360fn deref(&self) -> &[BindGroupLayoutEntry] {361&self.entries362}363}364365pub mod binding_types {366use core::num::NonZero;367use encase::ShaderType;368use wgpu_types::{369BufferBindingType, SamplerBindingType, TextureSampleType, TextureViewDimension,370};371use wgpu_types::{StorageTextureAccess, TextureFormat};372373use super::*;374375pub fn storage_buffer<T: ShaderType>(has_dynamic_offset: bool) -> BindGroupLayoutEntryBuilder {376storage_buffer_sized(has_dynamic_offset, Some(T::min_size()))377}378379pub fn storage_buffer_sized(380has_dynamic_offset: bool,381min_binding_size: Option<NonZero<u64>>,382) -> BindGroupLayoutEntryBuilder {383BindingType::Buffer {384ty: BufferBindingType::Storage { read_only: false },385has_dynamic_offset,386min_binding_size,387}388.into_bind_group_layout_entry_builder()389}390391pub fn storage_buffer_read_only<T: ShaderType>(392has_dynamic_offset: bool,393) -> BindGroupLayoutEntryBuilder {394storage_buffer_read_only_sized(has_dynamic_offset, Some(T::min_size()))395}396397pub fn storage_buffer_read_only_sized(398has_dynamic_offset: bool,399min_binding_size: Option<NonZero<u64>>,400) -> BindGroupLayoutEntryBuilder {401BindingType::Buffer {402ty: BufferBindingType::Storage { read_only: true },403has_dynamic_offset,404min_binding_size,405}406.into_bind_group_layout_entry_builder()407}408409pub fn uniform_buffer<T: ShaderType>(has_dynamic_offset: bool) -> BindGroupLayoutEntryBuilder {410uniform_buffer_sized(has_dynamic_offset, Some(T::min_size()))411}412413pub fn uniform_buffer_sized(414has_dynamic_offset: bool,415min_binding_size: Option<NonZero<u64>>,416) -> BindGroupLayoutEntryBuilder {417BindingType::Buffer {418ty: BufferBindingType::Uniform,419has_dynamic_offset,420min_binding_size,421}422.into_bind_group_layout_entry_builder()423}424425pub fn texture_1d(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {426BindingType::Texture {427sample_type,428view_dimension: TextureViewDimension::D1,429multisampled: false,430}431.into_bind_group_layout_entry_builder()432}433434pub fn texture_2d(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {435BindingType::Texture {436sample_type,437view_dimension: TextureViewDimension::D2,438multisampled: false,439}440.into_bind_group_layout_entry_builder()441}442443pub fn texture_2d_multisampled(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {444BindingType::Texture {445sample_type,446view_dimension: TextureViewDimension::D2,447multisampled: true,448}449.into_bind_group_layout_entry_builder()450}451452pub fn texture_2d_array(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {453BindingType::Texture {454sample_type,455view_dimension: TextureViewDimension::D2Array,456multisampled: false,457}458.into_bind_group_layout_entry_builder()459}460461pub fn texture_2d_array_multisampled(462sample_type: TextureSampleType,463) -> BindGroupLayoutEntryBuilder {464BindingType::Texture {465sample_type,466view_dimension: TextureViewDimension::D2Array,467multisampled: true,468}469.into_bind_group_layout_entry_builder()470}471472pub fn texture_depth_2d() -> BindGroupLayoutEntryBuilder {473texture_2d(TextureSampleType::Depth).into_bind_group_layout_entry_builder()474}475476pub fn texture_depth_2d_multisampled() -> BindGroupLayoutEntryBuilder {477texture_2d_multisampled(TextureSampleType::Depth).into_bind_group_layout_entry_builder()478}479480pub fn texture_cube(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {481BindingType::Texture {482sample_type,483view_dimension: TextureViewDimension::Cube,484multisampled: false,485}486.into_bind_group_layout_entry_builder()487}488489pub fn texture_cube_multisampled(490sample_type: TextureSampleType,491) -> BindGroupLayoutEntryBuilder {492BindingType::Texture {493sample_type,494view_dimension: TextureViewDimension::Cube,495multisampled: true,496}497.into_bind_group_layout_entry_builder()498}499500pub fn texture_cube_array(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {501BindingType::Texture {502sample_type,503view_dimension: TextureViewDimension::CubeArray,504multisampled: false,505}506.into_bind_group_layout_entry_builder()507}508509pub fn texture_cube_array_multisampled(510sample_type: TextureSampleType,511) -> BindGroupLayoutEntryBuilder {512BindingType::Texture {513sample_type,514view_dimension: TextureViewDimension::CubeArray,515multisampled: true,516}517.into_bind_group_layout_entry_builder()518}519520pub fn texture_3d(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {521BindingType::Texture {522sample_type,523view_dimension: TextureViewDimension::D3,524multisampled: false,525}526.into_bind_group_layout_entry_builder()527}528529pub fn texture_3d_multisampled(sample_type: TextureSampleType) -> BindGroupLayoutEntryBuilder {530BindingType::Texture {531sample_type,532view_dimension: TextureViewDimension::D3,533multisampled: true,534}535.into_bind_group_layout_entry_builder()536}537538pub fn sampler(sampler_binding_type: SamplerBindingType) -> BindGroupLayoutEntryBuilder {539BindingType::Sampler(sampler_binding_type).into_bind_group_layout_entry_builder()540}541542pub fn texture_storage_2d(543format: TextureFormat,544access: StorageTextureAccess,545) -> BindGroupLayoutEntryBuilder {546BindingType::StorageTexture {547access,548format,549view_dimension: TextureViewDimension::D2,550}551.into_bind_group_layout_entry_builder()552}553554pub fn texture_storage_2d_array(555format: TextureFormat,556access: StorageTextureAccess,557) -> BindGroupLayoutEntryBuilder {558BindingType::StorageTexture {559access,560format,561view_dimension: TextureViewDimension::D2Array,562}563.into_bind_group_layout_entry_builder()564}565566pub fn texture_storage_3d(567format: TextureFormat,568access: StorageTextureAccess,569) -> BindGroupLayoutEntryBuilder {570BindingType::StorageTexture {571access,572format,573view_dimension: TextureViewDimension::D3,574}575.into_bind_group_layout_entry_builder()576}577578pub fn acceleration_structure() -> BindGroupLayoutEntryBuilder {579BindingType::AccelerationStructure {580vertex_return: false,581}582.into_bind_group_layout_entry_builder()583}584585pub fn acceleration_structure_vertex_return() -> BindGroupLayoutEntryBuilder {586BindingType::AccelerationStructure {587vertex_return: true,588}589.into_bind_group_layout_entry_builder()590}591}592593594