makepad_platform/os/linux/
opengl.rs

1use {
2    std::{
3        fs::File,
4        io::prelude::*,
5        mem,
6        ptr,
7        ffi::CStr,
8    },
9    self::super::gl_sys,
10    crate::{
11        makepad_live_id::*,
12        makepad_error_log::*,
13        makepad_shader_compiler::generate_glsl,
14        cx::Cx,
15        texture::{TextureId, TextureDesc, TextureFormat},
16        makepad_math::{Mat4, DVec2, Vec4},
17        pass::{PassClearColor, PassClearDepth, PassId},
18        draw_list::DrawListId,
19        draw_shader::{CxDrawShaderMapping, DrawShaderTextureInput},
20    },
21};
22
23impl Cx {
24    
25    pub (crate) fn render_view(
26        &mut self,
27        pass_id: PassId,
28        draw_list_id: DrawListId,
29        zbias: &mut f32,
30        zbias_step: f32,
31    ) {
32        // tad ugly otherwise the borrow checker locks 'self' and we can't recur
33        let draw_items_len = self.draw_lists[draw_list_id].draw_items.len();
34        //self.views[view_id].set_clipping_uniforms();
35        self.draw_lists[draw_list_id].uniform_view_transform(&Mat4::identity());
36        
37        for draw_item_id in 0..draw_items_len {
38            if let Some(sub_list_id) = self.draw_lists[draw_list_id].draw_items[draw_item_id].kind.sub_list() {
39                self.render_view(
40                    pass_id,
41                    sub_list_id,
42                    zbias,
43                    zbias_step,
44                );
45            }
46            else {
47                let draw_list = &mut self.draw_lists[draw_list_id];
48                let draw_item = &mut draw_list.draw_items[draw_item_id];
49                
50                let draw_call = if let Some(draw_call) = draw_item.kind.draw_call_mut() {
51                    draw_call
52                }else {
53                    continue;
54                };
55                
56                let sh = &self.draw_shaders.shaders[draw_call.draw_shader.draw_shader_id];
57                if sh.os_shader_id.is_none() { // shader didnt compile somehow
58                    continue;
59                }
60                let shp = &mut self.draw_shaders.os_shaders[sh.os_shader_id.unwrap()];
61                
62                if shp.gl_shader.is_none(){
63                    shp.gl_shader = Some(GlShader::new(
64                        &shp.vertex,
65                        &shp.pixel,
66                        &sh.mapping,
67                        self.os_type.get_cache_dir().as_ref()
68                    ));
69                }
70                let shgl = shp.gl_shader.as_ref().unwrap();
71                
72                if draw_call.instance_dirty || draw_item.os.inst_vb.gl_buffer.is_none(){
73                    draw_call.instance_dirty = false;
74                    draw_item.os.inst_vb.update_with_f32_data(draw_item.instances.as_ref().unwrap());
75                }
76                
77                // update the zbias uniform if we have it.
78                draw_call.draw_uniforms.set_zbias(*zbias);
79                *zbias += zbias_step;
80                
81                let instances = (draw_item.instances.as_ref().unwrap().len() / sh.mapping.instances.total_slots) as u64;
82                
83                if instances == 0 {
84                    continue;
85                }
86                
87                let geometry_id = if let Some(geometry_id) = draw_call.geometry_id {geometry_id}
88                else {
89                    continue;
90                };
91                
92                let geometry = &mut self.geometries[geometry_id];
93                if geometry.dirty || geometry.os.vb.gl_buffer.is_none() || geometry.os.ib.gl_buffer.is_none() {
94                    geometry.os.vb.update_with_f32_data(&geometry.vertices);
95                    geometry.os.ib.update_with_u32_data(&geometry.indices);
96                    geometry.dirty = false;
97                }
98                
99                let indices = geometry.indices.len();
100                
101                if draw_call.uniforms_dirty {
102                    draw_call.uniforms_dirty = false;
103                }
104                
105                // update geometry?
106                let geometry = &mut self.geometries[geometry_id];
107                
108                // lets check if our vao is still valid
109                if draw_item.os.vao.is_none() {
110                    draw_item.os.vao = Some(CxOsDrawCallVao {
111                        vao: None,
112                        shader_id: None,
113                        inst_vb: None,
114                        geom_vb: None,
115                        geom_ib: None,
116                    });
117                }
118                
119                let vao = draw_item.os.vao.as_mut().unwrap();
120                if vao.inst_vb != draw_item.os.inst_vb.gl_buffer
121                    || vao.geom_vb != geometry.os.vb.gl_buffer
122                    || vao.geom_ib != geometry.os.ib.gl_buffer
123                    || vao.shader_id != Some(draw_call.draw_shader.draw_shader_id) {
124                    
125                    if let Some(vao) = vao.vao.take(){
126                        unsafe{gl_sys::DeleteVertexArrays(1, &vao)};
127                    }
128                        
129                    vao.vao = Some(unsafe {
130                        let mut vao = 0u32;
131                        gl_sys::GenVertexArrays(1, &mut vao);
132                        vao
133                    });    
134                    
135                    vao.shader_id = Some(draw_call.draw_shader.draw_shader_id);
136                    vao.inst_vb = draw_item.os.inst_vb.gl_buffer;
137                    vao.geom_vb = geometry.os.vb.gl_buffer;
138                    vao.geom_ib = geometry.os.ib.gl_buffer;
139                    unsafe {
140                        gl_sys::BindVertexArray(vao.vao.unwrap());
141                        
142                        // bind the vertex and indexbuffers
143                        gl_sys::BindBuffer(gl_sys::ARRAY_BUFFER, vao.geom_vb.unwrap());
144                        for attr in &shgl.geometries {
145                            gl_sys::VertexAttribPointer(attr.loc, attr.size, gl_sys::FLOAT, 0, attr.stride, attr.offset as *const () as *const _);
146                            gl_sys::EnableVertexAttribArray(attr.loc);
147                        }
148                        
149                        gl_sys::BindBuffer(gl_sys::ARRAY_BUFFER, vao.inst_vb.unwrap());
150                        
151                        for attr in &shgl.instances {
152                            gl_sys::VertexAttribPointer(attr.loc, attr.size, gl_sys::FLOAT, 0, attr.stride, attr.offset as *const () as *const _);
153                            gl_sys::EnableVertexAttribArray(attr.loc);
154                            gl_sys::VertexAttribDivisor(attr.loc, 1 as gl_sys::GLuint);
155                        }
156                        
157                        // bind the indexbuffer
158                        gl_sys::BindBuffer(gl_sys::ELEMENT_ARRAY_BUFFER, vao.geom_ib.unwrap());
159                        gl_sys::BindVertexArray(0);
160                    }
161                }
162                
163                unsafe {
164                    gl_sys::UseProgram(shgl.program);
165                    
166                    gl_sys::BindVertexArray(draw_item.os.vao.as_ref().unwrap().vao.unwrap());
167                    let instances = (draw_item.instances.as_ref().unwrap().len() / sh.mapping.instances.total_slots) as u64;
168                    
169                    let pass_uniforms = self.passes[pass_id].pass_uniforms.as_slice();
170                    let draw_list_uniforms = draw_list.draw_list_uniforms.as_slice();
171                    let draw_uniforms = draw_call.draw_uniforms.as_slice();
172                    
173                    GlShader::set_uniform_array(&shgl.pass_uniforms, pass_uniforms);
174                    GlShader::set_uniform_array(&shgl.view_uniforms, draw_list_uniforms);
175                    GlShader::set_uniform_array(&shgl.draw_uniforms, draw_uniforms);
176                    GlShader::set_uniform_array(&shgl.user_uniforms, &draw_call.user_uniforms);
177                    GlShader::set_uniform_array(&shgl.live_uniforms, &sh.mapping.live_uniforms_buf);
178                    
179                    let ct = &sh.mapping.const_table.table;
180                    if ct.len()>0 {
181                        GlShader::set_uniform_array(&shgl.const_table_uniform, ct);
182                    }
183                    
184                    // lets set our textures
185                    for i in 0..sh.mapping.textures.len() {
186                        let texture_id = if let Some(texture_id) = draw_call.texture_slots[i] {
187                            texture_id
188                        }else {
189                            continue;
190                        };
191                        let cxtexture = &mut self.textures[texture_id];
192
193                        if cxtexture.update_image || cxtexture.image_u32.len() != 0 && cxtexture.os.gl_texture.is_none(){
194                            cxtexture.update_image = false;
195                            cxtexture.os.update_platform_texture_image2d(
196                                cxtexture.desc.width.unwrap() as u32,
197                                cxtexture.desc.height.unwrap() as u32,
198                                &cxtexture.image_u32
199                            );
200                        }
201                    }
202                    for i in 0..sh.mapping.textures.len() {
203                        let texture_id = if let Some(texture_id) = draw_call.texture_slots[i] {
204                            texture_id
205                        }else {
206                            continue;
207                        };
208                        let cxtexture = &mut self.textures[texture_id];
209                        // get the loc
210                        gl_sys::ActiveTexture(gl_sys::TEXTURE0 + i as u32);
211                        if let Some(texture) = cxtexture.os.gl_texture {
212                            gl_sys::BindTexture(gl_sys::TEXTURE_2D, texture);
213                        }
214                        else {
215                            gl_sys::BindTexture(gl_sys::TEXTURE_2D, 0);
216                        }
217                        gl_sys::Uniform1i(shgl.textures[i].loc, i as i32);
218                    }
219                    
220                    gl_sys::DrawElementsInstanced(
221                        gl_sys::TRIANGLES,
222                        indices as i32,
223                        gl_sys::UNSIGNED_INT,
224                        ptr::null(),
225                        instances as i32
226                    );
227                    
228                    gl_sys::BindVertexArray(0);
229                }
230                
231            }
232        }
233    }
234    
235    pub fn set_default_depth_and_blend_mode() {
236        unsafe {
237            gl_sys::Enable(gl_sys::DEPTH_TEST);
238            gl_sys::DepthFunc(gl_sys::LEQUAL);
239            gl_sys::BlendEquationSeparate(gl_sys::FUNC_ADD, gl_sys::FUNC_ADD);
240            gl_sys::BlendFuncSeparate(gl_sys::ONE, gl_sys::ONE_MINUS_SRC_ALPHA, gl_sys::ONE, gl_sys::ONE_MINUS_SRC_ALPHA);
241            gl_sys::Enable(gl_sys::BLEND);
242        }
243    }
244    
245    pub fn setup_render_pass(&mut self, pass_id: PassId,) -> Option<DVec2> {
246        
247        let dpi_factor = self.passes[pass_id].dpi_factor.unwrap();
248        let pass_rect = self.get_pass_rect2(pass_id, dpi_factor).unwrap();
249        self.passes[pass_id].paint_dirty = false;
250        
251        if pass_rect.size.x <0.5 || pass_rect.size.y < 0.5 {
252            return None
253        }
254        
255        self.passes[pass_id].set_matrix(pass_rect.pos, pass_rect.size);
256        self.passes[pass_id].set_dpi_factor(dpi_factor);
257        Some(pass_rect.size)
258    }
259
260    pub fn draw_pass_to_texture(&mut self, pass_id: PassId, texture_id: TextureId) {
261        self.draw_pass_to_texture_inner(pass_id, Some(texture_id))
262    }
263
264    pub fn draw_pass_to_magic_texture(&mut self, pass_id: PassId) {
265        self.draw_pass_to_texture_inner(pass_id, None)
266    }
267
268    fn draw_pass_to_texture_inner(
269        &mut self,
270        pass_id: PassId,
271        maybe_texture_id: Option<TextureId>,
272    ) {
273        let draw_list_id = self.passes[pass_id].main_draw_list_id.unwrap();
274        
275        let pass_size = if let Some(pz) = self.setup_render_pass(pass_id) {
276            pz
277        }
278        else {
279            return
280        };
281        
282        let dpi_factor = self.passes[pass_id].dpi_factor.unwrap();
283        
284        self.passes[pass_id].set_dpi_factor(dpi_factor);
285        
286        let mut clear_color = Vec4::default();
287        let mut clear_depth = 1.0;
288        let mut clear_flags = 0;
289        
290        // make a framebuffer
291        if self.passes[pass_id].os.gl_framebuffer.is_none() {
292            unsafe {
293                let mut gl_framebuffer = std::mem::MaybeUninit::uninit();
294                gl_sys::GenFramebuffers(1, gl_framebuffer.as_mut_ptr());
295                self.passes[pass_id].os.gl_framebuffer = Some(gl_framebuffer.assume_init());
296            }
297        }
298        
299        // bind the framebuffer
300        unsafe {
301            gl_sys::BindFramebuffer(gl_sys::FRAMEBUFFER, self.passes[pass_id].os.gl_framebuffer.unwrap());
302        }
303
304        let color_textures_from_fb_texture = maybe_texture_id.map(|texture_id| {
305            [crate::pass::CxPassColorTexture {
306                clear_color: PassClearColor::ClearWith(self.passes[pass_id].clear_color),
307                texture_id,
308            }]
309        });
310        let color_textures = color_textures_from_fb_texture
311            .as_ref().map_or(&self.passes[pass_id].color_textures[..], |xs| &xs[..]);
312
313        for (index, color_texture) in color_textures.iter().enumerate() {
314            match color_texture.clear_color {
315                PassClearColor::InitWith(_clear_color) => {
316                    let cxtexture = &mut self.textures[color_texture.texture_id];
317                    if cxtexture.os.update_platform_render_target(&cxtexture.desc, dpi_factor * pass_size, false) {
318                        clear_color = _clear_color;
319                        clear_flags |= gl_sys::COLOR_BUFFER_BIT;
320                    }
321                },
322                PassClearColor::ClearWith(_clear_color) => {
323                    let cxtexture = &mut self.textures[color_texture.texture_id];
324                    cxtexture.os.update_platform_render_target(&cxtexture.desc, dpi_factor * pass_size, false);
325                    clear_color = _clear_color;
326                    clear_flags |= gl_sys::COLOR_BUFFER_BIT;
327                }
328            }
329            if let Some(gl_texture) = self.textures[color_texture.texture_id].os.gl_texture {
330                unsafe {
331                    gl_sys::FramebufferTexture2D(gl_sys::FRAMEBUFFER, gl_sys::COLOR_ATTACHMENT0 + index as u32, gl_sys::TEXTURE_2D, gl_texture, 0);
332                }
333            }
334        }
335        
336        // attach/clear depth buffers, if any
337        if let Some(depth_texture_id) = self.passes[pass_id].depth_texture {
338            match self.passes[pass_id].clear_depth {
339                PassClearDepth::InitWith(_clear_depth) => {
340                    let cxtexture = &mut self.textures[depth_texture_id];
341                    if cxtexture.os.update_platform_render_target(&cxtexture.desc, dpi_factor * pass_size, true) {
342                        clear_depth = _clear_depth;
343                        clear_flags |= gl_sys::DEPTH_BUFFER_BIT;
344                    }
345                },
346                PassClearDepth::ClearWith(_clear_depth) => {
347                    let cxtexture = &mut self.textures[depth_texture_id];
348                    cxtexture.os.update_platform_render_target(&cxtexture.desc, dpi_factor * pass_size, true);
349                    clear_depth = _clear_depth;
350                    clear_flags |= gl_sys::DEPTH_BUFFER_BIT;
351                }
352            }
353        }
354        else {
355            /* unsafe { // BUGFIX. we have to create a depthbuffer for rtt without depthbuffer use otherwise it fails if there is another pass with depth
356                if self.passes[pass_id].os.gl_bugfix_depthbuffer.is_none() {
357                    let mut gl_renderbuf = std::mem::MaybeUninit::uninit();
358                    gl_sys::GenRenderbuffers(1, gl_renderbuf.as_mut_ptr());
359                    let gl_renderbuffer = gl_renderbuf.assume_init();
360                    gl_sys::BindRenderbuffer(gl_sys::RENDERBUFFER, gl_renderbuffer);
361                    gl_sys::RenderbufferStorage(
362                        gl_sys::RENDERBUFFER,
363                        gl_sys::DEPTH_COMPONENT16,
364                        (pass_size.x * dpi_factor) as i32,
365                        (pass_size.y * dpi_factor) as i32
366                    );
367                    gl_sys::BindRenderbuffer(gl_sys::RENDERBUFFER, 0);
368                    self.passes[pass_id].os.gl_bugfix_depthbuffer = Some(gl_renderbuffer);
369                }
370                clear_depth = 1.0;
371                clear_flags |= gl_sys::DEPTH_BUFFER_BIT;
372                gl_sys::Disable(gl_sys::DEPTH_TEST);
373                gl_sys::FramebufferRenderbuffer(gl_sys::FRAMEBUFFER, gl_sys::DEPTH_ATTACHMENT, gl_sys::RENDERBUFFER, self.passes[pass_id].os.gl_bugfix_depthbuffer.unwrap());
374            }*/
375        }
376
377        // HACK(eddyb) drain error queue, so that we can check erors below.
378        while unsafe { gl_sys::GetError() } != 0 {}
379
380        unsafe {
381            let (x, mut y) = (0, 0);
382            let width = (pass_size.x * dpi_factor) as u32;
383            let height = (pass_size.y * dpi_factor) as u32;
384
385            // HACK(eddyb) to try and match DirectX and Metal conventions, we
386            // need the viewport to be placed on the other end of the Y axis.
387            if let [color_texture] = color_textures {
388                let cxtexture = &mut self.textures[color_texture.texture_id];
389                if cxtexture.os.gl_texture.is_some() {
390                    if let Some(alloc_height) = cxtexture.os.alloc_desc.height {
391                        let alloc_height = alloc_height as u32;
392                        if alloc_height > height {
393                            y = alloc_height - height;
394                        }
395                    }
396                }
397            }
398
399            gl_sys::Viewport(x as i32, y as i32, width as i32, height as i32);
400            assert_eq!(gl_sys::GetError(), 0, "glViewport({x}, {y}, {width}, {height}) failed");
401        }
402
403        if clear_flags != 0 {
404            unsafe {
405                if clear_flags & gl_sys::DEPTH_BUFFER_BIT != 0 {
406                    gl_sys::ClearDepthf(clear_depth);
407                }
408                gl_sys::ClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
409                gl_sys::Clear(clear_flags);
410            }
411        }
412        Self::set_default_depth_and_blend_mode();
413        
414        let mut zbias = 0.0;
415        let zbias_step = self.passes[pass_id].zbias_step;
416        
417        self.render_view(
418            pass_id,
419            draw_list_id,
420            &mut zbias,
421            zbias_step,
422        );
423        
424        unsafe {
425            gl_sys::BindFramebuffer(gl_sys::FRAMEBUFFER, 0);
426            //gl_sys::Finish();
427        }
428    }
429    
430    pub fn opengl_compile_shaders(&mut self) {
431        //let p = profile_start();
432        for draw_shader_ptr in &self.draw_shaders.compile_set {
433            if let Some(item) = self.draw_shaders.ptr_to_item.get(&draw_shader_ptr) {
434                let cx_shader = &mut self.draw_shaders.shaders[item.draw_shader_id];
435                let draw_shader_def = self.shader_registry.draw_shader_defs.get(&draw_shader_ptr);
436                
437                let vertex = generate_glsl::generate_vertex_shader(
438                    draw_shader_def.as_ref().unwrap(),
439                    &cx_shader.mapping.const_table,
440                    &self.shader_registry
441                );
442                let pixel = generate_glsl::generate_pixel_shader(
443                    draw_shader_def.as_ref().unwrap(),
444                    &cx_shader.mapping.const_table,
445                    &self.shader_registry
446                );
447                
448                if cx_shader.mapping.flags.debug {
449                    log!("{}\n{}", vertex, pixel);
450                }
451                
452                // lets see if we have the shader already
453                for (index, ds) in self.draw_shaders.os_shaders.iter().enumerate() {
454                    if ds.vertex == vertex && ds.pixel == pixel {
455                        cx_shader.os_shader_id = Some(index);
456                        break;
457                    }
458                }
459                
460                if cx_shader.os_shader_id.is_none() {
461                    let shp = CxOsDrawShader::new(&vertex, &pixel);
462                    cx_shader.os_shader_id = Some(self.draw_shaders.os_shaders.len());
463                    self.draw_shaders.os_shaders.push(shp);
464                }
465            }
466        }
467        self.draw_shaders.compile_set.clear();
468    }
469}
470
471
472#[derive(Clone)]
473pub struct CxOsDrawShader {
474    pub gl_shader: Option<GlShader>,
475    pub vertex: String,
476    pub pixel: String,
477}
478
479#[derive(Clone)]
480pub struct GlShader {
481    pub program: u32,
482    pub geometries: Vec<OpenglAttribute>,
483    pub instances: Vec<OpenglAttribute>,
484    pub textures: Vec<OpenglUniform>,
485    pub pass_uniforms: OpenglUniform,
486    pub view_uniforms: OpenglUniform,
487    pub draw_uniforms: OpenglUniform,
488    pub user_uniforms: OpenglUniform,
489    pub live_uniforms: OpenglUniform,
490    pub const_table_uniform: OpenglUniform,
491}
492
493impl GlShader{
494    pub fn new(vertex: &str, pixel: &str, mapping: &CxDrawShaderMapping, cache_dir: Option<&String>)->Self{
495        unsafe fn read_cache(vertex:&str, pixel:&str, cache_dir:Option<&String>)->Option<gl_sys::GLuint>{ 
496            if let Some(cache_dir) = cache_dir {
497                let shader_hash = live_id!(shader).str_append(&vertex).str_append(&pixel);
498                if let Ok(mut cache_file) = File::open(format!("{}/shader_{:08x}.bin", cache_dir, shader_hash.0)) {
499                    let mut binary = Vec::new();
500                    let mut format_bytes = [0u8; 4];
501                    if cache_file.read(&mut format_bytes).is_ok() {
502                        let binary_format = u32::from_be_bytes(format_bytes);
503                        if cache_file.read_to_end(&mut binary).is_ok() {
504                            let program = gl_sys::CreateProgram();
505                            gl_sys::ProgramBinary(program, binary_format, binary.as_ptr() as *const _, binary.len() as i32);
506                            return Some(program)
507                        }
508                    }
509                }
510            }
511            None
512        }
513        
514        unsafe {
515            let program = if let Some(program) = read_cache(&vertex,&pixel,cache_dir){
516                program
517            }
518            else{ 
519                let vs = gl_sys::CreateShader(gl_sys::VERTEX_SHADER);
520                gl_sys::ShaderSource(vs, 1, [vertex.as_ptr() as *const _].as_ptr(), ptr::null());
521                gl_sys::CompileShader(vs);
522                //println!("{}", Self::opengl_get_info_log(true, vs as usize, &vertex));
523                if let Some(error) = Self::opengl_has_shader_error(true, vs as usize, &vertex) {
524                    panic!("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n{}", error);
525                }
526                let fs = gl_sys::CreateShader(gl_sys::FRAGMENT_SHADER);
527                gl_sys::ShaderSource(fs, 1, [pixel.as_ptr() as *const _].as_ptr(), ptr::null());
528                gl_sys::CompileShader(fs);
529                //println!("{}", Self::opengl_get_info_log(true, fs as usize, &fragment));
530                if let Some(error) = Self::opengl_has_shader_error(true, fs as usize, &pixel) {
531                    panic!("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n{}", error);
532                }
533                
534                let program = gl_sys::CreateProgram();
535                gl_sys::AttachShader(program, vs);
536                gl_sys::AttachShader(program, fs);
537                gl_sys::LinkProgram(program);
538                if let Some(error) = Self::opengl_has_shader_error(false, program as usize, "") {
539                    panic!("ERROR::SHADER::LINK::COMPILATION_FAILED\n{}", error);
540                }
541                gl_sys::DeleteShader(vs);
542                gl_sys::DeleteShader(fs);
543                program
544            };
545            
546            if let Some(cache_dir) = cache_dir {
547                let mut binary = Vec::new();
548                let mut binary_len = 0;
549                gl_sys::GetProgramiv(program, gl_sys::PROGRAM_BINARY_LENGTH, &mut binary_len);
550                if binary_len != 0 {
551                    binary.resize(binary_len as usize, 0u8);
552                    let mut return_size = 0i32;
553                    let mut binary_format = 0u32;
554                    gl_sys::GetProgramBinary(program, binary.len() as i32, &mut return_size as *mut _, &mut binary_format as *mut _, binary.as_mut_ptr() as *mut _);
555                    if return_size != 0 {
556                        //log!("GOT FORMAT {}", format);
557                        let shader_hash = live_id!(shader).str_append(&vertex).str_append(&pixel);
558                        binary.resize(return_size as usize, 0u8);
559                        if let Ok(mut cache) = File::create(format!("{}/shader_{:08x}.bin", cache_dir, shader_hash.0)) {
560                            let _ = cache.write_all(&binary_format.to_be_bytes());
561                            let _ = cache.write_all(&binary);
562                        }
563                    }
564                } 
565            }
566
567            Self{
568                program,
569                geometries:Self::opengl_get_attributes(program, "packed_geometry_", mapping.geometries.total_slots),
570                instances: Self::opengl_get_attributes(program, "packed_instance_", mapping.instances.total_slots),
571                textures: Self::opengl_get_texture_slots(program, &mapping.textures),
572                pass_uniforms: Self::opengl_get_uniform(program, "pass_table"),
573                view_uniforms: Self::opengl_get_uniform(program, "view_table"),
574                draw_uniforms: Self::opengl_get_uniform(program, "draw_table"),
575                user_uniforms: Self::opengl_get_uniform(program, "user_table"),
576                live_uniforms: Self::opengl_get_uniform(program, "live_table"),
577                const_table_uniform: Self::opengl_get_uniform(program, "const_table"),
578            }
579        }
580    }
581
582    
583    pub fn set_uniform_array(loc: &OpenglUniform, array: &[f32]) {
584        unsafe {
585            gl_sys::Uniform1fv(loc.loc as i32, array.len() as i32, array.as_ptr());
586        }
587    }
588    
589    pub fn opengl_get_uniform(program: u32, name: &str) -> OpenglUniform {
590        let mut name0 = String::new();
591        name0.push_str(name);
592        name0.push_str("\0");
593        unsafe {
594            OpenglUniform {
595                loc: gl_sys::GetUniformLocation(program, name0.as_ptr() as *const _),
596                //name: name.to_string(),
597            }
598        }
599    }
600    
601    pub fn opengl_get_info_log(compile: bool, shader: usize, source: &str) -> String {
602        unsafe {
603            let mut length = 0;
604            if compile {
605                gl_sys::GetShaderiv(shader as u32, gl_sys::INFO_LOG_LENGTH, &mut length);
606            } else {
607                gl_sys::GetProgramiv(shader as u32, gl_sys::INFO_LOG_LENGTH, &mut length);
608            }
609            let mut log = Vec::with_capacity(length as usize);
610            if compile {
611                gl_sys::GetShaderInfoLog(shader as u32, length, ptr::null_mut(), log.as_mut_ptr());
612            } else {
613                gl_sys::GetProgramInfoLog(shader as u32, length, ptr::null_mut(), log.as_mut_ptr());
614            }
615            log.set_len(length as usize);
616            let mut r = "".to_string();
617            r.push_str(CStr::from_ptr(log.as_ptr()).to_str().unwrap());
618            r.push_str("\n");
619            let split = source.split("\n");
620            for (line, chunk) in split.enumerate() {
621                r.push_str(&(line + 1).to_string());
622                r.push_str(":");
623                r.push_str(chunk);
624                r.push_str("\n");
625            }
626            r
627        }
628    }
629    
630    pub fn opengl_has_shader_error(compile: bool, shader: usize, source: &str) -> Option<String> {
631        //None
632        unsafe {
633            
634            let mut success = gl_sys::TRUE as i32;
635            
636            if compile {
637                gl_sys::GetShaderiv(shader as u32, gl_sys::COMPILE_STATUS, &mut success);
638            }
639            else {
640                gl_sys::GetProgramiv(shader as u32, gl_sys::LINK_STATUS, &mut success);
641            };
642            
643            if success != gl_sys::TRUE as i32 {
644                Some(Self::opengl_get_info_log(compile, shader, source))
645            }
646            else {
647                None
648            }
649        }
650    }
651    
652    pub fn opengl_get_attributes(program: u32, prefix: &str, slots: usize) -> Vec<OpenglAttribute> {
653        let mut attribs = Vec::new();
654        
655        fn ceil_div4(base: usize) -> usize {
656            let r = base >> 2;
657            if base & 3 != 0 {
658                return r + 1
659            }
660            r
661        }
662        
663        let stride = (slots * mem::size_of::<f32>()) as i32;
664        let num_attr = ceil_div4(slots);
665        for i in 0..num_attr {
666            let mut name0 = prefix.to_string();
667            name0.push_str(&i.to_string());
668            name0.push_str("\0");
669            
670            let mut size = ((slots - i * 4)) as i32;
671            if size > 4 {
672                size = 4;
673            }
674            unsafe {
675                attribs.push(
676                    OpenglAttribute {
677                        loc: {
678                            let loc = gl_sys::GetAttribLocation(program, name0.as_ptr() as *const _) as u32;
679                            loc
680                        },
681                        offset: (i * 4 * mem::size_of::<f32>()) as usize,
682                        size: size,
683                        stride: stride
684                    }
685                )
686            }
687        }
688        attribs
689    }
690    
691    
692    pub fn opengl_get_texture_slots(program: u32, texture_slots: &Vec<DrawShaderTextureInput>) -> Vec<OpenglUniform> {
693        let mut gl_texture_slots = Vec::new();
694        
695        for slot in texture_slots {
696            let mut name0 = "ds_".to_string();
697            name0.push_str(&slot.id.to_string());
698            name0.push_str("\0");
699            unsafe {
700                gl_texture_slots.push(OpenglUniform {
701                    loc: gl_sys::GetUniformLocation(program, name0.as_ptr() as *const _),
702                })
703            }
704        }
705        gl_texture_slots
706    }
707
708    pub fn free_resources(self){
709        unsafe{
710            gl_sys::DeleteShader(self.program);
711        }
712    }
713}
714
715impl CxOsDrawShader {
716    pub fn new(vertex: &str, pixel: &str) -> Self {
717        
718        let vertex = format!("
719            #version 100
720            precision highp float;
721            precision highp int;
722            vec4 sample2d(sampler2D sampler, vec2 pos){{return texture2D(sampler, vec2(pos.x, pos.y)).zyxw;}} 
723            vec4 sample2d_rt(sampler2D sampler, vec2 pos){{return texture2D(sampler, vec2(pos.x, 1.0-pos.y));}}
724            mat4 transpose(mat4 m){{return mat4(m[0][0],m[1][0],m[2][0],m[3][0],m[0][1],m[1][1],m[2][1],m[3][1],m[0][2],m[1][2],m[2][2],m[3][3], m[3][0], m[3][1], m[3][2], m[3][3]);}}
725            mat3 transpose(mat3 m){{return mat3(m[0][0],m[1][0],m[2][0],m[0][1],m[1][1],m[2][1],m[0][2],m[1][2],m[2][2]);}}
726            mat2 transpose(mat2 m){{return mat2(m[0][0],m[1][0],m[0][1],m[1][1]);}}
727            {}\0", vertex);
728        
729        let pixel = format!("
730            #version 100
731            #extension GL_OES_standard_derivatives : enable
732            precision highp float;
733            precision highp int;
734            vec4 sample2d(sampler2D sampler, vec2 pos){{return texture2D(sampler, vec2(pos.x, pos.y)).zyxw;}}
735            vec4 sample2d_rt(sampler2D sampler, vec2 pos){{return texture2D(sampler, vec2(pos.x, 1.0-pos.y));}}
736            mat4 transpose(mat4 m){{return mat4(m[0][0],m[1][0],m[2][0],m[3][0],m[0][1],m[1][1],m[2][1],m[3][1],m[0][2],m[1][2],m[2][2],m[3][3], m[3][0], m[3][1], m[3][2], m[3][3]);}}
737            mat3 transpose(mat3 m){{return mat3(m[0][0],m[1][0],m[2][0],m[0][1],m[1][1],m[2][1],m[0][2],m[1][2],m[2][2]);}}
738            mat2 transpose(mat2 m){{return mat2(m[0][0],m[1][0],m[0][1],m[1][1]);}}
739            {}\0", pixel);
740        
741            // lets fetch the uniform positions for our uniforms
742        CxOsDrawShader {
743            vertex,
744            pixel,
745            gl_shader: None,
746        }
747    }
748
749    pub fn free_resources(&mut self){
750        if let Some(gl_shader) = self.gl_shader.take(){
751            gl_shader.free_resources();
752        }
753    }
754}
755
756#[derive(Default, Clone)]
757pub struct OpenglAttribute {
758    pub loc: u32,
759    pub size: i32,
760    pub offset: usize,
761    pub stride: i32
762}
763
764#[derive(Debug, Default, Clone)]
765pub struct OpenglUniform {
766    pub loc: i32,
767    //pub name: String,
768}
769
770
771#[derive(Clone, Default)]
772pub struct CxOsGeometry {
773    pub vb: OpenglBuffer,
774    pub ib: OpenglBuffer,
775}
776
777impl CxOsGeometry{
778    pub fn free_resources(&mut self){
779        self.vb.free_resources();
780        self.ib.free_resources();
781    }
782}
783    
784
785/*
786#[derive(Default, Clone)]
787pub struct OpenglTextureSlot {
788    pub loc: isize,
789    pub name: String
790}
791*/
792#[derive(Clone, Default)]
793pub struct CxOsView {
794}
795
796#[derive(Default, Clone)]
797pub struct CxOsDrawCallVao {
798    pub vao: Option<u32>,
799    pub shader_id: Option<usize>,
800    pub inst_vb: Option<u32>,
801    pub geom_vb: Option<u32>,
802    pub geom_ib: Option<u32>,
803}
804
805impl CxOsDrawCallVao {
806    pub fn free(self){
807        if let Some(vao) = self.vao{
808            unsafe{gl_sys::DeleteVertexArrays(1, &vao)};
809        }
810    }    
811}
812
813#[derive(Default, Clone)]
814pub struct CxOsDrawCall {
815    pub inst_vb: OpenglBuffer,
816    pub vao: Option<CxOsDrawCallVao>,
817}
818
819impl CxOsDrawCall {
820    pub fn free_resources(&mut self){
821        self.inst_vb.free_resources();
822        if let Some(vao) = self.vao.take(){
823            vao.free();
824        }
825    }    
826}
827
828#[derive(Clone, Default)]
829pub struct CxOsTexture {
830    pub alloc_desc: TextureDesc,
831    pub width: u64,
832    pub height: u64,
833    pub gl_texture: Option<u32>,
834    pub gl_renderbuffer: Option<u32>,
835}
836
837impl CxOsTexture {
838    
839    pub fn update_platform_texture_image2d(&mut self, width: u32, height: u32, image_u32: &Vec<u32>) {
840        
841        if image_u32.len() != (width * height) as usize {
842            log!("update_platform_texture_image2d with wrong buffer_u32 size! {} {} {}", image_u32.len(), width, height);
843            return;
844        }
845        
846        if self.gl_texture.is_none() {
847            unsafe {
848                let mut gl_texture = std::mem::MaybeUninit::uninit();
849                gl_sys::GenTextures(1, gl_texture.as_mut_ptr());
850                self.gl_texture = Some(gl_texture.assume_init());
851            }
852        }
853        unsafe {
854            gl_sys::BindTexture(gl_sys::TEXTURE_2D, self.gl_texture.unwrap());
855            gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_MIN_FILTER, gl_sys::LINEAR_MIPMAP_LINEAR as i32);            
856            gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_MAG_FILTER, gl_sys::NEAREST as i32);
857            gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_WRAP_S, gl_sys::CLAMP_TO_EDGE as i32);
858            gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_WRAP_T, gl_sys::CLAMP_TO_EDGE as i32);
859            gl_sys::TexImage2D(
860                gl_sys::TEXTURE_2D,
861                0,
862                gl_sys::RGBA as i32,
863                width as i32,
864                height as i32,
865                0,
866                gl_sys::RGBA,
867                gl_sys::UNSIGNED_BYTE,
868                image_u32.as_ptr() as *const _
869            );
870            gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_BASE_LEVEL, 0);
871            gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_MAX_LEVEL, 3);
872            gl_sys::GenerateMipmap(gl_sys::TEXTURE_2D);  
873            gl_sys::BindTexture(gl_sys::TEXTURE_2D, 0);
874        }
875    }
876    
877    pub fn update_platform_render_target(&mut self, desc: &TextureDesc, default_size: DVec2, is_depth: bool) -> bool {
878        let width = desc.width.unwrap_or(default_size.x as usize) as u64;
879        let height = desc.height.unwrap_or(default_size.y as usize) as u64;
880        
881        if (self.gl_texture.is_some() || self.gl_renderbuffer.is_some()) && self.width == width && self.height == height && self.alloc_desc == *desc {
882            return false
883        }
884        
885        unsafe {
886            
887            self.alloc_desc = desc.clone();
888            self.width = width;
889            self.height = height;
890            
891            if !is_depth {
892                match desc.format {
893                    TextureFormat::Default | TextureFormat::RenderBGRA => {
894                        if self.gl_texture.is_none() {
895                            let mut gl_texture = std::mem::MaybeUninit::uninit();
896                            gl_sys::GenTextures(1, gl_texture.as_mut_ptr());
897                            self.gl_texture = Some(gl_texture.assume_init());
898                        }
899                        
900                        gl_sys::BindTexture(gl_sys::TEXTURE_2D, self.gl_texture.unwrap());
901                        
902                        //self.gl_texture = Some(gl_texture);
903                        
904                        gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_MIN_FILTER, gl_sys::NEAREST as i32);
905                        gl_sys::TexParameteri(gl_sys::TEXTURE_2D, gl_sys::TEXTURE_MAG_FILTER, gl_sys::NEAREST as i32);
906                        gl_sys::TexImage2D(
907                            gl_sys::TEXTURE_2D,
908                            0,
909                            gl_sys::RGBA as i32,
910                            width as i32,
911                            height as i32,
912                            0,
913                            gl_sys::RGBA,
914                            gl_sys::UNSIGNED_BYTE,
915                            ptr::null()
916                        );
917                        gl_sys::BindTexture(gl_sys::TEXTURE_2D, 0);
918                    },
919                    _ => {
920                        println!("update_platform_render_target unsupported texture format");
921                        return false;
922                    }
923                }
924            }
925            else {
926                match desc.format {
927                    TextureFormat::Default | TextureFormat::Depth32Stencil8 => {
928                        
929                        if self.gl_renderbuffer.is_none() {
930                            let mut gl_renderbuf = std::mem::MaybeUninit::uninit();
931                            gl_sys::GenRenderbuffers(1, gl_renderbuf.as_mut_ptr());
932                            let gl_renderbuffer = gl_renderbuf.assume_init();
933                            self.gl_renderbuffer = Some(gl_renderbuffer);
934                        }
935                        
936                        gl_sys::BindRenderbuffer(gl_sys::RENDERBUFFER, self.gl_renderbuffer.unwrap());
937                        gl_sys::RenderbufferStorage(
938                            gl_sys::RENDERBUFFER,
939                            gl_sys::DEPTH_COMPONENT32F,
940                            width as i32,
941                            height as i32
942                        );
943                        gl_sys::BindRenderbuffer(gl_sys::RENDERBUFFER, 0);
944                    },
945                    _ => {
946                        println!("update_platform_render_targete unsupported texture format");
947                        return false;
948                    }
949                }
950            }
951            
952        }
953        return true;
954    }
955    
956    pub fn free_resources(&mut self){
957        if let Some(gl_texture) = self.gl_texture.take(){
958            unsafe{gl_sys::DeleteTextures(1, &gl_texture)};
959        }
960        if let Some(gl_renderbuffer) = self.gl_renderbuffer.take(){
961            unsafe{gl_sys::DeleteRenderbuffers(1, &gl_renderbuffer)};
962        }
963    }
964    
965}
966
967#[derive(Default, Clone)]
968pub struct CxOsPass {
969    pub gl_framebuffer: Option<u32>,
970}
971
972impl CxOsPass{
973    
974    pub fn free_resources(&mut self){
975        if let Some(gl_framebuffer) = self.gl_framebuffer.take(){
976            unsafe{gl_sys::DeleteFramebuffers(1, &gl_framebuffer)};
977        }
978    }    
979}
980
981#[derive(Default, Clone)]
982pub struct OpenglBuffer {
983    pub gl_buffer: Option<u32>
984}
985
986impl OpenglBuffer {
987    
988    pub fn alloc_gl_buffer(&mut self) {
989        unsafe {
990            let mut gl_buffer = std::mem::MaybeUninit::uninit();
991            gl_sys::GenBuffers(1, gl_buffer.as_mut_ptr());
992            self.gl_buffer = Some(gl_buffer.assume_init());
993        }
994    }
995    
996    pub fn update_with_f32_data(&mut self, data: &Vec<f32>) {
997        if self.gl_buffer.is_none() {
998            self.alloc_gl_buffer();
999        }
1000        unsafe {
1001            gl_sys::BindBuffer(gl_sys::ARRAY_BUFFER, self.gl_buffer.unwrap());
1002            gl_sys::BufferData(
1003                gl_sys::ARRAY_BUFFER,
1004                (data.len() * mem::size_of::<f32>()) as gl_sys::types::GLsizeiptr,
1005                data.as_ptr() as *const _,
1006                gl_sys::STATIC_DRAW
1007            );
1008        }
1009    }
1010    
1011    pub fn update_with_u32_data(&mut self, data: &Vec<u32>) {
1012        if self.gl_buffer.is_none() {
1013            self.alloc_gl_buffer();
1014        }
1015        unsafe {
1016            gl_sys::BindBuffer(gl_sys::ELEMENT_ARRAY_BUFFER, self.gl_buffer.unwrap());
1017            gl_sys::BufferData(
1018                gl_sys::ELEMENT_ARRAY_BUFFER,
1019                (data.len() * mem::size_of::<u32>()) as gl_sys::types::GLsizeiptr,
1020                data.as_ptr() as *const _,
1021                gl_sys::STATIC_DRAW
1022            );
1023        }
1024    }
1025    
1026    pub fn free_resources(&mut self){
1027        if let Some(gl_buffer) = self.gl_buffer.take(){
1028            unsafe{gl_sys::DeleteBuffers(1, &gl_buffer)};
1029        }
1030    }
1031
1032}
1033
1034/*
1035// void shaders to test if we are shader compiletime bottlenecked
1036
1037                let vertex = "
1038uniform float const_table[24];
1039uniform float draw_table[1];
1040uniform float pass_table[50];
1041uniform float view_table[16];
1042attribute vec2 packed_geometry_0;
1043attribute vec4 packed_instance_0;
1044attribute vec3 packed_instance_1;
1045
1046void main() {
1047    gl_Position = vec4(0.0,0.0,0.0,0.0);
1048}";
1049
1050let pixel = "
1051uniform float const_table[24];
1052uniform float draw_table[1];
1053uniform float pass_table[50];
1054uniform float view_table[16];
1055
1056void main() {
1057    gl_FragColor = vec4(0.0,0.0,0.0,0.0);
1058}";*/
1059