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
115impl DrawShader{
116    pub fn false_compare_id(&self)->u64{
117        ((self.draw_shader_id as u64)<<32) | self.draw_shader_ptr.0.index as u64
118    }
119}
120
121pub struct CxDrawShader {
122    pub class_prop: LiveId,
123    pub type_name: LiveId,
124    pub os_shader_id: Option<usize>,
125    pub mapping: CxDrawShaderMapping
126}
127
128#[derive(Debug, PartialEq)]
129pub struct DrawShaderFingerprint {
130    pub fingerprint: Vec<LiveNode>,
131    pub draw_shader_id: usize
132}
133
134impl DrawShaderFingerprint {
135    pub fn from_ptr(cx: &Cx, draw_shader_ptr: DrawShaderPtr) -> Vec<LiveNode> {
136        let live_registry_cp = cx.live_registry.clone();
137        let live_registry = live_registry_cp.borrow();
138        let doc = live_registry.ptr_to_doc(draw_shader_ptr.0);
139        let mut node_iter = doc.nodes.first_child(draw_shader_ptr.node_index());
140        let mut fingerprint = Vec::new();
141        while let Some(node_index) = node_iter {
142            let node = &doc.nodes[node_index];
143            match node.value {
144                LiveValue::DSL {token_start, token_count, ..} => {
145                    fingerprint.push(LiveNode {
146                        id: node.id,
147                        origin: node.origin,
148                        value: LiveValue::DSL {token_start, token_count, expand_index: None}
149                    });
150                }
151                _ => ()
152            }
153            node_iter = doc.nodes.next_child(node_index);
154        }
155        fingerprint
156    }
157}
158
159#[derive(Clone, Debug)]
160pub struct DrawShaderInputs {
161    pub inputs: Vec<DrawShaderInput>,
162    pub packing_method: DrawShaderInputPacking,
163    pub total_slots: usize,
164}
165
166#[derive(Clone, Copy, Debug)]
167pub enum DrawShaderInputPacking {
168    Attribute,
169    UniformsGLSLTight,
170    UniformsGLSL140,
171    #[allow(dead_code)]
172    UniformsHLSL,
173    #[allow(dead_code)]
174    UniformsMetal
175}
176
177
178#[derive(Clone, Debug)]
179pub struct DrawShaderInput {
180    pub id: LiveId,
181    pub ty: ShaderTy,
182    pub offset: usize,
183    pub slots: usize,
184    pub live_ptr: Option<LivePtr>
185}
186
187#[cfg(any(target_arch = "wasm32"))]
188pub const DRAW_SHADER_INPUT_PACKING: DrawShaderInputPacking = DrawShaderInputPacking::UniformsGLSLTight;
189
190
191#[cfg(all(any(target_os = "android", target_os = "linux"),use_gles_3))]
192pub const DRAW_SHADER_INPUT_PACKING: DrawShaderInputPacking = DrawShaderInputPacking::UniformsGLSL140;
193#[cfg(all(any(target_os = "android", target_os = "linux"),not(use_gles_3)))]
194pub const DRAW_SHADER_INPUT_PACKING: DrawShaderInputPacking = DrawShaderInputPacking::UniformsGLSLTight;
195
196
197#[cfg(any(target_os = "macos", target_os = "ios", target_os="tvos"))]
198pub const DRAW_SHADER_INPUT_PACKING: DrawShaderInputPacking = DrawShaderInputPacking::UniformsMetal;
199#[cfg(any(target_os = "windows"))]
200pub const DRAW_SHADER_INPUT_PACKING: DrawShaderInputPacking = DrawShaderInputPacking::UniformsHLSL;
201
202impl DrawShaderInputs {
203    pub fn new(packing_method: DrawShaderInputPacking) -> Self {
204        Self {
205            inputs: Vec::new(),
206            packing_method,
207            total_slots: 0
208        }
209    }
210    
211    pub fn push(&mut self, id: LiveId, ty: ShaderTy, live_ptr: Option<LivePtr>) {
212        let slots = ty.slots();
213        match self.packing_method {
214            DrawShaderInputPacking::Attribute => {
215                self.inputs.push(DrawShaderInput {
216                    id,
217                    offset: self.total_slots,
218                    slots,
219                    ty,
220                    live_ptr
221                });
222                self.total_slots += slots;
223            }
224            DrawShaderInputPacking::UniformsGLSLTight => {
225                self.inputs.push(DrawShaderInput {
226                    id,
227                    offset: self.total_slots,
228                    slots,
229                    ty,
230                    live_ptr
231                });
232                self.total_slots += slots;
233            }
234            DrawShaderInputPacking::UniformsGLSL140 => {
235                if (self.total_slots & 3) + 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 += slots;
246            }
247            DrawShaderInputPacking::UniformsHLSL => {
248                if (self.total_slots & 3) + slots > 4 { // goes over the boundary
249                    self.total_slots += 4 - (self.total_slots & 3); // make jump to new slot
250                }
251                self.inputs.push(DrawShaderInput {
252                    id,
253                    offset: self.total_slots,
254                    slots,
255                    ty,
256                    live_ptr
257                });
258                self.total_slots += slots;
259            }
260            DrawShaderInputPacking::UniformsMetal => {
261                let aligned_slots = if slots == 3 {4} else {slots};
262                if (self.total_slots & 3) + aligned_slots > 4 { // goes over the boundary
263                    self.total_slots += 4 - (self.total_slots & 3); // make jump to new slot
264                }
265                self.inputs.push(DrawShaderInput {
266                    id,
267                    offset: self.total_slots,
268                    slots,
269                    ty,
270                    live_ptr
271                });
272                self.total_slots += aligned_slots;
273            }
274        }
275    }
276    
277    pub fn finalize(&mut self) {
278        match self.packing_method {
279            DrawShaderInputPacking::Attribute => (),
280            DrawShaderInputPacking::UniformsGLSLTight =>(),
281            DrawShaderInputPacking::UniformsHLSL |
282            DrawShaderInputPacking::UniformsMetal|
283            DrawShaderInputPacking::UniformsGLSL140
284            => {
285                if self.total_slots & 3 > 0 {
286                    self.total_slots += 4 - (self.total_slots & 3);
287                }
288            }
289        }
290    }
291}
292
293#[derive(Clone)]
294pub struct DrawShaderTextureInput {
295    pub id: LiveId,
296    pub ty: ShaderTy
297}
298
299#[derive(Clone)]
300pub struct CxDrawShaderMapping {
301    pub flags: DrawShaderFlags,
302    pub const_table: DrawShaderConstTable,
303    
304    pub geometries: DrawShaderInputs,
305    pub instances: DrawShaderInputs,
306    pub var_instances: DrawShaderInputs,
307    pub live_instances: DrawShaderInputs,
308    pub live_uniforms: DrawShaderInputs,
309    pub user_uniforms: DrawShaderInputs,
310    pub draw_list_uniforms: DrawShaderInputs,
311    pub draw_call_uniforms: DrawShaderInputs,
312    pub pass_uniforms: DrawShaderInputs,
313    pub textures: Vec<DrawShaderTextureInput>,
314    pub uses_time: bool,
315    pub instance_enums: Vec<usize>,
316    pub rect_pos: Option<usize>,
317    pub rect_size: Option<usize>,
318    pub draw_clip: Option<usize>,
319    pub live_uniforms_buf: Vec<f32>,
320}
321
322impl CxDrawShaderMapping {
323    
324    pub fn from_draw_shader_def(draw_shader_def: &DrawShaderDef, const_table: DrawShaderConstTable, uniform_packing: DrawShaderInputPacking) -> CxDrawShaderMapping { //}, options: ShaderCompileOptions, metal_uniform_packing:bool) -> Self {
325        
326        let mut geometries = DrawShaderInputs::new(DrawShaderInputPacking::Attribute);
327        let mut instances = DrawShaderInputs::new(DrawShaderInputPacking::Attribute);
328        let mut var_instances = DrawShaderInputs::new(DrawShaderInputPacking::Attribute);
329        let mut live_instances = DrawShaderInputs::new(DrawShaderInputPacking::Attribute);
330        let mut user_uniforms = DrawShaderInputs::new(uniform_packing);
331        let mut live_uniforms = DrawShaderInputs::new(uniform_packing);
332        let mut draw_list_uniforms = DrawShaderInputs::new(uniform_packing);
333        let mut draw_call_uniforms = DrawShaderInputs::new(uniform_packing);
334        let mut pass_uniforms = DrawShaderInputs::new(uniform_packing);
335        let mut textures = Vec::new();
336        let mut instance_enums = Vec::new();
337        let mut rect_pos = None;
338        let mut rect_size = None;
339        let mut draw_clip = None;
340        for field in &draw_shader_def.fields {
341            let ty = field.ty_expr.ty.borrow().as_ref().unwrap().clone();
342            match &field.kind {
343                DrawShaderFieldKind::Geometry {..} => {
344                    geometries.push(field.ident.0, ty, None);
345                }
346                DrawShaderFieldKind::Instance {var_def_ptr, live_field_kind, ..} => {
347                    if field.ident.0 == live_id!(rect_pos) {
348                        rect_pos = Some(instances.total_slots);
349                    }
350                    if field.ident.0 == live_id!(rect_size) {
351                        rect_size = Some(instances.total_slots);
352                    }
353                    if field.ident.0 == live_id!(draw_clip) {
354                        draw_clip = Some(instances.total_slots);
355                    }
356                    if var_def_ptr.is_some() {
357                        var_instances.push(field.ident.0, ty.clone(), None,);
358                    }
359                    if let ShaderTy::Enum{..} = ty{
360                        instance_enums.push(instances.total_slots);
361                    }
362                    instances.push(field.ident.0, ty, None);
363                    if let LiveFieldKind::Live = live_field_kind {
364                        live_instances.inputs.push(instances.inputs.last().unwrap().clone());
365                    }
366                }
367                DrawShaderFieldKind::Uniform {block_ident, ..} => {
368                    match block_ident.0 {
369                        live_id!(draw_call) => {
370                            draw_call_uniforms.push(field.ident.0, ty, None);
371                        }
372                        live_id!(draw_list) => {
373                            draw_list_uniforms.push(field.ident.0, ty, None);
374                        }
375                        live_id!(pass) => {
376                            pass_uniforms.push(field.ident.0, ty, None);
377                        }
378                        live_id!(user) => {
379                            user_uniforms.push(field.ident.0, ty, None);
380                        }
381                        _ => ()
382                    }
383                }
384                DrawShaderFieldKind::Texture {..} => {
385                    textures.push(DrawShaderTextureInput {
386                        ty:ty,
387                        id: field.ident.0,
388                    });
389                }
390                _ => ()
391            }
392        }
393        
394        geometries.finalize();
395        instances.finalize();
396        var_instances.finalize();
397        user_uniforms.finalize();
398        live_uniforms.finalize();
399        draw_list_uniforms.finalize();
400        draw_call_uniforms.finalize();
401        pass_uniforms.finalize();
402        
403        // fill up the default values for the user uniforms
404        
405        
406        // ok now the live uniforms
407        for (value_node_ptr, ty) in draw_shader_def.all_live_refs.borrow().iter() {
408            live_uniforms.push(LiveId(0), ty.clone(), Some(value_node_ptr.0));
409        }
410        
411        CxDrawShaderMapping {
412            const_table,
413            uses_time: draw_shader_def.uses_time.get(),
414            flags: draw_shader_def.flags,
415            geometries,
416            instances,
417            live_uniforms_buf: {let mut r = Vec::new(); r.resize(live_uniforms.total_slots, 0.0); r},
418            var_instances,
419            live_instances,
420            user_uniforms,
421            live_uniforms,
422            draw_list_uniforms,
423            draw_call_uniforms,
424            pass_uniforms,
425            instance_enums,
426            textures,
427            rect_pos,
428            rect_size,
429            draw_clip,
430        }
431    }
432    
433    pub fn update_live_and_user_uniforms(&mut self, cx: &mut Cx, apply: &mut Apply) {
434        // and write em into the live_uniforms buffer
435        let live_registry = cx.live_registry.clone();
436        let live_registry = live_registry.borrow();
437        
438        for input in &self.live_uniforms.inputs {
439            let (nodes,index) = live_registry.ptr_to_nodes_index(input.live_ptr.unwrap());
440            DrawVars::apply_slots(
441                cx,
442                input.slots,
443                &mut self.live_uniforms_buf,
444                input.offset,
445                apply,
446                index,
447                nodes
448            );
449        }
450    }
451}