1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "TiledContentHost.h"
7 #include "gfxPrefs.h" // for gfxPrefs
8 #include "PaintedLayerComposite.h" // for PaintedLayerComposite
9 #include "mozilla/gfx/BaseSize.h" // for BaseSize
10 #include "mozilla/gfx/Matrix.h" // for Matrix4x4
11 #include "mozilla/gfx/Point.h" // for IntSize
12 #include "mozilla/layers/Compositor.h" // for Compositor
13 //#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent
14 #include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
15 #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
16 #include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
17 #include "nsAString.h"
18 #include "nsDebug.h" // for NS_WARNING
19 #include "nsPoint.h" // for IntPoint
20 #include "nsPrintfCString.h" // for nsPrintfCString
21 #include "nsRect.h" // for IntRect
22 #include "mozilla/layers/TextureClient.h"
23
24 namespace mozilla {
25 using namespace gfx;
26 namespace layers {
27
28 class Layer;
29
30 float
GetFadeInOpacity(float aOpacity)31 TileHost::GetFadeInOpacity(float aOpacity)
32 {
33 TimeStamp now = TimeStamp::Now();
34 if (!gfxPrefs::LayerTileFadeInEnabled() ||
35 mFadeStart.IsNull() ||
36 now < mFadeStart)
37 {
38 return aOpacity;
39 }
40
41 float duration = gfxPrefs::LayerTileFadeInDuration();
42 float elapsed = (now - mFadeStart).ToMilliseconds();
43 if (elapsed > duration) {
44 mFadeStart = TimeStamp();
45 return aOpacity;
46 }
47 return aOpacity * (elapsed / duration);
48 }
49
TiledLayerBufferComposite()50 TiledLayerBufferComposite::TiledLayerBufferComposite()
51 : mFrameResolution()
52 {}
53
~TiledLayerBufferComposite()54 TiledLayerBufferComposite::~TiledLayerBufferComposite()
55 {
56 Clear();
57 }
58
59 void
SetCompositor(Compositor * aCompositor)60 TiledLayerBufferComposite::SetCompositor(Compositor* aCompositor)
61 {
62 MOZ_ASSERT(aCompositor);
63 for (TileHost& tile : mRetainedTiles) {
64 if (tile.IsPlaceholderTile()) continue;
65 tile.mTextureHost->SetCompositor(aCompositor);
66 if (tile.mTextureHostOnWhite) {
67 tile.mTextureHostOnWhite->SetCompositor(aCompositor);
68 }
69 }
70 }
71
72 void
AddAnimationInvalidation(nsIntRegion & aRegion)73 TiledLayerBufferComposite::AddAnimationInvalidation(nsIntRegion& aRegion)
74 {
75 // We need to invalidate rects where we have a tile that is in the
76 // process of fading in.
77 for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
78 if (!mRetainedTiles[i].mFadeStart.IsNull()) {
79 TileIntPoint position = mTiles.TilePosition(i);
80 IntPoint offset = GetTileOffset(position);
81 nsIntRegion tileRegion = IntRect(offset, GetScaledTileSize());
82 aRegion.OrWith(tileRegion);
83 }
84 }
85 }
86
TiledContentHost(const TextureInfo & aTextureInfo)87 TiledContentHost::TiledContentHost(const TextureInfo& aTextureInfo)
88 : ContentHost(aTextureInfo)
89 , mTiledBuffer(TiledLayerBufferComposite())
90 , mLowPrecisionTiledBuffer(TiledLayerBufferComposite())
91 {
92 MOZ_COUNT_CTOR(TiledContentHost);
93 }
94
~TiledContentHost()95 TiledContentHost::~TiledContentHost()
96 {
97 MOZ_COUNT_DTOR(TiledContentHost);
98 }
99
100 already_AddRefed<TexturedEffect>
GenEffect(const gfx::SamplingFilter aSamplingFilter)101 TiledContentHost::GenEffect(const gfx::SamplingFilter aSamplingFilter)
102 {
103 // If we can use hwc for this TiledContentHost, it implies that we have exactly
104 // one high precision tile. Please check TiledContentHost::GetRenderState() for
105 // all condition.
106 MOZ_ASSERT(mTiledBuffer.GetTileCount() == 1 && mLowPrecisionTiledBuffer.GetTileCount() == 0);
107 MOZ_ASSERT(mTiledBuffer.GetTile(0).mTextureHost);
108
109 TileHost& tile = mTiledBuffer.GetTile(0);
110 if (!tile.mTextureHost->BindTextureSource(tile.mTextureSource)) {
111 return nullptr;
112 }
113
114 return CreateTexturedEffect(tile.mTextureSource,
115 nullptr,
116 aSamplingFilter,
117 true,
118 tile.mTextureHost->GetRenderState());
119 }
120
121 void
Attach(Layer * aLayer,Compositor * aCompositor,AttachFlags aFlags)122 TiledContentHost::Attach(Layer* aLayer,
123 Compositor* aCompositor,
124 AttachFlags aFlags /* = NO_FLAGS */)
125 {
126 CompositableHost::Attach(aLayer, aCompositor, aFlags);
127 }
128
129 void
Detach(Layer * aLayer,AttachFlags aFlags)130 TiledContentHost::Detach(Layer* aLayer,
131 AttachFlags aFlags /* = NO_FLAGS */)
132 {
133 if (!mKeepAttached || aLayer == mLayer || aFlags & FORCE_DETACH) {
134 // Clear the TiledLayerBuffers, which will take care of releasing the
135 // copy-on-write locks.
136 mTiledBuffer.Clear();
137 mLowPrecisionTiledBuffer.Clear();
138 }
139 CompositableHost::Detach(aLayer,aFlags);
140 }
141
142 bool
UseTiledLayerBuffer(ISurfaceAllocator * aAllocator,const SurfaceDescriptorTiles & aTiledDescriptor)143 TiledContentHost::UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
144 const SurfaceDescriptorTiles& aTiledDescriptor)
145 {
146 if (aTiledDescriptor.resolution() < 1) {
147 if (!mLowPrecisionTiledBuffer.UseTiles(aTiledDescriptor, mCompositor, aAllocator)) {
148 return false;
149 }
150 } else {
151 if (!mTiledBuffer.UseTiles(aTiledDescriptor, mCompositor, aAllocator)) {
152 return false;
153 }
154 }
155 return true;
156 }
157
158 void
UseTileTexture(CompositableTextureHostRef & aTexture,CompositableTextureSourceRef & aTextureSource,const IntRect & aUpdateRect,Compositor * aCompositor)159 UseTileTexture(CompositableTextureHostRef& aTexture,
160 CompositableTextureSourceRef& aTextureSource,
161 const IntRect& aUpdateRect,
162 Compositor* aCompositor)
163 {
164 MOZ_ASSERT(aTexture);
165 if (!aTexture) {
166 return;
167 }
168
169 if (aCompositor) {
170 aTexture->SetCompositor(aCompositor);
171 }
172
173 if (!aUpdateRect.IsEmpty()) {
174 // For !HasIntermediateBuffer() textures, this is likely a no-op.
175 nsIntRegion region = aUpdateRect;
176 aTexture->Updated(®ion);
177 }
178
179 aTexture->PrepareTextureSource(aTextureSource);
180 }
181
182 class TextureSourceRecycler
183 {
184 public:
TextureSourceRecycler(nsTArray<TileHost> && aTileSet)185 explicit TextureSourceRecycler(nsTArray<TileHost>&& aTileSet)
186 : mTiles(Move(aTileSet))
187 , mFirstPossibility(0)
188 {}
189
190 // Attempts to recycle a texture source that is already bound to the
191 // texture host for aTile.
RecycleTextureSourceForTile(TileHost & aTile)192 void RecycleTextureSourceForTile(TileHost& aTile) {
193 for (size_t i = mFirstPossibility; i < mTiles.Length(); i++) {
194 // Skip over existing tiles without a retained texture source
195 // and make sure we don't iterate them in the future.
196 if (!mTiles[i].mTextureSource) {
197 if (i == mFirstPossibility) {
198 mFirstPossibility++;
199 }
200 continue;
201 }
202
203 // If this tile matches, then copy across the retained texture source (if
204 // any).
205 if (aTile.mTextureHost == mTiles[i].mTextureHost) {
206 aTile.mTextureSource = Move(mTiles[i].mTextureSource);
207 if (aTile.mTextureHostOnWhite) {
208 aTile.mTextureSourceOnWhite = Move(mTiles[i].mTextureSourceOnWhite);
209 }
210 break;
211 }
212 }
213 }
214
215 // Attempts to recycle any texture source to avoid needing to allocate
216 // a new one.
RecycleTextureSource(TileHost & aTile)217 void RecycleTextureSource(TileHost& aTile) {
218 for (size_t i = mFirstPossibility; i < mTiles.Length(); i++) {
219 if (!mTiles[i].mTextureSource) {
220 if (i == mFirstPossibility) {
221 mFirstPossibility++;
222 }
223 continue;
224 }
225
226 if (mTiles[i].mTextureSource &&
227 mTiles[i].mTextureHost->GetFormat() == aTile.mTextureHost->GetFormat()) {
228 aTile.mTextureSource = Move(mTiles[i].mTextureSource);
229 if (aTile.mTextureHostOnWhite) {
230 aTile.mTextureSourceOnWhite = Move(mTiles[i].mTextureSourceOnWhite);
231 }
232 break;
233 }
234 }
235 }
236
RecycleTileFading(TileHost & aTile)237 void RecycleTileFading(TileHost& aTile) {
238 for (size_t i = 0; i < mTiles.Length(); i++) {
239 if (mTiles[i].mTextureHost == aTile.mTextureHost) {
240 aTile.mFadeStart = mTiles[i].mFadeStart;
241 }
242 }
243 }
244
245 protected:
246 nsTArray<TileHost> mTiles;
247 size_t mFirstPossibility;
248 };
249
250 bool
UseTiles(const SurfaceDescriptorTiles & aTiles,Compositor * aCompositor,ISurfaceAllocator * aAllocator)251 TiledLayerBufferComposite::UseTiles(const SurfaceDescriptorTiles& aTiles,
252 Compositor* aCompositor,
253 ISurfaceAllocator* aAllocator)
254 {
255 if (mResolution != aTiles.resolution() ||
256 aTiles.tileSize() != mTileSize) {
257 Clear();
258 }
259 MOZ_ASSERT(aAllocator);
260 MOZ_ASSERT(aCompositor);
261 if (!aAllocator || !aCompositor) {
262 return false;
263 }
264
265 if (aTiles.resolution() == 0 || IsNaN(aTiles.resolution())) {
266 // There are divisions by mResolution so this protects the compositor process
267 // against malicious content processes and fuzzing.
268 return false;
269 }
270
271 TilesPlacement newTiles(aTiles.firstTileX(), aTiles.firstTileY(),
272 aTiles.retainedWidth(), aTiles.retainedHeight());
273
274 const InfallibleTArray<TileDescriptor>& tileDescriptors = aTiles.tiles();
275
276 TextureSourceRecycler oldRetainedTiles(Move(mRetainedTiles));
277 mRetainedTiles.SetLength(tileDescriptors.Length());
278
279 // Step 1, deserialize the incoming set of tiles into mRetainedTiles, and attempt
280 // to recycle the TextureSource for any repeated tiles.
281 //
282 // Since we don't have any retained 'tile' object, we have to search for instances
283 // of the same TextureHost in the old tile set. The cost of binding a TextureHost
284 // to a TextureSource for gralloc (binding EGLImage to GL texture) can be really
285 // high, so we avoid this whenever possible.
286 for (size_t i = 0; i < tileDescriptors.Length(); i++) {
287 const TileDescriptor& tileDesc = tileDescriptors[i];
288
289 TileHost& tile = mRetainedTiles[i];
290
291 if (tileDesc.type() != TileDescriptor::TTexturedTileDescriptor) {
292 NS_WARNING_ASSERTION(
293 tileDesc.type() == TileDescriptor::TPlaceholderTileDescriptor,
294 "Unrecognised tile descriptor type");
295 continue;
296 }
297
298 const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
299
300 tile.mTextureHost = TextureHost::AsTextureHost(texturedDesc.textureParent());
301 tile.mTextureHost->SetCompositor(aCompositor);
302 tile.mTextureHost->DeserializeReadLock(texturedDesc.sharedLock(), aAllocator);
303
304 if (texturedDesc.textureOnWhite().type() == MaybeTexture::TPTextureParent) {
305 tile.mTextureHostOnWhite = TextureHost::AsTextureHost(
306 texturedDesc.textureOnWhite().get_PTextureParent()
307 );
308 tile.mTextureHostOnWhite->DeserializeReadLock(
309 texturedDesc.sharedLockOnWhite(), aAllocator
310 );
311 }
312
313 tile.mTilePosition = newTiles.TilePosition(i);
314
315 // If this same tile texture existed in the old tile set then this will move the texture
316 // source into our new tile.
317 oldRetainedTiles.RecycleTextureSourceForTile(tile);
318
319 // If this tile is in the process of fading, we need to keep that going
320 oldRetainedTiles.RecycleTileFading(tile);
321
322 if (aTiles.isProgressive() &&
323 texturedDesc.wasPlaceholder())
324 {
325 // This is a progressive paint, and the tile used to be a placeholder.
326 // We need to begin fading it in (if enabled via layers.tiles.fade-in.enabled)
327 tile.mFadeStart = TimeStamp::Now();
328
329 aCompositor->CompositeUntil(tile.mFadeStart +
330 TimeDuration::FromMilliseconds(gfxPrefs::LayerTileFadeInDuration()));
331 }
332 }
333
334 // Step 2, attempt to recycle unused texture sources from the old tile set into new tiles.
335 //
336 // For gralloc, binding a new TextureHost to the existing TextureSource is the fastest way
337 // to ensure that any implicit locking on the old gralloc image is released.
338 for (TileHost& tile : mRetainedTiles) {
339 if (!tile.mTextureHost || tile.mTextureSource) {
340 continue;
341 }
342 oldRetainedTiles.RecycleTextureSource(tile);
343 }
344
345 // Step 3, handle the texture uploads, texture source binding and release the
346 // copy-on-write locks for textures with an internal buffer.
347 for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
348 TileHost& tile = mRetainedTiles[i];
349 if (!tile.mTextureHost) {
350 continue;
351 }
352
353 const TileDescriptor& tileDesc = tileDescriptors[i];
354 const TexturedTileDescriptor& texturedDesc = tileDesc.get_TexturedTileDescriptor();
355
356 UseTileTexture(tile.mTextureHost,
357 tile.mTextureSource,
358 texturedDesc.updateRect(),
359 aCompositor);
360
361 if (tile.mTextureHostOnWhite) {
362 UseTileTexture(tile.mTextureHostOnWhite,
363 tile.mTextureSourceOnWhite,
364 texturedDesc.updateRect(),
365 aCompositor);
366 }
367 }
368
369 mTiles = newTiles;
370 mTileSize = aTiles.tileSize();
371 mTileOrigin = aTiles.tileOrigin();
372 mValidRegion = aTiles.validRegion();
373 mResolution = aTiles.resolution();
374 mFrameResolution = CSSToParentLayerScale2D(aTiles.frameXResolution(),
375 aTiles.frameYResolution());
376
377 return true;
378 }
379
380 void
Clear()381 TiledLayerBufferComposite::Clear()
382 {
383 mRetainedTiles.Clear();
384 mTiles.mFirst = TileIntPoint();
385 mTiles.mSize = TileIntSize();
386 mValidRegion = nsIntRegion();
387 mResolution = 1.0;
388 }
389
390 void
Composite(LayerComposite * aLayer,EffectChain & aEffectChain,float aOpacity,const gfx::Matrix4x4 & aTransform,const gfx::SamplingFilter aSamplingFilter,const gfx::IntRect & aClipRect,const nsIntRegion * aVisibleRegion)391 TiledContentHost::Composite(LayerComposite* aLayer,
392 EffectChain& aEffectChain,
393 float aOpacity,
394 const gfx::Matrix4x4& aTransform,
395 const gfx::SamplingFilter aSamplingFilter,
396 const gfx::IntRect& aClipRect,
397 const nsIntRegion* aVisibleRegion /* = nullptr */)
398 {
399 MOZ_ASSERT(mCompositor);
400 // Reduce the opacity of the low-precision buffer to make it a
401 // little more subtle and less jarring. In particular, text
402 // rendered at low-resolution and scaled tends to look pretty
403 // heavy and this helps mitigate that. When we reduce the opacity
404 // we also make sure to draw the background color behind the
405 // reduced-opacity tile so that content underneath doesn't show
406 // through.
407 // However, in cases where the background is transparent, or the layer
408 // already has some opacity, we want to skip this behaviour. Otherwise
409 // we end up changing the expected overall transparency of the content,
410 // and it just looks wrong.
411 Color backgroundColor;
412 if (aOpacity == 1.0f && gfxPrefs::LowPrecisionOpacity() < 1.0f) {
413 // Background colors are only stored on scrollable layers. Grab
414 // the one from the nearest scrollable ancestor layer.
415 for (LayerMetricsWrapper ancestor(GetLayer(), LayerMetricsWrapper::StartAt::BOTTOM); ancestor; ancestor = ancestor.GetParent()) {
416 if (ancestor.Metrics().IsScrollable()) {
417 backgroundColor = ancestor.Metadata().GetBackgroundColor();
418 break;
419 }
420 }
421 }
422 float lowPrecisionOpacityReduction =
423 (aOpacity == 1.0f && backgroundColor.a == 1.0f)
424 ? gfxPrefs::LowPrecisionOpacity() : 1.0f;
425
426 nsIntRegion tmpRegion;
427 const nsIntRegion* renderRegion = aVisibleRegion;
428 #ifndef MOZ_IGNORE_PAINT_WILL_RESAMPLE
429 if (PaintWillResample()) {
430 // If we're resampling, then the texture image will contain exactly the
431 // entire visible region's bounds, and we should draw it all in one quad
432 // to avoid unexpected aliasing.
433 tmpRegion = aVisibleRegion->GetBounds();
434 renderRegion = &tmpRegion;
435 }
436 #endif
437
438 // Render the low and high precision buffers.
439 RenderLayerBuffer(mLowPrecisionTiledBuffer,
440 lowPrecisionOpacityReduction < 1.0f ? &backgroundColor : nullptr,
441 aEffectChain, lowPrecisionOpacityReduction * aOpacity,
442 aSamplingFilter, aClipRect, *renderRegion, aTransform);
443 RenderLayerBuffer(mTiledBuffer, nullptr, aEffectChain, aOpacity, aSamplingFilter,
444 aClipRect, *renderRegion, aTransform);
445 }
446
447
448 void
RenderTile(TileHost & aTile,EffectChain & aEffectChain,float aOpacity,const gfx::Matrix4x4 & aTransform,const gfx::SamplingFilter aSamplingFilter,const gfx::IntRect & aClipRect,const nsIntRegion & aScreenRegion,const IntPoint & aTextureOffset,const IntSize & aTextureBounds,const gfx::Rect & aVisibleRect)449 TiledContentHost::RenderTile(TileHost& aTile,
450 EffectChain& aEffectChain,
451 float aOpacity,
452 const gfx::Matrix4x4& aTransform,
453 const gfx::SamplingFilter aSamplingFilter,
454 const gfx::IntRect& aClipRect,
455 const nsIntRegion& aScreenRegion,
456 const IntPoint& aTextureOffset,
457 const IntSize& aTextureBounds,
458 const gfx::Rect& aVisibleRect)
459 {
460 MOZ_ASSERT(!aTile.IsPlaceholderTile());
461
462 AutoLockTextureHost autoLock(aTile.mTextureHost);
463 AutoLockTextureHost autoLockOnWhite(aTile.mTextureHostOnWhite);
464 if (autoLock.Failed() ||
465 autoLockOnWhite.Failed()) {
466 NS_WARNING("Failed to lock tile");
467 return;
468 }
469
470 if (!aTile.mTextureHost->BindTextureSource(aTile.mTextureSource)) {
471 return;
472 }
473
474 if (aTile.mTextureHostOnWhite && !aTile.mTextureHostOnWhite->BindTextureSource(aTile.mTextureSourceOnWhite)) {
475 return;
476 }
477
478 RefPtr<TexturedEffect> effect =
479 CreateTexturedEffect(aTile.mTextureSource,
480 aTile.mTextureSourceOnWhite,
481 aSamplingFilter,
482 true,
483 aTile.mTextureHost->GetRenderState());
484 if (!effect) {
485 return;
486 }
487
488 float opacity = aTile.GetFadeInOpacity(aOpacity);
489 aEffectChain.mPrimaryEffect = effect;
490
491 for (auto iter = aScreenRegion.RectIter(); !iter.Done(); iter.Next()) {
492 const IntRect& rect = iter.Get();
493 Rect graphicsRect(rect.x, rect.y, rect.width, rect.height);
494 Rect textureRect(rect.x - aTextureOffset.x, rect.y - aTextureOffset.y,
495 rect.width, rect.height);
496
497 effect->mTextureCoords = Rect(textureRect.x / aTextureBounds.width,
498 textureRect.y / aTextureBounds.height,
499 textureRect.width / aTextureBounds.width,
500 textureRect.height / aTextureBounds.height);
501 mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, opacity, aTransform, aVisibleRect);
502 }
503 DiagnosticFlags flags = DiagnosticFlags::CONTENT | DiagnosticFlags::TILE;
504 if (aTile.mTextureHostOnWhite) {
505 flags |= DiagnosticFlags::COMPONENT_ALPHA;
506 }
507 mCompositor->DrawDiagnostics(flags,
508 aScreenRegion, aClipRect, aTransform, mFlashCounter);
509 }
510
511 void
RenderLayerBuffer(TiledLayerBufferComposite & aLayerBuffer,const Color * aBackgroundColor,EffectChain & aEffectChain,float aOpacity,const gfx::SamplingFilter aSamplingFilter,const gfx::IntRect & aClipRect,nsIntRegion aVisibleRegion,gfx::Matrix4x4 aTransform)512 TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
513 const Color* aBackgroundColor,
514 EffectChain& aEffectChain,
515 float aOpacity,
516 const gfx::SamplingFilter aSamplingFilter,
517 const gfx::IntRect& aClipRect,
518 nsIntRegion aVisibleRegion,
519 gfx::Matrix4x4 aTransform)
520 {
521 if (!mCompositor) {
522 NS_WARNING("Can't render tiled content host - no compositor");
523 return;
524 }
525 float resolution = aLayerBuffer.GetResolution();
526 gfx::Size layerScale(1, 1);
527
528 // We assume that the current frame resolution is the one used in our high
529 // precision layer buffer. Compensate for a changing frame resolution when
530 // rendering the low precision buffer.
531 if (aLayerBuffer.GetFrameResolution() != mTiledBuffer.GetFrameResolution()) {
532 const CSSToParentLayerScale2D& layerResolution = aLayerBuffer.GetFrameResolution();
533 const CSSToParentLayerScale2D& localResolution = mTiledBuffer.GetFrameResolution();
534 layerScale.width = layerResolution.xScale / localResolution.xScale;
535 layerScale.height = layerResolution.yScale / localResolution.yScale;
536 aVisibleRegion.ScaleRoundOut(layerScale.width, layerScale.height);
537 }
538
539 // Make sure we don't render at low resolution where we have valid high
540 // resolution content, to avoid overdraw and artifacts with semi-transparent
541 // layers.
542 nsIntRegion maskRegion;
543 if (resolution != mTiledBuffer.GetResolution()) {
544 maskRegion = mTiledBuffer.GetValidRegion();
545 // XXX This should be ScaleRoundIn, but there is no such function on
546 // nsIntRegion.
547 maskRegion.ScaleRoundOut(layerScale.width, layerScale.height);
548 }
549
550 // Make sure the resolution and difference in frame resolution are accounted
551 // for in the layer transform.
552 aTransform.PreScale(1/(resolution * layerScale.width),
553 1/(resolution * layerScale.height), 1);
554
555 DiagnosticFlags componentAlphaDiagnostic = DiagnosticFlags::NO_DIAGNOSTIC;
556
557 nsIntRegion compositeRegion = aLayerBuffer.GetValidRegion();
558 compositeRegion.AndWith(aVisibleRegion);
559 compositeRegion.SubOut(maskRegion);
560
561 IntRect visibleRect = aVisibleRegion.GetBounds();
562
563 if (compositeRegion.IsEmpty()) {
564 return;
565 }
566
567 if (aBackgroundColor) {
568 nsIntRegion backgroundRegion = compositeRegion;
569 backgroundRegion.ScaleRoundOut(resolution, resolution);
570 EffectChain effect;
571 effect.mPrimaryEffect = new EffectSolidColor(*aBackgroundColor);
572 for (auto iter = backgroundRegion.RectIter(); !iter.Done(); iter.Next()) {
573 const IntRect& rect = iter.Get();
574 Rect graphicsRect(rect.x, rect.y, rect.width, rect.height);
575 mCompositor->DrawQuad(graphicsRect, aClipRect, effect, 1.0, aTransform);
576 }
577 }
578
579 for (size_t i = 0; i < aLayerBuffer.GetTileCount(); ++i) {
580 TileHost& tile = aLayerBuffer.GetTile(i);
581 if (tile.IsPlaceholderTile()) {
582 continue;
583 }
584
585 TileIntPoint tilePosition = aLayerBuffer.GetPlacement().TilePosition(i);
586 // A sanity check that catches a lot of mistakes.
587 MOZ_ASSERT(tilePosition.x == tile.mTilePosition.x && tilePosition.y == tile.mTilePosition.y);
588
589 IntPoint tileOffset = aLayerBuffer.GetTileOffset(tilePosition);
590 nsIntRegion tileDrawRegion = IntRect(tileOffset, aLayerBuffer.GetScaledTileSize());
591 tileDrawRegion.AndWith(compositeRegion);
592
593 if (tileDrawRegion.IsEmpty()) {
594 continue;
595 }
596
597 tileDrawRegion.ScaleRoundOut(resolution, resolution);
598 RenderTile(tile, aEffectChain, aOpacity,
599 aTransform, aSamplingFilter, aClipRect, tileDrawRegion,
600 tileOffset * resolution, aLayerBuffer.GetTileSize(),
601 gfx::Rect(visibleRect.x, visibleRect.y,
602 visibleRect.width, visibleRect.height));
603 if (tile.mTextureHostOnWhite) {
604 componentAlphaDiagnostic = DiagnosticFlags::COMPONENT_ALPHA;
605 }
606 }
607
608 gfx::Rect rect(visibleRect.x, visibleRect.y,
609 visibleRect.width, visibleRect.height);
610 GetCompositor()->DrawDiagnostics(DiagnosticFlags::CONTENT | componentAlphaDiagnostic,
611 rect, aClipRect, aTransform, mFlashCounter);
612 }
613
614 void
PrintInfo(std::stringstream & aStream,const char * aPrefix)615 TiledContentHost::PrintInfo(std::stringstream& aStream, const char* aPrefix)
616 {
617 aStream << aPrefix;
618 aStream << nsPrintfCString("TiledContentHost (0x%p)", this).get();
619
620 if (gfxPrefs::LayersDumpTexture() || profiler_feature_active("layersdump")) {
621 nsAutoCString pfx(aPrefix);
622 pfx += " ";
623
624 Dump(aStream, pfx.get(), false);
625 }
626 }
627
628 void
Dump(std::stringstream & aStream,const char * aPrefix,bool aDumpHtml)629 TiledContentHost::Dump(std::stringstream& aStream,
630 const char* aPrefix,
631 bool aDumpHtml)
632 {
633 mTiledBuffer.Dump(aStream, aPrefix, aDumpHtml,
634 TextureDumpMode::DoNotCompress /* compression not supported on host side */);
635 }
636
637 void
AddAnimationInvalidation(nsIntRegion & aRegion)638 TiledContentHost::AddAnimationInvalidation(nsIntRegion& aRegion)
639 {
640 return mTiledBuffer.AddAnimationInvalidation(aRegion);
641 }
642
643
644 } // namespace layers
645 } // namespace mozilla
646