Backed out changeset bbc57e229df6 (bug 1520664) for webrender bustages. CLOSED TREE
authorBrindusan Cristian <cbrindusan@mozilla.com>
Thu, 17 Jan 2019 19:20:00 +0200
changeset 454319 855970c5fa721b829d664f4596df61b5fff8163b
parent 454318 a9a828f85c918316db6f21cecff15d5f20275296
child 454320 8fb54b5db199da787fa33b344d07f1fb7ef9bf3b
push id76294
push usercbrindusan@mozilla.com
push dateThu, 17 Jan 2019 17:21:56 +0000
treeherderautoland@855970c5fa72 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1520664
milestone66.0a1
backs outbbc57e229df64bdf5b4fa2d86bf419686bacf496
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
Backed out changeset bbc57e229df6 (bug 1520664) for webrender bustages. CLOSED TREE
gfx/layers/wr/AsyncImagePipelineManager.cpp
gfx/layers/wr/StackingContextHelper.cpp
gfx/layers/wr/StackingContextHelper.h
gfx/webrender_bindings/WebRenderAPI.cpp
gfx/webrender_bindings/WebRenderAPI.h
gfx/webrender_bindings/src/bindings.rs
gfx/wr/webrender/src/clip_scroll_tree.rs
gfx/wr/webrender/src/display_list_flattener.rs
gfx/wr/webrender/src/spatial_node.rs
gfx/wr/webrender/src/util.rs
gfx/wr/webrender_api/src/display_item.rs
gfx/wr/webrender_api/src/display_list.rs
layout/painting/nsDisplayList.cpp
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp
+++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp
@@ -398,18 +398,18 @@ void AsyncImagePipelineManager::ApplyAsy
                              aPipeline->mScBounds.Height()};
   wr::DisplayListBuilder builder(aPipelineId, contentSize);
 
   float opacity = 1.0f;
   Maybe<wr::WrSpatialId> referenceFrameId = builder.PushStackingContext(
       wr::ToRoundedLayoutRect(aPipeline->mScBounds),
       wr::WrStackingContextClip::None(), nullptr, &opacity,
       aPipeline->mScTransform.IsIdentity() ? nullptr : &aPipeline->mScTransform,
-      wr::TransformStyle::Flat, wr::ReferenceFrameKind::Transform,
-      aPipeline->mMixBlendMode, nsTArray<wr::FilterOp>(), true,
+      wr::TransformStyle::Flat, nullptr, aPipeline->mMixBlendMode,
+      nsTArray<wr::FilterOp>(), true,
       // This is fine to do unconditionally because we only push images here.
       wr::RasterSpace::Screen());
 
   Maybe<wr::SpaceAndClipChainHelper> spaceAndClipChainHelper;
   if (referenceFrameId) {
     spaceAndClipChainHelper.emplace(builder, referenceFrameId.ref());
   }
 
--- a/gfx/layers/wr/StackingContextHelper.cpp
+++ b/gfx/layers/wr/StackingContextHelper.cpp
@@ -22,33 +22,31 @@ StackingContextHelper::StackingContextHe
 }
 
 StackingContextHelper::StackingContextHelper(
     const StackingContextHelper& aParentSC, const ActiveScrolledRoot* aAsr,
     nsIFrame* aContainerFrame, nsDisplayItem* aContainerItem,
     wr::DisplayListBuilder& aBuilder, const nsTArray<wr::FilterOp>& aFilters,
     const LayoutDeviceRect& aBounds, const gfx::Matrix4x4* aBoundTransform,
     const wr::WrAnimationProperty* aAnimation, const float* aOpacityPtr,
-    const gfx::Matrix4x4* aTransformPtr,
-    wr::ReferenceFrameKind aReferenceFrameKind,
+    const gfx::Matrix4x4* aTransformPtr, const gfx::Matrix4x4* aPerspectivePtr,
     const gfx::CompositionOp& aMixBlendMode, bool aBackfaceVisible,
     bool aIsPreserve3D,
     const Maybe<nsDisplayTransform*>& aDeferredTransformItem,
     const wr::WrStackingContextClip& aClip, bool aAnimated)
     : mBuilder(&aBuilder),
       mScale(1.0f, 1.0f),
       mDeferredTransformItem(aDeferredTransformItem),
       mIsPreserve3D(aIsPreserve3D),
       mRasterizeLocally(aAnimated || aParentSC.mRasterizeLocally) {
   // Compute scale for fallback rendering. We don't try to guess a scale for 3d
   // transformed items
   gfx::Matrix transform2d;
   if (aBoundTransform && aBoundTransform->CanDraw2D(&transform2d) &&
-      aReferenceFrameKind != wr::ReferenceFrameKind::Perspective &&
-      !aParentSC.mIsPreserve3D) {
+      !aPerspectivePtr && !aParentSC.mIsPreserve3D) {
     mInheritedTransform = transform2d * aParentSC.mInheritedTransform;
 
     int32_t apd = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
     nsRect r = LayoutDevicePixel::ToAppUnits(aBounds, apd);
     mScale = FrameLayerBuilder::ChooseScale(aContainerFrame, aContainerItem, r,
                                             1.f, 1.f, mInheritedTransform,
                                             /* aCanDraw2D = */ true);
 
@@ -67,17 +65,17 @@ StackingContextHelper::StackingContextHe
   auto rasterSpace =
       mRasterizeLocally
           ? wr::RasterSpace::Local(std::max(mScale.width, mScale.height))
           : wr::RasterSpace::Screen();
 
   mReferenceFrameId = mBuilder->PushStackingContext(
       wr::ToLayoutRect(aBounds), aClip, aAnimation, aOpacityPtr, aTransformPtr,
       aIsPreserve3D ? wr::TransformStyle::Preserve3D : wr::TransformStyle::Flat,
-      aReferenceFrameKind, wr::ToMixBlendMode(aMixBlendMode), aFilters,
+      aPerspectivePtr, wr::ToMixBlendMode(aMixBlendMode), aFilters,
       aBackfaceVisible, rasterSpace);
 
   if (mReferenceFrameId) {
     mSpaceAndClipChainHelper.emplace(aBuilder, mReferenceFrameId.ref());
   }
 
   mAffectsClipPositioning =
       mReferenceFrameId.isSome() || (aBounds.TopLeft() != LayoutDevicePoint());
--- a/gfx/layers/wr/StackingContextHelper.h
+++ b/gfx/layers/wr/StackingContextHelper.h
@@ -32,17 +32,17 @@ class MOZ_RAII StackingContextHelper {
       nsIFrame* aContainerFrame, nsDisplayItem* aContainerItem,
       wr::DisplayListBuilder& aBuilder,
       const nsTArray<wr::FilterOp>& aFilters = nsTArray<wr::FilterOp>(),
       const LayoutDeviceRect& aBounds = LayoutDeviceRect(),
       const gfx::Matrix4x4* aBoundTransform = nullptr,
       const wr::WrAnimationProperty* aAnimation = nullptr,
       const float* aOpacityPtr = nullptr,
       const gfx::Matrix4x4* aTransformPtr = nullptr,
-      const wr::ReferenceFrameKind = wr::ReferenceFrameKind::Transform,
+      const gfx::Matrix4x4* aPerspectivePtr = nullptr,
       const gfx::CompositionOp& aMixBlendMode = gfx::CompositionOp::OP_OVER,
       bool aBackfaceVisible = true, bool aIsPreserve3D = false,
       const Maybe<nsDisplayTransform*>& aDeferredTransformItem = Nothing(),
       const wr::WrStackingContextClip& = wr::WrStackingContextClip::None(),
       bool aAnimated = false);
   // This version of the constructor should only be used at the root level
   // of the tree, so that we have a StackingContextHelper to pass down into
   // the RenderLayer traversal, but don't actually want it to push a stacking
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -671,34 +671,41 @@ void DisplayListBuilder::Finalize(wr::La
   wr_api_finalize_builder(mWrState, &aOutContentSize, &aOutDisplayList.dl_desc,
                           &aOutDisplayList.dl.inner);
 }
 
 Maybe<wr::WrSpatialId> DisplayListBuilder::PushStackingContext(
     const wr::LayoutRect& aBounds, const wr::WrStackingContextClip& aClip,
     const WrAnimationProperty* aAnimation, const float* aOpacity,
     const gfx::Matrix4x4* aTransform, wr::TransformStyle aTransformStyle,
-    const wr::ReferenceFrameKind aReferenceFrameKind, const wr::MixBlendMode& aMixBlendMode,
+    const gfx::Matrix4x4* aPerspective, const wr::MixBlendMode& aMixBlendMode,
     const nsTArray<wr::FilterOp>& aFilters, bool aIsBackfaceVisible,
     const wr::RasterSpace& aRasterSpace) {
   MOZ_ASSERT(mClipChainLeaf.isNothing(),
              "Non-empty leaf from clip chain given, but not used with SC!");
 
   wr::LayoutTransform matrix;
   if (aTransform) {
     matrix = ToLayoutTransform(*aTransform);
   }
   const wr::LayoutTransform* maybeTransform = aTransform ? &matrix : nullptr;
+  wr::LayoutTransform perspective;
+  if (aPerspective) {
+    perspective = ToLayoutTransform(*aPerspective);
+  }
+
+  const wr::LayoutTransform* maybePerspective =
+      aPerspective ? &perspective : nullptr;
   WRDL_LOG("PushStackingContext b=%s t=%s\n", mWrState,
            Stringify(aBounds).c_str(),
            aTransform ? Stringify(*aTransform).c_str() : "none");
 
   auto spatialId = wr_dp_push_stacking_context(
       mWrState, aBounds, mCurrentSpaceAndClipChain.space, &aClip, aAnimation,
-      aOpacity, maybeTransform, aTransformStyle, aReferenceFrameKind,
+      aOpacity, maybeTransform, aTransformStyle, maybePerspective,
       aMixBlendMode, aFilters.Elements(), aFilters.Length(), aIsBackfaceVisible,
       aRasterSpace);
 
   return spatialId.id != 0 ? Some(spatialId) : Nothing();
 }
 
 void DisplayListBuilder::PopStackingContext(bool aIsReferenceFrame) {
   WRDL_LOG("PopStackingContext\n", mWrState);
--- a/gfx/webrender_bindings/WebRenderAPI.h
+++ b/gfx/webrender_bindings/WebRenderAPI.h
@@ -328,17 +328,17 @@ class DisplayListBuilder {
   void Finalize(wr::LayoutSize& aOutContentSize,
                 wr::BuiltDisplayList& aOutDisplayList);
 
   Maybe<wr::WrSpatialId> PushStackingContext(
       // TODO: We should work with strongly typed rects
       const wr::LayoutRect& aBounds, const wr::WrStackingContextClip& aClip,
       const wr::WrAnimationProperty* aAnimation, const float* aOpacity,
       const gfx::Matrix4x4* aTransform, wr::TransformStyle aTransformStyle,
-      const wr::ReferenceFrameKind, const wr::MixBlendMode& aMixBlendMode,
+      const gfx::Matrix4x4* aPerspective, const wr::MixBlendMode& aMixBlendMode,
       const nsTArray<wr::FilterOp>& aFilters, bool aIsBackfaceVisible,
       const wr::RasterSpace& aRasterSpace);
   void PopStackingContext(bool aIsReferenceFrame);
 
   wr::WrClipChainId DefineClipChain(const Maybe<wr::WrClipChainId>& aParent,
                                     const nsTArray<wr::WrClipId>& aClips);
 
   wr::WrClipId DefineClip(
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1899,17 +1899,17 @@ pub extern "C" fn wr_dp_push_stacking_co
     state: &mut WrState,
     mut bounds: LayoutRect,
     spatial_id: WrSpatialId,
     clip: &WrStackingContextClip,
     animation: *const WrAnimationProperty,
     opacity: *const f32,
     transform: *const LayoutTransform,
     transform_style: TransformStyle,
-    reference_frame_kind: ReferenceFrameKind,
+    perspective: *const LayoutTransform,
     mix_blend_mode: MixBlendMode,
     filters: *const FilterOp,
     filter_count: usize,
     is_backface_visible: bool,
     glyph_raster_space: RasterSpace,
 ) -> WrSpatialId {
     debug_assert!(unsafe { !is_in_render_thread() });
 
@@ -1950,32 +1950,38 @@ pub extern "C" fn wr_dp_push_stacking_co
     }
 
     if let Some(opacity) = opacity_ref {
         if !has_opacity_animation && *opacity < 1.0 {
             filters.push(FilterOp::Opacity(PropertyBinding::Value(*opacity), *opacity));
         }
     }
 
+    let perspective_ref = unsafe { perspective.as_ref() };
+    let perspective = match perspective_ref {
+        Some(perspective) => Some(perspective.clone()),
+        None => None,
+    };
+
     let mut wr_spatial_id = spatial_id.to_webrender(state.pipeline_id);
     let wr_clip_id = clip.to_webrender(state.pipeline_id);
 
-    let is_reference_frame = transform_binding.is_some();
+    let is_reference_frame = transform_binding.is_some() || perspective.is_some();
     // Note: 0 has special meaning in WR land, standing for ROOT_REFERENCE_FRAME.
     // However, it is never returned by `push_reference_frame`, and we need to return
     // an option here across FFI, so we take that 0 value for the None semantics.
     // This is resolved into proper `Maybe<WrSpatialId>` inside `WebRenderAPI::PushStackingContext`.
     let mut result = WrSpatialId { id: 0 };
     if is_reference_frame {
         wr_spatial_id = state.frame_builder.dl_builder.push_reference_frame(
             &bounds,
             wr_spatial_id,
             transform_style,
             transform_binding,
-            reference_frame_kind,
+            perspective,
         );
 
         bounds.origin = LayoutPoint::zero();
         result.id = wr_spatial_id.0;
         assert_ne!(wr_spatial_id.0, 0);
     }
 
     let prim_info = LayoutPrimitiveInfo {
--- a/gfx/wr/webrender/src/clip_scroll_tree.rs
+++ b/gfx/wr/webrender/src/clip_scroll_tree.rs
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use api::{ExternalScrollId, LayoutPoint, LayoutRect, LayoutVector2D, ReferenceFrameKind};
+use api::{ExternalScrollId, LayoutPoint, LayoutRect, LayoutVector2D};
 use api::{PipelineId, ScrollClamping, ScrollNodeState, ScrollLocation, ScrollSensitivity};
 use api::{LayoutSize, LayoutTransform, PropertyBinding, TransformStyle, WorldPoint};
 use gpu_types::TransformPalette;
 use internal_types::{FastHashMap, FastHashSet};
 use print_tree::{PrintableTree, PrintTree, PrintTreePrinter};
 use scene::SceneProperties;
 use smallvec::SmallVec;
 use spatial_node::{ScrollFrameInfo, SpatialNode, SpatialNodeType, StickyFrameInfo, ScrollFrameKind};
@@ -348,25 +348,25 @@ impl ClipScrollTree {
         self.add_spatial_node(node)
     }
 
     pub fn add_reference_frame(
         &mut self,
         parent_index: Option<SpatialNodeIndex>,
         transform_style: TransformStyle,
         source_transform: Option<PropertyBinding<LayoutTransform>>,
-        kind: ReferenceFrameKind,
+        source_perspective: Option<LayoutTransform>,
         origin_in_parent_reference_frame: LayoutVector2D,
         pipeline_id: PipelineId,
     ) -> SpatialNodeIndex {
         let node = SpatialNode::new_reference_frame(
             parent_index,
             transform_style,
             source_transform,
-            kind,
+            source_perspective,
             origin_in_parent_reference_frame,
             pipeline_id,
         );
         self.add_spatial_node(node)
     }
 
     pub fn add_sticky_frame(
         &mut self,
@@ -451,16 +451,20 @@ impl ClipScrollTree {
     ) -> bool {
         let mut current = spatial_node_index;
 
         while current != ROOT_SPATIAL_NODE_INDEX {
             let node = &self.spatial_nodes[current.0 as usize];
 
             match node.node_type {
                 SpatialNodeType::ReferenceFrame(ref info) => {
+                    if !info.source_perspective.is_identity() {
+                        return false;
+                    }
+
                     match info.source_transform {
                         PropertyBinding::Value(transform) => {
                             if transform != LayoutTransform::identity() {
                                 return false;
                             }
                         }
                         PropertyBinding::Binding(..) => {
                             // Assume not identity since it may change with animation.
--- a/gfx/wr/webrender/src/display_list_flattener.rs
+++ b/gfx/wr/webrender/src/display_list_flattener.rs
@@ -4,17 +4,17 @@
 
 use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter};
 use api::{ClipId, ColorF, ComplexClipRegion, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
 use api::{DisplayItemRef, ExtendMode, ExternalScrollId, AuHelpers};
 use api::{FilterOp, FontInstanceKey, GlyphInstance, GlyphOptions, RasterSpace, GradientStop};
 use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayoutPoint, ColorDepth};
 use api::{LayoutPrimitiveInfo, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
 use api::{LineOrientation, LineStyle, NinePatchBorderSource, PipelineId};
-use api::{PropertyBinding, ReferenceFrame, ReferenceFrameKind, ScrollFrameDisplayItem, ScrollSensitivity};
+use api::{PropertyBinding, ReferenceFrame, ScrollFrameDisplayItem, ScrollSensitivity};
 use api::{Shadow, SpaceAndClipInfo, SpatialId, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
 use api::{ClipMode, TransformStyle, YuvColorSpace, YuvData};
 use app_units::Au;
 use clip::{ClipChainId, ClipRegion, ClipItemKey, ClipStore};
 use clip_scroll_tree::{ROOT_SPATIAL_NODE_INDEX, ClipScrollTree, SpatialNodeIndex};
 use frame_builder::{ChasePrimitive, FrameBuilder, FrameBuilderConfig};
 use glyph_rasterizer::FontInstance;
 use hit_test::{HitTestingItem, HitTestingRun};
@@ -593,17 +593,17 @@ impl<'a> DisplayListFlattener<'a> {
         reference_frame_relative_offset: LayoutVector2D,
     ) {
         self.push_reference_frame(
             reference_frame.id,
             Some(parent_spatial_node),
             pipeline_id,
             reference_frame.transform_style,
             reference_frame.transform,
-            reference_frame.kind,
+            reference_frame.perspective,
             reference_frame_relative_offset + origin.to_vector(),
         );
 
         self.flatten_items(traversal, pipeline_id, LayoutVector2D::zero());
     }
 
 
     fn flatten_stacking_context(
@@ -686,17 +686,17 @@ impl<'a> DisplayListFlattener<'a> {
         let bounds = item.rect();
         let origin = *reference_frame_relative_offset + bounds.origin.to_vector();
         let spatial_node_index = self.push_reference_frame(
             SpatialId::root_reference_frame(iframe_pipeline_id),
             Some(spatial_node_index),
             iframe_pipeline_id,
             TransformStyle::Flat,
             None,
-            ReferenceFrameKind::Transform,
+            None,
             origin,
         );
 
         let iframe_rect = LayoutRect::new(LayoutPoint::zero(), bounds.size);
         self.add_scroll_frame(
             SpatialId::root_scroll_node(iframe_pipeline_id),
             spatial_node_index,
             Some(ExternalScrollId(0, iframe_pipeline_id)),
@@ -1580,24 +1580,24 @@ impl<'a> DisplayListFlattener<'a> {
 
     pub fn push_reference_frame(
         &mut self,
         reference_frame_id: SpatialId,
         parent_index: Option<SpatialNodeIndex>,
         pipeline_id: PipelineId,
         transform_style: TransformStyle,
         source_transform: Option<PropertyBinding<LayoutTransform>>,
-        kind: ReferenceFrameKind,
+        source_perspective: Option<LayoutTransform>,
         origin_in_parent_reference_frame: LayoutVector2D,
     ) -> SpatialNodeIndex {
         let index = self.clip_scroll_tree.add_reference_frame(
             parent_index,
             transform_style,
             source_transform,
-            kind,
+            source_perspective,
             origin_in_parent_reference_frame,
             pipeline_id,
         );
         self.id_to_index_mapper.map_spatial_node(reference_frame_id, index);
 
         index
     }
 
@@ -1615,17 +1615,17 @@ impl<'a> DisplayListFlattener<'a> {
         self.id_to_index_mapper.add_clip_chain(ClipId::root(pipeline_id), ClipChainId::NONE, 0);
 
         let spatial_node_index = self.push_reference_frame(
             SpatialId::root_reference_frame(pipeline_id),
             None,
             pipeline_id,
             TransformStyle::Flat,
             None,
-            ReferenceFrameKind::Transform,
+            None,
             LayoutVector2D::zero(),
         );
 
         self.add_scroll_frame(
             SpatialId::root_scroll_node(pipeline_id),
             spatial_node_index,
             Some(ExternalScrollId(0, pipeline_id)),
             pipeline_id,
--- a/gfx/wr/webrender/src/spatial_node.rs
+++ b/gfx/wr/webrender/src/spatial_node.rs
@@ -1,15 +1,15 @@
 
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use api::{ExternalScrollId, LayoutPixel, LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
-use api::{LayoutVector2D, PipelineId, PropertyBinding, ReferenceFrameKind, ScrollClamping, ScrollLocation};
+use api::{LayoutVector2D, PipelineId, PropertyBinding, ScrollClamping, ScrollLocation};
 use api::{TransformStyle, ScrollSensitivity, StickyOffsetBounds};
 use clip_scroll_tree::{CoordinateSystem, CoordinateSystemId, SpatialNodeIndex, TransformUpdateState};
 use euclid::SideOffsets2D;
 use gpu_types::TransformPalette;
 use scene::SceneProperties;
 use util::{LayoutFastTransform, LayoutToWorldFastTransform, ScaleOffset, TransformedRectKind};
 
 #[derive(Clone, Debug)]
@@ -112,39 +112,42 @@ impl SpatialNode {
 
         Self::new(pipeline_id, Some(parent_index), node_type)
     }
 
     pub fn new_reference_frame(
         parent_index: Option<SpatialNodeIndex>,
         transform_style: TransformStyle,
         source_transform: Option<PropertyBinding<LayoutTransform>>,
-        kind: ReferenceFrameKind,
+        source_perspective: Option<LayoutTransform>,
         origin_in_parent_reference_frame: LayoutVector2D,
         pipeline_id: PipelineId,
     ) -> Self {
         let identity = LayoutTransform::identity();
+        let source_perspective = source_perspective.map_or_else(
+            LayoutFastTransform::identity, |perspective| perspective.into());
         let info = ReferenceFrameInfo {
             transform_style,
             source_transform: source_transform.unwrap_or(PropertyBinding::Value(identity)),
-            kind,
+            source_perspective,
             origin_in_parent_reference_frame,
             invertible: true,
         };
         Self::new(pipeline_id, parent_index, SpatialNodeType::ReferenceFrame(info))
     }
 
     pub fn new_sticky_frame(
         parent_index: SpatialNodeIndex,
         sticky_frame_info: StickyFrameInfo,
         pipeline_id: PipelineId,
     ) -> Self {
         Self::new(pipeline_id, Some(parent_index), SpatialNodeType::StickyFrame(sticky_frame_info))
     }
 
+
     pub fn add_child(&mut self, child: SpatialNodeIndex) {
         self.children.push(child);
     }
 
     pub fn apply_old_scrolling_state(&mut self, old_scroll_info: &ScrollFrameInfo) {
         match self.node_type {
             SpatialNodeType::ScrollFrame(ref mut scrolling) => {
                 *scrolling = scrolling.combine_with_old_scroll_info(old_scroll_info);
@@ -249,36 +252,27 @@ impl SpatialNode {
         &mut self,
         state: &mut TransformUpdateState,
         coord_systems: &mut Vec<CoordinateSystem>,
         scene_properties: &SceneProperties,
     ) {
         match self.node_type {
             SpatialNodeType::ReferenceFrame(ref mut info) => {
                 // Resolve the transform against any property bindings.
-                let source_transform = LayoutFastTransform::from(
-                    scene_properties.resolve_layout_transform(&info.source_transform)
-                );
+                let source_transform = scene_properties.resolve_layout_transform(&info.source_transform);
 
                 // Do a change-basis operation on the perspective matrix using
                 // the scroll offset.
-                let source_transform = match info.kind {
-                    ReferenceFrameKind::Perspective => {
-                        // Do a change-basis operation on the perspective matrix
-                        // using the scroll offset.
-                        source_transform
-                            .pre_translate(&state.parent_accumulated_scroll_offset)
-                            .post_translate(-state.parent_accumulated_scroll_offset)
-                    }
-                    ReferenceFrameKind::Transform => source_transform,
-                };
-
+                let scrolled_perspective = info.source_perspective
+                    .pre_translate(&state.parent_accumulated_scroll_offset)
+                    .post_translate(-state.parent_accumulated_scroll_offset);
                 let resolved_transform =
                     LayoutFastTransform::with_vector(info.origin_in_parent_reference_frame)
-                        .pre_mul(&source_transform);
+                    .pre_mul(&source_transform.into())
+                    .pre_mul(&scrolled_perspective);
 
                 // The transformation for this viewport in world coordinates is the transformation for
                 // our parent reference frame, plus any accumulated scrolling offsets from nodes
                 // between our reference frame and this node. Finally, we also include
                 // whatever local transformation this reference frame provides.
                 let relative_transform = resolved_transform
                     .post_translate(state.parent_accumulated_scroll_offset)
                     .to_transform()
@@ -495,18 +489,18 @@ impl SpatialNode {
                 state.parent_accumulated_scroll_offset += scrolling.offset;
                 state.nearest_scrolling_ancestor_offset = scrolling.offset;
                 state.nearest_scrolling_ancestor_viewport = scrolling.viewport_rect;
             }
             SpatialNodeType::ReferenceFrame(ref info) => {
                 state.parent_reference_frame_transform = self.world_viewport_transform;
 
                 let should_flatten =
-                    info.kind == ReferenceFrameKind::Transform &&
-                    info.transform_style == TransformStyle::Flat;
+                    info.transform_style == TransformStyle::Flat &&
+                    info.source_perspective.is_identity();
 
                 if should_flatten {
                     state.parent_reference_frame_transform = state.parent_reference_frame_transform.project_to_2d();
                 }
 
                 state.parent_accumulated_scroll_offset = LayoutVector2D::zero();
                 state.coordinate_system_relative_scale_offset = self.coordinate_system_relative_scale_offset;
                 let translation = -info.origin_in_parent_reference_frame;
@@ -662,17 +656,17 @@ impl ScrollFrameInfo {
 #[derive(Copy, Clone, Debug)]
 pub struct ReferenceFrameInfo {
     /// The source transform and perspective matrices provided by the stacking context
     /// that forms this reference frame. We maintain the property binding information
     /// here so that we can resolve the animated transform and update the tree each
     /// frame.
     pub source_transform: PropertyBinding<LayoutTransform>,
     pub transform_style: TransformStyle,
-    pub kind: ReferenceFrameKind,
+    pub source_perspective: LayoutFastTransform,
 
     /// The original, not including the transform and relative to the parent reference frame,
     /// origin of this reference frame. This is already rolled into the `transform' property, but
     /// we also store it here to properly transform the viewport for sticky positioning.
     pub origin_in_parent_reference_frame: LayoutVector2D,
 
     /// True if the resolved transform is invertible.
     pub invertible: bool,
--- a/gfx/wr/webrender/src/util.rs
+++ b/gfx/wr/webrender/src/util.rs
@@ -619,17 +619,16 @@ impl<Src, Dst> FastTransform<Src, Dst> {
     pub fn is_invertible(&self) -> bool {
         match *self {
             FastTransform::Offset(..) => true,
             FastTransform::Transform { ref inverse, .. } => inverse.is_some(),
         }
     }
 
     /// Return true if this is an identity transform
-    #[allow(unused)]
     pub fn is_identity(&self)-> bool {
         match *self {
             FastTransform::Offset(offset) => {
                 offset == TypedVector2D::zero()
             }
             FastTransform::Transform { ref transform, .. } => {
                 *transform == TypedTransform3D::identity()
             }
--- a/gfx/wr/webrender_api/src/display_item.rs
+++ b/gfx/wr/webrender_api/src/display_item.rs
@@ -520,29 +520,20 @@ pub struct ReferenceFrameDisplayListItem
 
 /// Provides a hint to WR that it should try to cache the items
 /// within a cache marker context in an off-screen surface.
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct CacheMarkerDisplayItem {
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
-#[repr(u8)]
-pub enum ReferenceFrameKind {
-    Transform,
-    Perspective,
-}
-
-#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ReferenceFrame {
-    pub kind: ReferenceFrameKind,
     pub transform_style: TransformStyle,
-    /// The transform matrix, either the perspective matrix or the transform
-    /// matrix.
     pub transform: Option<PropertyBinding<LayoutTransform>>,
+    pub perspective: Option<LayoutTransform>,
     pub id: SpatialId,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct PushStackingContextDisplayItem {
     pub stacking_context: StackingContext,
 }
 
--- a/gfx/wr/webrender_api/src/display_list.rs
+++ b/gfx/wr/webrender_api/src/display_list.rs
@@ -18,17 +18,17 @@ use {AlphaType, BorderDetails, BorderDis
 use {BoxShadowDisplayItem, ClipChainId, ClipChainItem, ClipDisplayItem, ClipId};
 use {ColorF, ComplexClipRegion, DisplayItem, ExtendMode, ExternalScrollId, FilterOp};
 use {FontInstanceKey, GlyphInstance, GlyphOptions, RasterSpace, Gradient, GradientBuilder};
 use {GradientDisplayItem, GradientStop, IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask};
 use {ImageRendering, LayoutPoint, LayoutPrimitiveInfo, LayoutRect, LayoutSideOffsets, LayoutSize};
 use {LayoutTransform, LayoutVector2D, LineDisplayItem, LineOrientation, LineStyle, MixBlendMode};
 use {PipelineId, PropertyBinding, ReferenceFrameDisplayListItem};
 use {PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem};
-use {RectangleDisplayItem, ReferenceFrame, ReferenceFrameKind, ScrollFrameDisplayItem, ScrollSensitivity};
+use {RectangleDisplayItem, ReferenceFrame, ScrollFrameDisplayItem, ScrollSensitivity};
 use {SerializedDisplayItem, Shadow, SpaceAndClipInfo, SpatialId, SpecificDisplayItem};
 use {StackingContext, StickyFrameDisplayItem, StickyOffsetBounds};
 use {TextDisplayItem, TransformStyle, YuvColorSpace, YuvData, YuvImageDisplayItem, ColorDepth};
 
 // We don't want to push a long text-run. If a text-run is too long, split it into several parts.
 // This needs to be set to (renderer::MAX_VERTEX_TEXTURE_WIDTH - VECS_PER_TEXT_RUN) * 2
 pub const MAX_TEXT_RUN_LENGTH: usize = 2040;
 
@@ -1252,25 +1252,25 @@ impl DisplayListBuilder {
     }
 
     pub fn push_reference_frame(
         &mut self,
         rect: &LayoutRect,
         parent: SpatialId,
         transform_style: TransformStyle,
         transform: Option<PropertyBinding<LayoutTransform>>,
-        kind: ReferenceFrameKind,
+        perspective: Option<LayoutTransform>,
     ) -> SpatialId {
         let id = self.generate_spatial_index();
 
         let item = SpecificDisplayItem::PushReferenceFrame(ReferenceFrameDisplayListItem {
             reference_frame: ReferenceFrame {
                 transform_style,
                 transform,
-                kind,
+                perspective,
                 id,
             },
         });
 
         let layout = LayoutPrimitiveInfo::new(*rect);
         self.push_item(&item, &layout, &SpaceAndClipInfo {
             spatial_id: parent,
             clip_id: ClipId::invalid(),
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -6108,17 +6108,17 @@ bool nsDisplayBlendMode::CreateWebRender
     mozilla::wr::DisplayListBuilder& aBuilder,
     mozilla::wr::IpcResourceUpdateQueue& aResources,
     const StackingContextHelper& aSc,
     mozilla::layers::RenderRootStateManager* aManager,
     nsDisplayListBuilder* aDisplayListBuilder) {
   nsTArray<mozilla::wr::FilterOp> filters;
   StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
                            filters, LayoutDeviceRect(), nullptr, nullptr,
-                           nullptr, nullptr, wr::ReferenceFrameKind::Transform,
+                           nullptr, nullptr, nullptr,
                            nsCSSRendering::GetGFXBlendMode(mBlendMode));
 
   return nsDisplayWrapList::CreateWebRenderCommands(
       aBuilder, aResources, sc, aManager, aDisplayListBuilder);
 }
 
 // nsDisplayBlendMode uses layers for rendering
 already_AddRefed<Layer> nsDisplayBlendMode::BuildLayer(
@@ -7876,20 +7876,20 @@ bool nsDisplayTransform::CreateWebRender
   bool animated =
       ActiveLayerTracker::IsStyleMaybeAnimated(Frame(), eCSSProperty_transform);
 
   bool preserve3D = mFrame->Extend3DContext() && !mIsTransformSeparator;
 
   StackingContextHelper sc(
       aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, filters,
       LayoutDeviceRect(position, LayoutDeviceSize()), &newTransformMatrix,
-      animationsId ? &prop : nullptr, nullptr, transformForSC,
-      wr::ReferenceFrameKind::Transform, gfx::CompositionOp::OP_OVER,
-      !BackfaceIsHidden(), preserve3D, deferredTransformItem,
-      wr::WrStackingContextClip::None(), animated);
+      animationsId ? &prop : nullptr, nullptr, transformForSC, nullptr,
+      gfx::CompositionOp::OP_OVER, !BackfaceIsHidden(),
+      preserve3D, deferredTransformItem, wr::WrStackingContextClip::None(),
+      animated);
 
   return mStoredList.CreateWebRenderCommands(aBuilder, aResources, sc, aManager,
                                              aDisplayListBuilder);
 }
 
 bool nsDisplayTransform::UpdateScrollData(
     mozilla::layers::WebRenderScrollData* aData,
     mozilla::layers::WebRenderLayerScrollData* aLayerData) {
@@ -8460,27 +8460,27 @@ bool nsDisplayPerspective::CreateWebRend
   Point3D newOrigin =
       Point3D(NSAppUnitsToFloatPixels(transform->ToReferenceFrame().x,
                                       appUnitsPerPixel),
               NSAppUnitsToFloatPixels(transform->ToReferenceFrame().y,
                                       appUnitsPerPixel),
               0.0f);
   Point3D roundedOrigin(NS_round(newOrigin.x), NS_round(newOrigin.y), 0);
 
-  perspectiveMatrix.PostTranslate(roundedOrigin);
+  gfx::Matrix4x4 transformForSC = gfx::Matrix4x4::Translation(roundedOrigin);
 
   nsIFrame* perspectiveFrame =
       mFrame->GetContainingBlock(nsIFrame::SKIP_SCROLLED_FRAME);
 
   nsTArray<mozilla::wr::FilterOp> filters;
-  StackingContextHelper sc(
-      aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, filters,
-      LayoutDeviceRect(), nullptr, nullptr, nullptr, &perspectiveMatrix,
-      wr::ReferenceFrameKind::Perspective, gfx::CompositionOp::OP_OVER,
-      !BackfaceIsHidden(), perspectiveFrame->Extend3DContext());
+  StackingContextHelper sc(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
+                           filters, LayoutDeviceRect(), nullptr, nullptr,
+                           nullptr, &transformForSC, &perspectiveMatrix,
+                           gfx::CompositionOp::OP_OVER, !BackfaceIsHidden(),
+                           perspectiveFrame->Extend3DContext());
 
   return mList.CreateWebRenderCommands(aBuilder, aResources, sc, aManager,
                                        aDisplayListBuilder);
 }
 
 nsDisplayItemGeometry* nsCharClipDisplayItem::AllocateGeometry(
     nsDisplayListBuilder* aBuilder) {
   return new nsCharClipGeometry(this, aBuilder);
@@ -9068,17 +9068,17 @@ bool nsDisplayMasksAndClipPaths::CreateW
 
     layer.emplace(aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder,
                   /*aFilters: */ nsTArray<wr::FilterOp>(),
                   /*aBounds: */ bounds,
                   /*aBoundTransform: */ nullptr,
                   /*aAnimation: */ nullptr,
                   /*aOpacity: */ opacity.ptrOr(nullptr),
                   /*aTransform: */ nullptr,
-                  /*aReferenceFrameKind: */ wr::ReferenceFrameKind::Transform,
+                  /*aPerspective: */ nullptr,
                   /*aMixBlendMode: */ gfx::CompositionOp::OP_OVER,
                   /*aBackfaceVisible: */ true,
                   /*aIsPreserve3D: */ false,
                   /*aTransformForScrollData: */ Nothing(),
                   /*aClip: */ wr::WrStackingContextClip::ClipId(clipId));
     sc = layer.ptr();
   }
 
@@ -9354,19 +9354,18 @@ bool nsDisplayFilters::CreateWebRenderCo
           mFrame, preFilterBounds, wrFilters, postFilterBounds)) {
     return false;
   }
 
   float opacity = mFrame->StyleEffects()->mOpacity;
   StackingContextHelper sc(
       aSc, GetActiveScrolledRoot(), mFrame, this, aBuilder, wrFilters,
       LayoutDeviceRect(), nullptr, nullptr,
-      opacity != 1.0f && mHandleOpacity ? &opacity : nullptr, nullptr,
-      wr::ReferenceFrameKind::Transform, gfx::CompositionOp::OP_OVER, true,
-      false, Nothing(),
+      opacity != 1.0f && mHandleOpacity ? &opacity : nullptr, nullptr, nullptr,
+      gfx::CompositionOp::OP_OVER, true, false, Nothing(),
       wr::WrStackingContextClip::ClipChain(aBuilder.CurrentClipChainId()));
 
   nsDisplayEffectsBase::CreateWebRenderCommands(aBuilder, aResources, sc,
                                                 aManager, aDisplayListBuilder);
 
   return true;
 }