浏览代码

Cache enabled vertex attributes, store params

* Cache the enabled vertex attributes in `Context`
* The vertex attribute parameters (offset, stride, ...) are not cached,
  yet
* Store parameters as `VertexAttribParams` in `Program`
Johannes Hofmann 7 年前
父节点
当前提交
5891c0de46
共有 6 个文件被更改,包括 207 次插入47 次删除
  1. 8
    1
      src/buffer.rs
  2. 47
    0
      src/context.rs
  3. 3
    2
      src/main.rs
  4. 43
    26
      src/map_view_gl.rs
  5. 56
    18
      src/program.rs
  6. 50
    0
      src/vertex_attrib.rs

+ 8
- 1
src/buffer.rs 查看文件

1
 use ::context;
1
 use ::context;
2
 use context::Context;
2
 use context::Context;
3
+use program::Program;
3
 use std::mem;
4
 use std::mem;
4
 
5
 
5
 
6
 
73
         self.num_elements = num_elements;
74
         self.num_elements = num_elements;
74
     }
75
     }
75
 
76
 
76
-    pub fn draw(&self, cx: &mut Context, mode: DrawMode) {
77
+    pub fn draw(&self, cx: &mut Context, program: &Program, mode: DrawMode) {
77
         cx.bind_buffer(self.buffer_id);
78
         cx.bind_buffer(self.buffer_id);
79
+        cx.use_program(program.id());
80
+        program.enable_vertex_attribs(cx);
78
         unsafe {
81
         unsafe {
79
             cx.gl.DrawArrays(
82
             cx.gl.DrawArrays(
80
                 mode.to_gl_enum(),
83
                 mode.to_gl_enum(),
82
                 self.num_elements as context::gl::types::GLsizei);
85
                 self.num_elements as context::gl::types::GLsizei);
83
         }
86
         }
84
     }
87
     }
88
+
89
+    pub fn id(&self) -> BufferId {
90
+        self.buffer_id
91
+    }
85
 }
92
 }

+ 47
- 0
src/context.rs 查看文件

2
 use glutin::GlContext;
2
 use glutin::GlContext;
3
 use glutin;
3
 use glutin;
4
 use program::ProgramId;
4
 use program::ProgramId;
5
+use std::collections::HashSet;
5
 use std::ffi::CStr;
6
 use std::ffi::CStr;
6
 use std::mem;
7
 use std::mem;
8
+use vertex_attrib::VertexAttribLoc;
7
 
9
 
8
 pub(crate) mod gl {
10
 pub(crate) mod gl {
9
     #![allow(unknown_lints)]
11
     #![allow(unknown_lints)]
28
     next_free_texture_unit: TextureUnit,
30
     next_free_texture_unit: TextureUnit,
29
     active_program: ProgramId,
31
     active_program: ProgramId,
30
     active_buffer: BufferId,
32
     active_buffer: BufferId,
33
+    active_attribs: HashSet<VertexAttribLoc>,
31
 }
34
 }
32
 
35
 
33
 impl ::std::fmt::Debug for Context {
36
 impl ::std::fmt::Debug for Context {
56
             next_free_texture_unit: TextureUnit(0),
59
             next_free_texture_unit: TextureUnit(0),
57
             active_program: ProgramId::invalid(),
60
             active_program: ProgramId::invalid(),
58
             active_buffer: BufferId::invalid(),
61
             active_buffer: BufferId::invalid(),
62
+            active_attribs: HashSet::new(),
59
         };
63
         };
60
 
64
 
61
         // Initialize a vertex array object (VAO) if the current OpenGL context supports it. VAOs are
65
         // Initialize a vertex array object (VAO) if the current OpenGL context supports it. VAOs are
181
             self.active_buffer = buf;
185
             self.active_buffer = buf;
182
         }
186
         }
183
     }
187
     }
188
+
189
+    /// Enable all vertex attributes given by their location and disable all other vertex
190
+    /// attributes.
191
+    //TODO group attribs by program
192
+    pub fn enable_vertex_attribs(&mut self, attribs: &[VertexAttribLoc]) {
193
+        let new_set: HashSet<_> = attribs.iter().cloned().collect();
194
+
195
+        unsafe {
196
+            for old_attrib in self.active_attribs.difference(&new_set) {
197
+                self.gl.DisableVertexAttribArray(old_attrib.index());
198
+            }
199
+
200
+            for new_attrib in new_set.difference(&self.active_attribs) {
201
+                self.gl.EnableVertexAttribArray(new_attrib.index());
202
+            }
203
+        }
204
+
205
+        self.active_attribs = new_set;
206
+    }
207
+
208
+    pub fn enable_vertex_attrib(&mut self, attrib: VertexAttribLoc) {
209
+        if !self.active_attribs.contains(&attrib) {
210
+            unsafe {
211
+                self.gl.EnableVertexAttribArray(attrib.index());
212
+            }
213
+            self.active_attribs.insert(attrib);
214
+        }
215
+    }
216
+
217
+    /// Print status of vector attributes.
218
+    pub fn debug_attribs(&self) {
219
+        unsafe {
220
+            let mut max_attribs = 0i32;
221
+            self.gl.GetIntegerv(gl::MAX_VERTEX_ATTRIBS, &mut max_attribs as *mut _);
222
+
223
+            for index in 0..(max_attribs as u32) {
224
+                let mut enabled = 0i32;
225
+                self.gl.GetVertexAttribiv(index, gl::VERTEX_ATTRIB_ARRAY_ENABLED, &mut enabled as *mut _);
226
+                let enabled: bool = enabled != 0;
227
+                println!("attribute {} enabled: {}", index, enabled);
228
+            }
229
+        }
230
+    }
184
 }
231
 }

+ 3
- 2
src/main.rs 查看文件

14
 extern crate toml;
14
 extern crate toml;
15
 
15
 
16
 pub mod args;
16
 pub mod args;
17
-#[macro_use]
18
-pub mod context;
19
 pub mod buffer;
17
 pub mod buffer;
20
 pub mod config;
18
 pub mod config;
19
+#[macro_use]
20
+pub mod context;
21
 pub mod coord;
21
 pub mod coord;
22
 pub mod map_view;
22
 pub mod map_view;
23
 pub mod map_view_gl;
23
 pub mod map_view_gl;
29
 pub mod tile_loader;
29
 pub mod tile_loader;
30
 pub mod tile_source;
30
 pub mod tile_source;
31
 pub mod url_template;
31
 pub mod url_template;
32
+pub mod vertex_attrib;
32
 
33
 
33
 use coord::ScreenCoord;
34
 use coord::ScreenCoord;
34
 use glutin::{ControlFlow, ElementState, Event, GlContext, MouseButton, MouseScrollDelta, VirtualKeyCode, WindowEvent};
35
 use glutin::{ControlFlow, ElementState, Event, GlContext, MouseButton, MouseScrollDelta, VirtualKeyCode, WindowEvent};

+ 43
- 26
src/map_view_gl.rs 查看文件

5
 use map_view::MapView;
5
 use map_view::MapView;
6
 use program::Program;
6
 use program::Program;
7
 use texture::{Texture, TextureFormat};
7
 use texture::{Texture, TextureFormat};
8
-use tile_cache::TileCache;
9
 use tile_atlas::TileAtlas;
8
 use tile_atlas::TileAtlas;
9
+use tile_cache::TileCache;
10
 use tile_source::TileSource;
10
 use tile_source::TileSource;
11
+use vertex_attrib::VertexAttribParams;
11
 
12
 
12
 
13
 
13
 const MIN_ZOOM_LEVEL: f64 = 0.0;
14
 const MIN_ZOOM_LEVEL: f64 = 0.0;
15
 
16
 
16
 #[derive(Debug)]
17
 #[derive(Debug)]
17
 pub struct MapViewGl {
18
 pub struct MapViewGl {
18
-    program: Program,
19
-    buf: Buffer,
20
-    viewport_size: (u32, u32),
21
     map_view: MapView,
19
     map_view: MapView,
20
+    viewport_size: (u32, u32),
21
+    tile_program: Program,
22
+    tile_buffer: Buffer,
22
     tile_cache: TileCache,
23
     tile_cache: TileCache,
23
     tile_atlas: TileAtlas,
24
     tile_atlas: TileAtlas,
24
 }
25
 }
33
         ) -> MapViewGl
34
         ) -> MapViewGl
34
         where F: Fn() + Sync + Send + 'static,
35
         where F: Fn() + Sync + Send + 'static,
35
     {
36
     {
36
-        let mut program = Program::new(
37
+        let tile_size = 256;
38
+
39
+        let mut map_view = MapView::with_filling_zoom(f64::from(initial_size.0), f64::from(initial_size.1), tile_size);
40
+
41
+        if map_view.zoom < MIN_ZOOM_LEVEL {
42
+            map_view.zoom = MIN_ZOOM_LEVEL;
43
+        }
44
+
45
+        let tile_buffer = Buffer::new(cx, &[], 0);
46
+        check_gl_errors!(cx);
47
+        cx.bind_buffer(tile_buffer.id());
48
+
49
+        let mut tile_program = Program::new(
37
             cx,
50
             cx,
38
             include_bytes!("../shader/map.vert"),
51
             include_bytes!("../shader/map.vert"),
39
             include_bytes!("../shader/map.frag"),
52
             include_bytes!("../shader/map.frag"),
40
         ).unwrap();
53
         ).unwrap();
41
         check_gl_errors!(cx);
54
         check_gl_errors!(cx);
42
 
55
 
43
-        let tile_size = 256;
44
-
45
         let atlas_size = {
56
         let atlas_size = {
46
             let default_size = 2048;
57
             let default_size = 2048;
47
             let max_size = cx.max_texture_size() as u32;
58
             let max_size = cx.max_texture_size() as u32;
56
             }
67
             }
57
         };
68
         };
58
 
69
 
59
-        let tex = Texture::empty(cx, atlas_size, atlas_size, TextureFormat::Rgb8);
60
-        check_gl_errors!(cx);
61
-
62
-        let buf = Buffer::new(cx, &[], 0);
70
+        let atlas_tex = Texture::empty(cx, atlas_size, atlas_size, TextureFormat::Rgb8);
63
         check_gl_errors!(cx);
71
         check_gl_errors!(cx);
64
 
72
 
65
-        program.add_texture(cx, &tex, CStr::from_bytes_with_nul(b"tex_map\0").unwrap());
73
+        tile_program.add_texture(cx, &atlas_tex, CStr::from_bytes_with_nul(b"tex_map\0").unwrap());
66
         check_gl_errors!(cx);
74
         check_gl_errors!(cx);
67
 
75
 
68
-        program.add_attribute(cx, CStr::from_bytes_with_nul(b"position\0").unwrap(), 2, 8, 0);
69
-        program.add_attribute(cx, CStr::from_bytes_with_nul(b"tex_coord\0").unwrap(), 2, 8, 2);
70
-        program.add_attribute(cx, CStr::from_bytes_with_nul(b"tex_minmax\0").unwrap(), 4, 8, 4);
76
+        tile_program.add_attribute(
77
+            cx,
78
+            CStr::from_bytes_with_nul(b"position\0").unwrap(),
79
+            &VertexAttribParams::new(2, 8, 0)
80
+        );
81
+        tile_program.add_attribute(
82
+            cx,
83
+            CStr::from_bytes_with_nul(b"tex_coord\0").unwrap(),
84
+            &VertexAttribParams::new(2, 8, 2)
85
+        );
86
+        tile_program.add_attribute(
87
+            cx,
88
+            CStr::from_bytes_with_nul(b"tex_minmax\0").unwrap(),
89
+            &VertexAttribParams::new(4, 8, 4)
90
+        );
71
         check_gl_errors!(cx);
91
         check_gl_errors!(cx);
72
 
92
 
73
-        let mut map_view = MapView::with_filling_zoom(f64::from(initial_size.0), f64::from(initial_size.1), tile_size);
74
-
75
-        if map_view.zoom < MIN_ZOOM_LEVEL {
76
-            map_view.zoom = MIN_ZOOM_LEVEL;
77
-        }
93
+        tile_program.enable_vertex_attribs(cx);
94
+        tile_program.set_vertex_attribs(cx, &tile_buffer);
78
 
95
 
79
         MapViewGl {
96
         MapViewGl {
80
-            program,
81
-            buf,
82
-            viewport_size: initial_size,
83
             map_view,
97
             map_view,
98
+            viewport_size: initial_size,
99
+            tile_program,
100
+            tile_buffer,
84
             tile_cache: TileCache::new(move |_tile| update_func(), use_network),
101
             tile_cache: TileCache::new(move |_tile| update_func(), use_network),
85
-            tile_atlas: TileAtlas::new(cx, tex, 256, use_async),
102
+            tile_atlas: TileAtlas::new(cx, atlas_tex, 256, use_async),
86
         }
103
         }
87
     }
104
     }
88
 
105
 
176
                 vertex_data.extend(&minmax);
193
                 vertex_data.extend(&minmax);
177
             }
194
             }
178
 
195
 
179
-            self.buf.set_data(cx, &vertex_data, vertex_data.len() / 4);
180
-            self.buf.draw(cx, DrawMode::Triangles);
196
+            self.tile_buffer.set_data(cx, &vertex_data, vertex_data.len() / 4);
197
+            self.tile_buffer.draw(cx, &self.tile_program, DrawMode::Triangles);
181
 
198
 
182
             num_draws += 1;
199
             num_draws += 1;
183
 
200
 

+ 56
- 18
src/program.rs 查看文件

1
 use ::context;
1
 use ::context;
2
+use buffer::Buffer;
2
 use context::Context;
3
 use context::Context;
3
 use std::ffi::CStr;
4
 use std::ffi::CStr;
4
 use std::fs::File;
5
 use std::fs::File;
7
 use std::mem;
8
 use std::mem;
8
 use std::path::Path;
9
 use std::path::Path;
9
 use texture::Texture;
10
 use texture::Texture;
11
+use vertex_attrib::{VertexAttribLoc, VertexAttribParams};
10
 
12
 
11
 
13
 
12
 #[derive(Clone, Debug)]
14
 #[derive(Clone, Debug)]
14
     vert_obj: u32,
16
     vert_obj: u32,
15
     frag_obj: u32,
17
     frag_obj: u32,
16
     program_id: ProgramId,
18
     program_id: ProgramId,
19
+    attrib_locs: Vec<VertexAttribLoc>,
20
+    attrib_params: Vec<VertexAttribParams>,
17
 }
21
 }
18
 
22
 
19
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
23
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
33
 }
37
 }
34
 
38
 
35
 impl Program {
39
 impl Program {
36
-    pub fn from_paths<P: AsRef<Path>>(cx: &mut Context, vert_path: P, frag_path: P) -> Result<Program, String> {
40
+    pub fn from_paths<P: AsRef<Path>>(
41
+        cx: &mut Context,
42
+        vert_path: P,
43
+        frag_path: P,
44
+    ) -> Result<Program, String> {
37
         let vert_src = {
45
         let vert_src = {
38
             let file = File::open(&vert_path)
46
             let file = File::open(&vert_path)
39
                 .map_err(|e| format!("{}", e))?;
47
                 .map_err(|e| format!("{}", e))?;
57
         Self::new(cx, &vert_src, &frag_src)
65
         Self::new(cx, &vert_src, &frag_src)
58
     }
66
     }
59
 
67
 
60
-    pub fn new(cx: &mut Context, vert_src: &[u8], frag_src: &[u8]) -> Result<Program, String> {
68
+    pub fn new(
69
+        cx: &mut Context,
70
+        vert_src: &[u8],
71
+        frag_src: &[u8],
72
+    ) -> Result<Program, String> {
61
         unsafe {
73
         unsafe {
62
             let vert_obj = {
74
             let vert_obj = {
63
                 let vert_obj = cx.gl.CreateShader(context::gl::VERTEX_SHADER);
75
                 let vert_obj = cx.gl.CreateShader(context::gl::VERTEX_SHADER);
100
             cx.use_program(program_id);
112
             cx.use_program(program_id);
101
             check_gl_errors!(cx);
113
             check_gl_errors!(cx);
102
 
114
 
103
-            Ok(Program {
104
-                vert_obj,
105
-                frag_obj,
106
-                program_id,
107
-            })
115
+            Ok(
116
+                Program {
117
+                    vert_obj,
118
+                    frag_obj,
119
+                    program_id,
120
+                    attrib_locs: vec![],
121
+                    attrib_params: vec![],
122
+                }
123
+            )
108
         }
124
         }
109
     }
125
     }
110
 
126
 
119
         }
135
         }
120
     }
136
     }
121
 
137
 
122
-    pub fn add_attribute(&mut self, cx: &mut Context, name: &CStr, number_components: u32, stride: usize, offset: usize) {
138
+    //TODO rename function or integrate into new()
139
+    pub fn add_attribute(
140
+        &mut self,
141
+        cx: &mut Context,
142
+        name: &CStr,
143
+        params: &VertexAttribParams,
144
+    ) {
123
         cx.use_program(self.program_id);
145
         cx.use_program(self.program_id);
124
-        unsafe {
125
-            let attrib_id = cx.gl.GetAttribLocation(self.program_id.index(), name.as_ptr() as *const _);
126
-            cx.gl.VertexAttribPointer(
127
-                attrib_id as u32,
128
-                number_components as i32, // size
129
-                context::gl::FLOAT, // type
130
-                0, // normalized
131
-                (stride * mem::size_of::<f32>()) as context::gl::types::GLsizei,
132
-                (offset * mem::size_of::<f32>()) as *const () as *const _);
133
-            cx.gl.EnableVertexAttribArray(attrib_id as u32);
146
+
147
+        let attrib_loc = unsafe {
148
+            cx.gl.GetAttribLocation(self.program_id.index(), name.as_ptr() as *const _)
149
+        };
150
+        if attrib_loc < 0 {
151
+            panic!("Attribute location not found: {:?}", name);
134
         }
152
         }
153
+        let attrib_loc = VertexAttribLoc::new(attrib_loc as u32);
135
         check_gl_errors!(cx);
154
         check_gl_errors!(cx);
155
+
156
+        self.attrib_locs.push(attrib_loc);
157
+        self.attrib_params.push(params.clone());
158
+    }
159
+
160
+    pub fn enable_vertex_attribs(&self, cx: &mut Context) {
161
+        cx.enable_vertex_attribs(&self.attrib_locs)
162
+    }
163
+
164
+    //TODO use separate buffer for each attribute
165
+    pub fn set_vertex_attribs(
166
+        &self,
167
+        cx: &mut Context,
168
+        buffer: &Buffer,
169
+    ) {
170
+        cx.bind_buffer(buffer.id());
171
+        for (params, loc) in self.attrib_params.iter().zip(self.attrib_locs.iter()) {
172
+            params.set(cx, *loc);
173
+        }
136
     }
174
     }
137
 
175
 
138
     pub fn id(&self) -> ProgramId {
176
     pub fn id(&self) -> ProgramId {

+ 50
- 0
src/vertex_attrib.rs 查看文件

1
+use ::context;
2
+use context::Context;
3
+use std::mem;
4
+
5
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
6
+pub struct VertexAttribLoc(u32);
7
+
8
+impl VertexAttribLoc {
9
+    pub fn new(location: u32) -> VertexAttribLoc {
10
+        VertexAttribLoc(location)
11
+    }
12
+
13
+    pub fn index(&self) -> u32 {
14
+        self.0
15
+    }
16
+}
17
+
18
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
19
+pub struct VertexAttribParams {
20
+    pub number_components: u32,
21
+    pub stride: usize,
22
+    pub offset: usize,
23
+}
24
+
25
+impl VertexAttribParams {
26
+    pub fn new(
27
+        number_components: u32,
28
+        stride: usize,
29
+        offset: usize,
30
+    ) -> VertexAttribParams {
31
+        VertexAttribParams {
32
+            number_components,
33
+            stride,
34
+            offset,
35
+        }
36
+    }
37
+
38
+    pub fn set(&self, cx: &mut Context, loc: VertexAttribLoc) {
39
+        unsafe {
40
+            cx.gl.VertexAttribPointer(
41
+                loc.0,
42
+                self.number_components as i32, // size
43
+                context::gl::FLOAT, // type
44
+                0, // normalized
45
+                (self.stride * mem::size_of::<f32>()) as context::gl::types::GLsizei,
46
+                (self.offset * mem::size_of::<f32>()) as *const () as *const _,
47
+            );
48
+        }
49
+    }
50
+}