Source code

Revision control

Other Tools

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#include "ContainerLayerComposite.h"
#include <algorithm> // for min
#include "FrameMetrics.h" // for FrameMetrics
#include "Units.h" // for LayerRect, LayerPixel, etc
#include "CompositableHost.h" // for CompositableHost
#include "gfxEnv.h" // for gfxEnv
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/RefPtr.h" // for RefPtr
#include "mozilla/StaticPrefs_apz.h"
#include "mozilla/StaticPrefs_layers.h"
#include "mozilla/UniquePtr.h" // for UniquePtr
#include "mozilla/gfx/BaseRect.h" // for BaseRect
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
#include "mozilla/gfx/Point.h" // for Point, IntPoint
#include "mozilla/gfx/Rect.h" // for IntRect, Rect
#include "mozilla/layers/APZSampler.h" // for APZSampler
#include "mozilla/layers/BSPTree.h"
#include "mozilla/layers/Compositor.h" // for Compositor, etc
#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent
#include "mozilla/layers/CompositorTypes.h" // for DiagnosticFlags::CONTAINER
#include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc
#include "mozilla/layers/TextureHost.h" // for CompositingRenderTarget
#include "mozilla/layers/APZUtils.h" // for AsyncTransform
#include "mozilla/layers/LayerManagerCompositeUtils.h"
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
#include "mozilla/layers/LayersHelpers.h"
#include "mozilla/mozalloc.h" // for operator delete, etc
#include "mozilla/RefPtr.h" // for nsRefPtr
#include "nsDebug.h" // for NS_ASSERTION
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
#include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
#include "nsRegion.h" // for nsIntRegion
#include "nsTArray.h" // for AutoTArray
#include <stack>
#include "TextRenderer.h" // for TextRenderer
#include <vector>
#include "GeckoProfiler.h" // for GeckoProfiler
static mozilla::LazyLogModule sGfxCullLog("gfx.culling");
#define CULLING_LOG(...) MOZ_LOG(sGfxCullLog, LogLevel::Debug, (__VA_ARGS__))
#define DUMP(...) \
do { \
if (gfxEnv::DumpDebug()) { \
printf_stderr(__VA_ARGS__); \
} \
} while (0)
#define XYWH(k) (k).X(), (k).Y(), (k).Width(), (k).Height()
#define XY(k) (k).X(), (k).Y()
#define WH(k) (k).Width(), (k).Height()
namespace mozilla {
namespace layers {
using namespace gfx;
static void DrawLayerInfo(const RenderTargetIntRect& aClipRect,
LayerManagerComposite* aManager, Layer* aLayer) {
if (aLayer->GetType() == Layer::LayerType::TYPE_CONTAINER) {
// XXX - should figure out a way to render this, but for now this
// is hard to do, since it will often get superimposed over the first
// child of the layer, which is bad.
return;
}
std::stringstream ss;
aLayer->PrintInfo(ss, "");
LayerIntRegion visibleRegion = aLayer->GetVisibleRegion();
uint32_t maxWidth =
std::min<uint32_t>(visibleRegion.GetBounds().Width(), 500);
IntPoint topLeft = visibleRegion.GetBounds().ToUnknownRect().TopLeft();
aManager->GetTextRenderer()->RenderText(
aManager->GetCompositor(), ss.str().c_str(), topLeft,
aLayer->GetEffectiveTransform(), 16, maxWidth);
}
static void PrintUniformityInfo(Layer* aLayer) {
#if defined(MOZ_GECKO_PROFILER)
if (!profiler_thread_is_being_profiled()) {
return;
}
// Don't want to print a log for smaller layers
if (aLayer->GetLocalVisibleRegion().GetBounds().Width() < 300 ||
aLayer->GetLocalVisibleRegion().GetBounds().Height() < 300) {
return;
}
Matrix4x4 transform = aLayer->AsHostLayer()->GetShadowBaseTransform();
if (!transform.Is2D()) {
return;
}
Point translation = transform.As2D().GetTranslation();
// Contains the translation applied to a 2d layer so we can track the layer
// position at each frame.
struct LayerTranslationMarker {
static constexpr Span<const char> MarkerTypeName() {
return MakeStringSpan("LayerTranslation");
}
static void StreamJSONMarkerData(
baseprofiler::SpliceableJSONWriter& aWriter,
ProfileBufferRawPointer<layers::Layer> aLayer, gfx::Point aPoint) {
const size_t bufferSize = 32;
char buffer[bufferSize];
SprintfLiteral(buffer, "%p", aLayer.mRawPointer);
aWriter.StringProperty("layer", buffer);
aWriter.IntProperty("x", aPoint.x);
aWriter.IntProperty("y", aPoint.y);
}
static MarkerSchema MarkerTypeDisplay() {
using MS = MarkerSchema;
MS schema{MS::Location::markerChart, MS::Location::markerTable};
schema.AddKeyLabelFormat("layer", "Layer", MS::Format::string);
schema.AddKeyLabelFormat("x", "X", MS::Format::integer);
schema.AddKeyLabelFormat("y", "Y", MS::Format::integer);
return schema;
}
};
profiler_add_marker("LayerTranslation", geckoprofiler::category::GRAPHICS, {},
LayerTranslationMarker{},
WrapProfileBufferRawPointer(aLayer), translation);
#endif
}
static Maybe<gfx::Polygon> SelectLayerGeometry(
const Maybe<gfx::Polygon>& aParentGeometry,
const Maybe<gfx::Polygon>& aChildGeometry) {
// Both the parent and the child layer were split.
if (aParentGeometry && aChildGeometry) {
return Some(aParentGeometry->ClipPolygon(*aChildGeometry));
}
// The parent layer was split.
if (aParentGeometry) {
return aParentGeometry;
}
// The child layer was split.
if (aChildGeometry) {
return aChildGeometry;
}
// No split.
return Nothing();
}
void TransformLayerGeometry(Layer* aLayer, Maybe<gfx::Polygon>& aGeometry) {
Layer* parent = aLayer;
gfx::Matrix4x4 transform;
// Collect all parent transforms.
while (parent != nullptr && !parent->Is3DContextLeaf()) {
transform = transform * parent->GetLocalTransform();
parent = parent->GetParent();
}
// Transform the geometry to the parent 3D context leaf coordinate space.
transform = transform.ProjectTo2D();
if (!transform.IsSingular()) {
aGeometry->TransformToScreenSpace(transform.Inverse(), transform);
} else {
// Discard the geometry since the result might not be correct.
aGeometry.reset();
}
}
template <class ContainerT>
static gfx::IntRect ContainerVisibleRect(ContainerT* aContainer) {
gfx::IntRect surfaceRect =
aContainer->GetLocalVisibleRegion().GetBounds().ToUnknownRect();
return surfaceRect;
}
/* all of the per-layer prepared data we need to maintain */
struct PreparedLayer {
PreparedLayer(Layer* aLayer, RenderTargetIntRect aClipRect,
Maybe<gfx::Polygon>&& aGeometry)
: mLayer(aLayer), mClipRect(aClipRect), mGeometry(std::move(aGeometry)) {}
RefPtr<Layer> mLayer;
RenderTargetIntRect mClipRect;
Maybe<Polygon> mGeometry;
};
/* all of the prepared data that we need in RenderLayer() */
struct PreparedData {
RefPtr<CompositingRenderTarget> mTmpTarget;
AutoTArray<PreparedLayer, 12> mLayers;
bool mNeedsSurfaceCopy;
};
// ContainerPrepare is shared between RefLayer and ContainerLayer
template <class ContainerT>
void ContainerPrepare(ContainerT* aContainer, LayerManagerComposite* aManager,
const RenderTargetIntRect& aClipRect) {
// We can end up calling prepare multiple times if we duplicated
// layers due to preserve-3d plane splitting. The results
// should be identical, so we only need to do it once.
if (aContainer->mPrepared) {
return;
}
aContainer->mPrepared = MakeUnique<PreparedData>();
aContainer->mPrepared->mNeedsSurfaceCopy = false;
const ContainerLayerComposite::SortMode sortMode =
aManager->GetCompositor()->SupportsLayerGeometry()
? ContainerLayerComposite::SortMode::WITH_GEOMETRY
: ContainerLayerComposite::SortMode::WITHOUT_GEOMETRY;
nsTArray<LayerPolygon> polygons =
aContainer->SortChildrenBy3DZOrder(sortMode);
for (LayerPolygon& layer : polygons) {
LayerComposite* layerToRender =
static_cast<LayerComposite*>(layer.layer->ImplData());
RenderTargetIntRect clipRect =
layerToRender->GetLayer()->CalculateScissorRect(aClipRect);
if (layerToRender->GetLayer()->IsBackfaceHidden()) {
continue;
}
// We don't want to skip container layers because otherwise their mPrepared
// may be null which is not allowed.
if (!layerToRender->GetLayer()->AsContainerLayer()) {
if (!layerToRender->GetLayer()->IsVisible()) {
CULLING_LOG("Sublayer %p has no effective visible region\n",
layerToRender->GetLayer());
continue;
}
if (clipRect.IsEmpty()) {
CULLING_LOG("Sublayer %p has an empty world clip rect\n",
layerToRender->GetLayer());
continue;
}
}
CULLING_LOG("Preparing sublayer %p\n", layerToRender->GetLayer());
layerToRender->Prepare(clipRect);
aContainer->mPrepared->mLayers.AppendElement(PreparedLayer(
layerToRender->GetLayer(), clipRect, std::move(layer.geometry)));
}
CULLING_LOG("Preparing container layer %p\n", aContainer->GetLayer());
/**
* Setup our temporary surface for rendering the contents of this container.
*/
gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
if (surfaceRect.IsEmpty()) {
return;
}
bool surfaceCopyNeeded;
// DefaultComputeSupportsComponentAlphaChildren can mutate aContainer so call
// it unconditionally
aContainer->DefaultComputeSupportsComponentAlphaChildren(&surfaceCopyNeeded);
if (aContainer->UseIntermediateSurface()) {
if (!surfaceCopyNeeded) {
RefPtr<CompositingRenderTarget> surface = nullptr;
RefPtr<CompositingRenderTarget>& lastSurf =
aContainer->mLastIntermediateSurface;
if (lastSurf && !aContainer->mChildrenChanged &&
lastSurf->GetRect().IsEqualEdges(surfaceRect)) {
surface = lastSurf;
}
if (!surface) {
// If we don't need a copy we can render to the intermediate now to
// avoid unecessary render target switching. This brings a big perf
// boost on mobile gpus.
surface = CreateOrRecycleTarget(aContainer, aManager);
MOZ_PERFORMANCE_WARNING(
"gfx",
"[%p] Container layer requires intermediate surface rendering\n",
aContainer);
RenderIntermediate(aContainer, aManager, aClipRect.ToUnknownRect(),
surface);
aContainer->SetChildrenChanged(false);
}
aContainer->mPrepared->mTmpTarget = surface;
} else {
MOZ_PERFORMANCE_WARNING(
"gfx", "[%p] Container layer requires intermediate surface copy\n",
aContainer);
aContainer->mPrepared->mNeedsSurfaceCopy = true;
aContainer->mLastIntermediateSurface = nullptr;
}
} else {
aContainer->mLastIntermediateSurface = nullptr;
}
}
template <class ContainerT>
void RenderMinimap(ContainerT* aContainer, const RefPtr<APZSampler>& aSampler,
LayerManagerComposite* aManager,
const RenderTargetIntRect& aClipRect, Layer* aLayer) {
Compositor* compositor = aManager->GetCompositor();
MOZ_ASSERT(aSampler);
if (aLayer->GetScrollMetadataCount() < 1) {
return;
}
LayerMetricsWrapper wrapper(aLayer, 0);
if (!wrapper.GetApzc()) {
return;
}
const FrameMetrics& fm = wrapper.Metrics();
MOZ_ASSERT(fm.IsScrollable());
ParentLayerPoint scrollOffset =
aSampler->GetCurrentAsyncScrollOffset(wrapper);
// Options
const int verticalPadding = 10;
const int horizontalPadding = 5;
gfx::DeviceColor backgroundColor(0.3f, 0.3f, 0.3f, 0.3f);
gfx::DeviceColor tileActiveColor(1, 1, 1, 0.4f);
gfx::DeviceColor tileBorderColor(0, 0, 0, 0.1f);
gfx::DeviceColor pageBorderColor(0, 0, 0);
gfx::DeviceColor criticalDisplayPortColor(1.f, 1.f, 0);
gfx::DeviceColor displayPortColor(0, 1.f, 0);
gfx::DeviceColor layoutPortColor(1.f, 0, 0);
gfx::DeviceColor visualPortColor(0, 0, 1.f, 0.3f);
// Rects
ParentLayerRect compositionBounds = fm.GetCompositionBounds();
LayerRect scrollRect = fm.GetScrollableRect() * fm.LayersPixelsPerCSSPixel();
LayerRect visualRect =
ParentLayerRect(scrollOffset, compositionBounds.Size()) /
LayerToParentLayerScale(1);
LayerRect dp = (fm.GetDisplayPort() + fm.GetLayoutScrollOffset()) *
fm.LayersPixelsPerCSSPixel();
Maybe<LayerRect> layoutRect;
Maybe<LayerRect> cdp;
if (fm.IsRootContent()) {
CSSRect viewport = aSampler->GetCurrentAsyncLayoutViewport(wrapper);
layoutRect = Some(viewport * fm.LayersPixelsPerCSSPixel());
}
if (!fm.GetCriticalDisplayPort().IsEmpty()) {
cdp = Some((fm.GetCriticalDisplayPort() + fm.GetLayoutScrollOffset()) *
fm.LayersPixelsPerCSSPixel());
}
// Don't render trivial minimap. They can show up from textboxes and other
// tiny frames.
if (visualRect.Width() < 64 && visualRect.Height() < 64) {
return;
}
// Compute a scale with an appropriate aspect ratio
// We allocate up to 100px of width and the height of this layer.
float scaleFactor;
float scaleFactorX;
float scaleFactorY;
Rect dest = Rect(aClipRect.ToUnknownRect());
if (aLayer->GetLocalClipRect()) {
dest = Rect(aLayer->GetLocalClipRect().value().ToUnknownRect());
} else {
dest = aContainer->GetEffectiveTransform().Inverse().TransformBounds(dest);
}
dest = dest.Intersect(compositionBounds.ToUnknownRect());
scaleFactorX = std::min(100.f, dest.Width() - (2 * horizontalPadding)) /
scrollRect.Width();
scaleFactorY = (dest.Height() - (2 * verticalPadding)) / scrollRect.Height();
scaleFactor = std::min(scaleFactorX, scaleFactorY);
if (scaleFactor <= 0) {
return;
}
Matrix4x4 transform = Matrix4x4::Scaling(scaleFactor, scaleFactor, 1);
transform.PostTranslate(horizontalPadding + dest.X(),
verticalPadding + dest.Y(), 0);
Rect transformedScrollRect =
transform.TransformBounds(scrollRect.ToUnknownRect());
IntRect clipRect =
RoundedOut(aContainer->GetEffectiveTransform().TransformBounds(
transformedScrollRect));
// Render the scrollable area.
compositor->FillRect(transformedScrollRect, backgroundColor, clipRect,
aContainer->GetEffectiveTransform());
compositor->SlowDrawRect(transformedScrollRect, pageBorderColor, clipRect,
aContainer->GetEffectiveTransform());
// Render the displayport.
Rect r = transform.TransformBounds(dp.ToUnknownRect());
compositor->FillRect(r, tileActiveColor, clipRect,
aContainer->GetEffectiveTransform());
compositor->SlowDrawRect(r, displayPortColor, clipRect,
aContainer->GetEffectiveTransform());
// Render the critical displayport if there is one
if (cdp) {
r = transform.TransformBounds(cdp->ToUnknownRect());
compositor->SlowDrawRect(r, criticalDisplayPortColor, clipRect,
aContainer->GetEffectiveTransform());
}
// Render the layout viewport if it exists (which is only in the root
// content APZC).
if (layoutRect) {
r = transform.TransformBounds(layoutRect->ToUnknownRect());
compositor->SlowDrawRect(r, layoutPortColor, clipRect,
aContainer->GetEffectiveTransform());
}
// Render the visual viewport.
r = transform.TransformBounds(visualRect.ToUnknownRect());
compositor->SlowDrawRect(r, visualPortColor, clipRect,
aContainer->GetEffectiveTransform(), 2);
}
template <class ContainerT>
void RenderLayers(ContainerT* aContainer, LayerManagerComposite* aManager,
const RenderTargetIntRect& aClipRect,
const Maybe<gfx::Polygon>& aGeometry) {
Compositor* compositor = aManager->GetCompositor();
RefPtr<APZSampler> sampler;
if (CompositorBridgeParent* cbp = compositor->GetCompositorBridgeParent()) {
sampler = cbp->GetAPZSampler();
}
for (size_t i = 0u; i < aContainer->mPrepared->mLayers.Length(); i++) {
PreparedLayer& preparedData = aContainer->mPrepared->mLayers[i];
const gfx::IntRect clipRect = preparedData.mClipRect.ToUnknownRect();
LayerComposite* layerToRender =
static_cast<LayerComposite*>(preparedData.mLayer->ImplData());
const Maybe<gfx::Polygon>& childGeometry = preparedData.mGeometry;
Layer* layer = layerToRender->GetLayer();
if (layerToRender->HasStaleCompositor()) {
continue;
}
if (StaticPrefs::layers_acceleration_draw_fps()) {
for (const auto& metadata : layer->GetAllScrollMetadata()) {
if (metadata.IsApzForceDisabled()) {
aManager->DisabledApzWarning();
break;
}
}
}
if (layerToRender->HasLayerBeenComposited()) {
// Composer2D will compose this layer so skip GPU composition
// this time. The flag will be reset for the next composition phase
// at the beginning of LayerManagerComposite::Rener().
gfx::IntRect clearRect = layerToRender->GetClearRect();
if (!clearRect.IsEmpty()) {
// Clear layer's visible rect on FrameBuffer with transparent pixels
gfx::Rect fbRect(clearRect.X(), clearRect.Y(), clearRect.Width(),
clearRect.Height());
compositor->ClearRect(fbRect);
layerToRender->SetClearRect(gfx::IntRect(0, 0, 0, 0));
}
} else {
// Since we force an intermediate surface for nested 3D contexts,
// aGeometry and childGeometry are both in the same coordinate space.
Maybe<gfx::Polygon> geometry =
SelectLayerGeometry(aGeometry, childGeometry);
// If we are dealing with a nested 3D context, we might need to transform
// the geometry back to the coordinate space of the current layer before
// rendering the layer.
ContainerLayer* container = layer->AsContainerLayer();
const bool isLeafLayer =
!container || container->UseIntermediateSurface();
if (geometry && isLeafLayer) {
TransformLayerGeometry(layer, geometry);
}
layerToRender->RenderLayer(clipRect, geometry);
}
if (StaticPrefs::layers_uniformity_info_AtStartup()) {
PrintUniformityInfo(layer);
}
if (StaticPrefs::layers_draw_layer_info()) {
DrawLayerInfo(preparedData.mClipRect, aManager, layer);
}
// Draw a border around scrollable layers.
// A layer can be scrolled by multiple scroll frames. Draw a border
// for each.
// Within the list of scroll frames for a layer, the layer border for a
// scroll frame lower down is affected by the async transforms on scroll
// frames higher up, so loop from the top down, and accumulate an async
// transform as we go along.
Matrix4x4 asyncTransform;
if (sampler) {
for (uint32_t i = layer->GetScrollMetadataCount(); i > 0; --i) {
LayerMetricsWrapper wrapper(layer, i - 1);
if (wrapper.GetApzc()) {
MOZ_ASSERT(wrapper.Metrics().IsScrollable());
// Since the composition bounds are in the parent layer's coordinates,
// use the parent's effective transform rather than the layer's own.
ParentLayerRect compositionBounds =
wrapper.Metrics().GetCompositionBounds();
aManager->GetCompositor()->DrawDiagnostics(
DiagnosticFlags::CONTAINER, compositionBounds.ToUnknownRect(),
aClipRect.ToUnknownRect(),
asyncTransform * aContainer->GetEffectiveTransform());
asyncTransform = sampler
->GetCurrentAsyncTransformWithOverscroll(
wrapper, LayoutAndVisual)
.ToUnknownMatrix() *
asyncTransform;
}
}
if (StaticPrefs::apz_minimap_enabled()) {
RenderMinimap(aContainer, sampler, aManager, aClipRect, layer);
}
}
// invariant: our GL context should be current here, I don't think we can
// assert it though
}
}
template <class ContainerT>
RefPtr<CompositingRenderTarget> CreateOrRecycleTarget(
ContainerT* aContainer, LayerManagerComposite* aManager) {
Compositor* compositor = aManager->GetCompositor();
SurfaceInitMode mode = INIT_MODE_CLEAR;
gfx::IntRect surfaceRect = ContainerVisibleRect(aContainer);
if (aContainer->GetLocalVisibleRegion().GetNumRects() == 1 &&
(aContainer->GetContentFlags() & Layer::CONTENT_OPAQUE)) {
mode = INIT_MODE_NONE;
}
RefPtr<CompositingRenderTarget>& lastSurf =
aContainer->mLastIntermediateSurface;
if (lastSurf && lastSurf->GetRect().IsEqualEdges(surfaceRect)) {
if (mode == INIT_MODE_CLEAR) {
lastSurf->ClearOnBind();
}
return lastSurf;
} else {
lastSurf = compositor->CreateRenderTarget(surfaceRect, mode);
return lastSurf;
}
}
template <class ContainerT>
RefPtr<CompositingRenderTarget> CreateTemporaryTargetAndCopyFromBackground(
ContainerT* aContainer, LayerManagerComposite* aManager) {
Compositor* compositor = aManager->GetCompositor();
gfx::IntRect visibleRect =
aContainer->GetLocalVisibleRegion().GetBounds().ToUnknownRect();
RefPtr<CompositingRenderTarget> previousTarget =
compositor->GetCurrentRenderTarget();
gfx::IntRect surfaceRect =
gfx::IntRect(visibleRect.X(), visibleRect.Y(), visibleRect.Width(),
visibleRect.Height());
gfx::IntPoint sourcePoint = gfx::IntPoint(visibleRect.X(), visibleRect.Y());
gfx::Matrix4x4 transform = aContainer->GetEffectiveTransform();
DebugOnly<gfx::Matrix> transform2d;
MOZ_ASSERT(transform.Is2D(&transform2d) &&
!gfx::ThebesMatrix(transform2d).HasNonIntegerTranslation());
sourcePoint += gfx::IntPoint::Truncate(transform._41, transform._42);
sourcePoint -= previousTarget->GetOrigin();
return compositor->CreateRenderTargetFromSource(surfaceRect, previousTarget,
sourcePoint);
}
template <class ContainerT>
void RenderIntermediate(ContainerT* aContainer, LayerManagerComposite* aManager,
const gfx::IntRect& aClipRect,
RefPtr<CompositingRenderTarget> surface) {
Compositor* compositor = aManager->GetCompositor();
RefPtr<CompositingRenderTarget> previousTarget =
compositor->GetCurrentRenderTarget();
if (!surface) {
return;
}
compositor->SetRenderTarget(surface);
// pre-render all of the layers into our temporary
RenderLayers(aContainer, aManager,
RenderTargetIntRect::FromUnknownRect(aClipRect), Nothing());
// Unbind the current surface and rebind the previous one.
compositor->SetRenderTarget(previousTarget);
}
template <class ContainerT>
void ContainerRender(ContainerT* aContainer, LayerManagerComposite* aManager,
const gfx::IntRect& aClipRect,
const Maybe<gfx::Polygon>& aGeometry) {
MOZ_ASSERT(aContainer->mPrepared);
if (aContainer->UseIntermediateSurface()) {
RefPtr<CompositingRenderTarget> surface;
if (aContainer->mPrepared->mNeedsSurfaceCopy) {
// we needed to copy the background so we waited until now to render the
// intermediate
surface =
CreateTemporaryTargetAndCopyFromBackground(aContainer, aManager);
RenderIntermediate(aContainer, aManager, aClipRect, surface);
} else {
surface = aContainer->mPrepared->mTmpTarget;
}
if (!surface) {
return;
}
gfx::Rect visibleRect(
aContainer->GetLocalVisibleRegion().GetBounds().ToUnknownRect());
RefPtr<Compositor> compositor = aManager->GetCompositor();
#ifdef MOZ_DUMP_PAINTING
if (gfxEnv::DumpCompositorTextures()) {
RefPtr<gfx::DataSourceSurface> surf = surface->Dump(compositor);
if (surf) {
WriteSnapshotToDumpFile(aContainer, surf);
}
}
#endif
RefPtr<ContainerT> container = aContainer;
RenderWithAllMasks(aContainer, compositor, aClipRect,
[&, surface, compositor, container](
EffectChain& effectChain, const IntRect& clipRect) {
effectChain.mPrimaryEffect =
new EffectRenderTarget(surface);
compositor->DrawGeometry(
visibleRect, clipRect, effectChain,
container->GetEffectiveOpacity(),
container->GetEffectiveTransform(), aGeometry);
});
} else {
RenderLayers(aContainer, aManager,
RenderTargetIntRect::FromUnknownRect(aClipRect), aGeometry);
}
// If it is a scrollable container layer with no child layers, and one of the
// APZCs attached to it has a nonempty async transform, then that transform is
// not applied to any visible content. Display a warning box (conditioned on
// the FPS display being enabled).
if (StaticPrefs::layers_acceleration_draw_fps() &&
aContainer->IsScrollableWithoutContent()) {
RefPtr<APZSampler> sampler =
aManager->GetCompositor()->GetCompositorBridgeParent()->GetAPZSampler();
// Since aContainer doesn't have any children we can just iterate from the
// top metrics on it down to the bottom using GetFirstChild and not worry
// about walking onto another underlying layer.
for (LayerMetricsWrapper i(aContainer); i; i = i.GetFirstChild()) {
if (sampler->HasUnusedAsyncTransform(i)) {
aManager->UnusedApzTransformWarning();
break;
}
}
}
}
ContainerLayerComposite::ContainerLayerComposite(
LayerManagerComposite* aManager)
: ContainerLayer(aManager, nullptr), LayerComposite(aManager) {
MOZ_COUNT_CTOR(ContainerLayerComposite);
mImplData = static_cast<LayerComposite*>(this);
}
ContainerLayerComposite::~ContainerLayerComposite() {
MOZ_COUNT_DTOR(ContainerLayerComposite);
// We don't Destroy() on destruction here because this destructor
// can be called after remote content has crashed, and it may not be
// safe to free the IPC resources of our children. Those resources
// are automatically cleaned up by IPDL-generated code.
//
// In the common case of normal shutdown, either
// LayerManagerComposite::Destroy(), a parent
// *ContainerLayerComposite::Destroy(), or Disconnect() will trigger
// cleanup of our resources.
RemoveAllChildren();
}
void ContainerLayerComposite::Destroy() {
if (!mDestroyed) {
while (mFirstChild) {
GetFirstChildComposite()->Destroy();
RemoveChild(mFirstChild);
}
mDestroyed = true;
}
}
LayerComposite* ContainerLayerComposite::GetFirstChildComposite() {
if (!mFirstChild) {
return nullptr;
}
return static_cast<LayerComposite*>(mFirstChild->AsHostLayer());
}
void ContainerLayerComposite::Cleanup() {
mPrepared = nullptr;
for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
static_cast<LayerComposite*>(l->AsHostLayer())->Cleanup();
}
}
void ContainerLayerComposite::RenderLayer(
const gfx::IntRect& aClipRect, const Maybe<gfx::Polygon>& aGeometry) {
ContainerRender(this, mCompositeManager, aClipRect, aGeometry);
}
void ContainerLayerComposite::Prepare(const RenderTargetIntRect& aClipRect) {
ContainerPrepare(this, mCompositeManager, aClipRect);
}
void ContainerLayerComposite::CleanupResources() {
mLastIntermediateSurface = nullptr;
mPrepared = nullptr;
for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
static_cast<LayerComposite*>(l->AsHostLayer())->CleanupResources();
}
}
const LayerIntRegion& ContainerLayerComposite::GetShadowVisibleRegion() {
if (!UseIntermediateSurface()) {
RecomputeShadowVisibleRegionFromChildren();
}
return mShadowVisibleRegion;
}
const LayerIntRegion& RefLayerComposite::GetShadowVisibleRegion() {
if (!UseIntermediateSurface()) {
RecomputeShadowVisibleRegionFromChildren();
}
return mShadowVisibleRegion;
}
RefLayerComposite::RefLayerComposite(LayerManagerComposite* aManager)
: RefLayer(aManager, nullptr), LayerComposite(aManager) {
mImplData = static_cast<LayerComposite*>(this);
}
RefLayerComposite::~RefLayerComposite() { Destroy(); }
void RefLayerComposite::Destroy() {
MOZ_ASSERT(!mFirstChild);
mDestroyed = true;
}
LayerComposite* RefLayerComposite::GetFirstChildComposite() {
if (!mFirstChild) {
return nullptr;
}
return static_cast<LayerComposite*>(mFirstChild->AsHostLayer());
}
void RefLayerComposite::RenderLayer(const gfx::IntRect& aClipRect,
const Maybe<gfx::Polygon>& aGeometry) {
ContainerRender(this, mCompositeManager, aClipRect, aGeometry);
}
void RefLayerComposite::Prepare(const RenderTargetIntRect& aClipRect) {
ContainerPrepare(this, mCompositeManager, aClipRect);
}
void RefLayerComposite::Cleanup() {
mPrepared = nullptr;
for (Layer* l = GetFirstChild(); l; l = l->GetNextSibling()) {
static_cast<LayerComposite*>(l->AsHostLayer())->Cleanup();
}
}
void RefLayerComposite::CleanupResources() {
mLastIntermediateSurface = nullptr;
mPrepared = nullptr;
}
} // namespace layers
} // namespace mozilla