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, PartialEq, Eq, Hash)]
61pub struct FramePortRef {
62 pub port: PortRef,
63 pub frame: u32,
64}
65
66impl FramePortRef {
67 pub fn new(port: PortRef, frame: u32) -> Self {
68 Self { port, frame }
69 }
70}
71
72pub trait GpuCompiledNode: std::fmt::Debug + Send + Sync {
73 fn node_id(&self) -> NodeId;
74
75 fn bind(
76 &self,
77 ctx: &crate::gpu::FrameBindContext<'_>,
78 bound: &mut BoundFrame,
79 ) -> crate::Result<()>;
80}
81
82#[derive(Debug)]
83pub struct CompiledComposition {
84 pub plan: lumen_gpu::RenderPlan,
85 pub output: RasterHandle,
86 pub node_outputs: HashMap<PortRef, CompiledOutput>,
87 pub compiled_nodes: HashMap<NodeId, Box<dyn GpuCompiledNode>>,
88}
89
90#[derive(Debug, Clone, Default)]
91pub struct BoundFrame {
92 buffer_uploads: Vec<(lumen_gpu::BufferId, u64, Vec<u8>)>,
93 texture_uploads: Vec<TextureUpload>,
94 media_textures: Vec<MediaTextureUpload>,
95}
96
97#[derive(Debug, Clone)]
98enum TextureUpload {
99 Rgba8 {
100 id: lumen_gpu::TextureId,
101 data: Vec<u8>,
102 bytes_per_row: u32,
103 rows_per_image: u32,
104 },
105 Rgba8Region {
106 id: lumen_gpu::TextureId,
107 data: Vec<u8>,
108 origin: [u32; 3],
109 size: lumen_gpu::Size,
110 bytes_per_row: u32,
111 rows_per_image: u32,
112 },
113 Rgba16Float {
114 id: lumen_gpu::TextureId,
115 data: Vec<u16>,
116 bytes_per_row: u32,
117 rows_per_image: u32,
118 },
119}
120
121#[derive(Debug, Clone, PartialEq, Eq, Hash)]
122pub struct MediaTextureKey {
123 pub source: String,
124 pub frame: Option<u32>,
125 pub width: u32,
126 pub height: u32,
127}
128
129#[derive(Debug, Clone)]
130pub struct MediaTextureUpload {
131 pub texture: lumen_gpu::TextureId,
132 pub key: MediaTextureKey,
133 pub frame: MediaFrame,
134 pub size: lumen_gpu::Size,
135}
136
137impl BoundFrame {
138 pub fn new() -> Self {
139 Self::default()
140 }
141
142 pub fn write_buffer(&mut self, id: lumen_gpu::BufferId, offset: u64, data: impl Into<Vec<u8>>) {
143 self.buffer_uploads.push((id, offset, data.into()));
144 }
145
146 pub fn write_texture_rgba8(
147 &mut self,
148 id: lumen_gpu::TextureId,
149 data: impl Into<Vec<u8>>,
150 bytes_per_row: u32,
151 rows_per_image: u32,
152 ) {
153 self.texture_uploads.push(TextureUpload::Rgba8 {
154 id,
155 data: data.into(),
156 bytes_per_row,
157 rows_per_image,
158 });
159 }
160
161 pub fn write_texture_rgba8_region(
162 &mut self,
163 id: lumen_gpu::TextureId,
164 data: impl Into<Vec<u8>>,
165 origin: [u32; 3],
166 size: lumen_gpu::Size,
167 bytes_per_row: u32,
168 rows_per_image: u32,
169 ) {
170 self.texture_uploads.push(TextureUpload::Rgba8Region {
171 id,
172 data: data.into(),
173 origin,
174 size,
175 bytes_per_row,
176 rows_per_image,
177 });
178 }
179
180 pub fn write_texture_rgba16_float(
181 &mut self,
182 id: lumen_gpu::TextureId,
183 data: impl Into<Vec<u16>>,
184 bytes_per_row: u32,
185 rows_per_image: u32,
186 ) {
187 self.texture_uploads.push(TextureUpload::Rgba16Float {
188 id,
189 data: data.into(),
190 bytes_per_row,
191 rows_per_image,
192 });
193 }
194
195 pub fn use_media_texture(
196 &mut self,
197 texture: lumen_gpu::TextureId,
198 key: MediaTextureKey,
199 frame: MediaFrame,
200 size: lumen_gpu::Size,
201 ) {
202 self.media_textures.push(MediaTextureUpload {
203 texture,
204 key,
205 frame,
206 size,
207 });
208 }
209
210 pub fn media_textures(&self) -> &[MediaTextureUpload] {
211 &self.media_textures
212 }
213
214 pub fn buffer_upload_count(&self) -> usize {
215 self.buffer_uploads.len()
216 }
217
218 pub fn texture_upload_count(&self) -> usize {
219 self.texture_uploads.len()
220 }
221
222 pub fn frame_update(&self) -> lumen_gpu::FrameUpdate<'_> {
223 let mut update = lumen_gpu::FrameUpdate::new();
224 for (id, offset, data) in &self.buffer_uploads {
225 update.write_buffer(*id, *offset, data);
226 }
227 for upload in &self.texture_uploads {
228 match upload {
229 TextureUpload::Rgba8 {
230 id,
231 data,
232 bytes_per_row,
233 rows_per_image,
234 } => {
235 update.write_texture_rgba8(*id, data, *bytes_per_row, *rows_per_image);
236 }
237 TextureUpload::Rgba8Region {
238 id,
239 data,
240 origin,
241 size,
242 bytes_per_row,
243 rows_per_image,
244 } => {
245 update.write_texture_rgba8_region(
246 *id,
247 data,
248 *origin,
249 *size,
250 *bytes_per_row,
251 *rows_per_image,
252 );
253 }
254 TextureUpload::Rgba16Float {
255 id,
256 data,
257 bytes_per_row,
258 rows_per_image,
259 } => {
260 update.write_texture_rgba16_float(*id, data, *bytes_per_row, *rows_per_image);
261 }
262 }
263 }
264 update
265 }
266}