makepad_platform/
draw_list.rs

1use {
2    crate::{
3        makepad_live_compiler::{
4            LiveId,
5        },
6        makepad_math::*,
7        makepad_error_log::*,
8        os::{
9            CxOsDrawCall,
10            CxOsView,
11        },
12        pass::PassId,
13        id_pool::*,
14        draw_shader::{
15            CxDrawShaderOptions,
16            CxDrawShaderMapping,
17            CxDrawShader,
18            DrawShader,
19        },
20        draw_vars::{
21            DrawVars,
22            DRAW_CALL_USER_UNIFORMS,
23            DRAW_CALL_TEXTURE_SLOTS
24        },
25        texture::TextureId,
26        geometry::{GeometryId}
27    }
28};
29
30
31#[derive(Debug)]
32pub struct DrawList(PoolId);
33
34#[derive(Clone, Debug, PartialEq, Copy, Hash, Ord, PartialOrd, Eq)]
35pub struct DrawListId(usize, u64);
36
37impl DrawListId{
38    pub fn index(&self)->usize{self.0}
39    pub fn generation(&self)->u64{self.1}
40}
41
42impl DrawList {
43    pub fn id(&self) -> DrawListId {DrawListId(self.0.id, self.0.generation)}
44}
45
46#[derive(Default)]
47pub struct CxDrawListPool(pub (crate) IdPool<CxDrawList>);
48impl CxDrawListPool {
49    pub fn alloc(&mut self) -> DrawList {
50        DrawList(self.0.alloc())
51    }
52}
53
54impl std::ops::Index<DrawListId> for CxDrawListPool {
55    
56    type Output = CxDrawList;
57    fn index(&self, index: DrawListId) -> &Self::Output {
58        let d = &self.0.pool[index.0];
59        if d.generation != index.1 {
60            error!("Drawlist id generation wrong {} {} {}", index.0, d.generation, index.1)
61        }
62        &d.item
63    }
64}
65
66impl std::ops::IndexMut<DrawListId> for CxDrawListPool {
67    fn index_mut(&mut self, index: DrawListId) -> &mut Self::Output {
68        let d = &mut self.0.pool[index.0];
69        if d.generation != index.1 {
70            error!("Drawlist id generation wrong {} {} {}", index.0, d.generation, index.1)
71        }
72        &mut d.item
73        
74    }
75}
76
77
78#[derive(Default, Clone)]
79#[repr(C)]
80pub struct DrawUniforms {
81    //pub draw_clip_x1: f32,
82    //pub draw_clip_y1: f32,
83    //pub draw_clip_x2: f32,
84    //pub draw_clip_y2: f32,
85    //pub draw_scroll: Vec4,
86    pub draw_zbias: f32,
87    pub pad1: f32,
88    pub pad2: f32,
89    pub pad3: f32
90}
91
92impl DrawUniforms {
93    pub fn as_slice(&self) -> &[f32; std::mem::size_of::<DrawUniforms>()] {
94        unsafe {std::mem::transmute(self)}
95    }
96    /*
97    pub fn get_local_scroll(&self) -> Vec4 {
98        self.draw_scroll
99    }*/
100    
101    pub fn set_zbias(&mut self, zbias: f32) {
102        self.draw_zbias = zbias;
103    }
104    /*
105    pub fn set_clip(&mut self, clip: (Vec2, Vec2)) {
106        self.draw_clip_x1 = clip.0.x;
107        self.draw_clip_y1 = clip.0.y;
108        self.draw_clip_x2 = clip.1.x;
109        self.draw_clip_y2 = clip.1.y;
110    }
111    
112    pub fn set_local_scroll(&mut self, scroll: Vec2, local_scroll: Vec2, options: &CxDrawShaderOptions) {
113        self.draw_scroll.x = scroll.x;
114        if !options.no_h_scroll {
115            self.draw_scroll.x += local_scroll.x;
116        }
117        self.draw_scroll.y = scroll.y;
118        if !options.no_v_scroll {
119            self.draw_scroll.y += local_scroll.y;
120        }
121        self.draw_scroll.z = local_scroll.x;
122        self.draw_scroll.w = local_scroll.y;
123    }*/
124}
125 
126pub enum CxDrawKind{
127    SubList(DrawListId),
128    DrawCall(CxDrawCall),
129    Empty
130}
131
132pub struct CxDrawItem {
133    pub redraw_id: u64,
134    pub kind: CxDrawKind,
135    // these values stick around to reduce buffer churn
136    pub draw_item_id: usize,
137    pub instances: Option<Vec<f32 >>,
138    pub os: CxOsDrawCall
139}
140
141impl std::ops::Deref for  CxDrawItem {
142    type Target = CxDrawKind;
143    fn deref(&self) -> &Self::Target {&self.kind}
144}
145
146impl CxDrawKind{
147    pub fn is_empty(&self)->bool{
148        match self{
149            CxDrawKind::Empty=>true,
150            _=>false
151        }
152    }
153    
154    pub fn sub_list(&self)->Option<DrawListId>{
155        match self{
156            CxDrawKind::SubList(id)=>Some(*id),
157            _=>None
158        }
159    }
160    pub fn draw_call(&self)->Option<&CxDrawCall>{
161        match self{
162            CxDrawKind::DrawCall(call)=>Some(call),
163            _=>None
164        }
165    }
166    pub fn draw_call_mut(&mut self)->Option<&mut CxDrawCall>{
167        match self{
168            CxDrawKind::DrawCall(call)=>Some(call),
169            _=>None
170        }
171    }
172}
173
174pub struct CxDrawCall {
175    pub draw_shader: DrawShader, // if shader_id changed, delete gl vao
176    pub options: CxDrawShaderOptions,
177    pub total_instance_slots: usize,
178    pub draw_uniforms: DrawUniforms, // draw uniforms
179    pub geometry_id: Option<GeometryId>,
180    pub user_uniforms: [f32; DRAW_CALL_USER_UNIFORMS], // user uniforms
181    pub texture_slots: [Option<TextureId>; DRAW_CALL_TEXTURE_SLOTS],
182    pub instance_dirty: bool,
183    pub uniforms_dirty: bool,
184}
185
186impl CxDrawCall {
187    pub fn new(mapping: &CxDrawShaderMapping, draw_vars: &DrawVars) -> Self {
188        CxDrawCall {
189            geometry_id: draw_vars.geometry_id,
190            options: draw_vars.options.clone(),
191            draw_shader: draw_vars.draw_shader.unwrap(),
192            total_instance_slots: mapping.instances.total_slots,
193            draw_uniforms: DrawUniforms::default(),
194            user_uniforms: draw_vars.user_uniforms,
195            texture_slots: draw_vars.texture_slots,
196            instance_dirty: true,
197            uniforms_dirty: true,
198        }
199    }
200}
201
202#[derive(Default, Clone)]
203#[repr(C)]
204pub struct CxDrawListUniforms {
205    pub view_transform: [f32; 16],
206}
207
208impl CxDrawListUniforms {
209    pub fn as_slice(&self) -> &[f32; std::mem::size_of::<CxDrawListUniforms>()] {
210        unsafe {std::mem::transmute(self)}
211    }
212}
213
214#[derive(Default)]
215pub struct CxDrawItems {
216    pub(crate) buffer: Vec<CxDrawItem>,
217    used: usize
218}
219
220impl std::ops::Index<usize> for CxDrawItems {
221    type Output = CxDrawItem;
222    fn index(&self, index: usize) -> &Self::Output {
223        &self.buffer[index]
224    }
225}
226
227impl std::ops::IndexMut<usize> for CxDrawItems {
228    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
229        &mut self.buffer[index]
230    }
231}
232
233impl CxDrawItems{
234    pub fn len(&self)->usize{self.used}
235    pub fn clear(&mut self){self.used = 0}
236    pub fn push_item(&mut self, redraw_id: u64, kind:CxDrawKind)->&mut CxDrawItem{
237        let draw_item_id = self.used;
238        if self.used >= self.buffer.len() {
239            self.buffer.push(CxDrawItem {
240                draw_item_id,
241                redraw_id,
242                instances: Some(Vec::new()),
243                os: CxOsDrawCall::default(),
244                kind: kind,
245            });
246        }
247        else{
248            // reuse an older one, keeping all GPU resources attached
249            let draw_item = &mut self.buffer[draw_item_id];
250            draw_item.instances.as_mut().unwrap().clear();
251            draw_item.kind = kind;
252            draw_item.redraw_id = redraw_id;
253        }
254        self.used += 1;
255        &mut self.buffer[draw_item_id]
256    }
257}
258
259#[derive(Default)]
260pub struct CxDrawList {
261    pub debug_id: LiveId,
262    
263    pub codeflow_parent_id: Option<DrawListId>, // the id of the parent we nest in, codeflow wise
264    
265    pub redraw_id: u64,
266    pub pass_id: Option<PassId>,
267    
268    pub draw_items: CxDrawItems,
269    
270    pub draw_list_uniforms: CxDrawListUniforms,
271    pub os: CxOsView,
272    pub rect_areas: Vec<CxRectArea>,
273}
274
275pub struct CxRectArea{
276    pub rect: Rect,
277    pub draw_clip: (DVec2,DVec2)
278}
279
280impl CxDrawList {
281/*
282    pub fn intersect_clip(&mut self, clip: (Vec2, Vec2)) -> (Vec2, Vec2) {
283        if !self.unclipped {
284            let min_x = self.rect.pos.x - self.parent_scroll.x;
285            let min_y = self.rect.pos.y - self.parent_scroll.y;
286            let max_x = self.rect.pos.x + self.rect.size.x - self.parent_scroll.x;
287            let max_y = self.rect.pos.y + self.rect.size.y - self.parent_scroll.y;
288            
289            let ret = (Vec2 {
290                x: min_x.max(clip.0.x),
291                y: min_y.max(clip.0.y)
292            }, Vec2 {
293                x: max_x.min(clip.1.x),
294                y: max_y.min(clip.1.y)
295            });
296            self.clip_points = ret;
297            ret
298        }
299        else {
300            self.clip_points = clip;
301            clip
302        }
303    }*/
304    
305    pub fn find_appendable_drawcall(&mut self, sh: &CxDrawShader, draw_vars: &DrawVars) -> Option<usize> {
306        // find our drawcall to append to the current layer
307        if self.draw_items.len() > 0 {
308            for i in (0..self.draw_items.len()).rev() {
309                let draw_item = &mut self.draw_items[i];
310                if let Some(draw_call) = &draw_item.draw_call() {
311                    if draw_call.draw_shader == draw_vars.draw_shader.unwrap() {
312                        // lets compare uniforms and textures..
313                        if !sh.mapping.flags.draw_call_nocompare {
314                            if draw_call.geometry_id != draw_vars.geometry_id {
315                                continue
316                            }
317                            let mut diff = false;
318                            for i in 0..sh.mapping.user_uniforms.total_slots {
319                                if draw_call.user_uniforms[i] != draw_vars.user_uniforms[i] {
320                                    diff = true;
321                                    break;
322                                }
323                            }
324                            if diff {continue}
325                            for i in 0..sh.mapping.textures.len() {
326                                if draw_call.texture_slots[i] != draw_vars.texture_slots[i] {
327                                    diff = true;
328                                    break;
329                                }
330                            }
331                            if diff {continue}
332                        }
333                        if !draw_call.options._appendable_drawcall(&draw_vars.options) {
334                            continue
335                        }
336                        return Some(i)
337                    }
338                }
339            }
340        }
341        None
342    }
343    
344    pub fn append_draw_call(&mut self, redraw_id: u64, sh: &CxDrawShader, draw_vars: &DrawVars) -> &mut CxDrawItem {
345        self.draw_items.push_item(
346            redraw_id,
347            CxDrawKind::DrawCall(CxDrawCall::new(&sh.mapping, draw_vars))
348        )
349    }
350    
351    pub fn clear_draw_items(&mut self, redraw_id: u64) {
352        self.redraw_id = redraw_id;
353        self.draw_items.clear();
354        self.rect_areas.clear();
355    }
356    
357    pub fn append_sub_list(&mut self, redraw_id: u64, sub_list_id: DrawListId) {
358        // see if we need to add a new one
359        self.draw_items.push_item(redraw_id, CxDrawKind::SubList(sub_list_id));
360    }
361    
362    pub fn store_sub_list_last(&mut self, redraw_id: u64, sub_list_id: DrawListId) {
363        // use an empty slot if we have them to insert our subview
364        let len = self.draw_items.len();
365        for i in 0..len{
366            let item = &mut self.draw_items[i];
367            if let Some(id) = item.kind.sub_list(){
368                if id == sub_list_id{
369                    item.kind = CxDrawKind::Empty;
370                    break
371                }
372            }
373        }
374        if len > 0{
375            let item = &mut self.draw_items[len - 1];
376            if item.kind.is_empty(){
377                item.redraw_id = redraw_id;
378                item.kind = CxDrawKind::SubList(sub_list_id);
379                return
380            }
381            if let CxDrawKind::SubList(id) = item.kind{
382                if id == sub_list_id{
383                    item.redraw_id = redraw_id;
384                    return
385                }
386            }
387        }
388        self.append_sub_list(redraw_id, sub_list_id);
389    }
390
391    pub fn store_sub_list(&mut self, redraw_id: u64, sub_list_id: DrawListId) {
392        // use an empty slot if we have them to insert our subview
393        for i in 0..self.draw_items.len(){
394            let item = &mut self.draw_items[i];
395            if let Some(id) = item.kind.sub_list(){
396                if id == sub_list_id{
397                    return
398                }
399            }
400        }
401        for i in 0..self.draw_items.len(){
402            let item = &mut self.draw_items[i];
403            if item.kind.is_empty(){
404                item.redraw_id = redraw_id;
405                item.kind = CxDrawKind::SubList(sub_list_id);
406                return
407            }
408        }
409        self.append_sub_list(redraw_id, sub_list_id);
410    }
411    
412    pub fn clear_sub_list(&mut self, sub_list_id: DrawListId) {
413        // set our subview to empty
414        for i in 0..self.draw_items.len(){
415            let item = &mut self.draw_items[i];
416            if let Some(check_id) = item.kind.sub_list(){
417                if check_id == sub_list_id{
418                    item.kind = CxDrawKind::Empty;
419                }
420            }
421        }
422    }
423    /*
424    pub fn get_local_scroll(&self) -> Vec2 {
425        let xs = if self.no_v_scroll {0.} else {self.snapped_scroll.x};
426        let ys = if self.no_h_scroll {0.} else {self.snapped_scroll.y};
427        Vec2 {x: xs, y: ys}
428    }*/
429    
430    pub fn uniform_view_transform(&mut self, v: &Mat4) {
431        //dump in uniforms
432        for i in 0..16 {
433            self.draw_list_uniforms.view_transform[i] = v.v[i];
434        }
435    }
436    
437    pub fn get_view_transform(&self) -> Mat4 {
438        //dump in uniforms
439        let mut m = Mat4::default();
440        for i in 0..16 {
441            m.v[i] = self.draw_list_uniforms.view_transform[i];
442        }
443        m
444    }
445}