makepad_platform/
draw_list.rs

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