Tile-level RLE

This commit is contained in:
Pyrex 2024-04-07 20:49:03 -07:00
parent 4edf6831d0
commit 90d1c5c4ef
3 changed files with 63 additions and 8 deletions

View File

@ -11,6 +11,7 @@ struct CoefTile {
coefs: [i16; TILE_SZ2]
}
#[derive(Clone, Copy)]
struct QuantTile {
quants: [i16; TILE_SZ2]
}
@ -53,8 +54,10 @@ pub fn compress<W: Write>(
for t in tiles.iter() {
t.write_zero(writer)?;
}
for t in tiles.iter() {
t.write_rest(writer)?;
for ti in 0..tiles.len() {
let prev = if ti > 0 { Some(tiles[ti - 1]) } else { None };
let t = tiles[ti];
t.write_rest(prev, writer)?;
}
Ok(())
@ -116,9 +119,28 @@ impl QuantTile {
Ok(())
}
fn write_rest<W: Write>(&self, writer: &mut ProtocolWriter<W>) -> ProtocolWriterResult<()> {
for i in 1..self.quants.len() {
fn write_rest<W: Write>(&self, prev: Option<QuantTile>, writer: &mut ProtocolWriter<W>) -> ProtocolWriterResult<()> {
if let Some(p) = prev {
if self.quants[1..] == p.quants[1..] {
// 255 zeroes can also encode "copy the rest from the previous tile"
writer.write_u8_wide(0xff)?;
return Ok(());
}
}
let mut i = 0;
loop {
let mut zeros: u8 = 0;
while i < TILE_SZ2 && self.quants[i] == 0 {
zeros += 1;
i += 1;
}
writer.write_u8_wide(zeros)?;
if i >= TILE_SZ2 { break; }
writer.write_i16_packed(self.quants[i])?;
i += 1;
}
Ok(())
}

View File

@ -12,7 +12,7 @@ struct CoefTile {
coefs: [i16; TILE_SZ2]
}
#[derive(Clone)]
#[derive(Clone, Copy)]
struct QuantTile {
quants: [i16; TILE_SZ2]
}
@ -42,7 +42,11 @@ pub fn decompress<R: Read>(
tiles[i].load_zero(reader)?;
}
for i in 0..n_tiles {
tiles[i].load_rest(reader)?;
let prev = if i > 0 { Some(tiles[i - 1]) } else { None };
tiles[i].load_rest(
prev,
reader
)?;
}
let mut tile_i = 0;
@ -120,10 +124,28 @@ impl QuantTile {
Ok(())
}
fn load_rest<R: Read>(&mut self, reader: &mut ProtocolReader<R>) -> ProtocolReaderResult<()> {
for i in 1..self.quants.len() {
self.quants[i] = reader.read_i16_packed()?;
fn load_rest<R: Read>(&
mut self,
prev: Option<QuantTile>,
reader: &mut ProtocolReader<R>
) -> ProtocolReaderResult<()> {
let mut i: usize = 0;
loop {
let cmd = reader.read_u8_wide()? as usize;
if let Some(p) = prev {
if cmd == 0xff {
self.quants[1..].copy_from_slice(&p.quants[1..]);
return Ok(());
}
}
i += cmd;
if i >= TILE_SZ2 { break; }
self.quants[i] = reader.read_i16_packed()?;
i += 1;
}
Ok(())
}

View File

@ -65,6 +65,10 @@ impl<W: Write> ProtocolWriter<W> {
self.writer.write_all(&value.to_le_bytes())?;
Ok(())
}
pub fn write_u8_wide(&mut self, value: u8) -> ProtocolWriterResult<()> {
self.writer.write_all(&value.to_le_bytes())?;
Ok(())
}
pub fn write_i16_packed(&mut self, value: i16) -> ProtocolWriterResult<()> {
// We reserve i8::MAX and i16::MAX as signal values that `value` is too big
// for each respective type
@ -110,6 +114,13 @@ impl<R: Read> ProtocolReader<R> {
Ok(i16::from_le_bytes(i16_buf))
}
pub fn read_u8_wide(&mut self) -> ProtocolReaderResult<u8> {
let mut u8_buf = [0; 1];
self.read_exact(&mut u8_buf)?;
Ok(u8::from_le_bytes(u8_buf))
}
pub fn read_i16_packed(&mut self) -> ProtocolReaderResult<i16> {
let mut i8_buf = [0; 1];
self.read_exact(&mut i8_buf)?;