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 _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(); 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 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 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 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 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 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 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 let mut trigger_to_process_objs = false;
272 let mut group_id = 0;
273
274 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 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