mewgpu 3.7.1-2

Maybe Easier Wgpu (mew), a thin abstraction over wgpu's chaos
Documentation
//! Wrapper over a
//! [`wgpu::BindGroup`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroup.html).
//! All its buffers are publicly accessible.
//!
//! See [`bind_group`] for details.


use std::{
    marker::PhantomData,
    ops::Deref,
};
use crate::wgpu;


/// Define a bind group, with internal buffer types (and their field names), and
/// their shader visibility (see
/// [`wgpu::ShaderStages`](https://docs.rs/wgpu/latest/wgpu/struct.ShaderStages.html)).
/// All members are taken ownership of in the struct - good to note that they
/// are reference-counted (`Arc`'d) by _wgpu_ internally.
///
/// You need to number each field, tuples are used and counting is hard in
/// macros.
///
/// ```
/// bind_group! { StuffBindGroup [
///     0 matrix_buffer @ VERTEX | COMPUTE => MatrixBuffer,
///     1 texture @ FRAGMENT => SomethingElseTexture,
///     2 another_matrix_buffer @ VERTEX_FRAGMENT => MatrixBuffer,
/// ] }
///
/// // TODO: Create buffers (see buffer docs)
/// let bind_group: StuffBindGroup = render_context.new_bind_group((matrix_buffer, ..));
///
/// queue.write_buffer(&bind_group.something_else_buffer, 0, &[1, 2, 3, ..]);
/// ```
#[macro_export]
macro_rules! bind_group {
    { $struct:ident [
        $( $num:tt $name:ident @ $( $shaderstage:ident )|+ => $buffer:ty /* $( as $bufferinner:ty )? */ ),* $(,)?
    ] } => {
        #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
        pub struct $struct {
            bind_group: $crate::wgpu::BindGroup,
            //$( pub $name : $crate::bind_group! { @bufferout $buffer $( as $bufferinner )? } , )*
            $( pub $name : $buffer , )*
        }

        impl ::std::ops::Deref for $struct {
            type Target = $crate::wgpu::BindGroup;
            fn deref(&self) -> &Self::Target {
                &self.bind_group
            }
        }

        impl $crate::bindgroup::MewBindGroup for $struct {
            //type BufferSet = ( $( $crate::bind_group! { @bufferout $buffer $( as $bufferinner)? } , )* );
            type BufferSet = ( $( $buffer , )* );
            type BufferArray<T> = [T; $crate::len! { $( $num )* }];

            fn new(bind_group: $crate::wgpu::BindGroup, buffers: Self::BufferSet) -> Self {
                Self {
                    bind_group,
                    $( $name : buffers.$num , )*
                }
            }

            fn layout_entries() -> &'static Self::BufferArray<$crate::wgpu::BindGroupLayoutEntry> {
                use ::std::sync::LazyLock;
                #[allow(unused_imports)]
                use $crate::{
                    buffer::{ MewBuffer, MewBufferBinding, },
                    sampler::MewSampler,
                    texture::MewTexture,
                };

                static ARRAY: LazyLock<<$struct as $crate::bindgroup::MewBindGroup>::BufferArray<$crate::wgpu::BindGroupLayoutEntry>> = LazyLock::new(|| [ $(
                    $crate::wgpu::BindGroupLayoutEntry {
                        binding: $num,
                        visibility: $( $crate::wgpu::ShaderStages::$shaderstage )|+,
                        //ty: <$crate::bind_group! { @bufferin $buffer $( as $bufferinner )? }>::binding_type(),
                        ty: <$buffer>::binding_type(),
                        count: None,
                    },
                )* ]);

                &*ARRAY
            }

            fn layout_desc() -> $crate::wgpu::BindGroupLayoutDescriptor<'static> {
                $crate::wgpu::BindGroupLayoutDescriptor {
                    label: Some(concat!(stringify!($struct), " Layout Descriptor")),
                    entries: Self::layout_entries(),
                }
            }

            /*
            fn layout_desc_with(entries: &Self::BufferArray<$crate::wgpu::BindGroupLayoutEntry>) -> $crate::wgpu::BindGroupLayoutDescriptor<'_> {
                $crate::wgpu::BindGroupLayoutDescriptor {
                    label: Some(concat!(stringify!($struct), " Layout Descriptor")),
                    entries,
                }
            }
            */

            fn bind_group_entries(buffers: &Self::BufferSet) -> Self::BufferArray<$crate::wgpu::BindGroupEntry<'_>> {
                #[allow(unused_imports)]
                use $crate::{
                    buffer::{ MewBuffer, MewBufferBinding, },
                    sampler::MewSampler,
                    texture::MewTexture,
                };

                [ $(
                    $crate::wgpu::BindGroupEntry {
                        binding: $num,
                        resource: buffers.$num.as_binding(),
                    },
                )* ]
            }

            fn bind_group_desc<'a>(layout: &'a $crate::bindgroup::MewBindGroupLayout<Self>, entries: &'a Self::BufferArray<$crate::wgpu::BindGroupEntry>) -> $crate::wgpu::BindGroupDescriptor<'a> {
                $crate::wgpu::BindGroupDescriptor {
                    label: Some(stringify!($struct)),
                    layout,
                    entries,
                }
            }
        }
    };
}
pub use bind_group;


/// Trait for internal use to work with bind groups - getting their layouts and
/// descriptors and whatnot.
///
/// The number of internal buffers must be defined in the generic parameter,
/// because associated `const`s are "uNsTAbLe", apparently.
pub trait MewBindGroup {
    /// A tuple of all the bind group's internal buffers.
    type BufferSet;
    /// A generic array the length of the number of buffers (literally `[T; N]`).
    type BufferArray<T>;
    /// Build this bind group type from a
    /// [`wgpu::BindGroup`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroup.html)
    /// and all its internal buffers in a tuple.
    ///
    /// Technically the buffers don't need to be stored with the bind group they're
    /// used in - or at all, it should even be safe to drop them as they'll be kept
    /// around on the GPU side - but as an abstraction, they exist as members of the
    /// bind group.
    fn new(bind_group: wgpu::BindGroup, buffers: Self::BufferSet) -> Self;
    /// Get an array of
    /// [`wgpu::BindGroupLayoutEntry`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroupLayoutEntry.html)s
    /// for all internal buffers.
    fn layout_entries() -> &'static Self::BufferArray<wgpu::BindGroupLayoutEntry>;
    /// Get a
    /// [`wgpu::BindGroupLayoutDescriptor`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroupLayoutDescriptor.html)
    /// to build this type of bind group.
    fn layout_desc() -> wgpu::BindGroupLayoutDescriptor<'static>;
    /*
    /// Get a layout descriptor using dynamic layout entries (not recommended, I
    /// forgor why I put this in).
    fn layout_desc_with<'a>(entries: &'a Self::BufferArray<wgpu::BindGroupLayoutEntry>) -> wgpu::BindGroupLayoutDescriptor<'a>;
    */
    /// Get an array of
    /// [`wgpu::BindGroupEntry`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroupEntry.html)s,
    /// for use with [`Self::bind_group_desc`].
    ///
    /// Necessary to put this in a separate function to keep the borrow checker
    /// happy - _wgpu_ needs a reference to owned entries, which we can't return
    /// in a struct later.
    fn bind_group_entries(buffers: &Self::BufferSet) -> Self::BufferArray<wgpu::BindGroupEntry<'_>>;
    /// Get a
    /// [`wgpu::BindGroupDescriptor`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroupDescriptor.html)
    /// to build this bind group, using its layout and a reference to its
    /// [`wgpu::BindGroupEntry`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroupEntry.html)s
    /// from [`Self::bind_group_entries`].
    fn bind_group_desc<'a>(layout: &'a MewBindGroupLayout<Self>, entries: &'a Self::BufferArray<wgpu::BindGroupEntry<'_>>) -> wgpu::BindGroupDescriptor<'a>;

    //fn dyn_descriptor() -> Box<dyn MewBindGroupDescriptor>;
}

/*
pub trait MewBindGroupDescriptor {
    fn type_id(&self) -> TypeId;
    fn layout_desc(&self) -> wgpu::BindGroupLayoutDescriptor<'static>;
}
*/


/// Wrapper for the layout of some bind group, so that the compiler will scream
/// at you if you mix up layouts.
pub struct MewBindGroupLayout<BIND: ?Sized> {
    layout: wgpu::BindGroupLayout,
    _marker: PhantomData<BIND>,
}
impl<BIND: ?Sized> Deref for MewBindGroupLayout<BIND> {
    type Target = wgpu::BindGroupLayout;
    fn deref(&self) -> &Self::Target {
        &self.layout
    }
}
impl<BIND> MewBindGroupLayout<BIND> {
    /// Wrap a
    /// [`wgpu::BindGroupLayout`](https://docs.rs/wgpu/latest/wgpu/struct.BindGroupLayout.html).
    pub fn new(layout: wgpu::BindGroupLayout) -> Self {
        Self {
            layout,
            _marker: PhantomData,
        }
    }
}