Merge branch 'master' of github.com:timvisee/pixelpwnr
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -221,6 +221,7 @@ dependencies = [
|
|||||||
"bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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)",
|
"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)",
|
"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)",
|
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ authors = ["Tim Visée <timvisee@gmail.com>"]
|
|||||||
bufstream = "0.1"
|
bufstream = "0.1"
|
||||||
clap = "2.29"
|
clap = "2.29"
|
||||||
image = "0.18"
|
image = "0.18"
|
||||||
|
num_cpus = "1.8"
|
||||||
regex = "0.2"
|
regex = "0.2"
|
||||||
|
|||||||
37
README.md
37
README.md
@@ -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
|
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
|
## Installation
|
||||||
For installation, Git and Rust cargo are required.
|
For installation, Git and Rust cargo are required.
|
||||||
Install the latest version of Rust with [rustup][rustup].
|
Install the latest version of Rust with [rustup][rustup].
|
||||||
|
|
||||||
Then, clone and install pixelpwnr with:
|
Then, clone and install `pixelpwnr` with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Clone the project
|
# Clone the project
|
||||||
@@ -60,7 +63,7 @@ pixelpwnr --help
|
|||||||
cargo run --release -- --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
|
```bash
|
||||||
# Clone the project
|
# Clone the project
|
||||||
@@ -74,6 +77,28 @@ cargo build --release
|
|||||||
./target/release/pixelpwnr --help
|
./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
|
## Help
|
||||||
```text
|
```text
|
||||||
pixelpwnr --help
|
pixelpwnr --help
|
||||||
@@ -93,9 +118,9 @@ OPTIONS:
|
|||||||
-i, --image <PATH>... Image paths
|
-i, --image <PATH>... Image paths
|
||||||
-w, --width <PIXELS> Draw width (def: screen width)
|
-w, --width <PIXELS> Draw width (def: screen width)
|
||||||
-h, --height <PIXELS> Draw height (def: screen height)
|
-h, --height <PIXELS> Draw height (def: screen height)
|
||||||
-x, --x <PIXELS> Draw X offset (def: 0)
|
-x <PIXELS> Draw X offset (def: 0)
|
||||||
-y, --y <PIXELS> Draw Y offset (def: 0)
|
-y <PIXELS> Draw Y offset (def: 0)
|
||||||
-c, --count <COUNT> Number of concurrent threads (def: 4)
|
-c, --count <COUNT> Number of concurrent threads (def: CPUs)
|
||||||
-r, --fps <RATE> Frames per second with multiple images (def: 1)
|
-r, --fps <RATE> Frames per second with multiple images (def: 1)
|
||||||
|
|
||||||
ARGS:
|
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
|
[34C3]: https://events.ccc.de/congress/2017/wiki/index.php/Main_Page
|
||||||
[pixelflut]: https://cccgoe.de/wiki/Pixelflut
|
[pixelflut]: https://cccgoe.de/wiki/Pixelflut
|
||||||
[pixelflut-video]: https://vimeo.com/92827556/
|
[pixelflut-video]: https://vimeo.com/92827556/
|
||||||
[rust]: https://rust-lang.org/
|
[rust]: https://www.rust-lang.org/
|
||||||
[rustup]: https://rustup.rs/
|
[rustup]: https://rustup.rs/
|
||||||
|
|||||||
19
TODO.md
19
TODO.md
@@ -1,10 +1,19 @@
|
|||||||
# TODO
|
# TODO
|
||||||
- Don't draw pixels outside screen.
|
- Resolve relative paths, or paths with a `~` correctly.
|
||||||
- Add alpha support.
|
- Add alpha support.
|
||||||
- Do not draw invisible (alpha) pixels.
|
|
||||||
- Read size from screen.
|
|
||||||
- Instantly update images in painter threads,
|
- Instantly update images in painter threads,
|
||||||
not just when the stopped drawing.
|
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.
|
- 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).
|
||||||
|
|||||||
@@ -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_AUTHOR: &'static str = "Tim Visee <timvisee@gmail.com>";
|
||||||
pub const APP_ABOUT: &'static str = "A quick pixelflut client, that pwns pixelflut panels.";
|
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
|
// The default frames per second rate
|
||||||
pub const DEFAULT_IMAGE_FPS: u32 = 1;
|
pub const DEFAULT_IMAGE_FPS: u32 = 1;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
extern crate clap;
|
extern crate clap;
|
||||||
|
extern crate num_cpus;
|
||||||
|
|
||||||
use clap::{Arg, ArgMatches, App};
|
use clap::{Arg, ArgMatches, App};
|
||||||
|
|
||||||
@@ -50,14 +51,12 @@ impl<'a: 'b, 'b> ArgHandler<'a> {
|
|||||||
.takes_value(true))
|
.takes_value(true))
|
||||||
.arg(Arg::with_name("x")
|
.arg(Arg::with_name("x")
|
||||||
.short("x")
|
.short("x")
|
||||||
.long("x")
|
|
||||||
.value_name("PIXELS")
|
.value_name("PIXELS")
|
||||||
.help("Draw X offset (def: 0)")
|
.help("Draw X offset (def: 0)")
|
||||||
.display_order(4)
|
.display_order(4)
|
||||||
.takes_value(true))
|
.takes_value(true))
|
||||||
.arg(Arg::with_name("y")
|
.arg(Arg::with_name("y")
|
||||||
.short("y")
|
.short("y")
|
||||||
.long("y")
|
|
||||||
.value_name("PIXELS")
|
.value_name("PIXELS")
|
||||||
.help("Draw Y offset (def: 0)")
|
.help("Draw Y offset (def: 0)")
|
||||||
.display_order(5)
|
.display_order(5)
|
||||||
@@ -68,7 +67,7 @@ impl<'a: 'b, 'b> ArgHandler<'a> {
|
|||||||
.alias("thread")
|
.alias("thread")
|
||||||
.alias("threads")
|
.alias("threads")
|
||||||
.value_name("COUNT")
|
.value_name("COUNT")
|
||||||
.help("Number of concurrent threads (def: 4)")
|
.help("Number of concurrent threads (def: CPUs)")
|
||||||
.display_order(6)
|
.display_order(6)
|
||||||
.takes_value(true))
|
.takes_value(true))
|
||||||
.arg(Arg::with_name("fps")
|
.arg(Arg::with_name("fps")
|
||||||
@@ -95,9 +94,10 @@ impl<'a: 'b, 'b> ArgHandler<'a> {
|
|||||||
/// Get the thread count.
|
/// Get the thread count.
|
||||||
pub fn count(&self) -> usize {
|
pub fn count(&self) -> usize {
|
||||||
self.matches.value_of("count")
|
self.matches.value_of("count")
|
||||||
.unwrap_or(&format!("{}", DEFAULT_THREAD_COUNT))
|
.map(|count| count.parse::<usize>()
|
||||||
.parse::<usize>()
|
|
||||||
.expect("Invalid count specified")
|
.expect("Invalid count specified")
|
||||||
|
)
|
||||||
|
.unwrap_or(num_cpus::get())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the image paths.
|
/// Get the image paths.
|
||||||
@@ -112,17 +112,19 @@ impl<'a: 'b, 'b> ArgHandler<'a> {
|
|||||||
pub fn size(&self, def: Option<(u32, u32)>) -> (u32, u32) {
|
pub fn size(&self, def: Option<(u32, u32)>) -> (u32, u32) {
|
||||||
(
|
(
|
||||||
self.matches.value_of("width")
|
self.matches.value_of("width")
|
||||||
.unwrap_or(
|
.map(|width| width.parse::<u32>()
|
||||||
&format!("{}", def.expect("No screen width set or known").0)
|
.expect("Invalid image width")
|
||||||
)
|
)
|
||||||
.parse::<u32>()
|
.unwrap_or(
|
||||||
.expect("Invalid image width"),
|
def.expect("No screen width set or known").0
|
||||||
|
),
|
||||||
self.matches.value_of("height")
|
self.matches.value_of("height")
|
||||||
.unwrap_or(
|
.map(|height| height.parse::<u32>()
|
||||||
&format!("{}", def.expect("No screen height set or known").1)
|
.expect("Invalid image height")
|
||||||
)
|
)
|
||||||
.parse::<u32>()
|
.unwrap_or(
|
||||||
.expect("Invalid image height"),
|
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) {
|
pub fn offset(&self) -> (u32, u32) {
|
||||||
(
|
(
|
||||||
self.matches.value_of("x")
|
self.matches.value_of("x")
|
||||||
.unwrap_or("0")
|
.map(|x| x.parse::<u32>()
|
||||||
.parse::<u32>()
|
.expect("Invalid X offset")
|
||||||
.expect("Invalid X offset"),
|
)
|
||||||
|
.unwrap_or(0),
|
||||||
self.matches.value_of("y")
|
self.matches.value_of("y")
|
||||||
.unwrap_or("0")
|
.map(|y| y.parse::<u32>()
|
||||||
.parse::<u32>()
|
.expect("Invalid Y offset")
|
||||||
.expect("Invalid Y offset"),
|
)
|
||||||
|
.unwrap_or(0),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the FPS.
|
/// Get the FPS.
|
||||||
pub fn fps(&self) -> u32 {
|
pub fn fps(&self) -> u32 {
|
||||||
self.matches.value_of("fps")
|
self.matches.value_of("fps")
|
||||||
.unwrap_or(&format!("{}", DEFAULT_IMAGE_FPS))
|
.map(|fps| fps.parse::<u32>()
|
||||||
.parse::<u32>()
|
|
||||||
.expect("Invalid frames per second rate")
|
.expect("Invalid frames per second rate")
|
||||||
|
)
|
||||||
|
.unwrap_or(DEFAULT_IMAGE_FPS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
// Re-export modules
|
// Reexport modules
|
||||||
pub mod painter;
|
pub mod painter;
|
||||||
pub mod handle;
|
pub mod handle;
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
// Re-export modules
|
// Reexport modules
|
||||||
pub mod canvas;
|
pub mod canvas;
|
||||||
pub mod client;
|
pub mod client;
|
||||||
|
|||||||
Reference in New Issue
Block a user