|
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 "LayerManagerComposite.h" |
|
7 #include <stddef.h> // for size_t |
|
8 #include <stdint.h> // for uint16_t, uint32_t |
|
9 #include "CanvasLayerComposite.h" // for CanvasLayerComposite |
|
10 #include "ColorLayerComposite.h" // for ColorLayerComposite |
|
11 #include "Composer2D.h" // for Composer2D |
|
12 #include "CompositableHost.h" // for CompositableHost |
|
13 #include "ContainerLayerComposite.h" // for ContainerLayerComposite, etc |
|
14 #include "FPSCounter.h" // for FPSState, FPSCounter |
|
15 #include "FrameMetrics.h" // for FrameMetrics |
|
16 #include "GeckoProfiler.h" // for profiler_set_frame_number, etc |
|
17 #include "ImageLayerComposite.h" // for ImageLayerComposite |
|
18 #include "Layers.h" // for Layer, ContainerLayer, etc |
|
19 #include "ThebesLayerComposite.h" // for ThebesLayerComposite |
|
20 #include "TiledLayerBuffer.h" // for TiledLayerComposer |
|
21 #include "Units.h" // for ScreenIntRect |
|
22 #include "gfx2DGlue.h" // for ToMatrix4x4 |
|
23 #include "gfx3DMatrix.h" // for gfx3DMatrix |
|
24 #include "gfxPrefs.h" // for gfxPrefs |
|
25 #ifdef XP_MACOSX |
|
26 #include "gfxPlatformMac.h" |
|
27 #endif |
|
28 #include "gfxRect.h" // for gfxRect |
|
29 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc |
|
30 #include "mozilla/RefPtr.h" // for RefPtr, TemporaryRef |
|
31 #include "mozilla/gfx/2D.h" // for DrawTarget |
|
32 #include "mozilla/gfx/Matrix.h" // for Matrix4x4 |
|
33 #include "mozilla/gfx/Point.h" // for IntSize, Point |
|
34 #include "mozilla/gfx/Rect.h" // for Rect |
|
35 #include "mozilla/gfx/Types.h" // for Color, SurfaceFormat |
|
36 #include "mozilla/layers/Compositor.h" // for Compositor |
|
37 #include "mozilla/layers/CompositorTypes.h" |
|
38 #include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc |
|
39 #include "mozilla/layers/LayersTypes.h" // for etc |
|
40 #include "ipc/ShadowLayerUtils.h" |
|
41 #include "mozilla/mozalloc.h" // for operator new, etc |
|
42 #include "nsAutoPtr.h" // for nsRefPtr |
|
43 #include "nsCOMPtr.h" // for already_AddRefed |
|
44 #include "nsDebug.h" // for NS_WARNING, NS_RUNTIMEABORT, etc |
|
45 #include "nsISupportsImpl.h" // for Layer::AddRef, etc |
|
46 #include "nsIWidget.h" // for nsIWidget |
|
47 #include "nsPoint.h" // for nsIntPoint |
|
48 #include "nsRect.h" // for nsIntRect |
|
49 #include "nsRegion.h" // for nsIntRegion, etc |
|
50 #ifdef MOZ_WIDGET_ANDROID |
|
51 #include <android/log.h> |
|
52 #endif |
|
53 #include "GeckoProfiler.h" |
|
54 #include "TextRenderer.h" // for TextRenderer |
|
55 |
|
56 class gfxContext; |
|
57 struct nsIntSize; |
|
58 |
|
59 |
|
60 namespace mozilla { |
|
61 namespace layers { |
|
62 |
|
63 class ImageLayer; |
|
64 |
|
65 using namespace mozilla::gfx; |
|
66 using namespace mozilla::gl; |
|
67 |
|
68 static LayerComposite* |
|
69 ToLayerComposite(Layer* aLayer) |
|
70 { |
|
71 return static_cast<LayerComposite*>(aLayer->ImplData()); |
|
72 } |
|
73 |
|
74 static void ClearSubtree(Layer* aLayer) |
|
75 { |
|
76 ToLayerComposite(aLayer)->CleanupResources(); |
|
77 for (Layer* child = aLayer->GetFirstChild(); child; |
|
78 child = child->GetNextSibling()) { |
|
79 ClearSubtree(child); |
|
80 } |
|
81 } |
|
82 |
|
83 void |
|
84 LayerManagerComposite::ClearCachedResources(Layer* aSubtree) |
|
85 { |
|
86 MOZ_ASSERT(!aSubtree || aSubtree->Manager() == this); |
|
87 Layer* subtree = aSubtree ? aSubtree : mRoot.get(); |
|
88 if (!subtree) { |
|
89 return; |
|
90 } |
|
91 |
|
92 ClearSubtree(subtree); |
|
93 // FIXME [bjacob] |
|
94 // XXX the old LayerManagerOGL code had a mMaybeInvalidTree that it set to true here. |
|
95 // Do we need that? |
|
96 } |
|
97 |
|
98 /** |
|
99 * LayerManagerComposite |
|
100 */ |
|
101 LayerManagerComposite::LayerManagerComposite(Compositor* aCompositor) |
|
102 : mCompositor(aCompositor) |
|
103 , mInTransaction(false) |
|
104 , mIsCompositorReady(false) |
|
105 , mDebugOverlayWantsNextFrame(false) |
|
106 , mGeometryChanged(true) |
|
107 { |
|
108 mTextRenderer = new TextRenderer(aCompositor); |
|
109 MOZ_ASSERT(aCompositor); |
|
110 } |
|
111 |
|
112 LayerManagerComposite::~LayerManagerComposite() |
|
113 { |
|
114 Destroy(); |
|
115 } |
|
116 |
|
117 |
|
118 bool |
|
119 LayerManagerComposite::Initialize() |
|
120 { |
|
121 bool result = mCompositor->Initialize(); |
|
122 return result; |
|
123 } |
|
124 |
|
125 void |
|
126 LayerManagerComposite::Destroy() |
|
127 { |
|
128 if (!mDestroyed) { |
|
129 mCompositor->GetWidget()->CleanupWindowEffects(); |
|
130 if (mRoot) { |
|
131 RootLayer()->Destroy(); |
|
132 } |
|
133 mRoot = nullptr; |
|
134 |
|
135 mCompositor->Destroy(); |
|
136 |
|
137 mDestroyed = true; |
|
138 } |
|
139 } |
|
140 |
|
141 void |
|
142 LayerManagerComposite::UpdateRenderBounds(const nsIntRect& aRect) |
|
143 { |
|
144 mRenderBounds = aRect; |
|
145 } |
|
146 |
|
147 void |
|
148 LayerManagerComposite::BeginTransaction() |
|
149 { |
|
150 mInTransaction = true; |
|
151 |
|
152 if (!mCompositor->Ready()) { |
|
153 return; |
|
154 } |
|
155 |
|
156 mIsCompositorReady = true; |
|
157 |
|
158 if (Compositor::GetBackend() == LayersBackend::LAYERS_OPENGL || |
|
159 Compositor::GetBackend() == LayersBackend::LAYERS_BASIC) { |
|
160 mClonedLayerTreeProperties = LayerProperties::CloneFrom(GetRoot()); |
|
161 } |
|
162 } |
|
163 |
|
164 void |
|
165 LayerManagerComposite::BeginTransactionWithDrawTarget(DrawTarget* aTarget) |
|
166 { |
|
167 mInTransaction = true; |
|
168 |
|
169 if (!mCompositor->Ready()) { |
|
170 return; |
|
171 } |
|
172 |
|
173 #ifdef MOZ_LAYERS_HAVE_LOG |
|
174 MOZ_LAYERS_LOG(("[----- BeginTransaction")); |
|
175 Log(); |
|
176 #endif |
|
177 |
|
178 if (mDestroyed) { |
|
179 NS_WARNING("Call on destroyed layer manager"); |
|
180 return; |
|
181 } |
|
182 |
|
183 mIsCompositorReady = true; |
|
184 mCompositor->SetTargetContext(aTarget); |
|
185 mTarget = aTarget; |
|
186 } |
|
187 |
|
188 bool |
|
189 LayerManagerComposite::EndEmptyTransaction(EndTransactionFlags aFlags) |
|
190 { |
|
191 NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?"); |
|
192 if (!mRoot) { |
|
193 mInTransaction = false; |
|
194 mIsCompositorReady = false; |
|
195 return false; |
|
196 } |
|
197 |
|
198 EndTransaction(nullptr, nullptr); |
|
199 return true; |
|
200 } |
|
201 |
|
202 void |
|
203 LayerManagerComposite::EndTransaction(DrawThebesLayerCallback aCallback, |
|
204 void* aCallbackData, |
|
205 EndTransactionFlags aFlags) |
|
206 { |
|
207 NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?"); |
|
208 NS_ASSERTION(!aCallback && !aCallbackData, "Not expecting callbacks here"); |
|
209 mInTransaction = false; |
|
210 |
|
211 if (!mIsCompositorReady) { |
|
212 return; |
|
213 } |
|
214 mIsCompositorReady = false; |
|
215 |
|
216 #ifdef MOZ_LAYERS_HAVE_LOG |
|
217 MOZ_LAYERS_LOG((" ----- (beginning paint)")); |
|
218 Log(); |
|
219 #endif |
|
220 |
|
221 if (mDestroyed) { |
|
222 NS_WARNING("Call on destroyed layer manager"); |
|
223 return; |
|
224 } |
|
225 |
|
226 if (mRoot && mClonedLayerTreeProperties) { |
|
227 nsIntRegion invalid = |
|
228 mClonedLayerTreeProperties->ComputeDifferences(mRoot, nullptr, &mGeometryChanged); |
|
229 mClonedLayerTreeProperties = nullptr; |
|
230 |
|
231 mInvalidRegion.Or(mInvalidRegion, invalid); |
|
232 } else { |
|
233 mInvalidRegion.Or(mInvalidRegion, mRenderBounds); |
|
234 } |
|
235 |
|
236 if (mRoot && !(aFlags & END_NO_IMMEDIATE_REDRAW)) { |
|
237 if (aFlags & END_NO_COMPOSITE) { |
|
238 // Apply pending tree updates before recomputing effective |
|
239 // properties. |
|
240 mRoot->ApplyPendingUpdatesToSubtree(); |
|
241 } |
|
242 |
|
243 // The results of our drawing always go directly into a pixel buffer, |
|
244 // so we don't need to pass any global transform here. |
|
245 mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4()); |
|
246 |
|
247 Render(); |
|
248 mGeometryChanged = false; |
|
249 } |
|
250 |
|
251 mCompositor->SetTargetContext(nullptr); |
|
252 mTarget = nullptr; |
|
253 |
|
254 #ifdef MOZ_LAYERS_HAVE_LOG |
|
255 Log(); |
|
256 MOZ_LAYERS_LOG(("]----- EndTransaction")); |
|
257 #endif |
|
258 } |
|
259 |
|
260 TemporaryRef<DrawTarget> |
|
261 LayerManagerComposite::CreateOptimalMaskDrawTarget(const IntSize &aSize) |
|
262 { |
|
263 NS_RUNTIMEABORT("Should only be called on the drawing side"); |
|
264 return nullptr; |
|
265 } |
|
266 |
|
267 already_AddRefed<ThebesLayer> |
|
268 LayerManagerComposite::CreateThebesLayer() |
|
269 { |
|
270 NS_RUNTIMEABORT("Should only be called on the drawing side"); |
|
271 return nullptr; |
|
272 } |
|
273 |
|
274 already_AddRefed<ContainerLayer> |
|
275 LayerManagerComposite::CreateContainerLayer() |
|
276 { |
|
277 NS_RUNTIMEABORT("Should only be called on the drawing side"); |
|
278 return nullptr; |
|
279 } |
|
280 |
|
281 already_AddRefed<ImageLayer> |
|
282 LayerManagerComposite::CreateImageLayer() |
|
283 { |
|
284 NS_RUNTIMEABORT("Should only be called on the drawing side"); |
|
285 return nullptr; |
|
286 } |
|
287 |
|
288 already_AddRefed<ColorLayer> |
|
289 LayerManagerComposite::CreateColorLayer() |
|
290 { |
|
291 NS_RUNTIMEABORT("Should only be called on the drawing side"); |
|
292 return nullptr; |
|
293 } |
|
294 |
|
295 already_AddRefed<CanvasLayer> |
|
296 LayerManagerComposite::CreateCanvasLayer() |
|
297 { |
|
298 NS_RUNTIMEABORT("Should only be called on the drawing side"); |
|
299 return nullptr; |
|
300 } |
|
301 |
|
302 LayerComposite* |
|
303 LayerManagerComposite::RootLayer() const |
|
304 { |
|
305 if (mDestroyed) { |
|
306 NS_WARNING("Call on destroyed layer manager"); |
|
307 return nullptr; |
|
308 } |
|
309 |
|
310 return ToLayerComposite(mRoot); |
|
311 } |
|
312 |
|
313 // Size of the builtin font. |
|
314 static const float FontHeight = 7.f; |
|
315 static const float FontWidth = 4.f; |
|
316 static const float FontStride = 4.f; |
|
317 |
|
318 // Scale the font when drawing it to the viewport for better readability. |
|
319 static const float FontScaleX = 2.f; |
|
320 static const float FontScaleY = 3.f; |
|
321 |
|
322 static void DrawDigits(unsigned int aValue, |
|
323 int aOffsetX, int aOffsetY, |
|
324 Compositor* aCompositor, |
|
325 EffectChain& aEffectChain) |
|
326 { |
|
327 if (aValue > 999) { |
|
328 aValue = 999; |
|
329 } |
|
330 |
|
331 unsigned int divisor = 100; |
|
332 float textureWidth = FontWidth * 10; |
|
333 gfx::Float opacity = 1; |
|
334 gfx::Matrix4x4 transform; |
|
335 transform.Scale(FontScaleX, FontScaleY, 1); |
|
336 |
|
337 for (size_t n = 0; n < 3; ++n) { |
|
338 unsigned int digit = aValue % (divisor * 10) / divisor; |
|
339 divisor /= 10; |
|
340 |
|
341 RefPtr<TexturedEffect> texturedEffect = static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get()); |
|
342 texturedEffect->mTextureCoords = Rect(float(digit * FontWidth) / textureWidth, 0, FontWidth / textureWidth, 1.0f); |
|
343 |
|
344 Rect drawRect = Rect(aOffsetX + n * FontWidth, aOffsetY, FontWidth, FontHeight); |
|
345 Rect clipRect = Rect(0, 0, 300, 100); |
|
346 aCompositor->DrawQuad(drawRect, clipRect, |
|
347 aEffectChain, opacity, transform); |
|
348 } |
|
349 } |
|
350 |
|
351 void FPSState::DrawFPS(TimeStamp aNow, |
|
352 unsigned int aFillRatio, |
|
353 Compositor* aCompositor) |
|
354 { |
|
355 if (!mFPSTextureSource) { |
|
356 const char *text = |
|
357 " " |
|
358 " XXX XX XXX XXX X X XXX XXX XXX XXX XXX" |
|
359 " X X X X X X X X X X X X X X" |
|
360 " X X X XXX XXX XXX XXX XXX X XXX XXX" |
|
361 " X X X X X X X X X X X X X" |
|
362 " XXX XXX XXX XXX X XXX XXX X XXX X" |
|
363 " "; |
|
364 |
|
365 // Convert the text encoding above to RGBA. |
|
366 int w = FontWidth * 10; |
|
367 int h = FontHeight; |
|
368 uint32_t* buf = (uint32_t *) malloc(w * h * sizeof(uint32_t)); |
|
369 for (int i = 0; i < h; i++) { |
|
370 for (int j = 0; j < w; j++) { |
|
371 uint32_t purple = 0xfff000ff; |
|
372 uint32_t white = 0xffffffff; |
|
373 buf[i * w + j] = (text[i * w + j] == ' ') ? purple : white; |
|
374 } |
|
375 } |
|
376 |
|
377 int bytesPerPixel = 4; |
|
378 RefPtr<DataSourceSurface> fpsSurface = Factory::CreateWrappingDataSourceSurface( |
|
379 reinterpret_cast<uint8_t*>(buf), w * bytesPerPixel, IntSize(w, h), SurfaceFormat::B8G8R8A8); |
|
380 mFPSTextureSource = aCompositor->CreateDataTextureSource(); |
|
381 mFPSTextureSource->Update(fpsSurface); |
|
382 } |
|
383 |
|
384 EffectChain effectChain; |
|
385 effectChain.mPrimaryEffect = CreateTexturedEffect(SurfaceFormat::B8G8R8A8, mFPSTextureSource, Filter::POINT); |
|
386 |
|
387 unsigned int fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow)); |
|
388 unsigned int txnFps = unsigned(mTransactionFps.GetFpsAt(aNow)); |
|
389 |
|
390 DrawDigits(fps, 0, 0, aCompositor, effectChain); |
|
391 DrawDigits(txnFps, FontWidth * 4, 0, aCompositor, effectChain); |
|
392 DrawDigits(aFillRatio, FontWidth * 8, 0, aCompositor, effectChain); |
|
393 } |
|
394 |
|
395 static uint16_t sFrameCount = 0; |
|
396 void |
|
397 LayerManagerComposite::RenderDebugOverlay(const Rect& aBounds) |
|
398 { |
|
399 if (gfxPrefs::LayersDrawFPS()) { |
|
400 if (!mFPS) { |
|
401 mFPS = new FPSState(); |
|
402 } |
|
403 |
|
404 float fillRatio = mCompositor->GetFillRatio(); |
|
405 mFPS->DrawFPS(TimeStamp::Now(), unsigned(fillRatio), mCompositor); |
|
406 } else { |
|
407 mFPS = nullptr; |
|
408 } |
|
409 |
|
410 if (gfxPrefs::DrawFrameCounter()) { |
|
411 profiler_set_frame_number(sFrameCount); |
|
412 |
|
413 uint16_t frameNumber = sFrameCount; |
|
414 const uint16_t bitWidth = 3; |
|
415 float opacity = 1.0; |
|
416 gfx::Rect clip(0,0, bitWidth*16, bitWidth); |
|
417 for (size_t i = 0; i < 16; i++) { |
|
418 |
|
419 gfx::Color bitColor; |
|
420 if ((frameNumber >> i) & 0x1) { |
|
421 bitColor = gfx::Color(0, 0, 0, 1.0); |
|
422 } else { |
|
423 bitColor = gfx::Color(1.0, 1.0, 1.0, 1.0); |
|
424 } |
|
425 EffectChain effects; |
|
426 effects.mPrimaryEffect = new EffectSolidColor(bitColor); |
|
427 mCompositor->DrawQuad(gfx::Rect(bitWidth*i, 0, bitWidth, bitWidth), |
|
428 clip, |
|
429 effects, |
|
430 opacity, |
|
431 gfx::Matrix4x4()); |
|
432 } |
|
433 // We intentionally overflow at 2^16. |
|
434 sFrameCount++; |
|
435 } |
|
436 } |
|
437 |
|
438 void |
|
439 LayerManagerComposite::Render() |
|
440 { |
|
441 PROFILER_LABEL("LayerManagerComposite", "Render"); |
|
442 if (mDestroyed) { |
|
443 NS_WARNING("Call on destroyed layer manager"); |
|
444 return; |
|
445 } |
|
446 |
|
447 if (gfxPrefs::LayersDump()) { |
|
448 this->Dump(); |
|
449 } |
|
450 |
|
451 /** Our more efficient but less powerful alter ego, if one is available. */ |
|
452 nsRefPtr<Composer2D> composer2D = mCompositor->GetWidget()->GetComposer2D(); |
|
453 |
|
454 if (!mTarget && composer2D && composer2D->TryRender(mRoot, mWorldMatrix, mGeometryChanged)) { |
|
455 if (mFPS) { |
|
456 double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now()); |
|
457 if (gfxPrefs::LayersDrawFPS()) { |
|
458 printf_stderr("HWComposer: FPS is %g\n", fps); |
|
459 } |
|
460 } |
|
461 mCompositor->EndFrameForExternalComposition(mWorldMatrix); |
|
462 return; |
|
463 } |
|
464 |
|
465 { |
|
466 PROFILER_LABEL("LayerManagerComposite", "PreRender"); |
|
467 if (!mCompositor->GetWidget()->PreRender(this)) { |
|
468 return; |
|
469 } |
|
470 } |
|
471 |
|
472 nsIntRect clipRect; |
|
473 Rect bounds(mRenderBounds.x, mRenderBounds.y, mRenderBounds.width, mRenderBounds.height); |
|
474 Rect actualBounds; |
|
475 if (mRoot->GetClipRect()) { |
|
476 clipRect = *mRoot->GetClipRect(); |
|
477 WorldTransformRect(clipRect); |
|
478 Rect rect(clipRect.x, clipRect.y, clipRect.width, clipRect.height); |
|
479 mCompositor->BeginFrame(mInvalidRegion, &rect, mWorldMatrix, bounds, nullptr, &actualBounds); |
|
480 } else { |
|
481 gfx::Rect rect; |
|
482 mCompositor->BeginFrame(mInvalidRegion, nullptr, mWorldMatrix, bounds, &rect, &actualBounds); |
|
483 clipRect = nsIntRect(rect.x, rect.y, rect.width, rect.height); |
|
484 } |
|
485 |
|
486 // Reset the invalid region now that we've begun compositing. |
|
487 mInvalidRegion.SetEmpty(); |
|
488 |
|
489 if (actualBounds.IsEmpty()) { |
|
490 mCompositor->GetWidget()->PostRender(this); |
|
491 return; |
|
492 } |
|
493 |
|
494 // Allow widget to render a custom background. |
|
495 mCompositor->GetWidget()->DrawWindowUnderlay(this, nsIntRect(actualBounds.x, |
|
496 actualBounds.y, |
|
497 actualBounds.width, |
|
498 actualBounds.height)); |
|
499 |
|
500 // Render our layers. |
|
501 RootLayer()->RenderLayer(clipRect); |
|
502 |
|
503 if (!mRegionToClear.IsEmpty()) { |
|
504 nsIntRegionRectIterator iter(mRegionToClear); |
|
505 const nsIntRect *r; |
|
506 while ((r = iter.Next())) { |
|
507 mCompositor->ClearRect(Rect(r->x, r->y, r->width, r->height)); |
|
508 } |
|
509 } |
|
510 |
|
511 // Allow widget to render a custom foreground. |
|
512 mCompositor->GetWidget()->DrawWindowOverlay(this, nsIntRect(actualBounds.x, |
|
513 actualBounds.y, |
|
514 actualBounds.width, |
|
515 actualBounds.height)); |
|
516 |
|
517 // Debugging |
|
518 RenderDebugOverlay(actualBounds); |
|
519 |
|
520 { |
|
521 PROFILER_LABEL("LayerManagerComposite", "EndFrame"); |
|
522 mCompositor->EndFrame(); |
|
523 mCompositor->SetFBAcquireFence(mRoot); |
|
524 } |
|
525 |
|
526 mCompositor->GetWidget()->PostRender(this); |
|
527 |
|
528 RecordFrame(); |
|
529 } |
|
530 |
|
531 void |
|
532 LayerManagerComposite::SetWorldTransform(const gfx::Matrix& aMatrix) |
|
533 { |
|
534 NS_ASSERTION(aMatrix.PreservesAxisAlignedRectangles(), |
|
535 "SetWorldTransform only accepts matrices that satisfy PreservesAxisAlignedRectangles"); |
|
536 NS_ASSERTION(!aMatrix.HasNonIntegerScale(), |
|
537 "SetWorldTransform only accepts matrices with integer scale"); |
|
538 |
|
539 mWorldMatrix = aMatrix; |
|
540 } |
|
541 |
|
542 gfx::Matrix& |
|
543 LayerManagerComposite::GetWorldTransform(void) |
|
544 { |
|
545 return mWorldMatrix; |
|
546 } |
|
547 |
|
548 void |
|
549 LayerManagerComposite::WorldTransformRect(nsIntRect& aRect) |
|
550 { |
|
551 gfx::Rect grect(aRect.x, aRect.y, aRect.width, aRect.height); |
|
552 grect = mWorldMatrix.TransformBounds(grect); |
|
553 aRect.SetRect(grect.X(), grect.Y(), grect.Width(), grect.Height()); |
|
554 } |
|
555 |
|
556 static void |
|
557 SubtractTransformedRegion(nsIntRegion& aRegion, |
|
558 const nsIntRegion& aRegionToSubtract, |
|
559 const gfx3DMatrix& aTransform) |
|
560 { |
|
561 if (aRegionToSubtract.IsEmpty()) { |
|
562 return; |
|
563 } |
|
564 |
|
565 // For each rect in the region, find out its bounds in screen space and |
|
566 // subtract it from the screen region. |
|
567 nsIntRegionRectIterator it(aRegionToSubtract); |
|
568 while (const nsIntRect* rect = it.Next()) { |
|
569 gfxRect incompleteRect = aTransform.TransformBounds(gfxRect(*rect)); |
|
570 aRegion.Sub(aRegion, nsIntRect(incompleteRect.x, |
|
571 incompleteRect.y, |
|
572 incompleteRect.width, |
|
573 incompleteRect.height)); |
|
574 } |
|
575 } |
|
576 |
|
577 /* static */ void |
|
578 LayerManagerComposite::ComputeRenderIntegrityInternal(Layer* aLayer, |
|
579 nsIntRegion& aScreenRegion, |
|
580 nsIntRegion& aLowPrecisionScreenRegion, |
|
581 const gfx3DMatrix& aTransform) |
|
582 { |
|
583 if (aLayer->GetOpacity() <= 0.f || |
|
584 (aScreenRegion.IsEmpty() && aLowPrecisionScreenRegion.IsEmpty())) { |
|
585 return; |
|
586 } |
|
587 |
|
588 // If the layer's a container, recurse into all of its children |
|
589 ContainerLayer* container = aLayer->AsContainerLayer(); |
|
590 if (container) { |
|
591 // Accumulate the transform of intermediate surfaces |
|
592 gfx3DMatrix transform = aTransform; |
|
593 if (container->UseIntermediateSurface()) { |
|
594 gfx::To3DMatrix(aLayer->GetEffectiveTransform(), transform); |
|
595 transform.PreMultiply(aTransform); |
|
596 } |
|
597 for (Layer* child = aLayer->GetFirstChild(); child; |
|
598 child = child->GetNextSibling()) { |
|
599 ComputeRenderIntegrityInternal(child, aScreenRegion, aLowPrecisionScreenRegion, transform); |
|
600 } |
|
601 return; |
|
602 } |
|
603 |
|
604 // Only thebes layers can be incomplete |
|
605 ThebesLayer* thebesLayer = aLayer->AsThebesLayer(); |
|
606 if (!thebesLayer) { |
|
607 return; |
|
608 } |
|
609 |
|
610 // See if there's any incomplete rendering |
|
611 nsIntRegion incompleteRegion = aLayer->GetEffectiveVisibleRegion(); |
|
612 incompleteRegion.Sub(incompleteRegion, thebesLayer->GetValidRegion()); |
|
613 |
|
614 if (!incompleteRegion.IsEmpty()) { |
|
615 // Calculate the transform to get between screen and layer space |
|
616 gfx3DMatrix transformToScreen; |
|
617 To3DMatrix(aLayer->GetEffectiveTransform(), transformToScreen); |
|
618 transformToScreen.PreMultiply(aTransform); |
|
619 |
|
620 SubtractTransformedRegion(aScreenRegion, incompleteRegion, transformToScreen); |
|
621 |
|
622 // See if there's any incomplete low-precision rendering |
|
623 TiledLayerComposer* composer = nullptr; |
|
624 LayerComposite* shadow = aLayer->AsLayerComposite(); |
|
625 if (shadow) { |
|
626 composer = shadow->GetTiledLayerComposer(); |
|
627 if (composer) { |
|
628 incompleteRegion.Sub(incompleteRegion, composer->GetValidLowPrecisionRegion()); |
|
629 if (!incompleteRegion.IsEmpty()) { |
|
630 SubtractTransformedRegion(aLowPrecisionScreenRegion, incompleteRegion, transformToScreen); |
|
631 } |
|
632 } |
|
633 } |
|
634 |
|
635 // If we can't get a valid low precision region, assume it's the same as |
|
636 // the high precision region. |
|
637 if (!composer) { |
|
638 SubtractTransformedRegion(aLowPrecisionScreenRegion, incompleteRegion, transformToScreen); |
|
639 } |
|
640 } |
|
641 } |
|
642 |
|
643 #ifdef MOZ_ANDROID_OMTC |
|
644 static float |
|
645 GetDisplayportCoverage(const CSSRect& aDisplayPort, |
|
646 const gfx3DMatrix& aTransformToScreen, |
|
647 const nsIntRect& aScreenRect) |
|
648 { |
|
649 gfxRect transformedDisplayport = |
|
650 aTransformToScreen.TransformBounds(gfxRect(aDisplayPort.x, |
|
651 aDisplayPort.y, |
|
652 aDisplayPort.width, |
|
653 aDisplayPort.height)); |
|
654 transformedDisplayport.RoundOut(); |
|
655 nsIntRect displayport = nsIntRect(transformedDisplayport.x, |
|
656 transformedDisplayport.y, |
|
657 transformedDisplayport.width, |
|
658 transformedDisplayport.height); |
|
659 if (!displayport.Contains(aScreenRect)) { |
|
660 nsIntRegion coveredRegion; |
|
661 coveredRegion.And(aScreenRect, displayport); |
|
662 return coveredRegion.Area() / (float)(aScreenRect.width * aScreenRect.height); |
|
663 } |
|
664 |
|
665 return 1.0f; |
|
666 } |
|
667 #endif // MOZ_ANDROID_OMTC |
|
668 |
|
669 float |
|
670 LayerManagerComposite::ComputeRenderIntegrity() |
|
671 { |
|
672 // We only ever have incomplete rendering when progressive tiles are enabled. |
|
673 Layer* root = GetRoot(); |
|
674 if (!gfxPrefs::UseProgressiveTilePainting() || !root) { |
|
675 return 1.f; |
|
676 } |
|
677 |
|
678 const FrameMetrics& rootMetrics = root->AsContainerLayer()->GetFrameMetrics(); |
|
679 nsIntRect screenRect(rootMetrics.mCompositionBounds.x, |
|
680 rootMetrics.mCompositionBounds.y, |
|
681 rootMetrics.mCompositionBounds.width, |
|
682 rootMetrics.mCompositionBounds.height); |
|
683 |
|
684 float lowPrecisionMultiplier = 1.0f; |
|
685 float highPrecisionMultiplier = 1.0f; |
|
686 |
|
687 #ifdef MOZ_ANDROID_OMTC |
|
688 // Use the transform on the primary scrollable layer and its FrameMetrics |
|
689 // to find out how much of the viewport the current displayport covers |
|
690 Layer* primaryScrollable = GetPrimaryScrollableLayer(); |
|
691 if (primaryScrollable) { |
|
692 // This is derived from the code in |
|
693 // AsyncCompositionManager::TransformScrollableLayer |
|
694 const FrameMetrics& metrics = primaryScrollable->AsContainerLayer()->GetFrameMetrics(); |
|
695 gfx3DMatrix transform; |
|
696 gfx::To3DMatrix(primaryScrollable->GetEffectiveTransform(), transform); |
|
697 transform.ScalePost(metrics.mResolution.scale, metrics.mResolution.scale, 1); |
|
698 |
|
699 // Clip the screen rect to the document bounds |
|
700 gfxRect documentBounds = |
|
701 transform.TransformBounds(gfxRect(metrics.mScrollableRect.x - metrics.GetScrollOffset().x, |
|
702 metrics.mScrollableRect.y - metrics.GetScrollOffset().y, |
|
703 metrics.mScrollableRect.width, |
|
704 metrics.mScrollableRect.height)); |
|
705 documentBounds.RoundOut(); |
|
706 screenRect = screenRect.Intersect(nsIntRect(documentBounds.x, documentBounds.y, |
|
707 documentBounds.width, documentBounds.height)); |
|
708 |
|
709 // If the screen rect is empty, the user has scrolled entirely into |
|
710 // over-scroll and so we can be considered to have full integrity. |
|
711 if (screenRect.IsEmpty()) { |
|
712 return 1.0f; |
|
713 } |
|
714 |
|
715 // Work out how much of the critical display-port covers the screen |
|
716 bool hasLowPrecision = false; |
|
717 if (!metrics.mCriticalDisplayPort.IsEmpty()) { |
|
718 hasLowPrecision = true; |
|
719 highPrecisionMultiplier = |
|
720 GetDisplayportCoverage(metrics.mCriticalDisplayPort, transform, screenRect); |
|
721 } |
|
722 |
|
723 // Work out how much of the display-port covers the screen |
|
724 if (!metrics.mDisplayPort.IsEmpty()) { |
|
725 if (hasLowPrecision) { |
|
726 lowPrecisionMultiplier = |
|
727 GetDisplayportCoverage(metrics.mDisplayPort, transform, screenRect); |
|
728 } else { |
|
729 lowPrecisionMultiplier = highPrecisionMultiplier = |
|
730 GetDisplayportCoverage(metrics.mDisplayPort, transform, screenRect); |
|
731 } |
|
732 } |
|
733 } |
|
734 |
|
735 // If none of the screen is covered, we have zero integrity. |
|
736 if (highPrecisionMultiplier <= 0.0f && lowPrecisionMultiplier <= 0.0f) { |
|
737 return 0.0f; |
|
738 } |
|
739 #endif // MOZ_ANDROID_OMTC |
|
740 |
|
741 nsIntRegion screenRegion(screenRect); |
|
742 nsIntRegion lowPrecisionScreenRegion(screenRect); |
|
743 gfx3DMatrix transform; |
|
744 ComputeRenderIntegrityInternal(root, screenRegion, |
|
745 lowPrecisionScreenRegion, transform); |
|
746 |
|
747 if (!screenRegion.IsEqual(screenRect)) { |
|
748 // Calculate the area of the region. All rects in an nsRegion are |
|
749 // non-overlapping. |
|
750 float screenArea = screenRect.width * screenRect.height; |
|
751 float highPrecisionIntegrity = screenRegion.Area() / screenArea; |
|
752 float lowPrecisionIntegrity = 1.f; |
|
753 if (!lowPrecisionScreenRegion.IsEqual(screenRect)) { |
|
754 lowPrecisionIntegrity = lowPrecisionScreenRegion.Area() / screenArea; |
|
755 } |
|
756 |
|
757 return ((highPrecisionIntegrity * highPrecisionMultiplier) + |
|
758 (lowPrecisionIntegrity * lowPrecisionMultiplier)) / 2; |
|
759 } |
|
760 |
|
761 return 1.f; |
|
762 } |
|
763 |
|
764 already_AddRefed<ThebesLayerComposite> |
|
765 LayerManagerComposite::CreateThebesLayerComposite() |
|
766 { |
|
767 if (mDestroyed) { |
|
768 NS_WARNING("Call on destroyed layer manager"); |
|
769 return nullptr; |
|
770 } |
|
771 return nsRefPtr<ThebesLayerComposite>(new ThebesLayerComposite(this)).forget(); |
|
772 } |
|
773 |
|
774 already_AddRefed<ContainerLayerComposite> |
|
775 LayerManagerComposite::CreateContainerLayerComposite() |
|
776 { |
|
777 if (mDestroyed) { |
|
778 NS_WARNING("Call on destroyed layer manager"); |
|
779 return nullptr; |
|
780 } |
|
781 return nsRefPtr<ContainerLayerComposite>(new ContainerLayerComposite(this)).forget(); |
|
782 } |
|
783 |
|
784 already_AddRefed<ImageLayerComposite> |
|
785 LayerManagerComposite::CreateImageLayerComposite() |
|
786 { |
|
787 if (mDestroyed) { |
|
788 NS_WARNING("Call on destroyed layer manager"); |
|
789 return nullptr; |
|
790 } |
|
791 return nsRefPtr<ImageLayerComposite>(new ImageLayerComposite(this)).forget(); |
|
792 } |
|
793 |
|
794 already_AddRefed<ColorLayerComposite> |
|
795 LayerManagerComposite::CreateColorLayerComposite() |
|
796 { |
|
797 if (LayerManagerComposite::mDestroyed) { |
|
798 NS_WARNING("Call on destroyed layer manager"); |
|
799 return nullptr; |
|
800 } |
|
801 return nsRefPtr<ColorLayerComposite>(new ColorLayerComposite(this)).forget(); |
|
802 } |
|
803 |
|
804 already_AddRefed<CanvasLayerComposite> |
|
805 LayerManagerComposite::CreateCanvasLayerComposite() |
|
806 { |
|
807 if (LayerManagerComposite::mDestroyed) { |
|
808 NS_WARNING("Call on destroyed layer manager"); |
|
809 return nullptr; |
|
810 } |
|
811 return nsRefPtr<CanvasLayerComposite>(new CanvasLayerComposite(this)).forget(); |
|
812 } |
|
813 |
|
814 already_AddRefed<RefLayerComposite> |
|
815 LayerManagerComposite::CreateRefLayerComposite() |
|
816 { |
|
817 if (LayerManagerComposite::mDestroyed) { |
|
818 NS_WARNING("Call on destroyed layer manager"); |
|
819 return nullptr; |
|
820 } |
|
821 return nsRefPtr<RefLayerComposite>(new RefLayerComposite(this)).forget(); |
|
822 } |
|
823 |
|
824 LayerManagerComposite::AutoAddMaskEffect::AutoAddMaskEffect(Layer* aMaskLayer, |
|
825 EffectChain& aEffects, |
|
826 bool aIs3D) |
|
827 : mCompositable(nullptr) |
|
828 { |
|
829 if (!aMaskLayer) { |
|
830 return; |
|
831 } |
|
832 |
|
833 mCompositable = ToLayerComposite(aMaskLayer)->GetCompositableHost(); |
|
834 if (!mCompositable) { |
|
835 NS_WARNING("Mask layer with no compositable host"); |
|
836 return; |
|
837 } |
|
838 |
|
839 if (!mCompositable->AddMaskEffect(aEffects, aMaskLayer->GetEffectiveTransform(), aIs3D)) { |
|
840 mCompositable = nullptr; |
|
841 } |
|
842 } |
|
843 |
|
844 LayerManagerComposite::AutoAddMaskEffect::~AutoAddMaskEffect() |
|
845 { |
|
846 if (!mCompositable) { |
|
847 return; |
|
848 } |
|
849 |
|
850 mCompositable->RemoveMaskEffect(); |
|
851 } |
|
852 |
|
853 TemporaryRef<DrawTarget> |
|
854 LayerManagerComposite::CreateDrawTarget(const IntSize &aSize, |
|
855 SurfaceFormat aFormat) |
|
856 { |
|
857 #ifdef XP_MACOSX |
|
858 // We don't want to accelerate if the surface is too small which indicates |
|
859 // that it's likely used for an icon/static image. We also don't want to |
|
860 // accelerate anything that is above the maximum texture size of weakest gpu. |
|
861 // Safari uses 5000 area as the minimum for acceleration, we decided 64^2 is more logical. |
|
862 bool useAcceleration = aSize.width <= 4096 && aSize.height <= 4096 && |
|
863 aSize.width > 64 && aSize.height > 64 && |
|
864 gfxPlatformMac::GetPlatform()->UseAcceleratedCanvas(); |
|
865 if (useAcceleration) { |
|
866 return Factory::CreateDrawTarget(BackendType::COREGRAPHICS_ACCELERATED, |
|
867 aSize, aFormat); |
|
868 } |
|
869 #endif |
|
870 return LayerManager::CreateDrawTarget(aSize, aFormat); |
|
871 } |
|
872 |
|
873 LayerComposite::LayerComposite(LayerManagerComposite *aManager) |
|
874 : mCompositeManager(aManager) |
|
875 , mCompositor(aManager->GetCompositor()) |
|
876 , mShadowOpacity(1.0) |
|
877 , mUseShadowClipRect(false) |
|
878 , mShadowTransformSetByAnimation(false) |
|
879 , mDestroyed(false) |
|
880 , mLayerComposited(false) |
|
881 { } |
|
882 |
|
883 LayerComposite::~LayerComposite() |
|
884 { |
|
885 } |
|
886 |
|
887 void |
|
888 LayerComposite::Destroy() |
|
889 { |
|
890 if (!mDestroyed) { |
|
891 mDestroyed = true; |
|
892 CleanupResources(); |
|
893 } |
|
894 } |
|
895 |
|
896 bool |
|
897 LayerManagerComposite::CanUseCanvasLayerForSize(const IntSize &aSize) |
|
898 { |
|
899 return mCompositor->CanUseCanvasLayerForSize(gfx::IntSize(aSize.width, |
|
900 aSize.height)); |
|
901 } |
|
902 |
|
903 void |
|
904 LayerManagerComposite::NotifyShadowTreeTransaction() |
|
905 { |
|
906 if (mFPS) { |
|
907 mFPS->NotifyShadowTreeTransaction(); |
|
908 } |
|
909 } |
|
910 |
|
911 #ifndef MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS |
|
912 |
|
913 /*static*/ bool |
|
914 LayerManagerComposite::SupportsDirectTexturing() |
|
915 { |
|
916 return false; |
|
917 } |
|
918 |
|
919 /*static*/ void |
|
920 LayerManagerComposite::PlatformSyncBeforeReplyUpdate() |
|
921 { |
|
922 } |
|
923 |
|
924 #endif // !defined(MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS) |
|
925 |
|
926 } /* layers */ |
|
927 } /* mozilla */ |