Skip to main content

Renderer

Struct Renderer 

pub struct Renderer { /* private fields */ }
Expand description

Renders a scene into a texture or surface.

Currently, each renderer only supports a single surface format, if it supports drawing to surfaces at all. This is an assumption which is known to be limiting, and is planned to change.

Implementations§

§

impl Renderer

pub fn precompile_pipelines( &self, device: &Device, queue: &Queue, helpers: usize, open_device: &(dyn Fn() -> Option<(Device, Queue)> + Sync), )

Run every GPU pipeline’s first dispatch now, spread over this device and up to helpers more opened by open_device, each driven from its own thread.

Mesa’s CPU Vulkan driver (lavapipe) compiles a pipeline’s machine code on its first dispatch, so a cold first frame compiles every stage one after another. It also keeps the code in its shader disk cache, shared by every device in the process. This dispatches the largest pipeline here while the helpers take the rest, whose code this device then reads from the cache. When that one dispatch finds its code already compiled, the cache is warm and the helpers stop before compiling anything.

pub fn new(device: &Device, options: RendererOptions) -> Result<Renderer, Error>

Creates a new renderer for the specified device.

pub fn new_deferring( device: &Device, options: RendererOptions, deferral: PipelineDeferral, ) -> Result<Renderer, Error>

Self::new, building before it returns only the pipelines deferral does not defer (Tilo patch). Call Self::start_deferred_pipelines once the first frame is out.

pub async fn new_async( device: &Device, options: RendererOptions, ) -> Result<Renderer, Error>

Creates a new renderer for the specified device, compiling its pipelines with Device::create_compute_pipeline_async (Tilo patch).

On WebGPU the browser then compiles them in parallel on worker threads, instead of one after another on its GPU process’s main thread. That thread also serves the page’s frames and every other page using the GPU process: a software rasteriser (SwiftShader) spends seconds per vello pipeline there, and in Chromium a page whose earlier WebGPU context is torn down meanwhile blocks its own main thread until the GPU process gets to it. Other backends create the pipelines synchronously, one after another.

pub fn start_deferred_pipelines( &mut self, device: &Device, built: impl FnOnce() + Send + 'static, )

Build the pipelines Self::new_deferring deferred, in the background on the renderer’s init threads: those a full frame on the default path dispatches first, the largest of each group first. Renders install them as they arrive, and wait for one they dispatch. built runs once every one is built (on that thread), or at once when nothing was deferred: the moment to keep a pipeline cache. A second call does nothing and drops its built.

pub fn deferred_pipelines(&mut self) -> DeferredPipelines

The pipelines Self::new_deferring deferred that are not installed yet, and how many a render had to build itself.

pub fn memory_stats(&self) -> RendererMemoryStats

Return the GPU allocations whose byte sizes are directly known to the renderer. This is intended for performance budgets and diagnostics.

pub fn set_image_atlas_max(&mut self, max_size: u32)

Limit the image atlas to max_size pixels per side (8192 by default). Images that do not fit after eviction are omitted and reported, instead of a 256 MB atlas taking a browser’s GPU process past its memory limit.

pub fn image_cache_stats(&self) -> ImageCacheStats

The image atlas’s side and the images resident in it, with the CPU pixels they keep alive. The atlas texture itself is in Self::memory_stats’ image_bytes.

pub fn shrink_image_atlas_soon(&mut self)

Images went for good (a window closed): an image atlas far bigger than what is still drawn comes down within the next few renders, not after sixty, so a desktop that goes idle gives the memory back.

pub fn set_bump_budget_grow_once(&mut self, grow_once: bool)

Grow the bump buffers at most once, straight to the Self::set_bump_budget_limit total, instead of doubling as a scene fills up. Each growth reallocates every buffer, which a browser’s GPU process briefly holds twice.

pub fn set_bump_budget_limit(&mut self, bytes: u64)

Limit the adaptive bump buffers to bytes in total, whatever frames report using. Scenes past it drop geometry, which the shaders report, instead of taking a browser’s GPU process past its memory limit. Viewport floors come on top.

pub fn trim_pooled_buffers(&mut self)

Drop transient GPU buffers held only for reuse. In-flight command buffers keep their own references, so this is safe at a damage-shape transition and prevents obsolete size classes living forever.

pub fn set_shrink_scratch(&mut self, enabled: bool)

Hand back scratch a busier scene needed once the scene has stayed smaller (off by default): pooled buffers no render has taken for a while are destroyed, and the bump reservation comes down to a few times what recent dense frames used. Without it a renderer that once drew a busy scene keeps that scene’s working memory for good.

pub fn shrink_scratch_soon(&mut self)

The scene got smaller for good (a window closed): with Self::set_shrink_scratch, scratch comes down within the next few renders rather than after a hundred, so a desktop that goes idle gives the memory back.

pub fn scratch_shrinks(&self) -> u64

Times the bump reservation shrank (Self::set_shrink_scratch): each dropped every buffer pooled at the larger sizes.

pub fn invalidate_texture_bindings(&mut self, texture: &TextureView)

Release cached bind groups referencing a scratch texture that its owner is about to replace. Other bind groups and GPU buffer pools stay warm, so animated damage resizing does not become a global cache flush.

pub fn render_to_texture( &mut self, device: &Device, queue: &Queue, scene: &Scene, texture: &TextureView, params: &RenderParams, ) -> Result<(), Error>

Renders a scene to the target texture.

The texture is assumed to be of the specified dimensions and have been created with the wgpu::TextureFormat::Rgba8Unorm format and the wgpu::TextureUsages::STORAGE_BINDING flag set.

If you want to render Vello content to a surface (such as in a UI toolkit), you have two options:

  1. Render to an intermediate texture, which is the same size as the surface. You would then use TextureBlitter to blit the rendered result from that texture to the surface. This pattern is supported by the util module.
  2. Call render_to_texture directly on the SurfaceTexture’s texture, if it has the right usages. This should generally be avoided, as some GPUs assume that you will not be rendering to the surface using a compute pipeline, and optimise accordingly.

pub fn poll_bump_budget( &mut self, device: &Device, ) -> Result<BumpBudgetPoll, BumpBudgetError>

Poll outstanding counter readbacks without waiting for the GPU.

Pending work retains any overflow collected by earlier renders. Only a completed poll consumes that overflow. Readback errors remain visible on subsequent polls, including errors found by ordinary render collection; replacing the renderer is required to discard a failed observation.

An idle renderer, or one with measurement deliberately disabled, has no outstanding counter work and reports complete. This method does not prove GPU submission or frame completion: callers must establish that separately.

pub fn override_image( &mut self, image: &ImageData, texture: Option<TexelCopyTextureInfo<Texture>>, ) -> Option<TexelCopyTextureInfo<Texture>>

Overwrite image with texture.

Most users should prefer register_texture, which ergonomically encapulates these requirements.

texture must have the wgpu::TextureFormat::Rgba8Unorm format and the wgpu::TextureUsages::COPY_SRC flag set. The Rgba8UnormSrgb format might also be supported, but this is not tested.

The given Texture’s data will be copied into the slot in Vello’s image atlas where the image would be placed each frame. This has the effect that wherever you request the image to be drawn (e.g. through Scene::draw_image), the data from the texture will be used instead.

Correct behaviour is not guaranteed if the texture does not have the same dimensions as the image, nor if an image which uses the same blob but different dimensions would be rendered.

pub fn draw_image_from( &mut self, image: &ImageData, source: Option<ImageSource>, ) -> Option<ImageSource>

Draw image from source (Tilo patch): its pixels are drawn into the atlas slot through a render pass whenever the image is written there, so source may be any colour format the device samples (a Bgra8Unorm Wayland client buffer, imported as it is) and may be drawn opaque. None stops drawing it from a source. Takes precedence over override_image. Returns the previous source.

source.texture must have the wgpu::TextureUsages::TEXTURE_BINDING flag and hold the image’s extent at source.origin. It is read only while the image is written into the atlas: on its first draw, after this call, and when the atlas is repacked. Keep it readable while any scene that draws image can still be rendered.

pub fn image_source_writes(&self) -> (u64, u64)

Images drawn into the atlas from an ImageSource since this renderer was made, and the bytes those draws wrote (Tilo patch).

pub fn mark_override_image_dirty(&mut self, image: &ImageData)

Marks image as dirty in the atlas cache, so its override texture will be recopied on the next render that uses it.

Call this for any image whose existing override texture has changed since the last render. Otherwise, stale image data from the atlas may be used.

pub fn register_texture(&mut self, texture: Texture) -> ImageData

Register a wgpu::Texture with Vello, to allow drawing GPU-resident data.

The returned Image can be used in Scenes (only those rendered with this Renderer) Rendering Scenes which use this Image with other Renderers will panic.

texture must have the wgpu::TextureFormat::Rgba8Unorm format and the wgpu::TextureUsages::COPY_SRC flag set. This is because the data will be copied into Vello’s image atlas at the start of each frame. The Rgba8UnormSrgb format might also be supported, but this is not tested. The texture is assumed to have unpremultiplied alpha.

This is a utility wrapper around override_image. For greater control, use that method.

If the texture is no longer active then it should be unregistered using unregister_texture

pub fn unregister_texture(&mut self, handle: ImageData)

Unregister a wgpu::Texture that was registered with register_texture.

pub async fn render_to_texture_async( &mut self, device: &Device, queue: &Queue, scene: &Scene, texture: &TextureView, params: &RenderParams, debug_layers: DebugLayers, ) -> Result<Option<BumpAllocators>, Error>

👎Deprecated:

render_to_texture should be preferred, as the _async version has no stability guarantees

Renders a scene to the target texture using an async pipeline.

Almost all consumers should prefer Self::render_to_texture.

The return value is the value of the BumpAllocators in this rendering, which is currently used for debug output.

This return type is not stable, and will likely be changed when a more principled way to access relevant statistics is implemented

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
§

impl<T> Downcast<T> for T

§

fn downcast(&self) -> &T

§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

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

Initializes a with the given initializer. Read more
§

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

Dereferences the given pointer. Read more
§

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

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

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

impl<T> Same for T

Source§

type Output = T

Should always be Self
§

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

§

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

§

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

§

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

impl<T> Upcast<T> for T

§

fn upcast(&self) -> Option<&T>

§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<T> ErasedDestructor for T
where T: 'static,

§

impl<T> Fruit for T
where T: Send + Downcast,

§

impl<T> WasmNotSend for T
where T: Send,