Merge branch 'master' of github.com:timvisee/pixelpwnr

This commit is contained in:
Tim Visée
2018-02-12 15:58:46 +01:00
8 changed files with 77 additions and 39 deletions

1
Cargo.lock generated
View File

@@ -221,6 +221,7 @@ dependencies = [
"bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]

View File

@@ -7,4 +7,5 @@ authors = ["Tim Visée <timvisee@gmail.com>"]
bufstream = "0.1"
clap = "2.29"
image = "0.18"
num_cpus = "1.8"
regex = "0.2"

View File

@@ -39,11 +39,14 @@ Pixelflut an animated image:
pixelpwnr 127.0.0.1:8080 -i *.png --fps 5 -c 4 -w 400 -h 400 -x 100 -y 100
```
Use the `--help` flag, or see the [help](#help) section for all available
options.
## Installation
For installation, Git and Rust cargo are required.
Install the latest version of Rust with [rustup][rustup].
Then, clone and install pixelpwnr with:
Then, clone and install `pixelpwnr` with:
```bash
# Clone the project
@@ -60,7 +63,7 @@ pixelpwnr --help
cargo run --release -- --help
```
Or just build it and invoke the binary directly:
Or just build it and invoke the binary directly (Linux/macOS):
```bash
# Clone the project
@@ -74,6 +77,28 @@ cargo build --release
./target/release/pixelpwnr --help
```
## Performance & speed optimization
There are many things that affect how quickly pixels can be painted on a
pixelflut server.
Some of them are:
- Size of the image that is drawn.
- Amount of connections used to push pixels.
- Performance of the machine `pixelpwnr` is running on.
- Network interface performance of the client.
- Network interface performance of the server.
- Performance of the pixelflut server.
Things that improve painting performance:
- Use a wired connection.
- Use a LAN connection, closely linked to the pixelflut server. The lower
latency the better, due to the connection being over TCP.
- Use as many threads (`-c` flag) as the server, your connection and your
machine allows.
- Paint a smaller image (`-w`, `-h` flags).
- Paint in an area on the screen, where the least other things are pained.
- Use multiple machines (servers) with multiple `pixelpwnr` instances to push
pixels to the screen.
## Help
```text
pixelpwnr --help
@@ -93,9 +118,9 @@ OPTIONS:
-i, --image <PATH>... Image paths
-w, --width <PIXELS> Draw width (def: screen width)
-h, --height <PIXELS> Draw height (def: screen height)
-x, --x <PIXELS> Draw X offset (def: 0)
-y, --y <PIXELS> Draw Y offset (def: 0)
-c, --count <COUNT> Number of concurrent threads (def: 4)
-x <PIXELS> Draw X offset (def: 0)
-y <PIXELS> Draw Y offset (def: 0)
-c, --count <COUNT> Number of concurrent threads (def: CPUs)
-r, --fps <RATE> Frames per second with multiple images (def: 1)
ARGS:
@@ -110,5 +135,5 @@ Check out the [LICENSE](LICENSE) file for more information.
[34C3]: https://events.ccc.de/congress/2017/wiki/index.php/Main_Page
[pixelflut]: https://cccgoe.de/wiki/Pixelflut
[pixelflut-video]: https://vimeo.com/92827556/
[rust]: https://rust-lang.org/
[rust]: https://www.rust-lang.org/
[rustup]: https://rustup.rs/

19
TODO.md
View File

@@ -1,10 +1,19 @@
# TODO
- Don't draw pixels outside screen.
- Resolve relative paths, or paths with a `~` correctly.
- Add alpha support.
- Do not draw invisible (alpha) pixels.
- Read size from screen.
- Instantly update images in painter threads,
not just when the stopped drawing.
- Process all images at start.
- Combine many pixel messages to improve performance.
- Create a small listening server, to benchmark throughput.
# Further optimizations
- Process and slice all images before starting, don't process them each frame
again.
- Create a pixel map at start, instead of continuously getting pixels from the
image.
- Convert whole image blocks to a single large command string, to push in one
piece to the pixelflut server. Instead of pushing each pixel command
separately.
- Do not draw transparant (alpha) pixels.
- Do not draw pixels outside the screen size.
- Further control buffering in drawing pipes.
- Allow UDP mode (for pixelflut servers that support it).

View File

@@ -4,8 +4,5 @@ pub const APP_VERSION: &'static str = "0.1";
pub const APP_AUTHOR: &'static str = "Tim Visee <timvisee@gmail.com>";
pub const APP_ABOUT: &'static str = "A quick pixelflut client, that pwns pixelflut panels.";
// The default thread count
pub const DEFAULT_THREAD_COUNT: usize = 4;
// The default frames per second rate
pub const DEFAULT_IMAGE_FPS: u32 = 1;

View File

@@ -1,4 +1,5 @@
extern crate clap;
extern crate num_cpus;
use clap::{Arg, ArgMatches, App};
@@ -50,14 +51,12 @@ impl<'a: 'b, 'b> ArgHandler<'a> {
.takes_value(true))
.arg(Arg::with_name("x")
.short("x")
.long("x")
.value_name("PIXELS")
.help("Draw X offset (def: 0)")
.display_order(4)
.takes_value(true))
.arg(Arg::with_name("y")
.short("y")
.long("y")
.value_name("PIXELS")
.help("Draw Y offset (def: 0)")
.display_order(5)
@@ -68,7 +67,7 @@ impl<'a: 'b, 'b> ArgHandler<'a> {
.alias("thread")
.alias("threads")
.value_name("COUNT")
.help("Number of concurrent threads (def: 4)")
.help("Number of concurrent threads (def: CPUs)")
.display_order(6)
.takes_value(true))
.arg(Arg::with_name("fps")
@@ -95,9 +94,10 @@ impl<'a: 'b, 'b> ArgHandler<'a> {
/// Get the thread count.
pub fn count(&self) -> usize {
self.matches.value_of("count")
.unwrap_or(&format!("{}", DEFAULT_THREAD_COUNT))
.parse::<usize>()
.expect("Invalid count specified")
.map(|count| count.parse::<usize>()
.expect("Invalid count specified")
)
.unwrap_or(num_cpus::get())
}
/// Get the image paths.
@@ -112,17 +112,19 @@ impl<'a: 'b, 'b> ArgHandler<'a> {
pub fn size(&self, def: Option<(u32, u32)>) -> (u32, u32) {
(
self.matches.value_of("width")
.unwrap_or(
&format!("{}", def.expect("No screen width set or known").0)
.map(|width| width.parse::<u32>()
.expect("Invalid image width")
)
.parse::<u32>()
.expect("Invalid image width"),
.unwrap_or(
def.expect("No screen width set or known").0
),
self.matches.value_of("height")
.unwrap_or(
&format!("{}", def.expect("No screen height set or known").1)
.map(|height| height.parse::<u32>()
.expect("Invalid image height")
)
.parse::<u32>()
.expect("Invalid image height"),
.unwrap_or(
def.expect("No screen height set or known").1
),
)
}
@@ -130,21 +132,24 @@ impl<'a: 'b, 'b> ArgHandler<'a> {
pub fn offset(&self) -> (u32, u32) {
(
self.matches.value_of("x")
.unwrap_or("0")
.parse::<u32>()
.expect("Invalid X offset"),
.map(|x| x.parse::<u32>()
.expect("Invalid X offset")
)
.unwrap_or(0),
self.matches.value_of("y")
.unwrap_or("0")
.parse::<u32>()
.expect("Invalid Y offset"),
.map(|y| y.parse::<u32>()
.expect("Invalid Y offset")
)
.unwrap_or(0),
)
}
/// Get the FPS.
pub fn fps(&self) -> u32 {
self.matches.value_of("fps")
.unwrap_or(&format!("{}", DEFAULT_IMAGE_FPS))
.parse::<u32>()
.expect("Invalid frames per second rate")
.map(|fps| fps.parse::<u32>()
.expect("Invalid frames per second rate")
)
.unwrap_or(DEFAULT_IMAGE_FPS)
}
}

View File

@@ -1,3 +1,3 @@
// Re-export modules
// Reexport modules
pub mod painter;
pub mod handle;

View File

@@ -1,3 +1,3 @@
// Re-export modules
// Reexport modules
pub mod canvas;
pub mod client;