diff --git a/examples/game_of_life/main.rs b/examples/game_of_life/main.rs index cfc9343..2685f71 100644 --- a/examples/game_of_life/main.rs +++ b/examples/game_of_life/main.rs @@ -10,10 +10,10 @@ use glass::{ Glass, GlassApp, GlassConfig, GlassContext, GlassError, RenderData, }; use wgpu::{ - AddressMode, Backends, BindGroup, BindGroupDescriptor, CommandBuffer, CommandEncoder, - ComputePassDescriptor, ComputePipeline, ComputePipelineDescriptor, Extent3d, FilterMode, - InstanceFlags, Limits, MemoryHints, PowerPreference, PresentMode, PushConstantRange, - SamplerDescriptor, ShaderStages, StorageTextureAccess, StoreOp, TextureFormat, TextureUsages, + Backends, BindGroup, BindGroupDescriptor, CommandBuffer, CommandEncoder, ComputePassDescriptor, + ComputePipeline, ComputePipelineDescriptor, Extent3d, InstanceFlags, Limits, MemoryHints, + PowerPreference, PresentMode, PushConstantRange, ShaderStages, StorageTextureAccess, StoreOp, + TextureFormat, TextureUsages, }; use winit::{ event::{ElementState, MouseButton, WindowEvent}, @@ -415,15 +415,6 @@ fn create_canvas_data( }, 1, TextureFormat::Rgba16Float, - &SamplerDescriptor { - address_mode_u: AddressMode::ClampToEdge, - address_mode_v: AddressMode::ClampToEdge, - address_mode_w: AddressMode::ClampToEdge, - mag_filter: FilterMode::Linear, - min_filter: FilterMode::Linear, - mipmap_filter: FilterMode::Linear, - ..Default::default() - }, TextureUsages::TEXTURE_BINDING | TextureUsages::STORAGE_BINDING, ); let data_in = Texture::empty( @@ -436,20 +427,14 @@ fn create_canvas_data( }, 1, TextureFormat::Rgba16Float, - &SamplerDescriptor { - address_mode_u: AddressMode::ClampToEdge, - address_mode_v: AddressMode::ClampToEdge, - address_mode_w: AddressMode::ClampToEdge, - mag_filter: FilterMode::Nearest, - min_filter: FilterMode::Nearest, - mipmap_filter: FilterMode::Nearest, - ..Default::default() - }, TextureUsages::TEXTURE_BINDING | TextureUsages::STORAGE_BINDING, ); // Create bind groups to match pipeline layouts (except update, create that dynamically each frame) - let canvas_bind_group = - quad_pipeline.create_bind_group(context.device(), &canvas.views[0], &canvas.sampler); + let canvas_bind_group = quad_pipeline.create_bind_group( + context.device(), + &canvas.views[0], + context.sampler_linear_clamp_to_edge(), + ); // These must match the bind group layout of our pipeline let init_bind_group_layout = init_pipeline.get_bind_group_layout(0); let init_bind_group = context.device().create_bind_group(&BindGroupDescriptor { diff --git a/examples/quad/main.rs b/examples/quad/main.rs index f53f70d..7f7f0db 100644 --- a/examples/quad/main.rs +++ b/examples/quad/main.rs @@ -5,10 +5,7 @@ use glass::{ window::{GlassWindow, WindowConfig}, Glass, GlassApp, GlassConfig, GlassContext, GlassError, RenderData, }; -use wgpu::{ - AddressMode, BindGroup, CommandBuffer, FilterMode, Limits, SamplerDescriptor, StoreOp, - TextureFormat, TextureUsages, -}; +use wgpu::{BindGroup, CommandBuffer, Limits, StoreOp, TextureFormat, TextureUsages}; use winit::event_loop::ActiveEventLoop; const WIDTH: u32 = 1920; @@ -131,8 +128,11 @@ struct ExampleData { fn create_example_data(context: &GlassContext, quad_pipeline: &QuadPipeline) -> ExampleData { let tree = create_tree_texture(context); // Create bind group - let tree_bind_group = - quad_pipeline.create_bind_group(context.device(), &tree.views[0], &tree.sampler); + let tree_bind_group = quad_pipeline.create_bind_group( + context.device(), + &tree.views[0], + context.sampler_linear_clamp_to_edge(), + ); ExampleData { tree, tree_bind_group, @@ -147,15 +147,6 @@ fn create_tree_texture(app: &GlassContext) -> Texture { diffuse_bytes, "tree.png", TextureFormat::Rgba8UnormSrgb, - &SamplerDescriptor { - address_mode_u: AddressMode::Repeat, - address_mode_v: AddressMode::Repeat, - address_mode_w: AddressMode::Repeat, - mag_filter: FilterMode::Linear, - min_filter: FilterMode::Linear, - mipmap_filter: FilterMode::Linear, - ..Default::default() - }, TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST, ) .unwrap() diff --git a/examples/sand/grid.rs b/examples/sand/grid.rs index c7794bf..36c350e 100644 --- a/examples/sand/grid.rs +++ b/examples/sand/grid.rs @@ -2,8 +2,8 @@ use glam::{IVec2, Vec2}; use glass::{pipelines::QuadPipeline, texture::Texture}; use image::RgbaImage; use wgpu::{ - BindGroup, Device, Extent3d, FilterMode, ImageCopyTexture, ImageDataLayout, Origin3d, Queue, - SamplerDescriptor, TextureAspect, TextureFormat, TextureUsages, + BindGroup, Device, Extent3d, ImageCopyTexture, ImageDataLayout, Origin3d, Queue, Sampler, + TextureAspect, TextureFormat, TextureUsages, }; use crate::sand::{Sand, SandType}; @@ -19,7 +19,13 @@ pub struct Grid { } impl Grid { - pub fn new(device: &Device, quad: &QuadPipeline, width: u32, height: u32) -> Grid { + pub fn new( + device: &Device, + quad: &QuadPipeline, + sampler: &Sampler, + width: u32, + height: u32, + ) -> Grid { let data = vec![Sand::empty(); (width * height) as usize]; let rgba = RgbaImage::new(width, height); let texture = Texture::empty( @@ -32,14 +38,9 @@ impl Grid { }, 1, TextureFormat::Rgba8UnormSrgb, - &SamplerDescriptor { - mag_filter: FilterMode::Nearest, - min_filter: FilterMode::Nearest, - ..Default::default() - }, TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST, ); - let grid_bind_group = quad.create_bind_group(device, &texture.views[0], &texture.sampler); + let grid_bind_group = quad.create_bind_group(device, &texture.views[0], sampler); Grid { data, rgba, diff --git a/examples/sand/main.rs b/examples/sand/main.rs index 3c6e690..c516b04 100644 --- a/examples/sand/main.rs +++ b/examples/sand/main.rs @@ -50,7 +50,13 @@ impl SandSim { }), write_mask: wgpu::ColorWrites::ALL, }); - let grid = Grid::new(context.device(), &quad_pipeline, CANVAS_SIZE, CANVAS_SIZE); + let grid = Grid::new( + context.device(), + &quad_pipeline, + context.sampler_nearest_clamp_to_edge(), + CANVAS_SIZE, + CANVAS_SIZE, + ); SandSim { grid, quad_pipeline, diff --git a/src/device_context.rs b/src/device_context.rs index 359ba21..69bab06 100644 --- a/src/device_context.rs +++ b/src/device_context.rs @@ -1,8 +1,9 @@ use std::{path::PathBuf, sync::Arc}; use wgpu::{ - Adapter, Backends, Device, DeviceDescriptor, Instance, InstanceDescriptor, InstanceFlags, - Limits, MemoryHints, PowerPreference, Queue, RequestAdapterOptions, Surface, + Adapter, AddressMode, Backends, Device, DeviceDescriptor, FilterMode, Instance, + InstanceDescriptor, InstanceFlags, Limits, MemoryHints, PowerPreference, Queue, + RequestAdapterOptions, Sampler, SamplerDescriptor, Surface, }; use crate::{utils::wait_async, GlassError}; @@ -53,6 +54,10 @@ pub struct DeviceContext { adapter: Adapter, device: Arc, queue: Arc, + sampler_nearest_repeat: Arc, + sampler_linear_repeat: Arc, + sampler_nearest_clamp_to_edge: Arc, + sampler_linear_clamp_to_edge: Arc, } unsafe impl Send for DeviceContext {} @@ -71,12 +76,53 @@ impl DeviceContext { Ok(adq) => adq, Err(e) => return Err(e), }; + let sampler_nearest_repeat = Arc::new(device.create_sampler(&SamplerDescriptor { + label: None, + address_mode_u: AddressMode::Repeat, + address_mode_v: AddressMode::Repeat, + mag_filter: FilterMode::Nearest, + min_filter: FilterMode::Nearest, + mipmap_filter: FilterMode::Nearest, + ..Default::default() + })); + let sampler_linear_repeat = Arc::new(device.create_sampler(&SamplerDescriptor { + label: None, + address_mode_u: AddressMode::Repeat, + address_mode_v: AddressMode::Repeat, + mag_filter: FilterMode::Linear, + min_filter: FilterMode::Linear, + mipmap_filter: FilterMode::Linear, + ..Default::default() + })); + let sampler_nearest_clamp_to_edge = Arc::new(device.create_sampler(&SamplerDescriptor { + label: None, + address_mode_u: AddressMode::ClampToEdge, + address_mode_v: AddressMode::ClampToEdge, + mag_filter: FilterMode::Nearest, + min_filter: FilterMode::Nearest, + mipmap_filter: FilterMode::Nearest, + ..Default::default() + })); + let sampler_linear_clamp_to_edge = Arc::new(device.create_sampler(&SamplerDescriptor { + label: None, + address_mode_u: AddressMode::ClampToEdge, + address_mode_v: AddressMode::ClampToEdge, + mag_filter: FilterMode::Linear, + min_filter: FilterMode::Linear, + mipmap_filter: FilterMode::Linear, + ..Default::default() + })); + Ok(Self { config: config.clone(), instance, adapter, device: Arc::new(device), queue: Arc::new(queue), + sampler_nearest_repeat, + sampler_linear_repeat, + sampler_nearest_clamp_to_edge, + sampler_linear_clamp_to_edge, }) } @@ -129,6 +175,22 @@ impl DeviceContext { Ok((adapter, device, queue)) } + pub fn sampler_nearest_repeat(&self) -> &Arc { + &self.sampler_nearest_repeat + } + + pub fn sampler_linear_repeat(&self) -> &Arc { + &self.sampler_linear_repeat + } + + pub fn sampler_nearest_clamp_to_edge(&self) -> &Arc { + &self.sampler_nearest_clamp_to_edge + } + + pub fn sampler_linear_clamp_to_edge(&self) -> &Arc { + &self.sampler_linear_clamp_to_edge + } + pub fn instance(&self) -> &Instance { &self.instance } diff --git a/src/glass.rs b/src/glass.rs index 02d7339..6c02a0e 100644 --- a/src/glass.rs +++ b/src/glass.rs @@ -4,7 +4,7 @@ use image::ImageError; use indexmap::IndexMap; use wgpu::{ Adapter, CreateSurfaceError, Device, Instance, PowerPreference, Queue, RequestDeviceError, - SurfaceConfiguration, + Sampler, SurfaceConfiguration, }; use winit::{ application::ApplicationHandler, @@ -374,6 +374,22 @@ impl GlassContext { }) } + pub fn sampler_nearest_repeat(&self) -> &Arc { + self.device_context.sampler_nearest_repeat() + } + + pub fn sampler_linear_repeat(&self) -> &Arc { + self.device_context.sampler_linear_repeat() + } + + pub fn sampler_nearest_clamp_to_edge(&self) -> &Arc { + self.device_context.sampler_nearest_clamp_to_edge() + } + + pub fn sampler_linear_clamp_to_edge(&self) -> &Arc { + self.device_context.sampler_linear_clamp_to_edge() + } + #[allow(unused)] pub fn instance(&self) -> &Instance { self.device_context.instance() diff --git a/src/pipelines/bloom/pipeline.rs b/src/pipelines/bloom/pipeline.rs index 34ec0b9..9ec2418 100644 --- a/src/pipelines/bloom/pipeline.rs +++ b/src/pipelines/bloom/pipeline.rs @@ -6,7 +6,7 @@ use wgpu::{ BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, BlendComponent, BlendFactor, BlendOperation, BlendState, Buffer, Color, ColorTargetState, ColorWrites, CommandEncoder, Device, Extent3d, FilterMode, LoadOp, Operations, PushConstantRange, - RenderPassColorAttachment, RenderPassDescriptor, RenderPipeline, SamplerBindingType, + RenderPassColorAttachment, RenderPassDescriptor, RenderPipeline, Sampler, SamplerBindingType, SamplerDescriptor, ShaderStages, StoreOp, TextureFormat, TextureSampleType, TextureUsages, TextureViewDimension, }; @@ -31,13 +31,6 @@ fn create_bloom_texture(device: &Device, width: u32, height: u32, mip_count: u32 }, mip_count, BLOOM_TEXTURE_FORMAT, - &SamplerDescriptor { - min_filter: FilterMode::Linear, - mag_filter: FilterMode::Linear, - address_mode_u: AddressMode::ClampToEdge, - address_mode_v: AddressMode::ClampToEdge, - ..Default::default() - }, TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING, ) } @@ -48,6 +41,7 @@ pub struct BloomPipeline { upsample_pipeline: RenderPipeline, final_pipeline: RenderPipeline, bloom_texture: Texture, + bloom_sampler: Sampler, downsampling_bind_groups: Vec, upsampling_bind_groups: Vec, vertices: Buffer, @@ -247,12 +241,20 @@ impl BloomPipeline { multiview: None, cache: None, }); + let bloom_sampler = device.create_sampler(&SamplerDescriptor { + min_filter: FilterMode::Linear, + mag_filter: FilterMode::Linear, + address_mode_u: AddressMode::ClampToEdge, + address_mode_v: AddressMode::ClampToEdge, + ..Default::default() + }); let (downsampling_bind_groups, upsampling_bind_groups) = Self::create_bind_groups( device, &downsample_pipeline, &upsample_pipeline, &bloom_texture, + &bloom_sampler, mip_count, ); @@ -262,6 +264,7 @@ impl BloomPipeline { upsample_pipeline, final_pipeline, bloom_texture, + bloom_sampler, downsampling_bind_groups, upsampling_bind_groups, vertices, @@ -277,6 +280,7 @@ impl BloomPipeline { downsample_pipeline: &RenderPipeline, upsample_pipeline: &RenderPipeline, bloom_texture: &Texture, + bloom_sampler: &Sampler, mip_count: u32, ) -> (Vec, Vec) { let bind_group_count = mip_count as usize - 1; @@ -292,7 +296,7 @@ impl BloomPipeline { }, BindGroupEntry { binding: 1, - resource: BindingResource::Sampler(&bloom_texture.sampler), + resource: BindingResource::Sampler(bloom_sampler), }, ], })); @@ -310,7 +314,7 @@ impl BloomPipeline { }, BindGroupEntry { binding: 1, - resource: BindingResource::Sampler(&bloom_texture.sampler), + resource: BindingResource::Sampler(bloom_sampler), }, ], })); @@ -358,7 +362,7 @@ impl BloomPipeline { }, BindGroupEntry { binding: 1, - resource: BindingResource::Sampler(&self.bloom_texture.sampler), + resource: BindingResource::Sampler(&self.bloom_sampler), }, ], }); diff --git a/src/pipelines/paste/pipeline.rs b/src/pipelines/paste/pipeline.rs index 8a8ba69..ac642d4 100644 --- a/src/pipelines/paste/pipeline.rs +++ b/src/pipelines/paste/pipeline.rs @@ -2,11 +2,10 @@ use std::borrow::Cow; use bytemuck::{Pod, Zeroable}; use wgpu::{ - util::DeviceExt, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, - BindGroupLayoutEntry, BindingResource, BindingType, Buffer, Color, ColorTargetState, - ColorWrites, CommandEncoder, Device, Operations, PushConstantRange, RenderPassColorAttachment, - RenderPassDescriptor, RenderPipeline, SamplerBindingType, ShaderStages, TextureFormat, - TextureSampleType, TextureViewDimension, + util::DeviceExt, BindGroup, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, + Buffer, Color, ColorTargetState, ColorWrites, CommandEncoder, Device, Operations, + PushConstantRange, RenderPassColorAttachment, RenderPassDescriptor, RenderPipeline, + SamplerBindingType, ShaderStages, TextureFormat, TextureSampleType, TextureViewDimension, }; use crate::{ @@ -120,10 +119,9 @@ impl PastePipeline { #[allow(clippy::too_many_arguments)] pub fn paste( &self, - device: &Device, encoder: &mut CommandEncoder, ops: Operations, - input: &Texture, + input_image_bind_group: &BindGroup, output: &Texture, tint: [f32; 4], size: [f32; 2], @@ -143,20 +141,6 @@ impl PastePipeline { -(2.0 * offset[1] - output.size[1]) / output.size[1], ], }; - let bind_group = device.create_bind_group(&BindGroupDescriptor { - label: Some("paste_bind_group"), - layout: &self.paste_pipeline.get_bind_group_layout(0), - entries: &[ - BindGroupEntry { - binding: 0, - resource: BindingResource::TextureView(&input.views[0]), - }, - BindGroupEntry { - binding: 1, - resource: BindingResource::Sampler(&input.sampler), - }, - ], - }); { let mut r_pass = encoder.begin_render_pass(&RenderPassDescriptor { label: Some("paste_pass"), @@ -170,7 +154,7 @@ impl PastePipeline { occlusion_query_set: None, }); r_pass.set_pipeline(&self.paste_pipeline); - r_pass.set_bind_group(0, &bind_group, &[]); + r_pass.set_bind_group(0, input_image_bind_group, &[]); r_pass.set_vertex_buffer(0, self.vertices.slice(..)); r_pass.set_index_buffer(self.indices.slice(..), wgpu::IndexFormat::Uint16); r_pass.set_push_constants( diff --git a/src/pipelines/tonemapping/pipeline.rs b/src/pipelines/tonemapping/pipeline.rs index bec2139..69c4432 100644 --- a/src/pipelines/tonemapping/pipeline.rs +++ b/src/pipelines/tonemapping/pipeline.rs @@ -2,11 +2,10 @@ use std::borrow::Cow; use bytemuck::{Pod, Zeroable}; use wgpu::{ - util::DeviceExt, BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, - BindGroupLayoutEntry, BindingResource, BindingType, Buffer, ColorTargetState, ColorWrites, - CommandEncoder, Device, Operations, PushConstantRange, RenderPassColorAttachment, - RenderPassDescriptor, RenderPipeline, SamplerBindingType, ShaderStages, TextureFormat, - TextureSampleType, TextureViewDimension, + util::DeviceExt, BindGroup, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, + Buffer, ColorTargetState, ColorWrites, CommandEncoder, Device, Operations, PushConstantRange, + RenderPassColorAttachment, RenderPassDescriptor, RenderPipeline, SamplerBindingType, + ShaderStages, TextureFormat, TextureSampleType, TextureViewDimension, }; use crate::{ @@ -98,27 +97,12 @@ impl TonemappingPipeline { pub fn tonemap( &self, - device: &Device, encoder: &mut CommandEncoder, - input: &Texture, + input_image_bind_group: &BindGroup, output: &Texture, color_grading: ColorGrading, ) { let push_constants: ToneMappingPushConstants = color_grading.into(); - let bind_group = device.create_bind_group(&BindGroupDescriptor { - label: Some("tonemapping_bind_group"), - layout: &self.tonemapping_pipeline.get_bind_group_layout(0), - entries: &[ - BindGroupEntry { - binding: 0, - resource: BindingResource::TextureView(&input.views[0]), - }, - BindGroupEntry { - binding: 1, - resource: BindingResource::Sampler(&input.sampler), - }, - ], - }); { let mut r_pass = encoder.begin_render_pass(&RenderPassDescriptor { label: Some("tonemapping_pass"), @@ -132,7 +116,7 @@ impl TonemappingPipeline { occlusion_query_set: None, }); r_pass.set_pipeline(&self.tonemapping_pipeline); - r_pass.set_bind_group(0, &bind_group, &[]); + r_pass.set_bind_group(0, input_image_bind_group, &[]); r_pass.set_vertex_buffer(0, self.vertices.slice(..)); r_pass.set_push_constants( ShaderStages::FRAGMENT, diff --git a/src/texture.rs b/src/texture.rs index bc1e3a3..865e8ed 100644 --- a/src/texture.rs +++ b/src/texture.rs @@ -1,8 +1,8 @@ use image::DynamicImage; use wgpu::{ - Device, Extent3d, ImageCopyTexture, ImageDataLayout, Origin3d, Queue, Sampler, - SamplerDescriptor, TextureAspect, TextureDescriptor, TextureDimension, TextureFormat, - TextureUsages, TextureView, TextureViewDescriptor, + Device, Extent3d, ImageCopyTexture, ImageDataLayout, Origin3d, Queue, TextureAspect, + TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, TextureView, + TextureViewDescriptor, }; use crate::GlassError; @@ -11,7 +11,6 @@ use crate::GlassError; pub struct Texture { pub texture: wgpu::Texture, pub views: Vec, - pub sampler: Sampler, pub size: [f32; 2], } @@ -22,7 +21,6 @@ impl Texture { size: Extent3d, mip_count: u32, format: TextureFormat, - sampler_descriptor: &SamplerDescriptor, usage: TextureUsages, ) -> Self { let texture = device.create_texture(&TextureDescriptor { @@ -44,12 +42,10 @@ impl Texture { }); views.push(view); } - let sampler = device.create_sampler(sampler_descriptor); Self { texture, views, - sampler, size: [size.width as f32, size.height as f32], } } @@ -60,7 +56,6 @@ impl Texture { bytes: &[u8], label: &str, format: TextureFormat, - sampler_descriptor: &SamplerDescriptor, usage: TextureUsages, ) -> Result { let img = match image::load_from_memory(bytes) { @@ -68,14 +63,7 @@ impl Texture { Err(e) => return Err(GlassError::ImageError(e)), }; Ok(Self::from_image( - device, - queue, - &img, - label, - format, - sampler_descriptor, - usage, - 1, + device, queue, &img, label, format, usage, 1, )) } @@ -86,7 +74,6 @@ impl Texture { img: &DynamicImage, label: &str, format: TextureFormat, - sampler_descriptor: &SamplerDescriptor, usage: TextureUsages, mip_count: u32, ) -> Self { @@ -126,12 +113,10 @@ impl Texture { ); let view = texture.create_view(&TextureViewDescriptor::default()); - let sampler = device.create_sampler(sampler_descriptor); Self { texture, views: vec![view], - sampler, size: [dimensions.0 as f32, dimensions.1 as f32], } }