linebender / linebender/vello

Image quality degrades significantly when downscaling by >2×

Open
#1,289 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-cpu C-gpu C-sparse-strips
Dominant language
Rust
Stars
4.3k
Forks
300
Avg merge
2d 13h
Merged PRs (30d)
61

Description

Summary

Images downscaled by more than 2× display severe visual artifacts including pixelation, jagged edges, and loss of fine details like text and thin lines.

Technical Cause

When a transform has scale < 1.0 (downscaling), the renderer inverts it to map from output space back to source image space. The x_advance and y_advance vectors are calculated from this inverted transform to determine how far to step in the source image for each output pixel.

Example with scale(0.125) (8× downscale):

  1. User transform: scale(0.125) — render 800px image at 100px width
  2. Internal transform: scale(0.125).inverse() = scale(8.0) — maps output→source
  3. Advances computed: x_advance = (8.0, 0.0), y_advance = (0.0, 8.0)
  4. During rasterization:
    • The SIMD rasterizer processes 4 rows at once, calculating positions as [0, 1, 2, 3] × y_advance + start_pos
    • For output starting at position (10, 5) → source position (80, 40)
    • Four SIMD lanes sample at y-positions spaced 8 pixels apart: [40, 48, 56, 64]
    • Bilinear filter applies fixed offsets [-0.5, 0.5], sampling 2 pixels at each position
    • Result: Samples only 8 pixels total; should ideally sample 32 pixels (4 rows × 8 pixels per row) — 75% of data skipped

The x_advance and y_advance correctly determine where to sample based on the scale factor, but the sampling kernel remains fixed at 2×2 (bilinear) or 4×4 (bicubic) pixels regardless of how large the advance steps are. For proper 8× downscaling, each output pixel should ideally average an 8×8 block (64 pixels), but instead samples only 4-16 pixels, skipping 60-48 pixels respectively and causing severe aliasing and loss of fine details.

Solution
  • Add progressive downsampling for better image quality at small scales

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the renderer's inverted downscaling transform through the SIMD rasterizer, focusing on x_advance, y_advance, and the fixed bilinear or bicubic sampling kernels described in the issue. Reproduce the scale(0.125) case and compare its sampled area with the expected downsampled region. Done means progressive downsampling improves detail and reduces aliasing at small scales without regressing other transforms.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
computer-graphics
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.