From 0e2b06a5606942cba7fcf7763b1f6ea2f49cd5a8 Mon Sep 17 00:00:00 2001 From: Sebastian Bernauer Date: Tue, 11 Jun 2024 16:07:52 +0200 Subject: [PATCH] Finish implementation --- CHANGELOG.md | 1 + README.md | 6 ++++++ breakwater-core/src/lib.rs | 2 +- breakwater-parser/src/original.rs | 1 + breakwater-parser/src/refactored.rs | 25 ++++++++++++++++++++++++- 5 files changed, 33 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f19e6e..4555dc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ### Added +- Support binary protocol ([#XX]) - Try to improve performance by calling `madvise` to inform Kernel we are reading sequentially ([#24]) - Expose metric on denied connection counts ([#26]) - Print nicer error messages ([#32]) diff --git a/README.md b/README.md index 2508baa..cf3fc03 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ Commands must be sent newline-separated, for more details see [Pixelflut](https: * `PX x y rrggbbaa`: Color the pixel (x,y) with the given hexadecimal color rrggbb (alpha channel is ignored for now), e.g. `PX 10 10 ff0000ff` * `PX x y gg`: Color the pixel (x,y) with the hexadecimal color gggggg. Basically this is the same as the other commands, but is a more efficient way of filling white, black or gray areas, e.g. `PX 10 10 00` to paint black * `PX x y`: Get the color value of the pixel (x,y), e.g. `PX 10 10` +* `PBxxyyrgba`: Binary version of the `PX` command. `x` and `y` are little-endian 16 bit coordinates, `r`, `g`, `b` and `a` are a byte each. There is **no** newline after the command. +Tipp: For most use-cases this is the most efficient format with 10 bytes per pixel ;) * `SIZE`: Get the size of the drawing surface, e.g. `SIZE 1920 1080` * `OFFSET x y`: Apply offset (x,y) to all further pixel draws on this connection. This can e.g. be used to pre-calculate an image/animation and simply use the OFFSET command to move it around the screen without the need to re-calculate it, e.g. `OFFSET 100 100` @@ -60,6 +62,8 @@ Options: Height of the drawing surface [default: 720] -f, --fps Frames per second the server should aim for [default: 30] + --network-buffer-size + The size in bytes of the network buffer used for each open TCP connection. Please use at least 64 KB (64_000 bytes) [default: 262144] -t, --text Text to display on the screen. The text will be followed by "on " [default: "Pixelflut server (breakwater)"] --font @@ -78,6 +82,8 @@ Options: Enable dump of video stream into file. File location will be `/pixelflut_dump_{timestamp}.mp4 -v, --vnc-port Port of the VNC server [default: 5900] + -c, --connections-per-ip + Allow only a certain number of connections per ip address -h, --help Print help -V, --version diff --git a/breakwater-core/src/lib.rs b/breakwater-core/src/lib.rs index bcb6e59..e3828e8 100644 --- a/breakwater-core/src/lib.rs +++ b/breakwater-core/src/lib.rs @@ -20,7 +20,7 @@ if cfg!(feature = "alpha") { "PX x y rrggbbaa: Color the pixel (x,y) with the given hexadecimal color rrggbb. The alpha part is discarded for performance reasons, as breakwater was compiled without the alpha feature" }, if cfg!(feature = "binary-commands") { - "PBxxyyrgba: Binary version of the PX command. x and y are little-endian 16 bit coordinates, r, g, b and are a byte each. There is *no* newline after the command.\n" + "PBxxyyrgba: Binary version of the PX command. x and y are little-endian 16 bit coordinates, r, g, b and a are a byte each. There is *no* newline after the command.\n" } else { "" } diff --git a/breakwater-parser/src/original.rs b/breakwater-parser/src/original.rs index a55f8da..801149b 100644 --- a/breakwater-parser/src/original.rs +++ b/breakwater-parser/src/original.rs @@ -152,6 +152,7 @@ impl Parser for OriginalParser { let y = u16::from_le((command_bytes >> 16) as u16); let rgba = u32::from_le((command_bytes >> 32) as u32); + // TODO: Support alpha channel (behind alpha feature flag) self.fb.set(x as usize, y as usize, rgba & 0x00ff_ffff); i += 10; diff --git a/breakwater-parser/src/refactored.rs b/breakwater-parser/src/refactored.rs index 2761145..4bdf336 100644 --- a/breakwater-parser/src/refactored.rs +++ b/breakwater-parser/src/refactored.rs @@ -4,7 +4,8 @@ use breakwater_core::{framebuffer::FrameBuffer, HELP_TEXT}; use crate::{ original::{ - parse_pixel_coordinates, simd_unhex, HELP_PATTERN, OFFSET_PATTERN, PX_PATTERN, SIZE_PATTERN, + parse_pixel_coordinates, simd_unhex, HELP_PATTERN, OFFSET_PATTERN, PB_PATTERN, PX_PATTERN, + SIZE_PATTERN, }, Parser, }; @@ -83,6 +84,24 @@ impl RefactoredParser { } } + #[inline(always)] + fn handle_binary_pixel(&self, buffer: &[u8], mut idx: usize) -> (usize, usize) { + let previous = idx; + idx += 2; + + let command_bytes = unsafe { (buffer.as_ptr().add(idx) as *const u64).read_unaligned() }; + + let x = u16::from_le((command_bytes) as u16); + let y = u16::from_le((command_bytes >> 16) as u16); + let rgba = u32::from_le((command_bytes >> 32) as u32); + + // TODO: Support alpha channel (behind alpha feature flag) + self.fb.set(x as usize, y as usize, rgba & 0x00ff_ffff); + + idx += 8; + (idx, previous) + } + #[inline(always)] fn handle_offset(&mut self, idx: &mut usize, buffer: &[u8]) { let (x, y, present) = parse_pixel_coordinates(buffer.as_ptr(), idx); @@ -185,6 +204,10 @@ impl Parser for RefactoredParser { unsafe { (buffer.as_ptr().add(i) as *const u64).read_unaligned() }; if current_command & 0x00ff_ffff == PX_PATTERN { (i, last_byte_parsed) = self.handle_pixel(buffer, i, response); + } else if cfg!(feature = "binary-commands") + && current_command & 0x0000_ffff == PB_PATTERN + { + (i, last_byte_parsed) = self.handle_binary_pixel(buffer, i); } else if current_command & 0x00ff_ffff_ffff_ffff == OFFSET_PATTERN { i += 7; self.handle_offset(&mut i, buffer);