Quellcode durchsuchen

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 vor 7 Jahren
Ursprung
Commit
5891c0de46
6 geänderte Dateien mit 207 neuen und 47 gelöschten Zeilen
  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 Datei anzeigen

@@ -1,5 +1,6 @@
1 1
 use ::context;
2 2
 use context::Context;
3
+use program::Program;
3 4
 use std::mem;
4 5
 
5 6
 
@@ -73,8 +74,10 @@ impl Buffer {
73 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 78
         cx.bind_buffer(self.buffer_id);
79
+        cx.use_program(program.id());
80
+        program.enable_vertex_attribs(cx);
78 81
         unsafe {
79 82
             cx.gl.DrawArrays(
80 83
                 mode.to_gl_enum(),
@@ -82,4 +85,8 @@ impl Buffer {
82 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 Datei anzeigen

@@ -2,8 +2,10 @@ use buffer::BufferId;
2 2
 use glutin::GlContext;
3 3
 use glutin;
4 4
 use program::ProgramId;
5
+use std::collections::HashSet;
5 6
 use std::ffi::CStr;
6 7
 use std::mem;
8
+use vertex_attrib::VertexAttribLoc;
7 9
 
8 10
 pub(crate) mod gl {
9 11
     #![allow(unknown_lints)]
@@ -28,6 +30,7 @@ pub struct Context {
28 30
     next_free_texture_unit: TextureUnit,
29 31
     active_program: ProgramId,
30 32
     active_buffer: BufferId,
33
+    active_attribs: HashSet<VertexAttribLoc>,
31 34
 }
32 35
 
33 36
 impl ::std::fmt::Debug for Context {
@@ -56,6 +59,7 @@ impl Context {
56 59
             next_free_texture_unit: TextureUnit(0),
57 60
             active_program: ProgramId::invalid(),
58 61
             active_buffer: BufferId::invalid(),
62
+            active_attribs: HashSet::new(),
59 63
         };
60 64
 
61 65
         // Initialize a vertex array object (VAO) if the current OpenGL context supports it. VAOs are
@@ -181,4 +185,47 @@ impl Context {
181 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 Datei anzeigen

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

+ 43
- 26
src/map_view_gl.rs Datei anzeigen

@@ -5,9 +5,10 @@ use coord::{ScreenCoord, View};
5 5
 use map_view::MapView;
6 6
 use program::Program;
7 7
 use texture::{Texture, TextureFormat};
8
-use tile_cache::TileCache;
9 8
 use tile_atlas::TileAtlas;
9
+use tile_cache::TileCache;
10 10
 use tile_source::TileSource;
11
+use vertex_attrib::VertexAttribParams;
11 12
 
12 13
 
13 14
 const MIN_ZOOM_LEVEL: f64 = 0.0;
@@ -15,10 +16,10 @@ const MAX_ZOOM_LEVEL: f64 = 22.0;
15 16
 
16 17
 #[derive(Debug)]
17 18
 pub struct MapViewGl {
18
-    program: Program,
19
-    buf: Buffer,
20
-    viewport_size: (u32, u32),
21 19
     map_view: MapView,
20
+    viewport_size: (u32, u32),
21
+    tile_program: Program,
22
+    tile_buffer: Buffer,
22 23
     tile_cache: TileCache,
23 24
     tile_atlas: TileAtlas,
24 25
 }
@@ -33,15 +34,25 @@ impl MapViewGl {
33 34
         ) -> MapViewGl
34 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 50
             cx,
38 51
             include_bytes!("../shader/map.vert"),
39 52
             include_bytes!("../shader/map.frag"),
40 53
         ).unwrap();
41 54
         check_gl_errors!(cx);
42 55
 
43
-        let tile_size = 256;
44
-
45 56
         let atlas_size = {
46 57
             let default_size = 2048;
47 58
             let max_size = cx.max_texture_size() as u32;
@@ -56,33 +67,39 @@ impl MapViewGl {
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 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 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 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 96
         MapViewGl {
80
-            program,
81
-            buf,
82
-            viewport_size: initial_size,
83 97
             map_view,
98
+            viewport_size: initial_size,
99
+            tile_program,
100
+            tile_buffer,
84 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,8 +193,8 @@ impl MapViewGl {
176 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 199
             num_draws += 1;
183 200
 

+ 56
- 18
src/program.rs Datei anzeigen

@@ -1,4 +1,5 @@
1 1
 use ::context;
2
+use buffer::Buffer;
2 3
 use context::Context;
3 4
 use std::ffi::CStr;
4 5
 use std::fs::File;
@@ -7,6 +8,7 @@ use std::io::Read;
7 8
 use std::mem;
8 9
 use std::path::Path;
9 10
 use texture::Texture;
11
+use vertex_attrib::{VertexAttribLoc, VertexAttribParams};
10 12
 
11 13
 
12 14
 #[derive(Clone, Debug)]
@@ -14,6 +16,8 @@ pub struct Program {
14 16
     vert_obj: u32,
15 17
     frag_obj: u32,
16 18
     program_id: ProgramId,
19
+    attrib_locs: Vec<VertexAttribLoc>,
20
+    attrib_params: Vec<VertexAttribParams>,
17 21
 }
18 22
 
19 23
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -33,7 +37,11 @@ impl ProgramId {
33 37
 }
34 38
 
35 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 45
         let vert_src = {
38 46
             let file = File::open(&vert_path)
39 47
                 .map_err(|e| format!("{}", e))?;
@@ -57,7 +65,11 @@ impl Program {
57 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 73
         unsafe {
62 74
             let vert_obj = {
63 75
                 let vert_obj = cx.gl.CreateShader(context::gl::VERTEX_SHADER);
@@ -100,11 +112,15 @@ impl Program {
100 112
             cx.use_program(program_id);
101 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,20 +135,42 @@ impl Program {
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 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 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 176
     pub fn id(&self) -> ProgramId {

+ 50
- 0
src/vertex_attrib.rs Datei anzeigen

@@ -0,0 +1,50 @@
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
+}