Bug 1548131 - WR reset texture allocation r=gw
authorDzmitry Malyshau <dmalyshau@mozilla.com>
Wed, 01 May 2019 22:43:16 +0000
changeset 531039 c0f3a0adee3ccb1bda58b1d0820bb1b961ec3c54
parent 531038 6462a738b3c5cb0ac8327c18c3c0ebed3955ad74
child 531040 8a7e44a884fc0f719fe953fcca70183f7f87d4ec
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw
bugs1548131
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1548131 - WR reset texture allocation r=gw Introduce a new texture allocation operation "reset", which acts like a "realloc" but without the contents preserved. Use it for the picture texture cache. Differential Revision: https://phabricator.services.mozilla.com/D29539
gfx/wr/webrender/src/internal_types.rs
gfx/wr/webrender/src/renderer.rs
gfx/wr/webrender/src/resource_cache.rs
gfx/wr/webrender/src/texture_cache.rs
gfx/wr/wrench/src/rawtest.rs
--- a/gfx/wr/webrender/src/internal_types.rs
+++ b/gfx/wr/webrender/src/internal_types.rs
@@ -141,16 +141,18 @@ pub struct TextureCacheAllocInfo {
 #[derive(Debug)]
 pub enum TextureCacheAllocationKind {
     /// Performs an initial texture allocation.
     Alloc(TextureCacheAllocInfo),
     /// Reallocates the texture. The existing live texture with the same id
     /// will be deallocated and its contents blitted over. The new size must
     /// be greater than the old size.
     Realloc(TextureCacheAllocInfo),
+    /// Reallocates the texture without preserving its contents.
+    Reset(TextureCacheAllocInfo),
     /// Frees the texture and the corresponding cache ID.
     Free,
 }
 
 /// Command to update the contents of the texture cache.
 #[derive(Debug)]
 pub struct TextureCacheUpdate {
     pub id: CacheTextureId,
@@ -237,44 +239,71 @@ impl TextureUpdateList {
     pub fn push_realloc(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
         self.debug_assert_coalesced(id);
 
         // Coallesce this realloc into a previous alloc or realloc, if available.
         if let Some(cur) = self.allocations.iter_mut().find(|x| x.id == id) {
             match cur.kind {
                 TextureCacheAllocationKind::Alloc(ref mut i) => *i = info,
                 TextureCacheAllocationKind::Realloc(ref mut i) => *i = info,
+                TextureCacheAllocationKind::Reset(ref mut i) => *i = info,
                 TextureCacheAllocationKind::Free => panic!("Reallocating freed texture"),
             }
-
-            return;
+            return
         }
 
         self.allocations.push(TextureCacheAllocation {
             id,
             kind: TextureCacheAllocationKind::Realloc(info),
         });
     }
 
+    /// Pushes a reallocation operation onto the list, potentially coalescing
+    /// with previous operations.
+    pub fn push_reset(&mut self, id: CacheTextureId, info: TextureCacheAllocInfo) {
+        self.debug_assert_coalesced(id);
+
+        // Coallesce this realloc into a previous alloc or realloc, if available.
+        if let Some(cur) = self.allocations.iter_mut().find(|x| x.id == id) {
+            match cur.kind {
+                TextureCacheAllocationKind::Alloc(ref mut i) => *i = info,
+                TextureCacheAllocationKind::Reset(ref mut i) => *i = info,
+                TextureCacheAllocationKind::Free => panic!("Resetting freed texture"),
+                TextureCacheAllocationKind::Realloc(_) => {
+                    // Reset takes precedence over realloc
+                    cur.kind = TextureCacheAllocationKind::Reset(info);
+                }
+            }
+            return
+        }
+
+        self.allocations.push(TextureCacheAllocation {
+            id,
+            kind: TextureCacheAllocationKind::Reset(info),
+        });
+    }
+
     /// Pushes a free operation onto the list, potentially coalescing with
     /// previous operations.
     pub fn push_free(&mut self, id: CacheTextureId) {
         self.debug_assert_coalesced(id);
 
         // Drop any unapplied updates to the to-be-freed texture.
         self.updates.retain(|x| x.id != id);
 
         // Drop any allocations for it as well. If we happen to be allocating and
         // freeing in the same batch, we can collapse them to a no-op.
         let idx = self.allocations.iter().position(|x| x.id == id);
         let removed_kind = idx.map(|i| self.allocations.remove(i).kind);
         match removed_kind {
             Some(TextureCacheAllocationKind::Alloc(..)) => { /* no-op! */ },
             Some(TextureCacheAllocationKind::Free) => panic!("Double free"),
-            Some(TextureCacheAllocationKind::Realloc(..)) | None => {
+            Some(TextureCacheAllocationKind::Realloc(..)) |
+            Some(TextureCacheAllocationKind::Reset(..)) |
+            None => {
                 self.allocations.push(TextureCacheAllocation {
                     id,
                     kind: TextureCacheAllocationKind::Free,
                 });
             }
         };
     }
 
--- a/gfx/wr/webrender/src/renderer.rs
+++ b/gfx/wr/webrender/src/renderer.rs
@@ -3295,20 +3295,20 @@ impl Renderer {
     fn update_texture_cache(&mut self) {
         let _gm = self.gpu_profile.start_marker("texture cache update");
         let mut pending_texture_updates = mem::replace(&mut self.pending_texture_updates, vec![]);
 
         let mut upload_time = TimeProfileCounter::new("Resource upload time", false);
         upload_time.profile(|| {
             for update_list in pending_texture_updates.drain(..) {
                 for allocation in update_list.allocations {
-                    let is_realloc = matches!(allocation.kind, TextureCacheAllocationKind::Realloc(..));
-                    match allocation.kind {
-                        TextureCacheAllocationKind::Alloc(info) |
-                        TextureCacheAllocationKind::Realloc(info) => {
+                    let old = match allocation.kind {
+                        TextureCacheAllocationKind::Alloc(ref info) |
+                        TextureCacheAllocationKind::Realloc(ref info) |
+                        TextureCacheAllocationKind::Reset(ref info) => {
                             // Create a new native texture, as requested by the texture cache.
                             //
                             // Ensure no PBO is bound when creating the texture storage,
                             // or GL will attempt to read data from there.
                             let mut texture = self.device.create_texture(
                                 TextureTarget::Array,
                                 info.format,
                                 info.width,
@@ -3327,30 +3327,41 @@ impl Renderer {
                                 // Textures in the cache generally don't need to be cleared,
                                 // but we do so if the debug display is active to make it
                                 // easier to identify unallocated regions.
                                 if self.debug_flags.contains(DebugFlags::TEXTURE_CACHE_DBG) {
                                     self.clear_texture(&texture, TEXTURE_CACHE_DBG_CLEAR_COLOR);
                                 }
                             }
 
-                            let old = self.texture_resolver.texture_cache_map.insert(allocation.id, texture);
-                            assert_eq!(old.is_some(), is_realloc, "Renderer and RenderBackend disagree");
-                            if let Some(old) = old {
-                                self.device.blit_renderable_texture(
-                                    self.texture_resolver.texture_cache_map.get_mut(&allocation.id).unwrap(),
-                                    &old
-                                );
-                                self.device.delete_texture(old);
-                            }
-                        },
+                            self.texture_resolver.texture_cache_map.insert(allocation.id, texture)
+                        }
                         TextureCacheAllocationKind::Free => {
-                            let texture = self.texture_resolver.texture_cache_map.remove(&allocation.id).unwrap();
-                            self.device.delete_texture(texture);
-                        },
+                            self.texture_resolver.texture_cache_map.remove(&allocation.id)
+                        }
+                    };
+
+                    match allocation.kind {
+                        TextureCacheAllocationKind::Alloc(_) => {
+                            assert!(old.is_none(), "Renderer and backend disagree!");
+                        }
+                        TextureCacheAllocationKind::Realloc(_) => {
+                            self.device.blit_renderable_texture(
+                                self.texture_resolver.texture_cache_map.get_mut(&allocation.id).unwrap(),
+                                old.as_ref().unwrap(),
+                            );
+                        }
+                        TextureCacheAllocationKind::Reset(_) |
+                        TextureCacheAllocationKind::Free => {
+                            assert!(old.is_some(), "Renderer and backend disagree!");
+                        }
+                    }
+
+                    if let Some(old) = old {
+                        self.device.delete_texture(old);
                     }
                 }
 
                 for update in update_list.updates {
                     let TextureCacheUpdate { id, rect, stride, offset, layer_index, source } = update;
                     let texture = &self.texture_resolver.texture_cache_map[&id];
 
                     let bytes_uploaded = match source {
--- a/gfx/wr/webrender/src/resource_cache.rs
+++ b/gfx/wr/webrender/src/resource_cache.rs
@@ -2178,31 +2178,30 @@ impl ResourceCache {
         use std::io::Read;
 
         info!("loading resource cache");
         //TODO: instead of filling the local path to Arc<data> map as we process
         // each of the resource types, we could go through all of the local paths
         // and fill out the map as the first step.
         let mut raw_map = FastHashMap::<String, Arc<Vec<u8>>>::default();
 
+        self.clear(ClearCache::all());
+        self.clear_images(|_| true);
+
         match caches {
             Some(cached) => {
                 self.current_frame_id = cached.current_frame_id;
                 self.cached_glyphs = cached.glyphs;
                 self.cached_glyph_dimensions = cached.glyph_dimensions;
                 self.cached_images = cached.images;
                 self.cached_render_tasks = cached.render_tasks;
                 self.texture_cache = cached.textures;
             }
             None => {
                 self.current_frame_id = FrameId::INVALID;
-                self.cached_glyphs.clear();
-                self.cached_glyph_dimensions.clear();
-                self.cached_images.clear();
-                self.cached_render_tasks.clear();
                 self.texture_cache = TextureCache::new(
                     self.texture_cache.max_texture_size(),
                     self.texture_cache.max_texture_layers(),
                     self.texture_cache.picture_tile_size(),
                     DeviceIntSize::zero(),
                 );
             }
         }
--- a/gfx/wr/webrender/src/texture_cache.rs
+++ b/gfx/wr/webrender/src/texture_cache.rs
@@ -634,17 +634,17 @@ impl TextureCache {
         debug_assert!(!self.now.is_valid());
         self.clear_kind(EntryKind::Standalone);
     }
 
     fn clear_picture(&mut self) {
         self.clear_kind(EntryKind::Picture);
         if let Some(ref mut picture_texture) = self.picture_texture {
             if let Some(texture_id) = picture_texture.reset(PICTURE_TEXTURE_ADD_SLICES) {
-                self.pending_updates.push_realloc(texture_id, picture_texture.to_info());
+                self.pending_updates.push_reset(texture_id, picture_texture.to_info());
             }
         }
     }
 
     fn clear_shared(&mut self) {
         self.unset_doc_data();
         self.clear_kind(EntryKind::Shared);
         self.shared_textures.clear(&mut self.pending_updates);
--- a/gfx/wr/wrench/src/rawtest.rs
+++ b/gfx/wr/wrench/src/rawtest.rs
@@ -39,16 +39,17 @@ impl<'a> RawtestHarness<'a> {
         self.test_tile_decomposition();
         self.test_very_large_blob();
         self.test_insufficient_blob_visible_area();
         self.test_offscreen_blob();
         self.test_save_restore();
         self.test_blur_cache();
         self.test_capture();
         self.test_zero_height_window();
+        self.test_clear_cache();
     }
 
     fn render_and_get_pixels(&mut self, window_rect: FramebufferIntRect) -> Vec<u8> {
         self.rx.recv().unwrap();
         self.wrench.render();
         self.wrench.renderer.read_pixels_rgba8(window_rect)
     }
 
@@ -458,17 +459,17 @@ impl<'a> RawtestHarness<'a> {
 
         txn = Transaction::new();
         txn.delete_blob_image(blob_img1);
         txn.delete_blob_image(blob_img2);
         self.wrench.api.update_resources(txn.resource_updates);
     }
 
     fn test_offscreen_blob(&mut self) {
-        println!("\toffscreen blob update.");
+        println!("\toffscreen blob update...");
 
         assert_eq!(self.wrench.device_pixel_ratio, 1.);
 
         let window_size = self.window.get_inner_size();
 
         let test_size = FramebufferIntSize::new(800, 800);
         let window_rect = FramebufferIntRect::new(
             point2(0, window_size.height - test_size.height),
@@ -1293,9 +1294,24 @@ impl<'a> RawtestHarness<'a> {
             assert_hit_test(WorldPoint::new(top_left.x, bottom_right.y), vec![(0, 1)]);
             assert_hit_test(bottom_right, vec![(0, 1)]);
         };
 
         test_rounded_rectangle(WorldPoint::new(100., 100.), WorldSize::new(100., 100.), (0, 4));
         test_rounded_rectangle(WorldPoint::new(200., 100.), WorldSize::new(100., 100.), (0, 5));
     }
 
+    fn test_clear_cache(&mut self) {
+        println!("\tclear cache test...");
+
+        self.wrench.api.send_message(ApiMsg::DebugCommand(DebugCommand::ClearCaches(ClearCache::all())));
+
+        let layout_size = LayoutSize::new(400., 400.);
+        let builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
+
+        let txn = Transaction::new();
+        let mut epoch = Epoch(0);
+        self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
+
+        self.rx.recv().unwrap();
+        self.wrench.render();
+    }
 }