浏览代码

Cache active texture unit, assign unit to texture

Each Texture is bound to a unique texture unit (glBindTexture is called
only once). Context keeps track of the current active texture unit and
reduces the number of glActiveTexture calls to a minimum.
Johannes Hofmann 7 年前
父节点
当前提交
c7f1518897
共有 4 个文件被更改,包括 51 次插入25 次删除
  1. 36
    1
      src/context.rs
  2. 0
    2
      src/map_view_gl.rs
  3. 2
    19
      src/program.rs
  4. 13
    3
      src/texture.rs

+ 36
- 1
src/context.rs 查看文件

10
     include!(concat!(env!("OUT_DIR"), "/gles_bindings.rs"));
10
     include!(concat!(env!("OUT_DIR"), "/gles_bindings.rs"));
11
 }
11
 }
12
 
12
 
13
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14
+pub struct TextureUnit(u32);
15
+
16
+impl TextureUnit {
17
+    pub fn index(&self) -> u32 {
18
+        self.0
19
+    }
20
+}
21
+
13
 #[derive(Clone)]
22
 #[derive(Clone)]
14
 pub struct Context {
23
 pub struct Context {
15
     pub(crate) gl: gl::Gl,
24
     pub(crate) gl: gl::Gl,
25
+    active_texture_unit: TextureUnit,
26
+    next_free_texture_unit: TextureUnit,
16
 }
27
 }
17
 
28
 
18
 impl ::std::fmt::Debug for Context {
29
 impl ::std::fmt::Debug for Context {
34
 impl Context {
45
 impl Context {
35
     pub fn from_gl_window(window: &glutin::GlWindow) -> Context {
46
     pub fn from_gl_window(window: &glutin::GlWindow) -> Context {
36
         let gl = gl::Gl::load_with(|ptr| window.get_proc_address(ptr) as *const _);
47
         let gl = gl::Gl::load_with(|ptr| window.get_proc_address(ptr) as *const _);
37
-        let cx = Context { gl };
48
+        let cx = Context {
49
+            gl,
50
+            /// Initial active texture unit is supposed to be GL_TEXTURE0
51
+            active_texture_unit: TextureUnit(0),
52
+            next_free_texture_unit: TextureUnit(0),
53
+        };
38
 
54
 
39
         // Initialize a vertex array object (VAO) if the current OpenGL context supports it. VAOs are
55
         // Initialize a vertex array object (VAO) if the current OpenGL context supports it. VAOs are
40
         // not OpenGL ES 2.0 compatible, but are required for rendering with a core context.
56
         // not OpenGL ES 2.0 compatible, but are required for rendering with a core context.
122
             );
138
             );
123
         }
139
         }
124
     }
140
     }
141
+
142
+    pub fn set_active_texture_unit(&mut self, unit: TextureUnit) {
143
+        if unit != self.active_texture_unit {
144
+            unsafe {
145
+                self.gl.ActiveTexture(gl::TEXTURE0 + unit.0);
146
+            }
147
+        }
148
+        self.active_texture_unit = unit;
149
+    }
150
+
151
+    pub fn occupy_free_texture_unit(&mut self) -> TextureUnit {
152
+        let tu = self.next_free_texture_unit;
153
+
154
+        //TODO check against max number of texture units
155
+        //TODO add a way to free texture units
156
+        self.next_free_texture_unit = TextureUnit(self.next_free_texture_unit.0 + 1);
157
+
158
+        tu
159
+    }
125
 }
160
 }

+ 0
- 2
src/map_view_gl.rs 查看文件

70
         program.add_attribute(cx, CStr::from_bytes_with_nul(b"tex_minmax\0").unwrap(), 4, 8, 4);
70
         program.add_attribute(cx, CStr::from_bytes_with_nul(b"tex_minmax\0").unwrap(), 4, 8, 4);
71
         check_gl_errors!(cx);
71
         check_gl_errors!(cx);
72
 
72
 
73
-        program.before_render(cx);
74
-
75
         let mut map_view = MapView::with_filling_zoom(f64::from(initial_size.0), f64::from(initial_size.1), tile_size);
73
         let mut map_view = MapView::with_filling_zoom(f64::from(initial_size.0), f64::from(initial_size.1), tile_size);
76
 
74
 
77
         if map_view.zoom < MIN_ZOOM_LEVEL {
75
         if map_view.zoom < MIN_ZOOM_LEVEL {

+ 2
- 19
src/program.rs 查看文件

6
 use std::io::Read;
6
 use std::io::Read;
7
 use std::mem;
7
 use std::mem;
8
 use std::path::Path;
8
 use std::path::Path;
9
-use texture::{Texture, TextureId};
9
+use texture::Texture;
10
 
10
 
11
 
11
 
12
 #[derive(Clone, Debug)]
12
 #[derive(Clone, Debug)]
14
     vert_obj: u32,
14
     vert_obj: u32,
15
     frag_obj: u32,
15
     frag_obj: u32,
16
     program_obj: u32,
16
     program_obj: u32,
17
-    tex_ids: Vec<TextureId>,
18
-    tex_locations: Vec<i32>,
19
 }
17
 }
20
 
18
 
21
 #[derive(Clone, Debug)]
19
 #[derive(Clone, Debug)]
94
                 vert_obj,
92
                 vert_obj,
95
                 frag_obj,
93
                 frag_obj,
96
                 program_obj,
94
                 program_obj,
97
-                tex_ids: vec![],
98
-                tex_locations: vec![],
99
             })
95
             })
100
         }
96
         }
101
     }
97
     }
106
             let tex_loc = cx.gl.GetUniformLocation(self.program_obj, uniform_name.as_ptr() as *const _);
102
             let tex_loc = cx.gl.GetUniformLocation(self.program_obj, uniform_name.as_ptr() as *const _);
107
             check_gl_errors!(cx);
103
             check_gl_errors!(cx);
108
 
104
 
109
-            self.tex_ids.push(texture.id());
110
-            self.tex_locations.push(tex_loc);
105
+            cx.gl.Uniform1i(tex_loc, texture.unit().index() as i32);
111
         }
106
         }
112
     }
107
     }
113
 
108
 
126
         check_gl_errors!(cx);
121
         check_gl_errors!(cx);
127
     }
122
     }
128
 
123
 
129
-    pub fn before_render(&self, cx: &mut Context) {
130
-        unsafe {
131
-            //cx.gl.UseProgram(self.program_obj);
132
-            //TODO check max texture number
133
-            for (i, (tex_id, &tex_loc)) in self.tex_ids.iter().zip(&self.tex_locations).enumerate() {
134
-                cx.gl.ActiveTexture(context::gl::TEXTURE0 + i as u32);
135
-                cx.gl.BindTexture(context::gl::TEXTURE_2D, tex_id.id);
136
-                cx.gl.Uniform1i(tex_loc, i as i32);
137
-            }
138
-        }
139
-    }
140
-
141
     pub fn id(&self) -> ProgramId {
124
     pub fn id(&self) -> ProgramId {
142
         ProgramId {
125
         ProgramId {
143
             id: self.program_obj,
126
             id: self.program_obj,

+ 13
- 3
src/texture.rs 查看文件

1
 use ::context;
1
 use ::context;
2
 use ::image;
2
 use ::image;
3
-use context::Context;
3
+use context::{Context, TextureUnit};
4
 use image::GenericImage;
4
 use image::GenericImage;
5
 use std::os::raw::c_void;
5
 use std::os::raw::c_void;
6
 
6
 
7
 #[derive(Clone, Debug)]
7
 #[derive(Clone, Debug)]
8
 pub struct Texture {
8
 pub struct Texture {
9
     texture_obj: u32,
9
     texture_obj: u32,
10
+    texture_unit: TextureUnit,
10
     width: u32,
11
     width: u32,
11
     height: u32,
12
     height: u32,
12
     format: TextureFormat,
13
     format: TextureFormat,
38
 
39
 
39
     fn from_ptr(cx: &mut Context, width: u32, height: u32, format: TextureFormat, data_ptr: *const c_void) -> Texture {
40
     fn from_ptr(cx: &mut Context, width: u32, height: u32, format: TextureFormat, data_ptr: *const c_void) -> Texture {
40
         let mut texture_obj = 0_u32;
41
         let mut texture_obj = 0_u32;
42
+
43
+        let texture_unit = cx.occupy_free_texture_unit();
44
+        cx.set_active_texture_unit(texture_unit);
45
+
41
         unsafe {
46
         unsafe {
42
             cx.gl.GenTextures(1, &mut texture_obj);
47
             cx.gl.GenTextures(1, &mut texture_obj);
43
             cx.gl.BindTexture(context::gl::TEXTURE_2D, texture_obj);
48
             cx.gl.BindTexture(context::gl::TEXTURE_2D, texture_obj);
61
 
66
 
62
         Texture {
67
         Texture {
63
             texture_obj,
68
             texture_obj,
69
+            texture_unit,
64
             width,
70
             width,
65
             height,
71
             height,
66
             format,
72
             format,
74
             _ => return,
80
             _ => return,
75
         };
81
         };
76
 
82
 
83
+        cx.set_active_texture_unit(self.texture_unit);
77
         unsafe {
84
         unsafe {
78
-            cx.gl.BindTexture(context::gl::TEXTURE_2D, self.texture_obj);
79
             cx.gl.TexSubImage2D(
85
             cx.gl.TexSubImage2D(
80
                 context::gl::TEXTURE_2D,
86
                 context::gl::TEXTURE_2D,
81
                 0, // level
87
                 0, // level
91
     }
97
     }
92
 
98
 
93
     pub fn resize(&mut self, cx: &mut Context, width: u32, height: u32) {
99
     pub fn resize(&mut self, cx: &mut Context, width: u32, height: u32) {
100
+        cx.set_active_texture_unit(self.texture_unit);
94
         unsafe {
101
         unsafe {
95
-            cx.gl.BindTexture(context::gl::TEXTURE_2D, self.texture_obj);
96
             cx.gl.TexImage2D(
102
             cx.gl.TexImage2D(
97
                 context::gl::TEXTURE_2D,
103
                 context::gl::TEXTURE_2D,
98
                 0, // level
104
                 0, // level
115
         }
121
         }
116
     }
122
     }
117
 
123
 
124
+    pub fn unit(&self) -> TextureUnit {
125
+        self.texture_unit
126
+    }
127
+
118
     pub fn width(&self) -> u32 {
128
     pub fn width(&self) -> u32 {
119
         self.width
129
         self.width
120
     }
130
     }