1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "ClientTiledPaintedLayer.h"
8 #include "FrameMetrics.h" // for FrameMetrics
9 #include "Units.h" // for ScreenIntRect, CSSPoint, etc
10 #include "UnitTransforms.h" // for TransformTo
11 #include "ClientLayerManager.h" // for ClientLayerManager, etc
12 #include "gfxPlatform.h" // for gfxPlatform
13 #include "gfxPrefs.h" // for gfxPrefs
14 #include "gfxRect.h" // for gfxRect
15 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
16 #include "mozilla/gfx/BaseSize.h" // for BaseSize
17 #include "mozilla/gfx/gfxVars.h"
18 #include "mozilla/gfx/Rect.h" // for Rect, RectTyped
19 #include "mozilla/layers/CompositorBridgeChild.h"
20 #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
21 #include "mozilla/layers/LayersMessages.h"
22 #include "mozilla/layers/PaintThread.h"
23 #include "mozilla/mozalloc.h" // for operator delete, etc
24 #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
25 #include "LayersLogging.h"
26 #include "mozilla/layers/SingleTiledContentClient.h"
27
28 namespace mozilla {
29 namespace layers {
30
31 using gfx::IntRect;
32 using gfx::IntSize;
33 using gfx::Rect;
34
ClientTiledPaintedLayer(ClientLayerManager * const aManager,ClientLayerManager::PaintedLayerCreationHint aCreationHint)35 ClientTiledPaintedLayer::ClientTiledPaintedLayer(
36 ClientLayerManager* const aManager,
37 ClientLayerManager::PaintedLayerCreationHint aCreationHint)
38 : PaintedLayer(aManager, static_cast<ClientLayer*>(this), aCreationHint),
39 mContentClient(),
40 mHaveSingleTiledContentClient(false) {
41 MOZ_COUNT_CTOR(ClientTiledPaintedLayer);
42 mPaintData.mLastScrollOffset = ParentLayerPoint(0, 0);
43 mPaintData.mFirstPaint = true;
44 }
45
~ClientTiledPaintedLayer()46 ClientTiledPaintedLayer::~ClientTiledPaintedLayer() {
47 MOZ_COUNT_DTOR(ClientTiledPaintedLayer);
48 }
49
ClearCachedResources()50 void ClientTiledPaintedLayer::ClearCachedResources() {
51 if (mContentClient) {
52 mContentClient->ClearCachedResources();
53 }
54 ClearValidRegion();
55 mContentClient = nullptr;
56 }
57
FillSpecificAttributes(SpecificLayerAttributes & aAttrs)58 void ClientTiledPaintedLayer::FillSpecificAttributes(
59 SpecificLayerAttributes& aAttrs) {
60 aAttrs = PaintedLayerAttributes(GetValidRegion());
61 }
62
ApplyParentLayerToLayerTransform(const ParentLayerToLayerMatrix4x4 & aTransform,const ParentLayerRect & aParentLayerRect,const LayerRect & aClip)63 static Maybe<LayerRect> ApplyParentLayerToLayerTransform(
64 const ParentLayerToLayerMatrix4x4& aTransform,
65 const ParentLayerRect& aParentLayerRect, const LayerRect& aClip) {
66 return UntransformBy(aTransform, aParentLayerRect, aClip);
67 }
68
GetTransformToAncestorsParentLayer(Layer * aStart,const LayerMetricsWrapper & aAncestor)69 static LayerToParentLayerMatrix4x4 GetTransformToAncestorsParentLayer(
70 Layer* aStart, const LayerMetricsWrapper& aAncestor) {
71 gfx::Matrix4x4 transform;
72 const LayerMetricsWrapper& ancestorParent = aAncestor.GetParent();
73 for (LayerMetricsWrapper iter(aStart, LayerMetricsWrapper::StartAt::BOTTOM);
74 ancestorParent ? iter != ancestorParent : iter.IsValid();
75 iter = iter.GetParent()) {
76 transform = transform * iter.GetTransform();
77
78 if (gfxPrefs::LayoutUseContainersForRootFrames()) {
79 // When scrolling containers, layout adds a post-scale into the transform
80 // of the displayport-ancestor (which we pick up in GetTransform() above)
81 // to cancel out the pres shell resolution (for historical reasons). The
82 // compositor in turn cancels out this post-scale (i.e., scales by the
83 // pres shell resolution), and to get correct calculations, we need to do
84 // so here, too.
85 //
86 // With containerless scrolling, the offending post-scale is on the
87 // parent layer of the displayport-ancestor, which we don't reach in this
88 // loop, so we don't need to worry about it.
89 float presShellResolution = iter.GetPresShellResolution();
90 transform.PostScale(presShellResolution, presShellResolution, 1.0f);
91 }
92 }
93 return ViewAs<LayerToParentLayerMatrix4x4>(transform);
94 }
95
GetAncestorLayers(LayerMetricsWrapper * aOutScrollAncestor,LayerMetricsWrapper * aOutDisplayPortAncestor,bool * aOutHasTransformAnimation)96 void ClientTiledPaintedLayer::GetAncestorLayers(
97 LayerMetricsWrapper* aOutScrollAncestor,
98 LayerMetricsWrapper* aOutDisplayPortAncestor,
99 bool* aOutHasTransformAnimation) {
100 LayerMetricsWrapper scrollAncestor;
101 LayerMetricsWrapper displayPortAncestor;
102 bool hasTransformAnimation = false;
103 for (LayerMetricsWrapper ancestor(this, LayerMetricsWrapper::StartAt::BOTTOM);
104 ancestor; ancestor = ancestor.GetParent()) {
105 hasTransformAnimation |= ancestor.HasTransformAnimation();
106 const FrameMetrics& metrics = ancestor.Metrics();
107 if (!scrollAncestor &&
108 metrics.GetScrollId() != FrameMetrics::NULL_SCROLL_ID) {
109 scrollAncestor = ancestor;
110 }
111 if (!metrics.GetDisplayPort().IsEmpty()) {
112 displayPortAncestor = ancestor;
113 // Any layer that has a displayport must be scrollable, so we can break
114 // here.
115 break;
116 }
117 }
118 if (aOutScrollAncestor) {
119 *aOutScrollAncestor = scrollAncestor;
120 }
121 if (aOutDisplayPortAncestor) {
122 *aOutDisplayPortAncestor = displayPortAncestor;
123 }
124 if (aOutHasTransformAnimation) {
125 *aOutHasTransformAnimation = hasTransformAnimation;
126 }
127 }
128
BeginPaint()129 void ClientTiledPaintedLayer::BeginPaint() {
130 mPaintData.ResetPaintData();
131
132 if (!GetBaseTransform().Is2D()) {
133 // Give up if there is a complex CSS transform on the layer. We might
134 // eventually support these but for now it's too complicated to handle
135 // given that it's a pretty rare scenario.
136 return;
137 }
138
139 // Get the metrics of the nearest scrollable layer and the nearest layer
140 // with a displayport.
141 LayerMetricsWrapper scrollAncestor;
142 LayerMetricsWrapper displayPortAncestor;
143 bool hasTransformAnimation;
144 GetAncestorLayers(&scrollAncestor, &displayPortAncestor,
145 &hasTransformAnimation);
146
147 if (!displayPortAncestor || !scrollAncestor) {
148 // No displayport or scroll ancestor, so we can't do progressive rendering.
149 #if defined(MOZ_WIDGET_ANDROID)
150 // Android are guaranteed to have a displayport set, so this
151 // should never happen.
152 NS_WARNING("Tiled PaintedLayer with no scrollable container ancestor");
153 #endif
154 return;
155 }
156
157 TILING_LOG(
158 "TILING %p: Found scrollAncestor %p, displayPortAncestor %p, transform "
159 "%d\n",
160 this, scrollAncestor.GetLayer(), displayPortAncestor.GetLayer(),
161 hasTransformAnimation);
162
163 const FrameMetrics& scrollMetrics = scrollAncestor.Metrics();
164 const FrameMetrics& displayportMetrics = displayPortAncestor.Metrics();
165
166 // Calculate the transform required to convert ParentLayer space of our
167 // display port ancestor to the Layer space of this layer.
168 ParentLayerToLayerMatrix4x4 transformDisplayPortToLayer =
169 GetTransformToAncestorsParentLayer(this, displayPortAncestor).Inverse();
170
171 LayerRect layerBounds(GetVisibleRegion().GetBounds());
172
173 // Compute the critical display port that applies to this layer in the
174 // LayoutDevice space of this layer, but only if there is no OMT animation
175 // on this layer. If there is an OMT animation then we need to draw the whole
176 // visible region of this layer as determined by layout, because we don't know
177 // what parts of it might move into view in the compositor.
178 mPaintData.mHasTransformAnimation = hasTransformAnimation;
179 if (!mPaintData.mHasTransformAnimation &&
180 mContentClient->GetLowPrecisionTiledBuffer()) {
181 ParentLayerRect criticalDisplayPort =
182 (displayportMetrics.GetCriticalDisplayPort() *
183 displayportMetrics.GetZoom()) +
184 displayportMetrics.GetCompositionBounds().TopLeft();
185 Maybe<LayerRect> criticalDisplayPortTransformed =
186 ApplyParentLayerToLayerTransform(transformDisplayPortToLayer,
187 criticalDisplayPort, layerBounds);
188 if (criticalDisplayPortTransformed) {
189 mPaintData.mCriticalDisplayPort =
190 Some(RoundedToInt(*criticalDisplayPortTransformed));
191 } else {
192 mPaintData.mCriticalDisplayPort = Some(LayerIntRect(0, 0, 0, 0));
193 }
194 }
195 TILING_LOG("TILING %p: Critical displayport %s\n", this,
196 mPaintData.mCriticalDisplayPort
197 ? Stringify(*mPaintData.mCriticalDisplayPort).c_str()
198 : "not set");
199
200 // Store the resolution from the displayport ancestor layer. Because this is
201 // Gecko-side, before any async transforms have occurred, we can use the zoom
202 // for this.
203 mPaintData.mResolution = displayportMetrics.GetZoom();
204 TILING_LOG("TILING %p: Resolution %s\n", this,
205 Stringify(mPaintData.mResolution).c_str());
206
207 // Store the applicable composition bounds in this layer's Layer units.
208 mPaintData.mTransformToCompBounds =
209 GetTransformToAncestorsParentLayer(this, scrollAncestor);
210 ParentLayerToLayerMatrix4x4 transformToBounds =
211 mPaintData.mTransformToCompBounds.Inverse();
212 Maybe<LayerRect> compositionBoundsTransformed =
213 ApplyParentLayerToLayerTransform(
214 transformToBounds, scrollMetrics.GetCompositionBounds(), layerBounds);
215 if (compositionBoundsTransformed) {
216 mPaintData.mCompositionBounds = *compositionBoundsTransformed;
217 } else {
218 mPaintData.mCompositionBounds.SetEmpty();
219 }
220 TILING_LOG("TILING %p: Composition bounds %s\n", this,
221 Stringify(mPaintData.mCompositionBounds).c_str());
222
223 // Calculate the scroll offset since the last transaction
224 mPaintData.mScrollOffset =
225 displayportMetrics.GetScrollOffset() * displayportMetrics.GetZoom();
226 TILING_LOG("TILING %p: Scroll offset %s\n", this,
227 Stringify(mPaintData.mScrollOffset).c_str());
228 }
229
IsScrollingOnCompositor(const FrameMetrics & aParentMetrics)230 bool ClientTiledPaintedLayer::IsScrollingOnCompositor(
231 const FrameMetrics& aParentMetrics) {
232 CompositorBridgeChild* compositor = nullptr;
233 if (Manager() && Manager()->AsClientLayerManager()) {
234 compositor = Manager()->AsClientLayerManager()->GetCompositorBridgeChild();
235 }
236
237 if (!compositor) {
238 return false;
239 }
240
241 FrameMetrics compositorMetrics;
242 if (!compositor->LookupCompositorFrameMetrics(aParentMetrics.GetScrollId(),
243 compositorMetrics)) {
244 return false;
245 }
246
247 // 1 is a tad high for a fuzzy equals epsilon however if our scroll delta
248 // is so small then we have nothing to gain from using paint heuristics.
249 float COORDINATE_EPSILON = 1.f;
250
251 return !FuzzyEqualsAdditive(compositorMetrics.GetScrollOffset().x,
252 aParentMetrics.GetScrollOffset().x,
253 COORDINATE_EPSILON) ||
254 !FuzzyEqualsAdditive(compositorMetrics.GetScrollOffset().y,
255 aParentMetrics.GetScrollOffset().y,
256 COORDINATE_EPSILON);
257 }
258
UseProgressiveDraw()259 bool ClientTiledPaintedLayer::UseProgressiveDraw() {
260 if (!gfxPrefs::ProgressivePaint()) {
261 // pref is disabled, so never do progressive
262 return false;
263 }
264
265 if (!mContentClient->GetTiledBuffer()->SupportsProgressiveUpdate()) {
266 return false;
267 }
268
269 if (ClientManager()->HasShadowTarget()) {
270 // This condition is true when we are in a reftest scenario. We don't want
271 // to draw progressively here because it can cause intermittent reftest
272 // failures because the harness won't wait for all the tiles to be drawn.
273 return false;
274 }
275
276 if (GetIsFixedPosition() || GetParent()->GetIsFixedPosition()) {
277 // This layer is fixed-position and so even if it does have a scrolling
278 // ancestor it will likely be entirely on-screen all the time, so we
279 // should draw it all at once
280 return false;
281 }
282
283 if (mPaintData.mHasTransformAnimation) {
284 // The compositor is going to animate this somehow, so we want it all
285 // on the screen at once.
286 return false;
287 }
288
289 if (ClientManager()->AsyncPanZoomEnabled()) {
290 LayerMetricsWrapper scrollAncestor;
291 GetAncestorLayers(&scrollAncestor, nullptr, nullptr);
292 MOZ_ASSERT(
293 scrollAncestor); // because mPaintData.mCriticalDisplayPort is set
294 if (!scrollAncestor) {
295 return false;
296 }
297 const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
298 if (!IsScrollingOnCompositor(parentMetrics)) {
299 return false;
300 }
301 }
302
303 return true;
304 }
305
RenderHighPrecision(const nsIntRegion & aInvalidRegion,const nsIntRegion & aVisibleRegion,LayerManager::DrawPaintedLayerCallback aCallback,void * aCallbackData)306 bool ClientTiledPaintedLayer::RenderHighPrecision(
307 const nsIntRegion& aInvalidRegion, const nsIntRegion& aVisibleRegion,
308 LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData) {
309 // If we have started drawing low-precision already, then we
310 // shouldn't do anything there.
311 if (mPaintData.mLowPrecisionPaintCount != 0) {
312 return false;
313 }
314
315 // Only draw progressively when there is something to paint and the
316 // resolution is unchanged
317 if (!aInvalidRegion.IsEmpty() && UseProgressiveDraw() &&
318 mContentClient->GetTiledBuffer()->GetFrameResolution() ==
319 mPaintData.mResolution) {
320 // Store the old valid region, then clear it before painting.
321 // We clip the old valid region to the visible region, as it only gets
322 // used to decide stale content (currently valid and previously visible)
323 nsIntRegion oldValidRegion =
324 mContentClient->GetTiledBuffer()->GetValidRegion();
325 oldValidRegion.And(oldValidRegion, aVisibleRegion);
326 if (mPaintData.mCriticalDisplayPort) {
327 oldValidRegion.And(oldValidRegion,
328 mPaintData.mCriticalDisplayPort->ToUnknownRect());
329 }
330
331 TILING_LOG("TILING %p: Progressive update with old valid region %s\n", this,
332 Stringify(oldValidRegion).c_str());
333
334 nsIntRegion drawnRegion;
335 bool updatedBuffer = mContentClient->GetTiledBuffer()->ProgressiveUpdate(
336 GetValidRegion(), aInvalidRegion, oldValidRegion, drawnRegion,
337 &mPaintData, aCallback, aCallbackData);
338 AddToValidRegion(drawnRegion);
339 return updatedBuffer;
340 }
341
342 // Otherwise do a non-progressive paint. We must do this even when
343 // the region to paint is empty as the valid region may have shrunk.
344
345 nsIntRegion validRegion = aVisibleRegion;
346 if (mPaintData.mCriticalDisplayPort) {
347 validRegion.AndWith(mPaintData.mCriticalDisplayPort->ToUnknownRect());
348 }
349 SetValidRegion(validRegion);
350
351 TILING_LOG("TILING %p: Non-progressive paint invalid region %s\n", this,
352 Stringify(aInvalidRegion).c_str());
353 TILING_LOG("TILING %p: Non-progressive paint new valid region %s\n", this,
354 Stringify(GetValidRegion()).c_str());
355
356 TilePaintFlags flags =
357 PaintThread::Get() ? TilePaintFlags::Async : TilePaintFlags::None;
358
359 mContentClient->GetTiledBuffer()->SetFrameResolution(mPaintData.mResolution);
360 mContentClient->GetTiledBuffer()->PaintThebes(
361 GetValidRegion(), aInvalidRegion, aInvalidRegion, aCallback,
362 aCallbackData, flags);
363 mPaintData.mPaintFinished = true;
364 return true;
365 }
366
RenderLowPrecision(const nsIntRegion & aInvalidRegion,const nsIntRegion & aVisibleRegion,LayerManager::DrawPaintedLayerCallback aCallback,void * aCallbackData)367 bool ClientTiledPaintedLayer::RenderLowPrecision(
368 const nsIntRegion& aInvalidRegion, const nsIntRegion& aVisibleRegion,
369 LayerManager::DrawPaintedLayerCallback aCallback, void* aCallbackData) {
370 nsIntRegion invalidRegion = aInvalidRegion;
371
372 // Render the low precision buffer, if the visible region is larger than the
373 // critical display port.
374 if (!mPaintData.mCriticalDisplayPort ||
375 !nsIntRegion(mPaintData.mCriticalDisplayPort->ToUnknownRect())
376 .Contains(aVisibleRegion)) {
377 nsIntRegion oldValidRegion =
378 mContentClient->GetLowPrecisionTiledBuffer()->GetValidRegion();
379 oldValidRegion.And(oldValidRegion, aVisibleRegion);
380
381 bool updatedBuffer = false;
382
383 // If the frame resolution or format have changed, invalidate the buffer
384 if (mContentClient->GetLowPrecisionTiledBuffer()->GetFrameResolution() !=
385 mPaintData.mResolution ||
386 mContentClient->GetLowPrecisionTiledBuffer()->HasFormatChanged()) {
387 if (!mLowPrecisionValidRegion.IsEmpty()) {
388 updatedBuffer = true;
389 }
390 oldValidRegion.SetEmpty();
391 mLowPrecisionValidRegion.SetEmpty();
392 mContentClient->GetLowPrecisionTiledBuffer()->ResetPaintedAndValidState();
393 mContentClient->GetLowPrecisionTiledBuffer()->SetFrameResolution(
394 mPaintData.mResolution);
395 invalidRegion = aVisibleRegion;
396 }
397
398 // Invalidate previously valid content that is no longer visible
399 if (mPaintData.mLowPrecisionPaintCount == 1) {
400 mLowPrecisionValidRegion.And(mLowPrecisionValidRegion, aVisibleRegion);
401 }
402 mPaintData.mLowPrecisionPaintCount++;
403
404 // Remove the valid high-precision region from the invalid low-precision
405 // region. We don't want to spend time drawing things twice.
406 invalidRegion.SubOut(GetValidRegion());
407
408 TILING_LOG(
409 "TILING %p: Progressive paint: low-precision invalid region is %s\n",
410 this, Stringify(invalidRegion).c_str());
411 TILING_LOG(
412 "TILING %p: Progressive paint: low-precision old valid region is %s\n",
413 this, Stringify(oldValidRegion).c_str());
414
415 if (!invalidRegion.IsEmpty()) {
416 nsIntRegion drawnRegion;
417 updatedBuffer =
418 mContentClient->GetLowPrecisionTiledBuffer()->ProgressiveUpdate(
419 mLowPrecisionValidRegion, invalidRegion, oldValidRegion,
420 drawnRegion, &mPaintData, aCallback, aCallbackData);
421 mLowPrecisionValidRegion.OrWith(drawnRegion);
422 }
423
424 TILING_LOG(
425 "TILING %p: Progressive paint: low-precision new valid region is %s\n",
426 this, Stringify(mLowPrecisionValidRegion).c_str());
427 return updatedBuffer;
428 }
429 if (!mLowPrecisionValidRegion.IsEmpty()) {
430 TILING_LOG("TILING %p: Clearing low-precision buffer\n", this);
431 // Clear the low precision tiled buffer.
432 mLowPrecisionValidRegion.SetEmpty();
433 mContentClient->GetLowPrecisionTiledBuffer()->ResetPaintedAndValidState();
434 // Return true here so we send a Painted callback after clearing the valid
435 // region of the low precision buffer. This allows the shadow buffer's valid
436 // region to be updated and the associated resources to be freed.
437 return true;
438 }
439 return false;
440 }
441
EndPaint()442 void ClientTiledPaintedLayer::EndPaint() {
443 mPaintData.mLastScrollOffset = mPaintData.mScrollOffset;
444 mPaintData.mPaintFinished = true;
445 mPaintData.mFirstPaint = false;
446 TILING_LOG("TILING %p: Paint finished\n", this);
447 }
448
RenderLayer()449 void ClientTiledPaintedLayer::RenderLayer() {
450 LayerManager::DrawPaintedLayerCallback callback =
451 ClientManager()->GetPaintedLayerCallback();
452 void* data = ClientManager()->GetPaintedLayerCallbackData();
453
454 IntSize layerSize = mVisibleRegion.ToUnknownRegion().GetBounds().Size();
455 IntSize tileSize = gfx::gfxVars::TileSize();
456 bool isHalfTileWidthOrHeight = layerSize.width <= tileSize.width / 2 ||
457 layerSize.height <= tileSize.height / 2;
458
459 // Use single tile when layer is not scrollable, is smaller than one
460 // tile, or when more than half of the tiles' pixels in either
461 // dimension would be wasted.
462 bool wantSingleTiledContentClient =
463 (mCreationHint == LayerManager::NONE || layerSize <= tileSize ||
464 isHalfTileWidthOrHeight) &&
465 SingleTiledContentClient::ClientSupportsLayerSize(layerSize,
466 ClientManager()) &&
467 gfxPrefs::LayersSingleTileEnabled();
468
469 if (mContentClient && mHaveSingleTiledContentClient &&
470 !wantSingleTiledContentClient) {
471 mContentClient = nullptr;
472 ClearValidRegion();
473 }
474
475 if (!mContentClient) {
476 if (wantSingleTiledContentClient) {
477 mContentClient = new SingleTiledContentClient(*this, ClientManager());
478 mHaveSingleTiledContentClient = true;
479 } else {
480 mContentClient = new MultiTiledContentClient(*this, ClientManager());
481 mHaveSingleTiledContentClient = false;
482 }
483
484 mContentClient->Connect();
485 ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
486 MOZ_ASSERT(mContentClient->GetForwarder());
487 }
488
489 if (mContentClient->GetTiledBuffer()->HasFormatChanged()) {
490 ClearValidRegion();
491 mContentClient->GetTiledBuffer()->ResetPaintedAndValidState();
492 }
493
494 TILING_LOG("TILING %p: Initial visible region %s\n", this,
495 Stringify(mVisibleRegion).c_str());
496 TILING_LOG("TILING %p: Initial valid region %s\n", this,
497 Stringify(GetValidRegion()).c_str());
498 TILING_LOG("TILING %p: Initial low-precision valid region %s\n", this,
499 Stringify(mLowPrecisionValidRegion).c_str());
500
501 nsIntRegion neededRegion = mVisibleRegion.ToUnknownRegion();
502 #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
503 // This is handled by PadDrawTargetOutFromRegion in TiledContentClient for
504 // mobile
505 if (MayResample()) {
506 // If we're resampling then bilinear filtering can read up to 1 pixel
507 // outside of our texture coords. Make the visible region a single rect,
508 // and pad it out by 1 pixel (restricted to tile boundaries) so that
509 // we always have valid content or transparent pixels to sample from.
510 IntRect bounds = neededRegion.GetBounds();
511 IntRect wholeTiles = bounds;
512 wholeTiles.InflateToMultiple(gfx::gfxVars::TileSize());
513 IntRect padded = bounds;
514 padded.Inflate(1);
515 padded.IntersectRect(padded, wholeTiles);
516 neededRegion = padded;
517 }
518 #endif
519
520 nsIntRegion invalidRegion;
521 invalidRegion.Sub(neededRegion, GetValidRegion());
522 if (invalidRegion.IsEmpty()) {
523 EndPaint();
524 return;
525 }
526
527 if (!callback) {
528 ClientManager()->SetTransactionIncomplete();
529 return;
530 }
531
532 if (!ClientManager()->IsRepeatTransaction()) {
533 // Only paint the mask layers on the first transaction.
534 RenderMaskLayers(this);
535
536 // For more complex cases we need to calculate a bunch of metrics before we
537 // can do the paint.
538 BeginPaint();
539 if (mPaintData.mPaintFinished) {
540 return;
541 }
542
543 // Make sure that tiles that fall outside of the visible region or outside
544 // of the critical displayport are discarded on the first update. Also make
545 // sure that we only draw stuff inside the critical displayport on the first
546 // update.
547 nsIntRegion validRegion;
548 validRegion.And(GetValidRegion(), neededRegion);
549 if (mPaintData.mCriticalDisplayPort) {
550 validRegion.AndWith(mPaintData.mCriticalDisplayPort->ToUnknownRect());
551 invalidRegion.And(invalidRegion,
552 mPaintData.mCriticalDisplayPort->ToUnknownRect());
553 }
554 SetValidRegion(validRegion);
555
556 TILING_LOG("TILING %p: First-transaction valid region %s\n", this,
557 Stringify(validRegion).c_str());
558 TILING_LOG("TILING %p: First-transaction invalid region %s\n", this,
559 Stringify(invalidRegion).c_str());
560 } else {
561 if (mPaintData.mCriticalDisplayPort) {
562 invalidRegion.And(invalidRegion,
563 mPaintData.mCriticalDisplayPort->ToUnknownRect());
564 }
565 TILING_LOG("TILING %p: Repeat-transaction invalid region %s\n", this,
566 Stringify(invalidRegion).c_str());
567 }
568
569 nsIntRegion lowPrecisionInvalidRegion;
570 if (mContentClient->GetLowPrecisionTiledBuffer()) {
571 // Calculate the invalid region for the low precision buffer. Make sure
572 // to remove the valid high-precision area so we don't double-paint it.
573 lowPrecisionInvalidRegion.Sub(neededRegion, mLowPrecisionValidRegion);
574 lowPrecisionInvalidRegion.Sub(lowPrecisionInvalidRegion, GetValidRegion());
575 }
576 TILING_LOG("TILING %p: Low-precision invalid region %s\n", this,
577 Stringify(lowPrecisionInvalidRegion).c_str());
578
579 bool updatedHighPrecision =
580 RenderHighPrecision(invalidRegion, neededRegion, callback, data);
581 if (updatedHighPrecision) {
582 ClientManager()->Hold(this);
583 mContentClient->UpdatedBuffer(TiledContentClient::TILED_BUFFER);
584
585 if (!mPaintData.mPaintFinished) {
586 // There is still more high-res stuff to paint, so we're not
587 // done yet. A subsequent transaction will take care of this.
588 ClientManager()->SetRepeatTransaction();
589 return;
590 }
591 }
592
593 // If there is nothing to draw in low-precision, then we're done.
594 if (lowPrecisionInvalidRegion.IsEmpty()) {
595 EndPaint();
596 return;
597 }
598
599 if (updatedHighPrecision) {
600 // If there are low precision updates, but we just did some high-precision
601 // updates, then mark the paint as unfinished and request a repeat
602 // transaction. This is so that we don't perform low-precision updates in
603 // the same transaction as high-precision updates.
604 TILING_LOG(
605 "TILING %p: Scheduling repeat transaction for low-precision painting\n",
606 this);
607 ClientManager()->SetRepeatTransaction();
608 mPaintData.mLowPrecisionPaintCount = 1;
609 mPaintData.mPaintFinished = false;
610 return;
611 }
612
613 bool updatedLowPrecision = RenderLowPrecision(lowPrecisionInvalidRegion,
614 neededRegion, callback, data);
615 if (updatedLowPrecision) {
616 ClientManager()->Hold(this);
617 mContentClient->UpdatedBuffer(
618 TiledContentClient::LOW_PRECISION_TILED_BUFFER);
619
620 if (!mPaintData.mPaintFinished) {
621 // There is still more low-res stuff to paint, so we're not
622 // done yet. A subsequent transaction will take care of this.
623 ClientManager()->SetRepeatTransaction();
624 return;
625 }
626 }
627
628 // If we get here, we've done all the high- and low-precision
629 // paints we wanted to do, so we can finish the paint and chill.
630 EndPaint();
631 }
632
IsOptimizedFor(LayerManager::PaintedLayerCreationHint aHint)633 bool ClientTiledPaintedLayer::IsOptimizedFor(
634 LayerManager::PaintedLayerCreationHint aHint) {
635 // The only creation hint is whether the layer is scrollable or not, and this
636 // is only respected on OSX, where it's used to determine whether to
637 // use a tiled content client or not.
638 // There are pretty nasty performance consequences for not using tiles on
639 // large, scrollable layers, so we want the layer to be recreated in this
640 // situation.
641 return aHint == GetCreationHint();
642 }
643
PrintInfo(std::stringstream & aStream,const char * aPrefix)644 void ClientTiledPaintedLayer::PrintInfo(std::stringstream& aStream,
645 const char* aPrefix) {
646 PaintedLayer::PrintInfo(aStream, aPrefix);
647 if (mContentClient) {
648 aStream << "\n";
649 nsAutoCString pfx(aPrefix);
650 pfx += " ";
651 mContentClient->PrintInfo(aStream, pfx.get());
652 }
653 }
654
655 } // namespace layers
656 } // namespace mozilla
657