lumen_engine/node/processing/
resize.rs1use crate::node::{NodeId, NodeParamEvalContext, NodeParams, PortRef};
2
3use crate::gpu::{
4 BoundFrame, CompiledOutput, FrameBindContext, GpuCompileNode, GpuCompiledNode, RasterHandle,
5 compiler,
6};
7
8pub(crate) const SHADER: &str = include_str!("resize.wgsl");
9
10#[derive(
11 Debug, Clone, Copy, PartialEq, Eq, Default, lumen_macros::NodeEnum, lumen_macros::Delegate,
12)]
13#[repr(i64)]
14#[delegate(kind = "enum")]
15pub enum ResizeMode {
16 #[default]
17 Stretch = 0,
18 Fit = 1,
19 Fill = 2,
20}
21
22#[derive(
23 Debug, Clone, Copy, PartialEq, Eq, Default, lumen_macros::NodeEnum, lumen_macros::Delegate,
24)]
25#[repr(i64)]
26#[delegate(kind = "enum")]
27pub enum ResizeSampling {
28 Nearest = 0,
29 #[default]
30 Linear = 1,
31}
32
33#[derive(Debug, Clone, lumen_macros::Delegate)]
35pub struct ResizeParams {
36 #[meta(min = 1, step = 1)]
38 pub width: i64,
39 #[meta(min = 1, step = 1)]
41 pub height: i64,
42 #[meta(kind = "enum", enum_type = ResizeMode)]
44 pub mode: ResizeMode,
45 #[meta(kind = "enum", enum_type = ResizeSampling)]
47 pub sampling: ResizeSampling,
48}
49
50impl Default for ResizeParams {
51 fn default() -> Self {
52 Self {
53 width: 1,
54 height: 1,
55 mode: ResizeMode::Stretch,
56 sampling: ResizeSampling::Linear,
57 }
58 }
59}
60
61#[derive(Debug, Clone, lumen_macros::Node)]
63#[node(kind = "resize", name = "Resize", category = "processing")]
64pub struct Resize {
65 pub id: NodeId,
66 #[params]
67 pub params: ResizeParamsDelegate,
68
69 #[input()]
70 pub source: PortRef,
71}
72
73impl Default for Resize {
74 fn default() -> Self {
75 Self {
76 id: NodeId::new(0),
77 params: ResizeParamsDelegate::default(),
78 source: PortRef::empty(),
79 }
80 }
81}
82
83impl GpuCompileNode for Resize {
84 fn compile_gpu(
85 &self,
86 ctx: &mut crate::gpu::CompileContext<'_>,
87 port: &PortRef,
88 ) -> crate::Result<CompiledOutput> {
89 if port.port != "output" {
90 return Err(ctx.missing_output(self.id, &port.port));
91 }
92
93 let source = ctx
94 .compile_port(&self.source)?
95 .into_raster(self.source.id, &self.source.port)?;
96 let size = lumen_gpu::Size::new(
97 ctx.static_dimension(&self.params.width, self.id, "width")?,
98 ctx.static_dimension(&self.params.height, self.id, "height")?,
99 );
100 let texture = ctx.builder_mut().texture_for(
101 lumen_gpu::NodeKey(self.id.0),
102 Some(format!("resize:{}:output", self.id.0)),
103 lumen_gpu::TextureDesc::storage(size, lumen_gpu::wgpu::TextureFormat::Rgba8Unorm),
104 );
105 let params = ctx.builder_mut().buffer_for(
106 lumen_gpu::NodeKey(self.id.0),
107 Some(format!("resize:{}:params", self.id.0)),
108 lumen_gpu::BufferDesc::uniform(std::mem::size_of::<compiler::ResizeParams>() as u64),
109 );
110 let program = ctx.spatial_program(self.id, "resize", SHADER);
111 ctx.builder_mut().compute_pass(lumen_gpu::ComputePassDesc {
112 label: Some(format!("resize:{}:apply", self.id.0)),
113 owner: Some(lumen_gpu::NodeKey(self.id.0)),
114 program,
115 bindings: compiler::spatial_bindings(source.texture, params, texture),
116 dispatch: compiler::dispatch_for(size).into(),
117 });
118 ctx.builder_mut().param(
119 lumen_gpu::ParamKey {
120 owner: lumen_gpu::NodeKey(self.id.0),
121 slot: 0,
122 },
123 lumen_gpu::ParamTarget::Buffer(params),
124 );
125 ctx.register_compiled_node(CompiledResize {
126 node_id: self.id,
127 params: self.params.clone(),
128 buffer: params,
129 });
130
131 Ok(CompiledOutput::Raster(RasterHandle {
132 texture,
133 domain: lumen_gpu::TextureDomain::full_frame(size),
134 metadata: source.metadata,
135 }))
136 }
137}
138
139#[derive(Debug, Clone)]
140struct CompiledResize {
141 node_id: NodeId,
142 params: ResizeParamsDelegate,
143 buffer: lumen_gpu::BufferId,
144}
145
146impl GpuCompiledNode for CompiledResize {
147 fn node_id(&self) -> NodeId {
148 self.node_id
149 }
150
151 fn bind(&self, ctx: &FrameBindContext<'_>, bound: &mut BoundFrame) -> crate::Result<()> {
152 let evaluated = self.params.eval(&NodeParamEvalContext {
153 node_id: self.node_id,
154 expr: &ctx.expr_context(self.node_id, "params"),
155 })?;
156 let params = compiler::ResizeParams {
157 size: [
158 evaluated.width.max(1) as u32,
159 evaluated.height.max(1) as u32,
160 ],
161 mode: evaluated.mode as u32,
162 sampling: evaluated.sampling as u32,
163 };
164 bound.write_buffer(self.buffer, 0, bytemuck::bytes_of(¶ms));
165 Ok(())
166 }
167}