lumen_engine/node/source/
background.rs1use crate::node::{NodeId, NodeParamEvalContext, NodeParams, vector::paint::Paint};
2
3use crate::gpu::{
4 BoundFrame, CompiledOutput, FrameBindContext, GpuCompileNode, GpuCompiledNode, RasterHandle,
5 RasterMetadata, compiler,
6};
7
8pub(crate) const SHADER: &str = include_str!("background.wgsl");
9
10#[derive(Debug, Clone, lumen_macros::Delegate)]
11pub struct BackgroundParams {
12 #[meta()]
14 pub paint: Paint,
15 #[meta(min = 0, step = 1)]
17 pub width: u32,
18 #[meta(min = 0, step = 1)]
20 pub height: u32,
21}
22
23impl Default for BackgroundParams {
24 fn default() -> Self {
25 Self {
26 paint: Paint::solid([0, 0, 0, 255]),
27 width: 0,
28 height: 0,
29 }
30 }
31}
32
33#[derive(Debug, Clone, lumen_macros::Node)]
35#[node(kind = "background", name = "Background", category = "source")]
36pub struct Background {
37 pub id: NodeId,
38 #[params]
39 pub params: BackgroundParamsDelegate,
40}
41
42impl Default for Background {
43 fn default() -> Self {
44 Self {
45 id: NodeId::new(0),
46 params: BackgroundParamsDelegate::default(),
47 }
48 }
49}
50
51#[derive(Debug, Clone)]
52struct CompiledBackground {
53 node_id: NodeId,
54 params: BackgroundParamsDelegate,
55 buffer: lumen_gpu::BufferId,
56}
57
58impl GpuCompiledNode for CompiledBackground {
59 fn node_id(&self) -> NodeId {
60 self.node_id
61 }
62
63 fn bind(&self, ctx: &FrameBindContext<'_>, bound: &mut BoundFrame) -> crate::Result<()> {
64 let params = self.params.eval(&NodeParamEvalContext {
65 node_id: self.node_id,
66 expr: &ctx.expr_context(self.node_id, "params"),
67 })?;
68 bound.write_buffer(
69 self.buffer,
70 0,
71 bytemuck::bytes_of(¶ms.paint.to_gpu([0, 0, 0, 255])),
72 );
73 Ok(())
74 }
75}
76
77impl GpuCompileNode for Background {
78 fn compile_gpu(
79 &self,
80 ctx: &mut crate::gpu::CompileContext<'_>,
81 port: &crate::node::PortRef,
82 ) -> crate::Result<CompiledOutput> {
83 if port.port != "output" {
84 return Err(ctx.missing_output(self.id, &port.port));
85 }
86
87 let params = self.params.eval(&NodeParamEvalContext {
88 node_id: self.id,
89 expr: &ctx.expr_context(self.id, "params"),
90 })?;
91 let width = ctx.static_dimension_value(i64::from(params.width), "width");
92 let height = ctx.static_dimension_value(i64::from(params.height), "height");
93 let size = lumen_gpu::Size::new(width, height);
94 let texture = ctx.builder_mut().texture_for(
95 lumen_gpu::NodeKey(self.id.0),
96 Some(format!("background:{}:output", self.id.0)),
97 lumen_gpu::TextureDesc::storage(size, lumen_gpu::wgpu::TextureFormat::Rgba8Unorm),
98 );
99 let buffer = ctx.builder_mut().buffer_for(
100 lumen_gpu::NodeKey(self.id.0),
101 Some(format!("background:{}:params", self.id.0)),
102 lumen_gpu::BufferDesc::uniform(
103 std::mem::size_of::<crate::node::vector::paint::GpuPaint>() as u64,
104 ),
105 );
106 let program = ctx.builder_mut().program_for(
107 lumen_gpu::NodeKey(self.id.0),
108 lumen_gpu::ProgramDesc::Compute(lumen_gpu::ComputeProgramDesc {
109 label: Some("background".to_string()),
110 shader: SHADER.to_string(),
111 entry: "cs_main".to_string(),
112 bind_groups: lumen_gpu::BindGroupLayoutSpec::single(vec![
113 lumen_gpu::BindingLayoutEntry::uniform(
114 0,
115 lumen_gpu::wgpu::ShaderStages::COMPUTE,
116 ),
117 lumen_gpu::BindingLayoutEntry::storage_texture(
118 1,
119 lumen_gpu::wgpu::ShaderStages::COMPUTE,
120 lumen_gpu::wgpu::TextureFormat::Rgba8Unorm,
121 lumen_gpu::wgpu::StorageTextureAccess::WriteOnly,
122 ),
123 ]),
124 }),
125 );
126 ctx.builder_mut().compute_pass(lumen_gpu::ComputePassDesc {
127 label: Some(format!("background:{}:fill", self.id.0)),
128 owner: Some(lumen_gpu::NodeKey(self.id.0)),
129 program,
130 bindings: vec![
131 lumen_gpu::Binding::uniform(0, 0, buffer),
132 lumen_gpu::Binding::storage_texture(0, 1, texture),
133 ],
134 dispatch: compiler::dispatch_for(size).into(),
135 });
136 ctx.builder_mut().param(
137 lumen_gpu::ParamKey {
138 owner: lumen_gpu::NodeKey(self.id.0),
139 slot: 0,
140 },
141 lumen_gpu::ParamTarget::Buffer(buffer),
142 );
143 ctx.register_compiled_node(CompiledBackground {
144 node_id: self.id,
145 params: self.params.clone(),
146 buffer,
147 });
148
149 Ok(CompiledOutput::Raster(RasterHandle {
150 texture,
151 domain: lumen_gpu::TextureDomain::full_frame(size),
152 metadata: RasterMetadata::default(),
153 }))
154 }
155}