zed icon indicating copy to clipboard operation
zed copied to clipboard

gpui: Improve path rendering & global multisample anti-aliasing

Open sunli829 opened this issue 11 months ago • 5 comments

Currently, the rendering path required creating a texture for each path, which wasted a large amount of video memory. In our application, simply drawing some charts resulted in video memory usage as high as 5G.

I removed the step of creating path textures and directly drew the paths on the rendering target, adding post-processing global multi-sampling anti-aliasing. Drawing paths no longer requires allocating any additional video memory and also improves the performance of path rendering.

Release Notes:

  • N/A

sunli829 avatar May 01 '25 03:05 sunli829

This need to wait @sunli829 to fix details, currently implementation was broke content_mask logic.

We just found today.

image

huacnlee avatar May 09 '25 03:05 huacnlee

done

sunli829 avatar May 09 '25 05:05 sunli829

@mikayla-maki ping

sunli829 avatar May 09 '25 05:05 sunli829

I modified painting.rs to draw 5000 stars in the same location to observe the performance improvement brought by this PR.

Previous version:

1

VRAM: increased from 2.8G to 15G
FPS: 5

This PR:

2

VRAM: increased from 2.8G to 3.6G
FPS: 7

The rendered graphics look identical.

for i in 0..5000 {
            // draw a ⭐
            let mut builder = PathBuilder::fill();
            builder.move_to(point(px(350.), px(100.)));
            builder.line_to(point(px(370.), px(160.)));
            builder.line_to(point(px(430.), px(160.)));
            builder.line_to(point(px(380.), px(200.)));
            builder.line_to(point(px(400.), px(260.)));
            builder.line_to(point(px(350.), px(220.)));
            builder.line_to(point(px(300.), px(260.)));
            builder.line_to(point(px(320.), px(200.)));
            builder.line_to(point(px(270.), px(160.)));
            builder.line_to(point(px(330.), px(160.)));
            builder.line_to(point(px(350.), px(100.)));
            let path = builder.build().unwrap();
            lines.push((
                path,
                linear_gradient(
                    180.,
                    linear_color_stop(rgb(0xFACC15), 0.7),
                    linear_color_stop(rgb(0xD56D0C), 1.),
                )
                .color_space(ColorSpace::Oklab),
            ));
        }

sunli829 avatar May 13 '25 06:05 sunli829

Hey, @mikayla-maki, we are applied this changes in our project and release version, and stable to use a couple of weeks. This change is actually resolved memory leak issue.

The CPU, GPU, memory, VRAM is all looks good. And we also check this PR change by startup Zed, there is not found other issue, special of the performance.

If you find something issue that we missed, please help us to point it, we will try to fix them as soon as possible.

The GPUI Component can move to depends on GPUI main branch, never need fork version, when this PR going to merge.

huacnlee avatar May 20 '25 14:05 huacnlee

I used the draw_indirect function to optimize path rendering, achieving a 30% performance improvement on Windows and 2% on Mac.

Before:

2

After:

1

sunli829 avatar Jun 09 '25 02:06 sunli829

Hi, thanks for this PR the code looks pretty good, but we're leery about the performance implications. All of our other primitives do their own AA directly in the fragment shader. Can you either document the performance ramifications or find a way to target the MSAA?

@mikayla-maki As far as I understand the changes in this PR, the MSAA is still used just as before. The difference is that instead of applying it to each and every Path texture separately, it is now applied to the main render target, where all the Paths are drawn directly. :+1:

filipwiech avatar Jun 09 '25 16:06 filipwiech

This PR also fixes the issue of hollowing at the intersection of two lines in the path.

before: image

after: image

sunli829 avatar Jun 10 '25 02:06 sunli829

Hey @mikayla-maki and @P1n3appl3, is anything still left to do here before this PR can be merged? :slightly_smiling_face:

filipwiech avatar Jun 27 '25 16:06 filipwiech

@sunli829 What is the purpose of the indirect draw calls here? It seems like all of the vertex data is already computed on the CPU. Why not use regular draw calls? Are the indirect calls faster?

Thanks for the huge improvement - it's great to be able to handle paths so much more efficiently.

maxbrunsfeld avatar Jul 15 '25 22:07 maxbrunsfeld

@sunli829 It seems like this is causing issues on certain GPU configurations, like intel macbooks with discrete GPUs (see https://github.com/zed-industries/zed/issues/34659). We had to revert, but I would love to figure out a way to re-apply this, if we can figure out what is causing the regression.

maxbrunsfeld avatar Jul 18 '25 19:07 maxbrunsfeld