Bug 1501323 - Update webrender to a8817b943a2fd0038307a7432fdf5cbccf4a943e. r=kats
authorWR Updater Bot <graphics-team@mozilla.staktrace.com>
Tue, 23 Oct 2018 15:18:03 +0000
changeset 490941 12552690d15d82b2193403f728ff40604b011a71
parent 490940 1df447ff4c775115522c4c70366db19e59b0e12c
child 490942 77fabbff45e0d2ede394a205b7e787360c7ad9fc
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewerskats
bugs1501323
milestone65.0a1
Bug 1501323 - Update webrender to a8817b943a2fd0038307a7432fdf5cbccf4a943e. r=kats Differential Revision: https://phabricator.services.mozilla.com/D9540
gfx/webrender/src/batch.rs
gfx/webrender/src/frame_builder.rs
gfx/webrender/src/gpu_types.rs
gfx/webrender/src/tiling.rs
gfx/webrender_bindings/revision.txt
--- a/gfx/webrender/src/batch.rs
+++ b/gfx/webrender/src/batch.rs
@@ -4,24 +4,24 @@
 
 use api::{AlphaType, ClipMode, DeviceIntRect, DeviceIntSize, LineStyle};
 use api::{DeviceUintRect, DeviceUintPoint, ExternalImageType, FilterOp, ImageRendering};
 use api::{YuvColorSpace, YuvFormat, WorldRect, ColorDepth};
 use clip::{ClipDataStore, ClipNodeFlags, ClipNodeRange, ClipItem, ClipStore};
 use clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex};
 use glyph_rasterizer::GlyphFormat;
 use gpu_cache::{GpuCache, GpuCacheHandle, GpuCacheAddress};
-use gpu_types::{BrushFlags, BrushInstance, PrimitiveHeaders};
+use gpu_types::{BrushFlags, BrushInstance, PrimitiveHeaders, ZBufferId, ZBufferIdGenerator};
 use gpu_types::{ClipMaskInstance, SplitCompositeInstance};
 use gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance};
 use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
 use internal_types::{FastHashMap, SavedTargetIndex, TextureSource};
 use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureSurface};
 use prim_store::{BrushKind, BrushPrimitive, BrushSegmentTaskId, DeferredResolve};
-use prim_store::{EdgeAaSegmentMask, ImageSource, PrimitiveIndex};
+use prim_store::{EdgeAaSegmentMask, ImageSource};
 use prim_store::{VisibleGradientTile, PrimitiveInstance};
 use prim_store::{BrushSegment, BorderSource, Primitive, PrimitiveDetails};
 use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskTree};
 use renderer::{BlendMode, ImageBufferKind, ShaderColorMode};
 use renderer::BLOCKS_PER_UV_RECT;
 use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache, ImageProperties};
 use scene::FilterOpHelpers;
 use smallvec::SmallVec;
@@ -122,36 +122,36 @@ impl BatchKey {
 fn textures_compatible(t1: TextureSource, t2: TextureSource) -> bool {
     t1 == TextureSource::Invalid || t2 == TextureSource::Invalid || t1 == t2
 }
 
 pub struct AlphaBatchList {
     pub batches: Vec<PrimitiveBatch>,
     pub item_rects: Vec<Vec<WorldRect>>,
     current_batch_index: usize,
-    current_prim_index: PrimitiveIndex,
+    current_z_id: ZBufferId,
 }
 
 impl AlphaBatchList {
     fn new() -> Self {
         AlphaBatchList {
             batches: Vec::new(),
             item_rects: Vec::new(),
-            current_prim_index: PrimitiveIndex(usize::MAX),
+            current_z_id: ZBufferId::invalid(),
             current_batch_index: usize::MAX,
         }
     }
 
     pub fn set_params_and_get_batch(
         &mut self,
         key: BatchKey,
         bounding_rect: &WorldRect,
-        prim_index: PrimitiveIndex,
+        z_id: ZBufferId,
     ) -> &mut Vec<PrimitiveInstanceData> {
-        if prim_index != self.current_prim_index ||
+        if z_id != self.current_z_id ||
            self.current_batch_index == usize::MAX ||
            !self.batches[self.current_batch_index].key.is_compatible_with(&key) {
             let mut selected_batch_index = None;
 
             match key.blend_mode {
                 BlendMode::SubpixelWithBgColor => {
                     'outer_multipass: for (batch_index, batch) in self.batches.iter().enumerate().rev().take(10) {
                         // Some subpixel batches are drawn in two passes. Because of this, we need
@@ -194,17 +194,17 @@ impl AlphaBatchList {
                 let new_batch = PrimitiveBatch::new(key);
                 selected_batch_index = Some(self.batches.len());
                 self.batches.push(new_batch);
                 self.item_rects.push(Vec::new());
             }
 
             self.current_batch_index = selected_batch_index.unwrap();
             self.item_rects[self.current_batch_index].push(*bounding_rect);
-            self.current_prim_index = prim_index;
+            self.current_z_id = z_id;
         }
 
         &mut self.batches[self.current_batch_index].instances
     }
 }
 
 pub struct OpaqueBatchList {
     pub pixel_area_threshold_for_new_batch: f32,
@@ -292,57 +292,57 @@ impl BatchList {
             opaque_batch_list: OpaqueBatchList::new(batch_area_threshold),
         }
     }
 
     pub fn push_single_instance(
         &mut self,
         key: BatchKey,
         bounding_rect: &WorldRect,
-        prim_index: PrimitiveIndex,
+        z_id: ZBufferId,
         instance: PrimitiveInstanceData,
     ) {
         match key.blend_mode {
             BlendMode::None => {
                 self.opaque_batch_list
                     .set_params_and_get_batch(key, bounding_rect)
                     .push(instance);
             }
             BlendMode::Alpha |
             BlendMode::PremultipliedAlpha |
             BlendMode::PremultipliedDestOut |
             BlendMode::SubpixelConstantTextColor(..) |
             BlendMode::SubpixelWithBgColor |
             BlendMode::SubpixelDualSource => {
                 self.alpha_batch_list
-                    .set_params_and_get_batch(key, bounding_rect, prim_index)
+                    .set_params_and_get_batch(key, bounding_rect, z_id)
                     .push(instance);
             }
         }
     }
 
     pub fn set_params_and_get_batch(
         &mut self,
         key: BatchKey,
         bounding_rect: &WorldRect,
-        prim_index: PrimitiveIndex,
+        z_id: ZBufferId,
     ) -> &mut Vec<PrimitiveInstanceData> {
         match key.blend_mode {
             BlendMode::None => {
                 self.opaque_batch_list
                     .set_params_and_get_batch(key, bounding_rect)
             }
             BlendMode::Alpha |
             BlendMode::PremultipliedAlpha |
             BlendMode::PremultipliedDestOut |
             BlendMode::SubpixelConstantTextColor(..) |
             BlendMode::SubpixelWithBgColor |
             BlendMode::SubpixelDualSource => {
                 self.alpha_batch_list
-                    .set_params_and_get_batch(key, bounding_rect, prim_index)
+                    .set_params_and_get_batch(key, bounding_rect, z_id)
             }
         }
     }
 
     fn finalize(&mut self) {
         self.opaque_batch_list.finalize()
     }
 }
@@ -470,32 +470,34 @@ impl AlphaBatchBuilder {
         task_id: RenderTaskId,
         ctx: &RenderTargetContext,
         gpu_cache: &mut GpuCache,
         render_tasks: &RenderTaskTree,
         deferred_resolves: &mut Vec<DeferredResolve>,
         prim_headers: &mut PrimitiveHeaders,
         transforms: &mut TransformPalette,
         root_spatial_node_index: SpatialNodeIndex,
+        z_generator: &mut ZBufferIdGenerator,
     ) {
         let task_address = render_tasks.get_task_address(task_id);
 
         // Add each run in this picture to the batch.
         for prim_instance in &pic.prim_instances {
             self.add_prim_to_batch(
                 prim_instance,
                 ctx,
                 gpu_cache,
                 render_tasks,
                 task_id,
                 task_address,
                 deferred_resolves,
                 prim_headers,
                 transforms,
                 root_spatial_node_index,
+                z_generator,
             );
         }
     }
 
     // Adds a primitive to a batch.
     // It can recursively call itself in some situations, for
     // example if it encounters a picture where the items
     // in that picture are being drawn into the same target.
@@ -506,16 +508,17 @@ impl AlphaBatchBuilder {
         gpu_cache: &mut GpuCache,
         render_tasks: &RenderTaskTree,
         task_id: RenderTaskId,
         task_address: RenderTaskAddress,
         deferred_resolves: &mut Vec<DeferredResolve>,
         prim_headers: &mut PrimitiveHeaders,
         transforms: &mut TransformPalette,
         root_spatial_node_index: SpatialNodeIndex,
+        z_generator: &mut ZBufferIdGenerator,
     ) {
         let prim = &ctx.prim_store.primitives[prim_instance.prim_index.0];
 
         if prim_instance.clipped_world_rect.is_none() {
             return;
         }
 
         #[cfg(debug_assertions)] //TODO: why is this needed?
@@ -530,16 +533,17 @@ impl AlphaBatchBuilder {
 
         // TODO(gw): Calculating this for every primitive is a bit
         //           wasteful. We should probably cache this in
         //           the scroll node...
         let transform_kind = transform_id.transform_kind();
         let bounding_rect = prim_instance.clipped_world_rect
                                          .as_ref()
                                          .expect("bug");
+        let z_id = z_generator.next();
 
         // If the primitive is internally decomposed into multiple sub-primitives we may not
         // use some of the per-primitive data and get it from each sub-primitive instead.
         let is_multiple_primitives = match prim.details {
             PrimitiveDetails::Brush(ref brush) => {
                 match brush.kind {
                     BrushKind::Image { ref visible_tiles, .. } => !visible_tiles.is_empty(),
                     BrushKind::LinearGradient { ref visible_tiles, .. } => !visible_tiles.is_empty(),
@@ -588,17 +592,16 @@ impl AlphaBatchBuilder {
         match prim.details {
             PrimitiveDetails::Brush(ref brush) => {
                 match brush.kind {
                     BrushKind::Picture { pic_index } => {
                         let picture = &ctx.prim_store.pictures[pic_index.0];
                         match picture.context_3d {
                             // Convert all children of the 3D hierarchy root into batches.
                             Picture3DContext::In { root_data: Some(ref list), .. } => {
-                                let z = prim_headers.z_generator.next();
                                 for child in list {
                                     let prim_instance = &picture.prim_instances[child.anchor];
                                     let pic_primitive = &ctx.prim_store.primitives[prim_instance.prim_index.0];
 
                                     let clip_task_address = prim_instance
                                         .clip_task_id
                                         .map_or(OPAQUE_TASK_ADDRESS, |id| render_tasks.get_task_address(id));
 
@@ -632,38 +635,38 @@ impl AlphaBatchBuilder {
                                         .as_ref()
                                         .expect("BUG: no surface")
                                         .resolve(
                                             render_tasks,
                                             ctx.resource_cache,
                                             gpu_cache,
                                         );
 
-                                    let prim_header_index = prim_headers.push(&prim_header, [
+                                    let prim_header_index = prim_headers.push(&prim_header, z_id, [
                                         uv_rect_address.as_int(),
                                         0,
                                         0,
                                     ]);
 
                                     let key = BatchKey::new(
                                         BatchKind::SplitComposite,
                                         BlendMode::PremultipliedAlpha,
                                         BatchTextures::no_texture(),
                                     );
 
                                     let instance = SplitCompositeInstance::new(
                                         prim_header_index,
                                         child.gpu_address,
-                                        z,
+                                        z_id,
                                     );
 
                                     self.batch_list.push_single_instance(
                                         key,
                                         &prim_instance.clipped_world_rect.as_ref().expect("bug"),
-                                        prim_instance.prim_index,
+                                        z_id,
                                         PrimitiveInstanceData::from(instance),
                                     );
                                 }
                             }
                             // Ignore the 3D pictures that are not in the root of preserve-3D
                             // hierarchy, since we process them with the root.
                             Picture3DContext::In { root_data: None, .. } => return,
                             // Proceed for non-3D pictures.
@@ -689,17 +692,17 @@ impl AlphaBatchBuilder {
                                                         ctx.resource_cache,
                                                         gpu_cache,
                                                     );
                                                 let key = BatchKey::new(
                                                     kind,
                                                     non_segmented_blend_mode,
                                                     textures,
                                                 );
-                                                let prim_header_index = prim_headers.push(&prim_header, [
+                                                let prim_header_index = prim_headers.push(&prim_header, z_id, [
                                                     ShaderColorMode::Image as i32,
                                                     RasterizationSpace::Screen as i32,
                                                     0,
                                                 ]);
 
                                                 let instance = BrushInstance {
                                                     prim_header_index,
                                                     segment_index: 0,
@@ -707,17 +710,17 @@ impl AlphaBatchBuilder {
                                                     brush_flags: BrushFlags::empty(),
                                                     clip_task_address,
                                                     user_data: uv_rect_address.as_int(),
                                                 };
 
                                                 self.batch_list.push_single_instance(
                                                     key,
                                                     bounding_rect,
-                                                    prim_instance.prim_index,
+                                                    z_id,
                                                     PrimitiveInstanceData::from(instance),
                                                 );
                                             }
                                             FilterOp::DropShadow(offset, ..) => {
                                                 // Draw an instance of the shadow first, following by the content.
 
                                                 // Both the shadow and the content get drawn as a brush image.
                                                 let kind = BatchKind::Brush(
@@ -751,33 +754,36 @@ impl AlphaBatchBuilder {
                                                     .as_int();
                                                 let content_uv_rect_address = render_tasks[secondary_id]
                                                     .get_texture_address(gpu_cache)
                                                     .as_int();
 
                                                 // Get the GPU cache address of the extra data handle.
                                                 let shadow_prim_address = gpu_cache.get_address(&picture.extra_gpu_data_handle);
 
-                                                let content_prim_header_index = prim_headers.push(&prim_header, [
+                                                let z_id_shadow = z_id;
+                                                let z_id_content = z_generator.next();
+
+                                                let content_prim_header_index = prim_headers.push(&prim_header, z_id_content, [
                                                     ShaderColorMode::Image as i32,
                                                     RasterizationSpace::Screen as i32,
                                                     0,
                                                 ]);
 
                                                 let shadow_rect = prim.local_rect.translate(&offset);
                                                 let shadow_clip_rect = prim.local_clip_rect.translate(&offset);
 
                                                 let shadow_prim_header = PrimitiveHeader {
                                                     local_rect: shadow_rect,
                                                     local_clip_rect: shadow_clip_rect,
                                                     specific_prim_address: shadow_prim_address,
                                                     ..prim_header
                                                 };
 
-                                                let shadow_prim_header_index = prim_headers.push(&shadow_prim_header, [
+                                                let shadow_prim_header_index = prim_headers.push(&shadow_prim_header, z_id_shadow, [
                                                     ShaderColorMode::Alpha as i32,
                                                     RasterizationSpace::Screen as i32,
                                                     0,
                                                 ]);
 
                                                 let shadow_instance = BrushInstance {
                                                     prim_header_index: shadow_prim_header_index,
                                                     clip_task_address,
@@ -794,24 +800,24 @@ impl AlphaBatchBuilder {
                                                     edge_flags: EdgeAaSegmentMask::empty(),
                                                     brush_flags: BrushFlags::empty(),
                                                     user_data: content_uv_rect_address,
                                                 };
 
                                                 self.batch_list.push_single_instance(
                                                     shadow_key,
                                                     bounding_rect,
-                                                    prim_instance.prim_index,
+                                                    z_id_shadow,
                                                     PrimitiveInstanceData::from(shadow_instance),
                                                 );
 
                                                 self.batch_list.push_single_instance(
                                                     content_key,
                                                     bounding_rect,
-                                                    prim_instance.prim_index,
+                                                    z_id_content,
                                                     PrimitiveInstanceData::from(content_instance),
                                                 );
                                             }
                                             _ => {
                                                 let filter_mode = match filter {
                                                     FilterOp::Identity => 1, // matches `Contrast(1)`
                                                     FilterOp::Blur(..) => 0,
                                                     FilterOp::Contrast(..) => 1,
@@ -861,17 +867,17 @@ impl AlphaBatchBuilder {
                                                     );
 
                                                 let key = BatchKey::new(
                                                     BatchKind::Brush(BrushBatchKind::Blend),
                                                     BlendMode::PremultipliedAlpha,
                                                     textures,
                                                 );
 
-                                                let prim_header_index = prim_headers.push(&prim_header, [
+                                                let prim_header_index = prim_headers.push(&prim_header, z_id, [
                                                     uv_rect_address.as_int(),
                                                     filter_mode,
                                                     user_data,
                                                 ]);
 
                                                 let instance = BrushInstance {
                                                     prim_header_index,
                                                     clip_task_address,
@@ -879,17 +885,17 @@ impl AlphaBatchBuilder {
                                                     edge_flags: EdgeAaSegmentMask::empty(),
                                                     brush_flags: BrushFlags::empty(),
                                                     user_data: 0,
                                                 };
 
                                                 self.batch_list.push_single_instance(
                                                     key,
                                                     bounding_rect,
-                                                    prim_instance.prim_index,
+                                                    z_id,
                                                     PrimitiveInstanceData::from(instance),
                                                 );
                                             }
                                         }
                                     }
                                     PictureCompositeMode::MixBlend(mode) => {
                                         let cache_task_id = surface.resolve_render_task_id();
                                         let backdrop_id = picture.secondary_render_task_id.expect("no backdrop!?");
@@ -902,17 +908,17 @@ impl AlphaBatchBuilder {
                                                     backdrop_id,
                                                 },
                                             ),
                                             BlendMode::PremultipliedAlpha,
                                             BatchTextures::no_texture(),
                                         );
                                         let backdrop_task_address = render_tasks.get_task_address(backdrop_id);
                                         let source_task_address = render_tasks.get_task_address(cache_task_id);
-                                        let prim_header_index = prim_headers.push(&prim_header, [
+                                        let prim_header_index = prim_headers.push(&prim_header, z_id, [
                                             mode as u32 as i32,
                                             backdrop_task_address.0 as i32,
                                             source_task_address.0 as i32,
                                         ]);
 
                                         let instance = BrushInstance {
                                             prim_header_index,
                                             clip_task_address,
@@ -920,17 +926,17 @@ impl AlphaBatchBuilder {
                                             edge_flags: EdgeAaSegmentMask::empty(),
                                             brush_flags: BrushFlags::empty(),
                                             user_data: 0,
                                         };
 
                                         self.batch_list.push_single_instance(
                                             key,
                                             bounding_rect,
-                                            prim_instance.prim_index,
+                                            z_id,
                                             PrimitiveInstanceData::from(instance),
                                         );
                                     }
                                     PictureCompositeMode::Blit => {
                                         let cache_task_id = surface.resolve_render_task_id();
                                         let kind = BatchKind::Brush(
                                             BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
                                         );
@@ -938,17 +944,17 @@ impl AlphaBatchBuilder {
                                             kind,
                                             non_segmented_blend_mode,
                                             BatchTextures::render_target_cache(),
                                         );
 
                                         let uv_rect_address = render_tasks[cache_task_id]
                                             .get_texture_address(gpu_cache)
                                             .as_int();
-                                        let prim_header_index = prim_headers.push(&prim_header, [
+                                        let prim_header_index = prim_headers.push(&prim_header, z_id, [
                                             ShaderColorMode::Image as i32,
                                             RasterizationSpace::Screen as i32,
                                             0,
                                         ]);
 
                                         let instance = BrushInstance {
                                             prim_header_index,
                                             clip_task_address,
@@ -956,17 +962,17 @@ impl AlphaBatchBuilder {
                                             edge_flags: EdgeAaSegmentMask::empty(),
                                             brush_flags: BrushFlags::empty(),
                                             user_data: uv_rect_address,
                                         };
 
                                         self.batch_list.push_single_instance(
                                             key,
                                             bounding_rect,
-                                            prim_instance.prim_index,
+                                            z_id,
                                             PrimitiveInstanceData::from(instance),
                                         );
                                     }
                                 }
                             }
                             None => {
                                 // If this picture is being drawn into an existing target (i.e. with
                                 // no composition operation), recurse and add to the current batch list.
@@ -975,16 +981,17 @@ impl AlphaBatchBuilder {
                                     task_id,
                                     ctx,
                                     gpu_cache,
                                     render_tasks,
                                     deferred_resolves,
                                     prim_headers,
                                     transforms,
                                     root_spatial_node_index,
+                                    z_generator,
                                 );
                             }
                         }
                     }
                     BrushKind::Image { request, ref visible_tiles, .. } if !visible_tiles.is_empty() => {
                         for tile in visible_tiles {
                             if let Some((batch_kind, textures, user_data, uv_rect_address)) = get_image_tile_params(
                                     ctx.resource_cache,
@@ -994,86 +1001,87 @@ impl AlphaBatchBuilder {
                             ) {
                                 let prim_cache_address = gpu_cache.get_address(&tile.handle);
                                 let prim_header = PrimitiveHeader {
                                     specific_prim_address: prim_cache_address,
                                     local_rect: tile.local_rect,
                                     local_clip_rect: tile.local_clip_rect,
                                     ..prim_header
                                 };
-                                let prim_header_index = prim_headers.push(&prim_header, user_data);
+                                let prim_header_index = prim_headers.push(&prim_header, z_id, user_data);
 
                                 self.add_image_tile_to_batch(
-                                    prim_instance,
                                     batch_kind,
                                     specified_blend_mode,
                                     textures,
                                     prim_header_index,
                                     clip_task_address,
                                     bounding_rect,
                                     tile.edge_flags,
                                     uv_rect_address,
+                                    z_id,
                                 );
                             }
                         }
                     }
                     BrushKind::LinearGradient { ref stops_handle, ref visible_tiles, .. } if !visible_tiles.is_empty() => {
                         add_gradient_tiles(
-                            prim_instance,
                             visible_tiles,
                             stops_handle,
                             BrushBatchKind::LinearGradient,
                             specified_blend_mode,
                             bounding_rect,
                             clip_task_address,
                             gpu_cache,
                             &mut self.batch_list,
                             &prim_header,
                             prim_headers,
+                            z_id,
                         );
                     }
                     BrushKind::RadialGradient { ref stops_handle, ref visible_tiles, .. } if !visible_tiles.is_empty() => {
                         add_gradient_tiles(
-                            prim_instance,
                             visible_tiles,
                             stops_handle,
                             BrushBatchKind::RadialGradient,
                             specified_blend_mode,
                             bounding_rect,
                             clip_task_address,
                             gpu_cache,
                             &mut self.batch_list,
                             &prim_header,
                             prim_headers,
+                            z_id,
                         );
                     }
                     _ => {
                         if let Some(params) = brush.get_batch_params(
                             ctx.resource_cache,
                             gpu_cache,
                             deferred_resolves,
                             ctx.prim_store.chase_id == Some(prim_instance.prim_index),
                         ) {
-                            let prim_header_index = prim_headers.push(&prim_header, params.prim_user_data);
+                            let prim_header_index = prim_headers.push(&prim_header, z_id, params.prim_user_data);
                             if cfg!(debug_assertions) && ctx.prim_store.chase_id == Some(prim_instance.prim_index) {
                                 println!("\t{:?} {:?}, task relative bounds {:?}",
                                     params.batch_kind, prim_header_index, bounding_rect);
                             }
 
                             self.add_brush_to_batch(
                                 brush,
                                 &params,
                                 prim_instance,
                                 specified_blend_mode,
                                 non_segmented_blend_mode,
                                 prim_header_index,
                                 clip_task_address,
                                 bounding_rect,
                                 transform_kind,
                                 render_tasks,
+                                z_id,
                             );
                         }
                     }
                 }
             }
             PrimitiveDetails::TextRun(ref text_cpu) => {
                 let subpx_dir = text_cpu.used_font.get_subpx_dir();
 
@@ -1141,25 +1149,25 @@ impl AlphaBatchBuilder {
                             GlyphFormat::ColorBitmap => {
                                 (
                                     BlendMode::PremultipliedAlpha,
                                     ShaderColorMode::ColorBitmap,
                                 )
                             }
                         };
 
-                        let prim_header_index = prim_headers.push(&prim_header, [0; 3]);
+                        let prim_header_index = prim_headers.push(&prim_header, z_id, [0; 3]);
                         let key = BatchKey::new(kind, blend_mode, textures);
                         let base_instance = GlyphInstance::new(
                             prim_header_index,
                         );
                         let batch = alpha_batch_list.set_params_and_get_batch(
                             key,
                             bounding_rect,
-                            prim_instance.prim_index,
+                            z_id,
                         );
 
                         for glyph in glyphs {
                             batch.push(base_instance.build(
                                 glyph.index_in_text_run,
                                 glyph.uv_rect_address.as_int(),
                                 (subpx_dir as u32 as i32) << 16 |
                                 (color_mode as u32 as i32),
@@ -1168,25 +1176,25 @@ impl AlphaBatchBuilder {
                     },
                 );
             }
         }
     }
 
     fn add_image_tile_to_batch(
         &mut self,
-        prim_instance: &PrimitiveInstance,
         batch_kind: BrushBatchKind,
         blend_mode: BlendMode,
         textures: BatchTextures,
         prim_header_index: PrimitiveHeaderIndex,
         clip_task_address: RenderTaskAddress,
         bounding_rect: &WorldRect,
         edge_flags: EdgeAaSegmentMask,
         uv_rect_address: GpuCacheAddress,
+        z_id: ZBufferId,
     ) {
         let base_instance = BrushInstance {
             prim_header_index,
             clip_task_address,
             segment_index: 0,
             edge_flags,
             brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
             user_data: uv_rect_address.as_int(),
@@ -1195,17 +1203,17 @@ impl AlphaBatchBuilder {
         let batch_key = BatchKey {
             blend_mode,
             kind: BatchKind::Brush(batch_kind),
             textures,
         };
         self.batch_list.push_single_instance(
             batch_key,
             bounding_rect,
-            prim_instance.prim_index,
+            z_id,
             PrimitiveInstanceData::from(base_instance),
         );
     }
 
     /// Add a single segment instance to a batch.
     fn add_segment_to_batch(
         &mut self,
         segment: &BrushSegment,
@@ -1213,16 +1221,17 @@ impl AlphaBatchBuilder {
         segment_index: i32,
         batch_kind: BrushBatchKind,
         prim_instance: &PrimitiveInstance,
         prim_header_index: PrimitiveHeaderIndex,
         alpha_blend_mode: BlendMode,
         bounding_rect: &WorldRect,
         transform_kind: TransformedRectKind,
         render_tasks: &RenderTaskTree,
+        z_id: ZBufferId,
     ) {
         let clip_task_address = match segment.clip_task_id {
             BrushSegmentTaskId::RenderTaskId(id) =>
                 render_tasks.get_task_address(id),
             BrushSegmentTaskId::Opaque => OPAQUE_TASK_ADDRESS,
             BrushSegmentTaskId::Empty => return,
         };
 
@@ -1252,17 +1261,17 @@ impl AlphaBatchBuilder {
             blend_mode: if needs_blending { alpha_blend_mode } else { BlendMode::None },
             kind: BatchKind::Brush(batch_kind),
             textures: segment_data.textures,
         };
 
         self.batch_list.push_single_instance(
             batch_key,
             bounding_rect,
-            prim_instance.prim_index,
+            z_id,
             instance,
         );
     }
 
     /// Add any segment(s) from a brush to batches.
     fn add_brush_to_batch(
         &mut self,
         brush: &BrushPrimitive,
@@ -1270,16 +1279,17 @@ impl AlphaBatchBuilder {
         prim_instance: &PrimitiveInstance,
         alpha_blend_mode: BlendMode,
         non_segmented_blend_mode: BlendMode,
         prim_header_index: PrimitiveHeaderIndex,
         clip_task_address: RenderTaskAddress,
         bounding_rect: &WorldRect,
         transform_kind: TransformedRectKind,
         render_tasks: &RenderTaskTree,
+        z_id: ZBufferId,
     ) {
         match (&brush.segment_desc, &params.segment_data) {
             (Some(ref segment_desc), SegmentDataKind::Instanced(ref segment_data)) => {
                 // In this case, we have both a list of segments, and a list of
                 // per-segment instance data. Zip them together to build batches.
                 debug_assert_eq!(segment_desc.segments.len(), segment_data.len());
                 for (segment_index, (segment, segment_data)) in segment_desc.segments
                     .iter()
@@ -1291,16 +1301,17 @@ impl AlphaBatchBuilder {
                         segment_index as i32,
                         params.batch_kind,
                         prim_instance,
                         prim_header_index,
                         alpha_blend_mode,
                         bounding_rect,
                         transform_kind,
                         render_tasks,
+                        z_id,
                     );
                 }
             }
             (Some(ref segment_desc), SegmentDataKind::Shared(ref segment_data)) => {
                 // A list of segments, but the per-segment data is common
                 // between all segments.
                 for (segment_index, segment) in segment_desc.segments
                     .iter()
@@ -1311,16 +1322,17 @@ impl AlphaBatchBuilder {
                         segment_index as i32,
                         params.batch_kind,
                         prim_instance,
                         prim_header_index,
                         alpha_blend_mode,
                         bounding_rect,
                         transform_kind,
                         render_tasks,
+                        z_id,
                     );
                 }
             }
             (None, SegmentDataKind::Shared(ref segment_data)) => {
                 // No segments, and thus no per-segment instance data.
                 let batch_key = BatchKey {
                     blend_mode: non_segmented_blend_mode,
                     kind: BatchKind::Brush(params.batch_kind),
@@ -1332,62 +1344,62 @@ impl AlphaBatchBuilder {
                     clip_task_address,
                     brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
                     prim_header_index,
                     user_data: segment_data.user_data,
                 });
                 self.batch_list.push_single_instance(
                     batch_key,
                     bounding_rect,
-                    prim_instance.prim_index,
+                    z_id,
                     PrimitiveInstanceData::from(instance),
                 );
             }
             (None, SegmentDataKind::Instanced(..)) => {
                 // We should never hit the case where there are no segments,
                 // but a list of segment instance data.
                 unreachable!();
             }
         }
     }
 }
 
 fn add_gradient_tiles(
-    prim_instance: &PrimitiveInstance,
     visible_tiles: &[VisibleGradientTile],
     stops_handle: &GpuCacheHandle,
     kind: BrushBatchKind,
     blend_mode: BlendMode,
     bounding_rect: &WorldRect,
     clip_task_address: RenderTaskAddress,
     gpu_cache: &GpuCache,
     batch_list: &mut BatchList,
     base_prim_header: &PrimitiveHeader,
     prim_headers: &mut PrimitiveHeaders,
+    z_id: ZBufferId,
 ) {
     let batch = batch_list.set_params_and_get_batch(
         BatchKey {
             blend_mode: blend_mode,
             kind: BatchKind::Brush(kind),
             textures: BatchTextures::no_texture(),
         },
         bounding_rect,
-        prim_instance.prim_index,
+        z_id,
     );
 
     let user_data = [stops_handle.as_int(gpu_cache), 0, 0];
 
     for tile in visible_tiles {
         let prim_header = PrimitiveHeader {
             specific_prim_address: gpu_cache.get_address(&tile.handle),
             local_rect: tile.local_rect,
             local_clip_rect: tile.local_clip_rect,
             ..*base_prim_header
         };
-        let prim_header_index = prim_headers.push(&prim_header, user_data);
+        let prim_header_index = prim_headers.push(&prim_header, z_id, user_data);
 
         batch.push(PrimitiveInstanceData::from(
             BrushInstance {
                 prim_header_index,
                 clip_task_address,
                 segment_index: 0,
                 edge_flags: EdgeAaSegmentMask::all(),
                 brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -4,17 +4,17 @@
 
 use api::{ColorF, DeviceIntPoint, DevicePixelScale, LayoutPixel, PicturePixel, RasterPixel};
 use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentLayer, FontRenderMode, PictureRect};
 use api::{LayoutPoint, LayoutRect, LayoutSize, PipelineId, RasterSpace, WorldPoint, WorldRect, WorldPixel};
 use clip::{ClipDataStore, ClipStore};
 use clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex};
 use display_list_flattener::{DisplayListFlattener};
 use gpu_cache::GpuCache;
-use gpu_types::{PrimitiveHeaders, TransformPalette, UvRectKind};
+use gpu_types::{PrimitiveHeaders, TransformPalette, UvRectKind, ZBufferIdGenerator};
 use hit_test::{HitTester, HitTestingRun};
 use internal_types::{FastHashMap, PlaneSplitter};
 use picture::{PictureCompositeMode, PictureSurface, RasterConfig};
 use prim_store::{PrimitiveIndex, PrimitiveStore, SpaceMapper, PictureIndex};
 use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
 use render_backend::{FrameResources, FrameId};
 use render_task::{RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree};
 use resource_cache::{ResourceCache};
@@ -375,16 +375,18 @@ impl FrameBuilder {
                 required_pass_count - 1,
                 &mut passes[2..],
             );
         }
 
         let mut deferred_resolves = vec![];
         let mut has_texture_cache_tasks = false;
         let mut prim_headers = PrimitiveHeaders::new();
+        // Used to generated a unique z-buffer value per primitive.
+        let mut z_generator = ZBufferIdGenerator::new();
         let use_dual_source_blending = self.config.dual_source_blending_is_enabled &&
                                        self.config.dual_source_blending_is_supported;
 
         for pass in &mut passes {
             let mut ctx = RenderTargetContext {
                 device_pixel_scale,
                 prim_store: &self.prim_store,
                 resource_cache,
@@ -396,16 +398,17 @@ impl FrameBuilder {
             pass.build(
                 &mut ctx,
                 gpu_cache,
                 &mut render_tasks,
                 &mut deferred_resolves,
                 &self.clip_store,
                 &mut transform_palette,
                 &mut prim_headers,
+                &mut z_generator,
             );
 
             if let RenderPassKind::OffScreen { ref texture_cache, .. } = pass.kind {
                 has_texture_cache_tasks |= !texture_cache.is_empty();
             }
         }
 
         let gpu_cache_frame_id = gpu_cache.end_frame(gpu_cache_profile);
--- a/gfx/webrender/src/gpu_types.rs
+++ b/gfx/webrender/src/gpu_types.rs
@@ -7,26 +7,33 @@ use api::{
     PremultipliedColorF, LayoutToPictureTransform, PictureToLayoutTransform, PicturePixel,
     WorldPixel, WorldToLayoutTransform,
 };
 use clip_scroll_tree::{ClipScrollTree, ROOT_SPATIAL_NODE_INDEX, SpatialNodeIndex};
 use gpu_cache::{GpuCacheAddress, GpuDataRequest};
 use internal_types::FastHashMap;
 use prim_store::EdgeAaSegmentMask;
 use render_task::RenderTaskAddress;
+use std::i32;
 use util::{TransformedRectKind, MatrixHelpers};
 
 // Contains type that must exactly match the same structures declared in GLSL.
 
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, PartialEq)]
 #[repr(C)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct ZBufferId(i32);
 
+impl ZBufferId {
+    pub fn invalid() -> Self {
+        ZBufferId(i32::MAX)
+    }
+}
+
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct ZBufferIdGenerator {
     next: i32,
 }
 
 impl ZBufferIdGenerator {
@@ -162,45 +169,43 @@ pub struct PrimitiveHeaderIndex(pub i32)
 #[repr(C)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct PrimitiveHeaders {
     // The integer-type headers for a primitive.
     pub headers_int: Vec<PrimitiveHeaderI>,
     // The float-type headers for a primitive.
     pub headers_float: Vec<PrimitiveHeaderF>,
-    // Used to generated a unique z-buffer value per primitive.
-    pub z_generator: ZBufferIdGenerator,
 }
 
 impl PrimitiveHeaders {
     pub fn new() -> PrimitiveHeaders {
         PrimitiveHeaders {
             headers_int: Vec::new(),
             headers_float: Vec::new(),
-            z_generator: ZBufferIdGenerator::new(),
         }
     }
 
     // Add a new primitive header.
     pub fn push(
         &mut self,
         prim_header: &PrimitiveHeader,
+        z: ZBufferId,
         user_data: [i32; 3],
     ) -> PrimitiveHeaderIndex {
         debug_assert_eq!(self.headers_int.len(), self.headers_float.len());
         let id = self.headers_float.len();
 
         self.headers_float.push(PrimitiveHeaderF {
             local_rect: prim_header.local_rect,
             local_clip_rect: prim_header.local_clip_rect,
         });
 
         self.headers_int.push(PrimitiveHeaderI {
-            z: self.z_generator.next(),
+            z,
             task_address: prim_header.task_address,
             specific_prim_address: prim_header.specific_prim_address.as_int(),
             clip_task_address: prim_header.clip_task_address,
             transform_id: prim_header.transform_id,
             user_data,
         });
 
         PrimitiveHeaderIndex(id as i32)
--- a/gfx/webrender/src/tiling.rs
+++ b/gfx/webrender/src/tiling.rs
@@ -8,17 +8,17 @@ use api::{MixBlendMode, PipelineId, Devi
 use batch::{AlphaBatchBuilder, AlphaBatchContainer, ClipBatcher, resolve_image};
 use clip::ClipStore;
 use clip_scroll_tree::{ClipScrollTree};
 use device::{FrameId, Texture};
 #[cfg(feature = "pathfinder")]
 use euclid::{TypedPoint2D, TypedVector2D};
 use gpu_cache::{GpuCache};
 use gpu_types::{BorderInstance, BlurDirection, BlurInstance, PrimitiveHeaders, ScalingInstance};
-use gpu_types::{TransformData, TransformPalette};
+use gpu_types::{TransformData, TransformPalette, ZBufferIdGenerator};
 use internal_types::{CacheTextureId, FastHashMap, SavedTargetIndex, TextureSource};
 #[cfg(feature = "pathfinder")]
 use pathfinder_partitioner::mesh::Mesh;
 use prim_store::{PrimitiveStore, DeferredResolve};
 use profiler::FrameProfileCounters;
 use render_backend::FrameResources;
 use render_task::{BlitSource, RenderTaskAddress, RenderTaskId, RenderTaskKind};
 use render_task::{BlurTask, ClearMode, GlyphTask, RenderTaskLocation, RenderTaskTree, ScalingTask};
@@ -119,16 +119,17 @@ pub trait RenderTarget {
     fn build(
         &mut self,
         _ctx: &mut RenderTargetContext,
         _gpu_cache: &mut GpuCache,
         _render_tasks: &mut RenderTaskTree,
         _deferred_resolves: &mut Vec<DeferredResolve>,
         _prim_headers: &mut PrimitiveHeaders,
         _transforms: &mut TransformPalette,
+        _z_generator: &mut ZBufferIdGenerator,
     ) {
     }
 
     /// Associates a `RenderTask` with this target. That task must be assigned
     /// to a region returned by invoking `allocate()` on this target.
     ///
     /// TODO(gw): It's a bit odd that we need the deferred resolves and mutable
     /// GPU cache here. They are typically used by the build step above. They
@@ -212,28 +213,30 @@ impl<T: RenderTarget> RenderTargetList<T
         &mut self,
         ctx: &mut RenderTargetContext,
         gpu_cache: &mut GpuCache,
         render_tasks: &mut RenderTaskTree,
         deferred_resolves: &mut Vec<DeferredResolve>,
         saved_index: Option<SavedTargetIndex>,
         prim_headers: &mut PrimitiveHeaders,
         transforms: &mut TransformPalette,
+        z_generator: &mut ZBufferIdGenerator,
     ) {
         debug_assert_eq!(None, self.saved_index);
         self.saved_index = saved_index;
 
         for target in &mut self.targets {
             target.build(
                 ctx,
                 gpu_cache,
                 render_tasks,
                 deferred_resolves,
                 prim_headers,
                 transforms,
+                z_generator,
             );
         }
     }
 
     fn add_task(
         &mut self,
         task_id: RenderTaskId,
         ctx: &RenderTargetContext,
@@ -394,16 +397,17 @@ impl RenderTarget for ColorRenderTarget 
     fn build(
         &mut self,
         ctx: &mut RenderTargetContext,
         gpu_cache: &mut GpuCache,
         render_tasks: &mut RenderTaskTree,
         deferred_resolves: &mut Vec<DeferredResolve>,
         prim_headers: &mut PrimitiveHeaders,
         transforms: &mut TransformPalette,
+        z_generator: &mut ZBufferIdGenerator,
     ) {
         let mut merged_batches = AlphaBatchContainer::new(None);
 
         for task_id in &self.alpha_tasks {
             let task = &render_tasks[*task_id];
 
             match task.kind {
                 RenderTaskKind::Picture(ref pic_task) => {
@@ -422,16 +426,17 @@ impl RenderTarget for ColorRenderTarget 
                         *task_id,
                         ctx,
                         gpu_cache,
                         render_tasks,
                         deferred_resolves,
                         prim_headers,
                         transforms,
                         pic_task.root_spatial_node_index,
+                        z_generator,
                     );
 
                     if let Some(batch_container) = batch_builder.build(&mut merged_batches) {
                         self.alpha_batch_containers.push(batch_container);
                     }
                 }
                 _ => {
                     unreachable!();
@@ -890,16 +895,17 @@ impl RenderPass {
         &mut self,
         ctx: &mut RenderTargetContext,
         gpu_cache: &mut GpuCache,
         render_tasks: &mut RenderTaskTree,
         deferred_resolves: &mut Vec<DeferredResolve>,
         clip_store: &ClipStore,
         transforms: &mut TransformPalette,
         prim_headers: &mut PrimitiveHeaders,
+        z_generator: &mut ZBufferIdGenerator,
     ) {
         profile_scope!("RenderPass::build");
 
         match self.kind {
             RenderPassKind::MainFramebuffer(ref mut target) => {
                 for &task_id in &self.tasks {
                     assert_eq!(render_tasks[task_id].target_kind(), RenderTargetKind::Color);
                     target.add_task(
@@ -914,16 +920,17 @@ impl RenderPass {
                 }
                 target.build(
                     ctx,
                     gpu_cache,
                     render_tasks,
                     deferred_resolves,
                     prim_headers,
                     transforms,
+                    z_generator,
                 );
             }
             RenderPassKind::OffScreen { ref mut color, ref mut alpha, ref mut texture_cache } => {
                 let saved_color = if self.tasks.iter().any(|&task_id| {
                     let t = &render_tasks[task_id];
                     t.target_kind() == RenderTargetKind::Color && t.saved_index.is_some()
                 }) {
                     Some(render_tasks.save_target())
@@ -1018,25 +1025,27 @@ impl RenderPass {
                 color.build(
                     ctx,
                     gpu_cache,
                     render_tasks,
                     deferred_resolves,
                     saved_color,
                     prim_headers,
                     transforms,
+                    z_generator,
                 );
                 alpha.build(
                     ctx,
                     gpu_cache,
                     render_tasks,
                     deferred_resolves,
                     saved_alpha,
                     prim_headers,
                     transforms,
+                    z_generator,
                 );
             }
         }
     }
 }
 
 #[derive(Debug, Clone, Default)]
 pub struct CompositeOps {
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-9b1a2f7e46cfb3496d43421b828543b08bb45810
+a8817b943a2fd0038307a7432fdf5cbccf4a943e