5 Commits

Author SHA1 Message Date
bl a7112f1577 chore: Release gpupaper version 0.1.1
Release / build (x86_64, ubuntu-latest, x86_64-unknown-linux-gnu) (push) Successful in 6m33s
Release / build (aarch64, aarch64, aarch64-unknown-linux-gnu) (push) Successful in 7m57s
Release / update-aur (push) Failing after 5s
2026-06-09 15:04:32 +02:00
bl ac417dc0d7 Use per-adapter limits for device creation; bump wgpu to 29.0.3
Query each adapter's actual limits via adapter.limits() instead of the
  conservative downlevel_defaults(), and drop the redundant surface
  reconfigure on Suboptimal (the texture is still valid to present).
2026-06-09 15:02:10 +02:00
bl cdc23926a5 Delete duplicate release assets before upload to keep re-runs idempotent
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 14:03:53 +02:00
bl 46cf53f6c6 add glpaper as a reference in readme 2026-06-09 11:26:02 +02:00
bl cd305b00a3 added readme 2026-06-09 11:16:47 +02:00
6 changed files with 207 additions and 78 deletions
+11
View File
@@ -74,6 +74,17 @@ jobs:
| jq -r '.id')
for FILE in "${{ env.TARBALL }}" "${{ env.TARBALL }}.sha256"; do
# Remove any existing asset with the same name so re-runs stay clean
EXISTING=$(curl -s \
-H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
"${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/releases/${RELEASE_ID}/assets" \
| jq -r ".[] | select(.name == \"${FILE}\") | .id")
for AID in $EXISTING; do
curl -sX DELETE \
-H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
"${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}/releases/${RELEASE_ID}/assets/${AID}"
done
curl -sX POST \
-H "Authorization: token ${{ secrets.GITEA_TOKEN }}" \
-H "Content-Type: application/octet-stream" \
Generated
+63 -63
View File
@@ -99,9 +99,9 @@ dependencies = [
[[package]]
name = "autocfg"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]]
name = "bit-set"
@@ -120,9 +120,9 @@ checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51"
[[package]]
name = "bitflags"
version = "2.11.1"
version = "2.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
[[package]]
name = "block2"
@@ -135,9 +135,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.20.2"
version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "bytemuck"
@@ -186,9 +186,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.61"
version = "1.2.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d"
checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -473,7 +473,7 @@ dependencies = [
[[package]]
name = "gpupaper"
version = "0.1.0"
version = "0.1.1"
dependencies = [
"anyhow",
"bytemuck",
@@ -523,9 +523,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.17.0"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]]
name = "heck"
@@ -552,7 +552,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
"hashbrown 0.17.0",
"hashbrown 0.17.1",
]
[[package]]
@@ -563,9 +563,9 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
[[package]]
name = "jiff"
version = "0.2.24"
version = "0.2.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f00b5dbd620d61dfdcb6007c9c1f6054ebd75319f163d886a9055cec1155073d"
checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102"
dependencies = [
"jiff-static",
"log",
@@ -576,9 +576,9 @@ dependencies = [
[[package]]
name = "jiff-static"
version = "0.2.24"
version = "0.2.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e000de030ff8022ea1da3f466fbb0f3a809f5e51ed31f6dd931c35181ad8e6d7"
checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47"
dependencies = [
"proc-macro2",
"quote",
@@ -615,13 +615,12 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.95"
version = "0.3.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca"
checksum = "f2025f20d7a4fa7785846e7b63d10a76d3f1cee98ee5cb79ea59703f95e42162"
dependencies = [
"cfg-if",
"futures-util",
"once_cell",
"wasm-bindgen",
]
@@ -687,15 +686,15 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.29"
version = "0.4.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
[[package]]
name = "memchr"
version = "2.8.0"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
[[package]]
name = "memmap2"
@@ -708,9 +707,9 @@ dependencies = [
[[package]]
name = "naga"
version = "29.0.1"
version = "29.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa2630921705b9b01dcdd0b6864b9562ca3c1951eecd0f0c4f5f04f61e412647"
checksum = "0dd91265cc2454558f659b3b4b9640f0ddb8cc6521277f166b8a8c181c898079"
dependencies = [
"arrayvec",
"bit-set",
@@ -931,15 +930,15 @@ dependencies = [
[[package]]
name = "profiling"
version = "1.0.17"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5"
[[package]]
name = "quick-xml"
version = "0.39.2"
version = "0.39.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "958f21e8e7ceb5a1aa7fa87fab28e7c75976e0bfe7e23ff069e0a260f894067d"
checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e"
dependencies = [
"memchr",
]
@@ -1090,9 +1089,9 @@ dependencies = [
[[package]]
name = "shlex"
version = "1.3.0"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
[[package]]
name = "slab"
@@ -1255,9 +1254,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "wasm-bindgen"
version = "0.2.118"
version = "0.2.123"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89"
checksum = "a254a4b10c19a76f09a27640e7ffbf9bc30bf67e16a3bf28aaefa4920fe81563"
dependencies = [
"cfg-if",
"once_cell",
@@ -1268,9 +1267,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.68"
version = "0.4.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8"
checksum = "54568702fabf5d4849ce2b90fadfa64168a097eaf4b351ce9df8b687a0086aaf"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -1278,9 +1277,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.118"
version = "0.2.123"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed"
checksum = "24a40fc75b0ec6f3746ceb10d36f53a93dcd68a93b11b6445983945d79eba0dc"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -1288,9 +1287,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.118"
version = "0.2.123"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904"
checksum = "908f34bd9b9ce3d4caf07b72dfab63d61504d156856c6bd3cd87fa350cf3985b"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -1301,9 +1300,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.118"
version = "0.2.123"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129"
checksum = "7acbf7616c27b194bbb550bf77ed0c2c3e5b7fd1260a93082b95fb7f47959b92"
dependencies = [
"unicode-ident",
]
@@ -1432,9 +1431,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.95"
version = "0.3.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d"
checksum = "6e0871acf327f283dc6da28a1696cdc64fb355ba9f935d052021fa77f35cce69"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -1442,9 +1441,9 @@ dependencies = [
[[package]]
name = "wgpu"
version = "29.0.1"
version = "29.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72c239a9a747bbd379590985bac952c2e53cb19873f7072b3370c6a6a8e06837"
checksum = "bb3feacc458f7bee8bc1737149b42b6c731aa461039a4264a67bb6681646b250"
dependencies = [
"arrayvec",
"bitflags",
@@ -1472,9 +1471,9 @@ dependencies = [
[[package]]
name = "wgpu-core"
version = "29.0.1"
version = "29.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e80ac6cf1895df6342f87d975162108f9d98772a0d74bc404ab7304ac29469e"
checksum = "02da3ad1b568337f25513b317870960ef87073ea0945502e44b864b67a8c77b7"
dependencies = [
"arrayvec",
"bit-set",
@@ -1505,36 +1504,36 @@ dependencies = [
[[package]]
name = "wgpu-core-deps-apple"
version = "29.0.0"
version = "29.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43acd053312501689cd92a01a9638d37f3e41a5fd9534875efa8917ee2d11ac0"
checksum = "62e51b5447e144b3dbba4feb01f80f4fa21696fa0cd99afb2c3df1affd6fdb28"
dependencies = [
"wgpu-hal",
]
[[package]]
name = "wgpu-core-deps-emscripten"
version = "29.0.0"
version = "29.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef043bf135cc68b6f667c55ff4e345ce2b5924d75bad36a47921b0287ca4b24a"
checksum = "3487cd6293a963bc5c0c0396f6a2192043c50003c07f4efdccbad3d90ec9d819"
dependencies = [
"wgpu-hal",
]
[[package]]
name = "wgpu-core-deps-windows-linux-android"
version = "29.0.0"
version = "29.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "725d5c006a8c02967b6d93ef04f6537ec4593313e330cfe86d9d3f946eb90f28"
checksum = "1bfb01076d0aa08b0ba9bd741e178b5cc440f5abe99d9581323a4c8b5d1a1916"
dependencies = [
"wgpu-hal",
]
[[package]]
name = "wgpu-hal"
version = "29.0.1"
version = "29.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89a47aef47636562f3937285af4c44b4b5b404b46577471411cc5313a921da7e"
checksum = "31f8e1a9e7a8512f276f7c62e018c7fa8d60954303fed2e5750114332049193f"
dependencies = [
"android_system_properties",
"arrayvec",
@@ -1581,13 +1580,14 @@ dependencies = [
"wgpu-types",
"windows",
"windows-core",
"windows-result",
]
[[package]]
name = "wgpu-naga-bridge"
version = "29.0.1"
version = "29.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b4684f4410da0cf95a4cb63bb5edaac022461dedb6adf0b64d0d9b5f6890d51"
checksum = "59c654c483f058800972c3645e95388a7eca31bf9fe1933bc20e036588a0be02"
dependencies = [
"naga",
"wgpu-types",
@@ -1595,9 +1595,9 @@ dependencies = [
[[package]]
name = "wgpu-types"
version = "29.0.1"
version = "29.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec2675540fb1a5cfa5ef122d3d5f390e2c75711a0b946410f2d6ac3a0f77d1f6"
checksum = "a9bcc31518a0e9735aefebedb5f7a9ef3ed1c42549c9f4c882fa9060ceaac639"
dependencies = [
"bitflags",
"bytemuck",
@@ -1769,18 +1769,18 @@ checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f"
[[package]]
name = "zerocopy"
version = "0.8.48"
version = "0.8.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9"
checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.48"
version = "0.8.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4"
checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639"
dependencies = [
"proc-macro2",
"quote",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "gpupaper"
version = "0.1.0"
version = "0.1.1"
edition = "2021"
[[bin]]
+122
View File
@@ -0,0 +1,122 @@
# gpupaper
Wayland layer-surface wallpaper runner powered by GLSL/WGSL fragment shaders, built on [wgpu](https://wgpu.rs).
Runs shaders full-screen on one or all monitors as a proper compositor layer surface (via `zwlr-layer-shell-v1`). Supports Vulkan and OpenGL backends, with automatic fallback for drivers that misbehave at device creation (e.g. Mesa V3DV on Raspberry Pi).
## Features
- **GLSL and WGSL shaders** — use `.frag`/`.glsl` for GLSL or `.wgsl` for WGSL
- **ShaderToy-compatible GLSL** — shaders using `mainImage(out vec4, in vec2)` work without modification
- **glpaper-compatible GLSL** — shaders using `void main()` and `gl_FragColor` work as-is
- **Multi-monitor support** — target a specific output by name or use `all` to run on every connected display simultaneously
- **Hotplug** — new outputs are picked up automatically when using `all`
- **Vulkan-first with GL fallback** — prefers discrete Vulkan, falls back gracefully to integrated or GL
- **Layer selection** — place the shader on any compositor layer: `background`, `bottom`, `top`, or `overlay`
- **FPS cap** — optionally limit frame rate; defaults to vsync
## Shader uniforms
The following uniforms are available in all shaders:
| Uniform | Type | Description |
|--------------|---------|------------------------------------|
| `time` | `float` | Seconds since program start |
| `resolution` | `vec2` | Output dimensions in pixels |
| `mouse` | `vec2` | Mouse position (currently `0,0`) |
**WGSL** shaders receive these via a uniform buffer:
```wgsl
struct Uniforms {
time: f32,
_pad: f32,
resolution: vec2<f32>,
mouse: vec2<f32>,
}
@group(0) @binding(0) var<uniform> u: Uniforms;
```
**GLSL** shaders can declare them as bare `uniform` variables — gpupaper strips those declarations and injects the UBO automatically, so existing ShaderToy-style shaders need no changes.
## Usage
```
gpupaper <output> <shader_file> [--fps <n>] [--layer <layer>]
```
| Argument | Description |
|-----------------|----------------------------------------------------------------|
| `<output>` | Wayland output name (e.g. `HDMI-A-1`) or `all` / `*` |
| `<shader_file>` | Path to a `.frag`, `.glsl`, or `.wgsl` shader file |
| `--fps <n>` | Target frame rate; `0` = vsync (default) |
| `--layer` | Compositor layer: `background` (default), `bottom`, `top`, `overlay` |
**Examples:**
```bash
# Run on all outputs, vsync
gpupaper all /usr/share/gpupaper/shaders/wave.frag
# Run on a specific monitor, capped at 30 fps
gpupaper DP-1 ~/shaders/my_shader.frag --fps 30
# Run on the bottom layer (above wallpaper managers that use background)
gpupaper all /usr/share/gpupaper/shaders/fireflies.frag --layer bottom
```
Output names can be found with `wlr-randr`, `hyprctl monitors`, or `wayland-info`.
## Bundled shaders
A collection of example shaders is installed to `/usr/share/gpupaper/shaders/`:
`black_hole` · `building` · `cloud` · `cloudninja` · `cubes` · `fireflies` · `firering` ·
`flags` · `fluid_spiral` · `green_lines` · `light_line` · `light_wave` · `matrix` · `mickey` ·
`rainbow_donut` · `rainbow_lights` · `rainbow_ring` · `rainbow_triangle` · `red_lines` ·
`slinky` · `snake_torus` · `space` · `spiral` · `torus` · `trippy_cube` · `tunnel` ·
`twisty` · `water` · `wave` · `white_hole` · `yellow_lines`
## Installation
### Arch Linux (AUR)
Binary package for `x86_64` and `aarch64` (no build dependencies required):
```bash
yay -S gpupaper
```
Or build from source:
```bash
yay -S gpupaper-git
```
### From source
Dependencies: Rust stable, `libwayland`, `libxkbcommon`, `pkg-config`
```bash
cargo build --release
./target/release/gpupaper --help
```
## Compatibility
| Platform | Backend | Notes |
|-----------------------|-----------------|-----------------------------------------|
| AMD / Intel (desktop) | Vulkan | |
| NVIDIA | Vulkan | Requires `nvidia-utils` |
| Raspberry Pi 4/5 | OpenGL (EGL) | V3DV Vulkan driver skipped automatically|
| Most other hardware | Vulkan or GL | Whichever wgpu can initialise first |
Requires a Wayland compositor that implements `zwlr-layer-shell-v1` (Sway, Hyprland, river, labwc, and most wlroots-based compositors).
## Acknowledgements
Inspired by [glpaper](https://hg.sr.ht/~scoopta/glpaper) by Scoopta. gpupaper extends the concept with multi-monitor support, WGSL, a wgpu backend, and compatibility with both glpaper-style and ShaderToy-style GLSL shaders.
## License
MIT
+1 -1
View File
@@ -1,6 +1,6 @@
# Maintainer: Bendik Aagaard Lynghaug <bendik.lynghaug@gmail.com>
pkgname=gpupaper
pkgver=0.1.0
pkgver=0.1.1
pkgrel=1
pkgdesc="Wayland layer-surface wallpaper runner powered by GLSL/WGSL fragment shaders (wgpu)"
arch=('x86_64' 'aarch64')
+9 -13
View File
@@ -139,17 +139,16 @@ impl GpuContext {
anyhow::bail!("no wgpu adapters found");
}
let device_desc = wgpu::DeviceDescriptor {
label: Some("gpupaper"),
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_defaults(),
memory_hints: wgpu::MemoryHints::default(),
experimental_features: Default::default(),
trace: Default::default(),
};
let mut selected: Option<(wgpu::Adapter, wgpu::Device, wgpu::Queue)> = None;
for adapter in &candidates {
let device_desc = wgpu::DeviceDescriptor {
label: Some("gpupaper"),
required_features: wgpu::Features::empty(),
required_limits: adapter.limits(),
memory_hints: wgpu::MemoryHints::default(),
experimental_features: Default::default(),
trace: Default::default(),
};
let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
pollster::block_on(adapter.request_device(&device_desc))
}));
@@ -415,10 +414,7 @@ impl SurfaceRenderer {
let surface_texture = match self.surface.get_current_texture() {
wgpu::CurrentSurfaceTexture::Success(t) => t,
wgpu::CurrentSurfaceTexture::Suboptimal(t) => {
self.surface.configure(&gpu.device, &self.surface_config);
t
}
wgpu::CurrentSurfaceTexture::Suboptimal(t) => t,
wgpu::CurrentSurfaceTexture::Lost | wgpu::CurrentSurfaceTexture::Outdated => {
self.surface.configure(&gpu.device, &self.surface_config);
return false;