diff --git a/common/net/src/msg/compression.rs b/common/net/src/msg/compression.rs index 1071a8f4a0..d5f1f81068 100644 --- a/common/net/src/msg/compression.rs +++ b/common/net/src/msg/compression.rs @@ -316,7 +316,6 @@ impl VoxelImageDecoding for MixedEncoding { indices[1]..indices[2], indices[2]..quad.len(), ]; - tracing::info!("{:?} {:?}", ranges, indices); let a = image_from_bytes(PngDecoder::new(&quad[ranges[0].clone()]).ok()?)?; let b = image_from_bytes(PngDecoder::new(&quad[ranges[1].clone()]).ok()?)?; let c = image_from_bytes(PngDecoder::new(&quad[ranges[2].clone()]).ok()?)?; @@ -350,9 +349,9 @@ impl VoxelImageDecoding for MixedEncoding { } #[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct QuadPngEncoding; +pub struct QuadPngEncoding(); -impl VoxelImageEncoding for QuadPngEncoding { +impl VoxelImageEncoding for QuadPngEncoding { type Output = CompressedData<(Vec, [usize; 3])>; #[allow(clippy::type_complexity)] type Workspace = ( @@ -367,7 +366,7 @@ impl VoxelImageEncoding for QuadPngEncoding { ImageBuffer::new(width, height), ImageBuffer::new(width, height), ImageBuffer::new(width, height), - ImageBuffer::new(width, height), + ImageBuffer::new(width / N, height / N), ) } @@ -375,7 +374,7 @@ impl VoxelImageEncoding for QuadPngEncoding { ws.0.put_pixel(x, y, image::Luma([kind as u8])); ws.1.put_pixel(x, y, image::Luma([0])); ws.2.put_pixel(x, y, image::Luma([0])); - ws.3.put_pixel(x, y, image::Rgb([rgb.r, rgb.g, rgb.b])); + ws.3.put_pixel(x / N, y / N, image::Rgb([rgb.r, rgb.g, rgb.b])); } fn put_sprite( @@ -389,7 +388,6 @@ impl VoxelImageEncoding for QuadPngEncoding { ws.0.put_pixel(x, y, image::Luma([kind as u8])); ws.1.put_pixel(x, y, image::Luma([sprite as u8])); ws.2.put_pixel(x, y, image::Luma([ori.unwrap_or(0)])); - ws.3.put_pixel(x, y, image::Rgb([0; 3])); } fn finish(ws: &Self::Workspace) -> Option { @@ -430,6 +428,48 @@ impl VoxelImageEncoding for QuadPngEncoding { } } +impl VoxelImageDecoding for QuadPngEncoding { + fn start(data: &Self::Output) -> Option { + use image::codecs::png::PngDecoder; + let (quad, indices) = data.decompress()?; + let ranges: [_; 4] = [ + 0..indices[0], + indices[0]..indices[1], + indices[1]..indices[2], + indices[2]..quad.len(), + ]; + let a = image_from_bytes(PngDecoder::new(&quad[ranges[0].clone()]).ok()?)?; + let b = image_from_bytes(PngDecoder::new(&quad[ranges[1].clone()]).ok()?)?; + let c = image_from_bytes(PngDecoder::new(&quad[ranges[2].clone()]).ok()?)?; + let d = image_from_bytes(PngDecoder::new(&quad[ranges[3].clone()]).ok()?)?; + Some((a, b, c, d)) + } + + fn get_block(ws: &Self::Workspace, x: u32, y: u32) -> Block { + if let Some(kind) = BlockKind::from_u8(ws.0.get_pixel(x, y).0[0]) { + if kind.is_filled() { + let rgb = ws.3.get_pixel(x / N, y / N); + Block::new(kind, Rgb { + r: rgb[0], + g: rgb[1], + b: rgb[2], + }) + } else { + let mut block = Block::new(kind, Rgb { r: 0, g: 0, b: 0 }); + if let Some(spritekind) = SpriteKind::from_u8(ws.1.get_pixel(x, y).0[0]) { + block = block.with_sprite(spritekind); + } + if let Some(oriblock) = block.with_ori(ws.2.get_pixel(x, y).0[0]) { + block = oriblock; + } + block + } + } else { + Block::empty() + } + } +} + pub fn image_terrain_chonk( vie: VIE, packing: P, @@ -480,7 +520,6 @@ pub fn image_terrain< lo: Vec3, hi: Vec3, ) -> Option { - tracing::info!("image_terrain: {:?} {:?}", lo, hi); let dims = Vec3::new( hi.x.wrapping_sub(lo.x), hi.y.wrapping_sub(lo.y), diff --git a/common/net/src/msg/mod.rs b/common/net/src/msg/mod.rs index 63c8708500..446c929ad5 100644 --- a/common/net/src/msg/mod.rs +++ b/common/net/src/msg/mod.rs @@ -9,7 +9,7 @@ pub use self::{ client::{ClientGeneral, ClientMsg, ClientRegister, ClientType}, compression::{ CompressedData, GridLtrPacking, JpegEncoding, MixedEncoding, PackingFormula, PngEncoding, - TallPacking, VoxelImageEncoding, WireChonk, + QuadPngEncoding, TallPacking, VoxelImageEncoding, WireChonk, }, ecs_packet::EcsCompPacket, server::{ diff --git a/common/net/src/msg/server.rs b/common/net/src/msg/server.rs index 79e2f59094..5f27954016 100644 --- a/common/net/src/msg/server.rs +++ b/common/net/src/msg/server.rs @@ -1,6 +1,6 @@ use super::{ world_msg::EconomyInfo, ClientType, CompressedData, EcsCompPacket, MixedEncoding, PingMsg, - TallPacking, WireChonk, + QuadPngEncoding, TallPacking, WireChonk, }; use crate::sync; use common::{ @@ -70,6 +70,7 @@ pub type ServerRegisterAnswer = Result<(), RegisterError>; pub enum SerializedTerrainChunk { DeflatedChonk(CompressedData), PngPngPngJpeg(WireChonk), + QuadPng(WireChonk, TallPacking, TerrainChunkMeta, TerrainChunkSize>), } impl SerializedTerrainChunk { @@ -77,7 +78,7 @@ impl SerializedTerrainChunk { Self::DeflatedChonk(CompressedData::compress(chunk, 5)) } - pub fn image(chunk: &TerrainChunk) -> Self { + pub fn jpeg(chunk: &TerrainChunk) -> Self { if let Some(wc) = WireChonk::from_chonk(MixedEncoding, TallPacking { flip_y: true }, chunk) { Self::PngPngPngJpeg(wc) @@ -87,10 +88,22 @@ impl SerializedTerrainChunk { } } + pub fn image(chunk: &TerrainChunk) -> Self { + if let Some(wc) = + WireChonk::from_chonk(QuadPngEncoding(), TallPacking { flip_y: true }, chunk) + { + Self::QuadPng(wc) + } else { + warn!("Image encoding failure occurred, falling back to deflate"); + Self::deflate(chunk) + } + } + pub fn to_chunk(&self) -> Option { match self { Self::DeflatedChonk(chonk) => chonk.decompress(), Self::PngPngPngJpeg(wc) => wc.to_chonk(), + Self::QuadPng(wc) => wc.to_chonk(), } } } diff --git a/world/src/bin/chunk_compression_benchmarks.rs b/world/src/bin/chunk_compression_benchmarks.rs index 3c57338c5f..3f1ed380c1 100644 --- a/world/src/bin/chunk_compression_benchmarks.rs +++ b/world/src/bin/chunk_compression_benchmarks.rs @@ -1,16 +1,15 @@ use common::{ spiral::Spiral2d, terrain::{chonk::Chonk, Block, BlockKind, SpriteKind}, - vol::{BaseVol, IntoVolIterator, ReadVol, RectVolSize, SizedVol, WriteVol}, + vol::{IntoVolIterator, RectVolSize, SizedVol, WriteVol}, volumes::{ dyna::{Access, ColumnAccess, Dyna}, vol_grid_2d::VolGrid2d, }, }; use common_net::msg::compression::{ - image_terrain, image_terrain_chonk, image_terrain_volgrid, CompressedData, GridLtrPacking, - JpegEncoding, MixedEncoding, PackingFormula, PngEncoding, QuadPngEncoding, TallPacking, - VoxelImageEncoding, + image_terrain_chonk, image_terrain_volgrid, CompressedData, GridLtrPacking, JpegEncoding, + MixedEncoding, PngEncoding, QuadPngEncoding, TallPacking, VoxelImageEncoding, }; use hashbrown::HashMap; use image::ImageBuffer; @@ -329,8 +328,8 @@ fn main() { )); for (sitename, sitepos) in sites.iter() { - let mut totals = [0.0; 13]; - let mut total_timings = [0.0; 10]; + let mut totals = [0.0; 15]; + let mut total_timings = [0.0; 12]; let mut count = 0; let mut volgrid = VolGrid2d::new().unwrap(); for (i, spiralpos) in Spiral2d::new() @@ -420,11 +419,32 @@ fn main() { .unwrap(); let mixeddense_post = Instant::now(); - let quadpng_pre = Instant::now(); - let quadpng = - image_terrain_chonk(QuadPngEncoding, TallPacking { flip_y: true }, &chunk) - .unwrap(); - let quadpng_post = Instant::now(); + let quadpngfull_pre = Instant::now(); + let quadpngfull = image_terrain_chonk( + QuadPngEncoding::<1>(), + TallPacking { flip_y: true }, + &chunk, + ) + .unwrap(); + let quadpngfull_post = Instant::now(); + + let quadpnghalf_pre = Instant::now(); + let quadpnghalf = image_terrain_chonk( + QuadPngEncoding::<2>(), + TallPacking { flip_y: true }, + &chunk, + ) + .unwrap(); + let quadpnghalf_post = Instant::now(); + + let quadpngquart_pre = Instant::now(); + let quadpngquart = image_terrain_chonk( + QuadPngEncoding::<4>(), + TallPacking { flip_y: true }, + &chunk, + ) + .unwrap(); + let quadpngquart_post = Instant::now(); let pngchonk_pre = Instant::now(); let pngchonk = image_terrain_chonk(PngEncoding, GridLtrPacking, &chunk).unwrap(); @@ -443,7 +463,9 @@ fn main() { mixedchonk.0.len() as f32 / n as f32, mixeddeflate.data.len() as f32 / n as f32, mixeddense.0.len() as f32 / n as f32, - quadpng.data.len() as f32 / n as f32, + quadpngfull.data.len() as f32 / n as f32, + quadpnghalf.data.len() as f32 / n as f32, + quadpngquart.data.len() as f32 / n as f32, pngchonk.len() as f32 / n as f32, ]; let best_idx = sizes @@ -466,7 +488,9 @@ fn main() { (mixedchonk_post - mixedchonk_pre).subsec_nanos(), (mixeddeflate_post - mixedchonk_pre).subsec_nanos(), (mixeddense_post - mixeddense_pre).subsec_nanos(), - (quadpng_post - quadpng_pre).subsec_nanos(), + (quadpngfull_post - quadpngfull_pre).subsec_nanos(), + (quadpnghalf_post - quadpnghalf_pre).subsec_nanos(), + (quadpngquart_post - quadpngquart_pre).subsec_nanos(), (pngchonk_post - pngchonk_pre).subsec_nanos(), ]; trace!( @@ -542,8 +566,10 @@ fn main() { println!("Average mixedchonk: {}", totals[8] / count as f32); println!("Average mixeddeflate: {}", totals[9] / count as f32); println!("Average mixeddense: {}", totals[10] / count as f32); - println!("Average quadpng: {}", totals[11] / count as f32); - println!("Average pngchonk: {}", totals[12] / count as f32); + println!("Average quadpngfull: {}", totals[11] / count as f32); + println!("Average quadpnghalf: {}", totals[12] / count as f32); + println!("Average quadpngquart: {}", totals[13] / count as f32); + println!("Average pngchonk: {}", totals[14] / count as f32); println!(""); println!( "Average lz4_chonk nanos : {:02}", @@ -578,13 +604,21 @@ fn main() { total_timings[7] / count as f32 ); println!( - "Average quadpng nanos: {:02}", + "Average quadpngfull nanos: {:02}", total_timings[8] / count as f32 ); println!( - "Average pngchonk nanos: {:02}", + "Average quadpnghalf nanos: {:02}", total_timings[9] / count as f32 ); + println!( + "Average quadpngquart nanos: {:02}", + total_timings[10] / count as f32 + ); + println!( + "Average pngchonk nanos: {:02}", + total_timings[11] / count as f32 + ); println!("-----"); } if i % 256 == 0 {