Bug 1528674 - WR improve picture texture cache allocaton r=gw
authorDzmitry Malyshau <dmalyshau@mozilla.com>
Thu, 28 Mar 2019 03:02:45 +0000
changeset 466513 03ef11b535d4c05d400a7b3d9965cbea6e2b6d2a
parent 466512 17f0796b0f6e7c6a8ff3931e6f48ab514711c8b9
child 466514 152457c26513998d59685b68da802576b955b2e7
push id35768
push useropoprus@mozilla.com
push dateThu, 28 Mar 2019 09:55:54 +0000
treeherdermozilla-central@c045dd97faf2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw
bugs1528674
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1528674 - WR improve picture texture cache allocaton r=gw The change contains a number of incremental improvements with the main goal of: - allocating exactly as many tile as required by the app - respecting the picture caching option Differential Revision: https://phabricator.services.mozilla.com/D24740
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/src/bindings.rs
gfx/wr/direct-composition/src/main_windows.rs
gfx/wr/examples/common/boilerplate.rs
gfx/wr/examples/multiwindow.rs
gfx/wr/webrender/src/device/gl.rs
gfx/wr/webrender/src/render_backend.rs
gfx/wr/webrender/src/renderer.rs
gfx/wr/webrender/src/resource_cache.rs
gfx/wr/webrender/src/texture_cache.rs
gfx/wr/wrench/src/wrench.rs
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -64,31 +64,34 @@ class NewRenderer : public RendererEvent
       // nullptr
       return;
     }
 
     *mUseANGLE = compositor->UseANGLE();
     *mUseDComp = compositor->UseDComp();
     *mUseTripleBuffering = compositor->UseTripleBuffering();
 
-    bool supportLowPriorityTransactions = true;  // TODO only for main windows.
+    bool isMainWindow = true;  // TODO!
+    bool supportLowPriorityTransactions = isMainWindow;
+    bool supportPictureCaching = isMainWindow;
     wr::Renderer* wrRenderer = nullptr;
-    if (!wr_window_new(aWindowId, mSize.width, mSize.height,
-                       supportLowPriorityTransactions,
-                       gfxPrefs::WebRenderPictureCaching(), compositor->gl(),
-                       aRenderThread.GetProgramCache()
-                           ? aRenderThread.GetProgramCache()->Raw()
-                           : nullptr,
-                       aRenderThread.GetShaders()
-                           ? aRenderThread.GetShaders()->RawShaders()
-                           : nullptr,
-                       aRenderThread.ThreadPool().Raw(), &WebRenderMallocSizeOf,
-                       &WebRenderMallocEnclosingSizeOf,
-                       (uint32_t)wr::RenderRoot::Default,
-                       mDocHandle, &wrRenderer, mMaxTextureSize)) {
+    if (!wr_window_new(
+            aWindowId, mSize.width, mSize.height,
+            supportLowPriorityTransactions,
+            gfxPrefs::WebRenderPictureCaching() && supportPictureCaching,
+            compositor->gl(),
+            aRenderThread.GetProgramCache()
+                ? aRenderThread.GetProgramCache()->Raw()
+                : nullptr,
+            aRenderThread.GetShaders()
+                ? aRenderThread.GetShaders()->RawShaders()
+                : nullptr,
+            aRenderThread.ThreadPool().Raw(), &WebRenderMallocSizeOf,
+            &WebRenderMallocEnclosingSizeOf, (uint32_t)wr::RenderRoot::Default,
+            mDocHandle, &wrRenderer, mMaxTextureSize)) {
       // wr_window_new puts a message into gfxCriticalNote if it returns false
       return;
     }
     MOZ_ASSERT(wrRenderer);
 
     RefPtr<RenderThread> thread = &aRenderThread;
     auto renderer =
         MakeUnique<RendererOGL>(std::move(thread), std::move(compositor),
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1154,35 +1154,35 @@ pub extern "C" fn wr_window_new(window_i
         enable_picture_caching,
         allow_pixel_local_storage_support: false,
         ..Default::default()
     };
 
     // Ensure the WR profiler callbacks are hooked up to the Gecko profiler.
     set_profiler_hooks(Some(&PROFILER_HOOKS));
 
+    let window_size = FramebufferIntSize::new(window_width, window_height);
     let notifier = Box::new(CppNotifier {
         window_id: window_id,
     });
-    let (renderer, sender) = match Renderer::new(gl, notifier, opts, shaders) {
+    let (renderer, sender) = match Renderer::new(gl, notifier, opts, shaders, window_size) {
         Ok((renderer, sender)) => (renderer, sender),
         Err(e) => {
             warn!(" Failed to create a Renderer: {:?}", e);
             let msg = CString::new(format!("wr_window_new: {:?}", e)).unwrap();
             unsafe {
                 gfx_critical_note(msg.as_ptr());
             }
             return false;
         },
     };
 
     unsafe {
         *out_max_texture_size = renderer.get_max_texture_size();
     }
-    let window_size = FramebufferIntSize::new(window_width, window_height);
     let layer = 0;
     *out_handle = Box::into_raw(Box::new(
             DocumentHandle::new_with_id(sender.create_api_by_client(next_namespace_id()),
                                         window_size, layer, document_id)));
     *out_renderer = Box::into_raw(Box::new(renderer));
 
     return true;
 }
--- a/gfx/wr/direct-composition/src/main_windows.rs
+++ b/gfx/wr/direct-composition/src/main_windows.rs
@@ -110,16 +110,17 @@ impl Rectangle {
             composition.gleam.clone(),
             notifier.clone(),
             webrender::RendererOptions {
                 clear_color: Some(api::ColorF::new(0., 0., 0., 0.)),
                 device_pixel_ratio,
                 ..webrender::RendererOptions::default()
             },
             None,
+            size,
         ).unwrap();
         let api = sender.create_api();
 
        Rectangle {
             visual,
             renderer: Some(renderer),
             document_id: api.add_document(size, 0),
             api,
--- a/gfx/wr/examples/common/boilerplate.rs
+++ b/gfx/wr/examples/common/boilerplate.rs
@@ -163,17 +163,23 @@ pub fn main_wrapper<E: Example>(
     let framebuffer_size = {
         let size = window
             .get_inner_size()
             .unwrap()
             .to_physical(device_pixel_ratio as f64);
         FramebufferIntSize::new(size.width as i32, size.height as i32)
     };
     let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
-    let (mut renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts, None).unwrap();
+    let (mut renderer, sender) = webrender::Renderer::new(
+        gl.clone(),
+        notifier,
+        opts,
+        None,
+        framebuffer_size,
+    ).unwrap();
     let api = sender.create_api();
     let document_id = api.add_document(framebuffer_size, 0);
 
     let (external, output) = example.get_image_handlers(&*gl);
 
     if let Some(output_image_handler) = output {
         renderer.set_output_image_handler(output_image_handler);
     }
--- a/gfx/wr/examples/multiwindow.rs
+++ b/gfx/wr/examples/multiwindow.rs
@@ -100,17 +100,17 @@ impl Window {
         let framebuffer_size = {
             let size = window
                 .get_inner_size()
                 .unwrap()
                 .to_physical(device_pixel_ratio as f64);
             FramebufferIntSize::new(size.width as i32, size.height as i32)
         };
         let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
-        let (renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts, None).unwrap();
+        let (renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts, None, framebuffer_size).unwrap();
         let api = sender.create_api();
         let document_id = api.add_document(framebuffer_size, 0);
 
         let epoch = Epoch(0);
         let pipeline_id = PipelineId(0, 0);
         let mut txn = Transaction::new();
 
         let font_key = api.generate_font_key();
--- a/gfx/wr/webrender/src/device/gl.rs
+++ b/gfx/wr/webrender/src/device/gl.rs
@@ -487,16 +487,17 @@ bitflags! {
     }
 }
 
 /// WebRender interface to an OpenGL texture.
 ///
 /// Because freeing a texture requires various device handles that are not
 /// reachable from this struct, manual destruction via `Device` is required.
 /// Our `Drop` implementation asserts that this has happened.
+#[derive(Debug)]
 pub struct Texture {
     id: gl::GLuint,
     target: gl::GLuint,
     layer_count: i32,
     format: ImageFormat,
     size: DeviceIntSize,
     filter: TextureFilter,
     flags: TextureFlags,
--- a/gfx/wr/webrender/src/render_backend.rs
+++ b/gfx/wr/webrender/src/render_backend.rs
@@ -1710,17 +1710,21 @@ impl RenderBackend {
         let backend = CaptureConfig::deserialize::<PlainRenderBackend, _>(root, "backend")
             .expect("Unable to open backend.ron");
         let caches_maybe = CaptureConfig::deserialize::<PlainCacheOwn, _>(root, "resource_cache");
 
         // Note: it would be great to have `RenderBackend` to be split
         // rather explicitly on what's used before and after scene building
         // so that, for example, we never miss anything in the code below:
 
-        let plain_externals = self.resource_cache.load_capture(backend.resources, caches_maybe, root);
+        let plain_externals = self.resource_cache.load_capture(
+            backend.resources,
+            caches_maybe,
+            root,
+        );
         let msg_load = ResultMsg::DebugOutput(
             DebugOutput::LoadCapture(root.clone(), plain_externals)
         );
         self.result_tx.send(msg_load).unwrap();
 
         self.gpu_cache = match CaptureConfig::deserialize::<GpuCache, _>(root, "gpu_cache") {
             Some(gpu_cache) => gpu_cache,
             None => GpuCache::new(),
--- a/gfx/wr/webrender/src/renderer.rs
+++ b/gfx/wr/webrender/src/renderer.rs
@@ -1742,17 +1742,18 @@ impl Renderer {
     /// };
     /// let (renderer, sender) = Renderer::new(opts);
     /// ```
     /// [rendereroptions]: struct.RendererOptions.html
     pub fn new(
         gl: Rc<gl::Gl>,
         notifier: Box<RenderNotifier>,
         mut options: RendererOptions,
-        shaders: Option<&mut WrShaders>
+        shaders: Option<&mut WrShaders>,
+        start_size: FramebufferIntSize,
     ) -> Result<(Self, RenderApiSender), RendererError> {
         HAS_BEEN_INITIALIZED.store(true, Ordering::SeqCst);
 
         let (api_tx, api_rx) = channel::msg_channel()?;
         let (payload_tx, payload_rx) = channel::payload_channel()?;
         let (result_tx, result_rx) = channel();
         let gl_type = gl.get_type();
 
@@ -2045,17 +2046,22 @@ impl Renderer {
             register_thread_with_profiler(rb_thread_name.clone());
             if let Some(ref thread_listener) = *thread_listener_for_render_backend {
                 thread_listener.thread_started(&rb_thread_name);
             }
 
             let texture_cache = TextureCache::new(
                 max_texture_size,
                 max_texture_layers,
-                TileCache::tile_dimensions(config.testing),
+                if config.enable_picture_caching {
+                    Some(TileCache::tile_dimensions(config.testing))
+                } else {
+                    None
+                },
+                start_size,
             );
 
             let resource_cache = ResourceCache::new(
                 texture_cache,
                 glyph_rasterizer,
                 blob_image_handler,
             );
 
--- a/gfx/wr/webrender/src/resource_cache.rs
+++ b/gfx/wr/webrender/src/resource_cache.rs
@@ -2196,16 +2196,17 @@ impl ResourceCache {
                 self.cached_glyphs.clear();
                 self.cached_glyph_dimensions.clear();
                 self.cached_images.clear();
                 self.cached_render_tasks.clear();
                 self.texture_cache = TextureCache::new(
                     self.texture_cache.max_texture_size(),
                     self.texture_cache.max_texture_layers(),
                     self.texture_cache.picture_tile_size(),
+                    FramebufferIntSize::zero(),
                 );
             }
         }
 
         self.glyph_rasterizer.reset();
         let res = &mut self.resources;
         res.font_templates.clear();
         *res.font_instances.write().unwrap() = resources.font_instances;
--- a/gfx/wr/webrender/src/texture_cache.rs
+++ b/gfx/wr/webrender/src/texture_cache.rs
@@ -20,20 +20,18 @@ use std::cell::Cell;
 use std::cmp;
 use std::mem;
 use std::time::{Duration, SystemTime};
 use std::rc::Rc;
 
 /// The size of each region/layer in shared cache texture arrays.
 pub const TEXTURE_REGION_DIMENSIONS: i32 = 512;
 
-/// The number of slices for picture caching to allocate at start.
-const BASE_PICTURE_TEXTURE_SLICES: usize = 16;
-/// The number of slices to add when we grow out of the current range.
-const ADD_PICTURE_TEXTURE_SLICES: usize = 8;
+const PICTURE_TEXTURE_ADD_SLICES: usize = 4;
+
 /// The chosen image format for picture tiles.
 const PICTURE_TILE_FORMAT: ImageFormat = ImageFormat::BGRA8;
 
 /// The number of pixels in a region. Derived from the above.
 const TEXTURE_REGION_PIXELS: usize =
     (TEXTURE_REGION_DIMENSIONS as usize) * (TEXTURE_REGION_DIMENSIONS as usize);
 
 /// Items in the texture cache can either be standalone textures,
@@ -470,17 +468,17 @@ impl PerDocumentData {
 /// live view of its contents in Firefox.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct TextureCache {
     /// Set of texture arrays in different formats used for the shared cache.
     shared_textures: SharedTextures,
 
     /// A single texture array for picture caching.
-    picture_texture: WholeTextureArray,
+    picture_texture: Option<WholeTextureArray>,
 
     /// Maximum texture size supported by hardware.
     max_texture_size: i32,
 
     /// Maximum number of texture layers supported by hardware.
     max_texture_layers: usize,
 
     /// The current set of debug flags.
@@ -515,17 +513,18 @@ pub struct TextureCache {
     /// We should try removing this when we require a rustc with NLL.
     doc_data: PerDocumentData,
 }
 
 impl TextureCache {
     pub fn new(
         max_texture_size: i32,
         mut max_texture_layers: usize,
-        picture_tile_size: DeviceIntSize,
+        picture_tile_size: Option<DeviceIntSize>,
+        initial_size: FramebufferIntSize,
     ) -> Self {
         if cfg!(target_os = "macos") {
             // On MBP integrated Intel GPUs, texture arrays appear to be
             // implemented as a single texture of stacked layers, and that
             // texture appears to be subject to the texture size limit. As such,
             // allocating more than 32 512x512 regions results in a dimension
             // longer than 16k (the max texture size), causing incorrect behavior.
             //
@@ -543,25 +542,36 @@ impl TextureCache {
             //     driver family, and those drivers are also likely to share
             //     the same max texture size of 16k. If we do encounter a driver
             //     with the same bug but a lower max texture size, we might need
             //     to rethink our strategy anyway, since a limit below 32MB might
             //     start to introduce performance issues.
             max_texture_layers = max_texture_layers.min(32);
         }
 
-        let picture_texture = WholeTextureArray {
-            size: picture_tile_size,
-            filter: TextureFilter::Linear,
-            format: PICTURE_TILE_FORMAT,
-            texture_id: CacheTextureId(1),
-            slices: vec![WholeTextureSlice { uv_rect_handle: None }; BASE_PICTURE_TEXTURE_SLICES],
+        let mut pending_updates = TextureUpdateList::new();
+        let picture_texture = if let Some(tile_size) = picture_tile_size{
+            let picture_texture = WholeTextureArray {
+                size: tile_size,
+                filter: TextureFilter::Linear,
+                format: PICTURE_TILE_FORMAT,
+                texture_id: CacheTextureId(1),
+                slices: {
+                    let num_x = (initial_size.width + tile_size.width - 1) / tile_size.width;
+                    let num_y = (initial_size.height + tile_size.height - 1) / tile_size.height;
+                    let count = (num_x * num_y).max(1) as usize;
+                    info!("Initializing picture texture with {}x{} slices", num_x, num_y);
+                    vec![WholeTextureSlice { uv_rect_handle: None }; count]
+                },
+            };
+            pending_updates.push_alloc(picture_texture.texture_id, picture_texture.to_info());
+            Some(picture_texture)
+        } else {
+            None
         };
-        let mut pending_updates = TextureUpdateList::new();
-        pending_updates.push_alloc(picture_texture.texture_id, picture_texture.to_info());
 
         TextureCache {
             shared_textures: SharedTextures::new(),
             picture_texture,
             reached_reclaim_threshold: None,
             entries: FreeList::new(),
             max_texture_size,
             max_texture_layers,
@@ -574,18 +584,17 @@ impl TextureCache {
         }
     }
 
     /// Creates a TextureCache and sets it up with a valid `FrameStamp`, which
     /// is useful for avoiding panics when instantiating the `TextureCache`
     /// directly from unit test code.
     #[cfg(test)]
     pub fn new_for_testing(max_texture_size: i32, max_texture_layers: usize) -> Self {
-        let tile_size = DeviceIntSize::new(64, 64);
-        let mut cache = Self::new(max_texture_size, max_texture_layers, tile_size);
+        let mut cache = Self::new(max_texture_size, max_texture_layers, None, FramebufferIntSize::zero());
         let mut now = FrameStamp::first(DocumentId::new(IdNamespace(1), 1));
         now.advance();
         cache.begin_frame(now);
         cache
     }
 
     pub fn set_debug_flags(&mut self, flags: DebugFlags) {
         self.debug_flags = flags;
@@ -618,18 +627,20 @@ impl TextureCache {
 
     fn clear_standalone(&mut self) {
         debug_assert!(!self.now.is_valid());
         self.clear_kind(EntryKind::Standalone);
     }
 
     fn clear_picture(&mut self) {
         self.clear_kind(EntryKind::Picture);
-        if let Some(texture_id) = self.picture_texture.reset(BASE_PICTURE_TEXTURE_SLICES) {
-            self.pending_updates.push_realloc(texture_id, self.picture_texture.to_info());
+        if let Some(ref mut picture_texture) = self.picture_texture {
+            if let Some(texture_id) = picture_texture.reset(PICTURE_TEXTURE_ADD_SLICES) {
+                self.pending_updates.push_realloc(texture_id, picture_texture.to_info());
+            }
         }
     }
 
     fn clear_shared(&mut self) {
         if self.debug_flags.contains(DebugFlags::TEXTURE_CACHE_DBG_DISABLE_SHRINK) {
             return;
         }
         self.unset_doc_data();
@@ -732,18 +743,20 @@ impl TextureCache {
             .update_profile(&mut texture_cache_profile.pages_a8_linear);
         self.shared_textures.array_a16_linear
             .update_profile(&mut texture_cache_profile.pages_a16_linear);
         self.shared_textures.array_rgba8_linear
             .update_profile(&mut texture_cache_profile.pages_rgba8_linear);
         self.shared_textures.array_rgba8_nearest
             .update_profile(&mut texture_cache_profile.pages_rgba8_nearest);
 
-        self.picture_texture
-            .update_profile(&mut texture_cache_profile.pages_picture);
+        if let Some(ref picture_texture) = self.picture_texture {
+            picture_texture
+                .update_profile(&mut texture_cache_profile.pages_picture);
+        }
 
         self.unset_doc_data();
         self.now = FrameStamp::INVALID;
     }
 
     // Request an item in the texture cache. All images that will
     // be used on a frame *must* have request() called on their
     // handle, to update the last used timestamp and ensure
@@ -777,18 +790,18 @@ impl TextureCache {
     }
 
     #[cfg(feature = "replay")]
     pub fn max_texture_layers(&self) -> usize {
         self.max_texture_layers
     }
 
     #[cfg(feature = "replay")]
-    pub fn picture_tile_size(&self) -> DeviceIntSize {
-        self.picture_texture.size
+    pub fn picture_tile_size(&self) -> Option<DeviceIntSize> {
+        self.picture_texture.as_ref().map(|pt| pt.size)
     }
 
     pub fn pending_updates(&mut self) -> TextureUpdateList {
         mem::replace(&mut self.pending_updates, TextureUpdateList::new())
     }
 
     // Update the data stored by a given texture cache handle.
     pub fn update(
@@ -989,35 +1002,38 @@ impl TextureCache {
             self.doc_data.last_shared_cache_expiration = self.now;
         }
         self.doc_data.handles.shared.len() != old_len
     }
 
     // Free a cache entry from the standalone list or shared cache.
     fn free(&mut self, entry: &CacheEntry) {
         match entry.details {
-            EntryDetails::Standalone => {
-                // This is a standalone texture allocation. Free it directly.
-                self.pending_updates.push_free(entry.texture_id);
-            }
             EntryDetails::Picture { layer_index } => {
-                self.picture_texture.slices[layer_index].uv_rect_handle = None;
+                let picture_texture = self.picture_texture
+                    .as_mut()
+                    .expect("Picture caching is expecte to be ON");
+                picture_texture.slices[layer_index].uv_rect_handle = None;
                 if self.debug_flags.contains(
                     DebugFlags::TEXTURE_CACHE_DBG |
                     DebugFlags::TEXTURE_CACHE_DBG_CLEAR_EVICTED)
                 {
                     self.pending_updates.push_debug_clear(
                         entry.texture_id,
                         DeviceIntPoint::zero(),
-                        self.picture_texture.size.width,
-                        self.picture_texture.size.height,
+                        picture_texture.size.width,
+                        picture_texture.size.height,
                         layer_index,
                     );
                 }
             }
+            EntryDetails::Standalone => {
+                // This is a standalone texture allocation. Free it directly.
+                self.pending_updates.push_free(entry.texture_id);
+            }
             EntryDetails::Cache { origin, layer_index } => {
                 // Free the block in the given region.
                 let texture_array = self.shared_textures.select(entry.format, entry.filter);
                 let region = &mut texture_array.regions[layer_index];
 
                 if self.debug_flags.contains(
                     DebugFlags::TEXTURE_CACHE_DBG |
                     DebugFlags::TEXTURE_CACHE_DBG_CLEAR_EVICTED)
@@ -1120,21 +1136,21 @@ impl TextureCache {
             height: params.descriptor.size.height,
             format: params.descriptor.format,
             filter: params.filter,
             layer_count: 1,
             is_shared_cache: false,
         };
         self.pending_updates.push_alloc(texture_id, info);
 
-        return CacheEntry::new_standalone(
+        CacheEntry::new_standalone(
             texture_id,
             self.now,
             params,
-        );
+        )
     }
 
     /// Allocates a cache entry appropriate for the given parameters.
     ///
     /// This allocates from the shared cache unless the parameters do not meet
     /// the shared cache requirements, in which case a standalone texture is
     /// used.
     fn allocate_cache_entry(
@@ -1259,27 +1275,31 @@ impl TextureCache {
     pub fn update_picture_cache(
         &mut self,
         handle: &mut TextureCacheHandle,
         gpu_cache: &mut GpuCache,
     ) {
         debug_assert!(self.now.is_valid());
 
         if self.entries.get_opt(handle).is_none() {
-            let layer_index = match self.picture_texture.find_free() {
-                Some(index) => index,
-                None => {
-                    let index = self.picture_texture.grow(ADD_PICTURE_TEXTURE_SLICES);
-                    let info = self.picture_texture.to_info();
-                    self.pending_updates.push_realloc(self.picture_texture.texture_id, info);
-                    index
-                },
+            let cache_entry = {
+                let picture_texture = self.picture_texture
+                    .as_mut()
+                    .expect("Picture caching is expecte to be ON");
+                let layer_index = match picture_texture.find_free() {
+                    Some(index) => index,
+                    None => {
+                        let index = picture_texture.grow(PICTURE_TEXTURE_ADD_SLICES);
+                        let info = picture_texture.to_info();
+                        self.pending_updates.push_realloc(picture_texture.texture_id, info);
+                        index
+                    },
+                };
+                picture_texture.occupy(layer_index, self.now)
             };
-
-            let cache_entry = self.picture_texture.occupy(layer_index, self.now);
             self.upsert_entry(cache_entry, handle)
         }
 
         // Upload the resource rect and texture array layer.
         self.entries
             .get_opt_mut(handle)
             .expect("BUG: handle must be valid now")
             .update_gpu_cache(gpu_cache);
@@ -1606,39 +1626,44 @@ impl WholeTextureArray {
         for _ in 0 .. count {
             self.slices.push(WholeTextureSlice {
                 uv_rect_handle: None,
             });
         }
         index
     }
 
-    /// Occupy a specified slice by a cache entry.
-    fn occupy(&mut self, layer_index: usize, now: FrameStamp) -> CacheEntry {
-        let uv_rect_handle = GpuCacheHandle::new();
-        assert!(self.slices[layer_index].uv_rect_handle.is_none());
-        self.slices[layer_index].uv_rect_handle = Some(uv_rect_handle);
-
+    fn cache_entry_impl(
+        &self, layer_index: usize, now: FrameStamp, uv_rect_handle: GpuCacheHandle, texture_id: CacheTextureId,
+    ) -> CacheEntry {
         CacheEntry {
             size: self.size,
             user_data: [0.0; 3],
             last_access: now,
             details: EntryDetails::Picture {
                 layer_index,
             },
             uv_rect_handle,
             format: self.format,
             filter: self.filter,
-            texture_id: self.texture_id,
+            texture_id,
             eviction_notice: None,
             uv_rect_kind: UvRectKind::Rect,
             eviction: Eviction::Eager,
         }
     }
 
+    /// Occupy a specified slice by a cache entry.
+    fn occupy(&mut self, layer_index: usize, now: FrameStamp) -> CacheEntry {
+        let uv_rect_handle = GpuCacheHandle::new();
+        assert!(self.slices[layer_index].uv_rect_handle.is_none());
+        self.slices[layer_index].uv_rect_handle = Some(uv_rect_handle);
+        self.cache_entry_impl(layer_index, now, uv_rect_handle, self.texture_id)
+    }
+
     /// Reset the texture array to the specified number of slices, if it's larger.
     fn reset(
         &mut self, num_slices: usize
     ) -> Option<CacheTextureId> {
         if self.slices.len() <= num_slices {
             None
         } else {
             self.slices.truncate(num_slices);
--- a/gfx/wr/wrench/src/wrench.rs
+++ b/gfx/wr/wrench/src/wrench.rs
@@ -233,17 +233,23 @@ impl Wrench {
         }
 
         let (timing_sender, timing_receiver) = chase_lev::deque();
         let notifier = notifier.unwrap_or_else(|| {
             let data = Arc::new(Mutex::new(NotifierData::new(proxy, timing_receiver, verbose)));
             Box::new(Notifier(data))
         });
 
-        let (renderer, sender) = webrender::Renderer::new(window.clone_gl(), notifier, opts, None).unwrap();
+        let (renderer, sender) = webrender::Renderer::new(
+            window.clone_gl(),
+            notifier,
+            opts,
+            None,
+            size,
+        ).unwrap();
         let api = sender.create_api();
         let document_id = api.add_document(size, 0);
 
         let graphics_api = renderer.get_graphics_api_info();
         let zoom_factor = ZoomFactor::new(zoom_factor);
 
         let mut wrench = Wrench {
             window_size: size,