diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 087c986..4f31e5e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,9 +20,21 @@ jobs: - uses: dtolnay/rust-toolchain@stable - name: Install native dependencies run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev - - run: cargo check --workspace + - run: cargo check --workspace + # Check vello (the default crate) without the features used by `with_winit` for debugging + - run: cargo check # --exclude with_bevy # for when bevy has an outdated wgpu version # -Dwarnings # for when we have fixed unused code warnings + + clippy: + runs-on: ubuntu-latest + name: Enforce clippy lints + steps: + - uses: actions/checkout@v2 + - uses: dtolnay/rust-toolchain@stable + - name: Install native dependencies + run: sudo apt-get update; sudo apt-get install --no-install-recommends libasound2-dev libudev-dev + - run: cargo clippy --all-targets --workspace -- -D warnings wasm: runs-on: ubuntu-latest diff --git a/crates/shaders/build.rs b/crates/shaders/build.rs index 614bacb..073d138 100644 --- a/crates/shaders/build.rs +++ b/crates/shaders/build.rs @@ -26,7 +26,7 @@ fn main() { .and_then(|p| Path::new(&p).parent().map(|p| p.to_owned())) .unwrap_or(PathBuf::from("../../")); let shader_dir = Path::new(&workspace_dir).join("shader"); - let mut shaders = compile::ShaderInfo::from_dir(&shader_dir); + let mut shaders = compile::ShaderInfo::from_dir(shader_dir); // Drop the HashMap and sort by name so that we get deterministic order. let mut shaders = shaders.drain().collect::>(); @@ -34,7 +34,7 @@ fn main() { let mut buf = String::default(); write_types(&mut buf, &shaders).unwrap(); write_shaders(&mut buf, &shaders).unwrap(); - std::fs::write(&dest_path, &buf).unwrap(); + std::fs::write(dest_path, &buf).unwrap(); println!("cargo:rerun-if-changed=../shader"); } @@ -93,12 +93,12 @@ fn write_shaders( wg_bufs )?; if cfg!(feature = "wgsl") { - writeln!(buf, " wgsl: Cow::Borrowed(&{:?}),", info.source)?; + writeln!(buf, " wgsl: Cow::Borrowed({:?}),", info.source)?; } if cfg!(feature = "msl") { writeln!( buf, - " msl: Cow::Borrowed(&{:?}),", + " msl: Cow::Borrowed({:?}),", compile::msl::translate(info).unwrap() )?; } diff --git a/examples/headless/src/main.rs b/examples/headless/src/main.rs index 43d33aa..5a49d05 100644 --- a/examples/headless/src/main.rs +++ b/examples/headless/src/main.rs @@ -21,7 +21,7 @@ fn main() -> Result<()> { #[cfg(not(target_arch = "wasm32"))] env_logger::init(); let args = Args::parse(); - let scenes = args.args.select_scene_set(|| Args::command())?; + let scenes = args.args.select_scene_set(Args::command)?; if let Some(scenes) = scenes { let mut scene_idx = None; for (idx, scene) in scenes.scenes.iter().enumerate() { @@ -41,8 +41,8 @@ fn main() -> Result<()> { args.scene ))?; - if !(parsed < scenes.scenes.len()) { - if scenes.scenes.len() == 0 { + if parsed >= scenes.scenes.len() { + if scenes.scenes.is_empty() { bail!("Cannot select a scene, as there are no scenes") } bail!( @@ -86,7 +86,7 @@ async fn render(mut scenes: SceneSet, index: usize, args: &Args) -> Result<()> { let device = &device_handle.device; let queue = &device_handle.queue; let mut renderer = vello::Renderer::new( - &device, + device, &RendererOptions { surface_format: None, }, @@ -120,20 +120,14 @@ async fn render(mut scenes: SceneSet, index: usize, args: &Args) -> Result<()> { }; let factor = Vec2::new(new_width as f64, new_height as f64); let scale_factor = (factor.x / resolution.x).min(factor.y / resolution.y); - transform = transform * Affine::scale(scale_factor); + transform *= Affine::scale(scale_factor); (new_width, new_height) } else { match (args.x_resolution, args.y_resolution) { (None, None) => (1000, 1000), - (None, Some(y)) => { - let y = y.try_into()?; - (y, y) - } - (Some(x), None) => { - let x = x.try_into()?; - (x, x) - } - (Some(x), Some(y)) => (x.try_into()?, y.try_into()?), + (None, Some(y)) => (y, y), + (Some(x), None) => (x, x), + (Some(x), Some(y)) => (x, y), } }; let render_params = vello::RenderParams { @@ -165,11 +159,11 @@ async fn render(mut scenes: SceneSet, index: usize, args: &Args) -> Result<()> { }); let view = target.create_view(&wgpu::TextureViewDescriptor::default()); renderer - .render_to_texture(&device, &queue, &scene, &view, &render_params) + .render_to_texture(device, queue, &scene, &view, &render_params) .or_else(|_| bail!("Got non-Send/Sync error from rendering"))?; // (width * 4).next_multiple_of(256) let padded_byte_width = { - let w = width as u32 * 4; + let w = width * 4; match w % 256 { 0 => w, r => w + (256 - r), @@ -202,7 +196,7 @@ async fn render(mut scenes: SceneSet, index: usize, args: &Args) -> Result<()> { let (sender, receiver) = futures_intrusive::channel::shared::oneshot_channel(); buf_slice.map_async(wgpu::MapMode::Read, move |v| sender.send(v).unwrap()); - if let Some(recv_result) = block_on_wgpu(&device, receiver.receive()) { + if let Some(recv_result) = block_on_wgpu(device, receiver.receive()) { recv_result?; } else { bail!("channel was closed"); diff --git a/examples/scenes/src/download.rs b/examples/scenes/src/download.rs index 805770d..3f3eb51 100644 --- a/examples/scenes/src/download.rs +++ b/examples/scenes/src/download.rs @@ -40,7 +40,7 @@ impl Download { if let Some(downloads) = &self.downloads { to_download = downloads .iter() - .map(|it| Self::parse_download(&it)) + .map(|it| Self::parse_download(it)) .collect(); } else { let mut accepted = self.auto; @@ -52,7 +52,7 @@ impl Download { }) .collect::>(); if !accepted { - if downloads.len() != 0 { + if !downloads.is_empty() { println!( "Would you like to download a set of default svg files? These files are:" ); @@ -140,7 +140,7 @@ impl SVGDownload { let mut file = std::fs::OpenOptions::new() .create_new(true) .write(true) - .open(&self.file_path(directory)) + .open(self.file_path(directory)) .context("Creating file")?; let mut reader = ureq::get(&self.url).call()?.into_reader(); @@ -152,14 +152,8 @@ impl SVGDownload { if reader.read_exact(&mut [0]).is_ok() { bail!("Size limit exceeded"); } - if limit_exact { - if file - .seek(std::io::SeekFrom::Current(0)) - .context("Checking file limit")? - != size_limit - { - bail!("Builtin downloaded file was not as expected"); - } + if limit_exact && file.stream_position().context("Checking file limit")? != size_limit { + bail!("Builtin downloaded file was not as expected"); } Ok(()) } diff --git a/examples/scenes/src/lib.rs b/examples/scenes/src/lib.rs index 7fee5cd..6cea26d 100644 --- a/examples/scenes/src/lib.rs +++ b/examples/scenes/src/lib.rs @@ -99,7 +99,7 @@ impl Arguments { if self.test_scenes { Ok(test_scenes()) } else if let Some(svgs) = &self.svgs { - scene_from_files(&svgs) + scene_from_files(svgs) } else { default_scene(command) } diff --git a/examples/scenes/src/mmark.rs b/examples/scenes/src/mmark.rs index dc5ce32..98be5fa 100644 --- a/examples/scenes/src/mmark.rs +++ b/examples/scenes/src/mmark.rs @@ -1,5 +1,7 @@ //! A benchmark based on MotionMark 1.2's path benchmark. +use std::cmp::Ordering; + use rand::{seq::SliceRandom, Rng}; use vello::peniko::Color; use vello::{ @@ -40,19 +42,21 @@ impl MMark { fn resize(&mut self, n: usize) { let old_n = self.elements.len(); - if n < old_n { - self.elements.truncate(n) - } else if n > old_n { - let mut last = self - .elements - .last() - .map(|e| e.grid_point) - .unwrap_or(GridPoint((GRID_WIDTH / 2, GRID_HEIGHT / 2))); - self.elements.extend((old_n..n).map(|_| { - let element = Element::new_rand(last); - last = element.grid_point; - element - })); + match n.cmp(&old_n) { + Ordering::Less => self.elements.truncate(n), + Ordering::Greater => { + let mut last = self + .elements + .last() + .map(|e| e.grid_point) + .unwrap_or(GridPoint((GRID_WIDTH / 2, GRID_HEIGHT / 2))); + self.elements.extend((old_n..n).map(|_| { + let element = Element::new_rand(last); + last = element.grid_point; + element + })); + } + _ => (), } } } @@ -149,7 +153,7 @@ impl Element { )), ) }; - let color = COLORS.choose(&mut rng).unwrap().clone(); + let color = *COLORS.choose(&mut rng).unwrap(); let width = rng.gen::().powi(5) * 20.0 + 1.0; let is_split = rng.gen(); Element { @@ -170,11 +174,11 @@ impl GridPoint { let offset = OFFSETS.choose(&mut rng).unwrap(); let mut x = last.0 .0 + offset.0; - if x < 0 || x > GRID_WIDTH { + if !(0..=GRID_WIDTH).contains(&x) { x -= offset.0 * 2; } let mut y = last.0 .1 + offset.1; - if y < 0 || y > GRID_HEIGHT { + if !(0..=GRID_HEIGHT).contains(&y) { y -= offset.1 * 2; } GridPoint((x, y)) diff --git a/examples/scenes/src/simple_text.rs b/examples/scenes/src/simple_text.rs index 717d0f1..9e81198 100644 --- a/examples/scenes/src/simple_text.rs +++ b/examples/scenes/src/simple_text.rs @@ -37,6 +37,7 @@ pub struct SimpleText { } impl SimpleText { + #[allow(clippy::new_without_default)] pub fn new() -> Self { Self { gcx: GlyphContext::new(), @@ -45,6 +46,7 @@ impl SimpleText { } } + #[allow(clippy::too_many_arguments)] pub fn add_run<'a>( &mut self, builder: &mut SceneBuilder, @@ -69,6 +71,7 @@ impl SimpleText { ); } + #[allow(clippy::too_many_arguments)] pub fn add_var_run<'a>( &mut self, builder: &mut SceneBuilder, @@ -118,7 +121,7 @@ impl SimpleText { } let gid = charmap.map(ch).unwrap_or_default(); let advance = glyph_metrics.advance_width(gid).unwrap_or_default(); - let x = pen_x as f32; + let x = pen_x; pen_x += advance; Some(Glyph { id: gid.to_u16() as u32, @@ -139,10 +142,7 @@ impl SimpleText { text: &str, ) { let default_font = FontRef::new(ROBOTO_FONT).unwrap(); - let font = font - .map(|font| to_font_ref(font)) - .flatten() - .unwrap_or(default_font); + let font = font.and_then(to_font_ref).unwrap_or(default_font); let fello_size = vello::fello::Size::new(size); let charmap = font.charmap(); let metrics = font.metrics(fello_size, Default::default()); @@ -171,7 +171,7 @@ impl SimpleText { } } -fn to_font_ref<'a>(font: &'a Font) -> Option> { +fn to_font_ref(font: &Font) -> Option> { use vello::fello::raw::FileRef; let file_ref = FileRef::new(font.data.as_ref()).ok()?; match file_ref { diff --git a/examples/scenes/src/svg.rs b/examples/scenes/src/svg.rs index 708be50..122bd79 100644 --- a/examples/scenes/src/svg.rs +++ b/examples/scenes/src/svg.rs @@ -75,8 +75,7 @@ fn example_scene_of(file: PathBuf) -> ExampleScene { .unwrap_or_else(|| "unknown".to_string()); ExampleScene { function: Box::new(svg_function_of(name.clone(), move || { - let contents = std::fs::read_to_string(&file).expect("failed to read svg file"); - contents + std::fs::read_to_string(file).expect("failed to read svg file") })), config: crate::SceneConfig { animated: false, @@ -91,7 +90,7 @@ pub fn svg_function_of>( ) -> impl FnMut(&mut SceneBuilder, &mut SceneParams) { fn render_svg_contents(name: &str, contents: &str) -> (SceneFragment, Vec2) { let start = Instant::now(); - let svg = usvg::Tree::from_str(&contents, &usvg::Options::default()) + let svg = usvg::Tree::from_str(contents, &usvg::Options::default()) .expect("failed to parse svg file"); eprintln!("Parsed svg {name} in {:?}", start.elapsed()); let start = Instant::now(); @@ -112,7 +111,7 @@ pub fn svg_function_of>( let mut contents = Some(contents); move |builder, params| { if let Some((scene_frag, resolution)) = cached_scene.as_mut() { - builder.append(&scene_frag, None); + builder.append(scene_frag, None); params.resolution = Some(*resolution); return; } diff --git a/examples/scenes/src/test_scenes.rs b/examples/scenes/src/test_scenes.rs index ef9676d..ab3ee1e 100644 --- a/examples/scenes/src/test_scenes.rs +++ b/examples/scenes/src/test_scenes.rs @@ -167,7 +167,7 @@ fn animated_text(sb: &mut SceneBuilder, params: &mut SceneParams) { Fill::NonZero, "And some vello\ntext with a newline", ); - let th = params.time as f64; + let th = params.time; let center = Point::new(500.0, 500.0); let mut p1 = center; p1.x += 400.0 * th.cos(); @@ -186,7 +186,7 @@ fn animated_text(sb: &mut SceneBuilder, params: &mut SceneParams) { None, &rect, ); - let alpha = (params.time as f64).sin() as f32 * 0.5 + 0.5; + let alpha = params.time.sin() as f32 * 0.5 + 0.5; sb.push_layer(Mix::Normal, alpha, Affine::IDENTITY, &rect); sb.fill( Fill::NonZero, @@ -284,12 +284,11 @@ fn gradient_extend(sb: &mut SceneBuilder, params: &mut SceneParams) { ); } let extend_modes = [Extend::Pad, Extend::Repeat, Extend::Reflect]; - for x in 0..3 { - let extend = extend_modes[x]; + for (x, extend) in extend_modes.iter().enumerate() { for y in 0..2 { let is_radial = y & 1 != 0; let transform = Affine::translate((x as f64 * 350.0 + 50.0, y as f64 * 350.0 + 100.0)); - square(sb, is_radial, transform, extend); + square(sb, is_radial, transform, *extend); } } for (i, label) in ["Pad", "Repeat", "Reflect"].iter().enumerate() { @@ -305,6 +304,7 @@ fn gradient_extend(sb: &mut SceneBuilder, params: &mut SceneParams) { } } +#[allow(clippy::too_many_arguments)] fn two_point_radial(sb: &mut SceneBuilder, _params: &mut SceneParams) { fn make( sb: &mut SceneBuilder, @@ -604,7 +604,7 @@ fn render_blend_square(sb: &mut SceneBuilder, blend: BlendMode, transform: Affin (125., 200., Color::rgb8(64, 192, 255)), ]; for (x, y, c) in GRADIENTS { - let mut color2 = c.clone(); + let mut color2 = *c; color2.a = 0; let radial = Gradient::new_radial((*x, *y), 100.0).with_stops([*c, color2]); sb.fill(Fill::NonZero, transform, &radial, None, &rect); diff --git a/examples/with_bevy/src/main.rs b/examples/with_bevy/src/main.rs index eb88c48..d4d57d6 100644 --- a/examples/with_bevy/src/main.rs +++ b/examples/with_bevy/src/main.rs @@ -63,7 +63,7 @@ fn render_scenes( .0 .render_to_texture( device.wgpu_device(), - &*queue, + &queue, &scene.0, &gpu_image.texture_view, ¶ms, diff --git a/examples/with_winit/src/lib.rs b/examples/with_winit/src/lib.rs index 94cd791..9ae4576 100644 --- a/examples/with_winit/src/lib.rs +++ b/examples/with_winit/src/lib.rs @@ -100,6 +100,8 @@ fn run( let mut images = ImageCache::new(); let mut stats = stats::Stats::new(); let mut stats_shown = true; + // Currently not updated in wasm builds + #[allow(unused_mut)] let mut scene_complexity: Option = None; let mut complexity_shown = false; let mut vsync_on = true; @@ -327,13 +329,13 @@ fn run( // TODO: Apply svg view_box, somehow let factor = Vec2::new(width as f64, height as f64); let scale_factor = (factor.x / resolution.x).min(factor.y / resolution.y); - transform = transform * Affine::scale(scale_factor); + transform *= Affine::scale(scale_factor); } builder.append(&fragment, Some(transform)); if stats_shown { snapshot.draw_layer( &mut builder, - &mut scene_params.text, + scene_params.text, width as f64, height as f64, stats.samples(), @@ -455,7 +457,7 @@ fn create_window(event_loop: &winit::event_loop::EventLoopWindowTarget Result<()> { #[cfg(not(target_arch = "wasm32"))] env_logger::init(); let args = Args::parse(); - let scenes = args.args.select_scene_set(|| Args::command())?; + let scenes = args.args.select_scene_set(Args::command)?; if let Some(scenes) = scenes { let event_loop = EventLoopBuilder::::with_user_event().build(); #[allow(unused_mut)] diff --git a/examples/with_winit/src/stats.rs b/examples/with_winit/src/stats.rs index 81dda86..694ecdf 100644 --- a/examples/with_winit/src/stats.rs +++ b/examples/with_winit/src/stats.rs @@ -33,6 +33,7 @@ pub struct Snapshot { } impl Snapshot { + #[allow(clippy::too_many_arguments)] pub fn draw_layer<'a, T>( &self, sb: &mut SceneBuilder, @@ -69,7 +70,7 @@ impl Snapshot { ]; if let Some(bump) = &bump { if bump.failed >= 1 { - labels.push(format!("Allocation Failed!")); + labels.push("Allocation Failed!".into()); } labels.push(format!("binning: {}", bump.binning)); labels.push(format!("ptcl: {}", bump.ptcl)); @@ -89,7 +90,7 @@ impl Snapshot { text_size, Some(&Brush::Solid(Color::WHITE)), offset * Affine::translate((left_margin, (i + 1) as f64 * text_height)), - &label, + label, ); } text.add( @@ -132,6 +133,7 @@ impl Snapshot { let sample_ms = ((*sample as f64) * 0.001).min(display_max); let h = sample_ms / display_max; let s = Affine::scale_non_uniform(1., -h); + #[allow(clippy::match_overlapping_arm)] let color = match *sample { ..=16_667 => Color::rgb8(100, 143, 255), ..=33_334 => Color::rgb8(255, 176, 0), diff --git a/src/engine.rs b/src/engine.rs index 85a5208..4a910e6 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -63,6 +63,7 @@ pub struct BufProxy { #[derive(Copy, Clone, PartialEq, Eq)] pub enum ImageFormat { Rgba8, + #[allow(unused)] Bgra8, } @@ -81,6 +82,7 @@ pub enum ResourceProxy { } pub enum ExternalResource<'a> { + #[allow(unused)] Buf(BufProxy, &'a Buffer), Image(ImageProxy, &'a TextureView), } @@ -800,7 +802,7 @@ impl ResourcePool { fn get_buf( &mut self, size: u64, - name: &'static str, + #[allow(unused)] name: &'static str, usage: BufferUsages, device: &Device, ) -> Buffer { @@ -809,7 +811,7 @@ impl ResourcePool { size: rounded_size, usages: usage, #[cfg(feature = "buffer_labels")] - name: name, + name, }; if let Some(buf_vec) = self.bufs.get_mut(&props) { if let Some(buf) = buf_vec.pop() { diff --git a/src/lib.rs b/src/lib.rs index a1e3b03..43be77a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -230,7 +230,7 @@ impl Renderer { return Err("channel was closed".into()); } let mapped = buf_slice.get_mapped_range(); - bump = Some(bytemuck::pod_read_unaligned(&*mapped)); + bump = Some(bytemuck::pod_read_unaligned(&mapped)); } // TODO: apply logic to determine whether we need to rerun coarse, and also // allocate the blend stack as needed. diff --git a/src/render.rs b/src/render.rs index 600aded..24ec41a 100644 --- a/src/render.rs +++ b/src/render.rs @@ -2,7 +2,7 @@ use crate::{ engine::{BufProxy, ImageFormat, ImageProxy, Recording, ResourceProxy}, - shaders::{self, FullShaders}, + shaders::FullShaders, RenderParams, Scene, }; use vello_encoding::{Encoding, WorkgroupSize}; diff --git a/src/shaders/preprocess.rs b/src/shaders/preprocess.rs index bb9ed68..97367b8 100644 --- a/src/shaders/preprocess.rs +++ b/src/shaders/preprocess.rs @@ -5,6 +5,7 @@ use std::{ vec, }; +#[allow(unused)] pub fn get_imports(shader_dir: &Path) -> HashMap { let mut imports = HashMap::new(); let imports_dir = shader_dir.join("shared");