forked from mirrors/gecko-dev
		
	 808163871b
			
		
	
	
		808163871b
		
	
	
	
	
		
			
			This patch was generated using a simple sed script: sed -i 's/ToUnknownRegion().GetBounds()/GetBounds().ToUnknownRect()/g' gfx/**/*.cpp gfx/**/*.h Differential Revision: https://phabricator.services.mozilla.com/D3875 --HG-- extra : rebase_source : 4e9e7c9f2fb4ca60122712dd06632147cdec7195
		
			
				
	
	
		
			634 lines
		
	
	
	
		
			25 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			634 lines
		
	
	
	
		
			25 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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 "ClientTiledPaintedLayer.h"
 | |
| #include "FrameMetrics.h"               // for FrameMetrics
 | |
| #include "Units.h"                      // for ScreenIntRect, CSSPoint, etc
 | |
| #include "UnitTransforms.h"             // for TransformTo
 | |
| #include "ClientLayerManager.h"         // for ClientLayerManager, etc
 | |
| #include "gfxPlatform.h"                // for gfxPlatform
 | |
| #include "gfxPrefs.h"                   // for gfxPrefs
 | |
| #include "gfxRect.h"                    // for gfxRect
 | |
| #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 | |
| #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 | |
| #include "mozilla/gfx/gfxVars.h"
 | |
| #include "mozilla/gfx/Rect.h"           // for Rect, RectTyped
 | |
| #include "mozilla/layers/CompositorBridgeChild.h"
 | |
| #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
 | |
| #include "mozilla/layers/LayersMessages.h"
 | |
| #include "mozilla/layers/PaintThread.h"
 | |
| #include "mozilla/mozalloc.h"           // for operator delete, etc
 | |
| #include "nsISupportsImpl.h"            // for MOZ_COUNT_CTOR, etc
 | |
| #include "LayersLogging.h"
 | |
| #include "mozilla/layers/MultiTiledContentClient.h"
 | |
| #include "mozilla/layers/SingleTiledContentClient.h"
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace layers {
 | |
| 
 | |
| using gfx::Rect;
 | |
| using gfx::IntRect;
 | |
| using gfx::IntSize;
 | |
| 
 | |
| ClientTiledPaintedLayer::ClientTiledPaintedLayer(ClientLayerManager* const aManager,
 | |
|                                                ClientLayerManager::PaintedLayerCreationHint aCreationHint)
 | |
|   : PaintedLayer(aManager, static_cast<ClientLayer*>(this), aCreationHint)
 | |
|   , mContentClient()
 | |
|   , mHaveSingleTiledContentClient(false)
 | |
| {
 | |
|   MOZ_COUNT_CTOR(ClientTiledPaintedLayer);
 | |
|   mPaintData.mLastScrollOffset = ParentLayerPoint(0, 0);
 | |
|   mPaintData.mFirstPaint = true;
 | |
| }
 | |
| 
 | |
| ClientTiledPaintedLayer::~ClientTiledPaintedLayer()
 | |
| {
 | |
|   MOZ_COUNT_DTOR(ClientTiledPaintedLayer);
 | |
| }
 | |
| 
 | |
| void
 | |
| ClientTiledPaintedLayer::ClearCachedResources()
 | |
| {
 | |
|   if (mContentClient) {
 | |
|     mContentClient->ClearCachedResources();
 | |
|   }
 | |
|   ClearValidRegion();
 | |
|   mContentClient = nullptr;
 | |
| }
 | |
| 
 | |
| void
 | |
| ClientTiledPaintedLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
 | |
| {
 | |
|   aAttrs = PaintedLayerAttributes(GetValidRegion());
 | |
| }
 | |
| 
 | |
| static Maybe<LayerRect>
 | |
| ApplyParentLayerToLayerTransform(const ParentLayerToLayerMatrix4x4& aTransform,
 | |
|                                  const ParentLayerRect& aParentLayerRect,
 | |
|                                  const LayerRect& aClip)
 | |
| {
 | |
|   return UntransformBy(aTransform, aParentLayerRect, aClip);
 | |
| }
 | |
| 
 | |
| static LayerToParentLayerMatrix4x4
 | |
| GetTransformToAncestorsParentLayer(Layer* aStart, const LayerMetricsWrapper& aAncestor)
 | |
| {
 | |
|   gfx::Matrix4x4 transform;
 | |
|   const LayerMetricsWrapper& ancestorParent = aAncestor.GetParent();
 | |
|   for (LayerMetricsWrapper iter(aStart, LayerMetricsWrapper::StartAt::BOTTOM);
 | |
|        ancestorParent ? iter != ancestorParent : iter.IsValid();
 | |
|        iter = iter.GetParent()) {
 | |
|     transform = transform * iter.GetTransform();
 | |
| 
 | |
|     if (gfxPrefs::LayoutUseContainersForRootFrames()) {
 | |
|       // When scrolling containers, layout adds a post-scale into the transform
 | |
|       // of the displayport-ancestor (which we pick up in GetTransform() above)
 | |
|       // to cancel out the pres shell resolution (for historical reasons). The
 | |
|       // compositor in turn cancels out this post-scale (i.e., scales by the
 | |
|       // pres shell resolution), and to get correct calculations, we need to do
 | |
|       // so here, too.
 | |
|       //
 | |
|       // With containerless scrolling, the offending post-scale is on the
 | |
|       // parent layer of the displayport-ancestor, which we don't reach in this
 | |
|       // loop, so we don't need to worry about it.
 | |
|       float presShellResolution = iter.GetPresShellResolution();
 | |
|       transform.PostScale(presShellResolution, presShellResolution, 1.0f);
 | |
|     }
 | |
|   }
 | |
|   return ViewAs<LayerToParentLayerMatrix4x4>(transform);
 | |
| }
 | |
| 
 | |
| void
 | |
| ClientTiledPaintedLayer::GetAncestorLayers(LayerMetricsWrapper* aOutScrollAncestor,
 | |
|                                            LayerMetricsWrapper* aOutDisplayPortAncestor,
 | |
|                                            bool* aOutHasTransformAnimation)
 | |
| {
 | |
|   LayerMetricsWrapper scrollAncestor;
 | |
|   LayerMetricsWrapper displayPortAncestor;
 | |
|   bool hasTransformAnimation = false;
 | |
|   for (LayerMetricsWrapper ancestor(this, LayerMetricsWrapper::StartAt::BOTTOM); ancestor; ancestor = ancestor.GetParent()) {
 | |
|     hasTransformAnimation |= ancestor.HasTransformAnimation();
 | |
|     const FrameMetrics& metrics = ancestor.Metrics();
 | |
|     if (!scrollAncestor && metrics.GetScrollId() != FrameMetrics::NULL_SCROLL_ID) {
 | |
|       scrollAncestor = ancestor;
 | |
|     }
 | |
|     if (!metrics.GetDisplayPort().IsEmpty()) {
 | |
|       displayPortAncestor = ancestor;
 | |
|       // Any layer that has a displayport must be scrollable, so we can break
 | |
|       // here.
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
|   if (aOutScrollAncestor) {
 | |
|     *aOutScrollAncestor = scrollAncestor;
 | |
|   }
 | |
|   if (aOutDisplayPortAncestor) {
 | |
|     *aOutDisplayPortAncestor = displayPortAncestor;
 | |
|   }
 | |
|   if (aOutHasTransformAnimation) {
 | |
|     *aOutHasTransformAnimation = hasTransformAnimation;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| ClientTiledPaintedLayer::BeginPaint()
 | |
| {
 | |
|   mPaintData.ResetPaintData();
 | |
| 
 | |
|   if (!GetBaseTransform().Is2D()) {
 | |
|     // Give up if there is a complex CSS transform on the layer. We might
 | |
|     // eventually support these but for now it's too complicated to handle
 | |
|     // given that it's a pretty rare scenario.
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // Get the metrics of the nearest scrollable layer and the nearest layer
 | |
|   // with a displayport.
 | |
|   LayerMetricsWrapper scrollAncestor;
 | |
|   LayerMetricsWrapper displayPortAncestor;
 | |
|   bool hasTransformAnimation;
 | |
|   GetAncestorLayers(&scrollAncestor, &displayPortAncestor, &hasTransformAnimation);
 | |
| 
 | |
|   if (!displayPortAncestor || !scrollAncestor) {
 | |
|     // No displayport or scroll ancestor, so we can't do progressive rendering.
 | |
| #if defined(MOZ_WIDGET_ANDROID)
 | |
|     // Android are guaranteed to have a displayport set, so this
 | |
|     // should never happen.
 | |
|     NS_WARNING("Tiled PaintedLayer with no scrollable container ancestor");
 | |
| #endif
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   TILING_LOG("TILING %p: Found scrollAncestor %p, displayPortAncestor %p, transform %d\n", this,
 | |
|     scrollAncestor.GetLayer(), displayPortAncestor.GetLayer(), hasTransformAnimation);
 | |
| 
 | |
|   const FrameMetrics& scrollMetrics = scrollAncestor.Metrics();
 | |
|   const FrameMetrics& displayportMetrics = displayPortAncestor.Metrics();
 | |
| 
 | |
|   // Calculate the transform required to convert ParentLayer space of our
 | |
|   // display port ancestor to the Layer space of this layer.
 | |
|   ParentLayerToLayerMatrix4x4 transformDisplayPortToLayer =
 | |
|     GetTransformToAncestorsParentLayer(this, displayPortAncestor).Inverse();
 | |
| 
 | |
|   LayerRect layerBounds(GetVisibleRegion().GetBounds());
 | |
| 
 | |
|   // Compute the critical display port that applies to this layer in the
 | |
|   // LayoutDevice space of this layer, but only if there is no OMT animation
 | |
|   // on this layer. If there is an OMT animation then we need to draw the whole
 | |
|   // visible region of this layer as determined by layout, because we don't know
 | |
|   // what parts of it might move into view in the compositor.
 | |
|   mPaintData.mHasTransformAnimation = hasTransformAnimation;
 | |
|   if (!mPaintData.mHasTransformAnimation &&
 | |
|       mContentClient->GetLowPrecisionTiledBuffer()) {
 | |
|     ParentLayerRect criticalDisplayPort =
 | |
|       (displayportMetrics.GetCriticalDisplayPort() * displayportMetrics.GetZoom())
 | |
|       + displayportMetrics.GetCompositionBounds().TopLeft();
 | |
|     Maybe<LayerRect> criticalDisplayPortTransformed =
 | |
|       ApplyParentLayerToLayerTransform(transformDisplayPortToLayer, criticalDisplayPort, layerBounds);
 | |
|     if (criticalDisplayPortTransformed) {
 | |
|       mPaintData.mCriticalDisplayPort = Some(RoundedToInt(*criticalDisplayPortTransformed));
 | |
|     } else {
 | |
|       mPaintData.mCriticalDisplayPort = Some(LayerIntRect(0, 0, 0, 0));
 | |
|     }
 | |
|   }
 | |
|   TILING_LOG("TILING %p: Critical displayport %s\n", this,
 | |
|              mPaintData.mCriticalDisplayPort ?
 | |
|              Stringify(*mPaintData.mCriticalDisplayPort).c_str() : "not set");
 | |
| 
 | |
|   // Store the resolution from the displayport ancestor layer. Because this is Gecko-side,
 | |
|   // before any async transforms have occurred, we can use the zoom for this.
 | |
|   mPaintData.mResolution = displayportMetrics.GetZoom();
 | |
|   TILING_LOG("TILING %p: Resolution %s\n", this, Stringify(mPaintData.mResolution).c_str());
 | |
| 
 | |
|   // Store the applicable composition bounds in this layer's Layer units.
 | |
|   mPaintData.mTransformToCompBounds =
 | |
|     GetTransformToAncestorsParentLayer(this, scrollAncestor);
 | |
|   ParentLayerToLayerMatrix4x4 transformToBounds = mPaintData.mTransformToCompBounds.Inverse();
 | |
|   Maybe<LayerRect> compositionBoundsTransformed = ApplyParentLayerToLayerTransform(
 | |
|     transformToBounds, scrollMetrics.GetCompositionBounds(), layerBounds);
 | |
|   if (compositionBoundsTransformed) {
 | |
|     mPaintData.mCompositionBounds = *compositionBoundsTransformed;
 | |
|   } else {
 | |
|     mPaintData.mCompositionBounds.SetEmpty();
 | |
|   }
 | |
|   TILING_LOG("TILING %p: Composition bounds %s\n", this, Stringify(mPaintData.mCompositionBounds).c_str());
 | |
| 
 | |
|   // Calculate the scroll offset since the last transaction
 | |
|   mPaintData.mScrollOffset = displayportMetrics.GetScrollOffset() * displayportMetrics.GetZoom();
 | |
|   TILING_LOG("TILING %p: Scroll offset %s\n", this, Stringify(mPaintData.mScrollOffset).c_str());
 | |
| }
 | |
| 
 | |
| bool
 | |
| ClientTiledPaintedLayer::IsScrollingOnCompositor(const FrameMetrics& aParentMetrics)
 | |
| {
 | |
|   CompositorBridgeChild* compositor = nullptr;
 | |
|   if (Manager() && Manager()->AsClientLayerManager()) {
 | |
|     compositor = Manager()->AsClientLayerManager()->GetCompositorBridgeChild();
 | |
|   }
 | |
| 
 | |
|   if (!compositor) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   FrameMetrics compositorMetrics;
 | |
|   if (!compositor->LookupCompositorFrameMetrics(aParentMetrics.GetScrollId(),
 | |
|                                                 compositorMetrics)) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   // 1 is a tad high for a fuzzy equals epsilon however if our scroll delta
 | |
|   // is so small then we have nothing to gain from using paint heuristics.
 | |
|   float COORDINATE_EPSILON = 1.f;
 | |
| 
 | |
|   return !FuzzyEqualsAdditive(compositorMetrics.GetScrollOffset().x,
 | |
|                               aParentMetrics.GetScrollOffset().x,
 | |
|                               COORDINATE_EPSILON) ||
 | |
|          !FuzzyEqualsAdditive(compositorMetrics.GetScrollOffset().y,
 | |
|                               aParentMetrics.GetScrollOffset().y,
 | |
|                               COORDINATE_EPSILON);
 | |
| }
 | |
| 
 | |
| bool
 | |
| ClientTiledPaintedLayer::UseProgressiveDraw() {
 | |
|   if (!gfxPrefs::ProgressivePaint()) {
 | |
|     // pref is disabled, so never do progressive
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (!mContentClient->GetTiledBuffer()->SupportsProgressiveUpdate()) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (ClientManager()->HasShadowTarget()) {
 | |
|     // This condition is true when we are in a reftest scenario. We don't want
 | |
|     // to draw progressively here because it can cause intermittent reftest
 | |
|     // failures because the harness won't wait for all the tiles to be drawn.
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (GetIsFixedPosition() || GetParent()->GetIsFixedPosition()) {
 | |
|     // This layer is fixed-position and so even if it does have a scrolling
 | |
|     // ancestor it will likely be entirely on-screen all the time, so we
 | |
|     // should draw it all at once
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (mPaintData.mHasTransformAnimation) {
 | |
|     // The compositor is going to animate this somehow, so we want it all
 | |
|     // on the screen at once.
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (ClientManager()->AsyncPanZoomEnabled()) {
 | |
|     LayerMetricsWrapper scrollAncestor;
 | |
|     GetAncestorLayers(&scrollAncestor, nullptr, nullptr);
 | |
|     MOZ_ASSERT(scrollAncestor); // because mPaintData.mCriticalDisplayPort is set
 | |
|     if (!scrollAncestor) {
 | |
|       return false;
 | |
|     }
 | |
|     const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
 | |
|     if (!IsScrollingOnCompositor(parentMetrics)) {
 | |
|       return false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool
 | |
| ClientTiledPaintedLayer::RenderHighPrecision(const nsIntRegion& aInvalidRegion,
 | |
|                                             const nsIntRegion& aVisibleRegion,
 | |
|                                             LayerManager::DrawPaintedLayerCallback aCallback,
 | |
|                                             void* aCallbackData)
 | |
| {
 | |
|   // If we have started drawing low-precision already, then we
 | |
|   // shouldn't do anything there.
 | |
|   if (mPaintData.mLowPrecisionPaintCount != 0) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   // Only draw progressively when there is something to paint and the
 | |
|   // resolution is unchanged
 | |
|   if (!aInvalidRegion.IsEmpty() &&
 | |
|       UseProgressiveDraw() &&
 | |
|       mContentClient->GetTiledBuffer()->GetFrameResolution() == mPaintData.mResolution) {
 | |
|     // Store the old valid region, then clear it before painting.
 | |
|     // We clip the old valid region to the visible region, as it only gets
 | |
|     // used to decide stale content (currently valid and previously visible)
 | |
|     nsIntRegion oldValidRegion = mContentClient->GetTiledBuffer()->GetValidRegion();
 | |
|     oldValidRegion.And(oldValidRegion, aVisibleRegion);
 | |
|     if (mPaintData.mCriticalDisplayPort) {
 | |
|       oldValidRegion.And(oldValidRegion, mPaintData.mCriticalDisplayPort->ToUnknownRect());
 | |
|     }
 | |
| 
 | |
|     TILING_LOG("TILING %p: Progressive update with old valid region %s\n", this, Stringify(oldValidRegion).c_str());
 | |
| 
 | |
|     nsIntRegion drawnRegion;
 | |
|     bool updatedBuffer =
 | |
|       mContentClient->GetTiledBuffer()->ProgressiveUpdate(GetValidRegion(), aInvalidRegion,
 | |
|                       oldValidRegion, drawnRegion, &mPaintData, aCallback, aCallbackData);
 | |
|     AddToValidRegion(drawnRegion);
 | |
|     return updatedBuffer;
 | |
|   }
 | |
| 
 | |
|   // Otherwise do a non-progressive paint. We must do this even when
 | |
|   // the region to paint is empty as the valid region may have shrunk.
 | |
| 
 | |
|   nsIntRegion validRegion = aVisibleRegion;
 | |
|   if (mPaintData.mCriticalDisplayPort) {
 | |
|     validRegion.AndWith(mPaintData.mCriticalDisplayPort->ToUnknownRect());
 | |
|   }
 | |
|   SetValidRegion(validRegion);
 | |
| 
 | |
|   TILING_LOG("TILING %p: Non-progressive paint invalid region %s\n", this, Stringify(aInvalidRegion).c_str());
 | |
|   TILING_LOG("TILING %p: Non-progressive paint new valid region %s\n", this, Stringify(GetValidRegion()).c_str());
 | |
| 
 | |
|   TilePaintFlags flags = PaintThread::Get()
 | |
|     ? TilePaintFlags::Async
 | |
|     : TilePaintFlags::None;
 | |
| 
 | |
|   mContentClient->GetTiledBuffer()->SetFrameResolution(mPaintData.mResolution);
 | |
|   mContentClient->GetTiledBuffer()->PaintThebes(GetValidRegion(), aInvalidRegion, aInvalidRegion,
 | |
|                                                 aCallback, aCallbackData, flags);
 | |
|   mPaintData.mPaintFinished = true;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool
 | |
| ClientTiledPaintedLayer::RenderLowPrecision(const nsIntRegion& aInvalidRegion,
 | |
|                                            const nsIntRegion& aVisibleRegion,
 | |
|                                            LayerManager::DrawPaintedLayerCallback aCallback,
 | |
|                                            void* aCallbackData)
 | |
| {
 | |
|   nsIntRegion invalidRegion = aInvalidRegion;
 | |
| 
 | |
|   // Render the low precision buffer, if the visible region is larger than the
 | |
|   // critical display port.
 | |
|   if (!mPaintData.mCriticalDisplayPort ||
 | |
|       !nsIntRegion(mPaintData.mCriticalDisplayPort->ToUnknownRect()).Contains(aVisibleRegion)) {
 | |
|     nsIntRegion oldValidRegion = mContentClient->GetLowPrecisionTiledBuffer()->GetValidRegion();
 | |
|     oldValidRegion.And(oldValidRegion, aVisibleRegion);
 | |
| 
 | |
|     bool updatedBuffer = false;
 | |
| 
 | |
|     // If the frame resolution or format have changed, invalidate the buffer
 | |
|     if (mContentClient->GetLowPrecisionTiledBuffer()->GetFrameResolution() != mPaintData.mResolution ||
 | |
|         mContentClient->GetLowPrecisionTiledBuffer()->HasFormatChanged()) {
 | |
|       if (!mLowPrecisionValidRegion.IsEmpty()) {
 | |
|         updatedBuffer = true;
 | |
|       }
 | |
|       oldValidRegion.SetEmpty();
 | |
|       mLowPrecisionValidRegion.SetEmpty();
 | |
|       mContentClient->GetLowPrecisionTiledBuffer()->ResetPaintedAndValidState();
 | |
|       mContentClient->GetLowPrecisionTiledBuffer()->SetFrameResolution(mPaintData.mResolution);
 | |
|       invalidRegion = aVisibleRegion;
 | |
|     }
 | |
| 
 | |
|     // Invalidate previously valid content that is no longer visible
 | |
|     if (mPaintData.mLowPrecisionPaintCount == 1) {
 | |
|       mLowPrecisionValidRegion.And(mLowPrecisionValidRegion, aVisibleRegion);
 | |
|     }
 | |
|     mPaintData.mLowPrecisionPaintCount++;
 | |
| 
 | |
|     // Remove the valid high-precision region from the invalid low-precision
 | |
|     // region. We don't want to spend time drawing things twice.
 | |
|     invalidRegion.SubOut(GetValidRegion());
 | |
| 
 | |
|     TILING_LOG("TILING %p: Progressive paint: low-precision invalid region is %s\n", this, Stringify(invalidRegion).c_str());
 | |
|     TILING_LOG("TILING %p: Progressive paint: low-precision old valid region is %s\n", this, Stringify(oldValidRegion).c_str());
 | |
| 
 | |
|     if (!invalidRegion.IsEmpty()) {
 | |
|       nsIntRegion drawnRegion;
 | |
|       updatedBuffer = mContentClient->GetLowPrecisionTiledBuffer()->ProgressiveUpdate(
 | |
|                             mLowPrecisionValidRegion, invalidRegion, oldValidRegion,
 | |
|                             drawnRegion, &mPaintData, aCallback, aCallbackData);
 | |
|       mLowPrecisionValidRegion.OrWith(drawnRegion);
 | |
|     }
 | |
| 
 | |
|     TILING_LOG("TILING %p: Progressive paint: low-precision new valid region is %s\n", this, Stringify(mLowPrecisionValidRegion).c_str());
 | |
|     return updatedBuffer;
 | |
|   }
 | |
|   if (!mLowPrecisionValidRegion.IsEmpty()) {
 | |
|     TILING_LOG("TILING %p: Clearing low-precision buffer\n", this);
 | |
|     // Clear the low precision tiled buffer.
 | |
|     mLowPrecisionValidRegion.SetEmpty();
 | |
|     mContentClient->GetLowPrecisionTiledBuffer()->ResetPaintedAndValidState();
 | |
|     // Return true here so we send a Painted callback after clearing the valid
 | |
|     // region of the low precision buffer. This allows the shadow buffer's valid
 | |
|     // region to be updated and the associated resources to be freed.
 | |
|     return true;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| void
 | |
| ClientTiledPaintedLayer::EndPaint()
 | |
| {
 | |
|   mPaintData.mLastScrollOffset = mPaintData.mScrollOffset;
 | |
|   mPaintData.mPaintFinished = true;
 | |
|   mPaintData.mFirstPaint = false;
 | |
|   TILING_LOG("TILING %p: Paint finished\n", this);
 | |
| }
 | |
| 
 | |
| void
 | |
| ClientTiledPaintedLayer::RenderLayer()
 | |
| {
 | |
|   LayerManager::DrawPaintedLayerCallback callback =
 | |
|     ClientManager()->GetPaintedLayerCallback();
 | |
|   void *data = ClientManager()->GetPaintedLayerCallbackData();
 | |
| 
 | |
|   IntSize layerSize = mVisibleRegion.GetBounds().ToUnknownRect().Size();
 | |
|   IntSize tileSize = gfx::gfxVars::TileSize();
 | |
|   bool isHalfTileWidthOrHeight = layerSize.width <= tileSize.width / 2 ||
 | |
|     layerSize.height <= tileSize.height / 2;
 | |
| 
 | |
|   // Use single tile when layer is not scrollable, is smaller than one
 | |
|   // tile, or when more than half of the tiles' pixels in either
 | |
|   // dimension would be wasted.
 | |
|   bool wantSingleTiledContentClient =
 | |
|       (mCreationHint == LayerManager::NONE ||
 | |
|        layerSize <= tileSize ||
 | |
|        isHalfTileWidthOrHeight) &&
 | |
|       SingleTiledContentClient::ClientSupportsLayerSize(layerSize, ClientManager()) &&
 | |
|       gfxPrefs::LayersSingleTileEnabled();
 | |
| 
 | |
|   if (mContentClient && mHaveSingleTiledContentClient && !wantSingleTiledContentClient) {
 | |
|     mContentClient = nullptr;
 | |
|     ClearValidRegion();
 | |
|   }
 | |
| 
 | |
|   if (!mContentClient) {
 | |
|     if (wantSingleTiledContentClient) {
 | |
|       mContentClient = new SingleTiledContentClient(*this, ClientManager());
 | |
|       mHaveSingleTiledContentClient = true;
 | |
|     } else {
 | |
|       mContentClient = new MultiTiledContentClient(*this, ClientManager());
 | |
|       mHaveSingleTiledContentClient = false;
 | |
|     }
 | |
| 
 | |
|     mContentClient->Connect();
 | |
|     ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
 | |
|     MOZ_ASSERT(mContentClient->GetForwarder());
 | |
|   }
 | |
| 
 | |
|   if (mContentClient->GetTiledBuffer()->HasFormatChanged()) {
 | |
|     ClearValidRegion();
 | |
|     mContentClient->GetTiledBuffer()->ResetPaintedAndValidState();
 | |
|   }
 | |
| 
 | |
|   TILING_LOG("TILING %p: Initial visible region %s\n", this, Stringify(mVisibleRegion).c_str());
 | |
|   TILING_LOG("TILING %p: Initial valid region %s\n", this, Stringify(GetValidRegion()).c_str());
 | |
|   TILING_LOG("TILING %p: Initial low-precision valid region %s\n", this, Stringify(mLowPrecisionValidRegion).c_str());
 | |
| 
 | |
|   nsIntRegion neededRegion = mVisibleRegion.ToUnknownRegion();
 | |
| #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
 | |
|   // This is handled by PadDrawTargetOutFromRegion in TiledContentClient for mobile
 | |
|   if (MayResample()) {
 | |
|     // If we're resampling then bilinear filtering can read up to 1 pixel
 | |
|     // outside of our texture coords. Make the visible region a single rect,
 | |
|     // and pad it out by 1 pixel (restricted to tile boundaries) so that
 | |
|     // we always have valid content or transparent pixels to sample from.
 | |
|     IntRect bounds = neededRegion.GetBounds();
 | |
|     IntRect wholeTiles = bounds;
 | |
|     wholeTiles.InflateToMultiple(gfx::gfxVars::TileSize());
 | |
|     IntRect padded = bounds;
 | |
|     padded.Inflate(1);
 | |
|     padded.IntersectRect(padded, wholeTiles);
 | |
|     neededRegion = padded;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   nsIntRegion invalidRegion;
 | |
|   invalidRegion.Sub(neededRegion, GetValidRegion());
 | |
|   if (invalidRegion.IsEmpty()) {
 | |
|     EndPaint();
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!callback) {
 | |
|     ClientManager()->SetTransactionIncomplete();
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!ClientManager()->IsRepeatTransaction()) {
 | |
|     // Only paint the mask layers on the first transaction.
 | |
|     RenderMaskLayers(this);
 | |
| 
 | |
|     // For more complex cases we need to calculate a bunch of metrics before we
 | |
|     // can do the paint.
 | |
|     BeginPaint();
 | |
|     if (mPaintData.mPaintFinished) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // Make sure that tiles that fall outside of the visible region or outside of the
 | |
|     // critical displayport are discarded on the first update. Also make sure that we
 | |
|     // only draw stuff inside the critical displayport on the first update.
 | |
|     nsIntRegion validRegion;
 | |
|     validRegion.And(GetValidRegion(), neededRegion);
 | |
|     if (mPaintData.mCriticalDisplayPort) {
 | |
|       validRegion.AndWith(mPaintData.mCriticalDisplayPort->ToUnknownRect());
 | |
|       invalidRegion.And(invalidRegion, mPaintData.mCriticalDisplayPort->ToUnknownRect());
 | |
|     }
 | |
|     SetValidRegion(validRegion);
 | |
| 
 | |
|     TILING_LOG("TILING %p: First-transaction valid region %s\n", this, Stringify(validRegion).c_str());
 | |
|     TILING_LOG("TILING %p: First-transaction invalid region %s\n", this, Stringify(invalidRegion).c_str());
 | |
|   } else {
 | |
|     if (mPaintData.mCriticalDisplayPort) {
 | |
|       invalidRegion.And(invalidRegion, mPaintData.mCriticalDisplayPort->ToUnknownRect());
 | |
|     }
 | |
|     TILING_LOG("TILING %p: Repeat-transaction invalid region %s\n", this, Stringify(invalidRegion).c_str());
 | |
|   }
 | |
| 
 | |
|   nsIntRegion lowPrecisionInvalidRegion;
 | |
|   if (mContentClient->GetLowPrecisionTiledBuffer()) {
 | |
|     // Calculate the invalid region for the low precision buffer. Make sure
 | |
|     // to remove the valid high-precision area so we don't double-paint it.
 | |
|     lowPrecisionInvalidRegion.Sub(neededRegion, mLowPrecisionValidRegion);
 | |
|     lowPrecisionInvalidRegion.Sub(lowPrecisionInvalidRegion, GetValidRegion());
 | |
|   }
 | |
|   TILING_LOG("TILING %p: Low-precision invalid region %s\n", this, Stringify(lowPrecisionInvalidRegion).c_str());
 | |
| 
 | |
|   bool updatedHighPrecision = RenderHighPrecision(invalidRegion,
 | |
|                                                   neededRegion,
 | |
|                                                   callback, data);
 | |
|   if (updatedHighPrecision) {
 | |
|     ClientManager()->Hold(this);
 | |
|     mContentClient->UpdatedBuffer(TiledContentClient::TILED_BUFFER);
 | |
| 
 | |
|     if (!mPaintData.mPaintFinished) {
 | |
|       // There is still more high-res stuff to paint, so we're not
 | |
|       // done yet. A subsequent transaction will take care of this.
 | |
|       ClientManager()->SetRepeatTransaction();
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // If there is nothing to draw in low-precision, then we're done.
 | |
|   if (lowPrecisionInvalidRegion.IsEmpty()) {
 | |
|     EndPaint();
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (updatedHighPrecision) {
 | |
|     // If there are low precision updates, but we just did some high-precision
 | |
|     // updates, then mark the paint as unfinished and request a repeat transaction.
 | |
|     // This is so that we don't perform low-precision updates in the same transaction
 | |
|     // as high-precision updates.
 | |
|     TILING_LOG("TILING %p: Scheduling repeat transaction for low-precision painting\n", this);
 | |
|     ClientManager()->SetRepeatTransaction();
 | |
|     mPaintData.mLowPrecisionPaintCount = 1;
 | |
|     mPaintData.mPaintFinished = false;
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   bool updatedLowPrecision = RenderLowPrecision(lowPrecisionInvalidRegion,
 | |
|                                                 neededRegion,
 | |
|                                                 callback, data);
 | |
|   if (updatedLowPrecision) {
 | |
|     ClientManager()->Hold(this);
 | |
|     mContentClient->UpdatedBuffer(TiledContentClient::LOW_PRECISION_TILED_BUFFER);
 | |
| 
 | |
|     if (!mPaintData.mPaintFinished) {
 | |
|       // There is still more low-res stuff to paint, so we're not
 | |
|       // done yet. A subsequent transaction will take care of this.
 | |
|       ClientManager()->SetRepeatTransaction();
 | |
|       return;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // If we get here, we've done all the high- and low-precision
 | |
|   // paints we wanted to do, so we can finish the paint and chill.
 | |
|   EndPaint();
 | |
| }
 | |
| 
 | |
| bool
 | |
| ClientTiledPaintedLayer::IsOptimizedFor(LayerManager::PaintedLayerCreationHint aHint)
 | |
| {
 | |
|   // The only creation hint is whether the layer is scrollable or not, and this
 | |
|   // is only respected on OSX, where it's used to determine whether to
 | |
|   // use a tiled content client or not.
 | |
|   // There are pretty nasty performance consequences for not using tiles on
 | |
|   // large, scrollable layers, so we want the layer to be recreated in this
 | |
|   // situation.
 | |
|   return aHint == GetCreationHint();
 | |
| }
 | |
| 
 | |
| void
 | |
| ClientTiledPaintedLayer::PrintInfo(std::stringstream& aStream, const char* aPrefix)
 | |
| {
 | |
|   PaintedLayer::PrintInfo(aStream, aPrefix);
 | |
|   if (mContentClient) {
 | |
|     aStream << "\n";
 | |
|     nsAutoCString pfx(aPrefix);
 | |
|     pfx += "  ";
 | |
|     mContentClient->PrintInfo(aStream, pfx.get());
 | |
|   }
 | |
| }
 | |
| 
 | |
| } // namespace layers
 | |
| } // namespace mozilla
 |