Add GPU-accelerated rendering: cpu/gpu/hybrid RenderBackend (Phase 8)
Splits RenderBackend's per-voxel face-visibility extraction and tile shading out as GPU-offloadable steps (wgpu compute shaders), while keeping greedy-mesh merge/compaction CPU-only per the plan's "partial GPU rendering" design. RENDER_BACKEND=cpu|gpu|hybrid selects the strategy, falling back to cpu automatically (logged) if no compatible GPU adapter is found. Verified against a real GPU: all tests pass, including ones asserting byte-identical output between the cpu and gpu backends; a new benchmark example honestly shows cpu currently outperforming gpu/hybrid at realistic batch sizes since each call is its own dispatch/readback round trip rather than batched across a whole render batch (documented as a follow-up optimization). Also fixes two real, pre-existing gaps found while validating the worker's actual `docker build`: a missing .dockerignore was sending the local multi-GB target/ dir into the build context, and the Dockerfile's rust:1.80 pin was already too old for current transitive dependency MSRVs (bumped to rust:1.97). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015tKdPZt78zbPUZMXWzKEKt
This commit is contained in:
@@ -11,12 +11,19 @@ Three independently-deployable services, each its own docker-compose service:
|
||||
|
||||
- `api/` — ElysiaJS on Bun. The I/O layer: WS gateway for mod connections, chat relay, chunk
|
||||
store, marker/waypoint sharing, admin config, region export, tile/mesh serving.
|
||||
- `worker/` — Rust. CPU-bound rendering: tile rasterization and chunk meshing, consumed off a
|
||||
Redis dirty-chunk stream. Stateless — scale it with `docker compose up --scale worker=N`, or
|
||||
run instances on separate hardware pointed at the same Postgres/Redis/MinIO over a private
|
||||
network. Rendering strategy (`cpu`/`gpu`/`hybrid`) is config-selectable behind a
|
||||
`RenderBackend` trait; only `cpu` (rayon) exists so far — `gpu`/`hybrid` (wgpu) land in
|
||||
Phase 8.
|
||||
- `worker/` — Rust. Tile rasterization and chunk meshing, consumed off a Redis dirty-chunk
|
||||
stream. Stateless — scale it with `docker compose up --scale worker=N`, or run instances on
|
||||
separate hardware pointed at the same Postgres/Redis/MinIO over a private network. Rendering
|
||||
strategy is config-selectable (`RENDER_BACKEND=cpu`/`gpu`/`hybrid`, see `worker/.env.example`)
|
||||
behind a `RenderBackend` trait (Phase 8): `cpu` (rayon, default) parallelizes across a whole
|
||||
batch of dirty chunks; `gpu` additionally offloads tile shading and per-voxel
|
||||
face-visibility extraction to a `wgpu` compute shader per chunk/section (greedy-mesh
|
||||
merge/compaction stays CPU-only regardless — sequential/branchy, not GPU-parallel-friendly);
|
||||
`hybrid` offloads only tile shading, keeping meshing on CPU. `gpu`/`hybrid` fall back to `cpu`
|
||||
automatically (logged) if no compatible GPU adapter is found — see `worker/src/render/gpu.rs`'s
|
||||
doc comment for the current known limitation (each tile/section is its own GPU dispatch, so at
|
||||
small batch sizes `cpu` currently outruns `gpu`/`hybrid` — see `cargo run --release --example
|
||||
benchmark`, in `worker/`, for real numbers on your own hardware).
|
||||
- `frontend/` — ElysiaJS + Pug + Tailwind 4 + Alpine.js. The public-facing pages (map viewer,
|
||||
chat, admin panel). Stateless — no DB access, calls `api` for anything server-rendered; the
|
||||
browser's own live map/chat/tile traffic talks to `api` directly, not proxied through here.
|
||||
@@ -117,7 +124,9 @@ map markers with a `show`/hide toggle and an online count, right above the regio
|
||||
## Running tests
|
||||
|
||||
`worker`'s tests (`cargo test`, in `worker/`) are pure unit tests (greedy mesher, tile
|
||||
rasterizer, block-color palette) and need nothing running. `api`'s and `frontend`'s (`bun test`,
|
||||
rasterizer, block-color palette) and need nothing running — including the `gpu`/`hybrid` backend
|
||||
tests (Phase 8), which request a real GPU adapter and skip themselves (rather than failing) if
|
||||
none is found, so `cargo test` still passes on a machine with no GPU. `api`'s and `frontend`'s (`bun test`,
|
||||
in each directory) are integration tests against real infra — start it first:
|
||||
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user