Rip base files from another project
This commit is contained in:
		
							parent
							
								
									a708985c85
								
							
						
					
					
						commit
						8f56358415
					
				
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -1,8 +1,12 @@ | ||||||
| [package] | [package] | ||||||
| name = "crawl" | name    = "crawl" | ||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
| edition = "2021" | edition = "2021" | ||||||
| 
 | 
 | ||||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||||
| 
 | 
 | ||||||
| [dependencies] | [dependencies] | ||||||
|  | bytemuck = "1.15.0" | ||||||
|  | log = "0.4.21" | ||||||
|  | wgpu     = "0.19.4" | ||||||
|  | winit    = "0.29.15" | ||||||
|  |  | ||||||
|  | @ -0,0 +1,137 @@ | ||||||
|  | use std::num::NonZeroU32; | ||||||
|  | 
 | ||||||
|  | use anyhow::{Context as _, Result}; | ||||||
|  | 
 | ||||||
|  | use super::Context; | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Default)] | ||||||
|  | pub struct BindGroupLayoutBuilder<'a> { | ||||||
|  |     next_binding: u32, | ||||||
|  |     entries: Vec<wgpu::BindGroupLayoutEntry>, | ||||||
|  |     label: Option<&'a str>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> BindGroupLayoutBuilder<'a> { | ||||||
|  |     pub fn new() -> Self { | ||||||
|  |         Self::default() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_label(mut self, label: &'a str) -> Self { | ||||||
|  |         self.label = Some(label); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_entry( | ||||||
|  |         mut self, | ||||||
|  |         visibility: wgpu::ShaderStages, | ||||||
|  |         ty: wgpu::BindingType, | ||||||
|  |         count: Option<NonZeroU32>, | ||||||
|  |     ) -> Self { | ||||||
|  |         self.entries.push(wgpu::BindGroupLayoutEntry { | ||||||
|  |             binding: self.next_binding, | ||||||
|  |             visibility, | ||||||
|  |             ty, | ||||||
|  |             count, | ||||||
|  |         }); | ||||||
|  |         self.next_binding += 1; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_uniform_entry(self, visibility: wgpu::ShaderStages) -> Self { | ||||||
|  |         self.with_entry( | ||||||
|  |             visibility, | ||||||
|  |             wgpu::BindingType::Buffer { | ||||||
|  |                 ty: wgpu::BufferBindingType::Uniform, | ||||||
|  |                 has_dynamic_offset: false, | ||||||
|  |                 min_binding_size: None, | ||||||
|  |             }, | ||||||
|  |             None, | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_rw_storage_entry(self, visibility: wgpu::ShaderStages) -> Self { | ||||||
|  |         self.with_entry( | ||||||
|  |             visibility, | ||||||
|  |             wgpu::BindingType::Buffer { | ||||||
|  |                 ty: wgpu::BufferBindingType::Storage { read_only: false }, | ||||||
|  |                 has_dynamic_offset: false, | ||||||
|  |                 min_binding_size: None, | ||||||
|  |             }, | ||||||
|  |             None, | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_ro_storage_entry(self, visibility: wgpu::ShaderStages) -> Self { | ||||||
|  |         self.with_entry( | ||||||
|  |             visibility, | ||||||
|  |             wgpu::BindingType::Buffer { | ||||||
|  |                 ty: wgpu::BufferBindingType::Storage { read_only: true }, | ||||||
|  |                 has_dynamic_offset: false, | ||||||
|  |                 min_binding_size: None, | ||||||
|  |             }, | ||||||
|  |             None, | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn build(self, context: &Context) -> wgpu::BindGroupLayout { | ||||||
|  |         context | ||||||
|  |             .device | ||||||
|  |             .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { | ||||||
|  |                 label: self.label, | ||||||
|  |                 entries: &self.entries, | ||||||
|  |             }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug, Default)] | ||||||
|  | pub struct BindGroupBuilder<'a> { | ||||||
|  |     next_binding: u32, | ||||||
|  |     label: Option<&'a str>, | ||||||
|  |     entries: Vec<wgpu::BindGroupEntry<'a>>, | ||||||
|  |     layout: Option<&'a wgpu::BindGroupLayout>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> BindGroupBuilder<'a> { | ||||||
|  |     pub fn new() -> Self { | ||||||
|  |         Self::default() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_label(mut self, label: &'a str) -> Self { | ||||||
|  |         self.label = Some(label); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_entry(mut self, resource: wgpu::BindingResource<'a>) -> Self { | ||||||
|  |         self.entries.push(wgpu::BindGroupEntry { | ||||||
|  |             binding: self.next_binding, | ||||||
|  |             resource, | ||||||
|  |         }); | ||||||
|  |         self.next_binding += 1; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_layout(mut self, layout: &'a wgpu::BindGroupLayout) -> Self { | ||||||
|  |         self.layout = Some(layout); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn build(self, context: &Context) -> Result<wgpu::BindGroup> { | ||||||
|  |         Ok(context | ||||||
|  |             .device | ||||||
|  |             .create_bind_group(&wgpu::BindGroupDescriptor { | ||||||
|  |                 label: self.label, | ||||||
|  |                 layout: self.layout.context("BindGroupBuilder has no layout.")?, | ||||||
|  |                 entries: self.entries.as_slice(), | ||||||
|  |             })) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,99 @@ | ||||||
|  | use std::ops::RangeBounds; | ||||||
|  | 
 | ||||||
|  | use bytemuck::NoUninit; | ||||||
|  | use wgpu::util::DeviceExt; | ||||||
|  | 
 | ||||||
|  | use super::Context; | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct BulkBufferBuilder<'a> { | ||||||
|  |     order: Vec<(bool, usize)>, | ||||||
|  |     init_descriptors: Vec<wgpu::util::BufferInitDescriptor<'a>>, | ||||||
|  |     descriptors: Vec<wgpu::BufferDescriptor<'a>>, | ||||||
|  |     current_usage: wgpu::BufferUsages, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'a> BulkBufferBuilder<'a> { | ||||||
|  |     pub fn new() -> Self { | ||||||
|  |         Self { | ||||||
|  |             order: vec![], | ||||||
|  |             init_descriptors: vec![], | ||||||
|  |             descriptors: vec![], | ||||||
|  |             current_usage: wgpu::BufferUsages::UNIFORM, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn set_usage(mut self, usage: wgpu::BufferUsages) -> Self { | ||||||
|  |         self.current_usage = usage; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn with_buffer(mut self, label: &'a str, size: u64, mapped: bool) -> Self { | ||||||
|  |         let descriptor = wgpu::BufferDescriptor { | ||||||
|  |             label: Some(label), | ||||||
|  |             size, | ||||||
|  |             usage: self.current_usage, | ||||||
|  |             mapped_at_creation: mapped, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         self.order.push((false, self.descriptors.len())); | ||||||
|  |         self.descriptors.push(descriptor); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn with_init_buffer(mut self, label: &'a str, contents: &'a [u8]) -> Self { | ||||||
|  |         let descriptor = wgpu::util::BufferInitDescriptor { | ||||||
|  |             label: Some(label), | ||||||
|  |             contents, | ||||||
|  |             usage: self.current_usage, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         self.order.push((true, self.init_descriptors.len())); | ||||||
|  |         self.init_descriptors.push(descriptor); | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn with_init_buffer_bm<A: NoUninit>(self, label: &'a str, contents: &'a [A]) -> Self { | ||||||
|  |         self.with_init_buffer(label, bytemuck::cast_slice(contents)) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn build(self, context: &Context) -> Vec<wgpu::Buffer> { | ||||||
|  |         let device = &context.device; | ||||||
|  |         let mut buffers = vec![]; | ||||||
|  |         for (init, index) in self.order { | ||||||
|  |             let buffer = if init { | ||||||
|  |                 device.create_buffer_init(&(self.init_descriptors[index])) | ||||||
|  |             } else { | ||||||
|  |                 device.create_buffer(&(self.descriptors[index])) | ||||||
|  |             }; | ||||||
|  | 
 | ||||||
|  |             buffers.push(buffer); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         buffers | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub trait BufferExt { | ||||||
|  |     fn get_mapped_range<S: RangeBounds<wgpu::BufferAddress>, T: bytemuck::Pod>( | ||||||
|  |         &self, | ||||||
|  |         context: &Context, | ||||||
|  |         bounds: S, | ||||||
|  |     ) -> Vec<T>; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl BufferExt for wgpu::Buffer { | ||||||
|  |     fn get_mapped_range<S: RangeBounds<wgpu::BufferAddress>, T: bytemuck::Pod>( | ||||||
|  |         &self, | ||||||
|  |         context: &Context, | ||||||
|  |         bounds: S, | ||||||
|  |     ) -> Vec<T> { | ||||||
|  |         let slice = self.slice(bounds); | ||||||
|  |         slice.map_async(wgpu::MapMode::Read, |_| {}); | ||||||
|  |         context.device.poll(wgpu::Maintain::Wait); | ||||||
|  |         let data: Vec<T> = bytemuck::cast_slice(slice.get_mapped_range().as_ref()).to_vec(); | ||||||
|  |         self.unmap(); | ||||||
|  | 
 | ||||||
|  |         data | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,108 @@ | ||||||
|  | use std::sync::Arc; | ||||||
|  | 
 | ||||||
|  | use anyhow::{Context as _, Result}; | ||||||
|  | use winit::{ | ||||||
|  |     dpi::PhysicalSize, event::WindowEvent, event_loop::EventLoopWindowTarget, window::Window, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | pub struct Context<'window> { | ||||||
|  |     pub window: Arc<Window>, | ||||||
|  |     pub instance: wgpu::Instance, | ||||||
|  |     pub size: PhysicalSize<u32>, | ||||||
|  |     pub surface: wgpu::Surface<'window>, | ||||||
|  |     pub surface_config: wgpu::SurfaceConfiguration, | ||||||
|  |     pub adapter: wgpu::Adapter, | ||||||
|  |     pub device: wgpu::Device, | ||||||
|  |     pub queue: wgpu::Queue, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<'window> Context<'window> { | ||||||
|  |     pub async fn new(window: Arc<Window>, limits: wgpu::Limits) -> Result<Self> { | ||||||
|  |         log::info!("Initialising WGPU context..."); | ||||||
|  |         let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { | ||||||
|  |             backends: wgpu::Backends::VULKAN, | ||||||
|  |             dx12_shader_compiler: Default::default(), | ||||||
|  |             ..Default::default() | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // To be able to start drawing we need a few things:
 | ||||||
|  |         // - A surface
 | ||||||
|  |         // - A GPU device to draw to the surface
 | ||||||
|  |         // - A draw command queue
 | ||||||
|  |         log::info!("Initialising window surface..."); | ||||||
|  |         let surface = instance.create_surface(window.clone())?; | ||||||
|  | 
 | ||||||
|  |         log::info!("Requesting GPU adapter..."); | ||||||
|  |         let adapter = instance | ||||||
|  |             .request_adapter(&wgpu::RequestAdapterOptions { | ||||||
|  |                 power_preference: wgpu::PowerPreference::HighPerformance, | ||||||
|  |                 force_fallback_adapter: false, | ||||||
|  |                 compatible_surface: Some(&surface), | ||||||
|  |             }) | ||||||
|  |             .await | ||||||
|  |             .context("Failed to find suitable GPU adapter")?; | ||||||
|  | 
 | ||||||
|  |         log::info!("Checking GPU adapter meets requirements"); | ||||||
|  |         log::info!("Requesting GPU device..."); | ||||||
|  |         let (device, queue) = adapter | ||||||
|  |             .request_device( | ||||||
|  |                 &wgpu::DeviceDescriptor { | ||||||
|  |                     label: None, | ||||||
|  |                     required_features: wgpu::Features::empty(), | ||||||
|  |                     required_limits: limits, | ||||||
|  |                 }, | ||||||
|  |                 None, | ||||||
|  |             ) | ||||||
|  |             .await?; | ||||||
|  | 
 | ||||||
|  |         log::info!("Configuring window surface..."); | ||||||
|  |         let size = window.inner_size(); | ||||||
|  |         let surface_config = surface | ||||||
|  |             .get_default_config(&adapter, size.width, size.height) | ||||||
|  |             .context("Surface configuration unsupported by adapter")?; | ||||||
|  |         surface.configure(&device, &surface_config); | ||||||
|  | 
 | ||||||
|  |         Ok(Self { | ||||||
|  |             window, | ||||||
|  |             instance, | ||||||
|  |             size, | ||||||
|  |             surface, | ||||||
|  |             surface_config, | ||||||
|  |             adapter, | ||||||
|  |             device, | ||||||
|  |             queue, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn resize_surface(&mut self, new_size: PhysicalSize<u32>) { | ||||||
|  |         if new_size.width > 0 && new_size.height > 0 { | ||||||
|  |             self.size = new_size; | ||||||
|  |             self.surface_config.width = new_size.width; | ||||||
|  |             self.surface_config.height = new_size.height; | ||||||
|  |             self.surface.configure(&self.device, &self.surface_config); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn handle_window_event( | ||||||
|  |         &mut self, | ||||||
|  |         event: &WindowEvent, | ||||||
|  |         elwt: &EventLoopWindowTarget<()>, | ||||||
|  |     ) -> bool { | ||||||
|  |         let mut handled = true; | ||||||
|  |         match event { | ||||||
|  |             WindowEvent::CloseRequested => { | ||||||
|  |                 elwt.exit(); | ||||||
|  |             } | ||||||
|  |             WindowEvent::Resized(physical_size) => { | ||||||
|  |                 self.resize_surface(*physical_size); | ||||||
|  |             } | ||||||
|  |             WindowEvent::ScaleFactorChanged { .. } => { | ||||||
|  |                 self.resize_surface(self.window.inner_size()); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             _ => handled = false, | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         handled | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								src/lib.rs
								
								
								
								
							
							
						
						
									
										23
									
								
								src/lib.rs
								
								
								
								
							|  | @ -1,14 +1,11 @@ | ||||||
| pub fn add(left: usize, right: usize) -> usize { | mod bind_group; | ||||||
|     left + right | mod buffer; | ||||||
| } | mod context; | ||||||
|  | mod texture; | ||||||
| 
 | 
 | ||||||
| #[cfg(test)] | pub use self::{ | ||||||
| mod tests { |     bind_group::{BindGroupBuilder, BindGroupLayoutBuilder}, | ||||||
|     use super::*; |     buffer::{BufferExt, BulkBufferBuilder}, | ||||||
| 
 |     context::Context, | ||||||
|     #[test] |     texture::{Texture, TextureBuilder}, | ||||||
|     fn it_works() { | }; | ||||||
|         let result = add(2, 2); |  | ||||||
|         assert_eq!(result, 4); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -0,0 +1,199 @@ | ||||||
|  | use anyhow::Result; | ||||||
|  | 
 | ||||||
|  | use super::{BindGroupBuilder, BindGroupLayoutBuilder, Context}; | ||||||
|  | 
 | ||||||
|  | // TODO: Support mip-mapping and multi-sampling
 | ||||||
|  | #[derive(Debug, Clone)] | ||||||
|  | pub struct TextureAttributes { | ||||||
|  |     pub size: wgpu::Extent3d, | ||||||
|  |     pub dimension: wgpu::TextureDimension, | ||||||
|  |     pub format: wgpu::TextureFormat, | ||||||
|  |     pub usage: wgpu::TextureUsages, | ||||||
|  |     pub address_mode_u: wgpu::AddressMode, | ||||||
|  |     pub address_mode_v: wgpu::AddressMode, | ||||||
|  |     pub address_mode_w: wgpu::AddressMode, | ||||||
|  |     pub mag_filter: wgpu::FilterMode, | ||||||
|  |     pub min_filter: wgpu::FilterMode, | ||||||
|  |     pub mipmap_filter: wgpu::FilterMode, | ||||||
|  |     pub shader_visibility: wgpu::ShaderStages, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Default for TextureAttributes { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self { | ||||||
|  |             size: Default::default(), | ||||||
|  |             dimension: wgpu::TextureDimension::D2, | ||||||
|  |             format: wgpu::TextureFormat::Rgba8UnormSrgb, | ||||||
|  |             usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, | ||||||
|  |             address_mode_u: wgpu::AddressMode::default(), | ||||||
|  |             address_mode_v: wgpu::AddressMode::default(), | ||||||
|  |             address_mode_w: wgpu::AddressMode::default(), | ||||||
|  |             mag_filter: wgpu::FilterMode::default(), | ||||||
|  |             min_filter: wgpu::FilterMode::default(), | ||||||
|  |             mipmap_filter: wgpu::FilterMode::default(), | ||||||
|  |             shader_visibility: wgpu::ShaderStages::FRAGMENT, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct TextureBuilder { | ||||||
|  |     pub attributes: TextureAttributes, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl TextureBuilder { | ||||||
|  |     pub fn new() -> Self { | ||||||
|  |         Self { | ||||||
|  |             attributes: Default::default(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_size(mut self, width: u32, height: u32, depth: u32) -> Self { | ||||||
|  |         self.attributes.size = wgpu::Extent3d { | ||||||
|  |             width, | ||||||
|  |             height, | ||||||
|  |             depth_or_array_layers: depth, | ||||||
|  |         }; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_dimension(mut self, dimension: wgpu::TextureDimension) -> Self { | ||||||
|  |         self.attributes.dimension = dimension; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_format(mut self, format: wgpu::TextureFormat) -> Self { | ||||||
|  |         self.attributes.format = format; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_usage(mut self, usage: wgpu::TextureUsages) -> Self { | ||||||
|  |         self.attributes.usage = usage; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_address_mode(mut self, address_mode: wgpu::AddressMode) -> Self { | ||||||
|  |         self.attributes.address_mode_u = address_mode; | ||||||
|  |         self.attributes.address_mode_v = address_mode; | ||||||
|  |         self.attributes.address_mode_w = address_mode; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_filter_mode(mut self, filter_mode: wgpu::FilterMode) -> Self { | ||||||
|  |         self.attributes.mag_filter = filter_mode; | ||||||
|  |         self.attributes.min_filter = filter_mode; | ||||||
|  |         self.attributes.mipmap_filter = filter_mode; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn with_shader_visibility(mut self, visibility: wgpu::ShaderStages) -> Self { | ||||||
|  |         self.attributes.shader_visibility = visibility; | ||||||
|  |         self | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline] | ||||||
|  |     pub fn build(self, context: &Context) -> Result<Texture> { | ||||||
|  |         Texture::new(context, self.attributes) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct Texture { | ||||||
|  |     pub attributes: TextureAttributes, | ||||||
|  |     pub texture: wgpu::Texture, | ||||||
|  |     pub view: wgpu::TextureView, | ||||||
|  |     pub sampler: wgpu::Sampler, | ||||||
|  |     pub bind_group_layout: wgpu::BindGroupLayout, | ||||||
|  |     pub bind_group: wgpu::BindGroup, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Texture { | ||||||
|  |     pub fn new(context: &Context, attributes: TextureAttributes) -> Result<Self> { | ||||||
|  |         let texture = context.device.create_texture(&wgpu::TextureDescriptor { | ||||||
|  |             label: None, | ||||||
|  |             size: attributes.size, | ||||||
|  |             mip_level_count: 1, | ||||||
|  |             sample_count: 1, | ||||||
|  |             dimension: attributes.dimension, | ||||||
|  |             format: attributes.format, | ||||||
|  |             usage: attributes.usage, | ||||||
|  |             view_formats: &[], | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); | ||||||
|  |         let sampler = context.device.create_sampler(&wgpu::SamplerDescriptor { | ||||||
|  |             address_mode_u: attributes.address_mode_u, | ||||||
|  |             address_mode_v: attributes.address_mode_v, | ||||||
|  |             address_mode_w: attributes.address_mode_w, | ||||||
|  |             mag_filter: attributes.mag_filter, | ||||||
|  |             min_filter: attributes.min_filter, | ||||||
|  |             mipmap_filter: attributes.mipmap_filter, | ||||||
|  |             ..Default::default() | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         let view_dimension = match attributes.dimension { | ||||||
|  |             wgpu::TextureDimension::D1 => wgpu::TextureViewDimension::D1, | ||||||
|  |             wgpu::TextureDimension::D2 => wgpu::TextureViewDimension::D2, | ||||||
|  |             wgpu::TextureDimension::D3 => wgpu::TextureViewDimension::D3, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         let bind_group_layout = BindGroupLayoutBuilder::new() | ||||||
|  |             .with_entry( | ||||||
|  |                 attributes.shader_visibility, | ||||||
|  |                 wgpu::BindingType::Texture { | ||||||
|  |                     sample_type: wgpu::TextureSampleType::Float { filterable: true }, | ||||||
|  |                     view_dimension, | ||||||
|  |                     multisampled: false, | ||||||
|  |                 }, | ||||||
|  |                 None, | ||||||
|  |             ) | ||||||
|  |             .with_entry( | ||||||
|  |                 attributes.shader_visibility, | ||||||
|  |                 wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), | ||||||
|  |                 None, | ||||||
|  |             ) | ||||||
|  |             .build(context); | ||||||
|  |         let bind_group = BindGroupBuilder::new() | ||||||
|  |             .with_layout(&bind_group_layout) | ||||||
|  |             .with_entry(wgpu::BindingResource::TextureView(&view)) | ||||||
|  |             .with_entry(wgpu::BindingResource::Sampler(&sampler)) | ||||||
|  |             .build(context)?; | ||||||
|  | 
 | ||||||
|  |         Ok(Self { | ||||||
|  |             attributes, | ||||||
|  |             texture, | ||||||
|  |             view, | ||||||
|  |             sampler, | ||||||
|  |             bind_group_layout, | ||||||
|  |             bind_group, | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn update(&self, context: &Context, data: &[u8]) { | ||||||
|  |         log::info!("Updating texture contents..."); | ||||||
|  |         let copy_texture = wgpu::ImageCopyTexture { | ||||||
|  |             texture: &self.texture, | ||||||
|  |             mip_level: 0, | ||||||
|  |             origin: wgpu::Origin3d::ZERO, | ||||||
|  |             aspect: wgpu::TextureAspect::All, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         let size = self.attributes.size; | ||||||
|  |         let image_layout = wgpu::ImageDataLayout { | ||||||
|  |             offset: 0, | ||||||
|  |             bytes_per_row: Some(4 * size.width), | ||||||
|  |             rows_per_image: Some(size.height), | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         context | ||||||
|  |             .queue | ||||||
|  |             .write_texture(copy_texture, data, image_layout, size); | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue