Skip to content

Commit

Permalink
Remove render_to_surface (linebender#803)
Browse files Browse the repository at this point in the history
Replace with blitting/texture utilities in the `utils` module.
Fixes linebender#549

Incompatible with linebender#801. I have a follow-up which shows you would do
transparency, but my current thinking is that you should drop off the
"utils" happy path if you need that. I could be convinced otherwise.
  • Loading branch information
DJMcNab authored Feb 11, 2025
1 parent 178d295 commit 782fb5a
Show file tree
Hide file tree
Showing 13 changed files with 271 additions and 452 deletions.
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
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
49 changes: 32 additions & 17 deletions examples/with_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,6 @@ impl ApplicationHandler<UserEvent> for VelloApp<'_> {
let 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 @@ -543,13 +542,6 @@ 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 on web, as
// it requires more async wiring for the readback. See
Expand All @@ -564,34 +556,58 @@ impl ApplicationHandler<UserEvent> for VelloApp<'_> {
self.renderers[surface.dev_id]
.as_mut()
.unwrap()
.render_to_surface_async(
.render_to_texture_async(
&device_handle.device,
&device_handle.queue,
&self.scene,
&surface_texture,
&surface.target_view,
&render_params,
self.debug,
),
)
.expect("failed to render to surface");
.expect("failed to render to texture");
} else {
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,
&render_params,
)
.expect("failed to render to surface");
.expect("failed to render to texture");
}
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(&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()]);
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 @@ -679,7 +695,6 @@ fn run(
let 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
20 changes: 7 additions & 13 deletions vello/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,14 @@ To use Vello as the renderer for your PDF reader / GUI toolkit / etc, your code
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: vello::AaSupport::all(),
num_init_threads: NonZeroUsize::new(1),
},
).expect("Failed to create renderer");

// Create scene and draw stuff in it
let mut scene = vello::Scene::new();
scene.fill(
Expand All @@ -83,31 +79,29 @@ scene.fill(
None,
&vello::Circle::new((420.0, 200.0), 120.0),
);

// Draw more stuff
scene.push_layer(...);
scene.fill(...);
scene.stroke(...);
scene.pop_layer(...);

// Render to your window/buffer/etc.
let surface_texture = surface.get_current_texture()
.expect("failed to get surface texture");
let texture = device.create_texture(&...);
// Render to a wgpu Texture
renderer
.render_to_surface(
.render_to_texture(
&device,
&queue,
&scene,
&surface_texture,
&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 surface texture, such as blitting it to the Surface using
// wgpu::util::TextureBlitter.
```

See the repository's [`examples`](https://github.com/linebender/vello/tree/main/examples) directory for code that integrates with frameworks like winit.
Expand Down
Loading

0 comments on commit 782fb5a

Please sign in to comment.