linebender / vello

An experimental GPU compute-centric 2D renderer.
http://linebender.org/vello/
Apache License 2.0
2.27k stars 129 forks source link

Rendering issue when clipping and stroking the same path #616

Open timtom-dev opened 3 months ago

timtom-dev commented 3 months ago

I'm trying to render a simple UI, and I'm using the same path to clip the contents of each button as well as stroke the border, but I'm getting some artifacts in the corners of some of the buttons. Is this a known issue?

image

raphlinus commented 3 months ago

Hm, that definitely looks like a rendering issue. Is there any chance you could make a minimal repro?

timtom-dev commented 3 months ago

Sure thing! I wasn't able to quickly repro the big black rectangle, but hopefully that's the same problem.

It looks like it only happens at certain coordinates, which is why the rectangle is at (60., 10.) it doesn't happen at 61, for example.

Swap this function in to the "simple" example in the vello repo:

fn add_shapes_to_scene(scene: &mut Scene) {
    let rect = RoundedRect::new(60.0, 10.0, 160.0, 100.0, 10.0);
    let stroke = Stroke::new(2.0);
    let fill = vello::peniko::Fill::NonZero;
    let mask_blend = vello::peniko::BlendMode::new(vello::peniko::Mix::Normal, vello::peniko::Compose::SrcOver);
    scene.push_layer(mask_blend, 1.0, Affine::IDENTITY, &rect);
    scene.stroke(&stroke, Affine::IDENTITY, Color::BLACK, None, &rect);
    scene.pop_layer();
}

image

timtom-dev commented 3 months ago

So it turns out that this has nothing to do with clipping layers. The following code also exhibits the issue:

    let rect = RoundedRect::new(60.0, 10.0, 160.0, 100.0, 10.0);
    let stroke = Stroke::new(2.0);
    scene.stroke(&stroke, Affine::IDENTITY, Color::WHITE, None, &rect);
DJMcNab commented 2 months ago

I can reproduce.

Some triage: 1) This doesn't reproduce if we use the CPU "flatten" stage 2) There seem to be two issues:

The issue reproducing with area anti-aliasing, with no image

raphlinus commented 2 months ago

Based on Daniel's investigation, this seems most likely to be a watertightness issue in the flatten stage, possibly related to fastmath (another issue that implicates fastmath is #581, so we should probably look at these together).

A good next step would be to examine the output of the flatten stage (ie the line soup buffer). We made some effort to make joins watertight, but it's very easy to image we missed something.