Skip to content

Conversation

@jserv
Copy link
Contributor

@jserv jserv commented Oct 31, 2025

Background

Anti-aliasing (AA) reduces visual artifacts (jaggies) on rasterized edges by sampling at sub-pixel positions. Traditional fixed AA uses the same sampling grid (e.g., 4x4) for all edges, which is accurate but expensive.

Standard 4x4 AA samples each pixel at 16 sub-pixel positions to compute coverage. Adaptive AA observes that:

  1. Perfectly vertical edges (dx=0) have zero horizontal variation → horizontal sub-sampling provides no benefit
  2. Text and curves are high-frequency details extremely sensitive to AA degradation
  3. Slope-based thresholds cannot distinguish text from geometry at runtime

Implementation Strategy

Conservative Approach: Only optimize perfectly vertical edges (dx=0)

  • ✅ Mathematically safe (vertical edges don't need horizontal AA)
  • ✅ Zero visual regression (verified with demo-sdl)
  • ❌ Rejected: Slope-based thresholds (caused text aliasing at 30-50°)

Span-Width Threshold: Apply optimization only to wide spans (≥16 pixels)

  • ✅ Avoids branch overhead on thin/medium spans
  • ✅ Optimal balance: +7.9% gain on large rectangles
  • ❌ Rejected: 4-pixel threshold (-30% to -35% regression due to branch overhead)

Technical Details

  • Add _span_fill_vertical() for vertical edge fast path
  • Use constant coverage values (0x40 for full pixels, count*0x10 for partial)
  • Optimize via constant multiplication (compiler converts to shift: count << 4)
  • Threshold 16 pixels * 4 samples/pixel = 64 samples minimum span width

Performance Results

Measured with mado-perf, 3-run average, Apple M1:

Test Case Improvement Statistical Significance
500x500 rectangles +7.9% p<0.05 (significant) ✅
100x100 rectangles +4.0% p≈0.07 (borderline)
500x500 vertical lines +3.1% Positive improvement
100x100 vertical lines +2.6% Positive improvement
Text shapes +0-2% Quality preserved ✅

Statistical Validation:

  • Variance coefficient: 0.9% to 6.5%
  • t-test analysis confirms large rectangle gains
  • 3 independent test runs for reliability

Precision Trade-off

  • Row 2 partial pixels: 0.4% rounding error (1/255)
  • Visual impact: Imperceptible (verified with demo-sdl)
  • Error source: 0x10 vs 0x0f for first sub-pixel
  • Full pixel: 0x40 vs 0x3f (accepted design choice)

Threshold Validation

Empirical testing of different threshold values:

Threshold Result Reason
16 pixels +2.6% to +7.9% Optimal balance
4 pixels -30% to -35% ❌ Branch overhead dominates

Why Conservative Approach?

Initial attempts with aggressive AA optimization caused issues:

  1. Slope-based thresholds (43°, 60°) caused visible text aliasing
  2. Cannot distinguish text from geometry at runtime
  3. Text rendering is extremely sensitive to AA quality (2-4 pixel strokes)
  4. Vertical edges (dx=0) inherently don't need horizontal AA → mathematically safe

Summary by cubic

Implemented adaptive anti-aliasing for polygon rendering that uses optimized span fill on perfectly vertical edges (dx=0) with 16-pixel span-width threshold. This delivers 2.6-7.9% speedups on common UI elements with zero visible quality loss, while preserving full 4x4 AA for text, curves, and diagonal strokes.

  • New Features
    • Added _span_fill_vertical() optimized fast path for vertical edges
    • Constant multiplication (count * 0x10) instead of array lookup
    • Span-width threshold (16 pixels) to avoid branch overhead
    • Comprehensive polygon benchmark suite with 7 test scenarios
    • Performance: +2.6% to +7.9% improvement, statistically validated
    • Quality: Zero visual regression, verified with demo-sdl

Written for commit 5841ceb29843f8831c80ff3968588ad44a60dfc3.

@jserv jserv changed the title poly: implement adaptive anti-aliasing for polygon rendering Implement adaptive anti-aliasing for polygon rendering Oct 31, 2025
cubic-dev-ai[bot]

This comment was marked as outdated.

@sysprog21 sysprog21 deleted a comment from cubic-dev-ai bot Oct 31, 2025
This improves span fill for perfectly vertical edges (dx=0) with
span-width threshold. This optimization targets the common case of
rectangles and UI elements while preserving full quality for text,
curves, and diagonal strokes.

Implementation Strategy:
- Conservative approach: only optimize dx=0 edges (mathematically safe)
- Rejected slope-based thresholds (caused text aliasing at 30-50°)
- Use constant coverage values to eliminate array lookups
- Apply only to wide spans (>=16 pixels) to avoid branch overhead

Technical Details:
- Add _span_fill_vertical() for vertical edge fast path
- Constant multiplication: count * 0x10 (compiler optimizes to shift)
- Full pixel coverage: 0x40 (vs array lookup)
- Span width threshold: 16 pixels * 4 samples = 64 samples

Performance Results (mado-perf, 3-run average, Apple M1):
- 500x500 rectangles: +7.9% (p<0.05, statistically significant)
- 100x100 rectangles: +4.0% (p≈0.07, borderline significant)
- 500x500 vertical lines: +3.1%
- 100x100 vertical lines: +2.6%
- Text shapes: +0-2% (quality preserved, zero visual regression)

Precision Trade-off:
- Row 2 partial pixels: 0.4% rounding error (1/255)
- Visually imperceptible, verified with demo-sdl
- Error: 0x10 vs 0x0f for first sub-pixel
- Full pixel: 0x40 vs 0x3f (accepted design choice)

Threshold Validation:
- Tested 4-pixel threshold: -30% to -35% regression (branch overhead)
- 16-pixel threshold: optimal balance (+2.6% to +7.9%)
@sysprog21 sysprog21 deleted a comment from cubic-dev-ai bot Oct 31, 2025
@jserv jserv marked this pull request as draft October 31, 2025 23:19
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files

Prompt for AI agents (all 1 issues)

Understand the root cause of the following 1 issues and fix them.


<file name="src/poly.c">

<violation number="1" location="src/poly.c:389">
The vertical-span fast path is triggered by checking `edge_start-&gt;dx == 0`, but this dx has already been reduced to the Bresenham remainder, so integer-slope diagonals (e.g., 45° lines where dx == dy) also satisfy the condition and drop to 1x1 AA, causing visible aliasing. Please base the check on a flag that preserves the original slope (e.g., `aa_quality`).</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

The previous implementation incorrectly checked 'dx == 0' to detect
vertical edges, but dx is modified by Bresenham reduction. This caused
diagonal lines with integer slopes to incorrectly use the vertical
optimization, resulting in thin diagonal strokes disappearing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants