Skip to content

perf(canvas): AA toggle, GPU sync for benchmarks, AA cost findings#633

Merged
softmarshmallow merged 5 commits intomainfrom
feature/wizardly-shaw
Apr 6, 2026
Merged

perf(canvas): AA toggle, GPU sync for benchmarks, AA cost findings#633
softmarshmallow merged 5 commits intomainfrom
feature/wizardly-shaw

Conversation

@softmarshmallow
Copy link
Copy Markdown
Member

@softmarshmallow softmarshmallow commented Apr 6, 2026

Summary

  • AA toggle on RenderPolicy: force_no_aa field + anti_alias() method. Paint functions accept aa: bool instead of hardcoding true. Bench CLI exposes --no-aa for A/B measurement.
  • GPU sync for benchmarks: sync_gpu config makes gpu_flush() block until GPU completes, fixing per-stage timing accuracy (mid_flush_us was measuring command submission, not GPU execution).
  • Isolated benchmark: skia_bench_subpixel measures AA cost at sub-pixel scale. Finding: AA on sub-pixel geometry is 3.2x more expensive than AA off.
  • Findings doc: docs/wg/feat-2d/aa-cost-findings.md with benchmark data and optimization implications.

Test plan

  • cargo test -p cg — 33 passed
  • cargo check -p cg -p grida-canvas-wasm -p grida-dev — all compile
  • cargo clippy -p cg --no-deps — no new warnings
  • A/B verified: --no-aa produces measurable difference on isolated bench (3.2x at 40K nodes, 0.02x zoom)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Anti-aliasing can be disabled (new CLI flag) and a render-policy toggle exposes no-AA for benchmarks.
    • Added a new Skia GPU microbenchmark example and a renamed “no-cache baseline” zoom scenario for A/B cost comparisons.
    • Optional GPU synchronization added to produce CPU-synced, stable timing measurements.
  • Documentation

    • Added findings on AA performance at sub-pixel scale and benchmark methodology; benchmark scenarios matrix updated.

softmarshmallow and others added 3 commits April 6, 2026 21:25
- Renamed scenarios to remove "BUG" prefix and reflect their purpose as no-cache baselines.
- Updated comments in the code to clarify the intent of passing `stable=true` for full draw measurements.
- Adjusted the Markdown documentation to align with the new scenario naming conventions.
…dings

- Add `force_no_aa` field to `RenderPolicy` with `anti_alias()` method,
  allowing A/B measurement of anti-aliasing cost at different zoom levels.
  Paint functions (`sk_solid_paint`, `sk_paint_stack`,
  `sk_paint_stack_without_images`) now accept an `aa: bool` parameter
  instead of hardcoding `true`.

- Add `sync_gpu` config on `RuntimeRendererConfig`. When enabled,
  `gpu_flush()` calls `flush_submit_and_sync_cpu()` instead of the
  async `flush_and_submit()`, making per-stage timing in
  `FrameFlushStats` reflect actual GPU execution cost. Benchmarks
  (`bench` and `bench-report`) enable this by default.

- Add `--no-aa` flag to the bench CLI for A/B AA cost measurement.

- Add `skia_bench_subpixel` isolated GPU benchmark measuring AA cost
  at sub-pixel scale (0.02x zoom). Key finding: AA on sub-pixel
  geometry is 3.2x more expensive than AA off.

- Add `docs/wg/feat-2d/aa-cost-findings.md` documenting the
  investigation results, including the GPU flush timing discovery.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Apr 6, 2026 7:41pm
6 Skipped Deployments
Project Deployment Actions Updated (UTC)
code Ignored Ignored Apr 6, 2026 7:41pm
legacy Ignored Ignored Apr 6, 2026 7:41pm
backgrounds Skipped Skipped Apr 6, 2026 7:41pm
blog Skipped Skipped Apr 6, 2026 7:41pm
grida Skipped Skipped Apr 6, 2026 7:41pm
viewer Skipped Skipped Apr 6, 2026 7:41pm

Request Review

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e94d7502-b7c6-4f38-ad6d-32cb12cd79c1

📥 Commits

Reviewing files that changed from the base of the PR and between 499281a and 940031e.

📒 Files selected for processing (1)
  • crates/grida-canvas/src/runtime/render_policy.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/grida-canvas/src/runtime/render_policy.rs

Walkthrough

Adds anti-aliasing control and GPU sync to the canvas stack, updates paint helper APIs and their call sites, introduces a GPU-timed Skia microbenchmark example, updates benchmark runner/CLI and scenario naming, and adds documentation of AA cost findings.

Changes

Cohort / File(s) Summary
Paint API & Helpers
crates/grida-canvas/src/painter/paint.rs
Added aa: bool parameter to sk_solid_paint, sk_paint_stack, and sk_paint_stack_without_images; use set_anti_alias(aa) instead of unconditional true.
Painter Call Sites
crates/grida-canvas/src/painter/painter.rs, crates/grida-canvas/src/painter/text_stroke.rs, crates/grida-canvas/src/cache/paragraph.rs, crates/grida-canvas/src/text/attributed_paragraph.rs, crates/grida-canvas/src/vectornetwork/vn_painter.rs, crates/grida-canvas/examples/golden_sk_paints.rs
Propagated new aa argument to paint-stack call sites (mostly self.policy.anti_alias() or true); replaced hardcoded set_anti_alias(true) with policy-driven value.
Render Policy & Runtime Config
crates/grida-canvas/src/runtime/render_policy.rs, crates/grida-canvas/src/runtime/config.rs
Added force_no_aa: bool and anti_alias() to RenderPolicy; added sync_gpu: bool to RuntimeRendererConfig (default false).
Scene & GPU Flush
crates/grida-canvas/src/runtime/scene.rs
Converted gpu_flush to an instance method using self.config.sync_gpu to choose between blocking flush_submit_and_sync_cpu() and non-blocking flush_and_submit(); added set_sync_gpu() setter and updated call sites.
Bench Runner & CLI
crates/grida-dev/src/bench/runner.rs, crates/grida-dev/src/bench/args.rs, .agents/skills/cg-perf/SKILL.md
Added --no-aa CLI flag; renamed zoom scenario kind from zoom_forced_stable to baseline_nocache_zoom; renderer now enables set_sync_gpu(true) during bench runs; updated skill doc scenarios.
Bench Example & Cargo
crates/grida-canvas/Cargo.toml, crates/grida-canvas/examples/skia_bench/skia_bench_subpixel.rs
Added new feature-gated example skia_bench_subpixel (native GL) that records Pictures, runs AA on/off and zoom scenarios, measures timing with optional GPU sync, and prints per-node estimates.
Docs
docs/wg/feat-2d/aa-cost-findings.md
New findings doc summarizing AA vs no-AA GPU costs at sub-pixel zoom, benchmark methodology, and measured results.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    rect rgba(200,200,255,0.5)
    participant CLI
    participant BenchRunner
    participant Renderer
    participant GPU
    end
    CLI->>BenchRunner: start benchmark (args, e.g. --no-aa)
    BenchRunner->>Renderer: init(policy: force_no_aa = args.no_aa)
    BenchRunner->>Renderer: set_sync_gpu(true)
    loop per-scenario
      BenchRunner->>Renderer: render_frame(pics, zoom, aa=policy.anti_alias())
      Renderer->>GPU: submit draw commands
      alt sync_gpu = true
        Renderer->>GPU: flush_submit_and_sync_cpu()  -- blocks until GPU complete
        GPU-->>Renderer: completed
      else
        Renderer->>GPU: flush_and_submit()  -- returns immediately
      end
      Renderer-->>BenchRunner: report elapsed (GPU-synced if enabled)
    end
    BenchRunner->>CLI: print results (AA on/off, baseline_nocache_zoom)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

canvas, documentation, tools

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main changes: adding AA toggle, GPU sync, and documenting findings—matching the primary objectives of the pull request.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/wizardly-shaw

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

# Conflicts:
#	.agents/skills/cg-perf/SKILL.md
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (6)
crates/grida-canvas/src/painter/paint.rs (2)

27-31: Document the new aa parameter in the function's doc comment.

The # Arguments section lists paints, size, and images, but the newly added aa parameter is not documented. Consider adding it for API clarity.

📝 Suggested documentation update
 /// # Arguments
 /// * `paints` - Array of paints to blend together
 /// * `size` - Container size for paint calculations
 /// * `images` - Image repository for image paint resolution
+/// * `aa` - Whether to enable anti-aliasing on the resulting paint
 ///
 /// # Returns
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/grida-canvas/src/painter/paint.rs` around lines 27 - 31, The doc
comment for sk_paint_stack is missing documentation for the new aa parameter;
update the function's Rust doc comment (the /// block above sk_paint_stack) to
add aa under the # Arguments section, describing that aa is a boolean that
toggles anti-aliasing (e.g., true = enable anti-aliasing, false = disable) and
any effects on rendering behavior so callers understand its purpose alongside
paints, size, and images.

87-91: Document the new aa parameter for consistency.

Similar to sk_paint_stack, the # Arguments section should include the aa parameter.

📝 Suggested documentation update
 /// # Arguments
 /// * `paints` - Array of paints to blend together (image paints will be ignored)
 /// * `size` - Container size for paint calculations
+/// * `aa` - Whether to enable anti-aliasing on the resulting paint
 ///
 /// # Returns
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/grida-canvas/src/painter/paint.rs` around lines 87 - 91, The public
function sk_paint_stack_without_images has a new boolean parameter aa that isn't
documented; update its doc comment (the /// doc block above
sk_paint_stack_without_images) to include an entry in the Arguments/# Arguments
section describing aa (e.g., "aa: enable/disable anti-aliasing for the returned
skia_safe::Paint") matching the style and wording used for sk_paint_stack so
docs stay consistent.
crates/grida-canvas/src/text/attributed_paragraph.rs (1)

38-48: Text rendering always uses AA regardless of render policy.

This helper always passes true for anti-aliasing. Unlike shape rendering in painter.rs which uses self.policy.anti_alias(), text will always render with AA enabled—even when force_no_aa is set for benchmarking.

If this is intentional (text quality often requires AA), consider adding a comment explaining the decision. If text should also respect the policy, this function would need to accept an aa parameter.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/grida-canvas/src/text/attributed_paragraph.rs` around lines 38 - 48,
The resolve_fill_paint helper always forces anti-aliasing by passing `true` to
paint_util::sk_paint_stack and paint_util::sk_paint_stack_without_images; update
resolve_fill_paint to accept an `aa: bool` parameter (or a descriptive name like
`anti_alias`) and forward that boolean to those two calls so text respects
rendering policy, then update all callers (text layout/render paths) to pass the
renderer's policy value (e.g., self.policy.anti_alias() or force_no_aa
inversion) instead of hardcoding true; alternatively, if AA-for-text is
intentional, add a clear comment inside resolve_fill_paint explaining why AA is
always enabled.
docs/wg/feat-2d/aa-cost-findings.md (2)

112-116: Consider using a relative link for internal docs reference.

The reference to docs/wg/feat-2d/optimization.md could be a relative link for better navigation within the documentation site:

📝 Proposed change
 ## Related

 - `crates/grida-canvas/examples/skia_bench/skia_bench_subpixel.rs` — isolated benchmark
-- `docs/wg/feat-2d/optimization.md` — master optimization catalog
+- [optimization.md](./optimization.md) — master optimization catalog
 - Chromium pinch-zoom: reduced rasterization quality during interaction
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/wg/feat-2d/aa-cost-findings.md` around lines 112 - 116, Update the
internal docs reference to use a relative link instead of an absolute-looking
path: replace the `docs/wg/feat-2d/optimization.md` entry in the "Related" list
with a relative link such as `./optimization.md` or `../feat-2d/optimization.md`
(choose the correct relative path from the current file's location) so the link
resolves correctly within the docs site; ensure the link text remains
`optimization.md` (or keep the existing descriptive text) and verify it
navigates properly after the change.

1-5: Add format: md frontmatter for MDX compatibility.

Per coding guidelines, documentation files in docs/{wg,reference}/** that don't use JSX/MDX features should include format: md frontmatter to opt out of MDX parsing. This prevents potential build issues with angle brackets or other special characters.

📝 Proposed fix
+---
+format: md
+---
+
 # Anti-Aliasing Cost at Sub-Pixel Scale

 **Date:** 2026-04-07

As per coding guidelines: "For MDX compatibility, add format: md frontmatter to documentation files that don't use JSX/MDX features to opt out of MDX parsing and prevent build issues with angle brackets."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/wg/feat-2d/aa-cost-findings.md` around lines 1 - 5, This markdown
document "Anti-Aliasing Cost at Sub-Pixel Scale" is missing MDX opt-out
frontmatter; add a top-matter block containing format: md (i.e., a frontmatter
section with format: md) to the very top of the file so the MDX parser treats it
as plain Markdown and avoids parsing angle-bracket content, ensuring the new
frontmatter appears before the existing title/header.
crates/grida-canvas/examples/skia_bench/skia_bench_subpixel.rs (1)

135-144: Nitpick: Float equality comparison.

Direct float comparison zoom != 1.0 works here because the values are hardcoded literals (1.0 and 0.02), but it's a minor code smell. A threshold comparison would be more defensive:

💡 Alternative approach
-        if zoom != 1.0 {
+        if (zoom - 1.0).abs() > f32::EPSILON {
             canvas.save();
             canvas.scale((zoom, zoom));
         }
         for pic in pics {
             canvas.draw_picture(pic, None, None);
         }
-        if zoom != 1.0 {
+        if (zoom - 1.0).abs() > f32::EPSILON {
             canvas.restore();
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/grida-canvas/examples/skia_bench/skia_bench_subpixel.rs` around lines
135 - 144, The code uses direct float equality checks `zoom != 1.0` around
canvas.save()/scale() and canvas.restore(); change these to an epsilon-based
comparison (e.g., `(zoom - 1.0).abs() > 1e-6` or use
`f32::EPSILON`/`f64::EPSILON` depending on zoom's type) to defensively detect
when zoom meaningfully differs from 1.0 before calling canvas.scale((zoom,
zoom)), ensuring both the pre-scale conditional and the matching restore check
use the same epsilon comparison.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/grida-canvas/src/painter/painter.rs`:
- Line 350: Helpers are still hardcoding anti-aliasing; update
shadow::draw_drop_shadow, shadow::draw_inner_shadow,
text_stroke::draw_text_stroke, text_stroke::draw_text_stroke_outside_fast_pre to
take an anti_alias: bool (or read PainterPolicy) and call
set_anti_alias(anti_alias) instead of set_anti_alias(true), then propagate that
flag from the caller sites in painter.rs and from VNPainter (add an anti_alias
field or read self.policy.anti_alias()) so all render paths (stroked text,
shadows, vector-network) honor self.policy.anti_alias(); ensure public
signatures and call sites are updated consistently.

In `@crates/grida-canvas/src/runtime/render_policy.rs`:
- Around line 105-107: RenderPolicy's force_no_aa field is not preserved across
the flags bridge; add a bit for force_no_aa to the RenderPolicyFlags
enum/bitflags and update the conversion logic in RenderPolicy::to_flags (or
policy.to_flags()) and RenderPolicy::from_flags so the bit is set when
force_no_aa is true and read back when reconstructing the policy, removing the
hardcoded false that currently appears in the from_flags path.

In `@crates/grida-dev/src/bench/runner.rs`:
- Line 1794: Summary: The serialized "kind" value for ScenarioResult was renamed
from "zoom_forced_stable" to "baseline_nocache_zoom", which is a breaking change
for downstream consumers. Fix: restore backward compatibility by either (a)
reverting the literal back to "zoom_forced_stable" in the assignment that sets
kind, or (b) update ScenarioResult's serde serialization to accept/emit both
names (use serde rename/alias or a custom Serialize/Deserialize impl) so
existing reports still parse; reference the affected symbol "kind" on
ScenarioResult and the serialization logic in report.rs when making the change,
and if the rename is intentional ensure you also bump the package/report format
version and update any CI comparison scripts/tests that depend on the old value.

---

Nitpick comments:
In `@crates/grida-canvas/examples/skia_bench/skia_bench_subpixel.rs`:
- Around line 135-144: The code uses direct float equality checks `zoom != 1.0`
around canvas.save()/scale() and canvas.restore(); change these to an
epsilon-based comparison (e.g., `(zoom - 1.0).abs() > 1e-6` or use
`f32::EPSILON`/`f64::EPSILON` depending on zoom's type) to defensively detect
when zoom meaningfully differs from 1.0 before calling canvas.scale((zoom,
zoom)), ensuring both the pre-scale conditional and the matching restore check
use the same epsilon comparison.

In `@crates/grida-canvas/src/painter/paint.rs`:
- Around line 27-31: The doc comment for sk_paint_stack is missing documentation
for the new aa parameter; update the function's Rust doc comment (the /// block
above sk_paint_stack) to add aa under the # Arguments section, describing that
aa is a boolean that toggles anti-aliasing (e.g., true = enable anti-aliasing,
false = disable) and any effects on rendering behavior so callers understand its
purpose alongside paints, size, and images.
- Around line 87-91: The public function sk_paint_stack_without_images has a new
boolean parameter aa that isn't documented; update its doc comment (the /// doc
block above sk_paint_stack_without_images) to include an entry in the
Arguments/# Arguments section describing aa (e.g., "aa: enable/disable
anti-aliasing for the returned skia_safe::Paint") matching the style and wording
used for sk_paint_stack so docs stay consistent.

In `@crates/grida-canvas/src/text/attributed_paragraph.rs`:
- Around line 38-48: The resolve_fill_paint helper always forces anti-aliasing
by passing `true` to paint_util::sk_paint_stack and
paint_util::sk_paint_stack_without_images; update resolve_fill_paint to accept
an `aa: bool` parameter (or a descriptive name like `anti_alias`) and forward
that boolean to those two calls so text respects rendering policy, then update
all callers (text layout/render paths) to pass the renderer's policy value
(e.g., self.policy.anti_alias() or force_no_aa inversion) instead of hardcoding
true; alternatively, if AA-for-text is intentional, add a clear comment inside
resolve_fill_paint explaining why AA is always enabled.

In `@docs/wg/feat-2d/aa-cost-findings.md`:
- Around line 112-116: Update the internal docs reference to use a relative link
instead of an absolute-looking path: replace the
`docs/wg/feat-2d/optimization.md` entry in the "Related" list with a relative
link such as `./optimization.md` or `../feat-2d/optimization.md` (choose the
correct relative path from the current file's location) so the link resolves
correctly within the docs site; ensure the link text remains `optimization.md`
(or keep the existing descriptive text) and verify it navigates properly after
the change.
- Around line 1-5: This markdown document "Anti-Aliasing Cost at Sub-Pixel
Scale" is missing MDX opt-out frontmatter; add a top-matter block containing
format: md (i.e., a frontmatter section with format: md) to the very top of the
file so the MDX parser treats it as plain Markdown and avoids parsing
angle-bracket content, ensuring the new frontmatter appears before the existing
title/header.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a91e8ea8-f6e2-4753-b222-59fa3bbe9738

📥 Commits

Reviewing files that changed from the base of the PR and between 067c579 and 4f00d22.

📒 Files selected for processing (16)
  • .agents/skills/cg-perf/SKILL.md
  • crates/grida-canvas/Cargo.toml
  • crates/grida-canvas/examples/golden_sk_paints.rs
  • crates/grida-canvas/examples/skia_bench/skia_bench_subpixel.rs
  • crates/grida-canvas/src/cache/paragraph.rs
  • crates/grida-canvas/src/painter/paint.rs
  • crates/grida-canvas/src/painter/painter.rs
  • crates/grida-canvas/src/painter/text_stroke.rs
  • crates/grida-canvas/src/runtime/config.rs
  • crates/grida-canvas/src/runtime/render_policy.rs
  • crates/grida-canvas/src/runtime/scene.rs
  • crates/grida-canvas/src/text/attributed_paragraph.rs
  • crates/grida-canvas/src/vectornetwork/vn_painter.rs
  • crates/grida-dev/src/bench/args.rs
  • crates/grida-dev/src/bench/runner.rs
  • docs/wg/feat-2d/aa-cost-findings.md


let mut p = SkPaint::default();
p.set_anti_alias(true);
p.set_anti_alias(self.policy.anti_alias());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

fd -i -0 'text_stroke\.rs|shadow\.rs|vn_painter\.rs' | while IFS= read -r -d '' f; do
  echo "== $f =="
  rg -n -C2 'fn draw_text_stroke|fn draw_text_stroke_outside_fast_pre|fn draw_drop_shadow|fn draw_inner_shadow|struct VNPainter|impl VNPainter|set_anti_alias' "$f"
done

echo "== call sites from painter =="
rg -n -C2 'draw_text_stroke(_outside_fast_pre)?\(|draw_drop_shadow\(|draw_inner_shadow\(|VNPainter::new_with_images|draw_vector_strokes\(' --type=rust

Repository: gridaco/grida

Length of output: 10121


🏁 Script executed:

# Get full signatures and first 20 lines of each helper function
echo "=== text_stroke.rs functions ==="
sed -n '12,35p' crates/grida-canvas/src/painter/text_stroke.rs
echo ""
sed -n '96,120p' crates/grida-canvas/src/painter/text_stroke.rs

echo ""
echo "=== shadow.rs draw_drop_shadow ==="
sed -n '40,50p' crates/grida-canvas/src/painter/shadow.rs

echo ""
echo "=== shadow.rs draw_inner_shadow ==="
sed -n '90,100p' crates/grida-canvas/src/painter/shadow.rs

echo ""
echo "=== vn_painter.rs struct and impl ==="
sed -n '28,80p' crates/grida-canvas/src/vectornetwork/vn_painter.rs

Repository: gridaco/grida

Length of output: 4478


--no-aa flag is bypassed by helper-driven render paths.

The inline paints in painter.rs now respect self.policy.anti_alias(), but the following helpers still ignore the policy:

  • shadow::draw_drop_shadow() and shadow::draw_inner_shadow() hardcode set_anti_alias(true) and accept no AA parameter
  • text_stroke::draw_text_stroke() and text_stroke::draw_text_stroke_outside_fast_pre() accept no AA parameter
  • VNPainter has no AA mechanism

This means stroked text, shape shadows, and vector-network rendering will continue using anti-aliasing even when --no-aa is enabled. Update these helpers to accept or read an anti-alias flag from the rendering policy to make the benchmark toggle effective across all render paths.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/grida-canvas/src/painter/painter.rs` at line 350, Helpers are still
hardcoding anti-aliasing; update shadow::draw_drop_shadow,
shadow::draw_inner_shadow, text_stroke::draw_text_stroke,
text_stroke::draw_text_stroke_outside_fast_pre to take an anti_alias: bool (or
read PainterPolicy) and call set_anti_alias(anti_alias) instead of
set_anti_alias(true), then propagate that flag from the caller sites in
painter.rs and from VNPainter (add an anti_alias field or read
self.policy.anti_alias()) so all render paths (stroked text, shadows,
vector-network) honor self.policy.anti_alias(); ensure public signatures and
call sites are updated consistently.

Comment thread crates/grida-canvas/src/runtime/render_policy.rs
results.push(ScenarioResult {
name: fss.name.to_string(),
kind: "zoom_forced_stable".to_string(),
kind: "baseline_nocache_zoom".to_string(),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Breaking change: kind field value renamed.

The kind field value changed from "zoom_forced_stable" to "baseline_nocache_zoom". Since ScenarioResult derives serde::Serialize (per report.rs:32-43), this is a breaking change for any downstream consumers—CI comparison scripts, report formatters, or dashboards—that match on this string value.

Consider whether this warrants a version bump or migration notice if existing benchmark reports are being compared across commits.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/grida-dev/src/bench/runner.rs` at line 1794, Summary: The serialized
"kind" value for ScenarioResult was renamed from "zoom_forced_stable" to
"baseline_nocache_zoom", which is a breaking change for downstream consumers.
Fix: restore backward compatibility by either (a) reverting the literal back to
"zoom_forced_stable" in the assignment that sets kind, or (b) update
ScenarioResult's serde serialization to accept/emit both names (use serde
rename/alias or a custom Serialize/Deserialize impl) so existing reports still
parse; reference the affected symbol "kind" on ScenarioResult and the
serialization logic in report.rs when making the change, and if the rename is
intentional ensure you also bump the package/report format version and update
any CI comparison scripts/tests that depend on the old value.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
crates/grida-canvas/src/runtime/scene.rs (1)

1540-1542: Consider documenting set_sync_gpu as benchmark-oriented API.

A short doc comment here would help prevent accidental enabling in interactive rendering paths.

Suggested doc tweak
 pub fn set_sync_gpu(&mut self, sync: bool) {
+    // Benchmark/timing mode: when true, flushes block until GPU completion.
+    // Keep disabled for normal interactive rendering.
     self.config.sync_gpu = sync;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/grida-canvas/src/runtime/scene.rs` around lines 1540 - 1542, Add a
short doc comment above the set_sync_gpu method explaining this API is intended
for benchmarking only and should not be enabled in interactive rendering paths;
mention that it toggles self.config.sync_gpu and can degrade real-time
performance or block GPU work, so callers (tests/benchmarks) should use it
rather than production UI code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/grida-canvas/src/runtime/scene.rs`:
- Around line 1540-1542: Add a short doc comment above the set_sync_gpu method
explaining this API is intended for benchmarking only and should not be enabled
in interactive rendering paths; mention that it toggles self.config.sync_gpu and
can degrade real-time performance or block GPU work, so callers
(tests/benchmarks) should use it rather than production UI code.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c413b52c-c7f5-43c0-a8ba-cc072f0d76f2

📥 Commits

Reviewing files that changed from the base of the PR and between 4f00d22 and 499281a.

📒 Files selected for processing (3)
  • .agents/skills/cg-perf/SKILL.md
  • crates/grida-canvas/Cargo.toml
  • crates/grida-canvas/src/runtime/scene.rs
✅ Files skipped from review due to trivial changes (1)
  • crates/grida-canvas/Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .agents/skills/cg-perf/SKILL.md

Add FLAG_FORCE_NO_AA to the RenderPolicyFlags bitmap so that
from_flags/to_flags round-trips preserve the AA override across
the WASM/host boundary.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel vercel Bot temporarily deployed to Preview – backgrounds April 6, 2026 19:40 Inactive
@vercel vercel Bot temporarily deployed to Preview – blog April 6, 2026 19:40 Inactive
@vercel vercel Bot temporarily deployed to Preview – grida April 6, 2026 19:40 Inactive
@vercel vercel Bot temporarily deployed to Preview – viewer April 6, 2026 19:40 Inactive
@softmarshmallow softmarshmallow merged commit 146bd9a into main Apr 6, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cg Core Graphics performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant