makepad_platform/
draw_shader.rs

1use {
2    std::{
3        ops::{Index, IndexMut},
4        collections::{
5            HashMap,
6            HashSet,
7            BTreeSet,
8        },
9    },
10    crate::{
11        makepad_live_compiler::{LiveValue, LiveFieldKind, LiveNode, LivePtr, LiveNodeSliceApi},
12        makepad_shader_compiler::*,
13        makepad_live_id::*,
14        live_traits::*,
15        draw_vars::DrawVars,
16        os::CxOsDrawShader,
17        cx::Cx
18    }
19};
20
21#[derive(Default, Debug, Clone, PartialEq)]
22pub struct CxDrawShaderOptions {
23    pub draw_call_group: LiveId,
24    pub debug_id: Option<LiveId>,
25}
26
27impl CxDrawShaderOptions {
28    pub fn from_ptr(cx: &Cx, draw_shader_ptr: DrawShaderPtr) -> Self {
29        let live_registry_cp = cx.live_registry.clone();
30        let live_registry = live_registry_cp.borrow();
31        let doc = live_registry.ptr_to_doc(draw_shader_ptr.0);
32        let mut ret = Self::default();
33        // copy in per-instance settings from the DSL
34        let mut node_iter = doc.nodes.first_child(draw_shader_ptr.node_index());
35        while let Some(node_index) = node_iter {
36            let node = &doc.nodes[node_index];
37            match node.id {
38                live_id!(draw_call_group) => if let LiveValue::Id(id) = node.value {
39                    ret.draw_call_group = id;
40                }
41                live_id!(debug_id) => if let LiveValue::Id(id) = node.value {
42                    ret.debug_id = Some(id);
43                }
44                _ => ()
45            }
46            node_iter = doc.nodes.next_child(node_index);
47        }
48        ret
49    }
50    
51    pub fn _appendable_drawcall(&self, other: &Self) -> bool {
52        self == other
53    }
54}
55
56#[derive(Default)]
57pub struct CxDrawShaderItem {
58    pub draw_shader_id: usize,
59    pub options: CxDrawShaderOptions
60}
61
62#[derive(Default)]
63pub struct CxDrawShaders {
64    pub shaders: Vec<CxDrawShader>,
65    pub os_shaders: Vec<CxOsDrawShader>,
66    pub generation: u64,
67    pub ptr_to_item: HashMap<DrawShaderPtr, CxDrawShaderItem>,
68    pub compile_set: BTreeSet<DrawShaderPtr>,
69    pub fingerprints: Vec<DrawShaderFingerprint>,
70    pub error_set: HashSet<DrawShaderPtr>,
71    pub error_fingerprints: Vec<Vec<LiveNode >>,
72}
73
74impl CxDrawShaders{
75    pub fn reset_for_live_reload(&mut self){
76        self.ptr_to_item.clear();
77        self.fingerprints.clear();
78        self.error_set.clear();
79        self.error_fingerprints.clear();
80    }
81}
82
83impl Cx {
84    pub fn flush_draw_shaders(&mut self) {
85        self.draw_shaders.generation += 1;
86        self.shader_registry.flush_registry();
87        self.draw_shaders.shaders.clear();
88        self.draw_shaders.ptr_to_item.clear();
89        self.draw_shaders.fingerprints.clear();
90        self.draw_shaders.error_set.clear();
91        self.draw_shaders.error_fingerprints.clear();
92    }
93}
94
95impl Index<usize> for CxDrawShaders {
96    type Output = CxDrawShader;
97    fn index(&self, index: usize) -> &Self::Output {
98        &self.shaders[index]
99    }
100}
101
102impl IndexMut<usize> for CxDrawShaders {
103    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
104        &mut self.shaders[index]
105    }
106}
107
108#[derive(Copy, Clone, PartialEq, Debug)]
109pub struct DrawShader {
110    pub draw_shader_generation: u64,
111    pub draw_shader_id: usize,
112    pub draw_shader_ptr: DrawShaderPtr
113}
114
115pub struct CxDrawShader {
116    pub class_prop: LiveId,
117    pub type_name: LiveId,
118    pub os_shader_id: Option<usize>,
119    pub mapping: CxDrawShaderMapping
120}
121
122#[derive(Debug, PartialEq)]
123pub struct DrawShaderFingerprint {
124    pub fingerprint: Vec<LiveNode>,
125    pub draw_shader_id: usize
126}
127
128impl DrawShaderFingerprint {
129    pub fn from_ptr(cx: &Cx, draw_shader_ptr: DrawShaderPtr) -> Vec<LiveNode> {
130        let live_registry_cp = cx.live_registry.clone();
131        let live_registry = live_registry_cp.borrow();
132        let doc = live_registry.ptr_to_doc(draw_shader_ptr.0);
133        let mut node_iter = doc.nodes.first_child(draw_shader_ptr.node_index());
134        let mut fingerprint = Vec::new();
135        while let Some(node_index) = node_iter {
136            let node = &doc.nodes[node_index];
137            match node.value {
138                LiveValue::DSL {token_start, token_count, ..} => {
139                    fingerprint.push(LiveNode {
140                        id: node.id,
141                        origin: node.origin,
142                        value: LiveValue::DSL {token_start, token_count, expand_index: None}
143                    });
144                }
145                _ => ()
146            }
147            node_iter = doc.nodes.next_child(node_index);
148        }
149        fingerprint
150    }
151}
152
153#[derive(Clone, Debug)]
154pub struct DrawShaderInputs {
155    pub inputs: Vec<DrawShaderInput>,
156    pub packing_method: DrawShaderInputPacking,
157    pub total_slots: usize,
158}
159
160#[derive(Clone, Copy, Debug)]
161pub enum DrawShaderInputPacking {
162    Attribute,
163    UniformsGLSL,
164    #[allow(dead_code)]
165    UniformsHLSL,
166    #[allow(dead_code)]
167    UniformsMetal
168}
169
170
171#[derive(Clone, Debug)]
172pub struct DrawShaderInput {
173    pub id: LiveId,
174    pub ty: ShaderTy,
175    pub offset: usize,
176    pub slots: usize,
177    pub live_ptr: Option<LivePtr>
178}
179
180
181#[cfg(any(target_os = "android", target_os = "linux", target_arch = "wasm32"))]
182pub const DRAW_SHADER_INPUT_PACKING: DrawShaderInputPacking = DrawShaderInputPacking::UniformsGLSL;
183#[cfg(any(target_os = "macos", target_os = "ios"))]
184pub const DRAW_SHADER_INPUT_PACKING: DrawShaderInputPacking = DrawShaderInputPacking::UniformsMetal;
185#[cfg(any(target_os = "windows"))]
186pub const DRAW_SHADER_INPUT_PACKING: DrawShaderInputPacking = DrawShaderInputPacking::UniformsHLSL;
187
188impl DrawShaderInputs {
189    pub fn new(packing_method: DrawShaderInputPacking) -> Self {
190        Self {
191            inputs: Vec::new(),
192            packing_method,
193            total_slots: 0
194        }
195    }
196    
197    pub fn push(&mut self, id: LiveId, ty: ShaderTy, live_ptr: Option<LivePtr>) {
198        let slots = ty.slots();
199        match self.packing_method {
200            DrawShaderInputPacking::Attribute => {
201                self.inputs.push(DrawShaderInput {
202                    id,
203                    offset: self.total_slots,
204                    slots,
205                    ty,
206                    live_ptr
207                });
208                self.total_slots += slots;
209            }
210            DrawShaderInputPacking::UniformsGLSL => {
211                self.inputs.push(DrawShaderInput {
212                    id,
213                    offset: self.total_slots,
214                    slots,
215                    ty,
216                    live_ptr
217                });
218                self.total_slots += slots;
219            }
220            DrawShaderInputPacking::UniformsHLSL => {
221                if (self.total_slots & 3) + slots > 4 { // goes over the boundary
222                    self.total_slots += 4 - (self.total_slots & 3); // make jump to new slot
223                }
224                self.inputs.push(DrawShaderInput {
225                    id,
226                    offset: self.total_slots,
227                    slots,
228                    ty,
229                    live_ptr
230                });
231                self.total_slots += slots;
232            }
233            DrawShaderInputPacking::UniformsMetal => {
234                let aligned_slots = if slots == 3 {4} else {slots};
235                if (self.total_slots & 3) + aligned_slots > 4 { // goes over the boundary
236                    self.total_slots += 4 - (self.total_slots & 3); // make jump to new slot
237                }
238                self.inputs.push(DrawShaderInput {
239                    id,
240                    offset: self.total_slots,
241                    slots,
242                    ty,
243                    live_ptr
244                });
245                self.total_slots += aligned_slots;
246            }
247        }
248    }
249    
250    pub fn finalize(&mut self) {
251        match self.packing_method {
252            DrawShaderInputPacking::Attribute => (),
253            DrawShaderInputPacking::UniformsGLSL =>(),
254            DrawShaderInputPacking::UniformsHLSL |
255            DrawShaderInputPacking::UniformsMetal => {
256                if self.total_slots & 3 > 0 {
257                    self.total_slots += 4 - (self.total_slots & 3);
258                }
259            }
260        }
261    }
262}
263
264#[derive(Clone)]
265pub struct DrawShaderTextureInput {
266    pub id: LiveId,
267    pub ty: ShaderTy
268}
269
270#[derive(Clone)]
271pub struct CxDrawShaderMapping {
272    pub flags: DrawShaderFlags,
273    pub const_table: DrawShaderConstTable,
274    
275    pub geometries: DrawShaderInputs,
276    pub instances: DrawShaderInputs,
277    pub var_instances: DrawShaderInputs,
278    pub live_instances: DrawShaderInputs,
279    pub live_uniforms: DrawShaderInputs,
280    pub user_uniforms: DrawShaderInputs,
281    pub draw_uniforms: DrawShaderInputs,
282    pub view_uniforms: DrawShaderInputs,
283    pub pass_uniforms: DrawShaderInputs,
284    pub textures: Vec<DrawShaderTextureInput>,
285    pub instance_enums: Vec<usize>,
286    pub rect_pos: Option<usize>,
287    pub rect_size: Option<usize>,
288    pub draw_clip: Option<usize>,
289    pub live_uniforms_buf: Vec<f32>,
290}
291
292impl CxDrawShaderMapping {
293    
294    pub fn from_draw_shader_def(draw_shader_def: &DrawShaderDef, const_table: DrawShaderConstTable, uniform_packing: DrawShaderInputPacking) -> CxDrawShaderMapping { //}, options: ShaderCompileOptions, metal_uniform_packing:bool) -> Self {
295        
296        let mut geometries = DrawShaderInputs::new(DrawShaderInputPacking::Attribute);
297        let mut instances = DrawShaderInputs::new(DrawShaderInputPacking::Attribute);
298        let mut var_instances = DrawShaderInputs::new(DrawShaderInputPacking::Attribute);
299        let mut live_instances = DrawShaderInputs::new(DrawShaderInputPacking::Attribute);
300        let mut user_uniforms = DrawShaderInputs::new(uniform_packing);
301        let mut live_uniforms = DrawShaderInputs::new(uniform_packing);
302        let mut draw_uniforms = DrawShaderInputs::new(uniform_packing);
303        let mut view_uniforms = DrawShaderInputs::new(uniform_packing);
304        let mut pass_uniforms = DrawShaderInputs::new(uniform_packing);
305        let mut textures = Vec::new();
306        let mut instance_enums = Vec::new();
307        let mut rect_pos = None;
308        let mut rect_size = None;
309        let mut draw_clip = None;
310        
311        for field in &draw_shader_def.fields {
312            let ty = field.ty_expr.ty.borrow().as_ref().unwrap().clone();
313            match &field.kind {
314                DrawShaderFieldKind::Geometry {..} => {
315                    geometries.push(field.ident.0, ty, None);
316                }
317                DrawShaderFieldKind::Instance {var_def_ptr, live_field_kind, ..} => {
318                    if field.ident.0 == live_id!(rect_pos) {
319                        rect_pos = Some(instances.total_slots);
320                    }
321                    if field.ident.0 == live_id!(rect_size) {
322                        rect_size = Some(instances.total_slots);
323                    }
324                    if field.ident.0 == live_id!(draw_clip) {
325                        draw_clip = Some(instances.total_slots);
326                    }
327                    if var_def_ptr.is_some() {
328                        var_instances.push(field.ident.0, ty.clone(), None,);
329                    }
330                    if let ShaderTy::Enum{..} = ty{
331                        instance_enums.push(instances.total_slots);
332                    }
333                    instances.push(field.ident.0, ty, None);
334                    if let LiveFieldKind::Live = live_field_kind {
335                        live_instances.inputs.push(instances.inputs.last().unwrap().clone());
336                    }
337                }
338                DrawShaderFieldKind::Uniform {block_ident, ..} => {
339                    match block_ident.0 {
340                        live_id!(draw) => {
341                            draw_uniforms.push(field.ident.0, ty, None);
342                        }
343                        live_id!(view) => {
344                            view_uniforms.push(field.ident.0, ty, None);
345                        }
346                        live_id!(pass) => {
347                            pass_uniforms.push(field.ident.0, ty, None);
348                        }
349                        live_id!(user) => {
350                            user_uniforms.push(field.ident.0, ty, None);
351                        }
352                        _ => ()
353                    }
354                }
355                DrawShaderFieldKind::Texture {..} => {
356                    textures.push(DrawShaderTextureInput {
357                        ty:ty,
358                        id: field.ident.0,
359                    });
360                }
361                _ => ()
362            }
363        }
364        
365        geometries.finalize();
366        instances.finalize();
367        var_instances.finalize();
368        user_uniforms.finalize();
369        live_uniforms.finalize();
370        draw_uniforms.finalize();
371        view_uniforms.finalize();
372        pass_uniforms.finalize();
373        
374        // fill up the default values for the user uniforms
375        
376        
377        // ok now the live uniforms
378        for (value_node_ptr, ty) in draw_shader_def.all_live_refs.borrow().iter() {
379            live_uniforms.push(LiveId(0), ty.clone(), Some(value_node_ptr.0));
380        }
381        
382        CxDrawShaderMapping {
383            const_table,
384            flags: draw_shader_def.flags,
385            geometries,
386            instances,
387            live_uniforms_buf: {let mut r = Vec::new(); r.resize(live_uniforms.total_slots, 0.0); r},
388            var_instances,
389            live_instances,
390            user_uniforms,
391            live_uniforms,
392            draw_uniforms,
393            view_uniforms,
394            pass_uniforms,
395            instance_enums,
396            textures,
397            rect_pos,
398            rect_size,
399            draw_clip,
400        }
401    }
402    
403    pub fn update_live_and_user_uniforms(&mut self, cx: &mut Cx, from: ApplyFrom) {
404        // and write em into the live_uniforms buffer
405        let live_registry = cx.live_registry.clone();
406        let live_registry = live_registry.borrow();
407        
408        for input in &self.live_uniforms.inputs {
409            let (nodes,index) = live_registry.ptr_to_nodes_index(input.live_ptr.unwrap());
410            DrawVars::apply_slots(
411                cx,
412                input.slots,
413                &mut self.live_uniforms_buf,
414                input.offset,
415                from,
416                index,
417                nodes
418            );
419        }
420    }
421}