Skip to content

Commit 5069ece

Browse files
committed
create target texture lazily
1 parent 8b3d867 commit 5069ece

File tree

2 files changed

+51
-81
lines changed

2 files changed

+51
-81
lines changed

node-graph/gstd/src/wasm_application_io.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ async fn render_canvas(
145145
if !data.contains_artboard() && !render_config.hide_artboards {
146146
background = Color::WHITE;
147147
}
148-
exec.render_vello_scene(&scene, &surface_handle, footprint.resolution.x, footprint.resolution.y, &context, background)
148+
exec.render_vello_scene(&scene, &surface_handle, footprint.resolution, &context, background)
149149
.await
150150
.expect("Failed to render Vello scene");
151151

node-graph/wgpu-executor/src/lib.rs

Lines changed: 50 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ use anyhow::Result;
44
pub use context::Context;
55
use dyn_any::StaticType;
66
use glam::UVec2;
7-
use graphene_application_io::{ApplicationIo, EditorApi, SurfaceHandle};
7+
use graphene_application_io::{ApplicationIo, EditorApi, SurfaceHandle, SurfaceId};
88
use graphene_core::{Color, Ctx};
99
pub use graphene_svg_renderer::RenderContext;
10-
use std::sync::Arc;
10+
use std::sync::{Arc, Mutex};
1111
use vello::Error;
1212
use vello::{AaConfig, AaSupport, RenderParams, Renderer, RendererOptions, Scene};
13-
use wgpu::TextureFormat;
1413
use wgpu::util::TextureBlitter;
1514
use wgpu::{Origin3d, SurfaceConfiguration, TextureAspect};
1615

@@ -35,19 +34,17 @@ impl<'a, T: ApplicationIo<Executor = WgpuExecutor>> From<&'a EditorApi<T>> for &
3534
pub type WgpuSurface = Arc<SurfaceHandle<Surface>>;
3635
pub type WgpuWindow = Arc<SurfaceHandle<WindowHandle>>;
3736

38-
impl graphene_application_io::Size for Surface {
39-
fn size(&self) -> UVec2 {
40-
self.resolution
41-
}
42-
}
43-
4437
pub struct Surface {
4538
pub inner: wgpu::Surface<'static>,
46-
pub target_texture: wgpu::Texture,
47-
pub target_view: wgpu::TextureView,
48-
pub blitter: wgpu::util::TextureBlitter,
49-
resolution: UVec2,
39+
pub target_texture: Mutex<Option<TargetTexture>>,
40+
pub blitter: TextureBlitter,
41+
}
42+
43+
pub struct TargetTexture {
44+
view: wgpu::TextureView,
45+
size: UVec2,
5046
}
47+
5148
#[cfg(target_arch = "wasm32")]
5249
pub type Window = web_sys::HtmlCanvasElement;
5350
#[cfg(not(target_arch = "wasm32"))]
@@ -58,29 +55,55 @@ unsafe impl StaticType for Surface {
5855
}
5956

6057
impl WgpuExecutor {
61-
pub async fn render_vello_scene(&self, scene: &Scene, surface: &WgpuSurface, width: u32, height: u32, context: &RenderContext, background: Color) -> Result<()> {
58+
pub async fn render_vello_scene(&self, scene: &Scene, surface: &WgpuSurface, size: UVec2, context: &RenderContext, background: Color) -> Result<()> {
59+
let mut guard = surface.surface.target_texture.lock().unwrap();
60+
let target_texture = if let Some(target_texture) = &*guard
61+
&& target_texture.size == size
62+
{
63+
target_texture
64+
} else {
65+
let texture = self.context.device.create_texture(&wgpu::TextureDescriptor {
66+
label: None,
67+
size: wgpu::Extent3d {
68+
width: size.x,
69+
height: size.y,
70+
depth_or_array_layers: 1,
71+
},
72+
mip_level_count: 1,
73+
sample_count: 1,
74+
dimension: wgpu::TextureDimension::D2,
75+
usage: wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING,
76+
format: wgpu::TextureFormat::Rgba8Unorm,
77+
view_formats: &[],
78+
});
79+
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
80+
*guard = Some(TargetTexture { size, view });
81+
guard.as_ref().unwrap()
82+
};
83+
6284
let surface_inner = &surface.surface.inner;
6385
let surface_caps = surface_inner.get_capabilities(&self.context.adapter);
6486
surface_inner.configure(
6587
&self.context.device,
6688
&SurfaceConfiguration {
6789
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::STORAGE_BINDING,
6890
format: wgpu::TextureFormat::Rgba8Unorm,
69-
width,
70-
height,
91+
width: size.x,
92+
height: size.y,
7193
present_mode: surface_caps.present_modes[0],
7294
alpha_mode: wgpu::CompositeAlphaMode::Opaque,
7395
view_formats: vec![],
7496
desired_maximum_frame_latency: 2,
7597
},
7698
);
99+
77100
let [r, g, b, _] = background.to_rgba8_srgb();
78101
let render_params = RenderParams {
79102
// We are using an explicit opaque color here to eliminate the alpha premultiplication step
80103
// which would be required to support a transparent webgpu canvas
81104
base_color: vello::peniko::Color::from_rgba8(r, g, b, 0xff),
82-
width,
83-
height,
105+
width: size.x,
106+
height: size.y,
84107
antialiasing_method: AaConfig::Msaa16,
85108
};
86109

@@ -99,17 +122,15 @@ impl WgpuExecutor {
99122
Some(texture_view),
100123
);
101124
}
102-
renderer
103-
.render_to_texture(&self.context.device, &self.context.queue, scene, &surface.surface.target_view, &render_params)
104-
.unwrap();
125+
renderer.render_to_texture(&self.context.device, &self.context.queue, scene, &target_texture.view, &render_params)?;
105126
}
106127

107128
let surface_texture = surface_inner.get_current_texture()?;
108129
let mut encoder = self.context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Surface Blit") });
109130
surface.surface.blitter.copy(
110131
&self.context.device,
111132
&mut encoder,
112-
&surface.surface.target_view,
133+
&target_texture.view,
113134
&surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default()),
114135
);
115136
self.context.queue.submit([encoder.finish()]);
@@ -121,78 +142,27 @@ impl WgpuExecutor {
121142
#[cfg(target_arch = "wasm32")]
122143
pub fn create_surface(&self, canvas: graphene_application_io::WasmSurfaceHandle) -> Result<SurfaceHandle<Surface>> {
123144
let surface = self.context.instance.create_surface(wgpu::SurfaceTarget::Canvas(canvas.surface))?;
124-
let size = UVec2::ZERO;
125-
126-
let capabilities = surface.get_capabilities(&self.context.adapter);
127-
let format = capabilities
128-
.formats
129-
.into_iter()
130-
.find(|it| matches!(it, TextureFormat::Rgba8Unorm | TextureFormat::Bgra8Unorm))
131-
.ok_or(Error::UnsupportedSurfaceFormat)?;
132-
let target_texture = self.context.device.create_texture(&wgpu::TextureDescriptor {
133-
label: None,
134-
size: wgpu::Extent3d {
135-
width: size.x,
136-
height: size.y,
137-
depth_or_array_layers: 1,
138-
},
139-
mip_level_count: 1,
140-
sample_count: 1,
141-
dimension: wgpu::TextureDimension::D2,
142-
usage: wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING,
143-
format: TextureFormat::Rgba8Unorm,
144-
view_formats: &[],
145-
});
146-
let target_view = target_texture.create_view(&wgpu::TextureViewDescriptor::default());
147-
let blitter = TextureBlitter::new(&self.context.device, format);
148-
149-
Ok(SurfaceHandle {
150-
window_id: canvas.window_id,
151-
surface: Surface {
152-
inner: surface,
153-
resolution: size,
154-
blitter,
155-
target_texture,
156-
target_view,
157-
},
158-
})
145+
self.create_surface_inner(surface, canvas.window_id)
159146
}
160147
#[cfg(not(target_arch = "wasm32"))]
161148
pub fn create_surface(&self, window: SurfaceHandle<Window>) -> Result<SurfaceHandle<Surface>> {
162-
let size = window.surface.inner_size();
163-
let resolution = UVec2::new(size.width, size.height);
164149
let surface = self.context.instance.create_surface(wgpu::SurfaceTarget::Window(Box::new(window.surface)))?;
150+
self.create_surface_inner(surface, window.window_id)
151+
}
165152

153+
pub fn create_surface_inner(&self, surface: wgpu::Surface<'static>, window_id: SurfaceId) -> Result<SurfaceHandle<Surface>> {
166154
let capabilities = surface.get_capabilities(&self.context.adapter);
167155
let format = capabilities
168156
.formats
169157
.into_iter()
170-
.find(|it| matches!(it, TextureFormat::Rgba8Unorm | TextureFormat::Bgra8Unorm))
158+
.find(|it| matches!(it, wgpu::TextureFormat::Rgba8Unorm | wgpu::TextureFormat::Bgra8Unorm))
171159
.ok_or(Error::UnsupportedSurfaceFormat)?;
172-
let target_texture = self.context.device.create_texture(&wgpu::TextureDescriptor {
173-
label: None,
174-
size: wgpu::Extent3d {
175-
width: size.width,
176-
height: size.height,
177-
depth_or_array_layers: 1,
178-
},
179-
mip_level_count: 1,
180-
sample_count: 1,
181-
dimension: wgpu::TextureDimension::D2,
182-
usage: wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING,
183-
format: TextureFormat::Rgba8Unorm,
184-
view_formats: &[],
185-
});
186-
let target_view = target_texture.create_view(&wgpu::TextureViewDescriptor::default());
187160
let blitter = TextureBlitter::new(&self.context.device, format);
188-
189161
Ok(SurfaceHandle {
190-
window_id: window.window_id,
162+
window_id,
191163
surface: Surface {
192164
inner: surface,
193-
resolution,
194-
target_view,
195-
target_texture,
165+
target_texture: Mutex::new(None),
196166
blitter,
197167
},
198168
})

0 commit comments

Comments
 (0)