Skip to main content

mew/
texture.rs

1pub mod sample_type {
2    //! Texture binding sample types. Enums exploded into `const`s because
3    //! `Float` has a useless `filterable` property which is annoying to write out.
4
5    /// <code>[wgpu::TextureSampleType::Float](https://docs.rs/wgpu/latest/wgpu/enum.TextureSampleType.html#variant.Float) { filterable: true, ‌}</code>
6    pub const FLOAT: wgpu::TextureSampleType = wgpu::TextureSampleType::Float { filterable: true, };
7    /// <code>[wgpu::TextureSampleType::Float](https://docs.rs/wgpu/latest/wgpu/enum.TextureSampleType.html#variant.Float) { filterable: false, ‌}  // wtf why</code>
8    pub const FLOAT_FILTERABLE_FALSE_IF_YOU_REALLY_CARE_LIKE_WHATS_THE_POINT_YOU_CAN_SET_FILTERABLE_TRUE_AND_STILL_USE_IT_WITH_A_NON_FILTERING_SAMPLER: wgpu::TextureSampleType = wgpu::TextureSampleType::Float { filterable: false, };  // wtf why
9    /// [`wgpu::TextureSampleType::Depth`](https://docs.rs/wgpu/latest/wgpu/enum.TextureSampleType.html#variant.Depth)
10    pub const DEPTH: wgpu::TextureSampleType = wgpu::TextureSampleType::Depth;
11    /// [`wgpu::TextureSampleType::Sint`](https://docs.rs/wgpu/latest/wgpu/enum.TextureSampleType.html#variant.Sint)
12    pub const SINT: wgpu::TextureSampleType = wgpu::TextureSampleType::Sint;
13    /// [`wgpu::TextureSampleType::Uint`](https://docs.rs/wgpu/latest/wgpu/enum.TextureSampleType.html#variant.Uint)
14    pub const UINT: wgpu::TextureSampleType = wgpu::TextureSampleType::Uint;
15}
16
17/// Define a type of texture - not its size or format, but a set of properties.
18///
19/// More specifically, its
20/// [`wgpu::TextureUsages`](https://docs.rs/wgpu/latest/wgpu/struct.TextureUsages.html),
21/// [`wgpu::TextureViewDimension`](https://docs.rs/wgpu/latest/wgpu/enum.TextureViewDimension.html),
22/// & the binding's
23/// [`wgpu::TextureSampleType`](https://docs.rs/wgpu/latest/wgpu/enum.TextureSampleType.html)
24/// as simplified under [`sample_type`].  
25/// The texture's size & format are defined on creation of the texture dynamically.
26///
27/// This struct also comes with a view of all layers, so you can bind to it
28/// directly.
29///
30/// ```
31/// texture! { Texture {
32///     usage: COPY_DST | TEXTURE_BINDING,
33///     dimension: D2,
34///     sample_type: FLOAT,
35/// } }
36///
37/// let texture: Texture = context.new_texture((64, 64, 1), wgpu::TextureFormat::Rgba8Unorm);
38/// ```
39///
40/// The texture is made with 1 mip level and sample count, this will probably
41/// eventually be customizable but I haven't made anything complex enough yet to
42/// figure out how that works.
43#[macro_export]
44macro_rules! texture {
45    { $struct:ident {
46        usage: $( $usage:ident )|+ ,
47        dimension: $dimension:ident,
48        sample_type: $sample:ident,
49    } } => {
50        #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
51        pub struct $struct {
52            pub texture: $crate::wgpu::Texture,
53            pub view: $crate::wgpu::TextureView,
54        }
55
56        impl ::std::ops::Deref for $struct {
57            type Target = $crate::wgpu::Texture;
58            fn deref(&self) -> &Self::Target {
59                &self.texture
60            }
61        }
62
63        impl $crate::texture::MewTexture for $struct {
64            fn new(texture: $crate::wgpu::Texture) -> Self {
65                let view = texture.create_view(&$crate::wgpu::TextureViewDescriptor {
66                    label: Some(concat!(stringify!($struct), " Texture View")),
67                    format: Some(texture.format()),
68                    dimension: Some($crate::wgpu::TextureViewDimension::$dimension),
69                    usage: Some($( $crate::wgpu::TextureUsages::$usage )|+),
70                    aspect: $crate::wgpu::TextureAspect::All,
71                    base_mip_level: 0,
72                    mip_level_count: None,
73                    base_array_layer: 0,
74                    array_layer_count: None,
75                });
76                Self {
77                    texture,
78                    view,
79                }
80            }
81
82            fn binding_type() -> $crate::wgpu::BindingType {
83                $crate::wgpu::BindingType::Texture {
84                    sample_type: $crate::texture::sample_type::$sample,
85                    view_dimension: $crate::wgpu::TextureViewDimension::$dimension,
86                    multisampled: false,
87                }
88            }
89
90            fn buffer_desc(inner_size: (u32, u32, u32), format: $crate::wgpu::TextureFormat) -> $crate::wgpu::TextureDescriptor<'static> {
91                $crate::wgpu::TextureDescriptor {
92                    label: Some(concat!(stringify!($struct), " Texture")),
93                    size: $crate::wgpu::Extent3d {
94                        width: inner_size.0,
95                        height: inner_size.1,
96                        depth_or_array_layers: inner_size.2,
97                    },
98                    mip_level_count: 1,
99                    sample_count: 1,
100                    dimension: $crate::wgpu::TextureViewDimension::$dimension.compatible_texture_dimension(),
101                    format,
102                    usage: $( $crate::wgpu::TextureUsages::$usage )|+,
103                    view_formats: &[],
104                }
105            }
106
107            fn as_binding<'a>(&'a self) -> $crate::wgpu::BindingResource<'a> {
108                $crate::wgpu::BindingResource::TextureView(&self.view)
109            }
110
111            fn as_colour_attachment<'a>(&'a self, clear: Option<$crate::wgpu::Color>, depth_slice: Option<u32>) -> $crate::wgpu::RenderPassColorAttachment<'a> {
112                $crate::wgpu::RenderPassColorAttachment {
113                    view: &self.view,
114                    depth_slice,
115                    resolve_target: None,  // ???
116                    ops: $crate::wgpu::Operations {
117                        load: clear.map(|colour| $crate::wgpu::LoadOp::Clear(colour)).unwrap_or($crate::wgpu::LoadOp::Load),
118                        store: $crate::wgpu::StoreOp::Store,
119                    },
120                }
121            }
122
123            fn as_depth_attachment<'a>(&'a self) -> $crate::wgpu::RenderPassDepthStencilAttachment<'a> {
124                $crate::wgpu::RenderPassDepthStencilAttachment {
125                    view: &self.view,
126                    depth_ops: Some($crate::wgpu::Operations {
127                        load: $crate::wgpu::LoadOp::Clear(1.0),
128                        store: $crate::wgpu::StoreOp::Store,
129                    }),
130                    stencil_ops: None,
131                }
132            }
133
134            fn memory_estimate(&self) -> u64 {
135                self.texture.format().theoretical_memory_footprint($crate::wgpu::Extent3d {
136                    width: self.texture.width(),
137                    height: self.texture.height(),
138                    depth_or_array_layers: self.texture.depth_or_array_layers(),
139                })
140            }
141
142            fn texel_layout(&self) -> $crate::wgpu::TexelCopyBufferLayout {
143                $crate::wgpu::TexelCopyBufferLayout {
144                    offset: 0,
145                    bytes_per_row: Some(self.texture.format().components() as u32 * self.texture.width()),
146                    rows_per_image: Some(self.texture.height())
147                }
148            }
149        }
150    }
151}
152pub use texture;
153
154
155/// Trait for internal use to work with texture bindings.
156pub trait MewTexture {
157    /// Build this texture type from a
158    /// [`wgpu::Texture`](https://docs.rs/wgpu/latest/wgpu/struct.Texture.html).
159    fn new(buffer: wgpu::Texture) -> Self;
160    /// Get a [`wgpu::BindingType`](https://docs.rs/wgpu/latest/wgpu/enum.BindingType.html)
161    /// to use for this type of texture.
162    fn binding_type() -> wgpu::BindingType;
163    /// Get a [`wgpu::TextureDescriptor`](https://docs.rs/wgpu/latest/wgpu/type.TextureDescriptor.html)
164    /// to build this type of texture with the given size &
165    /// [`wgpu::TextureFormat`](https://docs.rs/wgpu/latest/wgpu/enum.TextureFormat.html).
166    fn buffer_desc(inner_size: (u32, u32, u32), format: wgpu::TextureFormat) -> wgpu::TextureDescriptor<'static>;
167    /// Get this texture's [`wgpu::BindingResource`](https://docs.rs/wgpu/latest/wgpu/enum.BindingResource.html)
168    /// to bind it in a bind group.
169    fn as_binding<'a>(&'a self) -> wgpu::BindingResource<'a>;
170    /// Get a [`wgpu::RenderPassColorAttachment`](https://docs.rs/wgpu/latest/wgpu/struct.RenderPassColorAttachment.html)
171    /// to attach this texture to a render pass, to draw to it using a specified clear
172    /// colour on a 2D depth slice (set to `None` if it's a regular 2D texture).
173    fn as_colour_attachment<'a>(&'a self, clear: Option<wgpu::Color>, depth_slice: Option<u32>) -> wgpu::RenderPassColorAttachment<'a>;
174    /// Get a [`wgpu::RenderPassDepthStencilAttachment`](https://docs.rs/wgpu/latest/wgpu/struct.RenderPassDepthStencilAttachment.html)
175    /// to attach this texture to a render pass, to use as a depth stencil.
176    fn as_depth_attachment<'a>(&'a self) -> wgpu::RenderPassDepthStencilAttachment<'a>;
177    /// Get the estimated size of this texture. Default implementation just uses
178    /// [wgpu::TextureFormat::theoretical_memory_footprint](https://docs.rs/wgpu/latest/wgpu/enum.TextureFormat.html#method.theoretical_memory_footprint).
179    fn memory_estimate(&self) -> u64;
180    /// Get the [`wgpu::TexelCopyBufferLayout`](https://docs.rs/wgpu/latest/wgpu/struct.TexelCopyBufferLayout.html)
181    /// for this texture. Required by the queue to write any data to the texture.
182    fn texel_layout(&self) -> wgpu::TexelCopyBufferLayout;
183}