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