Bug 1595965 - Fix tile draw order with native compositor mode. r=sotaro
authorGlenn Watson <git@intuitionlibrary.com>
Thu, 14 Nov 2019 02:01:45 +0000
changeset 501880 e7837d7a78c67fb122f6f4685eb0e2f06841b621
parent 501879 7369676b8ab5d4ea0d0461299e0e8a10361a612c
child 501881 9acbf3949ad78573c5a99452b0fe9db6ff7d0815
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssotaro
bugs1595965
milestone72.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 1595965 - Fix tile draw order with native compositor mode. r=sotaro In Draw compositor mode, tiles are placed into a bucket based on the tile kind and/or opacity. This simplifies the renderer code for this mode, which uses the z-buffer to reject opaque tiles. In native compositor mode, the tiles need to be submitted in the correct draw order. Opacity is a property of the native surface, and should not affect the order the tiles are added to the visual tree of the native compositor. Differential Revision: https://phabricator.services.mozilla.com/D52933
gfx/wr/webrender/src/batch.rs
gfx/wr/webrender/src/composite.rs
gfx/wr/webrender/src/renderer.rs
--- a/gfx/wr/webrender/src/batch.rs
+++ b/gfx/wr/webrender/src/batch.rs
@@ -1201,55 +1201,42 @@ impl BatchBuilder {
                                     let tile = &tile_cache.tiles[key];
                                     if !tile.is_visible {
                                         // This can occur when a tile is found to be occluded during frame building.
                                         continue;
                                     }
                                     let device_rect = (tile.world_rect * ctx.global_device_pixel_scale).round();
                                     let dirty_rect = (tile.world_dirty_rect * ctx.global_device_pixel_scale).round();
                                     let surface = tile.surface.as_ref().expect("no tile surface set!");
-                                    match surface {
+
+                                    let (surface, is_opaque) = match surface {
                                         TileSurface::Color { color } => {
-                                            composite_state.opaque_tiles.push(CompositeTile {
-                                                surface: CompositeTileSurface::Color { color: *color },
-                                                rect: device_rect,
-                                                dirty_rect,
-                                                clip_rect: device_clip_rect,
-                                                z_id,
-                                            });
+                                            (CompositeTileSurface::Color { color: *color }, true)
                                         }
                                         TileSurface::Clear => {
-                                            composite_state.clear_tiles.push(CompositeTile {
-                                                surface: CompositeTileSurface::Clear,
-                                                rect: device_rect,
-                                                dirty_rect,
-                                                clip_rect: device_clip_rect,
-                                                z_id,
-                                            });
+                                            (CompositeTileSurface::Clear, false)
                                         }
                                         TileSurface::Texture { descriptor, .. } => {
                                             let surface = descriptor.resolve(ctx.resource_cache);
+                                            (
+                                                CompositeTileSurface::Texture { surface },
+                                                tile.is_opaque || tile_cache.is_opaque(),
+                                            )
+                                        }
+                                    };
 
-                                            let composite_tile = CompositeTile {
-                                                surface: CompositeTileSurface::Texture {
-                                                    surface,
-                                                },
-                                                rect: device_rect,
-                                                dirty_rect,
-                                                clip_rect: device_clip_rect,
-                                                z_id,
-                                            };
+                                    let tile = CompositeTile {
+                                        surface,
+                                        rect: device_rect,
+                                        dirty_rect,
+                                        clip_rect: device_clip_rect,
+                                        z_id,
+                                    };
 
-                                            if tile.is_opaque || tile_cache.is_opaque() {
-                                                composite_state.opaque_tiles.push(composite_tile);
-                                            } else {
-                                                composite_state.alpha_tiles.push(composite_tile);
-                                            }
-                                        }
-                                    }
+                                    composite_state.push_tile(tile, is_opaque);
                                 }
                             }
                             PictureCompositeMode::Filter(ref filter) => {
                                 assert!(filter.is_visible());
                                 match filter {
                                     Filter::Blur(..) => {
                                         let kind = BatchKind::Brush(
                                             BrushBatchKind::Image(ImageBufferKind::Texture2DArray)
--- a/gfx/wr/webrender/src/composite.rs
+++ b/gfx/wr/webrender/src/composite.rs
@@ -132,19 +132,29 @@ struct Occluder {
     slice: usize,
     device_rect: DeviceIntRect,
 }
 
 /// The list of tiles to be drawn this frame
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct CompositeState {
+    // TODO(gw): Consider splitting up CompositeState into separate struct types depending
+    //           on the selected compositing mode. Many of the fields in this state struct
+    //           are only applicable to either Native or Draw compositing mode.
+    /// List of tiles to be drawn by the native compositor. These are added in draw order
+    /// and not separated by kind (opacity is a property of the native surface).
+    pub native_tiles: Vec<CompositeTile>,
+    /// List of opaque tiles to be drawn by the Draw compositor.
     pub opaque_tiles: Vec<CompositeTile>,
+    /// List of alpha tiles to be drawn by the Draw compositor.
     pub alpha_tiles: Vec<CompositeTile>,
+    /// List of clear tiles to be drawn by the Draw compositor.
     pub clear_tiles: Vec<CompositeTile>,
+    /// Used to generate z-id values for tiles in the Draw compositor mode.
     pub z_generator: ZBufferIdGenerator,
     // If false, we can't rely on the dirty rects in the CompositeTile
     // instances. This currently occurs during a scroll event, as a
     // signal to refresh the whole screen. This is only a temporary
     // measure until we integrate with OS compositors. In the meantime
     // it gives us the ability to partial present for any non-scroll
     // case as a simple win (e.g. video, animation etc).
     pub dirty_rects_are_valid: bool,
@@ -174,16 +184,17 @@ impl CompositeState {
         if let CompositorKind::Native { .. } = compositor_kind {
             if !picture_caching_is_enabled {
                 warn!("Picture caching cannot be disabled in native compositor config");
             }
             picture_caching_is_enabled = true;
         }
 
         CompositeState {
+            native_tiles: Vec::new(),
             opaque_tiles: Vec::new(),
             alpha_tiles: Vec::new(),
             clear_tiles: Vec::new(),
             z_generator: ZBufferIdGenerator::new(0),
             dirty_rects_are_valid: true,
             native_surface_updates: Vec::new(),
             compositor_kind,
             picture_caching_is_enabled,
@@ -268,16 +279,58 @@ impl CompositeState {
 
         // Calculate the non-overlapping area of the valid occluders.
         let cover_area = area_of_occluders(&self.occluders, slice, &device_rect);
         debug_assert!(cover_area <= ref_area);
 
         // Check if the tile area is completely covered
         ref_area == cover_area
     }
+
+    /// Add a tile to the appropriate array, depending on tile properties and compositor mode.
+    pub fn push_tile(
+        &mut self,
+        tile: CompositeTile,
+        is_opaque: bool,
+    ) {
+        match (self.compositor_kind, &tile.surface) {
+            (CompositorKind::Draw { .. }, CompositeTileSurface::Color { .. }) => {
+                // Color tiles are, by definition, opaque. We might support non-opaque color
+                // tiles if we ever find pages that have a lot of these.
+                self.opaque_tiles.push(tile);
+            }
+            (CompositorKind::Draw { .. }, CompositeTileSurface::Clear) => {
+                // Clear tiles have a special bucket
+                self.clear_tiles.push(tile);
+            }
+            (CompositorKind::Draw { .. }, CompositeTileSurface::Texture { .. }) => {
+                // Texture surfaces get bucketed by opaque/alpha, for z-rejection
+                // on the Draw compositor mode.
+                if is_opaque {
+                    self.opaque_tiles.push(tile);
+                } else {
+                    self.alpha_tiles.push(tile);
+                }
+            }
+            (CompositorKind::Native { .. }, CompositeTileSurface::Color { .. }) => {
+                // Native compositor doesn't (yet) support color surfaces.
+                unreachable!();
+            }
+            (CompositorKind::Native { .. }, CompositeTileSurface::Clear) => {
+                // Native compositor doesn't support color surfaces.
+                unreachable!();
+            }
+            (CompositorKind::Native { .. }, CompositeTileSurface::Texture { .. }) => {
+                // Native tiles are supplied to the OS compositor in draw order,
+                // since there is no z-buffer involved (opacity is supplied as part
+                // of the surface properties).
+                self.native_tiles.push(tile);
+            }
+        }
+    }
 }
 
 /// An arbitrary identifier for a native (OS compositor) surface
 #[repr(C)]
 #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 pub struct NativeSurfaceId(pub u64);
--- a/gfx/wr/webrender/src/renderer.rs
+++ b/gfx/wr/webrender/src/renderer.rs
@@ -6757,17 +6757,17 @@ impl CompositeState {
     /// cache tiles to the OS compositor
     fn composite_native(
         &self,
         compositor: &mut dyn Compositor,
     ) {
         // For each tile, update the properties with the native OS compositor,
         // such as position and clip rect. z-order of the tiles are implicit based
         // on the order they are added in this loop.
-        for tile in self.opaque_tiles.iter().chain(self.alpha_tiles.iter()) {
+        for tile in &self.native_tiles {
             // Extract the native surface id. We should only ever encounter native surfaces here!
             let id = match tile.surface {
                 CompositeTileSurface::Texture { surface: ResolvedSurfaceTexture::NativeSurface { id, .. }, .. } => id,
                 _ => unreachable!(),
             };
 
             // Add the tile to the OS compositor.
             compositor.add_surface(