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