Просмотр исходного кода

Restructure OpenGL context sharing

Program, Buffer, Texture... structs no longer store a reference to a
Context. Now it has to be passed explicitly to all methods that mutate
the OpenGL state. This enables caching the state and removing redundant
calls to gl* functions.
Johannes Hofmann 7 лет назад
Родитель
Сommit
38d1cf35e5
6 измененных файлов: 83 добавлений и 91 удалений
  1. 9
    11
      src/buffer.rs
  2. 7
    7
      src/main.rs
  3. 20
    21
      src/map_view_gl.rs
  4. 17
    19
      src/program.rs
  5. 12
    18
      src/texture.rs
  6. 18
    15
      src/tile_atlas.rs

+ 9
- 11
src/buffer.rs Просмотреть файл

@@ -4,8 +4,7 @@ use std::mem;
4 4
 
5 5
 
6 6
 #[derive(Clone, Debug)]
7
-pub struct Buffer<'a> {
8
-    cx: &'a Context,
7
+pub struct Buffer {
9 8
     buffer_obj: u32,
10 9
     num_elements: usize,
11 10
 }
@@ -27,8 +26,8 @@ impl DrawMode {
27 26
     }
28 27
 }
29 28
 
30
-impl<'a> Buffer<'a> {
31
-    pub fn new(cx: &'a Context, vertex_data: &[f32], num_elements: usize) -> Buffer<'a> {
29
+impl Buffer {
30
+    pub fn new(cx: &mut Context, vertex_data: &[f32], num_elements: usize) -> Buffer {
32 31
         let mut buffer_obj = 0_u32;
33 32
 
34 33
         unsafe {
@@ -41,15 +40,14 @@ impl<'a> Buffer<'a> {
41 40
         }
42 41
 
43 42
         Buffer {
44
-            cx,
45 43
             buffer_obj,
46 44
             num_elements,
47 45
         }
48 46
     }
49 47
 
50
-    pub fn set_data(&mut self, vertex_data: &[f32], num_elements: usize) {
48
+    pub fn set_data(&mut self, cx: &mut Context, vertex_data: &[f32], num_elements: usize) {
51 49
         unsafe {
52
-            self.cx.gl.BufferData(context::gl::ARRAY_BUFFER,
50
+            cx.gl.BufferData(context::gl::ARRAY_BUFFER,
53 51
                                   (vertex_data.len() * mem::size_of::<f32>()) as context::gl::types::GLsizeiptr,
54 52
                                   vertex_data.as_ptr() as *const _,
55 53
                                   context::gl::DYNAMIC_DRAW);
@@ -57,15 +55,15 @@ impl<'a> Buffer<'a> {
57 55
         self.num_elements = num_elements;
58 56
     }
59 57
 
60
-    pub fn bind(&self) {
58
+    pub fn bind(&self, cx: &mut Context) {
61 59
         unsafe {
62
-            self.cx.gl.BindBuffer(context::gl::ARRAY_BUFFER, self.buffer_obj);
60
+            cx.gl.BindBuffer(context::gl::ARRAY_BUFFER, self.buffer_obj);
63 61
         }
64 62
     }
65 63
 
66
-    pub fn draw(&self, mode: DrawMode) {
64
+    pub fn draw(&self, cx: &mut Context, mode: DrawMode) {
67 65
         unsafe {
68
-            self.cx.gl.DrawArrays(
66
+            cx.gl.DrawArrays(
69 67
                 mode.to_gl_enum(),
70 68
                 0,
71 69
                 self.num_elements as context::gl::types::GLsizei);

+ 7
- 7
src/main.rs Просмотреть файл

@@ -206,13 +206,13 @@ fn run() -> Result<(), Box<Error>> {
206 206
     let window = gl_window.window();
207 207
 
208 208
     let _ = unsafe { gl_window.make_current() };
209
-    let cx = context::Context::from_gl_window(&gl_window);
209
+    let mut cx = context::Context::from_gl_window(&gl_window);
210 210
 
211 211
     let mut map = {
212 212
         let proxy = events_loop.create_proxy();
213 213
 
214 214
         map_view_gl::MapViewGl::new(
215
-            &cx,
215
+            &mut cx,
216 216
             window.get_inner_size().unwrap(),
217 217
             move || { proxy.wakeup().unwrap(); },
218 218
             config.use_network(),
@@ -282,7 +282,7 @@ fn run() -> Result<(), Box<Error>> {
282 282
 
283 283
         if let Action::Resize(w, h) = action {
284 284
             gl_window.resize(w, h);
285
-            map.set_viewport_size(w, h);
285
+            map.set_viewport_size(&mut cx, w, h);
286 286
         }
287 287
 
288 288
         let redraw = match action {
@@ -297,13 +297,15 @@ fn run() -> Result<(), Box<Error>> {
297 297
             if !map.viewport_in_map() {
298 298
                 cx.clear_color((0.2, 0.2, 0.2, 1.0));
299 299
             }
300
-            let draw_result = map.draw(sources.current());
300
+            let draw_result = map.draw(&mut cx, sources.current());
301 301
 
302 302
             let draw_dur = draw_start.elapsed();
303 303
 
304 304
 
305 305
             let _ = gl_window.swap_buffers();
306 306
 
307
+            last_draw = Instant::now();
308
+
307 309
             //TODO increase atlas size earlier to avoid excessive copying to the GPU
308 310
             //TODO increase max tile cache size?
309 311
             if increase_atlas_size_possible {
@@ -312,12 +314,10 @@ fn run() -> Result<(), Box<Error>> {
312 314
                     Err(x) => x,
313 315
                 };
314 316
                 if draws > 1 {
315
-                    increase_atlas_size_possible = map.increase_atlas_size().is_ok();
317
+                    increase_atlas_size_possible = map.increase_atlas_size(&mut cx).is_ok();
316 318
                 }
317 319
             }
318 320
 
319
-            last_draw = Instant::now();
320
-
321 321
             debug!("draw: {} sec (est {} sec)", dur_to_sec(draw_dur), dur_to_sec(est_draw_dur));
322 322
 
323 323
             est_draw_dur = if draw_dur > est_draw_dur {

+ 20
- 21
src/map_view_gl.rs Просмотреть файл

@@ -14,19 +14,18 @@ const MIN_ZOOM_LEVEL: f64 = 0.0;
14 14
 const MAX_ZOOM_LEVEL: f64 = 22.0;
15 15
 
16 16
 #[derive(Debug)]
17
-pub struct MapViewGl<'a> {
18
-    cx: &'a Context,
19
-    program: Program<'a>,
20
-    buf: Buffer<'a>,
17
+pub struct MapViewGl {
18
+    program: Program,
19
+    buf: Buffer,
21 20
     viewport_size: (u32, u32),
22 21
     map_view: MapView,
23 22
     tile_cache: TileCache,
24
-    tile_atlas: TileAtlas<'a>,
23
+    tile_atlas: TileAtlas,
25 24
 }
26 25
 
27
-impl<'a> MapViewGl<'a> {
26
+impl MapViewGl {
28 27
     pub fn new<F>(
29
-        cx: &Context,
28
+        cx: &mut Context,
30 29
         initial_size: (u32, u32),
31 30
         update_func: F,
32 31
         use_network: bool,
@@ -63,15 +62,15 @@ impl<'a> MapViewGl<'a> {
63 62
         let buf = Buffer::new(cx, &[], 0);
64 63
         check_gl_errors!(cx);
65 64
 
66
-        program.add_texture(&tex, CStr::from_bytes_with_nul(b"tex_map\0").unwrap());
65
+        program.add_texture(cx, &tex, CStr::from_bytes_with_nul(b"tex_map\0").unwrap());
67 66
         check_gl_errors!(cx);
68 67
 
69
-        program.add_attribute(CStr::from_bytes_with_nul(b"position\0").unwrap(), 2, 8, 0);
70
-        program.add_attribute(CStr::from_bytes_with_nul(b"tex_coord\0").unwrap(), 2, 8, 2);
71
-        program.add_attribute(CStr::from_bytes_with_nul(b"tex_minmax\0").unwrap(), 4, 8, 4);
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);
72 71
         check_gl_errors!(cx);
73 72
 
74
-        program.before_render();
73
+        program.before_render(cx);
75 74
 
76 75
         let mut map_view = MapView::with_filling_zoom(f64::from(initial_size.0), f64::from(initial_size.1), tile_size);
77 76
 
@@ -80,34 +79,33 @@ impl<'a> MapViewGl<'a> {
80 79
         }
81 80
 
82 81
         MapViewGl {
83
-            cx,
84 82
             program,
85 83
             buf,
86 84
             viewport_size: initial_size,
87 85
             map_view,
88 86
             tile_cache: TileCache::new(move |_tile| update_func(), use_network),
89
-            tile_atlas: TileAtlas::new(tex, 256, use_async),
87
+            tile_atlas: TileAtlas::new(cx, tex, 256, use_async),
90 88
         }
91 89
     }
92 90
 
93
-    pub fn set_viewport_size(&mut self, width: u32, height: u32) {
91
+    pub fn set_viewport_size(&mut self, cx: &mut Context, width: u32, height: u32) {
94 92
         self.viewport_size = (width, height);
95 93
         self.map_view.set_size(f64::from(width), f64::from(height));
96
-        self.cx.set_viewport(0, 0, width, height);
94
+        cx.set_viewport(0, 0, width, height);
97 95
     }
98 96
 
99 97
     pub fn viewport_in_map(&self) -> bool {
100 98
         self.map_view.viewport_in_map()
101 99
     }
102 100
 
103
-    pub fn increase_atlas_size(&mut self) -> Result<(), ()> {
104
-        self.tile_atlas.double_texture_size()
101
+    pub fn increase_atlas_size(&mut self, cx: &mut Context) -> Result<(), ()> {
102
+        self.tile_atlas.double_texture_size(cx)
105 103
     }
106 104
 
107 105
     /// Returns `Err` when tile cache is too small for this view.
108 106
     /// Returns the number of OpenGL draw calls, which can be decreased to `1` by increasing the
109 107
     /// size of the tile atlas.
110
-    pub fn draw(&mut self, source: &TileSource) -> Result<usize, usize> {
108
+    pub fn draw(&mut self, cx: &mut Context, source: &TileSource) -> Result<usize, usize> {
111 109
         self.tile_cache.set_view_location(View {
112 110
             source_id: source.id(),
113 111
             zoom: self.map_view.tile_zoom(),
@@ -122,6 +120,7 @@ impl<'a> MapViewGl<'a> {
122 120
         loop {
123 121
             let (textured_visible_tiles, remainder_opt, used_tiles) = {
124 122
                 self.tile_atlas.textured_visible_tiles(
123
+                    cx,
125 124
                     remainder,
126 125
                     max_tiles_to_use,
127 126
                     source,
@@ -179,8 +178,8 @@ impl<'a> MapViewGl<'a> {
179 178
                 vertex_data.extend(&minmax);
180 179
             }
181 180
 
182
-            self.buf.set_data(&vertex_data, vertex_data.len() / 4);
183
-            self.buf.draw(DrawMode::Triangles);
181
+            self.buf.set_data(cx, &vertex_data, vertex_data.len() / 4);
182
+            self.buf.draw(cx, DrawMode::Triangles);
184 183
 
185 184
             num_draws += 1;
186 185
 

+ 17
- 19
src/program.rs Просмотреть файл

@@ -10,8 +10,7 @@ use texture::{Texture, TextureId};
10 10
 
11 11
 
12 12
 #[derive(Clone, Debug)]
13
-pub struct Program<'a> {
14
-    cx: &'a ::context::Context,
13
+pub struct Program {
15 14
     vert_obj: u32,
16 15
     frag_obj: u32,
17 16
     program_obj: u32,
@@ -24,8 +23,8 @@ pub struct ProgramId {
24 23
     id: u32,
25 24
 }
26 25
 
27
-impl<'a> Program<'a> {
28
-    pub fn from_paths<P: AsRef<Path>>(cx: &'a Context, vert_path: P, frag_path: P) -> Result<Program<'a>, String> {
26
+impl Program {
27
+    pub fn from_paths<P: AsRef<Path>>(cx: &mut Context, vert_path: P, frag_path: P) -> Result<Program, String> {
29 28
         let vert_src = {
30 29
             let file = File::open(&vert_path)
31 30
                 .map_err(|e| format!("{}", e))?;
@@ -49,7 +48,7 @@ impl<'a> Program<'a> {
49 48
         Self::new(cx, &vert_src, &frag_src)
50 49
     }
51 50
 
52
-    pub fn new(cx: &'a Context, vert_src: &[u8], frag_src: &[u8]) -> Result<Program<'a>, String> {
51
+    pub fn new(cx: &mut Context, vert_src: &[u8], frag_src: &[u8]) -> Result<Program, String> {
53 52
         unsafe {
54 53
             let vert_obj = {
55 54
                 let vert_obj = cx.gl.CreateShader(context::gl::VERTEX_SHADER);
@@ -92,7 +91,6 @@ impl<'a> Program<'a> {
92 91
             };
93 92
 
94 93
             Ok(Program {
95
-                cx,
96 94
                 vert_obj,
97 95
                 frag_obj,
98 96
                 program_obj,
@@ -102,40 +100,40 @@ impl<'a> Program<'a> {
102 100
         }
103 101
     }
104 102
 
105
-    pub fn add_texture(&mut self, texture: &Texture, uniform_name: &CStr) {
103
+    pub fn add_texture(&mut self, cx: &mut Context, texture: &Texture, uniform_name: &CStr) {
106 104
         //TODO store reference to texture
107 105
         unsafe {
108
-            let tex_loc = self.cx.gl.GetUniformLocation(self.program_obj, uniform_name.as_ptr() as *const _);
109
-            check_gl_errors!(self.cx);
106
+            let tex_loc = cx.gl.GetUniformLocation(self.program_obj, uniform_name.as_ptr() as *const _);
107
+            check_gl_errors!(cx);
110 108
 
111 109
             self.tex_ids.push(texture.id());
112 110
             self.tex_locations.push(tex_loc);
113 111
         }
114 112
     }
115 113
 
116
-    pub fn add_attribute(&mut self, name: &CStr, number_components: u32, stride: usize, offset: usize) {
114
+    pub fn add_attribute(&mut self, cx: &mut Context, name: &CStr, number_components: u32, stride: usize, offset: usize) {
117 115
         unsafe {
118
-            let attrib_id = self.cx.gl.GetAttribLocation(self.program_obj, name.as_ptr() as *const _);
119
-            self.cx.gl.VertexAttribPointer(
116
+            let attrib_id = cx.gl.GetAttribLocation(self.program_obj, name.as_ptr() as *const _);
117
+            cx.gl.VertexAttribPointer(
120 118
                 attrib_id as u32,
121 119
                 number_components as i32, // size
122 120
                 context::gl::FLOAT, // type
123 121
                 0, // normalized
124 122
                 (stride * mem::size_of::<f32>()) as context::gl::types::GLsizei,
125 123
                 (offset * mem::size_of::<f32>()) as *const () as *const _);
126
-            self.cx.gl.EnableVertexAttribArray(attrib_id as u32);
124
+            cx.gl.EnableVertexAttribArray(attrib_id as u32);
127 125
         }
128
-        check_gl_errors!(self.cx);
126
+        check_gl_errors!(cx);
129 127
     }
130 128
 
131
-    pub fn before_render(&self) {
129
+    pub fn before_render(&self, cx: &mut Context) {
132 130
         unsafe {
133
-            //self.cx.gl.UseProgram(self.program_obj);
131
+            //cx.gl.UseProgram(self.program_obj);
134 132
             //TODO check max texture number
135 133
             for (i, (tex_id, &tex_loc)) in self.tex_ids.iter().zip(&self.tex_locations).enumerate() {
136
-                self.cx.gl.ActiveTexture(context::gl::TEXTURE0 + i as u32);
137
-                self.cx.gl.BindTexture(context::gl::TEXTURE_2D, tex_id.id);
138
-                self.cx.gl.Uniform1i(tex_loc, i as i32);
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);
139 137
             }
140 138
         }
141 139
     }

+ 12
- 18
src/texture.rs Просмотреть файл

@@ -5,8 +5,7 @@ use image::GenericImage;
5 5
 use std::os::raw::c_void;
6 6
 
7 7
 #[derive(Clone, Debug)]
8
-pub struct Texture<'a> {
9
-    cx: &'a Context,
8
+pub struct Texture {
10 9
     texture_obj: u32,
11 10
     width: u32,
12 11
     height: u32,
@@ -18,8 +17,8 @@ pub struct TextureId {
18 17
     pub(crate) id: u32,
19 18
 }
20 19
 
21
-impl<'a> Texture<'a> {
22
-    pub fn new(cx: &'a Context, img: &image::DynamicImage) -> Result<Texture<'a>, ()> {
20
+impl Texture {
21
+    pub fn new(cx: &mut Context, img: &image::DynamicImage) -> Result<Texture, ()> {
23 22
         let format = match *img {
24 23
             image::ImageRgb8(_) => TextureFormat::Rgb8,
25 24
             image::ImageRgba8(_) => TextureFormat::Rgba8,
@@ -29,15 +28,15 @@ impl<'a> Texture<'a> {
29 28
         Ok(Self::from_bytes(cx, img.width(), img.height(), format, &img.raw_pixels()))
30 29
     }
31 30
 
32
-    pub fn empty(cx: &'a Context, width: u32, height: u32, format: TextureFormat) -> Texture<'a> {
31
+    pub fn empty(cx: &mut Context, width: u32, height: u32, format: TextureFormat) -> Texture {
33 32
         Self::from_ptr(cx, width, height, format, ::std::ptr::null() as *const _)
34 33
     }
35 34
 
36
-    pub fn from_bytes(cx: &'a Context, width: u32, height: u32, format: TextureFormat, data: &[u8]) -> Texture<'a> {
35
+    pub fn from_bytes(cx: &mut Context, width: u32, height: u32, format: TextureFormat, data: &[u8]) -> Texture {
37 36
         Self::from_ptr(cx, width, height, format, data.as_ptr() as *const _)
38 37
     }
39 38
 
40
-    fn from_ptr(cx: &'a Context, width: u32, height: u32, format: TextureFormat, data_ptr: *const c_void) -> Texture<'a> {
39
+    fn from_ptr(cx: &mut Context, width: u32, height: u32, format: TextureFormat, data_ptr: *const c_void) -> Texture {
41 40
         let mut texture_obj = 0_u32;
42 41
         unsafe {
43 42
             cx.gl.GenTextures(1, &mut texture_obj);
@@ -61,7 +60,6 @@ impl<'a> Texture<'a> {
61 60
         }
62 61
 
63 62
         Texture {
64
-            cx,
65 63
             texture_obj,
66 64
             width,
67 65
             height,
@@ -69,7 +67,7 @@ impl<'a> Texture<'a> {
69 67
         }
70 68
     }
71 69
 
72
-    pub fn sub_image(&mut self, x: i32, y: i32, img: &image::DynamicImage) {
70
+    pub fn sub_image(&mut self, cx: &mut Context, x: i32, y: i32, img: &image::DynamicImage) {
73 71
         let format = match *img {
74 72
             image::ImageRgb8(_) => TextureFormat::Rgb8,
75 73
             image::ImageRgba8(_) => TextureFormat::Rgba8,
@@ -77,8 +75,8 @@ impl<'a> Texture<'a> {
77 75
         };
78 76
 
79 77
         unsafe {
80
-            self.cx.gl.BindTexture(context::gl::TEXTURE_2D, self.texture_obj);
81
-            self.cx.gl.TexSubImage2D(
78
+            cx.gl.BindTexture(context::gl::TEXTURE_2D, self.texture_obj);
79
+            cx.gl.TexSubImage2D(
82 80
                 context::gl::TEXTURE_2D,
83 81
                 0, // level
84 82
                 x, // x offset
@@ -92,10 +90,10 @@ impl<'a> Texture<'a> {
92 90
         }
93 91
     }
94 92
 
95
-    pub fn resize(&mut self, width: u32, height: u32) {
93
+    pub fn resize(&mut self, cx: &mut Context, width: u32, height: u32) {
96 94
         unsafe {
97
-            self.cx.gl.BindTexture(context::gl::TEXTURE_2D, self.texture_obj);
98
-            self.cx.gl.TexImage2D(
95
+            cx.gl.BindTexture(context::gl::TEXTURE_2D, self.texture_obj);
96
+            cx.gl.TexImage2D(
99 97
                 context::gl::TEXTURE_2D,
100 98
                 0, // level
101 99
                 self.format.to_gl_enum() as i32,
@@ -124,10 +122,6 @@ impl<'a> Texture<'a> {
124 122
     pub fn height(&self) -> u32 {
125 123
         self.height
126 124
     }
127
-
128
-    pub fn context(&self) -> &Context {
129
-        self.cx
130
-    }
131 125
 }
132 126
 
133 127
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]

+ 18
- 15
src/tile_atlas.rs Просмотреть файл

@@ -1,3 +1,4 @@
1
+use context::Context;
1 2
 use coord::{ScreenRect, SubTileCoord, TileCoord, TextureRect};
2 3
 use image;
3 4
 use linked_hash_map::LinkedHashMap;
@@ -17,22 +18,22 @@ pub struct TexturedVisibleTile {
17 18
 }
18 19
 
19 20
 #[derive(Clone, Debug)]
20
-pub struct TileAtlas<'a> {
21
-    texture: Texture<'a>,
21
+pub struct TileAtlas {
22
+    texture: Texture,
22 23
     tile_size: u32,
23 24
     slots_lru: LinkedHashMap<CacheSlot, Option<Tile>>, // LRU cache of slots
24 25
     tile_to_slot: HashMap<Tile, CacheSlot>,
25 26
     use_async: bool,
26 27
 }
27 28
 
28
-impl<'a> TileAtlas<'a> {
29
-    fn init(&mut self) {
29
+impl TileAtlas {
30
+    fn init(&mut self, cx: &mut Context) {
30 31
         // add tile for default slot
31 32
         {
32 33
             let img = image::load_from_memory(
33 34
                 include_bytes!("../img/no_tile.png"),
34 35
             ).unwrap();
35
-            self.texture.sub_image(0, 0, &img);
36
+            self.texture.sub_image(cx, 0, 0, &img);
36 37
         }
37 38
 
38 39
         let slots_x = self.texture.width() / self.tile_size;
@@ -53,7 +54,7 @@ impl<'a> TileAtlas<'a> {
53 54
         self.tile_to_slot.reserve(num_slots);
54 55
     }
55 56
 
56
-    pub fn new(tex: Texture<'a>, tile_size: u32, use_async: bool) -> Self {
57
+    pub fn new(cx: &mut Context, tex: Texture, tile_size: u32, use_async: bool) -> Self {
57 58
         let mut atlas = TileAtlas {
58 59
             texture: tex,
59 60
             tile_size,
@@ -62,21 +63,21 @@ impl<'a> TileAtlas<'a> {
62 63
             use_async,
63 64
         };
64 65
 
65
-        atlas.init();
66
+        atlas.init(cx);
66 67
         atlas
67 68
     }
68 69
 
69
-    pub fn double_texture_size(&mut self) -> Result<(), ()> {
70
-        let max_size = self.texture.context().max_texture_size() as u32;
70
+    pub fn double_texture_size(&mut self, cx: &mut Context) -> Result<(), ()> {
71
+        let max_size = cx.max_texture_size() as u32;
71 72
 
72 73
         let new_width = self.texture.width() * 2;
73 74
         let new_height = self.texture.height() * 2;
74 75
 
75 76
         if new_width <= max_size && new_height <= max_size {
76
-            self.texture.resize(new_width, new_height);
77
+            self.texture.resize(cx, new_width, new_height);
77 78
 
78 79
             // remove old entries, initialize texture
79
-            self.init();
80
+            self.init(cx);
80 81
 
81 82
             info!("new atlas size {}x{}", new_width, new_height);
82 83
 
@@ -90,7 +91,7 @@ impl<'a> TileAtlas<'a> {
90 91
         CacheSlot { x: 0, y: 0 }
91 92
     }
92 93
 
93
-    pub fn store(&mut self, tile_coord: TileCoord, source: &TileSource, cache: &mut TileCache, load: bool) -> Option<CacheSlot> {
94
+    pub fn store(&mut self, cx: &mut Context, tile_coord: TileCoord, source: &TileSource, cache: &mut TileCache, load: bool) -> Option<CacheSlot> {
94 95
         let mut remove_tile = None;
95 96
         let tile = Tile::new(tile_coord, source.id());
96 97
 
@@ -113,6 +114,7 @@ impl<'a> TileAtlas<'a> {
113 114
                     remove_tile = old_tile;
114 115
 
115 116
                     self.texture.sub_image(
117
+                        cx,
116 118
                         (slot.x * self.tile_size) as i32,
117 119
                         (slot.y * self.tile_size) as i32,
118 120
                         img,
@@ -145,6 +147,7 @@ impl<'a> TileAtlas<'a> {
145 147
     /// the number of used tiles is returned as an `usize`.
146 148
     pub fn textured_visible_tiles<'b>(
147 149
         &mut self,
150
+        cx: &mut Context,
148 151
         visible_tiles: &'b [VisibleTile],
149 152
         max_tiles_to_use: usize,
150 153
         source: &TileSource,
@@ -166,7 +169,7 @@ impl<'a> TileAtlas<'a> {
166 169
                 return (tvt, Some(&visible_tiles[i..]), used_slots);
167 170
             }
168 171
 
169
-            if let Some(slot) = self.store(vt.tile, source, cache, true) {
172
+            if let Some(slot) = self.store(cx, vt.tile, source, cache, true) {
170 173
                 let tex_rect = self.slot_to_texture_rect(slot);
171 174
                 used_slots += 1;
172 175
                 tvt.push(
@@ -190,7 +193,7 @@ impl<'a> TileAtlas<'a> {
190 193
                 // look for cached tiles in lower zoom layers
191 194
                 for dist in 1..31 {
192 195
                     if let Some((parent_tile, sub_coord)) = vt.tile.parent(dist) {
193
-                        if let Some(slot) = self.store(parent_tile, source, cache, false) {
196
+                        if let Some(slot) = self.store(cx, parent_tile, source, cache, false) {
194 197
                             used_slots += 1;
195 198
                             tex_sub_rect = self.subslot_to_texture_rect(slot, sub_coord);
196 199
                             tex_rect = self.slot_to_texture_rect(slot);
@@ -203,7 +206,7 @@ impl<'a> TileAtlas<'a> {
203 206
 
204 207
                 // look for cached tiles in higher zoom layers
205 208
                 for &(child_tile, child_sub_coord) in &vt.tile.children() {
206
-                    if let Some(slot) = self.store(child_tile, source, cache, false) {
209
+                    if let Some(slot) = self.store(cx, child_tile, source, cache, false) {
207 210
                         used_slots += 1;
208 211
                         let tex_rect = self.slot_to_texture_rect(slot);
209 212