tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

resource_cache.rs (100000B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 use api::{BlobImageRequest, ImageDescriptorFlags, ImageFormat, RasterizedBlobImage};
      6 use api::{DebugFlags, FontInstanceKey, FontKey, FontTemplate, GlyphIndex};
      7 use api::{ExternalImageData, ExternalImageType, ExternalImageId, BlobImageResult};
      8 use api::{DirtyRect, GlyphDimensions, IdNamespace, DEFAULT_TILE_SIZE};
      9 use api::{ColorF, ImageData, ImageDescriptor, ImageKey, ImageRendering, TileSize};
     10 use api::{BlobImageHandler, BlobImageKey, VoidPtrToSizeFn};
     11 use api::units::*;
     12 use euclid::size2;
     13 use crate::render_target::RenderTargetKind;
     14 use crate::render_task::{RenderTaskLocation, StaticRenderTaskSurface};
     15 use crate::{render_api::{ClearCache, AddFont, ResourceUpdate, MemoryReport}, util::WeakTable};
     16 use crate::prim_store::image::AdjustedImageSource;
     17 use crate::image_tiling::{compute_tile_size, compute_tile_range};
     18 #[cfg(feature = "capture")]
     19 use crate::capture::ExternalCaptureImage;
     20 #[cfg(feature = "replay")]
     21 use crate::capture::PlainExternalImage;
     22 #[cfg(any(feature = "replay", feature = "png", feature="capture"))]
     23 use crate::capture::CaptureConfig;
     24 use crate::composite::{NativeSurfaceId, NativeSurfaceOperation, NativeTileId, NativeSurfaceOperationDetails};
     25 use crate::device::TextureFilter;
     26 use crate::glyph_cache::{GlyphCache, CachedGlyphInfo};
     27 use crate::glyph_cache::GlyphCacheEntry;
     28 use glyph_rasterizer::{GLYPH_FLASHING, FontInstance, GlyphFormat, GlyphKey, GlyphRasterizer, GlyphRasterJob};
     29 use glyph_rasterizer::{SharedFontResources, BaseFontInstance};
     30 use crate::gpu_types::UvRectKind;
     31 use crate::internal_types::{
     32    CacheTextureId, FastHashMap, FastHashSet, TextureSource, ResourceUpdateList,
     33    FrameId, FrameStamp,
     34 };
     35 use crate::profiler::{self, TransactionProfile, bytes_to_mb};
     36 use crate::render_task_graph::{RenderTaskId, RenderTaskGraphBuilder};
     37 use crate::render_task_cache::{RenderTaskCache, RenderTaskCacheKey, RenderTaskParent};
     38 use crate::render_task_cache::{RenderTaskCacheEntry, RenderTaskCacheEntryHandle};
     39 use crate::renderer::{GpuBufferAddress, GpuBufferBuilder, GpuBufferBuilderF, GpuBufferHandle};
     40 use crate::surface::SurfaceBuilder;
     41 use euclid::point2;
     42 use smallvec::SmallVec;
     43 use std::collections::hash_map::Entry::{self, Occupied, Vacant};
     44 use std::collections::hash_map::{Iter, IterMut};
     45 use std::collections::VecDeque;
     46 use std::{cmp, mem};
     47 use std::fmt::Debug;
     48 use std::hash::Hash;
     49 use std::os::raw::c_void;
     50 #[cfg(any(feature = "capture", feature = "replay"))]
     51 use std::path::PathBuf;
     52 use std::sync::Arc;
     53 use std::sync::atomic::{AtomicUsize, Ordering};
     54 use std::u32;
     55 use crate::texture_cache::{TextureCache, TextureCacheHandle, Eviction, TargetShader};
     56 use crate::picture_textures::PictureTextures;
     57 use peek_poke::PeekPoke;
     58 
     59 // Counter for generating unique native surface ids
     60 static NEXT_NATIVE_SURFACE_ID: AtomicUsize = AtomicUsize::new(0);
     61 
     62 #[cfg_attr(feature = "capture", derive(Serialize))]
     63 #[cfg_attr(feature = "replay", derive(Deserialize))]
     64 pub struct GlyphFetchResult {
     65    pub index_in_text_run: i32,
     66    pub uv_rect_address: GpuBufferAddress,
     67    pub offset: DevicePoint,
     68    pub size: DeviceIntSize,
     69    pub scale: f32,
     70    pub subpx_offset_x: u8,
     71    pub subpx_offset_y: u8,
     72    pub is_packed_glyph: bool,
     73 }
     74 
     75 // These coordinates are always in texels.
     76 // They are converted to normalized ST
     77 // values in the vertex shader. The reason
     78 // for this is that the texture may change
     79 // dimensions (e.g. the pages in a texture
     80 // atlas can grow). When this happens, by
     81 // storing the coordinates as texel values
     82 // we don't need to go through and update
     83 // various CPU-side structures.
     84 #[derive(Debug, Clone)]
     85 #[cfg_attr(feature = "capture", derive(Serialize))]
     86 #[cfg_attr(feature = "replay", derive(Deserialize))]
     87 pub struct CacheItem {
     88    pub texture_id: TextureSource,
     89    pub uv_rect_handle: GpuBufferHandle,
     90    pub uv_rect: DeviceIntRect,
     91    pub user_data: [f32; 4],
     92 }
     93 
     94 impl CacheItem {
     95    pub fn invalid() -> Self {
     96        CacheItem {
     97            texture_id: TextureSource::Invalid,
     98            uv_rect_handle: GpuBufferHandle::INVALID,
     99            uv_rect: DeviceIntRect::zero(),
    100            user_data: [0.0; 4],
    101        }
    102    }
    103 
    104    pub fn is_valid(&self) -> bool {
    105        self.texture_id != TextureSource::Invalid
    106    }
    107 }
    108 
    109 /// Represents the backing store of an image in the cache.
    110 /// This storage can take several forms.
    111 #[derive(Clone, Debug)]
    112 pub enum CachedImageData {
    113    /// A simple series of bytes, provided by the embedding and owned by WebRender.
    114    /// The format is stored out-of-band, currently in ImageDescriptor.
    115    Raw(Arc<Vec<u8>>),
    116    /// An series of commands that can be rasterized into an image via an
    117    /// embedding-provided callback.
    118    ///
    119    /// The commands are stored elsewhere and this variant is used as a placeholder.
    120    Blob,
    121    /// A stacking context for which a snapshot has been requested.
    122    ///
    123    /// The snapshot is grabbed from GPU-side rasterized pixels so there is no
    124    /// CPU-side data to store here.
    125    Snapshot,
    126    /// An image owned by the embedding, and referenced by WebRender. This may
    127    /// take the form of a texture or a heap-allocated buffer.
    128    External(ExternalImageData),
    129 }
    130 
    131 impl From<ImageData> for CachedImageData {
    132    fn from(img_data: ImageData) -> Self {
    133        match img_data {
    134            ImageData::Raw(data) => CachedImageData::Raw(data),
    135            ImageData::External(data) => CachedImageData::External(data),
    136        }
    137    }
    138 }
    139 
    140 impl CachedImageData {
    141    /// Returns true if this represents a blob.
    142    #[inline]
    143    pub fn is_blob(&self) -> bool {
    144        match *self {
    145            CachedImageData::Blob => true,
    146            _ => false,
    147        }
    148    }
    149 
    150    #[inline]
    151    pub fn is_snapshot(&self) -> bool {
    152        match *self {
    153            CachedImageData::Snapshot => true,
    154            _ => false,
    155        }
    156    }
    157 
    158    /// Returns true if this variant of CachedImageData should go through the texture
    159    /// cache.
    160    #[inline]
    161    pub fn uses_texture_cache(&self) -> bool {
    162        match *self {
    163            CachedImageData::External(ref ext_data) => match ext_data.image_type {
    164                ExternalImageType::TextureHandle(_) => false,
    165                ExternalImageType::Buffer => true,
    166            },
    167            CachedImageData::Blob => true,
    168            CachedImageData::Raw(_) => true,
    169            CachedImageData::Snapshot => true,
    170        }
    171    }
    172 }
    173 
    174 #[derive(Debug)]
    175 #[cfg_attr(feature = "capture", derive(Serialize))]
    176 #[cfg_attr(feature = "replay", derive(Deserialize))]
    177 pub struct ImageProperties {
    178    pub descriptor: ImageDescriptor,
    179    pub external_image: Option<ExternalImageData>,
    180    pub tiling: Option<TileSize>,
    181    // Potentially a subset of the image's total rectangle. This rectangle is what
    182    // we map to the (layout space) display item bounds.
    183    pub visible_rect: DeviceIntRect,
    184    pub adjustment: AdjustedImageSource,
    185 }
    186 
    187 #[derive(Debug, Copy, Clone, PartialEq)]
    188 enum State {
    189    Idle,
    190    AddResources,
    191    QueryResources,
    192 }
    193 
    194 /// Post scene building state.
    195 type RasterizedBlob = FastHashMap<TileOffset, RasterizedBlobImage>;
    196 
    197 #[cfg_attr(feature = "capture", derive(Serialize))]
    198 #[cfg_attr(feature = "replay", derive(Deserialize))]
    199 #[derive(Debug, Copy, Clone, PartialEq, PeekPoke, Default)]
    200 pub struct ImageGeneration(pub u32);
    201 
    202 impl ImageGeneration {
    203    pub const INVALID: ImageGeneration = ImageGeneration(u32::MAX);
    204 }
    205 
    206 struct ImageResource {
    207    data: CachedImageData,
    208    descriptor: ImageDescriptor,
    209    tiling: Option<TileSize>,
    210    /// This is used to express images that are virtually very large
    211    /// but with only a visible sub-set that is valid at a given time.
    212    visible_rect: DeviceIntRect,
    213    adjustment: AdjustedImageSource,
    214    generation: ImageGeneration,
    215 }
    216 
    217 #[derive(Default)]
    218 struct ImageTemplates {
    219    images: FastHashMap<ImageKey, ImageResource>,
    220 }
    221 
    222 impl ImageTemplates {
    223    fn insert(&mut self, key: ImageKey, resource: ImageResource) {
    224        self.images.insert(key, resource);
    225    }
    226 
    227    fn remove(&mut self, key: ImageKey) -> Option<ImageResource> {
    228        self.images.remove(&key)
    229    }
    230 
    231    fn get(&self, key: ImageKey) -> Option<&ImageResource> {
    232        self.images.get(&key)
    233    }
    234 
    235    fn get_mut(&mut self, key: ImageKey) -> Option<&mut ImageResource> {
    236        self.images.get_mut(&key)
    237    }
    238 }
    239 
    240 #[cfg_attr(feature = "capture", derive(Serialize))]
    241 #[cfg_attr(feature = "replay", derive(Deserialize))]
    242 struct CachedImageInfo {
    243    texture_cache_handle: TextureCacheHandle,
    244    dirty_rect: ImageDirtyRect,
    245    manual_eviction: bool,
    246 }
    247 
    248 impl CachedImageInfo {
    249    fn mark_unused(&mut self, texture_cache: &mut TextureCache) {
    250        texture_cache.evict_handle(&self.texture_cache_handle);
    251        self.manual_eviction = false;
    252    }
    253 }
    254 
    255 #[cfg(debug_assertions)]
    256 impl Drop for CachedImageInfo {
    257    fn drop(&mut self) {
    258        debug_assert!(!self.manual_eviction, "Manual eviction requires cleanup");
    259    }
    260 }
    261 
    262 #[cfg_attr(feature = "capture", derive(Serialize))]
    263 #[cfg_attr(feature = "replay", derive(Deserialize))]
    264 pub struct ResourceClassCache<K: Hash + Eq, V, U: Default> {
    265    resources: FastHashMap<K, V>,
    266    pub user_data: U,
    267 }
    268 
    269 impl<K, V, U> ResourceClassCache<K, V, U>
    270 where
    271    K: Clone + Hash + Eq + Debug,
    272    U: Default,
    273 {
    274    pub fn new() -> Self {
    275        ResourceClassCache {
    276            resources: FastHashMap::default(),
    277            user_data: Default::default(),
    278        }
    279    }
    280 
    281    pub fn get(&self, key: &K) -> &V {
    282        self.resources.get(key)
    283            .expect("Didn't find a cached resource with that ID!")
    284    }
    285 
    286    pub fn try_get(&self, key: &K) -> Option<&V> {
    287        self.resources.get(key)
    288    }
    289 
    290    pub fn insert(&mut self, key: K, value: V) {
    291        self.resources.insert(key, value);
    292    }
    293 
    294    pub fn remove(&mut self, key: &K) -> Option<V> {
    295        self.resources.remove(key)
    296    }
    297 
    298    pub fn get_mut(&mut self, key: &K) -> &mut V {
    299        self.resources.get_mut(key)
    300            .expect("Didn't find a cached resource with that ID!")
    301    }
    302 
    303    pub fn try_get_mut(&mut self, key: &K) -> Option<&mut V> {
    304        self.resources.get_mut(key)
    305    }
    306 
    307    pub fn entry(&mut self, key: K) -> Entry<K, V> {
    308        self.resources.entry(key)
    309    }
    310 
    311    pub fn iter(&self) -> Iter<K, V> {
    312        self.resources.iter()
    313    }
    314 
    315    pub fn iter_mut(&mut self) -> IterMut<K, V> {
    316        self.resources.iter_mut()
    317    }
    318 
    319    pub fn is_empty(&mut self) -> bool {
    320        self.resources.is_empty()
    321    }
    322 
    323    pub fn clear(&mut self) {
    324        self.resources.clear();
    325    }
    326 
    327    pub fn retain<F>(&mut self, f: F)
    328    where
    329        F: FnMut(&K, &mut V) -> bool,
    330    {
    331        self.resources.retain(f);
    332    }
    333 }
    334 
    335 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
    336 #[cfg_attr(feature = "capture", derive(Serialize))]
    337 #[cfg_attr(feature = "replay", derive(Deserialize))]
    338 struct CachedImageKey {
    339    pub rendering: ImageRendering,
    340    pub tile: Option<TileOffset>,
    341 }
    342 
    343 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
    344 #[cfg_attr(feature = "capture", derive(Serialize))]
    345 #[cfg_attr(feature = "replay", derive(Deserialize))]
    346 pub struct ImageRequest {
    347    pub key: ImageKey,
    348    pub rendering: ImageRendering,
    349    pub tile: Option<TileOffset>,
    350 }
    351 
    352 impl ImageRequest {
    353    pub fn with_tile(&self, offset: TileOffset) -> Self {
    354        ImageRequest {
    355            key: self.key,
    356            rendering: self.rendering,
    357            tile: Some(offset),
    358        }
    359    }
    360 
    361    pub fn is_untiled_auto(&self) -> bool {
    362        self.tile.is_none() && self.rendering == ImageRendering::Auto
    363    }
    364 }
    365 
    366 impl Into<BlobImageRequest> for ImageRequest {
    367    fn into(self) -> BlobImageRequest {
    368        BlobImageRequest {
    369            key: BlobImageKey(self.key),
    370            tile: self.tile.unwrap(),
    371        }
    372    }
    373 }
    374 
    375 impl Into<CachedImageKey> for ImageRequest {
    376    fn into(self) -> CachedImageKey {
    377        CachedImageKey {
    378            rendering: self.rendering,
    379            tile: self.tile,
    380        }
    381    }
    382 }
    383 
    384 #[derive(Debug)]
    385 #[cfg_attr(feature = "capture", derive(Clone, Serialize))]
    386 #[cfg_attr(feature = "replay", derive(Deserialize))]
    387 pub enum ImageCacheError {
    388    OverLimitSize,
    389 }
    390 
    391 #[cfg_attr(feature = "capture", derive(Serialize))]
    392 #[cfg_attr(feature = "replay", derive(Deserialize))]
    393 enum ImageResult {
    394    UntiledAuto(CachedImageInfo),
    395    Multi(ResourceClassCache<CachedImageKey, CachedImageInfo, ()>),
    396    Err(ImageCacheError),
    397 }
    398 
    399 impl ImageResult {
    400    /// Releases any texture cache entries held alive by this ImageResult.
    401    fn drop_from_cache(&mut self, texture_cache: &mut TextureCache) {
    402        match *self {
    403            ImageResult::UntiledAuto(ref mut entry) => {
    404                entry.mark_unused(texture_cache);
    405            },
    406            ImageResult::Multi(ref mut entries) => {
    407                for entry in entries.resources.values_mut() {
    408                    entry.mark_unused(texture_cache);
    409                }
    410            },
    411            ImageResult::Err(_) => {},
    412        }
    413    }
    414 }
    415 
    416 type ImageCache = ResourceClassCache<ImageKey, ImageResult, ()>;
    417 
    418 struct Resources {
    419    fonts: SharedFontResources,
    420    image_templates: ImageTemplates,
    421    // We keep a set of Weak references to the fonts so that we're able to include them in memory
    422    // reports even if only the OS is holding on to the Vec<u8>. PtrWeakHashSet will periodically
    423    // drop any references that have gone dead.
    424    weak_fonts: WeakTable
    425 }
    426 
    427 // We only use this to report glyph dimensions to the user of the API, so using
    428 // the font instance key should be enough. If we start using it to cache dimensions
    429 // for internal font instances we should change the hash key accordingly.
    430 pub type GlyphDimensionsCache = FastHashMap<(FontInstanceKey, GlyphIndex), Option<GlyphDimensions>>;
    431 
    432 /// Internal information about allocated render targets in the pool
    433 struct RenderTarget {
    434    size: DeviceIntSize,
    435    format: ImageFormat,
    436    texture_id: CacheTextureId,
    437    /// If true, this is currently leant out, and not available to other passes
    438    is_active: bool,
    439    last_frame_used: FrameId,
    440 }
    441 
    442 impl RenderTarget {
    443    fn size_in_bytes(&self) -> usize {
    444        let bpp = self.format.bytes_per_pixel() as usize;
    445        (self.size.width * self.size.height) as usize * bpp
    446    }
    447 
    448    /// Returns true if this texture was used within `threshold` frames of
    449    /// the current frame.
    450    pub fn used_recently(&self, current_frame_id: FrameId, threshold: u64) -> bool {
    451        self.last_frame_used + threshold >= current_frame_id
    452    }
    453 }
    454 
    455 /// High-level container for resources managed by the `RenderBackend`.
    456 ///
    457 /// This includes a variety of things, including images, fonts, and glyphs,
    458 /// which may be stored as memory buffers, GPU textures, or handles to resources
    459 /// managed by the OS or other parts of WebRender.
    460 pub struct ResourceCache {
    461    cached_glyphs: GlyphCache,
    462    cached_images: ImageCache,
    463    cached_render_tasks: RenderTaskCache,
    464 
    465    resources: Resources,
    466    state: State,
    467    current_frame_id: FrameId,
    468 
    469    #[cfg(feature = "capture")]
    470    /// Used for capture sequences. If the resource cache is updated, then we
    471    /// mark it as dirty. When the next frame is captured in the sequence, we
    472    /// dump the state of the resource cache.
    473    capture_dirty: bool,
    474 
    475    pub texture_cache: TextureCache,
    476    pub picture_textures: PictureTextures,
    477 
    478    /// TODO(gw): We should expire (parts of) this cache semi-regularly!
    479    cached_glyph_dimensions: GlyphDimensionsCache,
    480    glyph_rasterizer: GlyphRasterizer,
    481 
    482    /// The set of images that aren't present or valid in the texture cache,
    483    /// and need to be rasterized and/or uploaded this frame. This includes
    484    /// both blobs and regular images.
    485    pending_image_requests: FastHashSet<ImageRequest>,
    486 
    487    rasterized_blob_images: FastHashMap<BlobImageKey, RasterizedBlob>,
    488 
    489    /// A log of the last three frames worth of deleted image keys kept
    490    /// for debugging purposes.
    491    deleted_blob_keys: VecDeque<Vec<BlobImageKey>>,
    492 
    493    /// We keep one around to be able to call clear_namespace
    494    /// after the api object is deleted. For most purposes the
    495    /// api object's blob handler should be used instead.
    496    blob_image_handler: Option<Box<dyn BlobImageHandler>>,
    497 
    498    /// A list of queued compositor surface updates to apply next frame.
    499    pending_native_surface_updates: Vec<NativeSurfaceOperation>,
    500 
    501    image_templates_memory: usize,
    502    font_templates_memory: usize,
    503 
    504    /// A pool of render targets for use by the render task graph
    505    render_target_pool: Vec<RenderTarget>,
    506 
    507    /// An empty (1x1 transparent) image used when a stacking context snapshot
    508    /// is missing.
    509    ///
    510    /// For now it acts as a catch-all solution for cases where WebRender fails
    511    /// to produce a texture cache item for a snapshotted tacking context.
    512    /// These cases include:
    513    /// - Empty stacking contexts.
    514    /// - Stacking contexts that are more aggressively culled out than they
    515    ///   should, for example when they are in a perspective transform that
    516    ///   cannot be projected to screen space.
    517    /// - Likely other cases we have not found yet.
    518    /// Over time it would be better to handle each of these cases explicitly
    519    /// and make it a hard error to fail to snapshot a stacking context.
    520    fallback_handle: TextureCacheHandle,
    521    debug_fallback_panic: bool,
    522    debug_fallback_pink: bool,
    523 }
    524 
    525 impl ResourceCache {
    526    pub fn new(
    527        texture_cache: TextureCache,
    528        picture_textures: PictureTextures,
    529        glyph_rasterizer: GlyphRasterizer,
    530        cached_glyphs: GlyphCache,
    531        fonts: SharedFontResources,
    532        blob_image_handler: Option<Box<dyn BlobImageHandler>>,
    533    ) -> Self {
    534        ResourceCache {
    535            cached_glyphs,
    536            cached_images: ResourceClassCache::new(),
    537            cached_render_tasks: RenderTaskCache::new(),
    538            resources: Resources {
    539                fonts,
    540                image_templates: ImageTemplates::default(),
    541                weak_fonts: WeakTable::new(),
    542            },
    543            cached_glyph_dimensions: FastHashMap::default(),
    544            texture_cache,
    545            picture_textures,
    546            state: State::Idle,
    547            current_frame_id: FrameId::INVALID,
    548            pending_image_requests: FastHashSet::default(),
    549            glyph_rasterizer,
    550            rasterized_blob_images: FastHashMap::default(),
    551            // We want to keep three frames worth of delete blob keys
    552            deleted_blob_keys: vec![Vec::new(), Vec::new(), Vec::new()].into(),
    553            blob_image_handler,
    554            pending_native_surface_updates: Vec::new(),
    555            #[cfg(feature = "capture")]
    556            capture_dirty: true,
    557            image_templates_memory: 0,
    558            font_templates_memory: 0,
    559            render_target_pool: Vec::new(),
    560            fallback_handle: TextureCacheHandle::invalid(),
    561            debug_fallback_panic: false,
    562            debug_fallback_pink: false,
    563        }
    564    }
    565 
    566    /// Construct a resource cache for use in unit tests.
    567    #[cfg(test)]
    568    pub fn new_for_testing() -> Self {
    569        use rayon::ThreadPoolBuilder;
    570 
    571        let texture_cache = TextureCache::new_for_testing(
    572            4096,
    573            ImageFormat::RGBA8,
    574        );
    575        let workers = Arc::new(ThreadPoolBuilder::new().build().unwrap());
    576        let glyph_rasterizer = GlyphRasterizer::new(workers, None, true);
    577        let cached_glyphs = GlyphCache::new();
    578        let fonts = SharedFontResources::new(IdNamespace(0));
    579        let picture_textures = PictureTextures::new(
    580            crate::tile_cache::TILE_SIZE_DEFAULT,
    581            TextureFilter::Nearest,
    582        );
    583 
    584        ResourceCache::new(
    585            texture_cache,
    586            picture_textures,
    587            glyph_rasterizer,
    588            cached_glyphs,
    589            fonts,
    590            None,
    591        )
    592    }
    593 
    594    pub fn max_texture_size(&self) -> i32 {
    595        self.texture_cache.max_texture_size()
    596    }
    597 
    598    /// Maximum texture size before we consider it preferrable to break the texture
    599    /// into tiles.
    600    pub fn tiling_threshold(&self) -> i32 {
    601        self.texture_cache.tiling_threshold()
    602    }
    603 
    604    pub fn enable_multithreading(&mut self, enable: bool) {
    605        self.glyph_rasterizer.enable_multithreading(enable);
    606    }
    607 
    608    fn should_tile(limit: i32, descriptor: &ImageDescriptor, data: &CachedImageData) -> bool {
    609        let size_check = descriptor.size.width > limit || descriptor.size.height > limit;
    610        match *data {
    611            CachedImageData::Raw(_) | CachedImageData::Blob => size_check,
    612            CachedImageData::External(info) => {
    613                // External handles already represent existing textures so it does
    614                // not make sense to tile them into smaller ones.
    615                info.image_type == ExternalImageType::Buffer && size_check
    616            }
    617            CachedImageData::Snapshot => false,
    618        }
    619    }
    620 
    621    /// Request an optionally cacheable render task.
    622    ///
    623    /// If the render task cache key is None, the render task is
    624    /// not cached.
    625    /// Otherwise, if the item is already cached, the texture cache
    626    /// handle will be returned. Otherwise, the user supplied
    627    /// closure will be invoked to generate the render task
    628    /// chain that is required to draw this task.
    629    ///
    630    /// This function takes care of adding the render task as a
    631    /// dependency to its parent task or surface.
    632    pub fn request_render_task(
    633        &mut self,
    634        key: Option<RenderTaskCacheKey>,
    635        is_opaque: bool,
    636        parent: RenderTaskParent,
    637        gpu_buffer_builder: &mut GpuBufferBuilderF,
    638        rg_builder: &mut RenderTaskGraphBuilder,
    639        surface_builder: &mut SurfaceBuilder,
    640        f: &mut dyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> RenderTaskId,
    641    ) -> RenderTaskId {
    642        self.cached_render_tasks.request_render_task(
    643            key.clone(),
    644            &mut self.texture_cache,
    645            is_opaque,
    646            parent,
    647            gpu_buffer_builder,
    648            rg_builder,
    649            surface_builder,
    650            f
    651        )
    652    }
    653 
    654    pub fn render_as_image(
    655        &mut self,
    656        image_key: ImageKey,
    657        size: DeviceIntSize,
    658        rg_builder: &mut RenderTaskGraphBuilder,
    659        gpu_buffer_builder: &mut GpuBufferBuilderF,
    660        is_opaque: bool,
    661        adjustment: &AdjustedImageSource,
    662        f: &mut dyn FnMut(&mut RenderTaskGraphBuilder, &mut GpuBufferBuilderF) -> RenderTaskId,
    663    ) -> RenderTaskId {
    664 
    665        let task_id = f(rg_builder, gpu_buffer_builder);
    666 
    667        let render_task = rg_builder.get_task_mut(task_id);
    668 
    669        // Note: We are defaulting to `ImageRendering::Auto` and only support
    670        // this mode here, because the desired rendering mode is known later
    671        // when an image display item will read the produced snapshot. In theory,
    672        // multiple image items with different rendering modes could refer to
    673        // the snapshot's image key, or they could first appear in a later frame
    674        // So delaying snapshotting logic until the we know about the rendering
    675        // mode would, in addition to adding complexity, only work in certain
    676        // cases.
    677        // If supporting more rendering modes is important for snapshots, we could
    678        // consider specifying it in the stacking context's snapshot params so
    679        // that we have the information early enough.
    680        // Here and in other parts of the code, this restriction manifests itself
    681        // in the expectation that we are dealing with `ImageResult::UntiledAuto`
    682        // which implicitly specifies the rendering mode.
    683 
    684        // Make sure to update the existing image info and texture cache handle
    685        // instead of overwriting them if they already exist for this key.
    686        let image_result = self.cached_images.entry(image_key).or_insert_with(|| {
    687            ImageResult::UntiledAuto(CachedImageInfo {
    688                texture_cache_handle: TextureCacheHandle::invalid(),
    689                dirty_rect: ImageDirtyRect::All,
    690                manual_eviction: true,
    691            })
    692        });
    693 
    694        let ImageResult::UntiledAuto(ref mut info) = *image_result else {
    695            unreachable!("Expected untiled image with auto filter for snapshot");
    696        };
    697 
    698        let flags = if is_opaque {
    699            ImageDescriptorFlags::IS_OPAQUE
    700        } else {
    701            ImageDescriptorFlags::empty()
    702        };
    703 
    704        let descriptor = ImageDescriptor::new(
    705            size.width,
    706            size.height,
    707            self.texture_cache.shared_color_expected_format(),
    708            flags,
    709        );
    710 
    711        // TODO(bug 1975123) We currently do not have a way to ensure that an
    712        // atlas texture used as a destination for the snapshot will not be
    713        // also used as an input by a primitive of the snapshot.
    714        // We can't both read and write the same texture in a draw call
    715        // so we work around it by preventing the snapshot from being placed
    716        // in a texture atlas.
    717        let force_standalone_texture = true;
    718 
    719        // Allocate space in the texture cache, but don't supply
    720        // and CPU-side data to be uploaded.
    721        let user_data = [0.0; 4];
    722        self.texture_cache.update(
    723            &mut info.texture_cache_handle,
    724            descriptor,
    725            TextureFilter::Linear,
    726            None,
    727            user_data,
    728            DirtyRect::All,
    729            gpu_buffer_builder,
    730            None,
    731            render_task.uv_rect_kind(),
    732            Eviction::Manual,
    733            TargetShader::Default,
    734            force_standalone_texture,
    735        );
    736 
    737        // Get the allocation details in the texture cache, and store
    738        // this in the render task. The renderer will draw this task
    739        // into the appropriate rect of the texture cache on this frame.
    740        let (texture_id, uv_rect, _, _, _) =
    741            self.texture_cache.get_cache_location(&info.texture_cache_handle);
    742 
    743        render_task.location = RenderTaskLocation::Static {
    744            surface: StaticRenderTaskSurface::TextureCache {
    745                texture: texture_id,
    746                target_kind: RenderTargetKind::Color,
    747            },
    748            rect: uv_rect.to_i32(),
    749        };
    750 
    751        self.resources.image_templates
    752            .get_mut(image_key)
    753            .unwrap()
    754            .adjustment = *adjustment;
    755 
    756        task_id
    757    }
    758 
    759    pub fn post_scene_building_update(
    760        &mut self,
    761        updates: Vec<ResourceUpdate>,
    762        profile: &mut TransactionProfile,
    763    ) {
    764        // TODO, there is potential for optimization here, by processing updates in
    765        // bulk rather than one by one (for example by sorting allocations by size or
    766        // in a way that reduces fragmentation in the atlas).
    767        #[cfg(feature = "capture")]
    768        match updates.is_empty() {
    769            false => self.capture_dirty = true,
    770            _ => {},
    771        }
    772 
    773        for update in updates {
    774            match update {
    775                ResourceUpdate::AddImage(img) => {
    776                    if let ImageData::Raw(ref bytes) = img.data {
    777                        self.image_templates_memory += bytes.len();
    778                        profile.set(profiler::IMAGE_TEMPLATES_MEM, bytes_to_mb(self.image_templates_memory));
    779                    }
    780                    self.add_image_template(
    781                        img.key,
    782                        img.descriptor,
    783                        img.data.into(),
    784                        &img.descriptor.size.into(),
    785                        img.tiling,
    786                    );
    787                    profile.set(profiler::IMAGE_TEMPLATES, self.resources.image_templates.images.len());
    788                }
    789                ResourceUpdate::UpdateImage(img) => {
    790                    self.update_image_template(img.key, img.descriptor, img.data.into(), &img.dirty_rect);
    791                }
    792                ResourceUpdate::AddBlobImage(img) => {
    793                    self.add_image_template(
    794                        img.key.as_image(),
    795                        img.descriptor,
    796                        CachedImageData::Blob,
    797                        &img.visible_rect,
    798                        Some(img.tile_size),
    799                    );
    800                }
    801                ResourceUpdate::UpdateBlobImage(img) => {
    802                    self.update_image_template(
    803                        img.key.as_image(),
    804                        img.descriptor,
    805                        CachedImageData::Blob,
    806                        &to_image_dirty_rect(
    807                            &img.dirty_rect
    808                        ),
    809                    );
    810                    self.discard_tiles_outside_visible_area(img.key, &img.visible_rect); // TODO: remove?
    811                    self.set_image_visible_rect(img.key.as_image(), &img.visible_rect);
    812                }
    813                ResourceUpdate::DeleteImage(img) => {
    814                    self.delete_image_template(img);
    815                    profile.set(profiler::IMAGE_TEMPLATES, self.resources.image_templates.images.len());
    816                    profile.set(profiler::IMAGE_TEMPLATES_MEM, bytes_to_mb(self.image_templates_memory));
    817                }
    818                ResourceUpdate::DeleteBlobImage(img) => {
    819                    self.delete_image_template(img.as_image());
    820                }
    821                ResourceUpdate::AddSnapshotImage(img) => {
    822                    let format = self.texture_cache.shared_color_expected_format();
    823                    self.add_image_template(
    824                        img.key.as_image(),
    825                        ImageDescriptor {
    826                            format,
    827                            // We'll know about the size when creating the render task.
    828                            size: DeviceIntSize::zero(),
    829                            stride: None,
    830                            offset: 0,
    831                            flags: ImageDescriptorFlags::empty(),
    832                        },
    833                        CachedImageData::Snapshot,
    834                        &DeviceIntRect::zero(),
    835                        None,
    836                    );
    837                }
    838                ResourceUpdate::DeleteSnapshotImage(img) => {
    839                    self.delete_image_template(img.as_image());
    840                }
    841                ResourceUpdate::DeleteFont(font) => {
    842                    if let Some(shared_key) = self.resources.fonts.font_keys.delete_key(&font) {
    843                        self.delete_font_template(shared_key);
    844                        if let Some(ref mut handler) = &mut self.blob_image_handler {
    845                            handler.delete_font(shared_key);
    846                        }
    847                        profile.set(profiler::FONT_TEMPLATES, self.resources.fonts.templates.len());
    848                        profile.set(profiler::FONT_TEMPLATES_MEM, bytes_to_mb(self.font_templates_memory));
    849                    }
    850                }
    851                ResourceUpdate::DeleteFontInstance(font) => {
    852                    if let Some(shared_key) = self.resources.fonts.instance_keys.delete_key(&font) {
    853                        self.delete_font_instance(shared_key);
    854                    }
    855                    if let Some(ref mut handler) = &mut self.blob_image_handler {
    856                        handler.delete_font_instance(font);
    857                    }
    858                }
    859                ResourceUpdate::SetBlobImageVisibleArea(key, area) => {
    860                    self.discard_tiles_outside_visible_area(key, &area);
    861                    self.set_image_visible_rect(key.as_image(), &area);
    862                }
    863                ResourceUpdate::AddFont(font) => {
    864                    // The shared key was already added in ApiResources, but the first time it is
    865                    // seen on the backend we still need to do some extra initialization here.
    866                    let (key, template) = match font {
    867                        AddFont::Raw(key, bytes, index) => {
    868                            (key, FontTemplate::Raw(bytes, index))
    869                        }
    870                        AddFont::Native(key, native_font_handle) => {
    871                            (key, FontTemplate::Native(native_font_handle))
    872                        }
    873                    };
    874                    let shared_key = self.resources.fonts.font_keys.map_key(&key);
    875                    if !self.glyph_rasterizer.has_font(shared_key) {
    876                        self.add_font_template(shared_key, template);
    877                        profile.set(profiler::FONT_TEMPLATES, self.resources.fonts.templates.len());
    878                        profile.set(profiler::FONT_TEMPLATES_MEM, bytes_to_mb(self.font_templates_memory));
    879                    }
    880                }
    881                ResourceUpdate::AddFontInstance(..) => {
    882                    // Already added in ApiResources.
    883                }
    884            }
    885        }
    886    }
    887 
    888    pub fn add_rasterized_blob_images(
    889        &mut self,
    890        images: Vec<(BlobImageRequest, BlobImageResult)>,
    891        profile: &mut TransactionProfile,
    892    ) {
    893        for (request, result) in images {
    894            let data = match result {
    895                Ok(data) => data,
    896                Err(..) => {
    897                    warn!("Failed to rasterize a blob image");
    898                    continue;
    899                }
    900            };
    901 
    902            profile.add(profiler::RASTERIZED_BLOBS_PX, data.rasterized_rect.area());
    903 
    904            // First make sure we have an entry for this key (using a placeholder
    905            // if need be).
    906            let tiles = self.rasterized_blob_images.entry(request.key).or_insert_with(
    907                || { RasterizedBlob::default() }
    908            );
    909 
    910            tiles.insert(request.tile, data);
    911 
    912            match self.cached_images.try_get_mut(&request.key.as_image()) {
    913                Some(&mut ImageResult::Multi(ref mut entries)) => {
    914                    let cached_key = CachedImageKey {
    915                        rendering: ImageRendering::Auto, // TODO(nical)
    916                        tile: Some(request.tile),
    917                    };
    918                    if let Some(entry) = entries.try_get_mut(&cached_key) {
    919                        entry.dirty_rect = DirtyRect::All;
    920                    }
    921                }
    922                _ => {}
    923            }
    924        }
    925    }
    926 
    927    pub fn add_font_template(&mut self, font_key: FontKey, template: FontTemplate) {
    928        // Push the new font to the font renderer, and also store
    929        // it locally for glyph metric requests.
    930        if let FontTemplate::Raw(ref data, _) = template {
    931            self.resources.weak_fonts.insert(Arc::downgrade(data));
    932            self.font_templates_memory += data.len();
    933        }
    934        self.glyph_rasterizer.add_font(font_key, template.clone());
    935        self.resources.fonts.templates.add_font(font_key, template);
    936    }
    937 
    938    pub fn delete_font_template(&mut self, font_key: FontKey) {
    939        self.glyph_rasterizer.delete_font(font_key);
    940        if let Some(FontTemplate::Raw(data, _)) = self.resources.fonts.templates.delete_font(&font_key) {
    941            self.font_templates_memory -= data.len();
    942        }
    943        self.cached_glyphs.delete_fonts(&[font_key]);
    944    }
    945 
    946    pub fn delete_font_instance(&mut self, instance_key: FontInstanceKey) {
    947        self.resources.fonts.instances.delete_font_instance(instance_key);
    948    }
    949 
    950    pub fn get_font_instance(&self, instance_key: FontInstanceKey) -> Option<Arc<BaseFontInstance>> {
    951        self.resources.fonts.instances.get_font_instance(instance_key)
    952    }
    953 
    954    pub fn get_fonts(&self) -> SharedFontResources {
    955        self.resources.fonts.clone()
    956    }
    957 
    958    pub fn add_image_template(
    959        &mut self,
    960        image_key: ImageKey,
    961        descriptor: ImageDescriptor,
    962        data: CachedImageData,
    963        visible_rect: &DeviceIntRect,
    964        mut tiling: Option<TileSize>,
    965    ) {
    966        if let Some(ref mut tile_size) = tiling {
    967            // Sanitize the value since it can be set by a pref.
    968            *tile_size = (*tile_size).max(16).min(2048);
    969        }
    970 
    971        if tiling.is_none() && Self::should_tile(self.tiling_threshold(), &descriptor, &data) {
    972            // We aren't going to be able to upload a texture this big, so tile it, even
    973            // if tiling was not requested.
    974            tiling = Some(DEFAULT_TILE_SIZE);
    975        }
    976 
    977        let resource = ImageResource {
    978            descriptor,
    979            data,
    980            tiling,
    981            visible_rect: *visible_rect,
    982            adjustment: AdjustedImageSource::new(),
    983            generation: ImageGeneration(0),
    984        };
    985 
    986        self.resources.image_templates.insert(image_key, resource);
    987    }
    988 
    989    pub fn update_image_template(
    990        &mut self,
    991        image_key: ImageKey,
    992        descriptor: ImageDescriptor,
    993        data: CachedImageData,
    994        dirty_rect: &ImageDirtyRect,
    995    ) {
    996        let tiling_threshold = self.tiling_threshold();
    997        let image = match self.resources.image_templates.get_mut(image_key) {
    998            Some(res) => res,
    999            None => panic!("Attempt to update non-existent image"),
   1000        };
   1001 
   1002        let mut tiling = image.tiling;
   1003        if tiling.is_none() && Self::should_tile(tiling_threshold, &descriptor, &data) {
   1004            tiling = Some(DEFAULT_TILE_SIZE);
   1005        }
   1006 
   1007        // Each cache entry stores its own copy of the image's dirty rect. This allows them to be
   1008        // updated independently.
   1009        match self.cached_images.try_get_mut(&image_key) {
   1010            Some(&mut ImageResult::UntiledAuto(ref mut entry)) => {
   1011                entry.dirty_rect = entry.dirty_rect.union(dirty_rect);
   1012            }
   1013            Some(&mut ImageResult::Multi(ref mut entries)) => {
   1014                for (key, entry) in entries.iter_mut() {
   1015                    // We want the dirty rect relative to the tile and not the whole image.
   1016                    let local_dirty_rect = match (tiling, key.tile) {
   1017                        (Some(tile_size), Some(tile)) => {
   1018                            dirty_rect.map(|mut rect|{
   1019                                let tile_offset = DeviceIntPoint::new(
   1020                                    tile.x as i32,
   1021                                    tile.y as i32,
   1022                                ) * tile_size as i32;
   1023                                rect = rect.translate(-tile_offset.to_vector());
   1024 
   1025                                let tile_rect = compute_tile_size(
   1026                                    &descriptor.size.into(),
   1027                                    tile_size,
   1028                                    tile,
   1029                                ).into();
   1030 
   1031                                rect.intersection(&tile_rect).unwrap_or_else(DeviceIntRect::zero)
   1032                            })
   1033                        }
   1034                        (None, Some(..)) => DirtyRect::All,
   1035                        _ => *dirty_rect,
   1036                    };
   1037                    entry.dirty_rect = entry.dirty_rect.union(&local_dirty_rect);
   1038                }
   1039            }
   1040            _ => {}
   1041        }
   1042 
   1043        if image.descriptor.format != descriptor.format {
   1044            // could be a stronger warning/error?
   1045            trace!("Format change {:?} -> {:?}", image.descriptor.format, descriptor.format);
   1046        }
   1047        *image = ImageResource {
   1048            descriptor,
   1049            data,
   1050            tiling,
   1051            visible_rect: descriptor.size.into(),
   1052            adjustment: AdjustedImageSource::new(),
   1053            generation: ImageGeneration(image.generation.0 + 1),
   1054        };
   1055    }
   1056 
   1057    pub fn increment_image_generation(&mut self, key: ImageKey) {
   1058        if let Some(image) = self.resources.image_templates.get_mut(key) {
   1059            image.generation.0 += 1;
   1060        }
   1061    }
   1062 
   1063    pub fn delete_image_template(&mut self, image_key: ImageKey) {
   1064        // Remove the template.
   1065        let value = self.resources.image_templates.remove(image_key);
   1066 
   1067        // Release the corresponding texture cache entry, if any.
   1068        if let Some(mut cached) = self.cached_images.remove(&image_key) {
   1069            cached.drop_from_cache(&mut self.texture_cache);
   1070        }
   1071 
   1072        match value {
   1073            Some(image) => if image.data.is_blob() {
   1074                if let CachedImageData::Raw(data) = image.data {
   1075                    self.image_templates_memory -= data.len();
   1076                }
   1077 
   1078                let blob_key = BlobImageKey(image_key);
   1079                self.deleted_blob_keys.back_mut().unwrap().push(blob_key);
   1080                self.rasterized_blob_images.remove(&blob_key);
   1081            },
   1082            None => {
   1083                warn!("Delete the non-exist key");
   1084                debug!("key={:?}", image_key);
   1085            }
   1086        }
   1087    }
   1088 
   1089    /// Return the current generation of an image template
   1090    pub fn get_image_generation(&self, key: ImageKey) -> ImageGeneration {
   1091        self.resources
   1092            .image_templates
   1093            .get(key)
   1094            .map_or(ImageGeneration::INVALID, |template| template.generation)
   1095    }
   1096 
   1097    /// Requests an image to ensure that it will be in the texture cache this frame.
   1098    ///
   1099    /// returns the size in device pixel of the image or tile.
   1100    pub fn request_image(
   1101        &mut self,
   1102        mut request: ImageRequest,
   1103        gpu_buffer: &mut GpuBufferBuilderF,
   1104    ) -> DeviceIntSize {
   1105        debug_assert_eq!(self.state, State::AddResources);
   1106 
   1107        let template = match self.resources.image_templates.get(request.key) {
   1108            Some(template) => template,
   1109            None => {
   1110                warn!("ERROR: Trying to render deleted / non-existent key");
   1111                debug!("key={:?}", request.key);
   1112                return DeviceIntSize::zero();
   1113            }
   1114        };
   1115 
   1116        let size = match request.tile {
   1117            Some(tile) => compute_tile_size(&template.visible_rect, template.tiling.unwrap(), tile),
   1118            None => template.descriptor.size,
   1119        };
   1120 
   1121        // Images that don't use the texture cache can early out.
   1122        if !template.data.uses_texture_cache() {
   1123            return size;
   1124        }
   1125 
   1126        if template.data.is_snapshot() {
   1127            // We only Support `Auto` for snapshots. This is because we have
   1128            // to make the decision about the filtering mode earlier when
   1129            // producing the snapshot.
   1130            // See the comment at the top of `render_as_image`.
   1131            request.rendering = ImageRendering::Auto;
   1132        }
   1133 
   1134        let side_size =
   1135            template.tiling.map_or(cmp::max(template.descriptor.size.width, template.descriptor.size.height),
   1136                                   |tile_size| tile_size as i32);
   1137        if side_size > self.texture_cache.max_texture_size() {
   1138            // The image or tiling size is too big for hardware texture size.
   1139            warn!("Dropping image, image:(w:{},h:{}, tile:{}) is too big for hardware!",
   1140                  template.descriptor.size.width, template.descriptor.size.height, template.tiling.unwrap_or(0));
   1141            self.cached_images.insert(request.key, ImageResult::Err(ImageCacheError::OverLimitSize));
   1142            return DeviceIntSize::zero();
   1143        }
   1144 
   1145        let storage = match self.cached_images.entry(request.key) {
   1146            Occupied(e) => {
   1147                // We might have an existing untiled entry, and need to insert
   1148                // a second entry. In such cases we need to move the old entry
   1149                // out first, replacing it with a dummy entry, and then creating
   1150                // the tiled/multi-entry variant.
   1151                let entry = e.into_mut();
   1152                if !request.is_untiled_auto() {
   1153                    let untiled_entry = match entry {
   1154                        &mut ImageResult::UntiledAuto(ref mut entry) => {
   1155                            Some(mem::replace(entry, CachedImageInfo {
   1156                                texture_cache_handle: TextureCacheHandle::invalid(),
   1157                                dirty_rect: DirtyRect::All,
   1158                                manual_eviction: false,
   1159                            }))
   1160                        }
   1161                        _ => None
   1162                    };
   1163 
   1164                    if let Some(untiled_entry) = untiled_entry {
   1165                        let mut entries = ResourceClassCache::new();
   1166                        let untiled_key = CachedImageKey {
   1167                            rendering: ImageRendering::Auto,
   1168                            tile: None,
   1169                        };
   1170                        entries.insert(untiled_key, untiled_entry);
   1171                        *entry = ImageResult::Multi(entries);
   1172                    }
   1173                }
   1174                entry
   1175            }
   1176            Vacant(entry) => {
   1177                entry.insert(if request.is_untiled_auto() {
   1178                    ImageResult::UntiledAuto(CachedImageInfo {
   1179                        texture_cache_handle: TextureCacheHandle::invalid(),
   1180                        dirty_rect: DirtyRect::All,
   1181                        manual_eviction: false,
   1182                    })
   1183                } else {
   1184                    ImageResult::Multi(ResourceClassCache::new())
   1185                })
   1186            }
   1187        };
   1188 
   1189        // If this image exists in the texture cache, *and* the dirty rect
   1190        // in the cache is empty, then it is valid to use as-is.
   1191        let entry = match *storage {
   1192            ImageResult::UntiledAuto(ref mut entry) => entry,
   1193            ImageResult::Multi(ref mut entries) => {
   1194                entries.entry(request.into())
   1195                    .or_insert(CachedImageInfo {
   1196                        texture_cache_handle: TextureCacheHandle::invalid(),
   1197                        dirty_rect: DirtyRect::All,
   1198                        manual_eviction: false,
   1199                    })
   1200            },
   1201            ImageResult::Err(_) => panic!("Errors should already have been handled"),
   1202        };
   1203 
   1204        let needs_upload = self.texture_cache.request(&entry.texture_cache_handle, gpu_buffer);
   1205 
   1206        if !needs_upload && entry.dirty_rect.is_empty() {
   1207            return size;
   1208        }
   1209 
   1210        if !self.pending_image_requests.insert(request) {
   1211            return size;
   1212        }
   1213 
   1214        if template.data.is_blob() {
   1215            let request: BlobImageRequest = request.into();
   1216            let missing = match self.rasterized_blob_images.get(&request.key) {
   1217                Some(tiles) => !tiles.contains_key(&request.tile),
   1218                _ => true,
   1219            };
   1220 
   1221            assert!(!missing);
   1222        }
   1223 
   1224        size
   1225    }
   1226 
   1227    fn discard_tiles_outside_visible_area(
   1228        &mut self,
   1229        key: BlobImageKey,
   1230        area: &DeviceIntRect
   1231    ) {
   1232        let tile_size = match self.resources.image_templates.get(key.as_image()) {
   1233            Some(template) => template.tiling.unwrap(),
   1234            None => {
   1235                //debug!("Missing image template (key={:?})!", key);
   1236                return;
   1237            }
   1238        };
   1239 
   1240        let tiles = match self.rasterized_blob_images.get_mut(&key) {
   1241            Some(tiles) => tiles,
   1242            _ => { return; }
   1243        };
   1244 
   1245        let tile_range = compute_tile_range(
   1246            &area,
   1247            tile_size,
   1248        );
   1249 
   1250        tiles.retain(|tile, _| { tile_range.contains(*tile) });
   1251 
   1252        let texture_cache = &mut self.texture_cache;
   1253        match self.cached_images.try_get_mut(&key.as_image()) {
   1254            Some(&mut ImageResult::Multi(ref mut entries)) => {
   1255                entries.retain(|key, entry| {
   1256                    if key.tile.is_none() || tile_range.contains(key.tile.unwrap()) {
   1257                        return true;
   1258                    }
   1259                    entry.mark_unused(texture_cache);
   1260                    return false;
   1261                });
   1262            }
   1263            _ => {}
   1264        }
   1265    }
   1266 
   1267    fn set_image_visible_rect(&mut self, key: ImageKey, rect: &DeviceIntRect) {
   1268        if let Some(image) = self.resources.image_templates.get_mut(key) {
   1269            image.visible_rect = *rect;
   1270            image.descriptor.size = rect.size();
   1271        }
   1272    }
   1273 
   1274    pub fn request_glyphs(
   1275        &mut self,
   1276        mut font: FontInstance,
   1277        glyph_keys: &[GlyphKey],
   1278        gpu_buffer: &mut GpuBufferBuilderF,
   1279    ) {
   1280        debug_assert_eq!(self.state, State::AddResources);
   1281 
   1282        self.glyph_rasterizer.prepare_font(&mut font);
   1283        let glyph_key_cache = self.cached_glyphs.insert_glyph_key_cache_for_font(&font);
   1284        let texture_cache = &mut self.texture_cache;
   1285        self.glyph_rasterizer.request_glyphs(
   1286            font,
   1287            glyph_keys,
   1288            |key| {
   1289                let cache_key = key.cache_key();
   1290                if let Some(entry) = glyph_key_cache.try_get(&cache_key) {
   1291                    match entry {
   1292                        GlyphCacheEntry::Cached(ref glyph) => {
   1293                            if !texture_cache.request(&glyph.texture_cache_handle, gpu_buffer) {
   1294                                return false;
   1295                            }
   1296                            // This case gets hit when we already rasterized the glyph, but the
   1297                            // glyph has been evicted from the texture cache. Just force it to
   1298                            // pending so it gets rematerialized.
   1299                        }
   1300                        // Otherwise, skip the entry if it is blank or pending.
   1301                        GlyphCacheEntry::Blank | GlyphCacheEntry::Pending => return false,
   1302                    }
   1303                };
   1304 
   1305                glyph_key_cache.add_glyph(cache_key, GlyphCacheEntry::Pending);
   1306 
   1307                true
   1308            }
   1309        );
   1310    }
   1311 
   1312    pub fn pending_updates(&mut self) -> ResourceUpdateList {
   1313        ResourceUpdateList {
   1314            texture_updates: self.texture_cache.pending_updates(),
   1315            native_surface_updates: mem::replace(&mut self.pending_native_surface_updates, Vec::new()),
   1316        }
   1317    }
   1318 
   1319    pub fn fetch_glyphs<F>(
   1320        &self,
   1321        mut font: FontInstance,
   1322        glyph_keys: &[GlyphKey],
   1323        gpu_buffer: &GpuBufferBuilderF,
   1324        fetch_buffer: &mut Vec<GlyphFetchResult>,
   1325        mut f: F,
   1326    ) where
   1327        F: FnMut(TextureSource, GlyphFormat, &[GlyphFetchResult]),
   1328    {
   1329        debug_assert_eq!(self.state, State::QueryResources);
   1330 
   1331        self.glyph_rasterizer.prepare_font(&mut font);
   1332        let glyph_key_cache = self.cached_glyphs.get_glyph_key_cache_for_font(&font);
   1333 
   1334        let mut current_texture_id = TextureSource::Invalid;
   1335        let mut current_glyph_format = GlyphFormat::Subpixel;
   1336        debug_assert!(fetch_buffer.is_empty());
   1337 
   1338        for (loop_index, key) in glyph_keys.iter().enumerate() {
   1339            let cache_key = key.cache_key();
   1340            let (cache_item, glyph_format, is_packed_glyph) = match *glyph_key_cache.get(&cache_key) {
   1341                GlyphCacheEntry::Cached(ref glyph) => {
   1342                    (self.texture_cache.get(&glyph.texture_cache_handle), glyph.format, glyph.is_packed_glyph)
   1343                }
   1344                GlyphCacheEntry::Blank | GlyphCacheEntry::Pending => continue,
   1345            };
   1346            if current_texture_id != cache_item.texture_id ||
   1347                current_glyph_format != glyph_format {
   1348                if !fetch_buffer.is_empty() {
   1349                    f(current_texture_id, current_glyph_format, fetch_buffer);
   1350                    fetch_buffer.clear();
   1351                }
   1352                current_texture_id = cache_item.texture_id;
   1353                current_glyph_format = glyph_format;
   1354            }
   1355            let (subpx_offset_x, subpx_offset_y) = key.subpixel_offset();
   1356            fetch_buffer.push(GlyphFetchResult {
   1357                index_in_text_run: loop_index as i32,
   1358                uv_rect_address: gpu_buffer.resolve_handle(cache_item.uv_rect_handle),
   1359                offset: DevicePoint::new(cache_item.user_data[0], cache_item.user_data[1]),
   1360                size: cache_item.uv_rect.size(),
   1361                scale: cache_item.user_data[2],
   1362                subpx_offset_x: subpx_offset_x as u8,
   1363                subpx_offset_y: subpx_offset_y as u8,
   1364                is_packed_glyph,
   1365            });
   1366        }
   1367 
   1368        if !fetch_buffer.is_empty() {
   1369            f(current_texture_id, current_glyph_format, fetch_buffer);
   1370            fetch_buffer.clear();
   1371        }
   1372    }
   1373 
   1374    pub fn map_font_key(&self, key: FontKey) -> FontKey {
   1375        self.resources.fonts.font_keys.map_key(&key)
   1376    }
   1377 
   1378    pub fn map_font_instance_key(&self, key: FontInstanceKey) -> FontInstanceKey {
   1379        self.resources.fonts.instance_keys.map_key(&key)
   1380    }
   1381 
   1382    pub fn get_glyph_dimensions(
   1383        &mut self,
   1384        font: &FontInstance,
   1385        glyph_index: GlyphIndex,
   1386    ) -> Option<GlyphDimensions> {
   1387        match self.cached_glyph_dimensions.entry((font.instance_key, glyph_index)) {
   1388            Occupied(entry) => *entry.get(),
   1389            Vacant(entry) => *entry.insert(
   1390                self.glyph_rasterizer
   1391                    .get_glyph_dimensions(font, glyph_index),
   1392            ),
   1393        }
   1394    }
   1395 
   1396    pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
   1397        self.glyph_rasterizer.get_glyph_index(font_key, ch)
   1398    }
   1399 
   1400    #[inline]
   1401    pub fn get_cached_image(&self, request: ImageRequest) -> Result<CacheItem, ()> {
   1402        debug_assert_eq!(self.state, State::QueryResources);
   1403        let image_info = self.get_image_info(request)?;
   1404 
   1405        if let Ok(item) = self.get_texture_cache_item(&image_info.texture_cache_handle) {
   1406            // Common path.
   1407            return Ok(item);
   1408        }
   1409 
   1410        if self.resources.image_templates
   1411            .get(request.key)
   1412            .map_or(false, |img| img.data.is_snapshot()) {
   1413            if self.debug_fallback_panic {
   1414                panic!("Missing snapshot image");
   1415            }
   1416            return self.get_texture_cache_item(&self.fallback_handle);
   1417        }
   1418 
   1419        panic!("Requested image missing from the texture cache");
   1420    }
   1421 
   1422    pub fn get_cached_render_task(
   1423        &self,
   1424        handle: &RenderTaskCacheEntryHandle,
   1425    ) -> &RenderTaskCacheEntry {
   1426        self.cached_render_tasks.get_cache_entry(handle)
   1427    }
   1428 
   1429    #[inline]
   1430    fn get_image_info(&self, request: ImageRequest) -> Result<&CachedImageInfo, ()> {
   1431        // TODO(Jerry): add a debug option to visualize the corresponding area for
   1432        // the Err() case of CacheItem.
   1433        match *self.cached_images.get(&request.key) {
   1434            ImageResult::UntiledAuto(ref image_info) => Ok(image_info),
   1435            ImageResult::Multi(ref entries) => Ok(entries.get(&request.into())),
   1436            ImageResult::Err(_) => Err(()),
   1437        }
   1438    }
   1439 
   1440    #[inline]
   1441    pub fn get_texture_cache_item(&self, handle: &TextureCacheHandle) -> Result<CacheItem, ()> {
   1442        if let Some(item) = self.texture_cache.try_get(handle) {
   1443            return Ok(item);
   1444        }
   1445 
   1446        Err(())
   1447    }
   1448 
   1449    pub fn get_image_properties(&self, image_key: ImageKey) -> Option<ImageProperties> {
   1450        let image_template = &self.resources.image_templates.get(image_key);
   1451 
   1452        image_template.map(|image_template| {
   1453            let external_image = match image_template.data {
   1454                CachedImageData::External(ext_image) => match ext_image.image_type {
   1455                    ExternalImageType::TextureHandle(_) => Some(ext_image),
   1456                    // external buffer uses resource_cache.
   1457                    ExternalImageType::Buffer => None,
   1458                },
   1459                // raw and blob image are all using resource_cache.
   1460                CachedImageData::Raw(..)
   1461                | CachedImageData::Blob
   1462                | CachedImageData::Snapshot
   1463                 => None,
   1464            };
   1465 
   1466            ImageProperties {
   1467                descriptor: image_template.descriptor,
   1468                external_image,
   1469                tiling: image_template.tiling,
   1470                visible_rect: image_template.visible_rect,
   1471                adjustment: image_template.adjustment,
   1472            }
   1473        })
   1474    }
   1475 
   1476    pub fn begin_frame(&mut self, stamp: FrameStamp, profile: &mut TransactionProfile) {
   1477        profile_scope!("begin_frame");
   1478        debug_assert_eq!(self.state, State::Idle);
   1479        self.state = State::AddResources;
   1480        self.texture_cache.begin_frame(stamp, profile);
   1481        self.picture_textures.begin_frame(stamp, &mut self.texture_cache.pending_updates);
   1482 
   1483        self.cached_glyphs.begin_frame(
   1484            stamp,
   1485            &mut self.texture_cache,
   1486            &mut self.glyph_rasterizer,
   1487        );
   1488        self.cached_render_tasks.begin_frame(&mut self.texture_cache);
   1489        self.current_frame_id = stamp.frame_id();
   1490 
   1491        // Pop the old frame and push a new one.
   1492        // Recycle the allocation if any.
   1493        let mut v = self.deleted_blob_keys.pop_front().unwrap_or_else(Vec::new);
   1494        v.clear();
   1495        self.deleted_blob_keys.push_back(v);
   1496 
   1497        self.texture_cache.run_compaction();
   1498    }
   1499 
   1500    pub fn block_until_all_resources_added(
   1501        &mut self,
   1502        gpu_buffer: &mut GpuBufferBuilder,
   1503        profile: &mut TransactionProfile,
   1504    ) {
   1505        profile_scope!("block_until_all_resources_added");
   1506 
   1507        debug_assert_eq!(self.state, State::AddResources);
   1508        self.state = State::QueryResources;
   1509 
   1510        let cached_glyphs = &mut self.cached_glyphs;
   1511        let texture_cache = &mut self.texture_cache;
   1512 
   1513        self.glyph_rasterizer.resolve_glyphs(
   1514            |job, can_use_r8_format| {
   1515                let GlyphRasterJob { font, key, result } = job;
   1516                let cache_key = key.cache_key();
   1517                let glyph_key_cache = cached_glyphs.get_glyph_key_cache_for_font_mut(&*font);
   1518                let glyph_info = match result {
   1519                    Err(_) => GlyphCacheEntry::Blank,
   1520                    Ok(ref glyph) if glyph.width == 0 || glyph.height == 0 => {
   1521                        GlyphCacheEntry::Blank
   1522                    }
   1523                    Ok(glyph) => {
   1524                        let mut texture_cache_handle = TextureCacheHandle::invalid();
   1525                        texture_cache.request(&texture_cache_handle, &mut gpu_buffer.f32);
   1526                        texture_cache.update(
   1527                            &mut texture_cache_handle,
   1528                            ImageDescriptor {
   1529                                size: size2(glyph.width, glyph.height),
   1530                                stride: None,
   1531                                format: glyph.format.image_format(can_use_r8_format),
   1532                                flags: ImageDescriptorFlags::empty(),
   1533                                offset: 0,
   1534                            },
   1535                            TextureFilter::Linear,
   1536                            Some(CachedImageData::Raw(Arc::new(glyph.bytes))),
   1537                            [glyph.left, -glyph.top, glyph.scale, 0.0],
   1538                            DirtyRect::All,
   1539                            &mut gpu_buffer.f32,
   1540                            Some(glyph_key_cache.eviction_notice()),
   1541                            UvRectKind::Rect,
   1542                            Eviction::Auto,
   1543                            TargetShader::Text,
   1544                            false,
   1545                        );
   1546                        GlyphCacheEntry::Cached(CachedGlyphInfo {
   1547                            texture_cache_handle,
   1548                            format: glyph.format,
   1549                            is_packed_glyph: glyph.is_packed_glyph,
   1550                        })
   1551                    }
   1552                };
   1553                glyph_key_cache.insert(cache_key, glyph_info);
   1554            },
   1555            profile,
   1556        );
   1557 
   1558        // Apply any updates of new / updated images (incl. blobs) to the texture cache.
   1559        self.update_texture_cache(gpu_buffer);
   1560    }
   1561 
   1562    fn update_texture_cache(&mut self, gpu_buffer: &mut GpuBufferBuilder) {
   1563        profile_scope!("update_texture_cache");
   1564 
   1565        if self.fallback_handle == TextureCacheHandle::invalid() {
   1566            let fallback_color = if self.debug_fallback_pink {
   1567                vec![255, 0, 255, 255]
   1568            } else {
   1569                vec![0, 0, 0, 0]
   1570            };
   1571            self.texture_cache.update(
   1572                &mut self.fallback_handle,
   1573                ImageDescriptor {
   1574                    size: size2(1, 1),
   1575                    stride: None,
   1576                    format: ImageFormat::BGRA8,
   1577                    flags: ImageDescriptorFlags::empty(),
   1578                    offset: 0,
   1579                },
   1580                TextureFilter::Linear,
   1581                Some(CachedImageData::Raw(Arc::new(fallback_color))),
   1582                [0.0; 4],
   1583                DirtyRect::All,
   1584                &mut gpu_buffer.f32,
   1585                None,
   1586                UvRectKind::Rect,
   1587                Eviction::Manual,
   1588                TargetShader::Default,
   1589                false,
   1590            );
   1591        }
   1592 
   1593        for request in self.pending_image_requests.drain() {
   1594            let image_template = self.resources.image_templates.get_mut(request.key).unwrap();
   1595            debug_assert!(image_template.data.uses_texture_cache());
   1596 
   1597            let mut updates: SmallVec<[(CachedImageData, Option<DeviceIntRect>); 1]> = SmallVec::new();
   1598 
   1599            match image_template.data {
   1600                CachedImageData::Snapshot => {
   1601                    // The update is done in ResourceCache::render_as_image.
   1602                }
   1603                CachedImageData::Raw(..)
   1604                | CachedImageData::External(..) => {
   1605                    // Safe to clone here since the Raw image data is an
   1606                    // Arc, and the external image data is small.
   1607                    updates.push((image_template.data.clone(), None));
   1608                }
   1609                CachedImageData::Blob => {
   1610                    let blob_image = self.rasterized_blob_images.get_mut(&BlobImageKey(request.key)).unwrap();
   1611                    let img = &blob_image[&request.tile.unwrap()];
   1612                    updates.push((
   1613                        CachedImageData::Raw(Arc::clone(&img.data)),
   1614                        Some(img.rasterized_rect)
   1615                    ));
   1616                }
   1617            };
   1618 
   1619            for (image_data, blob_rasterized_rect) in updates {
   1620                let entry = match *self.cached_images.get_mut(&request.key) {
   1621                    ImageResult::UntiledAuto(ref mut entry) => entry,
   1622                    ImageResult::Multi(ref mut entries) => entries.get_mut(&request.into()),
   1623                    ImageResult::Err(_) => panic!("Update requested for invalid entry")
   1624                };
   1625 
   1626                let mut descriptor = image_template.descriptor.clone();
   1627                let mut dirty_rect = entry.dirty_rect.replace_with_empty();
   1628 
   1629                if let Some(tile) = request.tile {
   1630                    let tile_size = image_template.tiling.unwrap();
   1631                    let clipped_tile_size = compute_tile_size(&image_template.visible_rect, tile_size, tile);
   1632                    // The tiled image could be stored on the CPU as one large image or be
   1633                    // already broken up into tiles. This affects the way we compute the stride
   1634                    // and offset.
   1635                    let tiled_on_cpu = image_template.data.is_blob();
   1636                    if !tiled_on_cpu {
   1637                        // we don't expect to have partial tiles at the top and left of non-blob
   1638                        // images.
   1639                        debug_assert_eq!(image_template.visible_rect.min, point2(0, 0));
   1640                        let bpp = descriptor.format.bytes_per_pixel();
   1641                        let stride = descriptor.compute_stride();
   1642                        descriptor.stride = Some(stride);
   1643                        descriptor.offset +=
   1644                            tile.y as i32 * tile_size as i32 * stride +
   1645                            tile.x as i32 * tile_size as i32 * bpp;
   1646                    }
   1647 
   1648                    descriptor.size = clipped_tile_size;
   1649                }
   1650 
   1651                // If we are uploading the dirty region of a blob image we might have several
   1652                // rects to upload so we use each of these rasterized rects rather than the
   1653                // overall dirty rect of the image.
   1654                if let Some(rect) = blob_rasterized_rect {
   1655                    dirty_rect = DirtyRect::Partial(rect);
   1656                }
   1657 
   1658                let filter = match request.rendering {
   1659                    ImageRendering::Pixelated => {
   1660                        TextureFilter::Nearest
   1661                    }
   1662                    ImageRendering::Auto | ImageRendering::CrispEdges => {
   1663                        // If the texture uses linear filtering, enable mipmaps and
   1664                        // trilinear filtering, for better image quality. We only
   1665                        // support this for now on textures that are not placed
   1666                        // into the shared cache. This accounts for any image
   1667                        // that is > 512 in either dimension, so it should cover
   1668                        // the most important use cases. We may want to support
   1669                        // mip-maps on shared cache items in the future.
   1670                        if descriptor.allow_mipmaps() &&
   1671                           descriptor.size.width > 512 &&
   1672                           descriptor.size.height > 512 &&
   1673                           !self.texture_cache.is_allowed_in_shared_cache(
   1674                            TextureFilter::Linear,
   1675                            &descriptor,
   1676                        ) {
   1677                            TextureFilter::Trilinear
   1678                        } else {
   1679                            TextureFilter::Linear
   1680                        }
   1681                    }
   1682                };
   1683 
   1684                let eviction = match &image_template.data {
   1685                    CachedImageData::Blob | CachedImageData::Snapshot => {
   1686                        entry.manual_eviction = true;
   1687                        Eviction::Manual
   1688                    }
   1689                    _ => {
   1690                        Eviction::Auto
   1691                    }
   1692                };
   1693 
   1694                //Note: at this point, the dirty rectangle is local to the descriptor space
   1695                self.texture_cache.update(
   1696                    &mut entry.texture_cache_handle,
   1697                    descriptor,
   1698                    filter,
   1699                    Some(image_data),
   1700                    [0.0; 4],
   1701                    dirty_rect,
   1702                    &mut gpu_buffer.f32,
   1703                    None,
   1704                    UvRectKind::Rect,
   1705                    eviction,
   1706                    TargetShader::Default,
   1707                    false,
   1708                );
   1709            }
   1710        }
   1711    }
   1712 
   1713    pub fn create_compositor_backdrop_surface(
   1714        &mut self,
   1715        color: ColorF
   1716    ) -> NativeSurfaceId {
   1717        let id = NativeSurfaceId(NEXT_NATIVE_SURFACE_ID.fetch_add(1, Ordering::Relaxed) as u64);
   1718 
   1719        self.pending_native_surface_updates.push(
   1720            NativeSurfaceOperation {
   1721                details: NativeSurfaceOperationDetails::CreateBackdropSurface {
   1722                    id,
   1723                    color,
   1724                },
   1725            }
   1726        );
   1727 
   1728        id
   1729    }
   1730 
   1731    /// Queue up allocation of a new OS native compositor surface with the
   1732    /// specified tile size.
   1733    pub fn create_compositor_surface(
   1734        &mut self,
   1735        virtual_offset: DeviceIntPoint,
   1736        tile_size: DeviceIntSize,
   1737        is_opaque: bool,
   1738    ) -> NativeSurfaceId {
   1739        let id = NativeSurfaceId(NEXT_NATIVE_SURFACE_ID.fetch_add(1, Ordering::Relaxed) as u64);
   1740 
   1741        self.pending_native_surface_updates.push(
   1742            NativeSurfaceOperation {
   1743                details: NativeSurfaceOperationDetails::CreateSurface {
   1744                    id,
   1745                    virtual_offset,
   1746                    tile_size,
   1747                    is_opaque,
   1748                },
   1749            }
   1750        );
   1751 
   1752        id
   1753    }
   1754 
   1755    pub fn create_compositor_external_surface(
   1756        &mut self,
   1757        is_opaque: bool,
   1758    ) -> NativeSurfaceId {
   1759        let id = NativeSurfaceId(NEXT_NATIVE_SURFACE_ID.fetch_add(1, Ordering::Relaxed) as u64);
   1760 
   1761        self.pending_native_surface_updates.push(
   1762            NativeSurfaceOperation {
   1763                details: NativeSurfaceOperationDetails::CreateExternalSurface {
   1764                    id,
   1765                    is_opaque,
   1766                },
   1767            }
   1768        );
   1769 
   1770        id
   1771    }
   1772 
   1773    /// Queue up destruction of an existing native OS surface. This is used when
   1774    /// a picture cache surface is dropped or resized.
   1775    pub fn destroy_compositor_surface(
   1776        &mut self,
   1777        id: NativeSurfaceId,
   1778    ) {
   1779        self.pending_native_surface_updates.push(
   1780            NativeSurfaceOperation {
   1781                details: NativeSurfaceOperationDetails::DestroySurface {
   1782                    id,
   1783                }
   1784            }
   1785        );
   1786    }
   1787 
   1788    /// Queue construction of a native compositor tile on a given surface.
   1789    pub fn create_compositor_tile(
   1790        &mut self,
   1791        id: NativeTileId,
   1792    ) {
   1793        self.pending_native_surface_updates.push(
   1794            NativeSurfaceOperation {
   1795                details: NativeSurfaceOperationDetails::CreateTile {
   1796                    id,
   1797                },
   1798            }
   1799        );
   1800    }
   1801 
   1802    /// Queue destruction of a native compositor tile.
   1803    pub fn destroy_compositor_tile(
   1804        &mut self,
   1805        id: NativeTileId,
   1806    ) {
   1807        self.pending_native_surface_updates.push(
   1808            NativeSurfaceOperation {
   1809                details: NativeSurfaceOperationDetails::DestroyTile {
   1810                    id,
   1811                },
   1812            }
   1813        );
   1814    }
   1815 
   1816    pub fn attach_compositor_external_image(
   1817        &mut self,
   1818        id: NativeSurfaceId,
   1819        external_image: ExternalImageId,
   1820    ) {
   1821        self.pending_native_surface_updates.push(
   1822            NativeSurfaceOperation {
   1823                details: NativeSurfaceOperationDetails::AttachExternalImage {
   1824                    id,
   1825                    external_image,
   1826                },
   1827            }
   1828        );
   1829    }
   1830 
   1831 
   1832    pub fn end_frame(&mut self, profile: &mut TransactionProfile) {
   1833        debug_assert_eq!(self.state, State::QueryResources);
   1834        profile_scope!("end_frame");
   1835        self.state = State::Idle;
   1836 
   1837        // GC the render target pool, if it's currently > 64 MB in size.
   1838        //
   1839        // We use a simple scheme whereby we drop any texture that hasn't been used
   1840        // in the last 60 frames, until we are below the size threshold. This should
   1841        // generally prevent any sustained build-up of unused textures, unless we don't
   1842        // generate frames for a long period. This can happen when the window is
   1843        // minimized, and we probably want to flush all the WebRender caches in that case [1].
   1844        // There is also a second "red line" memory threshold which prevents
   1845        // memory exhaustion if many render targets are allocated within a small
   1846        // number of frames. For now this is set at 320 MB (10x the normal memory threshold).
   1847        //
   1848        // [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1494099
   1849        self.gc_render_targets(
   1850            64 * 1024 * 1024,
   1851            32 * 1024 * 1024 * 10,
   1852            60,
   1853        );
   1854 
   1855        self.texture_cache.end_frame(profile);
   1856        self.picture_textures.gc(
   1857            &mut self.texture_cache.pending_updates,
   1858        );
   1859 
   1860        self.picture_textures.update_profile(profile);
   1861    }
   1862 
   1863    pub fn set_debug_flags(&mut self, flags: DebugFlags) {
   1864        GLYPH_FLASHING.store(flags.contains(DebugFlags::GLYPH_FLASHING), std::sync::atomic::Ordering::Relaxed);
   1865        self.texture_cache.set_debug_flags(flags);
   1866        self.picture_textures.set_debug_flags(flags);
   1867        self.debug_fallback_panic = flags.contains(DebugFlags::MISSING_SNAPSHOT_PANIC);
   1868        let fallback_pink = flags.contains(DebugFlags::MISSING_SNAPSHOT_PINK);
   1869 
   1870        if fallback_pink != self.debug_fallback_pink && self.fallback_handle != TextureCacheHandle::invalid() {
   1871            self.texture_cache.evict_handle(&self.fallback_handle);
   1872        }
   1873        self.debug_fallback_pink = fallback_pink;
   1874    }
   1875 
   1876    pub fn clear(&mut self, what: ClearCache) {
   1877        if what.contains(ClearCache::IMAGES) {
   1878            for (_key, mut cached) in self.cached_images.resources.drain() {
   1879                cached.drop_from_cache(&mut self.texture_cache);
   1880            }
   1881        }
   1882        if what.contains(ClearCache::GLYPHS) {
   1883            self.cached_glyphs.clear();
   1884        }
   1885        if what.contains(ClearCache::GLYPH_DIMENSIONS) {
   1886            self.cached_glyph_dimensions.clear();
   1887        }
   1888        if what.contains(ClearCache::RENDER_TASKS) {
   1889            self.cached_render_tasks.clear();
   1890        }
   1891        if what.contains(ClearCache::TEXTURE_CACHE) {
   1892            self.texture_cache.clear_all();
   1893            self.picture_textures.clear(&mut self.texture_cache.pending_updates);
   1894        }
   1895        if what.contains(ClearCache::RENDER_TARGETS) {
   1896            self.clear_render_target_pool();
   1897        }
   1898    }
   1899 
   1900    pub fn clear_namespace(&mut self, namespace: IdNamespace) {
   1901        self.clear_images(|k| k.0 == namespace);
   1902 
   1903        // First clear out any non-shared resources associated with the namespace.
   1904        self.resources.fonts.instances.clear_namespace(namespace);
   1905        let deleted_keys = self.resources.fonts.templates.clear_namespace(namespace);
   1906        self.glyph_rasterizer.delete_fonts(&deleted_keys);
   1907        self.cached_glyphs.clear_namespace(namespace);
   1908        if let Some(handler) = &mut self.blob_image_handler {
   1909            handler.clear_namespace(namespace);
   1910        }
   1911 
   1912        // Check for any shared instance keys that were remapped from the namespace.
   1913        let shared_instance_keys = self.resources.fonts.instance_keys.clear_namespace(namespace);
   1914        if !shared_instance_keys.is_empty() {
   1915            self.resources.fonts.instances.delete_font_instances(&shared_instance_keys);
   1916            self.cached_glyphs.delete_font_instances(&shared_instance_keys, &mut self.glyph_rasterizer);
   1917            // Blob font instances are not shared across namespaces, so there is no
   1918            // need to call the handler for them individually.
   1919        }
   1920 
   1921        // Finally check for any shared font keys that were remapped from the namespace.
   1922        let shared_keys = self.resources.fonts.font_keys.clear_namespace(namespace);
   1923        if !shared_keys.is_empty() {
   1924            self.glyph_rasterizer.delete_fonts(&shared_keys);
   1925            self.resources.fonts.templates.delete_fonts(&shared_keys);
   1926            self.cached_glyphs.delete_fonts(&shared_keys);
   1927            if let Some(handler) = &mut self.blob_image_handler {
   1928                for &key in &shared_keys {
   1929                    handler.delete_font(key);
   1930                }
   1931            }
   1932        }
   1933    }
   1934 
   1935    /// Reports the CPU heap usage of this ResourceCache.
   1936    ///
   1937    /// NB: It would be much better to use the derive(MallocSizeOf) machinery
   1938    /// here, but the Arcs complicate things. The two ways to handle that would
   1939    /// be to either (a) Implement MallocSizeOf manually for the things that own
   1940    /// them and manually avoid double-counting, or (b) Use the "seen this pointer
   1941    /// yet" machinery from the proper malloc_size_of crate. We can do this if/when
   1942    /// more accurate memory reporting on these resources becomes a priority.
   1943    pub fn report_memory(&self, op: VoidPtrToSizeFn) -> MemoryReport {
   1944        let mut report = MemoryReport::default();
   1945 
   1946        let mut seen_fonts = std::collections::HashSet::new();
   1947        // Measure fonts. We only need the templates here, because the instances
   1948        // don't have big buffers.
   1949        for (_, font) in self.resources.fonts.templates.lock().iter() {
   1950            if let FontTemplate::Raw(ref raw, _) = font {
   1951                report.fonts += unsafe { op(raw.as_ptr() as *const c_void) };
   1952                seen_fonts.insert(raw.as_ptr());
   1953            }
   1954        }
   1955 
   1956        for font in self.resources.weak_fonts.iter() {
   1957            if !seen_fonts.contains(&font.as_ptr()) {
   1958                report.weak_fonts += unsafe { op(font.as_ptr() as *const c_void) };
   1959            }
   1960        }
   1961 
   1962        // Measure images.
   1963        for (_, image) in self.resources.image_templates.images.iter() {
   1964            report.images += match image.data {
   1965                CachedImageData::Raw(ref v) => unsafe { op(v.as_ptr() as *const c_void) },
   1966                CachedImageData::Blob
   1967                | CachedImageData::External(..)
   1968                | CachedImageData::Snapshot => 0,
   1969            }
   1970        }
   1971 
   1972        // Mesure rasterized blobs.
   1973        // TODO(gw): Temporarily disabled while we roll back a crash. We can re-enable
   1974        //           these when that crash is fixed.
   1975        /*
   1976        for (_, image) in self.rasterized_blob_images.iter() {
   1977            let mut accumulate = |b: &RasterizedBlobImage| {
   1978                report.rasterized_blobs += unsafe { op(b.data.as_ptr() as *const c_void) };
   1979            };
   1980            match image {
   1981                RasterizedBlob::Tiled(map) => map.values().for_each(&mut accumulate),
   1982                RasterizedBlob::NonTiled(vec) => vec.iter().for_each(&mut accumulate),
   1983            };
   1984        }
   1985        */
   1986 
   1987        report
   1988    }
   1989 
   1990    /// Properly deletes all images matching the predicate.
   1991    fn clear_images<F: Fn(&ImageKey) -> bool>(&mut self, f: F) {
   1992        let keys = self.resources.image_templates.images.keys().filter(|k| f(*k))
   1993            .cloned().collect::<SmallVec<[ImageKey; 16]>>();
   1994 
   1995        for key in keys {
   1996            self.delete_image_template(key);
   1997        }
   1998 
   1999        #[cfg(feature="leak_checks")]
   2000        let check_leaks = true;
   2001        #[cfg(not(feature="leak_checks"))]
   2002        let check_leaks = false;
   2003 
   2004        if check_leaks {
   2005            let blob_f = |key: &BlobImageKey| { f(&key.as_image()) };
   2006            assert!(!self.resources.image_templates.images.keys().any(&f));
   2007            assert!(!self.cached_images.resources.keys().any(&f));
   2008            assert!(!self.rasterized_blob_images.keys().any(&blob_f));
   2009        }
   2010    }
   2011 
   2012    /// Get a render target from the pool, or allocate a new one if none are
   2013    /// currently available that match the requested parameters.
   2014    pub fn get_or_create_render_target_from_pool(
   2015        &mut self,
   2016        size: DeviceIntSize,
   2017        format: ImageFormat,
   2018    ) -> CacheTextureId {
   2019        for target in &mut self.render_target_pool {
   2020            if target.size == size &&
   2021               target.format == format &&
   2022               !target.is_active {
   2023                // Found a target that's not currently in use which matches. Update
   2024                // the last_frame_used for GC purposes.
   2025                target.is_active = true;
   2026                target.last_frame_used = self.current_frame_id;
   2027                return target.texture_id;
   2028            }
   2029        }
   2030 
   2031        // Need to create a new render target and add it to the pool
   2032 
   2033        let texture_id = self.texture_cache.alloc_render_target(
   2034            size,
   2035            format,
   2036        );
   2037 
   2038        self.render_target_pool.push(RenderTarget {
   2039            size,
   2040            format,
   2041            texture_id,
   2042            is_active: true,
   2043            last_frame_used: self.current_frame_id,
   2044        });
   2045 
   2046        texture_id
   2047    }
   2048 
   2049    /// Return a render target to the pool.
   2050    pub fn return_render_target_to_pool(
   2051        &mut self,
   2052        id: CacheTextureId,
   2053    ) {
   2054        let target = self.render_target_pool
   2055            .iter_mut()
   2056            .find(|t| t.texture_id == id)
   2057            .expect("bug: invalid render target id");
   2058 
   2059        assert!(target.is_active);
   2060        target.is_active = false;
   2061    }
   2062 
   2063    /// Clear all current render targets (e.g. on memory pressure)
   2064    fn clear_render_target_pool(
   2065        &mut self,
   2066    ) {
   2067        for target in self.render_target_pool.drain(..) {
   2068            debug_assert!(!target.is_active);
   2069            self.texture_cache.free_render_target(target.texture_id);
   2070        }
   2071    }
   2072 
   2073    /// Garbage collect and remove old render targets from the pool that haven't
   2074    /// been used for some time.
   2075    fn gc_render_targets(
   2076        &mut self,
   2077        total_bytes_threshold: usize,
   2078        total_bytes_red_line_threshold: usize,
   2079        frames_threshold: u64,
   2080    ) {
   2081        // Get the total GPU memory size used by the current render target pool
   2082        let mut rt_pool_size_in_bytes: usize = self.render_target_pool
   2083            .iter()
   2084            .map(|t| t.size_in_bytes())
   2085            .sum();
   2086 
   2087        // If the total size of the pool is less than the threshold, don't bother
   2088        // trying to GC any targets
   2089        if rt_pool_size_in_bytes <= total_bytes_threshold {
   2090            return;
   2091        }
   2092 
   2093        // Sort the current pool by age, so that we remove oldest textures first
   2094        self.render_target_pool.sort_by_key(|t| t.last_frame_used);
   2095 
   2096        // We can't just use retain() because `RenderTarget` requires manual cleanup.
   2097        let mut retained_targets = SmallVec::<[RenderTarget; 8]>::new();
   2098 
   2099        for target in self.render_target_pool.drain(..) {
   2100            assert!(!target.is_active);
   2101 
   2102            // Drop oldest textures until we are under the allowed size threshold.
   2103            // However, if it's been used in very recently, it is always kept around,
   2104            // which ensures we don't thrash texture allocations on pages that do
   2105            // require a very large render target pool and are regularly changing.
   2106            let above_red_line = rt_pool_size_in_bytes > total_bytes_red_line_threshold;
   2107            let above_threshold = rt_pool_size_in_bytes > total_bytes_threshold;
   2108            let used_recently = target.used_recently(self.current_frame_id, frames_threshold);
   2109            let used_this_frame = target.last_frame_used == self.current_frame_id;
   2110 
   2111            if !used_this_frame && (above_red_line || (above_threshold && !used_recently)) {
   2112                rt_pool_size_in_bytes -= target.size_in_bytes();
   2113                self.texture_cache.free_render_target(target.texture_id);
   2114            } else {
   2115                retained_targets.push(target);
   2116            }
   2117        }
   2118 
   2119        self.render_target_pool.extend(retained_targets);
   2120    }
   2121 
   2122    #[cfg(test)]
   2123    pub fn validate_surfaces(
   2124        &self,
   2125        expected_surfaces: &[(i32, i32, ImageFormat)],
   2126    ) {
   2127        assert_eq!(expected_surfaces.len(), self.render_target_pool.len());
   2128 
   2129        for (expected, surface) in expected_surfaces.iter().zip(self.render_target_pool.iter()) {
   2130            assert_eq!(DeviceIntSize::new(expected.0, expected.1), surface.size);
   2131            assert_eq!(expected.2, surface.format);
   2132        }
   2133    }
   2134 }
   2135 
   2136 impl Drop for ResourceCache {
   2137    fn drop(&mut self) {
   2138        self.clear_images(|_| true);
   2139    }
   2140 }
   2141 
   2142 #[cfg(any(feature = "capture", feature = "replay"))]
   2143 #[cfg_attr(feature = "capture", derive(Serialize))]
   2144 #[cfg_attr(feature = "replay", derive(Deserialize))]
   2145 struct PlainFontTemplate {
   2146    data: String,
   2147    index: u32,
   2148 }
   2149 
   2150 #[cfg(any(feature = "capture", feature = "replay"))]
   2151 #[cfg_attr(feature = "capture", derive(Serialize))]
   2152 #[cfg_attr(feature = "replay", derive(Deserialize))]
   2153 struct PlainImageTemplate {
   2154    data: String,
   2155    descriptor: ImageDescriptor,
   2156    tiling: Option<TileSize>,
   2157    generation: ImageGeneration,
   2158 }
   2159 
   2160 #[cfg(any(feature = "capture", feature = "replay"))]
   2161 #[cfg_attr(feature = "capture", derive(Serialize))]
   2162 #[cfg_attr(feature = "replay", derive(Deserialize))]
   2163 pub struct PlainResources {
   2164    font_templates: FastHashMap<FontKey, PlainFontTemplate>,
   2165    font_instances: Vec<BaseFontInstance>,
   2166    image_templates: FastHashMap<ImageKey, PlainImageTemplate>,
   2167 }
   2168 
   2169 #[cfg(feature = "capture")]
   2170 #[derive(Serialize)]
   2171 pub struct PlainCacheRef<'a> {
   2172    current_frame_id: FrameId,
   2173    glyphs: &'a GlyphCache,
   2174    glyph_dimensions: &'a GlyphDimensionsCache,
   2175    images: &'a ImageCache,
   2176    render_tasks: &'a RenderTaskCache,
   2177    textures: &'a TextureCache,
   2178    picture_textures: &'a PictureTextures,
   2179 }
   2180 
   2181 #[cfg(feature = "replay")]
   2182 #[derive(Deserialize)]
   2183 pub struct PlainCacheOwn {
   2184    current_frame_id: FrameId,
   2185    glyphs: GlyphCache,
   2186    glyph_dimensions: GlyphDimensionsCache,
   2187    images: ImageCache,
   2188    render_tasks: RenderTaskCache,
   2189    textures: TextureCache,
   2190    picture_textures: PictureTextures,
   2191 }
   2192 
   2193 #[cfg(feature = "replay")]
   2194 const NATIVE_FONT: &'static [u8] = include_bytes!("../res/Proggy.ttf");
   2195 
   2196 // This currently only casts the unit but will soon apply an offset
   2197 fn to_image_dirty_rect(blob_dirty_rect: &BlobDirtyRect) -> ImageDirtyRect {
   2198    match *blob_dirty_rect {
   2199        DirtyRect::Partial(rect) => DirtyRect::Partial(rect.cast_unit()),
   2200        DirtyRect::All => DirtyRect::All,
   2201    }
   2202 }
   2203 
   2204 impl ResourceCache {
   2205    #[cfg(feature = "capture")]
   2206    pub fn save_capture(
   2207        &mut self, root: &PathBuf
   2208    ) -> (PlainResources, Vec<ExternalCaptureImage>) {
   2209        use std::fs;
   2210        use std::io::Write;
   2211 
   2212        info!("saving resource cache");
   2213        let res = &self.resources;
   2214        let path_fonts = root.join("fonts");
   2215        if !path_fonts.is_dir() {
   2216            fs::create_dir(&path_fonts).unwrap();
   2217        }
   2218        let path_images = root.join("images");
   2219        if !path_images.is_dir() {
   2220            fs::create_dir(&path_images).unwrap();
   2221        }
   2222        let path_blobs = root.join("blobs");
   2223        if !path_blobs.is_dir() {
   2224            fs::create_dir(&path_blobs).unwrap();
   2225        }
   2226        let path_externals = root.join("externals");
   2227        if !path_externals.is_dir() {
   2228            fs::create_dir(&path_externals).unwrap();
   2229        }
   2230 
   2231        info!("\tfont templates");
   2232        let mut font_paths = FastHashMap::default();
   2233        for template in res.fonts.templates.lock().values() {
   2234            let data: &[u8] = match *template {
   2235                FontTemplate::Raw(ref arc, _) => arc,
   2236                FontTemplate::Native(_) => continue,
   2237            };
   2238            let font_id = res.fonts.templates.len() + 1;
   2239            let entry = match font_paths.entry(data.as_ptr()) {
   2240                Entry::Occupied(_) => continue,
   2241                Entry::Vacant(e) => e,
   2242            };
   2243            let file_name = format!("{}.raw", font_id);
   2244            let short_path = format!("fonts/{}", file_name);
   2245            fs::File::create(path_fonts.join(file_name))
   2246                .expect(&format!("Unable to create {}", short_path))
   2247                .write_all(data)
   2248                .unwrap();
   2249            entry.insert(short_path);
   2250        }
   2251 
   2252        info!("\timage templates");
   2253        let mut image_paths = FastHashMap::default();
   2254        let mut other_paths = FastHashMap::default();
   2255        let mut num_blobs = 0;
   2256        let mut external_images = Vec::new();
   2257        for (&key, template) in res.image_templates.images.iter() {
   2258            let desc = &template.descriptor;
   2259            match template.data {
   2260                CachedImageData::Raw(ref arc) => {
   2261                    let image_id = image_paths.len() + 1;
   2262                    let entry = match image_paths.entry(arc.as_ptr()) {
   2263                        Entry::Occupied(_) => continue,
   2264                        Entry::Vacant(e) => e,
   2265                    };
   2266 
   2267                    #[cfg(feature = "png")]
   2268                    CaptureConfig::save_png(
   2269                        root.join(format!("images/{}.png", image_id)),
   2270                        desc.size,
   2271                        desc.format,
   2272                        desc.stride,
   2273                        &arc,
   2274                    );
   2275                    let file_name = format!("{}.raw", image_id);
   2276                    let short_path = format!("images/{}", file_name);
   2277                    fs::File::create(path_images.join(file_name))
   2278                        .expect(&format!("Unable to create {}", short_path))
   2279                        .write_all(&*arc)
   2280                        .unwrap();
   2281                    entry.insert(short_path);
   2282                }
   2283                CachedImageData::Blob => {
   2284                    warn!("Tiled blob images aren't supported yet");
   2285                    let result = RasterizedBlobImage {
   2286                        rasterized_rect: desc.size.into(),
   2287                        data: Arc::new(vec![0; desc.compute_total_size() as usize])
   2288                    };
   2289 
   2290                    assert_eq!(result.rasterized_rect.size(), desc.size);
   2291                    assert_eq!(result.data.len(), desc.compute_total_size() as usize);
   2292 
   2293                    num_blobs += 1;
   2294                    #[cfg(feature = "png")]
   2295                    CaptureConfig::save_png(
   2296                        root.join(format!("blobs/{}.png", num_blobs)),
   2297                        desc.size,
   2298                        desc.format,
   2299                        desc.stride,
   2300                        &result.data,
   2301                    );
   2302                    let file_name = format!("{}.raw", num_blobs);
   2303                    let short_path = format!("blobs/{}", file_name);
   2304                    let full_path = path_blobs.clone().join(&file_name);
   2305                    fs::File::create(full_path)
   2306                        .expect(&format!("Unable to create {}", short_path))
   2307                        .write_all(&result.data)
   2308                        .unwrap();
   2309                    other_paths.insert(key, short_path);
   2310                }
   2311                CachedImageData::Snapshot => {
   2312                    let short_path = format!("snapshots/{}", external_images.len() + 1);
   2313                    other_paths.insert(key, short_path.clone());
   2314                }
   2315                CachedImageData::External(ref ext) => {
   2316                    let short_path = format!("externals/{}", external_images.len() + 1);
   2317                    other_paths.insert(key, short_path.clone());
   2318                    external_images.push(ExternalCaptureImage {
   2319                        short_path,
   2320                        descriptor: desc.clone(),
   2321                        external: ext.clone(),
   2322                    });
   2323                }
   2324            }
   2325        }
   2326 
   2327        let mut font_templates = FastHashMap::default();
   2328        let mut font_remap = FastHashMap::default();
   2329        // Generate a map from duplicate font keys to their template.
   2330        for key in res.fonts.font_keys.keys() {
   2331            let shared_key = res.fonts.font_keys.map_key(&key);
   2332            let template = match res.fonts.templates.get_font(&shared_key) {
   2333                Some(template) => template,
   2334                None => {
   2335                    debug!("Failed serializing font template {:?}", key);
   2336                    continue;
   2337                }
   2338            };
   2339            let plain_font = match template {
   2340                FontTemplate::Raw(arc, index) => {
   2341                    PlainFontTemplate {
   2342                        data: font_paths[&arc.as_ptr()].clone(),
   2343                        index,
   2344                    }
   2345                }
   2346                #[cfg(not(any(target_os = "macos", target_os = "ios")))]
   2347                FontTemplate::Native(native) => {
   2348                    PlainFontTemplate {
   2349                        data: native.path.to_string_lossy().to_string(),
   2350                        index: native.index,
   2351                    }
   2352                }
   2353                #[cfg(any(target_os = "macos", target_os = "ios"))]
   2354                FontTemplate::Native(native) => {
   2355                    PlainFontTemplate {
   2356                        data: native.name,
   2357                        index: 0,
   2358                    }
   2359                }
   2360            };
   2361            font_templates.insert(key, plain_font);
   2362            // Generate a reverse map from a shared key to a representive key.
   2363            font_remap.insert(shared_key, key);
   2364        }
   2365        let mut font_instances = Vec::new();
   2366        // Build a list of duplicate instance keys.
   2367        for instance_key in res.fonts.instance_keys.keys() {
   2368            let shared_key = res.fonts.instance_keys.map_key(&instance_key);
   2369            let instance = match res.fonts.instances.get_font_instance(shared_key) {
   2370                Some(instance) => instance,
   2371                None => {
   2372                    debug!("Failed serializing font instance {:?}", instance_key);
   2373                    continue;
   2374                }
   2375            };
   2376            // Target the instance towards a representive duplicate font key. The font key will be
   2377            // de-duplicated on load to an appropriate shared key.
   2378            font_instances.push(BaseFontInstance {
   2379                font_key: font_remap.get(&instance.font_key).cloned().unwrap_or(instance.font_key),
   2380                instance_key,
   2381                ..(*instance).clone()
   2382            });
   2383        }
   2384        let resources = PlainResources {
   2385            font_templates,
   2386            font_instances,
   2387            image_templates: res.image_templates.images
   2388                .iter()
   2389                .map(|(key, template)| {
   2390                    (*key, PlainImageTemplate {
   2391                        data: match template.data {
   2392                            CachedImageData::Raw(ref arc) => image_paths[&arc.as_ptr()].clone(),
   2393                            _ => other_paths[key].clone(),
   2394                        },
   2395                        descriptor: template.descriptor.clone(),
   2396                        tiling: template.tiling,
   2397                        generation: template.generation,
   2398                    })
   2399                })
   2400                .collect(),
   2401        };
   2402 
   2403        (resources, external_images)
   2404    }
   2405 
   2406    #[cfg(feature = "capture")]
   2407    pub fn save_caches(&self, _root: &PathBuf) -> PlainCacheRef {
   2408        PlainCacheRef {
   2409            current_frame_id: self.current_frame_id,
   2410            glyphs: &self.cached_glyphs,
   2411            glyph_dimensions: &self.cached_glyph_dimensions,
   2412            images: &self.cached_images,
   2413            render_tasks: &self.cached_render_tasks,
   2414            textures: &self.texture_cache,
   2415            picture_textures: &self.picture_textures,
   2416        }
   2417    }
   2418 
   2419    #[cfg(feature = "replay")]
   2420    pub fn load_capture(
   2421        &mut self,
   2422        resources: PlainResources,
   2423        caches: Option<PlainCacheOwn>,
   2424        config: &CaptureConfig,
   2425    ) -> Vec<PlainExternalImage> {
   2426        use std::{fs, path::Path};
   2427        use crate::texture_cache::TextureCacheConfig;
   2428 
   2429        info!("loading resource cache");
   2430        //TODO: instead of filling the local path to Arc<data> map as we process
   2431        // each of the resource types, we could go through all of the local paths
   2432        // and fill out the map as the first step.
   2433        let mut raw_map = FastHashMap::<String, Arc<Vec<u8>>>::default();
   2434 
   2435        self.clear(ClearCache::all());
   2436        self.clear_images(|_| true);
   2437 
   2438        match caches {
   2439            Some(cached) => {
   2440                self.current_frame_id = cached.current_frame_id;
   2441                self.cached_glyphs = cached.glyphs;
   2442                self.cached_glyph_dimensions = cached.glyph_dimensions;
   2443                self.cached_images = cached.images;
   2444                self.cached_render_tasks = cached.render_tasks;
   2445                self.texture_cache = cached.textures;
   2446                self.picture_textures = cached.picture_textures;
   2447            }
   2448            None => {
   2449                self.current_frame_id = FrameId::INVALID;
   2450                self.texture_cache = TextureCache::new(
   2451                    self.texture_cache.max_texture_size(),
   2452                    self.texture_cache.tiling_threshold(),
   2453                    self.texture_cache.color_formats(),
   2454                    self.texture_cache.swizzle_settings(),
   2455                    &TextureCacheConfig::DEFAULT,
   2456                );
   2457                self.picture_textures = PictureTextures::new(
   2458                    self.picture_textures.default_tile_size(),
   2459                    self.picture_textures.filter(),
   2460                );
   2461            }
   2462        }
   2463 
   2464        self.glyph_rasterizer.reset();
   2465        let res = &mut self.resources;
   2466        res.fonts.templates.clear();
   2467        res.fonts.instances.clear();
   2468        res.image_templates.images.clear();
   2469 
   2470        info!("\tfont templates...");
   2471        let root = config.resource_root();
   2472        let native_font_replacement = Arc::new(NATIVE_FONT.to_vec());
   2473        for (key, plain_template) in resources.font_templates {
   2474            let arc = match raw_map.entry(plain_template.data) {
   2475                Entry::Occupied(e) => {
   2476                    e.get().clone()
   2477                }
   2478                Entry::Vacant(e) => {
   2479                    let file_path = if Path::new(e.key()).is_absolute() {
   2480                        PathBuf::from(e.key())
   2481                    } else {
   2482                        root.join(e.key())
   2483                    };
   2484                    let arc = match fs::read(file_path) {
   2485                        Ok(buffer) => Arc::new(buffer),
   2486                        Err(err) => {
   2487                            error!("Unable to open font template {:?}: {:?}", e.key(), err);
   2488                            Arc::clone(&native_font_replacement)
   2489                        }
   2490                    };
   2491                    e.insert(arc).clone()
   2492                }
   2493            };
   2494 
   2495            let template = FontTemplate::Raw(arc, plain_template.index);
   2496            // Only add the template if this is the first time it has been seen.
   2497            if let Some(shared_key) = res.fonts.font_keys.add_key(&key, &template) {
   2498                self.glyph_rasterizer.add_font(shared_key, template.clone());
   2499                res.fonts.templates.add_font(shared_key, template);
   2500            }
   2501        }
   2502 
   2503        info!("\tfont instances...");
   2504        for instance in resources.font_instances {
   2505            // Target the instance to a shared font key.
   2506            let base = BaseFontInstance {
   2507                font_key: res.fonts.font_keys.map_key(&instance.font_key),
   2508                ..instance
   2509            };
   2510            if let Some(shared_instance) = res.fonts.instance_keys.add_key(base) {
   2511                res.fonts.instances.add_font_instance(shared_instance);
   2512            }
   2513        }
   2514 
   2515        info!("\timage templates...");
   2516        let mut external_images = Vec::new();
   2517        for (key, template) in resources.image_templates {
   2518            let data = if template.data.starts_with("snapshots/") {
   2519                // TODO(nical): If a snapshot was captured in a previous frame,
   2520                // we have to serialize/deserialize the image itself.
   2521                CachedImageData::Snapshot
   2522            } else {
   2523                match config.deserialize_for_resource::<PlainExternalImage, _>(&template.data) {
   2524                    Some(plain) => {
   2525                        let ext_data = plain.external;
   2526                        external_images.push(plain);
   2527                        CachedImageData::External(ext_data)
   2528                    }
   2529                    None => {
   2530                        let arc = match raw_map.entry(template.data) {
   2531                            Entry::Occupied(e) => e.get().clone(),
   2532                            Entry::Vacant(e) => {
   2533                                match fs::read(root.join(e.key())) {
   2534                                    Ok(buffer) => {
   2535                                        e.insert(Arc::new(buffer)).clone()
   2536                                    }
   2537                                    Err(err) => {
   2538                                        log::warn!("Unable to open {}: {err:?}", e.key());
   2539                                        continue;
   2540                                    }
   2541                                }
   2542                            }
   2543                        };
   2544                        CachedImageData::Raw(arc)
   2545                    }
   2546                }
   2547            };
   2548 
   2549            res.image_templates.images.insert(key, ImageResource {
   2550                data,
   2551                descriptor: template.descriptor,
   2552                tiling: template.tiling,
   2553                visible_rect: template.descriptor.size.into(),
   2554                adjustment: AdjustedImageSource::new(), // TODO(nical)
   2555                generation: template.generation,
   2556            });
   2557        }
   2558 
   2559        external_images
   2560    }
   2561 
   2562    #[cfg(feature = "capture")]
   2563    pub fn save_capture_sequence(&mut self, config: &mut CaptureConfig) -> Vec<ExternalCaptureImage> {
   2564        if self.capture_dirty {
   2565            self.capture_dirty = false;
   2566            config.prepare_resource();
   2567            let (resources, deferred) = self.save_capture(&config.resource_root());
   2568            config.serialize_for_resource(&resources, "plain-resources.ron");
   2569            deferred
   2570        } else {
   2571            Vec::new()
   2572        }
   2573    }
   2574 }