Skip to content

Commit bd7ffe5

Browse files
committed
Merge master into optimize-draw-arrange
2 parents 5d2f719 + 3d327c5 commit bd7ffe5

189 files changed

Lines changed: 8465 additions & 4060 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ jobs:
233233
cp "${src}/renderide" "${dist}/"
234234
cp "${src}/renderide-renderer" "${dist}/"
235235
cp -R "${src}/xr" "${dist}/xr"
236+
cp -R "${src}/shaders" "${dist}/shaders"
236237
case "${PLATFORM}" in
237238
macos-*)
238239
latest_macos_loader_dir=""
@@ -255,7 +256,7 @@ jobs:
255256
import os
256257
from pathlib import Path
257258
258-
files = ["renderide", "renderide-renderer", "xr"]
259+
files = ["renderide", "renderide-renderer", "xr", "shaders"]
259260
if os.environ["PLATFORM"].startswith("macos-"):
260261
files.append("libopenxr_loader.dylib")
261262
manifest = {
@@ -305,11 +306,12 @@ jobs:
305306
Copy-Item "$src/renderide.exe" -Destination $dist
306307
Copy-Item "$src/renderide-renderer.exe" -Destination $dist
307308
Copy-Item "$src/xr" -Destination $dist -Recurse
309+
Copy-Item "$src/shaders" -Destination $dist -Recurse
308310
if (-not (Test-Path "$src/openxr_loader.dll")) {
309311
throw "openxr_loader.dll missing from $src - vendored loader did not copy during build."
310312
}
311313
Copy-Item "$src/openxr_loader.dll" -Destination $dist
312-
$requiredFiles = @("renderide.exe", "renderide-renderer.exe", "xr", "openxr_loader.dll")
314+
$requiredFiles = @("renderide.exe", "renderide-renderer.exe", "xr", "shaders", "openxr_loader.dll")
313315
$sha256 = [ordered]@{}
314316
$distRoot = (Resolve-Path $dist).Path
315317
function Add-FileHash([string]$path) {
@@ -416,7 +418,7 @@ jobs:
416418
echo ""
417419
echo "Nightly build of [${SHA}](https://github.com/${GITHUB_REPOSITORY}/commit/${SHA})."
418420
echo ""
419-
echo "Each zip contains the launcher (\`renderide\`), the renderer (\`renderide-renderer\`), and the XR action manifests. Windows and macOS zips also bundle the Khronos OpenXR loader; Linux uses the system OpenXR loader."
421+
echo "Each zip contains the launcher (\`renderide\`), the renderer (\`renderide-renderer\`), the runtime shader package, and the XR action manifests. Windows and macOS zips also bundle the Khronos OpenXR loader; Linux uses the system OpenXR loader."
420422
echo ""
421423
echo "## Changelog"
422424
echo ""

.gitignore

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -437,8 +437,8 @@ FodyWeavers.xsd
437437

438438
# Generated by Cargo
439439
# will have compiled files and executables
440-
debug
441-
target
440+
/debug/
441+
/target/
442442

443443
# These are backup files generated by rustfmt
444444
**/*.rs.bk
@@ -463,4 +463,4 @@ target
463463
profile.json.gz
464464
!crates/renderide/src/bin/**
465465
*.lscache
466-
config.toml
466+
config.toml

CONTRIBUTING.md

Lines changed: 43 additions & 34 deletions
Large diffs are not rendered by default.

Cargo.toml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,20 @@ members = [
1111
]
1212

1313
[profile.dev]
14-
opt-level = 3
14+
opt-level = 1
1515
incremental = true
1616
codegen-units = 256
17+
debug = "line-tables-only"
1718

1819
# Global Release Build Settings
1920
[profile.release]
20-
debug = true
21-
strip = "debuginfo"
2221
opt-level = 3
22+
incremental = false
23+
codegen-units = 1
24+
debug = "line-tables-only"
25+
strip = "debuginfo"
2326
debug-assertions = false
2427
lto = "thin"
25-
codegen-units = 1
26-
incremental = false
2728
overflow-checks = false
2829

2930

README.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ The launcher will start the Resonite host and connect Renderide automatically.
6262

6363
### macOS
6464

65-
Renderide runs the Resonite Host from the Windows depot and renders natively through Metal. The launcher accepts an explicit Resonite install path, so local builds and release zips should not need hand-written symlinks or `dev-fast` path edits.
65+
Renderide runs the Resonite Host from the Windows depot and renders natively through Metal. The launcher accepts an explicit Resonite install path, so local builds and release zips should not need hand-written symlinks or source edits.
6666

6767
1. Install the Windows Resonite depot with SteamCMD:
6868

@@ -90,7 +90,7 @@ Renderide runs the Resonite Host from the Windows depot and renders natively thr
9090
./renderide --resonite-dir "$HOME/Games/ResoniteWindows"
9191
```
9292

93-
The macOS release zip contains `renderide`, `renderide-renderer`, `xr`, and the bundled OpenXR loader. If macOS quarantine blocks a downloaded zip, remove the quarantine attribute from the extracted Renderide folder:
93+
The macOS release zip contains `renderide`, `renderide-renderer`, `shaders`, `xr`, and the bundled OpenXR loader. If macOS quarantine blocks a downloaded zip, remove the quarantine attribute from the extracted Renderide folder:
9494

9595
```bash
9696
xattr -dr com.apple.quarantine /path/to/renderide-folder
@@ -120,13 +120,14 @@ Bootstrapper --shm queues--> Host (.NET / Resonite)
120120
Renderer (renderide-renderer)
121121
```
122122

123-
Inside the renderer, work is organized by layer:
123+
Inside the renderer, work is organized by layer and supporting renderer subsystems:
124124

125125
1. **App** - owns process bootstrap, logging, config loading, shutdown handling, the winit event loop, frame clock, window target, and OpenXR target selection.
126126
2. **Frontend** - owns Host transport: IPC queues, shared memory, init handshake, input conversion, output-device policy, and lock-step state.
127127
3. **Scene** - owns the host world mirror: transforms, render spaces, mesh and skinned renderables, lights, cameras, and overrides. Pure data; does not touch wgpu.
128-
4. **Backend** - owns GPU-facing renderer state: asset pools, material and shader systems, frame resources, draw preparation, render graph assembly, and command recording.
129-
5. **Runtime** - coordinates frontend, scene, and backend in the fixed per-tick order used by the app driver.
128+
4. **Assets and materials** - translate host payloads and material properties into resident GPU resources, shader routes, reflected bind groups, and pipeline state.
129+
5. **Backend, render graph, and GPU** - own device-facing state, frame resources, world-mesh draw preparation, pass registration, transient/history resources, command recording, and presentation helpers.
130+
6. **Runtime** - coordinates frontend, scene, assets, backend, XR, offscreen tasks, and diagnostics in the fixed per-tick order used by the app driver.
130131

131132
Each tick: poll IPC, integrate a budgeted slice of pending assets, drain offscreen camera/reflection-probe tasks, run the optional OpenXR begin step, complete the lock-step exchange with the host, schedule and render views, present or submit the HMD frame, then update HUD and diagnostics state.
132133

@@ -137,13 +138,13 @@ The workspace lives under `crates/`:
137138
| Crate | Purpose |
138139
| --- | --- |
139140
| [`bootstrapper`](crates/bootstrapper) | Builds the `renderide` launcher. Launches the Resonite host and renderer, owns bootstrap IPC (heartbeats, clipboard, renderer argv), and ties child process lifetimes together. |
140-
| [`renderide`](crates/renderide) | Builds the `renderide-renderer` process and `roundtrip` helper. Owns winit, wgpu, OpenXR, scene mirroring, render graph, materials, assets, diagnostics, and presentation. |
141+
| [`renderide`](crates/renderide) | Builds the `renderide-renderer` process and `roundtrip` helper. Owns winit, wgpu, OpenXR, scene mirroring, asset integration, materials, particles, render graph, diagnostics, and presentation. |
141142
| [`renderide-shared`](crates/renderide-shared) | Generated IPC types, binary packing helpers, shared-memory accessors/writers, and dual-queue wrappers. |
142143
| [`interprocess`](crates/interprocess) | Cloudtoid-compatible shared-memory ring queues used by every IPC channel. |
143144
| [`logger`](crates/logger) | File-first logging used by the bootstrapper, host capture, and renderer. |
144145
| [`renderide-test`](crates/renderide-test) | Integration test harness that drives the renderer end-to-end. |
145146

146-
A C# generator under [`generators/SharedTypeGenerator`](generators/SharedTypeGenerator) emits `crates/renderide-shared/src/shared.rs`. Its test project lives under [`generators/SharedTypeGenerator.Tests`](generators/SharedTypeGenerator.Tests) and uses the `roundtrip` binary to compare C# and Rust packing. [`RenderideMod`](RenderideMod) contains the host-side Resonite mod, and [`third_party/openxr_loader`](third_party/openxr_loader) contains vendored OpenXR loader binaries used by release artifacts on Windows and macOS.
147+
A C# generator under [`generators/SharedTypeGenerator`](generators/SharedTypeGenerator) emits `crates/renderide-shared/src/shared.rs`. Its test project lives under [`generators/SharedTypeGenerator.Tests`](generators/SharedTypeGenerator.Tests) and uses the `roundtrip` binary to compare C# and Rust packing. [`RenderideMod`](RenderideMod) contains the host-side Resonite mod, [`crates/renderide/assets`](crates/renderide/assets) contains runtime XR bindings and the shipped skybox model, and [`third_party/openxr_loader`](third_party/openxr_loader) contains vendored OpenXR loader binaries used by release artifacts on Windows and macOS.
147148

148149
## Feature flags
149150

@@ -152,15 +153,15 @@ The `renderide` crate exposes opt-in Cargo features for capabilities that depend
152153
Multiple features can be combined as a single space-separated argument:
153154

154155
```bash
155-
cargo build --features "tracy video-textures"
156+
cargo build --release --features "tracy video-textures"
156157
```
157158

158159
### `tracy`
159160

160161
CPU and GPU profiling integration. Activates `profiling::scope!` zones, frame marks, and `wgpu-profiler` GPU timestamp queries that stream into the [Tracy](https://github.com/wolfpld/tracy) profiler GUI on port 8086. The Tracy client links statically, so this feature has no system-library prerequisites.
161162

162163
```bash
163-
cargo build --features tracy
164+
cargo build --release --features tracy
164165
```
165166

166167
See [Profiling](#profiling) for adapter requirements and connection details.
@@ -176,7 +177,7 @@ System dependencies:
176177
- **Windows**: the official GStreamer MSVC SDK plus a working `pkg-config` (`pkgconf` rather than `pkgconfiglite`).
177178

178179
```bash
179-
cargo build --features video-textures
180+
cargo build --release --features video-textures
180181
```
181182

182183
## Configuration
@@ -197,7 +198,7 @@ If timestamp queries are unavailable, a warning is logged and Tracy still receiv
197198
### Building with profiling enabled
198199

199200
```bash
200-
cargo build --profile dev-fast --features tracy
201+
cargo build --release --features tracy
201202
```
202203

203204
### Connecting Tracy
@@ -218,7 +219,7 @@ Linux, macOS, and Windows are all tier-1 targets and exercised in CI ([`.github/
218219

219220
## Contributing
220221

221-
Contributions are welcome. The workspace builds with the standard Cargo commands listed above; lints (`cargo clippy --all-targets --all-features`) and formatting (`cargo fmt`, plus `taplo fmt` when editing `Cargo.toml`) are expected to be clean before opening a pull request, and CI runs the same checks across all three platforms.
222+
Contributions are welcome. The workspace builds with the standard Cargo commands listed above; lints (`cargo clippy --all-targets`, with feature coverage matching CI) and formatting (`cargo fmt`, plus `taplo fmt` when editing `Cargo.toml`) are expected to be clean before opening a pull request, and CI runs the same checks across all three platforms.
222223

223224
Read [`CONTRIBUTING.md`](CONTRIBUTING.md) to learn how to get started.
224225

crates/bootstrapper/src/updater/bundle.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -447,23 +447,26 @@ fn decode_hex_32(hex: &str) -> Result<[u8; 32], UpdateError> {
447447

448448
/// Returns the required install entries for a release platform token.
449449
pub(super) fn required_bundle_entries(platform: &str) -> Vec<BundleEntry> {
450-
let mut entries = Vec::with_capacity(5);
450+
let mut entries = Vec::with_capacity(6);
451451
match platform {
452452
"windows-x86_64" | "windows-aarch64" => {
453453
entries.push(BundleEntry::file("renderide.exe", true));
454454
entries.push(BundleEntry::file("renderide-renderer.exe", false));
455455
entries.push(BundleEntry::directory("xr"));
456+
entries.push(BundleEntry::directory("shaders"));
456457
entries.push(BundleEntry::file("openxr_loader.dll", false));
457458
}
458459
"linux-x86_64" | "linux-aarch64" => {
459460
entries.push(BundleEntry::file("renderide", true));
460461
entries.push(BundleEntry::file("renderide-renderer", false));
461462
entries.push(BundleEntry::directory("xr"));
463+
entries.push(BundleEntry::directory("shaders"));
462464
}
463465
"macos-x86_64" | "macos-aarch64" => {
464466
entries.push(BundleEntry::file("renderide", true));
465467
entries.push(BundleEntry::file("renderide-renderer", false));
466468
entries.push(BundleEntry::directory("xr"));
469+
entries.push(BundleEntry::directory("shaders"));
467470
entries.push(BundleEntry::file("libopenxr_loader.dylib", false));
468471
}
469472
_ => {}
@@ -567,7 +570,7 @@ mod tests {
567570
"tag": candidate.tag,
568571
"commit": candidate.commit,
569572
"platform": metadata.platform,
570-
"required_files": ["renderide", "renderide-renderer", "xr"],
573+
"required_files": ["renderide", "renderide-renderer", "xr", "shaders"],
571574
"sha256": {
572575
"renderide": LAUNCHER_SHA256,
573576
"renderide-renderer": RENDERER_SHA256
@@ -611,6 +614,10 @@ mod tests {
611614
|| entry.relative == "renderide-renderer.exe"),
612615
"{platform} should include renderer binary"
613616
);
617+
assert!(
618+
entries.iter().any(|entry| entry.relative == "shaders"),
619+
"{platform} should include runtime shader package"
620+
);
614621
}
615622
}
616623

@@ -619,6 +626,8 @@ mod tests {
619626
fs::write(root.join("renderide-renderer"), b"renderer").expect("write renderer");
620627
fs::create_dir_all(root.join("xr")).expect("create xr");
621628
fs::write(root.join("xr/actions.toml"), xr_actions).expect("write xr actions");
629+
fs::create_dir_all(root.join("shaders")).expect("create shaders");
630+
fs::write(root.join("shaders/shader_manifest.toml"), b"{}").expect("write shader manifest");
622631
}
623632

624633
fn linux_manifest_with_sha256(sha256: serde_json::Value) -> String {
@@ -628,7 +637,7 @@ mod tests {
628637
"tag": "nightly-2026-05-27-2222222",
629638
"commit": "2222222222222222222222222222222222222222",
630639
"platform": "linux-x86_64",
631-
"required_files": ["renderide", "renderide-renderer", "xr"],
640+
"required_files": ["renderide", "renderide-renderer", "xr", "shaders"],
632641
"sha256": sha256
633642
})
634643
.to_string()
@@ -638,7 +647,8 @@ mod tests {
638647
serde_json::json!({
639648
"renderide": LAUNCHER_SHA256,
640649
"renderide-renderer": RENDERER_SHA256,
641-
"xr/actions.toml": EMPTY_JSON_SHA256
650+
"xr/actions.toml": EMPTY_JSON_SHA256,
651+
"shaders/shader_manifest.toml": EMPTY_JSON_SHA256
642652
})
643653
}
644654

@@ -681,6 +691,7 @@ mod tests {
681691
"renderide": LAUNCHER_SHA256,
682692
"renderide-renderer": RENDERER_SHA256,
683693
"xr/actions.toml": EMPTY_JSON_SHA256,
694+
"shaders/shader_manifest.toml": EMPTY_JSON_SHA256,
684695
"renderide-release.json": EMPTY_JSON_SHA256
685696
}));
686697

@@ -695,6 +706,7 @@ mod tests {
695706
"renderide": LAUNCHER_SHA256,
696707
"renderide-renderer": RENDERER_SHA256,
697708
"xr/actions.toml": EMPTY_JSON_SHA256,
709+
"shaders/shader_manifest.toml": EMPTY_JSON_SHA256,
698710
"xr/../escape": EMPTY_JSON_SHA256
699711
}));
700712

crates/bootstrapper/src/updater/install.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,11 +548,12 @@ mod tests {
548548
"tag": UPDATE_TAG,
549549
"commit": UPDATE_COMMIT,
550550
"platform": PLATFORM,
551-
"required_files": ["renderide", "renderide-renderer", "xr"],
551+
"required_files": ["renderide", "renderide-renderer", "xr", "shaders"],
552552
"sha256": {
553553
"renderide": "ec9a6e9fe278eb1a471fbab6f40367d8548078b651d9c71581c57c2a6ca379e0",
554554
"renderide-renderer": "6bd52b204f5b4cffb267597f37d0fa62bae229341394dfec0e5d42439d8b722c",
555-
"xr/actions.json": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a"
555+
"xr/actions.json": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
556+
"shaders/shader_manifest.toml": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a"
556557
}
557558
})
558559
.to_string()
@@ -593,6 +594,7 @@ mod tests {
593594
&archive_path,
594595
&[
595596
TestZipEntry::Directory("xr/"),
597+
TestZipEntry::Directory("shaders/"),
596598
TestZipEntry::File {
597599
name: "renderide-release.json",
598600
contents: manifest.as_bytes(),
@@ -618,6 +620,11 @@ mod tests {
618620
contents: b"{}",
619621
unix_mode: Some(ZIP_REGULAR_FILE_MODE),
620622
},
623+
TestZipEntry::File {
624+
name: "shaders/shader_manifest.toml",
625+
contents: b"{}",
626+
unix_mode: Some(ZIP_REGULAR_FILE_MODE),
627+
},
621628
],
622629
);
623630

@@ -641,6 +648,7 @@ mod tests {
641648
&archive_path,
642649
&[
643650
TestZipEntry::Directory(&format!("{root_name}/xr/")),
651+
TestZipEntry::Directory(&format!("{root_name}/shaders/")),
644652
TestZipEntry::File {
645653
name: &format!("{root_name}/renderide-release.json"),
646654
contents: manifest.as_bytes(),
@@ -666,6 +674,11 @@ mod tests {
666674
contents: b"{}",
667675
unix_mode: Some(ZIP_REGULAR_FILE_MODE),
668676
},
677+
TestZipEntry::File {
678+
name: &format!("{root_name}/shaders/shader_manifest.toml"),
679+
contents: b"{}",
680+
unix_mode: Some(ZIP_REGULAR_FILE_MODE),
681+
},
669682
],
670683
);
671684

crates/interprocess/src/windows_security.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,14 @@ impl CurrentOwnerSecurityAttributes {
3434
.encode_utf16()
3535
.chain(std::iter::once(0))
3636
.collect();
37+
// SAFETY: `sddl` is a valid NUL-terminated UTF-16 string that outlives the call, and
38+
// `descriptor` is a valid out-pointer the API fills with a LocalAlloc'd descriptor that
39+
// `Drop` releases via `LocalFree`.
3740
let ok = unsafe {
3841
ConvertStringSecurityDescriptorToSecurityDescriptorW(
3942
sddl.as_ptr(),
4043
SDDL_REVISION_1,
41-
&mut descriptor,
44+
&raw mut descriptor,
4245
null_mut(),
4346
)
4447
};
@@ -57,14 +60,17 @@ impl CurrentOwnerSecurityAttributes {
5760

5861
/// Pointer passed to Win32 object creation calls.
5962
pub(crate) const fn as_ptr(&self) -> *const SECURITY_ATTRIBUTES {
60-
&self.attrs
63+
&raw const self.attrs
6164
}
6265
}
6366

6467
#[cfg(windows)]
6568
impl Drop for CurrentOwnerSecurityAttributes {
6669
fn drop(&mut self) {
6770
if !self.descriptor.is_null() {
71+
// SAFETY: `descriptor` was allocated by
72+
// `ConvertStringSecurityDescriptorToSecurityDescriptorW`, which documents LocalFree
73+
// as the matching release, and it is freed exactly once here.
6874
unsafe {
6975
LocalFree(self.descriptor.cast());
7076
}

0 commit comments

Comments
 (0)