Bug 1207041 - Treat mix-blend-mode layers as transparent for occlusion culling. (bug 1207041, r=mstange). r=mstange, a=lizzard
authorDavid Anderson <danderson@mozilla.com>
Wed, 30 Sep 2015 00:02:00 -0700
changeset 296396 970363447576e9a9ebe811a7aeecc37a0566065c
parent 296395 3fb257ea7183c55c314267357fd3473bbc0d948f
child 296397 b60e63d9a14b21dcba21f0b2a93015ad991e7196
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange, mstange, lizzard
bugs1207041
milestone43.0a2
Bug 1207041 - Treat mix-blend-mode layers as transparent for occlusion culling. (bug 1207041, r=mstange). r=mstange, a=lizzard
gfx/layers/Layers.cpp
gfx/layers/Layers.h
gfx/layers/composite/ContainerLayerComposite.cpp
gfx/layers/composite/LayerManagerComposite.cpp
layout/reftests/css-blending/mix-blend-mode-culling-1207041-ref.html
layout/reftests/css-blending/mix-blend-mode-culling-1207041.html
layout/reftests/css-blending/reftest.list
--- a/gfx/layers/Layers.cpp
+++ b/gfx/layers/Layers.cpp
@@ -552,16 +552,23 @@ Layer::ApplyPendingUpdatesToSubtree()
 {
   ApplyPendingUpdatesForThisTransaction();
   for (Layer* child = GetFirstChild(); child; child = child->GetNextSibling()) {
     child->ApplyPendingUpdatesToSubtree();
   }
 }
 
 bool
+Layer::IsOpaqueForVisibility()
+{
+  return GetLocalOpacity() == 1.0f &&
+         GetEffectiveMixBlendMode() == CompositionOp::OP_OVER;
+}
+
+bool
 Layer::CanUseOpaqueSurface()
 {
   // If the visible content in the layer is opaque, there is no need
   // for an alpha channel.
   if (GetContentFlags() & CONTENT_OPAQUE)
     return true;
   // Also, if this layer is the bottommost layer in a container which
   // doesn't need an alpha channel, we can use an opaque surface for this
--- a/gfx/layers/Layers.h
+++ b/gfx/layers/Layers.h
@@ -1373,16 +1373,21 @@ public:
   {
     if (CanUseOpaqueSurface())
       return SurfaceMode::SURFACE_OPAQUE;
     if (mContentFlags & CONTENT_COMPONENT_ALPHA)
       return SurfaceMode::SURFACE_COMPONENT_ALPHA;
     return SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
   }
 
+  // Returns true if this layer can be treated as opaque for visibility
+  // computation. A layer may be non-opaque for visibility even if it
+  // is not transparent, for example, if it has a mix-blend-mode.
+  bool IsOpaqueForVisibility();
+
   /**
    * This setter can be used anytime. The user data for all keys is
    * initially null. Ownership pases to the layer manager.
    */
   void SetUserData(void* aKey, LayerUserData* aData)
   {
     mUserData.Add(static_cast<gfx::UserDataKey*>(aKey), aData, LayerManagerUserDataDestroy);
   }
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -516,16 +516,17 @@ RenderLayers(ContainerT* aContainer,
   for (size_t i = 0u; i < aContainer->mPrepared->mLayers.Length(); i++) {
     PreparedLayer& preparedData = aContainer->mPrepared->mLayers[i];
     LayerComposite* layerToRender = preparedData.mLayer;
     const RenderTargetIntRect& clipRect = preparedData.mClipRect;
     Layer* layer = layerToRender->GetLayer();
 
     gfxRGBA color;
     if ((layer->GetContentFlags() & Layer::CONTENT_OPAQUE) &&
+        layer->IsOpaqueForVisibility() &&
         LayerHasCheckerboardingAPZC(layer, &color)) {
       if (gfxPrefs::APZHighlightCheckerboardedAreas()) {
         color = gfxRGBA(255 / 255.0, 188 / 255.0, 217 / 255.0, 1);  // "Cotton Candy"
       }
       // Ideally we would want to intersect the checkerboard region from the APZ with the layer bounds
       // and only fill in that area. However the layer bounds takes into account the base translation
       // for the painted layer whereas the checkerboard region does not. One does not simply
       // intersect areas in different coordinate spaces. So we do this a little more permissively
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -235,17 +235,17 @@ LayerManagerComposite::ApplyOcclusionCul
   for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
     ApplyOcclusionCulling(child, localOpaque);
   }
 
   // If we have a simple transform, then we can add our opaque area into
   // aOpaqueRegion.
   if (isTranslation &&
       !aLayer->HasMaskLayers() &&
-      aLayer->GetLocalOpacity() == 1.0f) {
+      aLayer->IsOpaqueForVisibility()) {
     if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) {
       localOpaque.Or(localOpaque, composite->GetFullyRenderedRegion());
     }
     localOpaque.MoveBy(transform2d._31, transform2d._32);
     const Maybe<ParentLayerIntRect>& clip = aLayer->GetEffectiveClipRect();
     if (clip) {
       localOpaque.And(localOpaque, ParentLayerIntRect::ToUntyped(*clip));
     }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-blending/mix-blend-mode-culling-1207041-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<head>
+  <style>
+    .parent {
+       width: 200px;
+       height: 200px;
+       isolation: isolate;
+       background: orange;
+    }
+    .child {
+      width: 200px;
+      height: 200px;
+      background: #ffd200;
+    }
+  </style>
+</head>
+<body>
+ <div class="parent">
+  <div class="child">
+  </div>
+ </div>
+</body>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-blending/mix-blend-mode-culling-1207041.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<head>
+  <style>
+    .parent {
+       width: 200px;
+       height: 200px;
+       isolation: isolate;
+       background: orange;
+    }
+    .child {
+      width: 200px;
+      height: 200px;
+      mix-blend-mode: screen;
+      background: green;
+    }
+  </style>
+</head>
+<body>
+ <div class="parent">
+  <div class="child">
+  </div>
+ </div>
+</body>
--- a/layout/reftests/css-blending/reftest.list
+++ b/layout/reftests/css-blending/reftest.list
@@ -41,16 +41,17 @@ fuzzy-if(azureQuartz,2,40000) fuzzy-if(a
 fuzzy(64,37) pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-952051.html mix-blend-mode-952051-ref.html
 
 pref(layout.css.mix-blend-mode.enabled,true) pref(layout.css.filters.enabled,true) == mix-blend-mode-and-filter.html mix-blend-mode-and-filter-ref.html
 pref(layout.css.mix-blend-mode.enabled,true) pref(layout.css.filters.enabled,true) == mix-blend-mode-and-filter.svg mix-blend-mode-and-filter-ref.svg
 
 pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-child-of-blended-has-opacity.html mix-blend-mode-child-of-blended-has-opacity-ref.html
 
 pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-nested-976533.html mix-blend-mode-nested-976533-ref.html
+pref(layout.css.mix-blend-mode.enabled,true) == mix-blend-mode-culling-1207041.html mix-blend-mode-culling-1207041-ref.html
 
 # Test plan 5.3.1 Blending between the background layers and the background color for an element with background-blend-mode
 # Test 9
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-svg-as-data-uri.html background-blending-image-color-ref.html
 # Test 10
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-gif.html background-blending-image-color-gif-ref.html
 pref(layout.css.background-blend-mode.enabled,true) == background-blending-image-color-transform3d.html background-blending-image-color-ref.html