From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- gfx/layers/composite/LayerManagerComposite.h | 687 +++++++++++++++++++++++++++ 1 file changed, 687 insertions(+) create mode 100644 gfx/layers/composite/LayerManagerComposite.h (limited to 'gfx/layers/composite/LayerManagerComposite.h') diff --git a/gfx/layers/composite/LayerManagerComposite.h b/gfx/layers/composite/LayerManagerComposite.h new file mode 100644 index 000000000..8fe7a6b34 --- /dev/null +++ b/gfx/layers/composite/LayerManagerComposite.h @@ -0,0 +1,687 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef GFX_LayerManagerComposite_H +#define GFX_LayerManagerComposite_H + +#include // for int32_t, uint32_t +#include "GLDefs.h" // for GLenum +#include "Layers.h" +#include "Units.h" // for ParentLayerIntRect +#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc +#include "mozilla/Attributes.h" // for override +#include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed +#include "mozilla/gfx/2D.h" +#include "mozilla/gfx/Point.h" // for IntSize +#include "mozilla/gfx/Rect.h" // for Rect +#include "mozilla/gfx/Types.h" // for SurfaceFormat +#include "mozilla/layers/CompositorTypes.h" +#include "mozilla/layers/Effects.h" // for EffectChain +#include "mozilla/layers/LayersMessages.h" +#include "mozilla/layers/LayersTypes.h" // for LayersBackend, etc +#include "mozilla/Maybe.h" // for Maybe +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" +#include "nsAString.h" +#include "mozilla/RefPtr.h" // for nsRefPtr +#include "nsCOMPtr.h" // for already_AddRefed +#include "nsDebug.h" // for NS_ASSERTION +#include "nsISupportsImpl.h" // for Layer::AddRef, etc +#include "nsRect.h" // for mozilla::gfx::IntRect +#include "nsRegion.h" // for nsIntRegion +#include "nscore.h" // for nsAString, etc +#include "LayerTreeInvalidation.h" + +class gfxContext; + +#ifdef XP_WIN +#include +#endif + +namespace mozilla { +namespace gfx { +class DrawTarget; +} // namespace gfx + +namespace layers { + +class CanvasLayerComposite; +class ColorLayerComposite; +class CompositableHost; +class Compositor; +class ContainerLayerComposite; +struct EffectChain; +class ImageLayer; +class ImageLayerComposite; +class LayerComposite; +class RefLayerComposite; +class PaintedLayerComposite; +class TextRenderer; +class CompositingRenderTarget; +struct FPSState; +class PaintCounter; + +static const int kVisualWarningDuration = 150; // ms + +class LayerManagerComposite final : public LayerManager +{ + typedef mozilla::gfx::DrawTarget DrawTarget; + typedef mozilla::gfx::IntSize IntSize; + typedef mozilla::gfx::SurfaceFormat SurfaceFormat; + +public: + explicit LayerManagerComposite(Compositor* aCompositor); + ~LayerManagerComposite(); + + virtual void Destroy() override; + + /** + * Sets the clipping region for this layer manager. This is important on + * windows because using OGL we no longer have GDI's native clipping. Therefor + * widget must tell us what part of the screen is being invalidated, + * and we should clip to this. + * + * \param aClippingRegion Region to clip to. Setting an empty region + * will disable clipping. + */ + void SetClippingRegion(const nsIntRegion& aClippingRegion) + { + mClippingRegion = aClippingRegion; + } + + /** + * LayerManager implementation. + */ + virtual LayerManagerComposite* AsLayerManagerComposite() override + { + return this; + } + + void UpdateRenderBounds(const gfx::IntRect& aRect); + + virtual bool BeginTransaction() override; + virtual bool BeginTransactionWithTarget(gfxContext* aTarget) override + { + MOZ_CRASH("GFX: Use BeginTransactionWithDrawTarget"); + return false; + } + void BeginTransactionWithDrawTarget(gfx::DrawTarget* aTarget, + const gfx::IntRect& aRect); + + virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT) override + { + MOZ_CRASH("GFX: Use EndTransaction(aTimeStamp)"); + return false; + } + virtual void EndTransaction(DrawPaintedLayerCallback aCallback, + void* aCallbackData, + EndTransactionFlags aFlags = END_DEFAULT) override + { + MOZ_CRASH("GFX: Use EndTransaction(aTimeStamp)"); + } + void EndTransaction(const TimeStamp& aTimeStamp, + EndTransactionFlags aFlags = END_DEFAULT); + + virtual void SetRoot(Layer* aLayer) override { mRoot = aLayer; } + + // XXX[nrc]: never called, we should move this logic to ClientLayerManager + // (bug 946926). + virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) override; + + virtual int32_t GetMaxTextureSize() const override + { + MOZ_CRASH("GFX: Call on compositor, not LayerManagerComposite"); + } + + virtual void ClearCachedResources(Layer* aSubtree = nullptr) override; + + virtual already_AddRefed CreatePaintedLayer() override; + virtual already_AddRefed CreateContainerLayer() override; + virtual already_AddRefed CreateImageLayer() override; + virtual already_AddRefed CreateColorLayer() override; + virtual already_AddRefed CreateCanvasLayer() override; + already_AddRefed CreatePaintedLayerComposite(); + already_AddRefed CreateContainerLayerComposite(); + already_AddRefed CreateImageLayerComposite(); + already_AddRefed CreateColorLayerComposite(); + already_AddRefed CreateCanvasLayerComposite(); + already_AddRefed CreateRefLayerComposite(); + + virtual LayersBackend GetBackendType() override + { + MOZ_CRASH("GFX: Shouldn't be called for composited layer manager"); + } + virtual void GetBackendName(nsAString& name) override + { + MOZ_CRASH("GFX: Shouldn't be called for composited layer manager"); + } + + virtual bool AreComponentAlphaLayersEnabled() override; + + virtual already_AddRefed + CreateOptimalMaskDrawTarget(const IntSize &aSize) override; + + virtual const char* Name() const override { return ""; } + + /** + * Post-processes layers before composition. This performs the following: + * + * - Applies occlusion culling. This restricts the shadow visible region + * of layers that are covered with opaque content. + * |aOpaqueRegion| is the region already known to be covered with opaque + * content, in the post-transform coordinate space of aLayer. + * + * - Recomputes visible regions to account for async transforms. + * Each layer accumulates into |aVisibleRegion| its post-transform + * (including async transforms) visible region. + */ + void PostProcessLayers(Layer* aLayer, + nsIntRegion& aOpaqueRegion, + LayerIntRegion& aVisibleRegion, + const Maybe& aClipFromAncestors); + + /** + * RAII helper class to add a mask effect with the compositable from aMaskLayer + * to the EffectChain aEffect and notify the compositable when we are done. + */ + class AutoAddMaskEffect + { + public: + AutoAddMaskEffect(Layer* aMaskLayer, + EffectChain& aEffect); + ~AutoAddMaskEffect(); + + bool Failed() const { return mFailed; } + private: + CompositableHost* mCompositable; + bool mFailed; + }; + + /** + * returns true if PlatformAllocBuffer will return a buffer that supports + * direct texturing + */ + static bool SupportsDirectTexturing(); + + static void PlatformSyncBeforeReplyUpdate(); + + void AddInvalidRegion(const nsIntRegion& aRegion) + { + mInvalidRegion.Or(mInvalidRegion, aRegion); + } + + void ClearApproximatelyVisibleRegions(uint64_t aLayersId, + const Maybe& aPresShellId) + { + for (auto iter = mVisibleRegions.Iter(); !iter.Done(); iter.Next()) { + if (iter.Key().mLayersId == aLayersId && + (!aPresShellId || iter.Key().mPresShellId == *aPresShellId)) { + iter.Remove(); + } + } + } + + void UpdateApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid, + const CSSIntRegion& aRegion) + { + CSSIntRegion* regionForScrollFrame = mVisibleRegions.LookupOrAdd(aGuid); + MOZ_ASSERT(regionForScrollFrame); + + *regionForScrollFrame = aRegion; + } + + CSSIntRegion* GetApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid) + { + return mVisibleRegions.Get(aGuid); + } + + Compositor* GetCompositor() const + { + return mCompositor; + } + + // Called by CompositorBridgeParent when a new compositor has been created due + // to a device reset. The layer manager must clear any cached resources + // attached to the old compositor, and make a best effort at ignoring + // layer or texture updates against the old compositor. + void ChangeCompositor(Compositor* aNewCompositor); + + /** + * LayerManagerComposite provides sophisticated debug overlays + * that can request a next frame. + */ + bool DebugOverlayWantsNextFrame() { return mDebugOverlayWantsNextFrame; } + void SetDebugOverlayWantsNextFrame(bool aVal) + { mDebugOverlayWantsNextFrame = aVal; } + + void NotifyShadowTreeTransaction(); + + TextRenderer* GetTextRenderer() { return mTextRenderer; } + + /** + * Add an on frame warning. + * @param severity ranges from 0 to 1. It's used to compute the warning color. + */ + void VisualFrameWarning(float severity) { + mozilla::TimeStamp now = TimeStamp::Now(); + if (mWarnTime.IsNull() || + severity > mWarningLevel || + mWarnTime + TimeDuration::FromMilliseconds(kVisualWarningDuration) < now) { + mWarnTime = now; + mWarningLevel = severity; + } + } + + void UnusedApzTransformWarning() { + mUnusedApzTransformWarning = true; + } + void DisabledApzWarning() { + mDisabledApzWarning = true; + } + + bool LastFrameMissedHWC() { return mLastFrameMissedHWC; } + + bool AsyncPanZoomEnabled() const override; + + void AppendImageCompositeNotification(const ImageCompositeNotification& aNotification) + { + // Only send composite notifications when we're drawing to the screen, + // because that's what they mean. + // Also when we're not drawing to the screen, DidComposite will not be + // called to extract and send these notifications, so they might linger + // and contain stale ImageContainerParent pointers. + if (!mCompositor->GetTargetContext()) { + mImageCompositeNotifications.AppendElement(aNotification); + } + } + void ExtractImageCompositeNotifications(nsTArray* aNotifications) + { + aNotifications->AppendElements(Move(mImageCompositeNotifications)); + } + + // Indicate that we need to composite even if nothing in our layers has + // changed, so that the widget can draw something different in its window + // overlay. + void SetWindowOverlayChanged() { mWindowOverlayChanged = true; } + + void ForcePresent() { mCompositor->ForcePresent(); } + + void SetPaintTime(const TimeDuration& aPaintTime) { mLastPaintTime = aPaintTime; } + +private: + /** Region we're clipping our current drawing to. */ + nsIntRegion mClippingRegion; + gfx::IntRect mRenderBounds; + + /** Current root layer. */ + LayerComposite* RootLayer() const; + + /** + * Update the invalid region and render it. + */ + void UpdateAndRender(); + + /** + * Render the current layer tree to the active target. + */ + void Render(const nsIntRegion& aInvalidRegion, const nsIntRegion& aOpaqueRegion); +#if defined(MOZ_WIDGET_ANDROID) + void RenderToPresentationSurface(); +#endif + + /** + * We need to know our invalid region before we're ready to render. + */ + void InvalidateDebugOverlay(nsIntRegion& aInvalidRegion, const gfx::IntRect& aBounds); + + /** + * Render debug overlays such as the FPS/FrameCounter above the frame. + */ + void RenderDebugOverlay(const gfx::IntRect& aBounds); + + + RefPtr PushGroupForLayerEffects(); + void PopGroupForLayerEffects(RefPtr aPreviousTarget, + gfx::IntRect aClipRect, + bool aGrayscaleEffect, + bool aInvertEffect, + float aContrastEffect); + + void ChangeCompositorInternal(Compositor* aNewCompositor); + + float mWarningLevel; + mozilla::TimeStamp mWarnTime; + bool mUnusedApzTransformWarning; + bool mDisabledApzWarning; + RefPtr mCompositor; + UniquePtr mClonedLayerTreeProperties; + + nsTArray mImageCompositeNotifications; + + /** + * Context target, nullptr when drawing directly to our swap chain. + */ + RefPtr mTarget; + gfx::IntRect mTargetBounds; + + nsIntRegion mInvalidRegion; + + typedef nsClassHashtable, + CSSIntRegion> VisibleRegions; + VisibleRegions mVisibleRegions; + + UniquePtr mFPS; + + bool mInTransaction; + bool mIsCompositorReady; + bool mDebugOverlayWantsNextFrame; + + RefPtr mTwoPassTmpTarget; + RefPtr mTextRenderer; + bool mGeometryChanged; + + // Testing property. If hardware composer is supported, this will return + // true if the last frame was deemed 'too complicated' to be rendered. + bool mLastFrameMissedHWC; + + bool mWindowOverlayChanged; + TimeDuration mLastPaintTime; + TimeStamp mRenderStartTime; + +#ifdef USE_SKIA + /** + * Render paint and composite times above the frame. + */ + void DrawPaintTimes(Compositor* aCompositor); + RefPtr mPaintCounter; +#endif +}; + +/** + * Composite layers are for use with OMTC on the compositor thread only. There + * must be corresponding Basic layers on the content thread. For composite + * layers, the layer manager only maintains the layer tree, all rendering is + * done by a Compositor (see Compositor.h). As such, composite layers are + * platform-independent and can be used on any platform for which there is a + * Compositor implementation. + * + * The composite layer tree reflects exactly the basic layer tree. To + * composite to screen, the layer manager walks the layer tree calling render + * methods which in turn call into their CompositableHosts' Composite methods. + * These call Compositor::DrawQuad to do the rendering. + * + * Mostly, layers are updated during the layers transaction. This is done from + * CompositableClient to CompositableHost without interacting with the layer. + * + * A reference to the Compositor is stored in LayerManagerComposite. + */ +class LayerComposite +{ +public: + explicit LayerComposite(LayerManagerComposite* aManager); + + virtual ~LayerComposite(); + + virtual LayerComposite* GetFirstChildComposite() + { + return nullptr; + } + + /* Do NOT call this from the generic LayerComposite destructor. Only from the + * concrete class destructor + */ + virtual void Destroy(); + + virtual Layer* GetLayer() = 0; + + virtual void SetLayerManager(LayerManagerComposite* aManager); + + LayerManagerComposite* GetLayerManager() const { return mCompositeManager; } + + /** + * Perform a first pass over the layer tree to render all of the intermediate + * surfaces that we can. This allows us to avoid framebuffer switches in the + * middle of our render which is inefficient especially on mobile GPUs. This + * must be called before RenderLayer. + */ + virtual void Prepare(const RenderTargetIntRect& aClipRect) {} + + // TODO: This should also take RenderTargetIntRect like Prepare. + virtual void RenderLayer(const gfx::IntRect& aClipRect) = 0; + + virtual bool SetCompositableHost(CompositableHost*) + { + // We must handle this gracefully, see bug 967824 + NS_WARNING("called SetCompositableHost for a layer type not accepting a compositable"); + return false; + } + virtual CompositableHost* GetCompositableHost() = 0; + + virtual void CleanupResources() = 0; + + virtual void DestroyFrontBuffer() { } + + void AddBlendModeEffect(EffectChain& aEffectChain); + + virtual void GenEffectChain(EffectChain& aEffect) { } + + /** + * The following methods are + * + * CONSTRUCTION PHASE ONLY + * + * They are analogous to the Layer interface. + */ + void SetShadowVisibleRegion(const LayerIntRegion& aRegion) + { + mShadowVisibleRegion = aRegion; + } + + void SetShadowOpacity(float aOpacity) + { + mShadowOpacity = aOpacity; + } + void SetShadowOpacitySetByAnimation(bool aSetByAnimation) + { + mShadowOpacitySetByAnimation = aSetByAnimation; + } + + void SetShadowClipRect(const Maybe& aRect) + { + mShadowClipRect = aRect; + } + + void SetShadowBaseTransform(const gfx::Matrix4x4& aMatrix) + { + mShadowTransform = aMatrix; + } + void SetShadowTransformSetByAnimation(bool aSetByAnimation) + { + mShadowTransformSetByAnimation = aSetByAnimation; + } + + void SetLayerComposited(bool value) + { + mLayerComposited = value; + } + + void SetClearRect(const gfx::IntRect& aRect) + { + mClearRect = aRect; + } + + // These getters can be used anytime. + float GetShadowOpacity() { return mShadowOpacity; } + const Maybe& GetShadowClipRect() { return mShadowClipRect; } + const LayerIntRegion& GetShadowVisibleRegion() { return mShadowVisibleRegion; } + const gfx::Matrix4x4& GetShadowBaseTransform() { return mShadowTransform; } + gfx::Matrix4x4 GetShadowTransform(); + bool GetShadowTransformSetByAnimation() { return mShadowTransformSetByAnimation; } + bool GetShadowOpacitySetByAnimation() { return mShadowOpacitySetByAnimation; } + bool HasLayerBeenComposited() { return mLayerComposited; } + gfx::IntRect GetClearRect() { return mClearRect; } + + // Returns false if the layer is attached to an older compositor. + bool HasStaleCompositor() const; + + /** + * Return the part of the visible region that has been fully rendered. + * While progressive drawing is in progress this region will be + * a subset of the shadow visible region. + */ + virtual nsIntRegion GetFullyRenderedRegion(); + + /** + * Return true if a checkerboarding background color needs to be drawn + * for this layer. + */ + bool NeedToDrawCheckerboarding(gfx::Color* aOutCheckerboardingColor = nullptr); + +protected: + gfx::Matrix4x4 mShadowTransform; + LayerIntRegion mShadowVisibleRegion; + Maybe mShadowClipRect; + LayerManagerComposite* mCompositeManager; + RefPtr mCompositor; + float mShadowOpacity; + bool mShadowTransformSetByAnimation; + bool mShadowOpacitySetByAnimation; + bool mDestroyed; + bool mLayerComposited; + gfx::IntRect mClearRect; +}; + +// Render aLayer using aCompositor and apply all mask layers of aLayer: The +// layer's own mask layer (aLayer->GetMaskLayer()), and any ancestor mask +// layers. +// If more than one mask layer needs to be applied, we use intermediate surfaces +// (CompositingRenderTargets) for rendering, applying one mask layer at a time. +// Callers need to provide a callback function aRenderCallback that does the +// actual rendering of the source. It needs to have the following form: +// void (EffectChain& effectChain, const Rect& clipRect) +// aRenderCallback is called exactly once, inside this function, unless aLayer's +// visible region is completely clipped out (in that case, aRenderCallback won't +// be called at all). +// This function calls aLayer->AsLayerComposite()->AddBlendModeEffect for the +// final rendering pass. +// +// (This function should really live in LayerManagerComposite.cpp, but we +// need to use templates for passing lambdas until bug 1164522 is resolved.) +template +void +RenderWithAllMasks(Layer* aLayer, Compositor* aCompositor, + const gfx::IntRect& aClipRect, + RenderCallbackType aRenderCallback) +{ + Layer* firstMask = nullptr; + size_t maskLayerCount = 0; + size_t nextAncestorMaskLayer = 0; + + size_t ancestorMaskLayerCount = aLayer->GetAncestorMaskLayerCount(); + if (Layer* ownMask = aLayer->GetMaskLayer()) { + firstMask = ownMask; + maskLayerCount = ancestorMaskLayerCount + 1; + nextAncestorMaskLayer = 0; + } else if (ancestorMaskLayerCount > 0) { + firstMask = aLayer->GetAncestorMaskLayerAt(0); + maskLayerCount = ancestorMaskLayerCount; + nextAncestorMaskLayer = 1; + } else { + // no mask layers at all + } + + if (maskLayerCount <= 1) { + // This is the common case. Render in one pass and return. + EffectChain effectChain(aLayer); + LayerManagerComposite::AutoAddMaskEffect + autoMaskEffect(firstMask, effectChain); + aLayer->AsLayerComposite()->AddBlendModeEffect(effectChain); + aRenderCallback(effectChain, aClipRect); + return; + } + + // We have multiple mask layers. + // We split our list of mask layers into three parts: + // (1) The first mask + // (2) The list of intermediate masks (every mask except first and last) + // (3) The final mask. + // Part (2) can be empty. + // For parts (1) and (2) we need to allocate intermediate surfaces to render + // into. The final mask gets rendered into the original render target. + + // Calculate the size of the intermediate surfaces. + gfx::Rect visibleRect(aLayer->GetLocalVisibleRegion().ToUnknownRegion().GetBounds()); + gfx::Matrix4x4 transform = aLayer->GetEffectiveTransform(); + // TODO: Use RenderTargetIntRect and TransformBy here + gfx::IntRect surfaceRect = + RoundedOut(transform.TransformAndClipBounds(visibleRect, gfx::Rect(aClipRect))); + if (surfaceRect.IsEmpty()) { + return; + } + + RefPtr originalTarget = + aCompositor->GetCurrentRenderTarget(); + + RefPtr firstTarget = + aCompositor->CreateRenderTarget(surfaceRect, INIT_MODE_CLEAR); + if (!firstTarget) { + return; + } + + // Render the source while applying the first mask. + aCompositor->SetRenderTarget(firstTarget); + { + EffectChain firstEffectChain(aLayer); + LayerManagerComposite::AutoAddMaskEffect + firstMaskEffect(firstMask, firstEffectChain); + aRenderCallback(firstEffectChain, aClipRect - surfaceRect.TopLeft()); + // firstTarget now contains the transformed source with the first mask and + // opacity already applied. + } + + // Apply the intermediate masks. + gfx::IntRect intermediateClip(surfaceRect - surfaceRect.TopLeft()); + RefPtr previousTarget = firstTarget; + for (size_t i = nextAncestorMaskLayer; i < ancestorMaskLayerCount - 1; i++) { + Layer* intermediateMask = aLayer->GetAncestorMaskLayerAt(i); + RefPtr intermediateTarget = + aCompositor->CreateRenderTarget(surfaceRect, INIT_MODE_CLEAR); + if (!intermediateTarget) { + break; + } + aCompositor->SetRenderTarget(intermediateTarget); + EffectChain intermediateEffectChain(aLayer); + LayerManagerComposite::AutoAddMaskEffect + intermediateMaskEffect(intermediateMask, intermediateEffectChain); + if (intermediateMaskEffect.Failed()) { + continue; + } + intermediateEffectChain.mPrimaryEffect = new EffectRenderTarget(previousTarget); + aCompositor->DrawQuad(gfx::Rect(surfaceRect), intermediateClip, + intermediateEffectChain, 1.0, gfx::Matrix4x4()); + previousTarget = intermediateTarget; + } + + aCompositor->SetRenderTarget(originalTarget); + + // Apply the final mask, rendering into originalTarget. + EffectChain finalEffectChain(aLayer); + finalEffectChain.mPrimaryEffect = new EffectRenderTarget(previousTarget); + Layer* finalMask = aLayer->GetAncestorMaskLayerAt(ancestorMaskLayerCount - 1); + + // The blend mode needs to be applied in this final step, because this is + // where we're blending with the actual background (which is in originalTarget). + aLayer->AsLayerComposite()->AddBlendModeEffect(finalEffectChain); + LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(finalMask, finalEffectChain); + if (!autoMaskEffect.Failed()) { + aCompositor->DrawQuad(gfx::Rect(surfaceRect), aClipRect, + finalEffectChain, 1.0, gfx::Matrix4x4()); + } +} + +} // namespace layers +} // namespace mozilla + +#endif /* GFX_LayerManagerComposite_H */ -- cgit v1.2.3