Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove render_to_surface and the async pipeline #803

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ You can find its changes [documented below](#040---2025-01-20).

This release has an [MSRV][] of 1.82.

<!-- TODO: Wgpu 24 (#791); override_image change (#802) -->

## Removed

- Breaking: The `Renderer::render_to_surface` has been removed. ([#803][] by [@DJMcNab][])
This API was not fit for purpose for several reasons, for example, it assumed that you would only ever use a single window.
The new recommended way to use Vello to render to a surface is to use `Renderer::render_to_texture`, then copy from that to the surface yourself.
This can use the new [`TextureBlitter`](https://docs.rs/wgpu/latest/wgpu/util/struct.TextureBlitter.html) type from `wgpu` for this blitting.
The `util` module has been updated to create a blit pipeline and intermediate texture for each surface.

## [0.4.0][] - 2025-01-20

This release has an [MSRV][] of 1.82.
Expand Down Expand Up @@ -233,6 +243,7 @@ This release has an [MSRV][] of 1.75.
[#766]: https://github.com/linebender/vello/pull/766
[#792]: https://github.com/linebender/vello/pull/792
[#796]: https://github.com/linebender/vello/pull/796
[#803]: https://github.com/linebender/vello/pull/803

[Unreleased]: https://github.com/linebender/vello/compare/v0.4.0...HEAD
[0.4.0]: https://github.com/linebender/vello/compare/v0.3.0...v0.4.0
Expand Down
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 14 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,52 +76,47 @@ use vello::{
let (width, height) = ...;
let device: wgpu::Device = ...;
let queue: wgpu::Queue = ...;
let surface: wgpu::Surface<'_> = ...;
let texture_format: wgpu::TextureFormat = ...;
let mut renderer = Renderer::new(
&device,
RendererOptions {
surface_format: Some(texture_format),
use_cpu: false,
antialiasing_support: AaSupport::all(),
antialiasing_support: vello::AaSupport::all(),
num_init_threads: NonZeroUsize::new(1),
},
).expect("Failed to create renderer");

// Create scene and draw stuff in it
let mut scene = Scene::new();
let mut scene = vello::Scene::new();
scene.fill(
Fill::NonZero,
Affine::IDENTITY,
Color::from_rgb8(242, 140, 168),
vello::peniko::Fill::NonZero,
vello::Affine::IDENTITY,
vello::Color::from_rgb8(242, 140, 168),
None,
&Circle::new((420.0, 200.0), 120.0),
&vello::Circle::new((420.0, 200.0), 120.0),
);

// Draw more stuff
scene.push_layer(...);
scene.fill(...);
scene.stroke(...);
scene.pop_layer(...);
let texture = device.create_texture(&...);

// Render to your window/buffer/etc.
let surface_texture = surface.get_current_texture()
.expect("failed to get surface texture");
// Render to a wgpu Texture
renderer
.render_to_surface(
.render_to_texture(
&device,
&queue,
&scene,
&surface_texture,
&RenderParams {
&texture,
&vello::RenderParams {
base_color: palette::css::BLACK, // Background color
width,
height,
antialiasing_method: AaConfig::Msaa16,
},
)
.expect("Failed to render to surface");
surface_texture.present();
.expect("Failed to render to a texture");
// Do things with `texture`, such as blitting it to the Surface using
// wgpu::util::TextureBlitter
```

See the [`examples`](https://github.com/linebender/vello/tree/main/examples) directory for code that integrates with frameworks like winit.
Expand Down
1 change: 0 additions & 1 deletion examples/headless/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ async fn render(mut scenes: SceneSet, index: usize, args: &Args) -> Result<()> {
let mut renderer = vello::Renderer::new(
device,
RendererOptions {
surface_format: None,
use_cpu: args.use_cpu,
num_init_threads: NonZeroUsize::new(1),
antialiasing_support: vello::AaSupport::area_only(),
Expand Down
35 changes: 25 additions & 10 deletions examples/simple/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,21 +131,15 @@ impl ApplicationHandler for SimpleVelloApp<'_> {
// Get a handle to the device
let device_handle = &self.context.devices[surface.dev_id];

// Get the surface's texture
let surface_texture = surface
.surface
.get_current_texture()
.expect("failed to get surface texture");

// Render to the surface's texture
// Render to a texture, which we will later copy into the surface
self.renderers[surface.dev_id]
.as_mut()
.unwrap()
.render_to_surface(
.render_to_texture(
&device_handle.device,
&device_handle.queue,
&self.scene,
&surface_texture,
&surface.target_view,
&vello::RenderParams {
base_color: palette::css::BLACK, // Background color
width,
Expand All @@ -155,6 +149,28 @@ impl ApplicationHandler for SimpleVelloApp<'_> {
)
.expect("failed to render to surface");

// Get the surface's texture
let surface_texture = surface
.surface
.get_current_texture()
.expect("failed to get surface texture");

// Perform the copy
let mut encoder =
device_handle
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Surface Blit"),
});
surface.blitter.copy(
&device_handle.device,
&mut encoder,
&surface.target_view,
&surface_texture
.texture
.create_view(&wgpu::TextureViewDescriptor::default()),
);
device_handle.queue.submit([encoder.finish()]);
// Queue the texture to be presented on the surface
surface_texture.present();

Expand Down Expand Up @@ -196,7 +212,6 @@ fn create_vello_renderer(render_cx: &RenderContext, surface: &RenderSurface<'_>)
Renderer::new(
&render_cx.devices[surface.dev_id].device,
RendererOptions {
surface_format: Some(surface.format),
use_cpu: false,
antialiasing_support: vello::AaSupport::all(),
num_init_threads: NonZeroUsize::new(1),
Expand Down
30 changes: 22 additions & 8 deletions examples/simple_sdl2/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,14 @@ fn main() {

let device_handle = &context.devices[surface.dev_id];

let surface_texture = surface
.surface
.get_current_texture()
.expect("failed to get surface texture");

renderers[surface.dev_id]
.as_mut()
.unwrap()
.render_to_surface(
.render_to_texture(
&device_handle.device,
&device_handle.queue,
&scene,
&surface_texture,
&surface.target_view,
&vello::RenderParams {
base_color: palette::css::BLACK, // Background color
width,
Expand All @@ -89,6 +84,26 @@ fn main() {
)
.expect("failed to render to surface");

let surface_texture = surface
.surface
.get_current_texture()
.expect("failed to get surface texture");

let mut encoder =
device_handle
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Surface Blit"),
});
surface.blitter.copy(
&device_handle.device,
&mut encoder,
&surface.target_view,
&surface_texture
.texture
.create_view(&wgpu::TextureViewDescriptor::default()),
);
device_handle.queue.submit([encoder.finish()]);
for event in event_pump.poll_iter() {
match event {
Event::Quit { .. }
Expand All @@ -108,7 +123,6 @@ fn create_vello_renderer(render_cx: &RenderContext, surface: &RenderSurface<'_>)
Renderer::new(
&render_cx.devices[surface.dev_id].device,
RendererOptions {
surface_format: Some(surface.format),
use_cpu: false,
antialiasing_support: vello::AaSupport::all(),
num_init_threads: NonZeroUsize::new(1),
Expand Down
78 changes: 35 additions & 43 deletions examples/with_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ use winit::dpi::LogicalSize;
use winit::event_loop::EventLoop;
use winit::window::{Window, WindowAttributes};

use vello::wgpu;
use vello::wgpu::{self, CommandEncoderDescriptor};

#[cfg(not(any(target_arch = "wasm32", target_os = "android")))]
mod hot_reload;
Expand Down Expand Up @@ -213,7 +213,6 @@ impl ApplicationHandler<UserEvent> for VelloApp<'_> {
let mut renderer = Renderer::new(
&self.context.devices[id].device,
RendererOptions {
surface_format: Some(render_state.surface.format),
use_cpu: self.use_cpu,
antialiasing_support: AA_CONFIGS.iter().copied().collect(),
num_init_threads: NonZeroUsize::new(self.num_init_threads),
Expand Down Expand Up @@ -547,53 +546,47 @@ impl ApplicationHandler<UserEvent> for VelloApp<'_> {
}
}
drop(encoding_span);
let texture_span = tracing::trace_span!("Getting texture").entered();
let surface_texture = surface
.surface
.get_current_texture()
.expect("failed to get surface texture");

drop(texture_span);
let render_span = tracing::trace_span!("Dispatching render").entered();
// Note: we don't run the async/"robust" pipeline, as
// it requires more async wiring for the readback. See
// [#gpu > async on wasm](https://xi.zulipchat.com/#narrow/stream/197075-gpu/topic/async.20on.20wasm)
#[allow(deprecated)]
// #[expect(deprecated, reason = "This deprecation is not targeted at us.")] // Our MSRV is too low to use `expect`
if self.async_pipeline && cfg!(not(target_arch = "wasm32")) {
self.scene_complexity = vello::util::block_on_wgpu(
self.renderers[surface.dev_id]
.as_mut()
.unwrap()
.render_to_texture(
&device_handle.device,
self.renderers[surface.dev_id]
.as_mut()
.unwrap()
.render_to_surface_async(
&device_handle.device,
&device_handle.queue,
&self.scene,
&surface_texture,
&render_params,
self.debug,
),
&device_handle.queue,
&self.scene,
&surface.target_view,
&render_params,
)
.expect("failed to render to surface");
} else {
self.renderers[surface.dev_id]
.as_mut()
.unwrap()
.render_to_surface(
&device_handle.device,
&device_handle.queue,
&self.scene,
&surface_texture,
&render_params,
)
.expect("failed to render to surface");
}
surface_texture.present();
drop(render_span);

let texture_span = tracing::trace_span!("Blitting to surface").entered();
let surface_texture = surface
.surface
.get_current_texture()
.expect("failed to get surface texture");
// Perform the copy
// (TODO: Does it improve throughput to acquire the surface after the previous texture render has happened?)
let mut encoder =
device_handle
.device
.create_command_encoder(&CommandEncoderDescriptor {
label: Some("Surface Blit"),
});
surface.blitter.copy(
&device_handle.device,
&mut encoder,
&surface.target_view,
&surface_texture
.texture
.create_view(&wgpu::TextureViewDescriptor::default()),
);
device_handle.queue.submit([encoder.finish()]);
surface_texture.present();
drop(texture_span);

{
let _poll_aspan = tracing::trace_span!("Polling wgpu device").entered();
let _poll_span = tracing::trace_span!("Polling wgpu device").entered();
device_handle.device.poll(wgpu::Maintain::Poll);
}
let new_time = Instant::now();
Expand Down Expand Up @@ -684,7 +677,6 @@ fn run(
let mut renderer = Renderer::new(
&render_cx.devices[id].device,
RendererOptions {
surface_format: Some(render_state.surface.format),
use_cpu: args.use_cpu,
antialiasing_support: AA_CONFIGS.iter().copied().collect(),
// We currently initialise on one thread on WASM, but mark this here
Expand Down
3 changes: 1 addition & 2 deletions vello/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ default = ["wgpu"]
# bump-allocated GPU memory.
# TODO: Turn this into a runtime option used at resolve time and remove the feature.
bump_estimate = ["vello_encoding/bump_estimate"]
wgpu = ["dep:wgpu", "dep:vello_shaders", "dep:futures-intrusive"]
wgpu = ["dep:wgpu", "dep:vello_shaders"]

# Development only features

Expand Down Expand Up @@ -50,7 +50,6 @@ peniko = { workspace = true }
wgpu = { workspace = true, optional = true }
log = { workspace = true }
static_assertions = { workspace = true }
futures-intrusive = { workspace = true, optional = true }
wgpu-profiler = { workspace = true, optional = true }
thiserror = { workspace = true }
# TODO: Add feature for built-in bitmap emoji support?
Expand Down
Loading