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 #ifndef GFX_LayerManagerComposite_H
7 #define GFX_LayerManagerComposite_H
8
9 #include <stdint.h> // for int32_t, uint32_t
10 #include "GLDefs.h" // for GLenum
11 #include "Layers.h"
12 #include "Units.h" // for ParentLayerIntRect
13 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
14 #include "mozilla/Attributes.h" // for override
15 #include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed
16 #include "mozilla/gfx/2D.h"
17 #include "mozilla/gfx/Point.h" // for IntSize
18 #include "mozilla/gfx/Rect.h" // for Rect
19 #include "mozilla/gfx/Types.h" // for SurfaceFormat
20 #include "mozilla/layers/CompositorTypes.h"
21 #include "mozilla/layers/Effects.h" // for EffectChain
22 #include "mozilla/layers/LayersMessages.h"
23 #include "mozilla/layers/LayersTypes.h" // for LayersBackend, etc
24 #include "mozilla/Maybe.h" // for Maybe
25 #include "mozilla/RefPtr.h"
26 #include "mozilla/UniquePtr.h"
27 #include "nsAString.h"
28 #include "mozilla/RefPtr.h" // for nsRefPtr
29 #include "nsCOMPtr.h" // for already_AddRefed
30 #include "nsDebug.h" // for NS_ASSERTION
31 #include "nsISupportsImpl.h" // for Layer::AddRef, etc
32 #include "nsRect.h" // for mozilla::gfx::IntRect
33 #include "nsRegion.h" // for nsIntRegion
34 #include "nscore.h" // for nsAString, etc
35 #include "LayerTreeInvalidation.h"
36
37 class gfxContext;
38
39 #ifdef XP_WIN
40 #include <windows.h>
41 #endif
42
43 namespace mozilla {
44 namespace gfx {
45 class DrawTarget;
46 } // namespace gfx
47
48 namespace layers {
49
50 class CanvasLayerComposite;
51 class ColorLayerComposite;
52 class CompositableHost;
53 class Compositor;
54 class ContainerLayerComposite;
55 struct EffectChain;
56 class ImageLayer;
57 class ImageLayerComposite;
58 class LayerComposite;
59 class RefLayerComposite;
60 class PaintedLayerComposite;
61 class TextRenderer;
62 class CompositingRenderTarget;
63 struct FPSState;
64 class PaintCounter;
65
66 static const int kVisualWarningDuration = 150; // ms
67
68 class LayerManagerComposite final : public LayerManager
69 {
70 typedef mozilla::gfx::DrawTarget DrawTarget;
71 typedef mozilla::gfx::IntSize IntSize;
72 typedef mozilla::gfx::SurfaceFormat SurfaceFormat;
73
74 public:
75 explicit LayerManagerComposite(Compositor* aCompositor);
76 ~LayerManagerComposite();
77
78 virtual void Destroy() override;
79
80 /**
81 * Sets the clipping region for this layer manager. This is important on
82 * windows because using OGL we no longer have GDI's native clipping. Therefor
83 * widget must tell us what part of the screen is being invalidated,
84 * and we should clip to this.
85 *
86 * \param aClippingRegion Region to clip to. Setting an empty region
87 * will disable clipping.
88 */
SetClippingRegion(const nsIntRegion & aClippingRegion)89 void SetClippingRegion(const nsIntRegion& aClippingRegion)
90 {
91 mClippingRegion = aClippingRegion;
92 }
93
94 /**
95 * LayerManager implementation.
96 */
AsLayerManagerComposite()97 virtual LayerManagerComposite* AsLayerManagerComposite() override
98 {
99 return this;
100 }
101
102 void UpdateRenderBounds(const gfx::IntRect& aRect);
103
104 virtual bool BeginTransaction() override;
BeginTransactionWithTarget(gfxContext * aTarget)105 virtual bool BeginTransactionWithTarget(gfxContext* aTarget) override
106 {
107 MOZ_CRASH("GFX: Use BeginTransactionWithDrawTarget");
108 return false;
109 }
110 void BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget,
111 const gfx::IntRect& aRect);
112
113 virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override
114 {
115 MOZ_CRASH("GFX: Use EndTransaction(aTimeStamp)");
116 return false;
117 }
118 virtual void EndTransaction(DrawPaintedLayerCallback aCallback,
119 void* aCallbackData,
120 EndTransactionFlags aFlags = END_DEFAULT) override
121 {
122 MOZ_CRASH("GFX: Use EndTransaction(aTimeStamp)");
123 }
124 void EndTransaction(const TimeStamp& aTimeStamp,
125 EndTransactionFlags aFlags = END_DEFAULT);
126
SetRoot(Layer * aLayer)127 virtual void SetRoot(Layer* aLayer) override { mRoot = aLayer; }
128
129 // XXX[nrc]: never called, we should move this logic to ClientLayerManager
130 // (bug 946926).
131 virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) override;
132
GetMaxTextureSize()133 virtual int32_t GetMaxTextureSize() const override
134 {
135 MOZ_CRASH("GFX: Call on compositor, not LayerManagerComposite");
136 }
137
138 virtual void ClearCachedResources(Layer* aSubtree = nullptr) override;
139
140 virtual already_AddRefed<PaintedLayer> CreatePaintedLayer() override;
141 virtual already_AddRefed<ContainerLayer> CreateContainerLayer() override;
142 virtual already_AddRefed<ImageLayer> CreateImageLayer() override;
143 virtual already_AddRefed<ColorLayer> CreateColorLayer() override;
144 virtual already_AddRefed<CanvasLayer> CreateCanvasLayer() override;
145 already_AddRefed<PaintedLayerComposite> CreatePaintedLayerComposite();
146 already_AddRefed<ContainerLayerComposite> CreateContainerLayerComposite();
147 already_AddRefed<ImageLayerComposite> CreateImageLayerComposite();
148 already_AddRefed<ColorLayerComposite> CreateColorLayerComposite();
149 already_AddRefed<CanvasLayerComposite> CreateCanvasLayerComposite();
150 already_AddRefed<RefLayerComposite> CreateRefLayerComposite();
151
GetBackendType()152 virtual LayersBackend GetBackendType() override
153 {
154 MOZ_CRASH("GFX: Shouldn't be called for composited layer manager");
155 }
GetBackendName(nsAString & name)156 virtual void GetBackendName(nsAString& name) override
157 {
158 MOZ_CRASH("GFX: Shouldn't be called for composited layer manager");
159 }
160
161 virtual bool AreComponentAlphaLayersEnabled() override;
162
163 virtual already_AddRefed<DrawTarget>
164 CreateOptimalMaskDrawTarget(const IntSize &aSize) override;
165
Name()166 virtual const char* Name() const override { return ""; }
167
168 /**
169 * Post-processes layers before composition. This performs the following:
170 *
171 * - Applies occlusion culling. This restricts the shadow visible region
172 * of layers that are covered with opaque content.
173 * |aOpaqueRegion| is the region already known to be covered with opaque
174 * content, in the post-transform coordinate space of aLayer.
175 *
176 * - Recomputes visible regions to account for async transforms.
177 * Each layer accumulates into |aVisibleRegion| its post-transform
178 * (including async transforms) visible region.
179 */
180 void PostProcessLayers(Layer* aLayer,
181 nsIntRegion& aOpaqueRegion,
182 LayerIntRegion& aVisibleRegion,
183 const Maybe<ParentLayerIntRect>& aClipFromAncestors);
184
185 /**
186 * RAII helper class to add a mask effect with the compositable from aMaskLayer
187 * to the EffectChain aEffect and notify the compositable when we are done.
188 */
189 class AutoAddMaskEffect
190 {
191 public:
192 AutoAddMaskEffect(Layer* aMaskLayer,
193 EffectChain& aEffect);
194 ~AutoAddMaskEffect();
195
Failed()196 bool Failed() const { return mFailed; }
197 private:
198 CompositableHost* mCompositable;
199 bool mFailed;
200 };
201
202 /**
203 * returns true if PlatformAllocBuffer will return a buffer that supports
204 * direct texturing
205 */
206 static bool SupportsDirectTexturing();
207
208 static void PlatformSyncBeforeReplyUpdate();
209
AddInvalidRegion(const nsIntRegion & aRegion)210 void AddInvalidRegion(const nsIntRegion& aRegion)
211 {
212 mInvalidRegion.Or(mInvalidRegion, aRegion);
213 }
214
ClearApproximatelyVisibleRegions(uint64_t aLayersId,const Maybe<uint32_t> & aPresShellId)215 void ClearApproximatelyVisibleRegions(uint64_t aLayersId,
216 const Maybe<uint32_t>& aPresShellId)
217 {
218 for (auto iter = mVisibleRegions.Iter(); !iter.Done(); iter.Next()) {
219 if (iter.Key().mLayersId == aLayersId &&
220 (!aPresShellId || iter.Key().mPresShellId == *aPresShellId)) {
221 iter.Remove();
222 }
223 }
224 }
225
UpdateApproximatelyVisibleRegion(const ScrollableLayerGuid & aGuid,const CSSIntRegion & aRegion)226 void UpdateApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
227 const CSSIntRegion& aRegion)
228 {
229 CSSIntRegion* regionForScrollFrame = mVisibleRegions.LookupOrAdd(aGuid);
230 MOZ_ASSERT(regionForScrollFrame);
231
232 *regionForScrollFrame = aRegion;
233 }
234
GetApproximatelyVisibleRegion(const ScrollableLayerGuid & aGuid)235 CSSIntRegion* GetApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid)
236 {
237 return mVisibleRegions.Get(aGuid);
238 }
239
GetCompositor()240 Compositor* GetCompositor() const
241 {
242 return mCompositor;
243 }
244
245 // Called by CompositorBridgeParent when a new compositor has been created due
246 // to a device reset. The layer manager must clear any cached resources
247 // attached to the old compositor, and make a best effort at ignoring
248 // layer or texture updates against the old compositor.
249 void ChangeCompositor(Compositor* aNewCompositor);
250
251 /**
252 * LayerManagerComposite provides sophisticated debug overlays
253 * that can request a next frame.
254 */
DebugOverlayWantsNextFrame()255 bool DebugOverlayWantsNextFrame() { return mDebugOverlayWantsNextFrame; }
SetDebugOverlayWantsNextFrame(bool aVal)256 void SetDebugOverlayWantsNextFrame(bool aVal)
257 { mDebugOverlayWantsNextFrame = aVal; }
258
259 void NotifyShadowTreeTransaction();
260
GetTextRenderer()261 TextRenderer* GetTextRenderer() { return mTextRenderer; }
262
263 /**
264 * Add an on frame warning.
265 * @param severity ranges from 0 to 1. It's used to compute the warning color.
266 */
VisualFrameWarning(float severity)267 void VisualFrameWarning(float severity) {
268 mozilla::TimeStamp now = TimeStamp::Now();
269 if (mWarnTime.IsNull() ||
270 severity > mWarningLevel ||
271 mWarnTime + TimeDuration::FromMilliseconds(kVisualWarningDuration) < now) {
272 mWarnTime = now;
273 mWarningLevel = severity;
274 }
275 }
276
UnusedApzTransformWarning()277 void UnusedApzTransformWarning() {
278 mUnusedApzTransformWarning = true;
279 }
DisabledApzWarning()280 void DisabledApzWarning() {
281 mDisabledApzWarning = true;
282 }
283
LastFrameMissedHWC()284 bool LastFrameMissedHWC() { return mLastFrameMissedHWC; }
285
286 bool AsyncPanZoomEnabled() const override;
287
AppendImageCompositeNotification(const ImageCompositeNotification & aNotification)288 void AppendImageCompositeNotification(const ImageCompositeNotification& aNotification)
289 {
290 // Only send composite notifications when we're drawing to the screen,
291 // because that's what they mean.
292 // Also when we're not drawing to the screen, DidComposite will not be
293 // called to extract and send these notifications, so they might linger
294 // and contain stale ImageContainerParent pointers.
295 if (!mCompositor->GetTargetContext()) {
296 mImageCompositeNotifications.AppendElement(aNotification);
297 }
298 }
ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotification> * aNotifications)299 void ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotification>* aNotifications)
300 {
301 aNotifications->AppendElements(Move(mImageCompositeNotifications));
302 }
303
304 // Indicate that we need to composite even if nothing in our layers has
305 // changed, so that the widget can draw something different in its window
306 // overlay.
SetWindowOverlayChanged()307 void SetWindowOverlayChanged() { mWindowOverlayChanged = true; }
308
ForcePresent()309 void ForcePresent() { mCompositor->ForcePresent(); }
310
SetPaintTime(const TimeDuration & aPaintTime)311 void SetPaintTime(const TimeDuration& aPaintTime) { mLastPaintTime = aPaintTime; }
312
313 private:
314 /** Region we're clipping our current drawing to. */
315 nsIntRegion mClippingRegion;
316 gfx::IntRect mRenderBounds;
317
318 /** Current root layer. */
319 LayerComposite* RootLayer() const;
320
321 /**
322 * Update the invalid region and render it.
323 */
324 void UpdateAndRender();
325
326 /**
327 * Render the current layer tree to the active target.
328 */
329 void Render(const nsIntRegion& aInvalidRegion, const nsIntRegion& aOpaqueRegion);
330 #if defined(MOZ_WIDGET_ANDROID)
331 void RenderToPresentationSurface();
332 #endif
333
334 /**
335 * We need to know our invalid region before we're ready to render.
336 */
337 void InvalidateDebugOverlay(nsIntRegion& aInvalidRegion, const gfx::IntRect& aBounds);
338
339 /**
340 * Render debug overlays such as the FPS/FrameCounter above the frame.
341 */
342 void RenderDebugOverlay(const gfx::IntRect& aBounds);
343
344
345 RefPtr<CompositingRenderTarget> PushGroupForLayerEffects();
346 void PopGroupForLayerEffects(RefPtr<CompositingRenderTarget> aPreviousTarget,
347 gfx::IntRect aClipRect,
348 bool aGrayscaleEffect,
349 bool aInvertEffect,
350 float aContrastEffect);
351
352 void ChangeCompositorInternal(Compositor* aNewCompositor);
353
354 float mWarningLevel;
355 mozilla::TimeStamp mWarnTime;
356 bool mUnusedApzTransformWarning;
357 bool mDisabledApzWarning;
358 RefPtr<Compositor> mCompositor;
359 UniquePtr<LayerProperties> mClonedLayerTreeProperties;
360
361 nsTArray<ImageCompositeNotification> mImageCompositeNotifications;
362
363 /**
364 * Context target, nullptr when drawing directly to our swap chain.
365 */
366 RefPtr<gfx::DrawTarget> mTarget;
367 gfx::IntRect mTargetBounds;
368
369 nsIntRegion mInvalidRegion;
370
371 typedef nsClassHashtable<nsGenericHashKey<ScrollableLayerGuid>,
372 CSSIntRegion> VisibleRegions;
373 VisibleRegions mVisibleRegions;
374
375 UniquePtr<FPSState> mFPS;
376
377 bool mInTransaction;
378 bool mIsCompositorReady;
379 bool mDebugOverlayWantsNextFrame;
380
381 RefPtr<CompositingRenderTarget> mTwoPassTmpTarget;
382 RefPtr<TextRenderer> mTextRenderer;
383 bool mGeometryChanged;
384
385 // Testing property. If hardware composer is supported, this will return
386 // true if the last frame was deemed 'too complicated' to be rendered.
387 bool mLastFrameMissedHWC;
388
389 bool mWindowOverlayChanged;
390 TimeDuration mLastPaintTime;
391 TimeStamp mRenderStartTime;
392
393 #ifdef USE_SKIA
394 /**
395 * Render paint and composite times above the frame.
396 */
397 void DrawPaintTimes(Compositor* aCompositor);
398 RefPtr<PaintCounter> mPaintCounter;
399 #endif
400 };
401
402 /**
403 * Composite layers are for use with OMTC on the compositor thread only. There
404 * must be corresponding Basic layers on the content thread. For composite
405 * layers, the layer manager only maintains the layer tree, all rendering is
406 * done by a Compositor (see Compositor.h). As such, composite layers are
407 * platform-independent and can be used on any platform for which there is a
408 * Compositor implementation.
409 *
410 * The composite layer tree reflects exactly the basic layer tree. To
411 * composite to screen, the layer manager walks the layer tree calling render
412 * methods which in turn call into their CompositableHosts' Composite methods.
413 * These call Compositor::DrawQuad to do the rendering.
414 *
415 * Mostly, layers are updated during the layers transaction. This is done from
416 * CompositableClient to CompositableHost without interacting with the layer.
417 *
418 * A reference to the Compositor is stored in LayerManagerComposite.
419 */
420 class LayerComposite
421 {
422 public:
423 explicit LayerComposite(LayerManagerComposite* aManager);
424
425 virtual ~LayerComposite();
426
GetFirstChildComposite()427 virtual LayerComposite* GetFirstChildComposite()
428 {
429 return nullptr;
430 }
431
432 /* Do NOT call this from the generic LayerComposite destructor. Only from the
433 * concrete class destructor
434 */
435 virtual void Destroy();
436
437 virtual Layer* GetLayer() = 0;
438
439 virtual void SetLayerManager(LayerManagerComposite* aManager);
440
GetLayerManager()441 LayerManagerComposite* GetLayerManager() const { return mCompositeManager; }
442
443 /**
444 * Perform a first pass over the layer tree to render all of the intermediate
445 * surfaces that we can. This allows us to avoid framebuffer switches in the
446 * middle of our render which is inefficient especially on mobile GPUs. This
447 * must be called before RenderLayer.
448 */
Prepare(const RenderTargetIntRect & aClipRect)449 virtual void Prepare(const RenderTargetIntRect& aClipRect) {}
450
451 // TODO: This should also take RenderTargetIntRect like Prepare.
452 virtual void RenderLayer(const gfx::IntRect& aClipRect) = 0;
453
SetCompositableHost(CompositableHost *)454 virtual bool SetCompositableHost(CompositableHost*)
455 {
456 // We must handle this gracefully, see bug 967824
457 NS_WARNING("called SetCompositableHost for a layer type not accepting a compositable");
458 return false;
459 }
460 virtual CompositableHost* GetCompositableHost() = 0;
461
462 virtual void CleanupResources() = 0;
463
DestroyFrontBuffer()464 virtual void DestroyFrontBuffer() { }
465
466 void AddBlendModeEffect(EffectChain& aEffectChain);
467
GenEffectChain(EffectChain & aEffect)468 virtual void GenEffectChain(EffectChain& aEffect) { }
469
470 /**
471 * The following methods are
472 *
473 * CONSTRUCTION PHASE ONLY
474 *
475 * They are analogous to the Layer interface.
476 */
SetShadowVisibleRegion(const LayerIntRegion & aRegion)477 void SetShadowVisibleRegion(const LayerIntRegion& aRegion)
478 {
479 mShadowVisibleRegion = aRegion;
480 }
481
SetShadowOpacity(float aOpacity)482 void SetShadowOpacity(float aOpacity)
483 {
484 mShadowOpacity = aOpacity;
485 }
SetShadowOpacitySetByAnimation(bool aSetByAnimation)486 void SetShadowOpacitySetByAnimation(bool aSetByAnimation)
487 {
488 mShadowOpacitySetByAnimation = aSetByAnimation;
489 }
490
SetShadowClipRect(const Maybe<ParentLayerIntRect> & aRect)491 void SetShadowClipRect(const Maybe<ParentLayerIntRect>& aRect)
492 {
493 mShadowClipRect = aRect;
494 }
495
SetShadowBaseTransform(const gfx::Matrix4x4 & aMatrix)496 void SetShadowBaseTransform(const gfx::Matrix4x4& aMatrix)
497 {
498 mShadowTransform = aMatrix;
499 }
SetShadowTransformSetByAnimation(bool aSetByAnimation)500 void SetShadowTransformSetByAnimation(bool aSetByAnimation)
501 {
502 mShadowTransformSetByAnimation = aSetByAnimation;
503 }
504
SetLayerComposited(bool value)505 void SetLayerComposited(bool value)
506 {
507 mLayerComposited = value;
508 }
509
SetClearRect(const gfx::IntRect & aRect)510 void SetClearRect(const gfx::IntRect& aRect)
511 {
512 mClearRect = aRect;
513 }
514
515 // These getters can be used anytime.
GetShadowOpacity()516 float GetShadowOpacity() { return mShadowOpacity; }
GetShadowClipRect()517 const Maybe<ParentLayerIntRect>& GetShadowClipRect() { return mShadowClipRect; }
GetShadowVisibleRegion()518 const LayerIntRegion& GetShadowVisibleRegion() { return mShadowVisibleRegion; }
GetShadowBaseTransform()519 const gfx::Matrix4x4& GetShadowBaseTransform() { return mShadowTransform; }
520 gfx::Matrix4x4 GetShadowTransform();
GetShadowTransformSetByAnimation()521 bool GetShadowTransformSetByAnimation() { return mShadowTransformSetByAnimation; }
GetShadowOpacitySetByAnimation()522 bool GetShadowOpacitySetByAnimation() { return mShadowOpacitySetByAnimation; }
HasLayerBeenComposited()523 bool HasLayerBeenComposited() { return mLayerComposited; }
GetClearRect()524 gfx::IntRect GetClearRect() { return mClearRect; }
525
526 // Returns false if the layer is attached to an older compositor.
527 bool HasStaleCompositor() const;
528
529 /**
530 * Return the part of the visible region that has been fully rendered.
531 * While progressive drawing is in progress this region will be
532 * a subset of the shadow visible region.
533 */
534 virtual nsIntRegion GetFullyRenderedRegion();
535
536 /**
537 * Return true if a checkerboarding background color needs to be drawn
538 * for this layer.
539 */
540 bool NeedToDrawCheckerboarding(gfx::Color* aOutCheckerboardingColor = nullptr);
541
542 protected:
543 gfx::Matrix4x4 mShadowTransform;
544 LayerIntRegion mShadowVisibleRegion;
545 Maybe<ParentLayerIntRect> mShadowClipRect;
546 LayerManagerComposite* mCompositeManager;
547 RefPtr<Compositor> mCompositor;
548 float mShadowOpacity;
549 bool mShadowTransformSetByAnimation;
550 bool mShadowOpacitySetByAnimation;
551 bool mDestroyed;
552 bool mLayerComposited;
553 gfx::IntRect mClearRect;
554 };
555
556 // Render aLayer using aCompositor and apply all mask layers of aLayer: The
557 // layer's own mask layer (aLayer->GetMaskLayer()), and any ancestor mask
558 // layers.
559 // If more than one mask layer needs to be applied, we use intermediate surfaces
560 // (CompositingRenderTargets) for rendering, applying one mask layer at a time.
561 // Callers need to provide a callback function aRenderCallback that does the
562 // actual rendering of the source. It needs to have the following form:
563 // void (EffectChain& effectChain, const Rect& clipRect)
564 // aRenderCallback is called exactly once, inside this function, unless aLayer's
565 // visible region is completely clipped out (in that case, aRenderCallback won't
566 // be called at all).
567 // This function calls aLayer->AsLayerComposite()->AddBlendModeEffect for the
568 // final rendering pass.
569 //
570 // (This function should really live in LayerManagerComposite.cpp, but we
571 // need to use templates for passing lambdas until bug 1164522 is resolved.)
572 template<typename RenderCallbackType>
573 void
RenderWithAllMasks(Layer * aLayer,Compositor * aCompositor,const gfx::IntRect & aClipRect,RenderCallbackType aRenderCallback)574 RenderWithAllMasks(Layer* aLayer, Compositor* aCompositor,
575 const gfx::IntRect& aClipRect,
576 RenderCallbackType aRenderCallback)
577 {
578 Layer* firstMask = nullptr;
579 size_t maskLayerCount = 0;
580 size_t nextAncestorMaskLayer = 0;
581
582 size_t ancestorMaskLayerCount = aLayer->GetAncestorMaskLayerCount();
583 if (Layer* ownMask = aLayer->GetMaskLayer()) {
584 firstMask = ownMask;
585 maskLayerCount = ancestorMaskLayerCount + 1;
586 nextAncestorMaskLayer = 0;
587 } else if (ancestorMaskLayerCount > 0) {
588 firstMask = aLayer->GetAncestorMaskLayerAt(0);
589 maskLayerCount = ancestorMaskLayerCount;
590 nextAncestorMaskLayer = 1;
591 } else {
592 // no mask layers at all
593 }
594
595 if (maskLayerCount <= 1) {
596 // This is the common case. Render in one pass and return.
597 EffectChain effectChain(aLayer);
598 LayerManagerComposite::AutoAddMaskEffect
599 autoMaskEffect(firstMask, effectChain);
600 aLayer->AsLayerComposite()->AddBlendModeEffect(effectChain);
601 aRenderCallback(effectChain, aClipRect);
602 return;
603 }
604
605 // We have multiple mask layers.
606 // We split our list of mask layers into three parts:
607 // (1) The first mask
608 // (2) The list of intermediate masks (every mask except first and last)
609 // (3) The final mask.
610 // Part (2) can be empty.
611 // For parts (1) and (2) we need to allocate intermediate surfaces to render
612 // into. The final mask gets rendered into the original render target.
613
614 // Calculate the size of the intermediate surfaces.
615 gfx::Rect visibleRect(aLayer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds());
616 gfx::Matrix4x4 transform = aLayer->GetEffectiveTransform();
617 // TODO: Use RenderTargetIntRect and TransformBy here
618 gfx::IntRect surfaceRect =
619 RoundedOut(transform.TransformAndClipBounds(visibleRect, gfx::Rect(aClipRect)));
620 if (surfaceRect.IsEmpty()) {
621 return;
622 }
623
624 RefPtr<CompositingRenderTarget> originalTarget =
625 aCompositor->GetCurrentRenderTarget();
626
627 RefPtr<CompositingRenderTarget> firstTarget =
628 aCompositor->CreateRenderTarget(surfaceRect, INIT_MODE_CLEAR);
629 if (!firstTarget) {
630 return;
631 }
632
633 // Render the source while applying the first mask.
634 aCompositor->SetRenderTarget(firstTarget);
635 {
636 EffectChain firstEffectChain(aLayer);
637 LayerManagerComposite::AutoAddMaskEffect
638 firstMaskEffect(firstMask, firstEffectChain);
639 aRenderCallback(firstEffectChain, aClipRect - surfaceRect.TopLeft());
640 // firstTarget now contains the transformed source with the first mask and
641 // opacity already applied.
642 }
643
644 // Apply the intermediate masks.
645 gfx::IntRect intermediateClip(surfaceRect - surfaceRect.TopLeft());
646 RefPtr<CompositingRenderTarget> previousTarget = firstTarget;
647 for (size_t i = nextAncestorMaskLayer; i < ancestorMaskLayerCount - 1; i++) {
648 Layer* intermediateMask = aLayer->GetAncestorMaskLayerAt(i);
649 RefPtr<CompositingRenderTarget> intermediateTarget =
650 aCompositor->CreateRenderTarget(surfaceRect, INIT_MODE_CLEAR);
651 if (!intermediateTarget) {
652 break;
653 }
654 aCompositor->SetRenderTarget(intermediateTarget);
655 EffectChain intermediateEffectChain(aLayer);
656 LayerManagerComposite::AutoAddMaskEffect
657 intermediateMaskEffect(intermediateMask, intermediateEffectChain);
658 if (intermediateMaskEffect.Failed()) {
659 continue;
660 }
661 intermediateEffectChain.mPrimaryEffect = new EffectRenderTarget(previousTarget);
662 aCompositor->DrawQuad(gfx::Rect(surfaceRect), intermediateClip,
663 intermediateEffectChain, 1.0, gfx::Matrix4x4());
664 previousTarget = intermediateTarget;
665 }
666
667 aCompositor->SetRenderTarget(originalTarget);
668
669 // Apply the final mask, rendering into originalTarget.
670 EffectChain finalEffectChain(aLayer);
671 finalEffectChain.mPrimaryEffect = new EffectRenderTarget(previousTarget);
672 Layer* finalMask = aLayer->GetAncestorMaskLayerAt(ancestorMaskLayerCount - 1);
673
674 // The blend mode needs to be applied in this final step, because this is
675 // where we're blending with the actual background (which is in originalTarget).
676 aLayer->AsLayerComposite()->AddBlendModeEffect(finalEffectChain);
677 LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(finalMask, finalEffectChain);
678 if (!autoMaskEffect.Failed()) {
679 aCompositor->DrawQuad(gfx::Rect(surfaceRect), aClipRect,
680 finalEffectChain, 1.0, gfx::Matrix4x4());
681 }
682 }
683
684 } // namespace layers
685 } // namespace mozilla
686
687 #endif /* GFX_LayerManagerComposite_H */
688