gpui: Improve path rendering & global multisample anti-aliasing
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
This need to wait @sunli829 to fix details, currently implementation was broke content_mask logic.
We just found today.
done
@mikayla-maki ping
I modified painting.rs to draw 5000 stars in the same location to observe the performance improvement brought by this PR.
Previous version:
VRAM: increased from 2.8G to 15G
FPS: 5
This PR:
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),
));
}
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.
I used the draw_indirect function to optimize path rendering, achieving a 30% performance improvement on Windows and 2% on Mac.
Before:
After:
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:
This PR also fixes the issue of hollowing at the intersection of two lines in the path.
before:
after:
Hey @mikayla-maki and @P1n3appl3, is anything still left to do here before this PR can be merged? :slightly_smiling_face:
@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.
@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.