Skip to content

Commit f17644e

Browse files
committed
Refactor TargetTexture into proper abstraction with ensure_size() method
1 parent aadc989 commit f17644e

2 files changed

Lines changed: 66 additions & 19 deletions

File tree

  • desktop/src/render
  • node-graph/libraries/wgpu-executor/src

desktop/src/render/state.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::window::Window;
22

33
use crate::wrapper::{Color, WgpuContext, WgpuExecutor};
4+
use wgpu_executor::TargetTexture;
45

56
#[derive(derivative::Derivative)]
67
#[derivative(Debug)]
@@ -18,6 +19,7 @@ pub(crate) struct RenderState {
1819
viewport_offset: [f32; 2],
1920
viewport_texture: Option<wgpu::Texture>,
2021
overlays_texture: Option<wgpu::Texture>,
22+
overlays_target_texture: Option<TargetTexture>,
2123
ui_texture: Option<wgpu::Texture>,
2224
bind_group: Option<wgpu::BindGroup>,
2325
#[derivative(Debug = "ignore")]
@@ -182,6 +184,7 @@ impl RenderState {
182184
viewport_offset: [0.0, 0.0],
183185
viewport_texture: None,
184186
overlays_texture: None,
187+
overlays_target_texture: None,
185188
ui_texture: None,
186189
bind_group: None,
187190
overlays_scene: None,
@@ -236,12 +239,18 @@ impl RenderState {
236239
return;
237240
};
238241
let size = glam::UVec2::new(viewport_texture.width(), viewport_texture.height());
239-
let texture = futures::executor::block_on(self.executor.render_vello_scene_to_texture(&scene, size, &Default::default(), Color::TRANSPARENT));
240-
let Ok(texture) = texture else {
241-
tracing::error!("Error rendering overlays");
242+
let result = futures::executor::block_on(
243+
self.executor
244+
.render_vello_scene_to_target_texture(&scene, size, &Default::default(), Color::TRANSPARENT, &mut self.overlays_target_texture),
245+
);
246+
if let Err(e) = result {
247+
tracing::error!("Error rendering overlays: {:?}", e);
242248
return;
243-
};
244-
self.bind_overlays_texture(texture);
249+
}
250+
if let Some(target_texture) = &self.overlays_target_texture {
251+
self.overlays_texture = Some(target_texture.texture().clone());
252+
self.update_bindgroup();
253+
}
245254
}
246255

247256
pub(crate) fn render(&mut self, window: &Window) -> Result<(), RenderError> {

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

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,47 @@ pub struct TargetTexture {
5454
size: UVec2,
5555
}
5656

57+
impl TargetTexture {
58+
/// Ensures the texture has the specified size, creating a new one if needed.
59+
/// This allows reusing the same texture across frames when the size hasn't changed.
60+
pub fn ensure_size(&mut self, device: &wgpu::Device, size: UVec2) {
61+
let size = size.max(UVec2::ONE);
62+
if self.size == size {
63+
return;
64+
}
65+
66+
let texture = device.create_texture(&wgpu::TextureDescriptor {
67+
label: None,
68+
size: wgpu::Extent3d {
69+
width: size.x,
70+
height: size.y,
71+
depth_or_array_layers: 1,
72+
},
73+
mip_level_count: 1,
74+
sample_count: 1,
75+
dimension: wgpu::TextureDimension::D2,
76+
usage: wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_SRC,
77+
format: VELLO_SURFACE_FORMAT,
78+
view_formats: &[],
79+
});
80+
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
81+
82+
self.texture = texture;
83+
self.view = view;
84+
self.size = size;
85+
}
86+
87+
/// Returns a reference to the texture view for rendering.
88+
pub fn view(&self) -> &wgpu::TextureView {
89+
&self.view
90+
}
91+
92+
/// Returns a reference to the underlying texture.
93+
pub fn texture(&self) -> &wgpu::Texture {
94+
&self.texture
95+
}
96+
}
97+
5798
#[cfg(target_family = "wasm")]
5899
pub type Window = web_sys::HtmlCanvasElement;
59100
#[cfg(not(target_family = "wasm"))]
@@ -71,19 +112,14 @@ impl WgpuExecutor {
71112
self.render_vello_scene_to_target_texture(scene, size, context, background, &mut output).await?;
72113
Ok(output.unwrap().texture)
73114
}
74-
75-
async fn render_vello_scene_to_target_texture(&self, scene: &Scene, size: UVec2, context: &RenderContext, background: Color, output: &mut Option<TargetTexture>) -> Result<()> {
76-
let size = size.max(UVec2::ONE);
77-
let target_texture = if let Some(target_texture) = output
78-
&& target_texture.size == size
79-
{
80-
target_texture
81-
} else {
115+
pub async fn render_vello_scene_to_target_texture(&self, scene: &Scene, size: UVec2, context: &RenderContext, background: Color, output: &mut Option<TargetTexture>) -> Result<()> {
116+
// Initialize with a minimal texture if this is the first call
117+
if output.is_none() {
82118
let texture = self.context.device.create_texture(&wgpu::TextureDescriptor {
83119
label: None,
84120
size: wgpu::Extent3d {
85-
width: size.x,
86-
height: size.y,
121+
width: 1,
122+
height: 1,
87123
depth_or_array_layers: 1,
88124
},
89125
mip_level_count: 1,
@@ -94,9 +130,11 @@ impl WgpuExecutor {
94130
view_formats: &[],
95131
});
96132
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
97-
*output = Some(TargetTexture { texture, view, size });
98-
output.as_mut().unwrap()
99-
};
133+
*output = Some(TargetTexture { texture, view, size: UVec2::ONE });
134+
}
135+
136+
let target_texture = output.as_mut().unwrap();
137+
target_texture.ensure_size(&self.context.device, size);
100138

101139
let [r, g, b, a] = background.to_rgba8_srgb();
102140
let render_params = RenderParams {
@@ -117,7 +155,7 @@ impl WgpuExecutor {
117155
};
118156
renderer.override_image(&image_brush.image, Some(texture_view));
119157
}
120-
renderer.render_to_texture(&self.context.device, &self.context.queue, scene, &target_texture.view, &render_params)?;
158+
renderer.render_to_texture(&self.context.device, &self.context.queue, scene, target_texture.view(), &render_params)?;
121159
for (image_brush, _) in context.resource_overrides.iter() {
122160
renderer.override_image(&image_brush.image, None);
123161
}

0 commit comments

Comments
 (0)