Kaynağa Gözat

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 yıl önce
ebeveyn
işleme
c7f1518897
4 değiştirilmiş dosya ile 51 ekleme ve 25 silme
  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 Dosyayı Görüntüle

@@ -10,9 +10,20 @@ pub(crate) mod gl {
10 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 22
 #[derive(Clone)]
14 23
 pub struct Context {
15 24
     pub(crate) gl: gl::Gl,
25
+    active_texture_unit: TextureUnit,
26
+    next_free_texture_unit: TextureUnit,
16 27
 }
17 28
 
18 29
 impl ::std::fmt::Debug for Context {
@@ -34,7 +45,12 @@ macro_rules! check_gl_errors {
34 45
 impl Context {
35 46
     pub fn from_gl_window(window: &glutin::GlWindow) -> Context {
36 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 55
         // Initialize a vertex array object (VAO) if the current OpenGL context supports it. VAOs are
40 56
         // not OpenGL ES 2.0 compatible, but are required for rendering with a core context.
@@ -122,4 +138,23 @@ impl 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 Dosyayı Görüntüle

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

+ 2
- 19
src/program.rs Dosyayı Görüntüle

@@ -6,7 +6,7 @@ use std::io::BufReader;
6 6
 use std::io::Read;
7 7
 use std::mem;
8 8
 use std::path::Path;
9
-use texture::{Texture, TextureId};
9
+use texture::Texture;
10 10
 
11 11
 
12 12
 #[derive(Clone, Debug)]
@@ -14,8 +14,6 @@ pub struct Program {
14 14
     vert_obj: u32,
15 15
     frag_obj: u32,
16 16
     program_obj: u32,
17
-    tex_ids: Vec<TextureId>,
18
-    tex_locations: Vec<i32>,
19 17
 }
20 18
 
21 19
 #[derive(Clone, Debug)]
@@ -94,8 +92,6 @@ impl Program {
94 92
                 vert_obj,
95 93
                 frag_obj,
96 94
                 program_obj,
97
-                tex_ids: vec![],
98
-                tex_locations: vec![],
99 95
             })
100 96
         }
101 97
     }
@@ -106,8 +102,7 @@ impl Program {
106 102
             let tex_loc = cx.gl.GetUniformLocation(self.program_obj, uniform_name.as_ptr() as *const _);
107 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,18 +121,6 @@ impl Program {
126 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 124
     pub fn id(&self) -> ProgramId {
142 125
         ProgramId {
143 126
             id: self.program_obj,

+ 13
- 3
src/texture.rs Dosyayı Görüntüle

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