e2rcore/implement/render/
renderer_gl.rs

1extern crate pretty_env_logger;
2extern crate gl;
3extern crate chrono;
4
5use self::chrono::prelude::*;
6
7use ::std::str;
8use ::std::ops::DerefMut;
9use std::collections::HashMap;
10use std::cell::RefCell;   
11
12use interface::i_ele;
13use interface::i_renderobj::RenderDevice;
14use interface::i_renderobj;
15use interface::i_renderpass;
16use interface::i_component;
17use interface::i_renderer::IRenderer;
18
19use implement::capability::capability_gl;
20use implement::render::util_gl;
21use implement::render::shader_collection;
22use implement::render::texture_collection;
23use implement::render::router;
24use implement::render::renderdevice_gl;
25use implement::render::render_commands;
26
27pub struct Renderer {
28    _rp: Vec< Box< i_renderpass::IRenderPass > >,
29    _map_string_to_rp: HashMap< String, usize >,
30    pub _shader_collection: RefCell< shader_collection::ShaderCollection >,
31    _texture_collection: texture_collection::TextureCollection,
32    _shader_programs: Vec< u64 >,
33    _draw_groups: RefCell< Vec< renderdevice_gl::RenderDrawGroup > >,
34    _vaos: Vec< gl::types::GLuint >,
35    _vbos: Vec< gl::types::GLuint >,
36    _objs: Vec< i_ele::Ele >,
37    _uniforms: RefCell< renderdevice_gl::RenderUniformCollection >,
38    _draw_group_uniforms: RefCell< Vec< Vec< u64 > > >,
39    _shaders_compiled: Vec< gl::types::GLuint >,
40    //todo: to be removed
41    _current_shader_program: u64,
42    _is_init: bool,
43    _draw_group: usize,
44}
45
46impl Drop for Renderer {
47    fn drop( & mut self ) {
48        unsafe {
49            gl::DeleteBuffers( self._vaos.len() as _, self._vaos.as_ptr(), );
50
51            gl::DeleteBuffers( self._vbos.len() as _, self._vbos.as_ptr(), );
52        }
53        self._shader_collection.borrow_mut().clear().is_ok(); //does DeleteProgram
54        unsafe {
55            for i in self._shaders_compiled.iter() {
56                gl::DeleteShader( *i );
57            }
58        }
59    }
60}
61
62pub enum Event {
63    AddObj( i_ele::Ele ),
64    LoadShader( Vec< ( String, util_gl::ShaderType ) > ),
65    LoadTexture( String, Vec< u8 >, usize, usize ),
66    CreateDrawGroup( i_renderobj::RenderObjType ),
67}
68
69pub enum EventResult {
70    IdShaderProgram( isize ),
71    IdTexture( isize ),
72    IdDrawGroup( isize ),
73}
74
75impl IRenderer for Renderer {
76
77    type EventRender = Event;
78    
79    fn init() -> Result< Self, & 'static str > {
80        Renderer::init()
81    }
82    fn process_render_events( & mut self, e: Vec< Self::EventRender > ) -> Result< (), & 'static str > {
83        //first time initialization
84        if !self._is_init {
85            info!("renderer: first time initialization.");
86            self._is_init = true;
87            let ( _vao, _vbo, draw_group ) = self.create_draw_group( i_renderobj::RenderObjType::TRI ).unwrap();
88            self._draw_group = draw_group;
89        }
90        
91        //setup hardcoded draw group for now
92        //todo: remove it and put in a configurable hook
93        let dummy_str = "";
94        let draw_group = self._draw_group;
95        self.add_obj( dummy_str, i_ele::Ele::init( render_commands::CmdDrawGroupClear::init( draw_group ) ) ).is_ok();
96
97        //handle events
98        //todo: handle return values from calls
99        for i in e {
100            let t0 = Local::now();
101            match i {
102                Event::AddObj( x ) => {
103                    self.add_obj( dummy_str, x )?;
104                    let t1 = Local::now();
105                    let t_delta = t1.signed_duration_since(t0).num_milliseconds() as f64;
106                    debug!( "t_render_add_obj: {} ms", t_delta );
107                },
108                Event::LoadShader( x ) => {
109                    self.load_shader( x.as_slice() )?;
110                    let t1 = Local::now();
111                    let t_delta = t1.signed_duration_since(t0).num_milliseconds() as f64;
112                    debug!( "t_render_load_shader: {} ms", t_delta );
113                },
114                Event::LoadTexture( s, data, w, h ) => {
115                    self.load_texture( s, &data, w, h )?;
116                    let t1 = Local::now();
117                    let t_delta = t1.signed_duration_since(t0).num_milliseconds() as f64;
118                    debug!( "t_render_load_texture: {} ms", t_delta );
119                },
120                Event::CreateDrawGroup( x ) => {
121                    self.create_draw_group( x )?;
122                    let t1 = Local::now();
123                    let t_delta = t1.signed_duration_since(t0).num_milliseconds() as f64;
124                    debug!( "t_render_create_draw_group: {} ms", t_delta );
125                },
126            }
127            util_gl::check_last_op();
128        }
129
130        //some hardcoded draw calls in preparation for rendering
131        //todo: put these in a configurable hook
132
133        let t0 = Local::now();
134
135        self.add_obj( dummy_str, i_ele::Ele::init( render_commands::CmdDrawGroupBind::init( draw_group ) ) ).is_ok();
136
137        let t1 = Local::now();
138        
139        self.add_obj( dummy_str, i_ele::Ele::init( render_commands::CmdDrawGroupDependentUniforms::init( draw_group, &[0u64,1u64] ) ) ).is_ok();
140
141        let t2 = Local::now();
142
143        self.add_obj( dummy_str, i_ele::Ele::init( render_commands::CmdDrawGroupDispatch::init( draw_group ) ) ).is_ok();
144
145        let t3 = Local::now();
146
147        {
148            let t_delta = t1.signed_duration_since(t0).num_milliseconds() as f64;
149            debug!( "t_draw_group_bind: {} ms", t_delta );
150        }
151        {
152            let t_delta = t2.signed_duration_since(t1).num_milliseconds() as f64;
153            debug!( "t_draw_group_dependent_uniforms: {} ms", t_delta );
154        }
155        {
156            let t_delta = t3.signed_duration_since(t2).num_milliseconds() as f64;
157            debug!( "t_draw_group_dispatch: {} ms", t_delta );
158        }
159
160        Ok( () )
161    }
162}
163
164impl Renderer {
165    pub fn init() -> Result< Renderer, & 'static str > {
166        let rk = Renderer {
167            _rp: vec![],
168            _map_string_to_rp: HashMap::new(),
169            _shader_collection: RefCell::new( Default::default() ),
170            _texture_collection: Default::default(),
171            _shader_programs: vec![],
172            _draw_groups: RefCell::new( vec![] ),
173            _vaos: vec![],
174            _vbos: vec![],
175            _objs: vec![],
176            _uniforms: RefCell::new( Default::default() ),
177            _draw_group_uniforms: RefCell::new( vec![] ),
178            _shaders_compiled: vec![],
179            _current_shader_program: 0,
180            _is_init: false,
181            _draw_group: 0usize,
182        };
183        let cap = capability_gl::query_gl();
184        info!( "GL capability: {}", cap );
185        Ok( rk )
186    }
187    pub fn load_shader( & mut self, sources: &[ ( String, util_gl::ShaderType ) ] ) -> Result< ( u64 ), & 'static str > {
188        let mut compiled_shaders = vec![];
189        for &(ref src, ref src_type ) in sources.into_iter() {
190            let s = match util_gl::load_and_compile_shader( (*src).as_str(), *src_type ) {
191                Ok( o ) => o,
192                Err( o ) => {
193                    error!( "{}", o );
194                    return Err( "error loading shader" )
195                }
196            };
197            util_gl::check_last_op();
198            compiled_shaders.push( s );
199        }
200        {
201            let i = self._shader_programs.len();
202            {
203                self._shader_collection.borrow_mut().put( i as u64, router::ShaderType::GLSL, util_gl::create_program_from_shaders( compiled_shaders.as_slice() ) as _, String::from("ads_program") ).is_ok();
204            }
205            let shader_program = self._shader_collection.borrow_mut().get( i as u64 ).unwrap();
206            unsafe {
207                gl::UseProgram( shader_program as _ );
208                self._current_shader_program = i as u64;
209                gl::BindFramebuffer( gl::FRAMEBUFFER, 0 );
210                gl::Enable( gl::DEPTH_TEST );
211            }
212            self._shader_programs.push( shader_program as u64 );
213            {
214                self._shaders_compiled.append( & mut compiled_shaders );
215            }
216            Ok( i as u64 )
217        }
218    }
219    pub fn load_texture( & mut self, description: String, image: &[u8], w: usize, h: usize ) -> Result< ( u64 ), & 'static str > {
220        let shader_program_internal = self._shader_collection.borrow_mut().get( self._current_shader_program ).unwrap();
221        let handle = match util_gl::load_texture( shader_program_internal as _, 0, image, w, h ) {
222            Ok( h ) => h,
223            _ => return Err( "loading texture failed" )
224        };
225        let h = match self._texture_collection.add( router::ShaderType::GLSL, handle as _, description ) {
226            Ok( h ) => h,
227            Err( e ) => return Err( e ),
228        };
229        Ok( h )
230    }
231    pub fn create_draw_group( & mut self, prim_type: i_renderobj::RenderObjType ) -> Result< ( gl::types::GLuint, gl::types::GLuint, usize ), & 'static str > {
232        let mut obj_vao = 0;
233        let mut obj_vbo = 0;
234        unsafe {
235            gl::GenVertexArrays( 1, & mut obj_vao );
236            util_gl::check_last_op();
237            gl::GenBuffers( 1, & mut obj_vbo );
238            util_gl::check_last_op();
239        }
240        
241        let draw_group = match prim_type {
242            i_renderobj::RenderObjType::TRI => renderdevice_gl::RenderDrawGroup::init_with_default_format_triangle( obj_vao as _, obj_vbo as _ ),
243            i_renderobj::RenderObjType::POINT => renderdevice_gl::RenderDrawGroup::init_with_default_format_point( obj_vao as _, obj_vbo as _ ),
244            _ => return Err("unsupported primitive type for draw group detected")
245        };
246        // let mut draw_group = renderdevice_gl::RenderDrawGroup::init_with_default_format( obj_vao as _, obj_vbo as _ );
247        self._draw_groups.borrow_mut().push( draw_group );
248        Ok( ( obj_vao, obj_vbo, self._draw_groups.borrow_mut().len() - 1) )
249    }
250    #[allow(unused)]
251    pub fn add_obj( & mut self, name: &str, e: i_ele::Ele ) -> Result< ( usize ), & 'static str > {
252        
253        let index = self._objs.len();
254        self._objs.push( e );
255
256        let t0 = Local::now();
257        
258        //load component data
259        match self._objs[index].update_components_from_impl() {
260            Err( e ) => { return Err( e ) },
261            _ => (),
262        }
263
264        let t1 = Local::now();
265
266        let t_delta = t1.signed_duration_since(t0).num_milliseconds() as f64;
267
268        debug!( "t_update_components_from_impl: {} ms", t_delta );
269
270        //detect command to flush and process all data in buffer
271        let mut trigger_to_process_objs = false;
272        let mut group_id = 0;
273
274        // println!( "component numbers: {}", self._objs.borrow_mut()[index]._components.len() );
275        
276        for j in self._objs[index]._components.iter() {
277            match j.as_any().downcast_ref::< i_component::ComponentDrawGroupDispatch >() {
278                Some( o ) => {
279                    trace!("detected trigger for draw group dispatch");
280                    trigger_to_process_objs = true;
281                    group_id = o._group_id;
282                },
283                None => {},
284            }
285        }
286        
287        if trigger_to_process_objs {
288
289            let t2 = Local::now();
290            
291            Renderer::process_objs( self, group_id )?;
292
293            let t3 = Local::now();
294
295            let t_delta = t3.signed_duration_since(t2).num_milliseconds() as f64;
296
297            debug!( "t_process_objs flush: {} ms", t_delta );
298        }
299
300        Ok( self._objs.len() )
301    }
302    pub fn process_objs( renderer: & mut Renderer, group_index: usize ) -> Result< (), & 'static str > {        
303
304        let drained = renderer._objs.drain(..).collect::<Vec<_>>();
305
306        for i in drained {
307
308            for j in i._components {
309
310                match j.as_any().downcast_ref::< i_component::ComponentRenderBuffer >() {
311                    Some( o ) => {
312                        trace!("buffer flushed");
313                        match o.flush_into_render_device( & mut renderer._draw_groups.get_mut()[ group_index ] ) {
314                            Err( e ) => return Err( e ),
315                            _ => { continue; },
316                        }
317                    },
318                    None => (),
319                }
320                match j.as_any().downcast_ref::< i_component::ComponentRenderUniform >() {
321                    Some( o ) => {
322                        trace!("uniform flushed");
323                        let shader_program = renderer._shader_collection.borrow_mut().get( renderer._current_shader_program ).unwrap();
324                        match o.flush_into_uniform_collection( shader_program, & mut renderer._uniforms.borrow_mut() ) {
325                            Err( e ) => return Err( e ),
326                            _ => { continue; },
327                        }
328                    },
329                    None => (),
330                }
331                match j.as_any().downcast_ref::< i_component::ComponentDrawGroupClear >() {
332                    Some( o ) => {
333                        trace!("draw group clear");
334                        renderer.reset_draw_group_data( &[ o._group_id ] ).is_ok();
335                        continue;
336                    },
337                    None => (),
338                }
339                match j.as_any().downcast_ref::< i_component::ComponentDrawGroupBind >() {
340                    Some( o ) => {
341                        trace!("draw group bind");
342                        renderer.bind_draw_group_data( &[ o._group_id ] ).is_ok();
343                        continue;
344                    },
345                    None => (),
346                }
347                match j.as_any().downcast_ref::< i_component::ComponentDrawGroupDependentUniforms >() {
348                    Some( o ) => {
349                        trace!("draw group dependent uniforms");
350                        renderer.set_draw_group_uniforms( o._group_id, &o._uniform_ids[..] ).is_ok();
351                        continue;
352                    },
353                    None => (),
354                }
355                match j.as_any().downcast_ref::< i_component::ComponentDrawGroupDispatch >() {
356                    Some( o ) => {
357                        trace!("draw group dispatch");
358                        let renderer_immut : & Renderer = & * renderer;
359                        Renderer::drawcall_draw_group( renderer_immut, &[ o._group_id ] ).is_ok();
360                        continue;
361                    },
362                    None => (),
363                }
364                return Err( &"unmatching render command" );
365            }
366        }
367
368        assert_eq!(renderer._objs.len(), 0 );
369
370        Ok( () )
371    }
372    pub fn reset_draw_group_data( & self, group_indices: &[ usize ] ) -> Result< (), & 'static str > {
373        for &i in group_indices {
374            if i >= self._draw_groups.borrow_mut().len() {
375                return Err( "object index out of range" )
376            }
377            let mut dg = self._draw_groups.borrow_mut();
378            dg[ i ].clear_buff_data();
379        }
380        Ok( () )
381    }
382    pub fn bind_draw_group_data( & self, group_indices: &[ usize ] ) -> Result< (), & 'static str > {
383        for &i in group_indices {
384            if i >= self._draw_groups.borrow_mut().len() {
385                return Err( "object index out of range" )
386            }
387            match self._draw_groups.borrow_mut()[ i ].bind_buffer() {
388                Err( e ) => return Err( e ),
389                _ => (),
390            }
391        }
392        Ok( () )
393    }
394    pub fn drawcall_draw_group( renderer: & Renderer, group_indices: &[ usize ] ) -> Result< (), & 'static str > {
395        for &i in group_indices {
396            for uniform_group in renderer._draw_group_uniforms.borrow()[i].iter() {
397                trace!("dispatching uniform group: {}", *uniform_group );
398                if i >= renderer._draw_groups.borrow().len() {
399                    return Err( "object index out of range" )
400                }
401                match renderer._uniforms.borrow_mut().send_uniform_group( *uniform_group ){
402                    Err(e) => return Err(e),
403                    _ => ()
404                }
405                match renderer._draw_groups.borrow_mut()[ i ].draw_buffer_all() {
406                    Err( e ) => return Err( e ),
407                    _ => (),
408                }
409            }
410        }
411        Ok( () )
412    }
413    pub fn add_renderpass< T > ( & mut self, name: String, rp: T ) -> usize
414    where T: i_renderpass::IRenderPass + 'static {
415        let i = self._rp.len();
416        self._map_string_to_rp.insert( name, i );
417        self._rp.push( Box::new( rp ) );
418        i
419    }
420    pub fn get_renderpass( & mut self, name: String ) -> Option< & mut i_renderpass::IRenderPass > {
421        match self._map_string_to_rp.get( &name ){
422            None => None,
423            Some( o ) => {
424                Some( self._rp[*o].deref_mut() )
425            }
426        }
427    }
428    // pub fn uniforms_ref( & mut self ) -> & mut renderdevice_gl::RenderUniformCollection {
429    //     & mut self._uniforms.get_mut()
430    // }
431    pub fn add_draw_group_uniforms( & self, draw_group: usize, uniform_group: &[u64] ) -> Result< (), & 'static str > {
432        if self._draw_group_uniforms.borrow_mut().len() <= draw_group {
433            self._draw_group_uniforms.borrow_mut().resize( draw_group + 1, vec![] );
434        }
435        self._draw_group_uniforms.borrow_mut()[ draw_group ].extend_from_slice( uniform_group );
436        Ok( () )
437    }
438    pub fn set_draw_group_uniforms( & self, draw_group: usize, uniform_group: &[u64] ) -> Result< (), & 'static str > {
439        if self._draw_group_uniforms.borrow_mut().len() <= draw_group {
440            self._draw_group_uniforms.borrow_mut().resize( draw_group + 1, vec![] );
441        }
442        self._draw_group_uniforms.borrow_mut()[ draw_group ].clear();
443        self._draw_group_uniforms.borrow_mut()[ draw_group ].extend_from_slice( uniform_group );
444        Ok( () )
445    }
446    pub fn clear_draw_group_uniforms( & self, draw_group: usize ) -> Result< (), & 'static str > {
447        if self._draw_group_uniforms.borrow_mut().len() <= draw_group {
448            return Err( "draw group out of range" )
449        }
450        self._draw_group_uniforms.borrow_mut()[ draw_group ].clear();
451        Ok( () )
452    }
453    pub fn get_shader_program( & mut self, id: u64 ) -> Option< i64 > {
454        self._shader_collection.borrow_mut().get( id )
455    }
456}
457