Skip to main content

lumen_engine/gpu/
types.rs

1use std::collections::HashMap;
2
3use crate::media::MediaFrame;
4use crate::node::{NodeId, PortRef};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum AlphaMode {
8    Premultiplied,
9    Unpremultiplied,
10}
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum ColorSpace {
14    Srgb,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub struct RasterMetadata {
19    pub alpha_mode: AlphaMode,
20    pub color_space: ColorSpace,
21}
22
23impl Default for RasterMetadata {
24    fn default() -> Self {
25        Self {
26            alpha_mode: AlphaMode::Premultiplied,
27            color_space: ColorSpace::Srgb,
28        }
29    }
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub struct RasterHandle {
34    pub texture: lumen_gpu::TextureId,
35    pub domain: lumen_gpu::TextureDomain,
36    pub metadata: RasterMetadata,
37}
38
39#[derive(Debug, Clone, PartialEq, Eq)]
40pub enum CompiledOutput {
41    Raster(RasterHandle),
42    Empty,
43}
44
45impl CompiledOutput {
46    pub fn into_raster(self, node_id: NodeId, _port: &str) -> crate::Result<RasterHandle> {
47        match self {
48            Self::Raster(raster) => Ok(raster),
49            Self::Empty => Err(crate::error::RenderError::InvalidNodeOutputType {
50                frame: 0,
51                node_id,
52                expected: "Raster",
53                actual: "Empty",
54            }
55            .into()),
56        }
57    }
58}
59
60#[derive(Debug, Clone)]
61pub enum FrameBinding {
62    SolidColor {
63        node_id: NodeId,
64        color: crate::node::NodeProperty,
65        buffer: lumen_gpu::BufferId,
66    },
67    Shape {
68        node_id: NodeId,
69        geometry_kind: crate::node::NodeProperty,
70        width: crate::node::NodeProperty,
71        height: crate::node::NodeProperty,
72        border_radius: crate::node::NodeProperty,
73        position: crate::node::NodeProperty,
74        fill_enabled: crate::node::NodeProperty,
75        fill_color: crate::node::NodeProperty,
76        stroke_enabled: crate::node::NodeProperty,
77        stroke_color: crate::node::NodeProperty,
78        stroke_width: crate::node::NodeProperty,
79        buffer: lumen_gpu::BufferId,
80    },
81    Text {
82        node_id: NodeId,
83        content: crate::node::NodeProperty,
84        font_family: crate::node::NodeProperty,
85        font_size: crate::node::NodeProperty,
86        font_weight: crate::node::NodeProperty,
87        font_style: crate::node::NodeProperty,
88        max_width: crate::node::NodeProperty,
89        position: crate::node::NodeProperty,
90        color: crate::node::NodeProperty,
91        alignment_horizontal: crate::node::NodeProperty,
92        alignment_vertical: crate::node::NodeProperty,
93        atlas_texture: lumen_gpu::TextureId,
94        globals_buffer: lumen_gpu::BufferId,
95        instances_buffer: lumen_gpu::BufferId,
96        atlas_size: lumen_gpu::Size,
97        max_glyphs: usize,
98        size: lumen_gpu::Size,
99    },
100    Path {
101        node_id: NodeId,
102        data: crate::node::NodeProperty,
103        position: crate::node::NodeProperty,
104        fill_enabled: crate::node::NodeProperty,
105        fill_color: crate::node::NodeProperty,
106        stroke_enabled: crate::node::NodeProperty,
107        stroke_color: crate::node::NodeProperty,
108        stroke_width: crate::node::NodeProperty,
109        params_buffer: lumen_gpu::BufferId,
110        points_buffer: lumen_gpu::BufferId,
111        max_points: usize,
112    },
113    AlphaPremultiply {
114        node_id: NodeId,
115        mode: crate::node::NodeProperty,
116        buffer: lumen_gpu::BufferId,
117    },
118    ChannelShuffle {
119        node_id: NodeId,
120        red: crate::node::NodeProperty,
121        green: crate::node::NodeProperty,
122        blue: crate::node::NodeProperty,
123        alpha: crate::node::NodeProperty,
124        buffer: lumen_gpu::BufferId,
125    },
126    ColorGrade {
127        node_id: NodeId,
128        lut_source: crate::node::NodeProperty,
129        strength: crate::node::NodeProperty,
130        interpolation: crate::node::NodeProperty,
131        params_buffer: lumen_gpu::BufferId,
132        lut_buffer: lumen_gpu::BufferId,
133    },
134    Exposure {
135        node_id: NodeId,
136        exposure: crate::node::NodeProperty,
137        contrast: crate::node::NodeProperty,
138        offset: crate::node::NodeProperty,
139        buffer: lumen_gpu::BufferId,
140    },
141    HueSaturation {
142        node_id: NodeId,
143        hue_degrees: crate::node::NodeProperty,
144        saturation: crate::node::NodeProperty,
145        lightness: crate::node::NodeProperty,
146        buffer: lumen_gpu::BufferId,
147    },
148    Levels {
149        node_id: NodeId,
150        black_point: crate::node::NodeProperty,
151        white_point: crate::node::NodeProperty,
152        gamma: crate::node::NodeProperty,
153        output_black: crate::node::NodeProperty,
154        output_white: crate::node::NodeProperty,
155        buffer: lumen_gpu::BufferId,
156    },
157    Blur {
158        node_id: NodeId,
159        radius: crate::node::NodeProperty,
160        buffer: lumen_gpu::BufferId,
161    },
162    Curves {
163        node_id: NodeId,
164        curve_source: crate::node::NodeProperty,
165        strength: crate::node::NodeProperty,
166        params_buffer: lumen_gpu::BufferId,
167        curve_buffer: lumen_gpu::BufferId,
168    },
169    Shadow {
170        node_id: NodeId,
171        offset_x: crate::node::NodeProperty,
172        offset_y: crate::node::NodeProperty,
173        radius: crate::node::NodeProperty,
174        color: crate::node::NodeProperty,
175        opacity: crate::node::NodeProperty,
176        buffer: lumen_gpu::BufferId,
177    },
178    WgslShader {
179        node_id: NodeId,
180        shader: crate::node::NodeProperty,
181        bindings: crate::node::NodeProperty,
182        buffer: lumen_gpu::BufferId,
183    },
184    Boolean {
185        node_id: NodeId,
186        operation: crate::node::NodeProperty,
187        threshold: crate::node::NodeProperty,
188        buffer: lumen_gpu::BufferId,
189    },
190    RasterMultiMerge {
191        node_id: NodeId,
192        opacity: crate::node::NodeProperty,
193        blend_mode: crate::node::NodeProperty,
194        buffer: lumen_gpu::BufferId,
195    },
196    Merge {
197        node_id: NodeId,
198        opacity: crate::node::NodeProperty,
199        blend_mode: crate::node::NodeProperty,
200        has_mask: bool,
201        buffer: lumen_gpu::BufferId,
202    },
203    Memo {
204        node_id: NodeId,
205        cache_id: crate::node::NodeProperty,
206        allow_expressions: crate::node::NodeProperty,
207    },
208    TimeRemap {
209        node_id: NodeId,
210        frame: crate::node::NodeProperty,
211        loop_enabled: crate::node::NodeProperty,
212        loop_start: crate::node::NodeProperty,
213        loop_end: crate::node::NodeProperty,
214    },
215    Transform {
216        node_id: NodeId,
217        scale_x: crate::node::NodeProperty,
218        scale_y: crate::node::NodeProperty,
219        translate_x: crate::node::NodeProperty,
220        translate_y: crate::node::NodeProperty,
221        rotate: crate::node::NodeProperty,
222        pivot_x: crate::node::NodeProperty,
223        pivot_y: crate::node::NodeProperty,
224        sampling: crate::node::NodeProperty,
225        buffer: lumen_gpu::BufferId,
226    },
227    Crop {
228        node_id: NodeId,
229        x: crate::node::NodeProperty,
230        y: crate::node::NodeProperty,
231        width: crate::node::NodeProperty,
232        height: crate::node::NodeProperty,
233        buffer: lumen_gpu::BufferId,
234    },
235    Resize {
236        node_id: NodeId,
237        width: crate::node::NodeProperty,
238        height: crate::node::NodeProperty,
239        mode: crate::node::NodeProperty,
240        sampling: crate::node::NodeProperty,
241        buffer: lumen_gpu::BufferId,
242    },
243    Switch {
244        node_id: NodeId,
245        selected_layer: Option<usize>,
246    },
247    MediaInput {
248        node_id: NodeId,
249        source: crate::node::NodeProperty,
250        texture: lumen_gpu::TextureId,
251        size: lumen_gpu::Size,
252    },
253}
254
255impl FrameBinding {
256    pub fn node_id(&self) -> NodeId {
257        match self {
258            Self::SolidColor { node_id, .. }
259            | Self::Shape { node_id, .. }
260            | Self::Text { node_id, .. }
261            | Self::Path { node_id, .. }
262            | Self::AlphaPremultiply { node_id, .. }
263            | Self::ChannelShuffle { node_id, .. }
264            | Self::ColorGrade { node_id, .. }
265            | Self::Exposure { node_id, .. }
266            | Self::HueSaturation { node_id, .. }
267            | Self::Levels { node_id, .. }
268            | Self::Blur { node_id, .. }
269            | Self::Curves { node_id, .. }
270            | Self::Shadow { node_id, .. }
271            | Self::WgslShader { node_id, .. }
272            | Self::Boolean { node_id, .. }
273            | Self::RasterMultiMerge { node_id, .. }
274            | Self::Merge { node_id, .. }
275            | Self::Memo { node_id, .. }
276            | Self::TimeRemap { node_id, .. }
277            | Self::Transform { node_id, .. }
278            | Self::Crop { node_id, .. }
279            | Self::Resize { node_id, .. }
280            | Self::Switch { node_id, .. }
281            | Self::MediaInput { node_id, .. } => *node_id,
282        }
283    }
284}
285
286#[derive(Debug, Clone)]
287pub struct CompiledComposition {
288    pub plan: lumen_gpu::RenderPlan,
289    pub output: RasterHandle,
290    pub node_outputs: HashMap<PortRef, CompiledOutput>,
291    pub frame_bindings: Vec<FrameBinding>,
292    pub frame_binding_frames: Vec<Option<u32>>,
293}
294
295#[derive(Debug, Clone, Default)]
296pub struct BoundFrame {
297    buffer_uploads: Vec<(lumen_gpu::BufferId, u64, Vec<u8>)>,
298    texture_uploads: Vec<TextureUpload>,
299    media_textures: Vec<MediaTextureUpload>,
300}
301
302#[derive(Debug, Clone)]
303enum TextureUpload {
304    Rgba8 {
305        id: lumen_gpu::TextureId,
306        data: Vec<u8>,
307        bytes_per_row: u32,
308        rows_per_image: u32,
309    },
310    Rgba8Region {
311        id: lumen_gpu::TextureId,
312        data: Vec<u8>,
313        origin: [u32; 3],
314        size: lumen_gpu::Size,
315        bytes_per_row: u32,
316        rows_per_image: u32,
317    },
318    Rgba16Float {
319        id: lumen_gpu::TextureId,
320        data: Vec<u16>,
321        bytes_per_row: u32,
322        rows_per_image: u32,
323    },
324}
325
326#[derive(Debug, Clone, PartialEq, Eq, Hash)]
327pub struct MediaTextureKey {
328    pub source: String,
329    pub frame: Option<u32>,
330    pub width: u32,
331    pub height: u32,
332}
333
334#[derive(Debug, Clone)]
335pub struct MediaTextureUpload {
336    pub texture: lumen_gpu::TextureId,
337    pub key: MediaTextureKey,
338    pub frame: MediaFrame,
339    pub size: lumen_gpu::Size,
340}
341
342impl BoundFrame {
343    pub fn new() -> Self {
344        Self::default()
345    }
346
347    pub fn write_buffer(&mut self, id: lumen_gpu::BufferId, offset: u64, data: impl Into<Vec<u8>>) {
348        self.buffer_uploads.push((id, offset, data.into()));
349    }
350
351    pub fn write_texture_rgba8(
352        &mut self,
353        id: lumen_gpu::TextureId,
354        data: impl Into<Vec<u8>>,
355        bytes_per_row: u32,
356        rows_per_image: u32,
357    ) {
358        self.texture_uploads.push(TextureUpload::Rgba8 {
359            id,
360            data: data.into(),
361            bytes_per_row,
362            rows_per_image,
363        });
364    }
365
366    pub fn write_texture_rgba8_region(
367        &mut self,
368        id: lumen_gpu::TextureId,
369        data: impl Into<Vec<u8>>,
370        origin: [u32; 3],
371        size: lumen_gpu::Size,
372        bytes_per_row: u32,
373        rows_per_image: u32,
374    ) {
375        self.texture_uploads.push(TextureUpload::Rgba8Region {
376            id,
377            data: data.into(),
378            origin,
379            size,
380            bytes_per_row,
381            rows_per_image,
382        });
383    }
384
385    pub fn write_texture_rgba16_float(
386        &mut self,
387        id: lumen_gpu::TextureId,
388        data: impl Into<Vec<u16>>,
389        bytes_per_row: u32,
390        rows_per_image: u32,
391    ) {
392        self.texture_uploads.push(TextureUpload::Rgba16Float {
393            id,
394            data: data.into(),
395            bytes_per_row,
396            rows_per_image,
397        });
398    }
399
400    pub fn use_media_texture(
401        &mut self,
402        texture: lumen_gpu::TextureId,
403        key: MediaTextureKey,
404        frame: MediaFrame,
405        size: lumen_gpu::Size,
406    ) {
407        self.media_textures.push(MediaTextureUpload {
408            texture,
409            key,
410            frame,
411            size,
412        });
413    }
414
415    pub fn media_textures(&self) -> &[MediaTextureUpload] {
416        &self.media_textures
417    }
418
419    pub fn buffer_upload_count(&self) -> usize {
420        self.buffer_uploads.len()
421    }
422
423    pub fn texture_upload_count(&self) -> usize {
424        self.texture_uploads.len()
425    }
426
427    pub fn frame_update(&self) -> lumen_gpu::FrameUpdate<'_> {
428        let mut update = lumen_gpu::FrameUpdate::new();
429        for (id, offset, data) in &self.buffer_uploads {
430            update.write_buffer(*id, *offset, data);
431        }
432        for upload in &self.texture_uploads {
433            match upload {
434                TextureUpload::Rgba8 {
435                    id,
436                    data,
437                    bytes_per_row,
438                    rows_per_image,
439                } => {
440                    update.write_texture_rgba8(*id, data, *bytes_per_row, *rows_per_image);
441                }
442                TextureUpload::Rgba8Region {
443                    id,
444                    data,
445                    origin,
446                    size,
447                    bytes_per_row,
448                    rows_per_image,
449                } => {
450                    update.write_texture_rgba8_region(
451                        *id,
452                        data,
453                        *origin,
454                        *size,
455                        *bytes_per_row,
456                        *rows_per_image,
457                    );
458                }
459                TextureUpload::Rgba16Float {
460                    id,
461                    data,
462                    bytes_per_row,
463                    rows_per_image,
464                } => {
465                    update.write_texture_rgba16_float(*id, data, *bytes_per_row, *rows_per_image);
466                }
467            }
468        }
469        update
470    }
471}