From 7d37f6a5d018ca2e2ba1d67a5a3bc6f1b4716d9a Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 20 Sep 2023 00:38:19 +0200 Subject: [PATCH] Add summary messages --- src/core/region_processor.rs | 38 +++++++++++++++++------ src/core/tile_mipmapper.rs | 60 ++++++++++++++++++++++++++---------- src/core/tile_renderer.rs | 33 +++++++++++++++----- 3 files changed, 97 insertions(+), 34 deletions(-) diff --git a/src/core/region_processor.rs b/src/core/region_processor.rs index 6fb23c3..ac6b42e 100644 --- a/src/core/region_processor.rs +++ b/src/core/region_processor.rs @@ -5,7 +5,7 @@ use std::{ffi::OsStr, path::Path, time::SystemTime}; use anyhow::{Context, Result}; use indexmap::IndexSet; use rayon::prelude::*; -use tracing::{debug, error}; +use tracing::{debug, error, info}; use super::common::*; use crate::{ @@ -132,7 +132,7 @@ impl<'a> RegionProcessor<'a> { } /// Processes a single region file - fn process_region(&self, coords: TileCoords) -> Result<()> { + fn process_region(&self, coords: TileCoords) -> Result { /// Width/height of the region data const N: u32 = (BLOCKS_PER_CHUNK * CHUNKS_PER_REGION) as u32; @@ -150,7 +150,7 @@ impl<'a> RegionProcessor<'a> { if Some(input_timestamp) <= output_timestamp && Some(input_timestamp) <= lightmap_timestamp { debug!("Skipping unchanged region r.{}.{}.mca", coords.x, coords.z); - return Ok(()); + return Ok(false); } debug!("Processing region r.{}.{}.mca", coords.x, coords.z); @@ -188,7 +188,7 @@ impl<'a> RegionProcessor<'a> { Self::save_lightmap(&lightmap_path, &lightmap, input_timestamp)?; } - Ok(()) + Ok(true) } /// Iterates over all region files of a Minecraft save directory @@ -203,11 +203,31 @@ impl<'a> RegionProcessor<'a> { fs::create_dir_all(&self.config.processed_dir)?; fs::create_dir_all(&self.config.tile_dir(TileKind::Lightmap, 0))?; - regions.par_iter().for_each(|&coords| { - if let Err(err) = self.process_region(coords) { - error!("Failed to process region {:?}: {:?}", coords, err); - } - }); + info!("Processing region files..."); + + let mut results = vec![]; + regions + .par_iter() + .map(|&coords| { + let result = self.process_region(coords); + if let Err(err) = &result { + error!("Failed to process region {:?}: {:?}", coords, err); + } + result + }) + .collect_into_vec(&mut results); + + let processed = results + .iter() + .filter(|result| matches!(result, Ok(true))) + .count(); + let errors = results.iter().filter(|result| result.is_err()).count(); + info!( + "Processed region files ({} processed, {} unchanged, {} errors)", + processed, + results.len() - processed, + errors, + ); Ok(regions) } diff --git a/src/core/tile_mipmapper.rs b/src/core/tile_mipmapper.rs index e5d44fd..d2b1ac5 100644 --- a/src/core/tile_mipmapper.rs +++ b/src/core/tile_mipmapper.rs @@ -2,7 +2,7 @@ use anyhow::{Context, Result}; use rayon::prelude::*; -use tracing::{debug, warn}; +use tracing::{debug, info, warn}; use super::common::*; use crate::{io::fs, types::*}; @@ -58,7 +58,7 @@ impl<'a> TileMipmapper<'a> { level: usize, coords: TileCoords, prev: &TileCoordMap, - ) -> Result<()> + ) -> Result<(bool, bool)> where [P::Subpixel]: image::EncodableLayout, image::ImageBuffer>: Into, @@ -93,7 +93,7 @@ impl<'a> TileMipmapper<'a> { .collect(); let Some(input_timestamp) = sources.iter().map(|(_, _, ts)| *ts).max() else { - return Ok(()); + return Ok((false, false)); }; if Some(input_timestamp) <= output_timestamp { @@ -104,7 +104,7 @@ impl<'a> TileMipmapper<'a> { .expect("tile path must be in output directory") .display(), ); - return Ok(()); + return Ok((true, false)); } debug!( @@ -143,7 +143,9 @@ impl<'a> TileMipmapper<'a> { image .write_to(file, image::ImageFormat::Png) .context("Failed to save image") - }) + })?; + + Ok((true, true)) } /// Runs the mipmap generation @@ -165,24 +167,48 @@ impl<'a> TileMipmapper<'a> { break; } + info!("Generating level {} mipmaps...", level); + fs::create_dir_all(&self.config.tile_dir(TileKind::Map, level))?; fs::create_dir_all(&self.config.tile_dir(TileKind::Lightmap, level))?; let next = Self::map_coords(prev); - next.0.par_iter().try_for_each(|(&z, xs)| { - xs.par_iter().try_for_each(|&x| { - let coords = TileCoords { x, z }; - self.render_mipmap::>(TileKind::Map, level, coords, prev)?; - self.render_mipmap::>( - TileKind::Lightmap, - level, - coords, - prev, - )?; - anyhow::Ok(()) + let (total, processed) = next + .0 + .par_iter() + .flat_map(|(&z, xs)| { + let mipmapper = &self; + xs.par_iter().map(move |&x| { + let coords = TileCoords { x, z }; + let (found_map, processed_map) = mipmapper + .render_mipmap::>(TileKind::Map, level, coords, prev)?; + let (found_light, processed_light) = mipmapper + .render_mipmap::>( + TileKind::Lightmap, + level, + coords, + prev, + )?; + anyhow::Ok(( + usize::from(found_map) + usize::from(found_light), + usize::from(processed_map) + usize::from(processed_light), + )) + }) }) - })?; + .try_reduce( + || (0, 0), + |(found_a, processed_a), (found_b, processed_b)| { + Ok((found_a + found_b, processed_a + processed_b)) + }, + )?; + + info!( + "Generated level {} mipmaps ({} processed, {} unchanged)", + level, + processed, + total - processed, + ); tile_stack.push(next); } diff --git a/src/core/tile_renderer.rs b/src/core/tile_renderer.rs index 1386aa9..219e7c8 100644 --- a/src/core/tile_renderer.rs +++ b/src/core/tile_renderer.rs @@ -12,7 +12,7 @@ use glam::Vec3; use lru::LruCache; use rayon::prelude::*; use tokio::sync::OnceCell; -use tracing::debug; +use tracing::{debug, info}; use super::{common::*, region_group::RegionGroup}; use crate::{ @@ -263,7 +263,7 @@ impl<'a> TileRenderer<'a> { } /// Renders and saves a region tile image - fn render_tile(&self, coords: TileCoords) -> Result<()> { + fn render_tile(&self, coords: TileCoords) -> Result { /// Width/height of a tile image const N: u32 = (BLOCKS_PER_CHUNK * CHUNKS_PER_REGION) as u32; @@ -280,7 +280,7 @@ impl<'a> TileRenderer<'a> { .expect("tile path must be in output directory") .display(), ); - return Ok(()); + return Ok(false); } debug!( @@ -307,18 +307,35 @@ impl<'a> TileRenderer<'a> { .write_to(file, image::ImageFormat::Png) .context("Failed to save image") }, - ) + )?; + + Ok(true) } /// Runs the tile generation pub fn run(self) -> Result<()> { fs::create_dir_all(&self.config.tile_dir(TileKind::Map, 0))?; + info!("Rendering map tiles..."); + // Use par_bridge to process items in order (for better use of region cache) - self.regions.iter().par_bridge().try_for_each(|&coords| { - self.render_tile(coords) - .with_context(|| format!("Failed to render tile {:?}", coords)) - })?; + let processed = self + .regions + .iter() + .par_bridge() + .map(|&coords| { + anyhow::Ok(usize::from( + self.render_tile(coords) + .with_context(|| format!("Failed to render tile {:?}", coords))?, + )) + }) + .try_reduce(|| 0, |a, b| Ok(a + b))?; + + info!( + "Rendered map tiles ({} processed, {} unchanged)", + processed, + self.regions.len() - processed, + ); Ok(()) }