cg: headless gpu#567
Conversation
Skip off-screen layers during draw by building a visible-node set from the R-tree frame plan and passing it to new culled-draw methods in Painter. Camera pan/zoom on a 4900-node scene is 67x faster when zoomed in (~1% visible) and 1529x faster when the viewport is empty. - Add draw_layer_list_culled / draw_render_commands_culled to Painter - Build HashSet<NodeId> from FramePlan regions in draw_layers_with_scene_cache - Add viewport_culling correctness tests (3 integration tests) - Add bench_viewport_culling criterion benchmark (5K and 50K nodes)
Add HeadlessGpu for windowless GPU-backed Skia rendering, useful for benchmarks, tests, CLI tools, and future SDK usage. Gated behind the native-gl-context feature flag so cg remains platform-agnostic by default. - Add cg::window::headless module (CGL on macOS, EGL on Linux) - Add headless_gpu example with per-scenario timing stats - Add glutin + raw-window-handle as optional deps behind native-gl-context - Enable native-gl-context in grida-dev
…y culling Use a Vec<bool> indexed by NodeId (sequential u64) instead of HashSet<NodeId> for the per-frame visible-node set. This eliminates hashing overhead and HashMap bucket allocation, giving O(1) array lookups with better cache locality on every draw call.
The R-tree query returns layer indices in arbitrary order. The previous sort ensured Z-order, but with culled drawing the Z-order comes from the command tree traversal, not the index array. The indices are only used to build the visibility bitset and prefill the picture cache, neither of which is order-dependent.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedPull request was closed or merged during review WalkthroughThis PR adds viewport frustum culling optimization to reduce rendering costs for off-screen content, introduces headless GPU rendering capability without a display window, provides benchmarks and tests for validation, and updates the wasm serving environment variable naming. Changes
Sequence Diagram(s)sequenceDiagram
participant Scene
participant FramePlanner
participant Painter
participant LayerRenderer
Scene->>FramePlanner: Compute regions during frame planning
FramePlanner->>FramePlanner: Build visible_ids bitset from intersecting regions
rect rgba(100, 150, 200, 0.5)
Note over Scene,LayerRenderer: Viewport Culling Path (New)
Painter->>Painter: draw_layer_list_culled(layer_list, visible_ids)
Painter->>Painter: Check wireframe mode
alt Culled Raster Path
Painter->>LayerRenderer: draw_render_commands_culled<br/>(skip non-visible by ID)
else Culled Outline Path
Painter->>LayerRenderer: draw_layer_list_outline_culled<br/>(skip non-visible by ID)
end
LayerRenderer-->>Painter: Render only visible content
end
Painter-->>Scene: Frame rendered with off-screen culling
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested labels
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Changed the environment variable from NEXT_PUBLIC_GRIDA_WASM_SERVE_URL to NEXT_PUBLIC_GRIDA_WASM_DEV_SERVE_URL in the .env.example file and updated the locateFile function to use the new variable for local WASM file serving. This change clarifies the purpose of the variable for development environments.
Reverts the draw-time culling introduced in: - feat(cg): viewport culling at draw time - perf(cg): replace HashSet<NodeId> with Vec<bool> bitset for visibility culling - perf(cg): remove unnecessary sort of R-tree indices in frame plan Removes draw_layer_list_culled / draw_render_commands_culled / draw_layer_list_outline_culled from Painter, restores the draw_layer_list call in draw_layers_with_scene_cache, and re-adds the indices.sort() in the frame plan builder for Z-order correctness. Made-with: Cursor
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b11fedc1c6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| .with_context_api(ContextApi::OpenGl(Some(Version::new(3, 3)))) | ||
| .build(None); | ||
| let fallback = ContextAttributesBuilder::new() | ||
| .with_context_api(ContextApi::OpenGl(None)) |
There was a problem hiding this comment.
Fall back to GLES when creating headless EGL context
The fallback context still requests desktop OpenGL (ContextApi::OpenGl(None)), so on Linux/EGL environments that expose only GLES (common in headless CI, containers, and ARM devices) both context-creation attempts fail and HeadlessGpu::new returns an error. The existing native window bootstrap already includes a GLES fallback in crates/grida-dev/src/platform/winit.rs, so this new headless path regresses compatibility in exactly the environments this feature targets.
Useful? React with 👍 / 👎.
| const [path, version] = args; | ||
| if (process.env.NEXT_PUBLIC_GRIDA_WASM_SERVE_URL) { | ||
| return `${process.env.NEXT_PUBLIC_GRIDA_WASM_SERVE_URL}/${path}`; | ||
| if (process.env.NEXT_PUBLIC_GRIDA_WASM_DEV_SERVE_URL) { |
There was a problem hiding this comment.
Preserve legacy WASM serve env var during rename
This rename drops support for NEXT_PUBLIC_GRIDA_WASM_SERVE_URL with no fallback, so any existing environment that still sets the old key will silently stop using its custom WASM host and fall back to localhost/unpkg resolution instead. That can load the wrong binary source at runtime until every deployed environment variable is migrated.
Useful? React with 👍 / 👎.
Summary by CodeRabbit
New Features
Tests & Benchmarks
Chores