Bug 1039883 - release Tiled layer's gralloc when an application is background r=nical
[gecko.git] / gfx / layers / client / ClientTiledThebesLayer.cpp
blob7f5c7c8cfa09fb8fc92b9a0e39b59b3d3e842681
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "ClientTiledThebesLayer.h"
6 #include "FrameMetrics.h" // for FrameMetrics
7 #include "Units.h" // for ScreenIntRect, CSSPoint, etc
8 #include "UnitTransforms.h" // for TransformTo
9 #include "ClientLayerManager.h" // for ClientLayerManager, etc
10 #include "gfx3DMatrix.h" // for gfx3DMatrix
11 #include "gfxPlatform.h" // for gfxPlatform
12 #include "gfxPrefs.h" // for gfxPrefs
13 #include "gfxRect.h" // for gfxRect
14 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
15 #include "mozilla/gfx/BaseSize.h" // for BaseSize
16 #include "mozilla/gfx/Rect.h" // for Rect, RectTyped
17 #include "mozilla/layers/LayersMessages.h"
18 #include "mozilla/mozalloc.h" // for operator delete, etc
19 #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
20 #include "nsRect.h" // for nsIntRect
21 #include "LayersLogging.h"
23 namespace mozilla {
24 namespace layers {
27 ClientTiledThebesLayer::ClientTiledThebesLayer(ClientLayerManager* const aManager,
28 ClientLayerManager::ThebesLayerCreationHint aCreationHint)
29 : ThebesLayer(aManager,
30 static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()),
31 aCreationHint)
32 , mContentClient()
34 MOZ_COUNT_CTOR(ClientTiledThebesLayer);
35 mPaintData.mLastScrollOffset = ParentLayerPoint(0, 0);
36 mPaintData.mFirstPaint = true;
39 ClientTiledThebesLayer::~ClientTiledThebesLayer()
41 MOZ_COUNT_DTOR(ClientTiledThebesLayer);
44 void
45 ClientTiledThebesLayer::ClearCachedResources()
47 if (mContentClient) {
48 mContentClient->ClearCachedResources();
50 mValidRegion.SetEmpty();
53 void
54 ClientTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
56 aAttrs = ThebesLayerAttributes(GetValidRegion());
59 static LayerRect
60 ApplyParentLayerToLayerTransform(const gfx3DMatrix& aTransform, const ParentLayerRect& aParentLayerRect)
62 return TransformTo<LayerPixel>(aTransform, aParentLayerRect);
65 static gfx3DMatrix
66 GetTransformToAncestorsParentLayer(Layer* aStart, Layer* aAncestor)
68 gfx::Matrix4x4 transform;
69 Layer* ancestorParent = aAncestor->GetParent();
70 for (Layer* iter = aStart; iter != ancestorParent; iter = iter->GetParent()) {
71 if (iter->AsContainerLayer()) {
72 // If the layer has a non-transient async transform then we need to apply it here
73 // because it will get applied by the APZ in the compositor as well
74 const FrameMetrics& metrics = iter->AsContainerLayer()->GetFrameMetrics();
75 transform = transform * gfx::Matrix4x4().Scale(metrics.mResolution.scale, metrics.mResolution.scale, 1.f);
77 transform = transform * iter->GetTransform();
79 gfx3DMatrix ret;
80 gfx::To3DMatrix(transform, ret);
81 return ret;
84 void
85 ClientTiledThebesLayer::GetAncestorLayers(ContainerLayer** aOutScrollAncestor,
86 ContainerLayer** aOutDisplayPortAncestor)
88 ContainerLayer* scrollAncestor = nullptr;
89 ContainerLayer* displayPortAncestor = nullptr;
90 for (ContainerLayer* ancestor = GetParent(); ancestor; ancestor = ancestor->GetParent()) {
91 const FrameMetrics& metrics = ancestor->GetFrameMetrics();
92 if (!scrollAncestor && metrics.GetScrollId() != FrameMetrics::NULL_SCROLL_ID) {
93 scrollAncestor = ancestor;
95 if (!metrics.mDisplayPort.IsEmpty()) {
96 displayPortAncestor = ancestor;
97 // Any layer that has a displayport must be scrollable, so we can break
98 // here.
99 break;
102 if (aOutScrollAncestor) {
103 *aOutScrollAncestor = scrollAncestor;
105 if (aOutDisplayPortAncestor) {
106 *aOutDisplayPortAncestor = displayPortAncestor;
110 void
111 ClientTiledThebesLayer::BeginPaint()
113 mPaintData.mLowPrecisionPaintCount = 0;
114 mPaintData.mPaintFinished = false;
115 mPaintData.mCompositionBounds.SetEmpty();
116 mPaintData.mCriticalDisplayPort.SetEmpty();
118 if (!GetBaseTransform().Is2D()) {
119 // Give up if there is a complex CSS transform on the layer. We might
120 // eventually support these but for now it's too complicated to handle
121 // given that it's a pretty rare scenario.
122 return;
125 // Get the metrics of the nearest scrollable layer and the nearest layer
126 // with a displayport.
127 ContainerLayer* scrollAncestor = nullptr;
128 ContainerLayer* displayPortAncestor = nullptr;
129 GetAncestorLayers(&scrollAncestor, &displayPortAncestor);
131 if (!displayPortAncestor || !scrollAncestor) {
132 // No displayport or scroll ancestor, so we can't do progressive rendering.
133 #if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_B2G)
134 // Both Android and b2g are guaranteed to have a displayport set, so this
135 // should never happen.
136 NS_WARNING("Tiled Thebes layer with no scrollable container ancestor");
137 #endif
138 return;
141 TILING_LOG("TILING %p: Found scrollAncestor %p and displayPortAncestor %p\n", this,
142 scrollAncestor, displayPortAncestor);
144 const FrameMetrics& scrollMetrics = scrollAncestor->GetFrameMetrics();
145 const FrameMetrics& displayportMetrics = displayPortAncestor->GetFrameMetrics();
147 // Calculate the transform required to convert ParentLayer space of our
148 // display port ancestor to the Layer space of this layer.
149 gfx3DMatrix transformDisplayPortToLayer =
150 GetTransformToAncestorsParentLayer(this, displayPortAncestor).Inverse();
152 // Note that below we use GetZoomToParent() in a number of places. Because this
153 // code runs on the client side, the mTransformScale field of the FrameMetrics
154 // will not have been set. This can result in incorrect values being returned
155 // by GetZoomToParent() when we have CSS transforms set on some of these layers.
156 // This code should be audited and updated as part of fixing bug 993525.
158 // Compute the critical display port that applies to this layer in the
159 // LayoutDevice space of this layer.
160 ParentLayerRect criticalDisplayPort =
161 (displayportMetrics.mCriticalDisplayPort * displayportMetrics.GetZoomToParent())
162 + displayportMetrics.mCompositionBounds.TopLeft();
163 mPaintData.mCriticalDisplayPort = RoundedOut(
164 ApplyParentLayerToLayerTransform(transformDisplayPortToLayer, criticalDisplayPort));
165 TILING_LOG("TILING %p: Critical displayport %s\n", this, Stringify(mPaintData.mCriticalDisplayPort).c_str());
167 // Store the resolution from the displayport ancestor layer. Because this is Gecko-side,
168 // before any async transforms have occurred, we can use the zoom for this.
169 mPaintData.mResolution = displayportMetrics.GetZoomToParent();
170 TILING_LOG("TILING %p: Resolution %f\n", this, mPaintData.mResolution.scale);
172 // Store the applicable composition bounds in this layer's Layer units.
173 mPaintData.mTransformToCompBounds =
174 GetTransformToAncestorsParentLayer(this, scrollAncestor);
175 mPaintData.mCompositionBounds = ApplyParentLayerToLayerTransform(
176 mPaintData.mTransformToCompBounds.Inverse(), scrollMetrics.mCompositionBounds);
177 TILING_LOG("TILING %p: Composition bounds %s\n", this, Stringify(mPaintData.mCompositionBounds).c_str());
179 // Calculate the scroll offset since the last transaction
180 mPaintData.mScrollOffset = displayportMetrics.GetScrollOffset() * displayportMetrics.GetZoomToParent();
181 TILING_LOG("TILING %p: Scroll offset %s\n", this, Stringify(mPaintData.mScrollOffset).c_str());
184 bool
185 ClientTiledThebesLayer::UseFastPath()
187 const FrameMetrics& parentMetrics = GetParent()->GetFrameMetrics();
188 bool multipleTransactionsNeeded = gfxPrefs::UseProgressiveTilePainting()
189 || gfxPrefs::UseLowPrecisionBuffer()
190 || !parentMetrics.mCriticalDisplayPort.IsEmpty();
191 bool isFixed = GetIsFixedPosition() || GetParent()->GetIsFixedPosition();
192 return !multipleTransactionsNeeded || isFixed || parentMetrics.mDisplayPort.IsEmpty();
195 bool
196 ClientTiledThebesLayer::RenderHighPrecision(nsIntRegion& aInvalidRegion,
197 LayerManager::DrawThebesLayerCallback aCallback,
198 void* aCallbackData)
200 // If we have no high-precision stuff to draw, or we have started drawing low-precision
201 // already, then we shouldn't do anything there.
202 if (aInvalidRegion.IsEmpty() || mPaintData.mLowPrecisionPaintCount != 0) {
203 return false;
206 // Only draw progressively when the resolution is unchanged, and we're not
207 // in a reftest scenario (that's what the HasShadowManager() check is for).
208 if (gfxPrefs::UseProgressiveTilePainting() &&
209 !ClientManager()->HasShadowTarget() &&
210 mContentClient->mTiledBuffer.GetFrameResolution() == mPaintData.mResolution) {
211 // Store the old valid region, then clear it before painting.
212 // We clip the old valid region to the visible region, as it only gets
213 // used to decide stale content (currently valid and previously visible)
214 nsIntRegion oldValidRegion = mContentClient->mTiledBuffer.GetValidRegion();
215 oldValidRegion.And(oldValidRegion, mVisibleRegion);
216 if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
217 oldValidRegion.And(oldValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
220 TILING_LOG("TILING %p: Progressive update with old valid region %s\n", this, Stringify(oldValidRegion).c_str());
222 return mContentClient->mTiledBuffer.ProgressiveUpdate(mValidRegion, aInvalidRegion,
223 oldValidRegion, &mPaintData, aCallback, aCallbackData);
226 // Otherwise do a non-progressive paint
228 mValidRegion = mVisibleRegion;
229 if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
230 mValidRegion.And(mValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
233 TILING_LOG("TILING %p: Non-progressive paint invalid region %s\n", this, Stringify(aInvalidRegion).c_str());
234 TILING_LOG("TILING %p: Non-progressive paint new valid region %s\n", this, Stringify(mValidRegion).c_str());
236 mContentClient->mTiledBuffer.SetFrameResolution(mPaintData.mResolution);
237 mContentClient->mTiledBuffer.PaintThebes(mValidRegion, aInvalidRegion, aCallback, aCallbackData);
238 return true;
241 bool
242 ClientTiledThebesLayer::RenderLowPrecision(nsIntRegion& aInvalidRegion,
243 LayerManager::DrawThebesLayerCallback aCallback,
244 void* aCallbackData)
246 // Render the low precision buffer, if the visible region is larger than the
247 // critical display port.
248 if (!nsIntRegion(LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort)).Contains(mVisibleRegion)) {
249 nsIntRegion oldValidRegion = mContentClient->mLowPrecisionTiledBuffer.GetValidRegion();
250 oldValidRegion.And(oldValidRegion, mVisibleRegion);
252 bool updatedBuffer = false;
254 // If the frame resolution or format have changed, invalidate the buffer
255 if (mContentClient->mLowPrecisionTiledBuffer.GetFrameResolution() != mPaintData.mResolution ||
256 mContentClient->mLowPrecisionTiledBuffer.HasFormatChanged()) {
257 if (!mLowPrecisionValidRegion.IsEmpty()) {
258 updatedBuffer = true;
260 oldValidRegion.SetEmpty();
261 mLowPrecisionValidRegion.SetEmpty();
262 mContentClient->mLowPrecisionTiledBuffer.SetFrameResolution(mPaintData.mResolution);
263 aInvalidRegion = mVisibleRegion;
266 // Invalidate previously valid content that is no longer visible
267 if (mPaintData.mLowPrecisionPaintCount == 1) {
268 mLowPrecisionValidRegion.And(mLowPrecisionValidRegion, mVisibleRegion);
270 mPaintData.mLowPrecisionPaintCount++;
272 // Remove the valid high-precision region from the invalid low-precision
273 // region. We don't want to spend time drawing things twice.
274 aInvalidRegion.Sub(aInvalidRegion, mValidRegion);
276 TILING_LOG("TILING %p: Progressive paint: low-precision invalid region is %s\n", this, Stringify(aInvalidRegion).c_str());
277 TILING_LOG("TILING %p: Progressive paint: low-precision old valid region is %s\n", this, Stringify(oldValidRegion).c_str());
279 if (!aInvalidRegion.IsEmpty()) {
280 updatedBuffer = mContentClient->mLowPrecisionTiledBuffer.ProgressiveUpdate(
281 mLowPrecisionValidRegion, aInvalidRegion, oldValidRegion,
282 &mPaintData, aCallback, aCallbackData);
285 TILING_LOG("TILING %p: Progressive paint: low-precision new valid region is %s\n", this, Stringify(mLowPrecisionValidRegion).c_str());
286 return updatedBuffer;
288 if (!mLowPrecisionValidRegion.IsEmpty()) {
289 TILING_LOG("TILING %p: Clearing low-precision buffer\n", this);
290 // Clear the low precision tiled buffer.
291 mLowPrecisionValidRegion.SetEmpty();
292 mContentClient->mLowPrecisionTiledBuffer.ResetPaintedAndValidState();
293 // Return true here so we send a Painted callback after clearing the valid
294 // region of the low precision buffer. This allows the shadow buffer's valid
295 // region to be updated and the associated resources to be freed.
296 return true;
298 return false;
301 void
302 ClientTiledThebesLayer::EndPaint()
304 mPaintData.mLastScrollOffset = mPaintData.mScrollOffset;
305 mPaintData.mPaintFinished = true;
306 mPaintData.mFirstPaint = false;
307 TILING_LOG("TILING %p: Paint finished\n", this);
310 void
311 ClientTiledThebesLayer::RenderLayer()
313 LayerManager::DrawThebesLayerCallback callback =
314 ClientManager()->GetThebesLayerCallback();
315 void *data = ClientManager()->GetThebesLayerCallbackData();
316 if (!callback) {
317 ClientManager()->SetTransactionIncomplete();
318 return;
321 if (!mContentClient) {
322 mContentClient = new TiledContentClient(this, ClientManager());
324 mContentClient->Connect();
325 ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
326 MOZ_ASSERT(mContentClient->GetForwarder());
329 if (mContentClient->mTiledBuffer.HasFormatChanged()) {
330 mValidRegion = nsIntRegion();
333 TILING_LOG("TILING %p: Initial visible region %s\n", this, Stringify(mVisibleRegion).c_str());
334 TILING_LOG("TILING %p: Initial valid region %s\n", this, Stringify(mValidRegion).c_str());
335 TILING_LOG("TILING %p: Initial low-precision valid region %s\n", this, Stringify(mLowPrecisionValidRegion).c_str());
337 nsIntRegion invalidRegion;
338 invalidRegion.Sub(mVisibleRegion, mValidRegion);
339 if (invalidRegion.IsEmpty()) {
340 EndPaint();
341 return;
344 if (!ClientManager()->IsRepeatTransaction()) {
345 // Only paint the mask layer on the first transaction.
346 if (GetMaskLayer()) {
347 ToClientLayer(GetMaskLayer())->RenderLayer();
350 // In some cases we can take a fast path and just be done with it.
351 if (UseFastPath()) {
352 TILING_LOG("TILING %p: Taking fast-path\n", this);
353 mValidRegion = mVisibleRegion;
354 mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion, callback, data);
355 ClientManager()->Hold(this);
356 mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER);
357 return;
360 // For more complex cases we need to calculate a bunch of metrics before we
361 // can do the paint.
362 BeginPaint();
363 if (mPaintData.mPaintFinished) {
364 return;
367 // Make sure that tiles that fall outside of the visible region or outside of the
368 // critical displayport are discarded on the first update. Also make sure that we
369 // only draw stuff inside the critical displayport on the first update.
370 mValidRegion.And(mValidRegion, mVisibleRegion);
371 if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
372 mValidRegion.And(mValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
373 invalidRegion.And(invalidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
376 TILING_LOG("TILING %p: First-transaction valid region %s\n", this, Stringify(mValidRegion).c_str());
377 TILING_LOG("TILING %p: First-transaction invalid region %s\n", this, Stringify(invalidRegion).c_str());
378 } else {
379 if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
380 invalidRegion.And(invalidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
382 TILING_LOG("TILING %p: Repeat-transaction invalid region %s\n", this, Stringify(invalidRegion).c_str());
385 nsIntRegion lowPrecisionInvalidRegion;
386 if (gfxPrefs::UseLowPrecisionBuffer()) {
387 // Calculate the invalid region for the low precision buffer. Make sure
388 // to remove the valid high-precision area so we don't double-paint it.
389 lowPrecisionInvalidRegion.Sub(mVisibleRegion, mLowPrecisionValidRegion);
390 lowPrecisionInvalidRegion.Sub(lowPrecisionInvalidRegion, mValidRegion);
392 TILING_LOG("TILING %p: Low-precision invalid region %s\n", this, Stringify(lowPrecisionInvalidRegion).c_str());
394 bool updatedHighPrecision = RenderHighPrecision(invalidRegion, callback, data);
395 if (updatedHighPrecision) {
396 ClientManager()->Hold(this);
397 mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER);
399 if (!mPaintData.mPaintFinished) {
400 // There is still more high-res stuff to paint, so we're not
401 // done yet. A subsequent transaction will take care of this.
402 ClientManager()->SetRepeatTransaction();
403 return;
407 // If there is nothing to draw in low-precision, then we're done.
408 if (lowPrecisionInvalidRegion.IsEmpty()) {
409 EndPaint();
410 return;
413 if (updatedHighPrecision) {
414 // If there are low precision updates, but we just did some high-precision
415 // updates, then mark the paint as unfinished and request a repeat transaction.
416 // This is so that we don't perform low-precision updates in the same transaction
417 // as high-precision updates.
418 TILING_LOG("TILING %p: Scheduling repeat transaction for low-precision painting\n", this);
419 ClientManager()->SetRepeatTransaction();
420 mPaintData.mLowPrecisionPaintCount = 1;
421 mPaintData.mPaintFinished = false;
422 return;
425 bool updatedLowPrecision = RenderLowPrecision(lowPrecisionInvalidRegion, callback, data);
426 if (updatedLowPrecision) {
427 ClientManager()->Hold(this);
428 mContentClient->UseTiledLayerBuffer(TiledContentClient::LOW_PRECISION_TILED_BUFFER);
430 if (!mPaintData.mPaintFinished) {
431 // There is still more low-res stuff to paint, so we're not
432 // done yet. A subsequent transaction will take care of this.
433 ClientManager()->SetRepeatTransaction();
434 return;
438 // If we get here, we've done all the high- and low-precision
439 // paints we wanted to do, so we can finish the paint and chill.
440 EndPaint();
443 } // mozilla
444 } // layers