void RenderViewMLGPU::PrepareClears() {
  // We don't do any clearing if we're copying from a source backdrop.
  if (mContainer && mContainer->NeedsSurfaceCopy()) {
    return;
  }

  // Get the list of rects to clear. If using the depth buffer, we don't
  // care if it's accurate since the GPU will do occlusion testing for us.
  // If not using the depth buffer, we subtract out the occluded region.
  LayerIntRegion region = LayerIntRect::FromUnknownRect(mInvalidBounds);
  if (!mUseDepthBuffer) {
    // Don't let the clear region become too complicated.
    region.SubOut(mOccludedRegion);
    region.SimplifyOutward(kMaxClearViewRects);
  }

  Maybe<int32_t> sortIndex;
  if (mUseDepthBuffer) {
    // Note that we use the lowest available sorting index, to ensure that when
    // using the z-buffer, we don't draw over already-drawn content.
    sortIndex = Some(mNextSortIndex++);
  }

  nsTArray<IntRect> rects = ToRectArray(region);
  mDevice->PrepareClearRegion(&mPreClear, std::move(rects), sortIndex);

  if (!mPostClearRegion.IsEmpty()) {
    // Prepare the final clear as well. Note that we always do this clear at the
    // very end, even when the depth buffer is enabled, so we don't bother
    // setting a useful sorting index. If and when we try to ship the depth
    // buffer, we would execute this clear earlier in the pipeline and give it
    // the closest possible z-ordering to the screen.
    nsTArray<IntRect> rects = ToRectArray(mPostClearRegion);
    mDevice->PrepareClearRegion(&mPostClear, std::move(rects), Nothing());
  }
}
void
LayerManagerComposite::PostProcessLayers(Layer* aLayer,
                                         nsIntRegion& aOpaqueRegion,
                                         LayerIntRegion& aVisibleRegion,
                                         const Maybe<ParentLayerIntRect>& aClipFromAncestors)
{
  if (aLayer->Extend3DContext()) {
    // For layers participating 3D rendering context, their visible
    // region should be empty (invisible), so we pass through them
    // without doing anything.

    // Direct children of the establisher may have a clip, becaue the
    // item containing it; ex. of nsHTMLScrollFrame, may give it one.
    Maybe<ParentLayerIntRect> layerClip =
      aLayer->AsHostLayer()->GetShadowClipRect();
    Maybe<ParentLayerIntRect> ancestorClipForChildren =
      IntersectMaybeRects(layerClip, aClipFromAncestors);
    MOZ_ASSERT(!layerClip || !aLayer->Combines3DTransformWithAncestors(),
               "Only direct children of the establisher could have a clip");

    for (Layer* child = aLayer->GetLastChild();
         child;
         child = child->GetPrevSibling()) {
      PostProcessLayers(child, aOpaqueRegion, aVisibleRegion,
                        ancestorClipForChildren);
    }
    return;
  }

  nsIntRegion localOpaque;
  // Treat layers on the path to the root of the 3D rendering context as
  // a giant layer if it is a leaf.
  Matrix4x4 transform = GetAccTransformIn3DContext(aLayer);
  Matrix transform2d;
  Maybe<IntPoint> integerTranslation;
  // If aLayer has a simple transform (only an integer translation) then we
  // can easily convert aOpaqueRegion into pre-transform coordinates and include
  // that region.
  if (transform.Is2D(&transform2d)) {
    if (transform2d.IsIntegerTranslation()) {
      integerTranslation = Some(IntPoint::Truncate(transform2d.GetTranslation()));
      localOpaque = aOpaqueRegion;
      localOpaque.MoveBy(-*integerTranslation);
    }
  }

  // Compute a clip that's the combination of our layer clip with the clip
  // from our ancestors.
  LayerComposite* composite = static_cast<LayerComposite*>(aLayer->AsHostLayer());
  Maybe<ParentLayerIntRect> layerClip = composite->GetShadowClipRect();
  MOZ_ASSERT(!layerClip || !aLayer->Combines3DTransformWithAncestors(),
             "The layer with a clip should not participate "
             "a 3D rendering context");
  Maybe<ParentLayerIntRect> outsideClip =
    IntersectMaybeRects(layerClip, aClipFromAncestors);

  // Convert the combined clip into our pre-transform coordinate space, so
  // that it can later be intersected with our visible region.
  // If our transform is a perspective, there's no meaningful insideClip rect
  // we can compute (it would need to be a cone).
  Maybe<LayerIntRect> insideClip;
  if (outsideClip && !transform.HasPerspectiveComponent()) {
    Matrix4x4 inverse = transform;
    if (inverse.Invert()) {
      Maybe<LayerRect> insideClipFloat =
        UntransformBy(ViewAs<ParentLayerToLayerMatrix4x4>(inverse),
                      ParentLayerRect(*outsideClip),
                      LayerRect::MaxIntRect());
      if (insideClipFloat) {
        insideClipFloat->RoundOut();
        LayerIntRect insideClipInt;
        if (insideClipFloat->ToIntRect(&insideClipInt)) {
          insideClip = Some(insideClipInt);
        }
      }
    }
  }

  Maybe<ParentLayerIntRect> ancestorClipForChildren;
  if (insideClip) {
    ancestorClipForChildren =
      Some(ViewAs<ParentLayerPixel>(*insideClip, PixelCastJustification::MovingDownToChildren));
  }

  // Save the value of localOpaque, which currently stores the region obscured
  // by siblings (and uncles and such), before our descendants contribute to it.
  nsIntRegion obscured = localOpaque;

  // Recurse on our descendants, in front-to-back order. In this process:
  //  - Occlusions are computed for them, and they contribute to localOpaque.
  //  - They recalculate their visible regions, taking ancestorClipForChildren
  //    into account, and accumulate them into descendantsVisibleRegion.
  LayerIntRegion descendantsVisibleRegion;
  bool hasPreserve3DChild = false;
  for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
    PostProcessLayers(child, localOpaque, descendantsVisibleRegion, ancestorClipForChildren);
    if (child->Extend3DContext()) {
      hasPreserve3DChild = true;
    }
  }

  // Recalculate our visible region.
  LayerIntRegion visible = composite->GetShadowVisibleRegion();

  // If we have descendants, throw away the visible region stored on this
  // layer, and use the region accumulated by our descendants instead.
  if (aLayer->GetFirstChild() && !hasPreserve3DChild) {
    visible = descendantsVisibleRegion;
  }

  // Subtract any areas that we know to be opaque.
  if (!obscured.IsEmpty()) {
    visible.SubOut(LayerIntRegion::FromUnknownRegion(obscured));
  }

  // Clip the visible region using the combined clip.
  if (insideClip) {
    visible.AndWith(*insideClip);
  }
  composite->SetShadowVisibleRegion(visible);

  // Transform the newly calculated visible region into our parent's space,
  // apply our clip to it (if any), and accumulate it into |aVisibleRegion|
  // for the caller to use.
  ParentLayerIntRegion visibleParentSpace = TransformBy(
      ViewAs<LayerToParentLayerMatrix4x4>(transform), visible);
  if (const Maybe<ParentLayerIntRect>& clipRect = composite->GetShadowClipRect()) {
    visibleParentSpace.AndWith(*clipRect);
  }
  aVisibleRegion.OrWith(ViewAs<LayerPixel>(visibleParentSpace,
      PixelCastJustification::MovingDownToChildren));

  // If we have a simple transform, then we can add our opaque area into
  // aOpaqueRegion.
  if (integerTranslation &&
      !aLayer->HasMaskLayers() &&
      aLayer->IsOpaqueForVisibility()) {
    if (aLayer->IsOpaque()) {
      localOpaque.OrWith(composite->GetFullyRenderedRegion());
    }
    localOpaque.MoveBy(*integerTranslation);
    if (layerClip) {
      localOpaque.AndWith(layerClip->ToUnknownRect());
    }
    aOpaqueRegion.OrWith(localOpaque);
  }
}
bool RenderViewMLGPU::UpdateVisibleRegion(ItemInfo& aItem) {
  // If the item has some kind of complex transform, we perform a very
  // simple occlusion test and move on. We using a depth buffer we skip
  // CPU-based occlusion culling as well, since the GPU will do most of our
  // culling work for us.
  if (mUseDepthBuffer || !aItem.translation ||
      !gfxPrefs::AdvancedLayersEnableCPUOcclusion()) {
    // Update the render region even if we won't compute visibility, since some
    // layer types (like Canvas and Image) need to have the visible region
    // clamped.
    LayerIntRegion region = aItem.layer->GetShadowVisibleRegion();
    aItem.layer->SetRenderRegion(std::move(region));

    AL_LOG("RenderView %p simple occlusion test, bounds=%s, translation?=%d\n",
           this, Stringify(aItem.bounds).c_str(), aItem.translation ? 1 : 0);
    return mInvalidBounds.Intersects(aItem.bounds);
  }

  MOZ_ASSERT(aItem.rectilinear);

  AL_LOG("RenderView %p starting visibility tests:\n", this);
  AL_LOG("  occluded=%s\n", Stringify(mOccludedRegion).c_str());

  // Compute the translation into render target space.
  LayerIntPoint translation = LayerIntPoint::FromUnknownPoint(
      aItem.translation.value() - mTargetOffset);
  AL_LOG("  translation=%s\n", Stringify(translation).c_str());

  IntRect clip = aItem.layer->GetComputedClipRect().ToUnknownRect();
  AL_LOG("  clip=%s\n", Stringify(translation).c_str());

  LayerIntRegion region = aItem.layer->GetShadowVisibleRegion();
  region.MoveBy(translation);
  AL_LOG("  effective-visible=%s\n", Stringify(region).c_str());

  region.SubOut(mOccludedRegion);
  region.AndWith(LayerIntRect::FromUnknownRect(mInvalidBounds));
  region.AndWith(LayerIntRect::FromUnknownRect(clip));
  if (region.IsEmpty()) {
    return false;
  }

  // Move the visible region back into layer space.
  region.MoveBy(-translation);
  AL_LOG("  new-local-visible=%s\n", Stringify(region).c_str());

  aItem.layer->SetRenderRegion(std::move(region));

  // Apply the new occluded area. We do another dance with the translation to
  // avoid copying the region. We do this after the SetRegionToRender call to
  // accomodate the possiblity of a layer changing its visible region.
  if (aItem.opaque) {
    mOccludedRegion.MoveBy(-translation);
    mOccludedRegion.OrWith(aItem.layer->GetRenderRegion());
    mOccludedRegion.MoveBy(translation);
    AL_LOG("  new-occluded=%s\n", Stringify(mOccludedRegion).c_str());

    // If the occluded region gets too complicated, we reset it.
    if (mOccludedRegion.GetNumRects() >= 32) {
      mOccludedRegion.SetEmpty();
      AL_LOG("  clear-occluded, too many rects\n");
    }
  }
  return true;
}
void
LayerManagerComposite::PostProcessLayers(Layer* aLayer,
                                         nsIntRegion& aOpaqueRegion,
                                         LayerIntRegion& aVisibleRegion)
{
  nsIntRegion localOpaque;
  Matrix transform2d;
  Maybe<nsIntPoint> integerTranslation;
  // If aLayer has a simple transform (only an integer translation) then we
  // can easily convert aOpaqueRegion into pre-transform coordinates and include
  // that region.
  if (aLayer->GetLocalTransform().Is2D(&transform2d)) {
    if (transform2d.IsIntegerTranslation()) {
      integerTranslation = Some(TruncatedToInt(transform2d.GetTranslation()));
      localOpaque = aOpaqueRegion;
      localOpaque.MoveBy(-*integerTranslation);
    }
  }

  // Save the value of localOpaque, which currently stores the region obscured
  // by siblings (and uncles and such), before our descendants contribute to it.
  nsIntRegion obscured = localOpaque;

  // Recurse on our descendants, in front-to-back order. In this process:
  //  - Occlusions are computed for them, and they contribute to localOpaque.
  //  - They recalculate their visible regions, and accumulate them into
  //    descendantsVisibleRegion.
  LayerIntRegion descendantsVisibleRegion;
  for (Layer* child = aLayer->GetLastChild(); child; child = child->GetPrevSibling()) {
    PostProcessLayers(child, localOpaque, descendantsVisibleRegion);
  }

  // Recalculate our visible region.
  LayerComposite* composite = aLayer->AsLayerComposite();
  LayerIntRegion visible = composite->GetShadowVisibleRegion();

  // If we have descendants, throw away the visible region stored on this
  // layer, and use the region accumulated by our descendants instead.
  if (aLayer->GetFirstChild()) {
    visible = descendantsVisibleRegion;
  }

  // Subtract any areas that we know to be opaque.
  if (!obscured.IsEmpty()) {
    visible.SubOut(LayerIntRegion::FromUnknownRegion(obscured));
  }

  composite->SetShadowVisibleRegion(visible);

  // Transform the newly calculated visible region into our parent's space,
  // apply our clip to it (if any), and accumulate it into |aVisibleRegion|
  // for the caller to use.
  ParentLayerIntRegion visibleParentSpace = TransformTo<ParentLayerPixel>(
      aLayer->GetLocalTransform(), visible);
  if (const Maybe<ParentLayerIntRect>& clipRect = composite->GetShadowClipRect()) {
    visibleParentSpace.AndWith(*clipRect);
  }
  aVisibleRegion.OrWith(ViewAs<LayerPixel>(visibleParentSpace,
      PixelCastJustification::MovingDownToChildren));

  // If we have a simple transform, then we can add our opaque area into
  // aOpaqueRegion.
  if (integerTranslation &&
      !aLayer->HasMaskLayers() &&
      aLayer->IsOpaqueForVisibility()) {
    if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) {
      localOpaque.OrWith(composite->GetFullyRenderedRegion());
    }
    localOpaque.MoveBy(*integerTranslation);
    const Maybe<ParentLayerIntRect>& clip = aLayer->GetEffectiveClipRect();
    if (clip) {
      localOpaque.AndWith(clip->ToUnknownRect());
    }
    aOpaqueRegion.OrWith(localOpaque);
  }
}