Skip to main content

Resources

Struct Resources 

Source
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

Source

pub fn new() -> Self

Create a new set of renderer resources.

Examples found in repository?
examples/clipping.rs (line 129)
128fn save_pixmap(ctx: &RenderContext, filename: &str) {
129    let mut resources = Resources::new();
130    let mut pixmap = Pixmap::new(ctx.width(), ctx.height());
131    ctx.render(&mut pixmap, &mut resources);
132    let png = pixmap.into_png().unwrap();
133    std::fs::write(format!("{filename}.png"), png).unwrap();
134}
More examples
Hide additional examples
examples/paints.rs (line 136)
135fn save_pixmap(ctx: &RenderContext, filename: &str) {
136    let mut resources = Resources::new();
137    let mut pixmap = Pixmap::new(ctx.width(), ctx.height());
138    ctx.render(&mut pixmap, &mut resources);
139    let png = pixmap.into_png().unwrap();
140    std::fs::write(format!("{filename}.png"), png).unwrap();
141}
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.

Source

pub fn register_image(&mut self, pixmap: Arc<Pixmap>) -> ImageId

Register a pixmap in the image registry and return its ImageId.

Source

pub fn destroy_image(&mut self, id: ImageId) -> bool

Remove an image from the registry.

Source

pub fn resolve_image(&self, id: ImageId) -> Option<Arc<Pixmap>>

Resolve an ImageId to its pixmap data.

Source

pub fn clear_images(&mut self)

Clear the image registry.

Trait Implementations§

Source§

impl Debug for Resources

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Resources

Source§

fn default() -> Resources

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, S> SimdFrom<T, S> for T
where S: Simd,

Source§

fn simd_from(_simd: S, value: T) -> T

Source§

impl<F, T, S> SimdInto<T, S> for F
where T: SimdFrom<F, S>, S: Simd,

Source§

fn simd_into(self, simd: S) -> T

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.