Bug 1493473. Update webrender to 4e7d0ed1b08f5402a6971230864a7e497b2453ec
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Sat, 22 Sep 2018 23:11:30 -0400
changeset 493557 5c2a8331f82c
parent 493556 89a0922393da
child 493558 4ff201d93d71
child 493565 b106fa22e262
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1493473
milestone64.0a1
first release with
nightly linux32
5c2a8331f82c / 64.0a1 / 20180923100316 / files
nightly linux64
5c2a8331f82c / 64.0a1 / 20180923100316 / files
nightly mac
5c2a8331f82c / 64.0a1 / 20180923100316 / files
nightly win32
5c2a8331f82c / 64.0a1 / 20180923100316 / files
nightly win64
5c2a8331f82c / 64.0a1 / 20180923100316 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1493473. Update webrender to 4e7d0ed1b08f5402a6971230864a7e497b2453ec
gfx/webrender/src/resource_cache.rs
gfx/webrender_bindings/revision.txt
--- a/gfx/webrender/src/resource_cache.rs
+++ b/gfx/webrender/src/resource_cache.rs
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{AddFont, BlobImageResources, AsyncBlobImageRasterizer, ResourceUpdate};
-use api::{BlobImageDescriptor, BlobImageHandler, BlobImageRequest, RasterizedBlobImage};
+use api::{BlobImageDescriptor, BlobImageHandler, BlobImageRequest};
 use api::{ClearCache, ColorF, DevicePoint, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
 use api::{FontInstanceKey, FontKey, FontTemplate, GlyphIndex};
 use api::{ExternalImageData, ExternalImageType, BlobImageResult, BlobImageParams};
 use api::{FontInstanceData, FontInstanceOptions, FontInstancePlatformOptions, FontVariation};
 use api::{GlyphDimensions, IdNamespace};
 use api::{ImageData, ImageDescriptor, ImageKey, ImageRendering};
 use api::{MemoryReport, VoidPtrToSizeFn};
 use api::{TileOffset, TileSize, TileRange, NormalizedRect, BlobImageData};
@@ -28,17 +28,16 @@ use glyph_rasterizer::{FontInstance, Gly
 use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
 use gpu_types::UvRectKind;
 use image::{compute_tile_range, for_each_tile_in_range};
 use internal_types::{FastHashMap, FastHashSet, SourceTexture, TextureUpdateList};
 use profiler::{ResourceProfileCounters, TextureCacheProfileCounters};
 use render_backend::FrameId;
 use render_task::{RenderTaskCache, RenderTaskCacheKey, RenderTaskId};
 use render_task::{RenderTaskCacheEntry, RenderTaskCacheEntryHandle, RenderTaskTree};
-use smallvec::SmallVec;
 use std::collections::hash_map::Entry::{self, Occupied, Vacant};
 use std::collections::hash_map::IterMut;
 use std::{cmp, mem};
 use std::fmt::Debug;
 use std::hash::Hash;
 use std::os::raw::c_void;
 #[cfg(any(feature = "capture", feature = "replay"))]
 use std::path::PathBuf;
@@ -96,19 +95,18 @@ pub struct ImageProperties {
 #[derive(Debug, Copy, Clone, PartialEq)]
 enum State {
     Idle,
     AddResources,
     QueryResources,
 }
 
 /// Post scene building state.
-enum RasterizedBlob {
-    Tiled(FastHashMap<TileOffset, RasterizedBlobImage>),
-    NonTiled(Vec<RasterizedBlobImage>),
+struct RasterizedBlobImage {
+    data: FastHashMap<Option<TileOffset>, BlobImageResult>,
 }
 
 /// Pre scene building state.
 /// We use this to generate the async blob rendering requests.
 struct BlobImageTemplate {
     descriptor: ImageDescriptor,
     tiling: Option<TileSize>,
     dirty_rect: Option<DeviceUintRect>,
@@ -402,17 +400,17 @@ pub struct ResourceCache {
     glyph_rasterizer: GlyphRasterizer,
 
     // The set of images that aren't present or valid in the texture cache,
     // and need to be rasterized and/or uploaded this frame. This includes
     // both blobs and regular images.
     pending_image_requests: FastHashSet<ImageRequest>,
 
     blob_image_handler: Option<Box<BlobImageHandler>>,
-    rasterized_blob_images: FastHashMap<ImageKey, RasterizedBlob>,
+    rasterized_blob_images: FastHashMap<ImageKey, RasterizedBlobImage>,
     blob_image_templates: FastHashMap<ImageKey, BlobImageTemplate>,
 
     // If while building a frame we encounter blobs that we didn't already
     // rasterize, add them to this list and rasterize them synchronously.
     missing_blob_images: Vec<BlobImageParams>,
     // The rasterizer associated with the current scene.
     blob_image_rasterizer: Option<Box<AsyncBlobImageRasterizer>>,
 }
@@ -601,50 +599,20 @@ impl ResourceCache {
     }
 
     pub fn set_blob_rasterizer(&mut self, rasterizer: Box<AsyncBlobImageRasterizer>) {
         self.blob_image_rasterizer = Some(rasterizer);
     }
 
     pub fn add_rasterized_blob_images(&mut self, images: Vec<(BlobImageRequest, BlobImageResult)>) {
         for (request, result) in images {
-            let data = match result {
-                Ok(data) => data,
-                Err(..) => {
-                    warn!("Failed to rasterize a blob image");
-                    continue;
-                }
-            };
-
-            // First make sure we have an entry for this key (using a placeholder
-            // if need be).
             let image = self.rasterized_blob_images.entry(request.key).or_insert_with(
-                || { RasterizedBlob::Tiled(FastHashMap::default()) }
+                || { RasterizedBlobImage { data: FastHashMap::default() } }
             );
-
-            if let Some(tile) = request.tile {
-                if let RasterizedBlob::NonTiled(..) = *image {
-                    *image = RasterizedBlob::Tiled(FastHashMap::default());
-                }
-
-                if let RasterizedBlob::Tiled(ref mut tiles) = *image {
-                    tiles.insert(tile, data);
-                }
-            } else {
-                if let RasterizedBlob::NonTiled(ref mut queue) = *image {
-                    // If our new rasterized rect overwrites items in the queue, discard them.
-                    queue.retain(|img| {
-                        !data.rasterized_rect.contains_rect(&img.rasterized_rect)
-                    });
-
-                    queue.push(data);
-                } else {
-                    *image = RasterizedBlob::NonTiled(vec![data]);
-                }
-            }
+            image.data.insert(request.tile, result);
         }
     }
 
     pub fn add_font_template(&mut self, font_key: FontKey, template: FontTemplate) {
         // Push the new font to the font renderer, and also store
         // it locally for glyph metric requests.
         self.glyph_rasterizer.add_font(font_key, template.clone());
         self.resources.font_templates.insert(font_key, template);
@@ -972,20 +940,19 @@ impl ResourceCache {
         }
 
         if !self.pending_image_requests.insert(request) {
             return
         }
 
         if template.data.is_blob() {
             let request: BlobImageRequest = request.into();
-            let missing = match (self.rasterized_blob_images.get(&request.key), request.tile) {
-                (Some(RasterizedBlob::Tiled(tiles)), Some(tile)) => !tiles.contains_key(&tile),
-                (Some(RasterizedBlob::NonTiled(..)), None) => false,
-                _ => true,
+            let missing = match self.rasterized_blob_images.get(&request.key) {
+                Some(img) => !img.data.contains_key(&request.tile),
+                None => true,
             };
 
             // For some reason the blob image is missing. We'll fall back to
             // rasterizing it on the render backend thread.
             if missing {
                 let descriptor = match template.tiling {
                     Some(tile_size) => {
                         let tile = request.tile.unwrap();
@@ -1110,42 +1077,23 @@ impl ResourceCache {
                                 tile: Some(tile),
                             },
                             descriptor,
                             dirty_rect: None,
                         }
                     );
                 });
             } else {
-                let mut needs_upload = match self.cached_images.try_get(&key) {
+                let needs_upload = match self.cached_images.try_get(&key) {
                     Some(&ImageResult::UntiledAuto(ref entry)) => {
                         self.texture_cache.needs_upload(&entry.texture_cache_handle)
                     }
                     _ => true,
                 };
 
-                // If the queue of ratserized updates is growing it probably means that
-                // the texture is not getting uploaded because the display item is off-screen.
-                // In that case we are better off
-                // - Either not kicking rasterization for that image (avoid wasted cpu work
-                //   but will jank next time the item is visible because of lazy rasterization.
-                // - Clobber the update queue by pushing an update with a larger dirty rect
-                //   to prevent it from accumulating.
-                //
-                // We do the latter here but it's not ideal and might want to revisit and do
-                // the former instead.
-                match self.rasterized_blob_images.get(&key) {
-                    Some(RasterizedBlob::NonTiled(ref queue)) => {
-                        if queue.len() > 2 {
-                            needs_upload = true;
-                        }
-                    }
-                    _ => {},
-                };
-
                 let dirty_rect = if needs_upload {
                     // The texture cache entry has been evicted, treat it as all dirty.
                     None
                 } else {
                     template.dirty_rect
                 };
 
                 blob_request_params.push(
@@ -1181,29 +1129,38 @@ impl ResourceCache {
                 //println!("Missing image template (key={:?})!", key);
                 return;
             }
         };
         let tile_size = match template.tiling {
             Some(size) => size,
             None => { return; }
         };
-
-        let tiles = match self.rasterized_blob_images.get_mut(&key) {
-            Some(RasterizedBlob::Tiled(tiles)) => tiles,
-            _ => { return; }
+        let image = match self.rasterized_blob_images.get_mut(&key) {
+            Some(image) => image,
+            None => {
+                //println!("Missing rasterized blob (key={:?})!", key);
+                return;
+            }
         };
-
         let tile_range = compute_tile_range(
             &area,
             &template.descriptor.size,
             tile_size,
         );
-
-        tiles.retain(|tile, _| { tile_range.contains(tile) });
+        image.data.retain(|tile, _| {
+            match *tile {
+                Some(offset) => tile_range.contains(&offset),
+                // This would be a bug. If we get here the blob should be tiled.
+                None => {
+                    error!("Blob image template and image data tiling don't match.");
+                    false
+                }
+            }
+        });
     }
 
     pub fn request_glyphs(
         &mut self,
         mut font: FontInstance,
         glyph_keys: &[GlyphKey],
         gpu_cache: &mut GpuCache,
         render_task_tree: &mut RenderTaskTree,
@@ -1458,147 +1415,139 @@ impl ResourceCache {
         self.missing_blob_images.clear();
     }
 
     fn update_texture_cache(&mut self, gpu_cache: &mut GpuCache) {
         for request in self.pending_image_requests.drain() {
             let image_template = self.resources.image_templates.get_mut(request.key).unwrap();
             debug_assert!(image_template.data.uses_texture_cache());
 
-            let mut updates: SmallVec<[(ImageData, Option<DeviceUintRect>); 1]> = SmallVec::new();
-
-            match image_template.data {
+            let mut blob_rasterized_rect = None;
+            let image_data = match image_template.data {
                 ImageData::Raw(..) | ImageData::External(..) => {
                     // Safe to clone here since the Raw image data is an
                     // Arc, and the external image data is small.
-                    updates.push((image_template.data.clone(), None));
+                    image_template.data.clone()
                 }
                 ImageData::Blob(..) => {
+                    let blob_image = self.rasterized_blob_images.get(&request.key).unwrap();
+                    match blob_image.data.get(&request.tile) {
+                        Some(result) => {
+                            let result = result
+                                .as_ref()
+                                .expect("Failed to render a blob image");
 
-                    let blob_image = self.rasterized_blob_images.get_mut(&request.key).unwrap();
-                    match (blob_image, request.tile) {
-                        (RasterizedBlob::Tiled(ref tiles), Some(tile)) => {
-                            let img = &tiles[&tile];
-                            updates.push((
-                                ImageData::Raw(Arc::clone(&img.data)),
-                                Some(img.rasterized_rect)
-                            ));
+                            // TODO: we may want to not panic and show a placeholder instead.
+
+                            blob_rasterized_rect = Some(result.rasterized_rect);
+
+                            ImageData::Raw(Arc::clone(&result.data))
                         }
-                        (RasterizedBlob::NonTiled(ref mut queue), None) => {
-                            for img in queue.drain(..) {
-                                updates.push((
-                                    ImageData::Raw(img.data),
-                                    Some(img.rasterized_rect)
-                                ));
-                            }
-                        }
-                        _ =>  {
+                        None => {
                             debug_assert!(false, "invalid blob image request during frame building");
                             continue;
                         }
                     }
                 }
             };
 
-            for (image_data, blob_rasterized_rect) in updates {
-                let entry = match *self.cached_images.get_mut(&request.key) {
-                    ImageResult::UntiledAuto(ref mut entry) => entry,
-                    ImageResult::Multi(ref mut entries) => entries.get_mut(&request.into()),
-                    ImageResult::Err(_) => panic!("Update requested for invalid entry")
+            let entry = match *self.cached_images.get_mut(&request.key) {
+                ImageResult::UntiledAuto(ref mut entry) => entry,
+                ImageResult::Multi(ref mut entries) => entries.get_mut(&request.into()),
+                ImageResult::Err(_) => panic!("Update requested for invalid entry")
+            };
+
+            match (blob_rasterized_rect, entry.dirty_rect) {
+                (Some(rasterized), Some(dirty)) => {
+                    debug_assert!(request.tile.is_some() || rasterized.contains_rect(&dirty));
+                }
+                _ => {}
+            }
+
+            let mut descriptor = image_template.descriptor.clone();
+            let local_dirty_rect;
+
+            if let Some(tile) = request.tile {
+                let tile_size = image_template.tiling.unwrap();
+                let clipped_tile_size = compute_tile_size(&descriptor, tile_size, tile);
+
+                local_dirty_rect = if let Some(rect) = entry.dirty_rect.take() {
+                    // We should either have a dirty rect, or we are re-uploading where the dirty
+                    // rect is ignored anyway.
+                    let intersection = intersect_for_tile(rect, clipped_tile_size, tile_size, tile);
+                    debug_assert!(intersection.is_some() ||
+                                  self.texture_cache.needs_upload(&entry.texture_cache_handle));
+                    intersection
+                } else {
+                    None
                 };
 
-                let mut descriptor = image_template.descriptor.clone();
-                let mut local_dirty_rect;
-
-                if let Some(tile) = request.tile {
-                    let tile_size = image_template.tiling.unwrap();
-                    let clipped_tile_size = compute_tile_size(&descriptor, tile_size, tile);
-
-                    local_dirty_rect = if let Some(rect) = entry.dirty_rect.take() {
-                        // We should either have a dirty rect, or we are re-uploading where the dirty
-                        // rect is ignored anyway.
-                        let intersection = intersect_for_tile(rect, clipped_tile_size, tile_size, tile);
-                        debug_assert!(intersection.is_some() ||
-                                      self.texture_cache.needs_upload(&entry.texture_cache_handle));
-                        intersection
-                    } else {
-                        None
-                    };
-
-                    // The tiled image could be stored on the CPU as one large image or be
-                    // already broken up into tiles. This affects the way we compute the stride
-                    // and offset.
-                    let tiled_on_cpu = image_template.data.is_blob();
-                    if !tiled_on_cpu {
-                        let bpp = descriptor.format.bytes_per_pixel();
-                        let stride = descriptor.compute_stride();
-                        descriptor.stride = Some(stride);
-                        descriptor.offset +=
-                            tile.y as u32 * tile_size as u32 * stride +
-                            tile.x as u32 * tile_size as u32 * bpp;
-                    }
-
-                    descriptor.size = clipped_tile_size;
-                } else {
-                    local_dirty_rect = entry.dirty_rect.take();
+                // The tiled image could be stored on the CPU as one large image or be
+                // already broken up into tiles. This affects the way we compute the stride
+                // and offset.
+                let tiled_on_cpu = image_template.data.is_blob();
+                if !tiled_on_cpu {
+                    let bpp = descriptor.format.bytes_per_pixel();
+                    let stride = descriptor.compute_stride();
+                    descriptor.stride = Some(stride);
+                    descriptor.offset +=
+                        tile.y as u32 * tile_size as u32 * stride +
+                        tile.x as u32 * tile_size as u32 * bpp;
                 }
 
-                // If we are uploading the dirty region of a blob image we might have several
-                // rects to upload so we use each of these rasterized rects rather than the
-                // overall dirty rect of the image.
-                if blob_rasterized_rect.is_some() {
-                    local_dirty_rect = blob_rasterized_rect;
+                descriptor.size = clipped_tile_size;
+            } else {
+                local_dirty_rect = entry.dirty_rect.take();
+            }
+
+            let filter = match request.rendering {
+                ImageRendering::Pixelated => {
+                    TextureFilter::Nearest
                 }
-
-                let filter = match request.rendering {
-                    ImageRendering::Pixelated => {
-                        TextureFilter::Nearest
+                ImageRendering::Auto | ImageRendering::CrispEdges => {
+                    // If the texture uses linear filtering, enable mipmaps and
+                    // trilinear filtering, for better image quality. We only
+                    // support this for now on textures that are not placed
+                    // into the shared cache. This accounts for any image
+                    // that is > 512 in either dimension, so it should cover
+                    // the most important use cases. We may want to support
+                    // mip-maps on shared cache items in the future.
+                    if descriptor.allow_mipmaps &&
+                       descriptor.size.width > 512 &&
+                       descriptor.size.height > 512 &&
+                       !self.texture_cache.is_allowed_in_shared_cache(
+                        TextureFilter::Linear,
+                        &descriptor,
+                    ) {
+                        TextureFilter::Trilinear
+                    } else {
+                        TextureFilter::Linear
                     }
-                    ImageRendering::Auto | ImageRendering::CrispEdges => {
-                        // If the texture uses linear filtering, enable mipmaps and
-                        // trilinear filtering, for better image quality. We only
-                        // support this for now on textures that are not placed
-                        // into the shared cache. This accounts for any image
-                        // that is > 512 in either dimension, so it should cover
-                        // the most important use cases. We may want to support
-                        // mip-maps on shared cache items in the future.
-                        if descriptor.allow_mipmaps &&
-                           descriptor.size.width > 512 &&
-                           descriptor.size.height > 512 &&
-                           !self.texture_cache.is_allowed_in_shared_cache(
-                            TextureFilter::Linear,
-                            &descriptor,
-                        ) {
-                            TextureFilter::Trilinear
-                        } else {
-                            TextureFilter::Linear
-                        }
-                    }
-                };
+                }
+            };
+
+            let eviction = if image_template.data.is_blob() {
+                Eviction::Manual
+            } else {
+                Eviction::Auto
+            };
 
-                let eviction = if image_template.data.is_blob() {
-                    Eviction::Manual
-                } else {
-                    Eviction::Auto
-                };
-
-                //Note: at this point, the dirty rectangle is local to the descriptor space
-                self.texture_cache.update(
-                    &mut entry.texture_cache_handle,
-                    descriptor,
-                    filter,
-                    Some(image_data),
-                    [0.0; 3],
-                    local_dirty_rect,
-                    gpu_cache,
-                    None,
-                    UvRectKind::Rect,
-                    eviction,
-                );
-            }
+            //Note: at this point, the dirty rectangle is local to the descriptor space
+            self.texture_cache.update(
+                &mut entry.texture_cache_handle,
+                descriptor,
+                filter,
+                Some(image_data),
+                [0.0; 3],
+                local_dirty_rect,
+                gpu_cache,
+                None,
+                UvRectKind::Rect,
+                eviction,
+            );
         }
     }
 
     pub fn end_frame(&mut self) {
         debug_assert_eq!(self.state, State::QueryResources);
         self.state = State::Idle;
     }
 
@@ -1666,25 +1615,29 @@ impl ResourceCache {
             report.images += match image.data {
                 ImageData::Raw(ref v) => unsafe { op(v.as_ptr() as *const c_void) },
                 ImageData::Blob(ref v) => unsafe { op(v.as_ptr() as *const c_void) },
                 ImageData::External(..) => 0,
             }
         }
 
         // Mesure rasterized blobs.
+        // TODO(gw): Temporarily disabled while we roll back a crash. We can re-enable
+        //           these when that crash is fixed.
+        /*
         for (_, image) in self.rasterized_blob_images.iter() {
             let mut accumulate = |b: &RasterizedBlobImage| {
                 report.rasterized_blobs += unsafe { op(b.data.as_ptr() as *const c_void) };
             };
             match image {
                 RasterizedBlob::Tiled(map) => map.values().for_each(&mut accumulate),
                 RasterizedBlob::NonTiled(vec) => vec.iter().for_each(&mut accumulate),
             };
         }
+        */
 
         report
     }
 }
 
 pub fn get_blob_tiling(
     tiling: Option<TileSize>,
     descriptor: &ImageDescriptor,
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-3f6016fbb6fb93b2f1fc7046bce186555ca836f3
+4e7d0ed1b08f5402a6971230864a7e497b2453ec