pub struct Resources { /* private fields */ }Expand description
Persistent resources required by Vello CPU for rendering.
You should create one such instance per renderer.
Implementations§
Source§impl Resources
impl Resources
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new set of renderer resources.
Examples found in repository?
More examples
examples/masking.rs (line 22)
12fn main() {
13 // Vello CPU supports applying luminance and alpha masks to your drawings.
14
15 // First, we need to create our actual mask. There are multiple ways how
16 // you can get to it, in our case we are going to draw our own custom mask.
17 let mask = {
18 // In this case, we are drawing the mask ourselves. Note that the
19 // dimensions of the final mask need to match the dimensions of our
20 // original render context!
21 let mut mask_ctx = RenderContext::new(SIZE, SIZE);
22 let mut mask_resources = Resources::new();
23 let mut pixmap = Pixmap::new(SIZE, SIZE);
24
25 mask_ctx.set_paint(RED);
26 mask_ctx.fill_rect(&Rect::new(30.0, 30.0, 170.0, 170.0));
27 mask_ctx.flush();
28 mask_ctx.render(&mut pixmap, &mut mask_resources);
29
30 Mask::new_luminance(&pixmap)
31 };
32
33 // Create the main render context.
34 let mut ctx = RenderContext::new(SIZE, SIZE);
35
36 // Similarly to clip paths (see the clipping example), there are two
37 // different ways of applying them:
38 // The first method is by creating a new isolated layer where the mask
39 // will be applied once the whole layer has been drawn and is composited
40 // into the backdrop. The second method is by setting the mask in the
41 // render context, in which case the mask will be applied to each shape
42 // directly before being drawn. Which method you should use once again
43 // depends on the imaging model you are reflecting.
44
45 // Method 1: Non-isolated masking via `set_mask`.
46 {
47 ctx.set_paint(WHITE);
48 ctx.fill_rect(&Rect::new(0.0, 0.0, SIZE as f64, SIZE as f64));
49
50 // Once the mask is set, the mask will be applied to every path we
51 // are drawing individually before compositing it into the background.
52 ctx.set_mask(mask.clone());
53 // We first apply the mask to the blue rectangle and then composite it.
54 ctx.set_paint(BLUE);
55 ctx.fill_rect(&Rect::new(20.0, 20.0, 130.0, 130.0));
56 // Now, we yet again first apply the mask to the red rectangle only and
57 // then composite the result.
58 ctx.set_paint(RED);
59 ctx.fill_rect(&Rect::new(70.0, 70.0, 180.0, 180.0));
60 // Use this method if you want to reset the mask currently in place.
61 ctx.reset_mask();
62
63 ctx.flush();
64 save_pixmap(&ctx, "example_masking1");
65 }
66
67 ctx.reset();
68 // Method 2: Isolated masking via `push_mask_layer`.
69 {
70 ctx.set_paint(WHITE);
71 ctx.fill_rect(&Rect::new(0.0, 0.0, SIZE as f64, SIZE as f64));
72
73 // Using this method, we first push a new isolated layer. Apart from that,
74 // nothing happens so far.
75 ctx.push_mask_layer(mask);
76 // Here, the blue rectangle will be drawn first. Then, the red one is drawn
77 // and subsequently composited on top of the blue one,
78 // without any special handling.
79 ctx.set_paint(BLUE);
80 ctx.fill_rect(&Rect::new(20.0, 20.0, 130.0, 130.0));
81 ctx.set_paint(RED);
82 ctx.fill_rect(&Rect::new(70.0, 70.0, 180.0, 180.0));
83 // Now, the whole layer is taken, the mask is applied to all of it
84 // and then composited into the background.
85 ctx.pop_layer();
86
87 ctx.flush();
88 save_pixmap(&ctx, "example_masking2");
89 }
90
91 // As can be seen, the visual result of the two methods can be different!
92}
93
94fn save_pixmap(ctx: &RenderContext, filename: &str) {
95 let mut resources = Resources::new();
96 let mut pixmap = Pixmap::new(ctx.width(), ctx.height());
97 ctx.render(&mut pixmap, &mut resources);
98 let png = pixmap.into_png().unwrap();
99 std::fs::write(format!("{filename}.png"), png).unwrap();
100}examples/basic.rs (line 91)
16fn main() {
17 // Vello CPU is a CPU-based 2D renderer. It takes drawing commands like
18 // "fill a rectangle" or "stroke a triangle" as input and rasterizes
19 // them into a bitmap with premultiplied RGBA pixels, which can then
20 // be further processed (for example by converting to PNG or displaying
21 // the result in a window).
22
23 // We first need to define some basic render settings.
24 let settings = RenderSettings {
25 // The `level` field indicates what SIMD level should be used. In
26 // the vast majority of cases, you should just use `Level::new` so that
27 // Vello CPU automatically uses an appropriate level that is
28 // available on the host system.
29 //
30 // There are very few reasons to override that value. One instance where
31 // it might be useful to override is for example when using Vello CPU
32 // to create reference images for test suites. In that case, you could
33 // pass `Level::fallback`, which indicates to Vello CPU that no
34 // platform-specific SIMD intrinsics should be used. This might be useful
35 // because it reduces the possibility of slight pixel differences when
36 // running on different platforms.
37 level: Level::new(),
38 // The number of additional threads that should be used for rendering.
39 // This setting only has an effect when the `multi-threading` feature
40 // is enabled. More threads _usually_ translates to better performance,
41 // but also higher CPU usage. Multi-threading can be very effective
42 // in situations where you need to continually redraw scenes (for example
43 // when rendering GUIs), but is usually less useful for one-time
44 // rendering operations. It should also be noted that the current
45 // implementation of multi-threading is still not fully optimized and
46 // might not work as well in certain workloads, so it's worth trying
47 // yourself whether it actually leads to any speedups before using it.
48 //
49 // If you enabled the multi-threading feature and leave this as 0,
50 // it has the exact same effect as rendering in single-threaded mode.
51 // According to our experiments, 2-4 threads give the best results,
52 // using 4+ threads might result in diminishing results, depending on
53 // the workload.
54 num_threads: 0,
55 };
56 let rasterizer_settings = RasterizerSettings {
57 // Define whether the renderer should prioritize speed or quality
58 // during rendering. Currently, the only difference is that
59 // `OptimizeSpeed` will use u8/u16 for the rasterization
60 // while `OptimizeQuality` uses f32. The former is much faster, but
61 // has the disadvantage that the overall color accuracy might be slightly
62 // worse due to quantization. Unless you really care about that, it is
63 // highly recommended to use the `OptimizeSpeed` rendering mode.
64 render_mode: RenderMode::OptimizeSpeed,
65 ..Default::default()
66 };
67
68 // Vello CPU embraces a slightly different paradigm than a lot of other 2D
69 // renderers. Many 2D renderers use _immediate mode rendering_, where
70 // you create a single `Pixmap` and then dispatch rendering commands into
71 // it. In Vello CPU, there are two components instead.
72 //
73 // The first component is the `RenderContext`, which can be thought of as
74 // a reusable buffer for dispatching rendering commands. The `reusable`
75 // part is important: In situations where you are executing multiple
76 // rendering passes at the same resolution, you should reset the context
77 // and reuse it instead of always creating a new one, as will be shown below.
78 // This is important because it allows Vello CPU to reuse existing memory
79 // allocations, leading to better performance.
80 //
81 // The second component is then the `Pixmap`, which simply acts as a storage
82 // for the raw RGBA pixels from the render context.
83
84 // Let's start by creating a new render context with a certain
85 // width and height in pixels, as well as our render settings.
86 let mut ctx = RenderContext::new_with(100, 100, settings);
87 // Vello CPU needs this to track certain resources (e.g. for glyph caching)
88 // across multiple frames. You need to make sure that you create on such struct
89 // for each render context you create, and then only use it in combination with that
90 // specific render context.
91 let mut resources = Resources::new();
92
93 // Vello CPU uses a Postscript-like API, where you can use methods like
94 // `set_paint` or `set_stroke` to update an internal state, and then
95 // dispatch commands to fill or stroke paths, using the current state.
96
97 // Using the `set_paint` method, we can change what color our shapes should
98 // be drawn with. You can use any RGBA color for that. Apart from that, you
99 // can also paint your shapes using gradients or patterns (see the `paints`
100 // example). In this case, we are setting the color to blue.
101 ctx.set_paint(BLUE);
102 // Now, we can dispatch a commands, for example to fill a rectangle with
103 // the given dimensions.
104 ctx.fill_path(&Rect::new(25.0, 25.0, 75.0, 75.0).to_path(0.1));
105
106 // We can then update the color to a red with 50% opacity...
107 ctx.set_paint(RED.with_alpha(0.5));
108 // ...and draw a different rectangle that overlaps the previous one. You
109 // can also use the `fill_rect` convenience method for that.
110 ctx.fill_rect(&Rect::new(50.0, 50.0, 85.0, 85.0));
111
112 ctx.set_paint(GREEN);
113 // As mentioned, stroking is also supported. You can update the stroke
114 // properties using the `set_stroke` method.
115 ctx.stroke_path(&Circle::new((50.0, 50.0), 30.0).to_path(0.1));
116
117 // Let's say that we have drawn everything we wanted to now. Next, it is
118 // recommended that you call the `flush` method. In theory, this call
119 // is only necessary when using multi-threaded rendering, to signal that
120 // no more operations will be dispatched and the render context should be
121 // synchronized. If you forget to call this during multi-threaded rendering,
122 // the application will panic. In single-threaded rendering, nothing happens.
123 //
124 // However, it is highly recommended that you always call this.
125 // This way, downstream consumers of your crate that might have externally
126 // enabled Vello CPU's multi-threading feature won't run into panics when
127 // running your code.
128 ctx.flush();
129
130 // Now the second step is to copy the results of the render context into the
131 // pixmap. We do this by creating a new pixmap (or reusing an existing one).
132 // The pixmap and render context can have different dimensions. See the documentation
133 // of the `render_with` method for more information.
134 let mut pixmap_1 = Pixmap::new(100, 100);
135 // Now, simply extract the results from the render context into the
136 // pixmap.
137 ctx.render_with(&mut pixmap_1, &mut resources, rasterizer_settings);
138
139 // Now you can do whatever you want with the pixmap, which provides raw
140 // access to the premultiplied RGBA pixels of the image. If you have enabled
141 // the `png` feature, you can convert it into a PNG image very easily and
142 // then save it to disk.
143 let png_1 = pixmap_1.into_png().unwrap();
144 std::fs::write("example_basic1.png", png_1).unwrap();
145
146 // If you have another scene you want to draw at the same resolution,
147 // you can simply reuse the existing render context instead of creating
148 // a new one.
149 ctx.reset();
150
151 // Vello CPU supports arbitrary affine transformations.
152 ctx.set_transform(Affine::scale(3.0));
153 ctx.set_paint(YELLOW);
154 // The rectangle will now actually have the dimensions 60x60 since we
155 // applied an affine transform that scales everything by 3x to the context.
156 ctx.fill_rect(&Rect::new(0.0, 0.0, 20.0, 20.0));
157 ctx.flush();
158
159 // Once again, we render the results into a pixmap again. If you can,
160 // you can just reuse existing pixmaps (assuming they have the correct
161 // dimension), since all previous pixels in the pixmap will be cleared by
162 // the default replace mode. In our case, we need to create a new one since
163 // our call to `into_png` consumed the pixmap.
164 let mut pixmap_2 = Pixmap::new(100, 100);
165 ctx.render_with(&mut pixmap_2, &mut resources, rasterizer_settings);
166 let png_2 = pixmap_2.into_png().unwrap();
167 std::fs::write("example_basic2.png", png_2).unwrap();
168}Source§impl Resources
Image registry implementation.
impl Resources
Image registry implementation.
Sourcepub fn register_image(&mut self, pixmap: Arc<Pixmap>) -> ImageId
pub fn register_image(&mut self, pixmap: Arc<Pixmap>) -> ImageId
Register a pixmap in the image registry and return its ImageId.
Sourcepub fn destroy_image(&mut self, id: ImageId) -> bool
pub fn destroy_image(&mut self, id: ImageId) -> bool
Remove an image from the registry.
Sourcepub fn resolve_image(&self, id: ImageId) -> Option<Arc<Pixmap>>
pub fn resolve_image(&self, id: ImageId) -> Option<Arc<Pixmap>>
Resolve an ImageId to its pixmap data.
Sourcepub fn clear_images(&mut self)
pub fn clear_images(&mut self)
Clear the image registry.
Trait Implementations§
Auto Trait Implementations§
impl !RefUnwindSafe for Resources
impl !Sync for Resources
impl !UnwindSafe for Resources
impl Freeze for Resources
impl Send for Resources
impl Unpin for Resources
impl UnsafeUnpin for Resources
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more