tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit fd32df7fa7f0750ed8dc272badd289cb04ae590d
parent 71623fa5a1f7afd950c5e081d899cfb373d45a8e
Author: Alexandru Marc <amarc@mozilla.com>
Date:   Fri,  3 Oct 2025 02:31:36 +0300

Revert "Bug 1987007 - Keep doing reftest snapshots in the parent, even though we can now do them in the GPU process. r=bradwerth" for causing build bustages @ NativeLayerRootRemoteMacChild.mm

This reverts commit 8bffb8f28dadfe6a26ecc5ff99c0a9a9182dd774.

Revert "Bug 1987007 - Remove now-unused remote snapshotter implementation. r=bradwerth"

This reverts commit 8f6791c0b7e3ed49e19577f3cb3c71badfe33e53.

Revert "Bug 1987007 - Use NativeLayerRootSnapshotterCA for NativeLayerRootRemoteMacChild. r=bradwerth"

This reverts commit c2bd9d2d0058f4b6db2914980bd9f50711922c5e.

Revert "Bug 1987007 - Change type of mNativeLayers to use concrete layer class. r=bradwerth"

This reverts commit 93857df07b0ea4fe6240e74863be90c0afd9b144.

Revert "Bug 1987007 - Pass gfx::DeviceColor instead of CGColorRef to NativeLayerCARepresentation. r=bradwerth"

This reverts commit 4af322140b19a7dbbc6c8191617b5b17979e3798.

Revert "Bug 1987007 - Move NativeLayerCA::Representation out of NativeLayerCA and call it NativeLayerCARepresentation. r=bradwerth"

This reverts commit 0cba8e85148c30db16cabf7d573466b94ceb6a40.

Revert "Bug 1987007 - Add a SnapshotterCADelegate interface. r=bradwerth"

This reverts commit 6894c9a01b6f174c9b746299177e3129208da478.

Revert "Bug 1987007 - Make the snapshotter responsible for managing the offscreen root CALayer. r=bradwerth"

This reverts commit 01c978484fed93dc0ae0178fab8c303b81c7e5a5.

Revert "Bug 1987007 - Extract a loop into GetMaxUpdateRequired. r=bradwerth"

This reverts commit a1d4037cd14a9a83e9e0c939f33eecb30924bd3e.

Revert "Bug 1987007 - Remove stray indent from CommitToScreen. r=bradwerth"

This reverts commit 74bd6c9d12f1f7b9ef0df8abccb43d037273c7d8.

Revert "Bug 1987007 - Fold HasExtent tracking into ApplyChanges. r=bradwerth"

This reverts commit 4780d8eb2e94a18d5e0297057f08f7c2df8bad97.

Revert "Bug 1987007 - Fold WillUpdateAffectLayers into ApplyChanges. r=bradwerth"

This reverts commit db48e85b637a4bb7da82773fcc94df7dc714a5c9.

Revert "Bug 1987007 - Inline-away NativeLayerRootCA::Representation. r=bradwerth"

This reverts commit 4c982435788b70ad8361c83b15a6702eb18ec8d4.

Revert "Bug 1987007 - Use IOSurfaceRef instead of auto. r=bradwerth"

This reverts commit 016fd8b67add34175acc53f160f82c39fd0a4936.

Revert "Bug 1987007 - Remove unused forward declarations. r=bradwerth"

This reverts commit e9934647fe3859981cae7d392c87ede2de2fe75c.

Diffstat:
Mgfx/layers/NativeLayerCA.h | 259+++++++++++++++++++++++++++++++------------------------------------------------
Mgfx/layers/NativeLayerCA.mm | 424++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mgfx/layers/NativeLayerRemoteMac.h | 8++------
Mgfx/layers/NativeLayerRemoteMac.mm | 42+++++-------------------------------------
Mgfx/layers/NativeLayerRootRemoteMacChild.h | 54++++++------------------------------------------------
Mgfx/layers/NativeLayerRootRemoteMacChild.mm | 51+++++++++++----------------------------------------
Agfx/layers/NativeLayerRootRemoteMacSnapshotter.h | 47+++++++++++++++++++++++++++++++++++++++++++++++
Agfx/layers/NativeLayerRootRemoteMacSnapshotter.mm | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Mgfx/layers/moz.build | 2++
9 files changed, 441 insertions(+), 496 deletions(-)

diff --git a/gfx/layers/NativeLayerCA.h b/gfx/layers/NativeLayerCA.h @@ -43,7 +43,9 @@ class RenderMacIOSurfaceTextureHost; namespace layers { +#ifdef XP_MACOSX class NativeLayerRootSnapshotterCA; +#endif enum class VideoLowPowerType { // These must be kept synchronized with the telemetry histogram enums. @@ -61,32 +63,6 @@ enum class VideoLowPowerType { FailEnqueue, // Enqueueing the video didn't work. }; -// The type of update needed to apply the pending changes to a NativeLayerCA -// representation. -// -// Order is important. Each enum must fully encompass the work implied by the -// previous enums. -enum class NativeLayerCAUpdateType { - None, - OnlyVideo, - All, -}; - -class SnapshotterCADelegate { - public: - virtual ~SnapshotterCADelegate(); - - virtual float BackingScale() const { return 1.0f; } - virtual bool DoCustomReadbackForReftestsIfDesired( - const gfx::IntSize& aReadbackSize, gfx::SurfaceFormat aReadbackFormat, - const Range<uint8_t>& aReadbackBuffer) { - return false; - } - virtual void UpdateSnapshotterLayers(CALayer* aRootCALayer) = 0; - virtual void OnSnapshotterDestroyed( - NativeLayerRootSnapshotterCA* aSnapshotter) {} -}; - // NativeLayerRootCA is the CoreAnimation implementation of the NativeLayerRoot // interface. A NativeLayerRootCA is created by the widget around an existing // CALayer with a call to CreateForCALayer - this CALayer is the root of the @@ -119,7 +95,7 @@ class SnapshotterCADelegate { // effect. To solve this problem, we build two CALayer representations, so that // one representation can stay inside the window and the other can stay attached // to the CARenderer. -class NativeLayerRootCA final : public NativeLayerRoot { +class NativeLayerRootCA : public NativeLayerRoot { public: static already_AddRefed<NativeLayerRootCA> CreateForCALayer(CALayer* aLayer); @@ -130,9 +106,11 @@ class NativeLayerRootCA final : public NativeLayerRoot { // off-main-thread commits are suspended. bool CommitToScreen() override; - void CommitOffscreen(CALayer* aRootCALayer); + void CommitOffscreen(); +#ifdef XP_MACOSX void OnNativeLayerRootSnapshotterDestroyed( NativeLayerRootSnapshotterCA* aNativeLayerRootSnapshotter); +#endif // Enters a mode during which CommitToScreen(), when called on a non-main // thread, will not apply any updates to the CALayer tree. @@ -180,45 +158,25 @@ class NativeLayerRootCA final : public NativeLayerRoot { explicit NativeLayerRootCA(CALayer* aLayer); ~NativeLayerRootCA() override; - // Do a commit of the pending changes to the CALayers. This is used for both - // onscreen commits (modifying the CALayers attached to the NSView), and for - // "offscreen" commits. - // "Offscreen" commits are updating a separate copy of the CALayer tree for - // use with CARenderer by the snapshotter. - void CommitRepresentation(WhichRepresentation aRepresentation, - CALayer* aRootCALayer, - const nsTArray<RefPtr<NativeLayerCA>>& aSublayers, - bool aMutatedLayerStructure, - bool aWindowIsFullscreen); - - void SetMutatedLayerStructure(); - - using UpdateType = NativeLayerCAUpdateType; - UpdateType GetMaxUpdateRequired( - WhichRepresentation aRepresentation, - const nsTArray<RefPtr<NativeLayerCA>>& aSublayers, - bool aMutatedLayerStructure) const; - - // An implementation of SnapshotterCADelegate, backed by a NativeLayerRootCA. - struct SnapshotterDelegate final : public SnapshotterCADelegate { - explicit SnapshotterDelegate(NativeLayerRootCA* aLayerRoot); - virtual ~SnapshotterDelegate() override; - virtual float BackingScale() const override { - return mLayerRoot->BackingScale(); - } - virtual void UpdateSnapshotterLayers(CALayer* aRootCALayer) override { - mLayerRoot->CommitOffscreen(aRootCALayer); - } - virtual void OnSnapshotterDestroyed( - NativeLayerRootSnapshotterCA* aSnapshotter) override { - mLayerRoot->OnNativeLayerRootSnapshotterDestroyed(aSnapshotter); - } - RefPtr<NativeLayerRootCA> mLayerRoot; + struct Representation { + explicit Representation(CALayer* aRootCALayer); + ~Representation(); + void Commit(WhichRepresentation aRepresentation, + const nsTArray<RefPtr<NativeLayerCA>>& aSublayers, + bool aWindowIsFullscreen); + CALayer* mRootCALayer = nullptr; // strong + bool mMutatedLayerStructure = false; }; - Mutex mMutex MOZ_UNANNOTATED; // protects all other fields - CALayer* mOnscreenRootCALayer = nullptr; // strong + template <typename F> + void ForAllRepresentations(F aFn); + + Mutex mMutex MOZ_UNANNOTATED; // protects all other fields + Representation mOnscreenRepresentation; + Representation mOffscreenRepresentation; +#ifdef XP_MACOSX NativeLayerRootSnapshotterCA* mWeakSnapshotter = nullptr; +#endif nsTArray<RefPtr<NativeLayerCA>> mSublayers; // in z-order float mBackingScale = 1.0f; bool mMutated = false; @@ -239,10 +197,6 @@ class NativeLayerRootCA final : public NativeLayerRoot { // of that window. bool mWindowIsFullscreen = false; - // Whether mSublayers has changed since the last onscreen / offscreen commit. - bool mMutatedOnscreenLayerStructure = false; - bool mMutatedOffscreenLayerStructure = false; - // How many times have we committed since the last time we emitted // telemetry? unsigned int mTelemetryCommitCount = 0; @@ -254,7 +208,7 @@ class RenderSourceNLRS; class NativeLayerRootSnapshotterCA final : public NativeLayerRootSnapshotter { public: static UniquePtr<NativeLayerRootSnapshotterCA> Create( - UniquePtr<SnapshotterCADelegate>&& aDelegate); + NativeLayerRootCA* aLayerRoot, CALayer* aRootCALayer); virtual ~NativeLayerRootSnapshotterCA(); bool ReadbackPixels(const gfx::IntSize& aReadbackSize, @@ -268,11 +222,12 @@ class NativeLayerRootSnapshotterCA final : public NativeLayerRootSnapshotter { CreateAsyncReadbackBuffer(const gfx::IntSize& aSize) override; protected: - NativeLayerRootSnapshotterCA(UniquePtr<SnapshotterCADelegate>&& aDelegate, - RefPtr<gl::GLContext>&& aGL); + NativeLayerRootSnapshotterCA(NativeLayerRootCA* aLayerRoot, + RefPtr<gl::GLContext>&& aGL, + CALayer* aRootCALayer); void UpdateSnapshot(const gfx::IntSize& aSize); - UniquePtr<SnapshotterCADelegate> mDelegate; + RefPtr<NativeLayerRootCA> mLayerRoot; RefPtr<gl::GLContext> mGL; // Can be null. Created and updated in UpdateSnapshot. @@ -281,80 +236,6 @@ class NativeLayerRootSnapshotterCA final : public NativeLayerRootSnapshotter { }; #endif -// Wraps one CALayer representation of NativeLayerCA. -struct NativeLayerCARepresentation { - using UpdateType = NativeLayerCAUpdateType; - - NativeLayerCARepresentation(); - ~NativeLayerCARepresentation(); - - // Returns null if the layer is currently completely clipped out. - CALayer* UnderlyingCALayer() { - return mWrappingCALayerHasExtent ? mWrappingCALayer : nullptr; - } - - bool EnqueueSurface(IOSurfaceRef aSurfaceRef); - - // Applies buffered changes to the native CALayers. The contract with the - // caller is as follows: If any of these values have changed since the last - // call to ApplyChanges, mMutated[Field] needs to have been set to true - // before the call. If aUpdate is not All, then a partial update will be - // applied. In such a case, ApplyChanges may not make any changes that - // require a CATransacation, because no transaction will be created. In a - // a partial update, the return value will indicate if all the needed - // changes were able to be applied under these restrictions. A false return - // value indicates an All update is necessary. - bool ApplyChanges(NativeLayerCAUpdateType aUpdate, const gfx::IntSize& aSize, - bool aIsOpaque, const gfx::IntPoint& aPosition, - const gfx::Matrix4x4& aTransform, - const gfx::IntRect& aDisplayRect, - const Maybe<gfx::IntRect>& aClipRect, - const Maybe<gfx::RoundedRect>& aRoundedClip, - float aBackingScale, bool aSurfaceIsFlipped, - gfx::SamplingFilter aSamplingFilter, bool aSpecializeVideo, - const CFTypeRefPtr<IOSurfaceRef>& aFrontSurface, - const Maybe<gfx::DeviceColor>& aColor, bool aIsDRM, - bool aIsVideo); - - // Return whether any aspects of this layer representation have been mutated - // since the last call to ApplyChanges, i.e. whether ApplyChanges needs to - // be called. - // This is used to optimize away a CATransaction commit if no layers have - // changed. - NativeLayerCAUpdateType HasUpdate(bool aIsVideo); - - // Lazily initialized by first call to ApplyChanges. mWrappingLayer is the - // layer that applies the intersection of mDisplayRect and mClipRect (if - // set), and mContentCALayer is the layer that hosts the IOSurface. We do - // not share clip layers between consecutive NativeLayerCA objects with the - // same clip rect. - CALayer* mWrappingCALayer = nullptr; // strong - CALayer* mRoundedClipCALayer = nullptr; // strong - CALayer* mContentCALayer = nullptr; // strong - CALayer* mOpaquenessTintLayer = nullptr; // strong - -#ifdef NIGHTLY_BUILD - bool mLogNextVideoSurface = false; -#endif - - bool mWrappingCALayerHasExtent : 1; - - // These are all initialized to true by the constructor. - bool mMutatedPosition : 1; - bool mMutatedTransform : 1; - bool mMutatedDisplayRect : 1; - bool mMutatedClipRect : 1; - bool mMutatedRoundedClipRect : 1; - bool mMutatedBackingScale : 1; - bool mMutatedSize : 1; - bool mMutatedSurfaceIsFlipped : 1; - bool mMutatedFrontSurface : 1; - bool mMutatedSamplingFilter : 1; - bool mMutatedSpecializeVideo : 1; - bool mMutatedIsDRM : 1; - // Don't forget to update the constructor when you add a field here. -}; - // NativeLayerCA wraps a CALayer and lets you draw to it. It ensures that only // fully-drawn frames make their way to the screen, by maintaining a swap chain // of IOSurfaces. @@ -409,10 +290,6 @@ class NativeLayerCA : public NativeLayer { protected: friend class NativeLayerRootCA; - friend struct NativeLayerCARepresentation; - using UpdateType = NativeLayerCAUpdateType; - using WhichRepresentation = NativeLayerRootCA::WhichRepresentation; - using Representation = NativeLayerCARepresentation; NativeLayerCA(const gfx::IntSize& aSize, bool aIsOpaque, SurfacePoolHandleCA* aSurfacePoolHandle); @@ -425,15 +302,18 @@ class NativeLayerCA : public NativeLayer { ~NativeLayerCA() override; // To be called by NativeLayerRootCA: + typedef NativeLayerRootCA::WhichRepresentation WhichRepresentation; CALayer* UnderlyingCALayer(WhichRepresentation aRepresentation); - NativeLayerCAUpdateType HasUpdate(WhichRepresentation aRepresentation); + enum class UpdateType { + None, // Order is important. Each enum must fully encompass the + OnlyVideo, // work implied by the previous enums. + All, + }; - // Apply pending updates to the underlaying CALayer. Sets *aMustRebuild to - // true if the update requires changing which set of CALayers should be in the - // parent. - bool ApplyChanges(WhichRepresentation aRepresentation, UpdateType aUpdate, - bool* aMustRebuild); + UpdateType HasUpdate(WhichRepresentation aRepresentation); + bool WillUpdateAffectLayers(WhichRepresentation aRepresentation); + bool ApplyChanges(WhichRepresentation aRepresentation, UpdateType aUpdate); void SetBackingScale(float aBackingScale); @@ -450,6 +330,8 @@ class NativeLayerCA : public NativeLayer { bool IsVideo(const MutexAutoLock& aProofOfLock); bool ShouldSpecializeVideo(const MutexAutoLock& aProofOfLock); + bool HasExtent() const { return mHasExtent; } + void SetHasExtent(bool aHasExtent) { mHasExtent = aHasExtent; } // This function returns a CGRect if a clip should be applied to the layer. // If set, the CGRect has the scaled position of the clip relative to the @@ -459,6 +341,68 @@ class NativeLayerCA : public NativeLayer { const gfx::Matrix4x4& aTransform, const gfx::IntRect& aDisplayRect, const Maybe<gfx::IntRect>& aClipRect, float aBackingScale); + // Wraps one CALayer representation of this NativeLayer. + struct Representation { + Representation(); + ~Representation(); + + CALayer* UnderlyingCALayer() { return mWrappingCALayer; } + + bool EnqueueSurface(IOSurfaceRef aSurfaceRef); + + // Applies buffered changes to the native CALayers. The contract with the + // caller is as follows: If any of these values have changed since the last + // call to ApplyChanges, mMutated[Field] needs to have been set to true + // before the call. If aUpdate is not All, then a partial update will be + // applied. In such a case, ApplyChanges may not make any changes that + // require a CATransacation, because no transaction will be created. In a + // a partial update, the return value will indicate if all the needed + // changes were able to be applied under these restrictions. A false return + // value indicates an All update is necessary. + bool ApplyChanges( + UpdateType aUpdate, const gfx::IntSize& aSize, bool aIsOpaque, + const gfx::IntPoint& aPosition, const gfx::Matrix4x4& aTransform, + const gfx::IntRect& aDisplayRect, const Maybe<gfx::IntRect>& aClipRect, + const Maybe<gfx::RoundedRect>& aRoundedClip, float aBackingScale, + bool aSurfaceIsFlipped, gfx::SamplingFilter aSamplingFilter, + bool aSpecializeVideo, CFTypeRefPtr<IOSurfaceRef> aFrontSurface, + CFTypeRefPtr<CGColorRef> aColor, bool aIsDRM, bool aIsVideo); + + // Return whether any aspects of this layer representation have been mutated + // since the last call to ApplyChanges, i.e. whether ApplyChanges needs to + // be called. + // This is used to optimize away a CATransaction commit if no layers have + // changed. + UpdateType HasUpdate(bool aIsVideo); + + // Lazily initialized by first call to ApplyChanges. mWrappingLayer is the + // layer that applies the intersection of mDisplayRect and mClipRect (if + // set), and mContentCALayer is the layer that hosts the IOSurface. We do + // not share clip layers between consecutive NativeLayerCA objects with the + // same clip rect. + CALayer* mWrappingCALayer = nullptr; // strong + CALayer* mRoundedClipCALayer = nullptr; // strong + CALayer* mContentCALayer = nullptr; // strong + CALayer* mOpaquenessTintLayer = nullptr; // strong + +#ifdef NIGHTLY_BUILD + bool mLogNextVideoSurface = false; +#endif + + bool mMutatedPosition : 1; + bool mMutatedTransform : 1; + bool mMutatedDisplayRect : 1; + bool mMutatedClipRect : 1; + bool mMutatedRoundedClipRect : 1; + bool mMutatedBackingScale : 1; + bool mMutatedSize : 1; + bool mMutatedSurfaceIsFlipped : 1; + bool mMutatedFrontSurface : 1; + bool mMutatedSamplingFilter : 1; + bool mMutatedSpecializeVideo : 1; + bool mMutatedIsDRM : 1; + }; + Representation& GetRepresentation(WhichRepresentation aRepresentation); template <typename F> void ForAllRepresentations(F aFn); @@ -482,13 +426,14 @@ class NativeLayerCA : public NativeLayer { gfx::IntSize mSize; Maybe<gfx::IntRect> mClipRect; Maybe<gfx::RoundedRect> mRoundedClipRect; - Maybe<gfx::DeviceColor> mColor; gfx::SamplingFilter mSamplingFilter = gfx::SamplingFilter::POINT; float mBackingScale = 1.0f; bool mSurfaceIsFlipped = false; + CFTypeRefPtr<CGColorRef> mColor; const bool mIsOpaque = false; bool mRootWindowIsFullscreen = false; bool mSpecializeVideo = false; + bool mHasExtent = false; bool mIsDRM = false; bool mIsHDR = false; diff --git a/gfx/layers/NativeLayerCA.mm b/gfx/layers/NativeLayerCA.mm @@ -203,22 +203,37 @@ NativeLayerRootCA::CreateForCALayer(CALayer* aLayer) { return layerRoot.forget(); } +// Returns an autoreleased CALayer* object. +static CALayer* MakeOffscreenRootCALayer() { + // This layer should behave similarly to the backing layer of a flipped + // NSView. It will never be rendered on the screen and it will never be + // attached to an NSView's layer; instead, it will be the root layer of a + // "local" CAContext. Setting geometryFlipped to YES causes the orientation of + // descendant CALayers' contents (such as IOSurfaces) to be consistent with + // what happens in a layer subtree that is attached to a flipped NSView. + // Setting it to NO would cause the surfaces in individual leaf layers to + // render upside down (rather than just flipping the entire layer tree upside + // down). + AutoCATransaction transaction; + CALayer* layer = [CALayer layer]; + layer.position = CGPointZero; + layer.bounds = CGRectZero; + layer.anchorPoint = CGPointZero; + layer.contentsGravity = kCAGravityTopLeft; + layer.masksToBounds = YES; + layer.geometryFlipped = YES; + return layer; +} + NativeLayerRootCA::NativeLayerRootCA(CALayer* aLayer) - : mMutex("NativeLayerRootCA"), mOnscreenRootCALayer([aLayer retain]) {} + : mMutex("NativeLayerRootCA"), + mOnscreenRepresentation(aLayer), + mOffscreenRepresentation(MakeOffscreenRootCALayer()) {} NativeLayerRootCA::~NativeLayerRootCA() { MOZ_RELEASE_ASSERT( mSublayers.IsEmpty(), "Please clear all layers before destroying the layer root."); - - if (mMutatedOnscreenLayerStructure || mMutatedOffscreenLayerStructure) { - // Clear the root layer's sublayers. At this point the window is usually - // closed, so this transaction does not cause any screen updates. - AutoCATransaction transaction; - mOnscreenRootCALayer.sublayers = @[]; - } - - [mOnscreenRootCALayer release]; } already_AddRefed<NativeLayer> NativeLayerRootCA::CreateLayer( @@ -257,7 +272,8 @@ void NativeLayerRootCA::AppendLayer(NativeLayer* aLayer) { mSublayers.AppendElement(layerCA); layerCA->SetBackingScale(mBackingScale); layerCA->SetRootWindowIsFullscreen(mWindowIsFullscreen); - SetMutatedLayerStructure(); + ForAllRepresentations( + [&](Representation& r) { r.mMutatedLayerStructure = true; }); } void NativeLayerRootCA::RemoveLayer(NativeLayer* aLayer) { @@ -267,7 +283,8 @@ void NativeLayerRootCA::RemoveLayer(NativeLayer* aLayer) { MOZ_RELEASE_ASSERT(layerCA); mSublayers.RemoveElement(layerCA); - SetMutatedLayerStructure(); + ForAllRepresentations( + [&](Representation& r) { r.mMutatedLayerStructure = true; }); } void NativeLayerRootCA::SetLayers( @@ -292,7 +309,8 @@ void NativeLayerRootCA::SetLayers( if (layersCA != mSublayers) { mSublayers = std::move(layersCA); - SetMutatedLayerStructure(); + ForAllRepresentations( + [&](Representation& r) { r.mMutatedLayerStructure = true; }); } } @@ -327,49 +345,50 @@ bool NativeLayerRootCA::AreOffMainThreadCommitsSuspended() { } bool NativeLayerRootCA::CommitToScreen() { - MutexAutoLock lock(mMutex); + { + MutexAutoLock lock(mMutex); - if (!NS_IsMainThread() && mOffMainThreadCommitsSuspended) { - mCommitPending = true; - return false; - } + if (!NS_IsMainThread() && mOffMainThreadCommitsSuspended) { + mCommitPending = true; + return false; + } - CommitRepresentation(WhichRepresentation::ONSCREEN, mOnscreenRootCALayer, - mSublayers, mMutatedOnscreenLayerStructure, - mWindowIsFullscreen); - mMutatedOnscreenLayerStructure = false; - - mCommitPending = false; - - if (StaticPrefs::gfx_webrender_debug_dump_native_layer_tree_to_file()) { - static uint32_t sFrameID = 0; - uint32_t frameID = sFrameID++; - - NSString* dirPath = - [NSString stringWithFormat:@"%@/Desktop/nativelayerdumps-%d", - NSHomeDirectory(), getpid()]; - if ([NSFileManager.defaultManager createDirectoryAtPath:dirPath - withIntermediateDirectories:YES - attributes:nil - error:nullptr]) { - NSString* filename = - [NSString stringWithFormat:@"frame-%d.html", frameID]; - NSString* filePath = [dirPath stringByAppendingPathComponent:filename]; - DumpLayerTreeToFile([filePath UTF8String], lock); - } else { - NSLog(@"Failed to create directory %@", dirPath); + mOnscreenRepresentation.Commit(WhichRepresentation::ONSCREEN, mSublayers, + mWindowIsFullscreen); + + mCommitPending = false; + + if (StaticPrefs::gfx_webrender_debug_dump_native_layer_tree_to_file()) { + static uint32_t sFrameID = 0; + uint32_t frameID = sFrameID++; + + NSString* dirPath = + [NSString stringWithFormat:@"%@/Desktop/nativelayerdumps-%d", + NSHomeDirectory(), getpid()]; + if ([NSFileManager.defaultManager createDirectoryAtPath:dirPath + withIntermediateDirectories:YES + attributes:nil + error:nullptr]) { + NSString* filename = + [NSString stringWithFormat:@"frame-%d.html", frameID]; + NSString* filePath = [dirPath stringByAppendingPathComponent:filename]; + DumpLayerTreeToFile([filePath UTF8String], lock); + } else { + NSLog(@"Failed to create directory %@", dirPath); + } } - } - // Decide if we are going to emit telemetry about video low power on this - // commit. - static const int32_t TELEMETRY_COMMIT_PERIOD = - StaticPrefs::gfx_core_animation_low_power_telemetry_frames_AtStartup(); - mTelemetryCommitCount = (mTelemetryCommitCount + 1) % TELEMETRY_COMMIT_PERIOD; - if (mTelemetryCommitCount == 0) { - // Figure out if we are hitting video low power mode. - VideoLowPowerType videoLowPower = CheckVideoLowPower(lock); - EmitTelemetryForVideoLowPower(videoLowPower); + // Decide if we are going to emit telemetry about video low power on this + // commit. + static const int32_t TELEMETRY_COMMIT_PERIOD = + StaticPrefs::gfx_core_animation_low_power_telemetry_frames_AtStartup(); + mTelemetryCommitCount = + (mTelemetryCommitCount + 1) % TELEMETRY_COMMIT_PERIOD; + if (mTelemetryCommitCount == 0) { + // Figure out if we are hitting video low power mode. + VideoLowPowerType videoLowPower = CheckVideoLowPower(lock); + EmitTelemetryForVideoLowPower(videoLowPower); + } } return true; @@ -383,7 +402,7 @@ UniquePtr<NativeLayerRootSnapshotter> NativeLayerRootCA::CreateSnapshotter() { "should exist when this is called"); auto cr = NativeLayerRootSnapshotterCA::Create( - MakeUnique<SnapshotterDelegate>(this)); + this, mOffscreenRepresentation.mRootCALayer); if (cr) { mWeakSnapshotter = cr.get(); } @@ -393,101 +412,126 @@ UniquePtr<NativeLayerRootSnapshotter> NativeLayerRootCA::CreateSnapshotter() { #endif } +#ifdef XP_MACOSX void NativeLayerRootCA::OnNativeLayerRootSnapshotterDestroyed( NativeLayerRootSnapshotterCA* aNativeLayerRootSnapshotter) { MutexAutoLock lock(mMutex); MOZ_RELEASE_ASSERT(mWeakSnapshotter == aNativeLayerRootSnapshotter); mWeakSnapshotter = nullptr; } +#endif -void NativeLayerRootCA::CommitOffscreen(CALayer* aRootCALayer) { +void NativeLayerRootCA::CommitOffscreen() { MutexAutoLock lock(mMutex); - CommitRepresentation(WhichRepresentation::OFFSCREEN, aRootCALayer, mSublayers, - mMutatedOffscreenLayerStructure, mWindowIsFullscreen); - mMutatedOffscreenLayerStructure = false; + mOffscreenRepresentation.Commit(WhichRepresentation::OFFSCREEN, mSublayers, + mWindowIsFullscreen); } -void NativeLayerRootCA::SetMutatedLayerStructure() { - mMutatedOnscreenLayerStructure = true; - mMutatedOffscreenLayerStructure = true; +template <typename F> +void NativeLayerRootCA::ForAllRepresentations(F aFn) { + aFn(mOnscreenRepresentation); + aFn(mOffscreenRepresentation); } -NativeLayerCAUpdateType NativeLayerRootCA::GetMaxUpdateRequired( - WhichRepresentation aRepresentation, - const nsTArray<RefPtr<NativeLayerCA>>& aSublayers, - bool aMutatedLayerStructure) const { - if (aMutatedLayerStructure) { - return UpdateType::All; - } +NativeLayerRootCA::Representation::Representation(CALayer* aRootCALayer) + : mRootCALayer([aRootCALayer retain]) {} - UpdateType maxUpdateRequired = UpdateType::None; - for (const auto& layer : aSublayers) { - UpdateType updateRequired = layer->HasUpdate(aRepresentation); - if (updateRequired == UpdateType::All) { - return UpdateType::All; - } - // Use the ordering of our UpdateType enum values. - maxUpdateRequired = std::max(maxUpdateRequired, updateRequired); +NativeLayerRootCA::Representation::~Representation() { + if (mMutatedLayerStructure) { + // Clear the root layer's sublayers. At this point the window is usually + // closed, so this transaction does not cause any screen updates. + AutoCATransaction transaction; + mRootCALayer.sublayers = @[]; } - return maxUpdateRequired; + + [mRootCALayer release]; } -void NativeLayerRootCA::CommitRepresentation( - WhichRepresentation aRepresentation, CALayer* aRootCALayer, +void NativeLayerRootCA::Representation::Commit( + WhichRepresentation aRepresentation, const nsTArray<RefPtr<NativeLayerCA>>& aSublayers, - bool aMutatedLayerStructure, bool aWindowIsFullscreen) { - UpdateType updateRequired = - GetMaxUpdateRequired(aRepresentation, aSublayers, aMutatedLayerStructure); - if (updateRequired == NativeLayerCA::UpdateType::OnlyVideo) { - // Attempt a video-only update, which does not require being wrapped in a - // CATransaction. - bool allUpdatesSucceeded = - std::all_of(aSublayers.begin(), aSublayers.end(), - [=](const RefPtr<NativeLayerCA>& layer) { - bool ignoredMustRebuild = false; - return layer->ApplyChanges( - aRepresentation, NativeLayerCA::UpdateType::OnlyVideo, - &ignoredMustRebuild); - }); - - if (allUpdatesSucceeded) { + bool aWindowIsFullscreen) { + bool mustRebuild = mMutatedLayerStructure; + if (!mustRebuild) { + // Check which type of update we need to do, if any. + NativeLayerCA::UpdateType updateRequired = NativeLayerCA::UpdateType::None; + + for (auto layer : aSublayers) { + // Use the ordering of our UpdateType enums to build a maximal update + // type. + updateRequired = + std::max(updateRequired, layer->HasUpdate(aRepresentation)); + if (updateRequired == NativeLayerCA::UpdateType::All) { + break; + } + } + + if (updateRequired == NativeLayerCA::UpdateType::None) { // Nothing more needed, so early exit. return; } + + if (updateRequired == NativeLayerCA::UpdateType::OnlyVideo) { + bool allUpdatesSucceeded = std::all_of( + aSublayers.begin(), aSublayers.end(), + [=](const RefPtr<NativeLayerCA>& layer) { + return layer->ApplyChanges(aRepresentation, + NativeLayerCA::UpdateType::OnlyVideo); + }); + + if (allUpdatesSucceeded) { + // Nothing more needed, so early exit; + return; + } + } } // We're going to do a full update now, which requires a transaction. Update - // all of the sublayers. We collect all sublayers with non-zero extents into - // the sublayers array - layers which are completely clipped out will return - // null from UndelyingCALayer. + // all of the sublayers. Afterwards, only continue processing the sublayers + // which have an extent. AutoCATransaction transaction; - NSMutableArray<CALayer*>* sublayers = - [NSMutableArray arrayWithCapacity:aSublayers.Length()]; - bool mustRebuild = updateRequired == UpdateType::All; - for (const auto& layer : aSublayers) { - layer->ApplyChanges(aRepresentation, NativeLayerCA::UpdateType::All, - &mustRebuild); - if (CALayer* caLayer = layer->UnderlyingCALayer(aRepresentation)) { - [sublayers addObject:caLayer]; + nsTArray<NativeLayerCA*> sublayersWithExtent; + for (auto layer : aSublayers) { + mustRebuild |= layer->WillUpdateAffectLayers(aRepresentation); + layer->ApplyChanges(aRepresentation, NativeLayerCA::UpdateType::All); + CALayer* caLayer = layer->UnderlyingCALayer(aRepresentation); + if (!caLayer.masksToBounds || !CGRectIsEmpty(caLayer.bounds)) { + // This layer has an extent. If it didn't before, we need to rebuild. + mustRebuild |= !layer->HasExtent(); + layer->SetHasExtent(true); + sublayersWithExtent.AppendElement(layer); + } else { + // This layer has no extent. If it did before, we need to rebuild. + mustRebuild |= layer->HasExtent(); + layer->SetHasExtent(false); } + + // One other reason we may need to rebuild is if the caLayer is not part of + // the root layer's sublayers. This might happen if the caLayer was rebuilt. + // We construct this check in a way that maximizes the boolean + // short-circuit, because we don't want to call containsObject unless + // absolutely necessary. + mustRebuild = + mustRebuild || ![mRootCALayer.sublayers containsObject:caLayer]; } if (mustRebuild) { - aRootCALayer.sublayers = sublayers; + uint32_t sublayersCount = sublayersWithExtent.Length(); + NSMutableArray<CALayer*>* sublayers = + [NSMutableArray arrayWithCapacity:sublayersCount]; + for (auto layer : sublayersWithExtent) { + [sublayers addObject:layer->UnderlyingCALayer(aRepresentation)]; + } + mRootCALayer.sublayers = sublayers; } -} -SnapshotterCADelegate::~SnapshotterCADelegate() = default; - -NativeLayerRootCA::SnapshotterDelegate::SnapshotterDelegate( - NativeLayerRootCA* aLayerRoot) - : mLayerRoot(aLayerRoot) {} -NativeLayerRootCA::SnapshotterDelegate::~SnapshotterDelegate() = default; + mMutatedLayerStructure = false; +} #ifdef XP_MACOSX /* static */ UniquePtr<NativeLayerRootSnapshotterCA> -NativeLayerRootSnapshotterCA::Create( - UniquePtr<SnapshotterCADelegate>&& aDelegate) { +NativeLayerRootSnapshotterCA::Create(NativeLayerRootCA* aLayerRoot, + CALayer* aRootCALayer) { if (NS_IsMainThread()) { // Disallow creating snapshotters on the main thread. // On the main thread, any explicit CATransaction / NSAnimationContext is @@ -508,7 +552,8 @@ NativeLayerRootSnapshotterCA::Create( } return UniquePtr<NativeLayerRootSnapshotterCA>( - new NativeLayerRootSnapshotterCA(std::move(aDelegate), std::move(gl))); + new NativeLayerRootSnapshotterCA(aLayerRoot, std::move(gl), + aRootCALayer)); } #endif @@ -581,25 +626,22 @@ VideoLowPowerType NativeLayerRootCA::CheckVideoLowPower( // determine more detail. uint32_t videoLayerCount = 0; - DebugOnly<RefPtr<NativeLayerCA>> topLayer; + NativeLayerCA* topLayer = nullptr; CALayer* topCALayer = nil; CALayer* secondCALayer = nil; bool topLayerIsVideo = false; for (auto layer : mSublayers) { // Only layers with extent are contributing to our sublayers. - CALayer* caLayer = layer->UnderlyingCALayer(WhichRepresentation::ONSCREEN); - if (caLayer) { - bool isVideo = layer->IsVideo(aProofOfLock); - if (isVideo) { - ++videoLayerCount; - } + if (layer->HasExtent()) { + topLayer = layer; secondCALayer = topCALayer; - - topLayer = layer; - topCALayer = caLayer; - topLayerIsVideo = isVideo; + topCALayer = topLayer->UnderlyingCALayer(WhichRepresentation::ONSCREEN); + topLayerIsVideo = topLayer->IsVideo(aProofOfLock); + if (topLayerIsVideo) { + ++videoLayerCount; + } } } @@ -672,17 +714,19 @@ VideoLowPowerType NativeLayerRootCA::CheckVideoLowPower( #ifdef XP_MACOSX NativeLayerRootSnapshotterCA::NativeLayerRootSnapshotterCA( - UniquePtr<SnapshotterCADelegate>&& aDelegate, RefPtr<GLContext>&& aGL) - : mDelegate(std::move(aDelegate)), mGL(aGL) {} + NativeLayerRootCA* aLayerRoot, RefPtr<GLContext>&& aGL, + CALayer* aRootCALayer) + : mLayerRoot(aLayerRoot), mGL(aGL) { + AutoCATransaction transaction; + mRenderer = [[CARenderer + rendererWithCGLContext:gl::GLContextCGL::Cast(mGL)->GetCGLContext() + options:nil] retain]; + mRenderer.layer = aRootCALayer; +} NativeLayerRootSnapshotterCA::~NativeLayerRootSnapshotterCA() { - mDelegate->OnSnapshotterDestroyed(this); - - if (mRenderer) { - AutoCATransaction transaction; - mRenderer.layer.sublayers = @[]; - [mRenderer release]; - } + mLayerRoot->OnNativeLayerRootSnapshotterDestroyed(this); + [mRenderer release]; } already_AddRefed<profiler_screenshots::RenderSource> @@ -695,44 +739,20 @@ void NativeLayerRootSnapshotterCA::UpdateSnapshot(const IntSize& aSize) { CGRect bounds = CGRectMake(0, 0, aSize.width, aSize.height); { - // Lazily initialize our renderer, and set the correct bounds and scale - // on the renderer and its root layer. - AutoCATransaction transaction; - if (!mRenderer) { - mRenderer = [[CARenderer - rendererWithCGLContext:gl::GLContextCGL::Cast(mGL)->GetCGLContext() - options:nil] retain]; - // This layer should behave similarly to the backing layer of a flipped - // NSView. It will never be rendered on the screen and it will never be - // attached to an NSView's layer; instead, it will be the root layer of a - // "local" CAContext. Setting geometryFlipped to YES causes the - // orientation of descendant CALayers' contents (such as IOSurfaces) to be - // consistent with what happens in a layer subtree that is attached to a - // flipped NSView. Setting it to NO would cause the surfaces in individual - // leaf layers to render upside down (rather than just flipping the entire - // layer tree upside down). - AutoCATransaction transaction; - CALayer* layer = [CALayer layer]; - layer.position = CGPointZero; - layer.anchorPoint = CGPointZero; - layer.contentsGravity = kCAGravityTopLeft; - layer.masksToBounds = YES; - layer.geometryFlipped = YES; - mRenderer.layer = layer; - } - + // Set the correct bounds and scale on the renderer and its root layer. // CARenderer always renders at unit scale, i.e. the coordinates on the root // layer must map 1:1 to render target pixels. But the coordinates on our // content layers are in "points", where 1 point maps to 2 device pixels on // HiDPI. So in order to render at the full device pixel resolution, we set // a scale transform on the root offscreen layer. + AutoCATransaction transaction; mRenderer.layer.bounds = bounds; - float scale = mDelegate->BackingScale(); + float scale = mLayerRoot->BackingScale(); mRenderer.layer.sublayerTransform = CATransform3DMakeScale(scale, scale, 1); mRenderer.bounds = bounds; } - mDelegate->UpdateSnapshotterLayers(mRenderer.layer); + mLayerRoot->CommitOffscreen(); mGL->MakeCurrent(); @@ -790,11 +810,6 @@ void NativeLayerRootSnapshotterCA::UpdateSnapshot(const IntSize& aSize) { bool NativeLayerRootSnapshotterCA::ReadbackPixels( const IntSize& aReadbackSize, SurfaceFormat aReadbackFormat, const Range<uint8_t>& aReadbackBuffer) { - if (mDelegate->DoCustomReadbackForReftestsIfDesired( - aReadbackSize, aReadbackFormat, aReadbackBuffer)) { - return true; - } - if (aReadbackFormat != SurfaceFormat::B8G8R8A8) { return false; } @@ -856,7 +871,7 @@ NativeLayerCA::NativeLayerCA(bool aIsOpaque) #endif } -CGColorRef CGColorCreateForDeviceColor(const gfx::DeviceColor& aColor) { +CGColorRef CGColorCreateForDeviceColor(gfx::DeviceColor aColor) { if (StaticPrefs::gfx_color_management_native_srgb()) { return CGColorCreateSRGB(aColor.r, aColor.g, aColor.b, aColor.a); } @@ -865,10 +880,9 @@ CGColorRef CGColorCreateForDeviceColor(const gfx::DeviceColor& aColor) { } NativeLayerCA::NativeLayerCA(gfx::DeviceColor aColor) - : mMutex("NativeLayerCA"), - mColor(Some(aColor)), - mIsOpaque(aColor.a >= 1.0f) { + : mMutex("NativeLayerCA"), mIsOpaque(aColor.a >= 1.0f) { MOZ_ASSERT(aColor.a > 0.0f, "Can't handle a fully transparent backdrop."); + mColor.AssignUnderCreateRule(CGColorCreateForDeviceColor(aColor)); } NativeLayerCA::NativeLayerCA(const IntSize& aSize, bool aIsOpaque) @@ -1192,9 +1206,10 @@ void NativeLayerCA::DumpLayer(std::ostream& aOutputStream) { } if (mColor) { - aOutputStream << "background: rgb(" << mColor->r * 255.0f << " " - << mColor->g * 255.0f << " " << mColor->b * 255.0f - << "); opacity: " << mColor->a << "; "; + const CGFloat* components = CGColorGetComponents(mColor.get()); + aOutputStream << "background: rgb(" << components[0] * 255.0f << " " + << components[1] * 255.0f << " " << components[2] * 255.0f + << "); opacity: " << components[3] << "; "; // That's all we need for color layers. We don't need to specify an image. aOutputStream << "\"/></div>\n"; @@ -1357,9 +1372,8 @@ void NativeLayerCA::SetSurfaceToPresent(CFTypeRefPtr<IOSurfaceRef> aSurfaceRef, }); } -NativeLayerCARepresentation::NativeLayerCARepresentation() - : mWrappingCALayerHasExtent(false), - mMutatedPosition(true), +NativeLayerCA::Representation::Representation() + : mMutatedPosition(true), mMutatedTransform(true), mMutatedDisplayRect(true), mMutatedClipRect(true), @@ -1372,7 +1386,7 @@ NativeLayerCARepresentation::NativeLayerCARepresentation() mMutatedSpecializeVideo(true), mMutatedIsDRM(true) {} -NativeLayerCARepresentation::~NativeLayerCARepresentation() { +NativeLayerCA::Representation::~Representation() { [mContentCALayer release]; [mOpaquenessTintLayer release]; [mWrappingCALayer release]; @@ -1430,7 +1444,7 @@ void NativeLayerCA::DiscardBackbuffers() { mSurfaceHandler->DiscardBackbuffers(); } -NativeLayerCARepresentation& NativeLayerCA::GetRepresentation( +NativeLayerCA::Representation& NativeLayerCA::GetRepresentation( WhichRepresentation aRepresentation) { switch (aRepresentation) { case WhichRepresentation::ONSCREEN: @@ -1482,8 +1496,7 @@ Maybe<CGRect> NativeLayerCA::CalculateClipGeometry( } bool NativeLayerCA::ApplyChanges(WhichRepresentation aRepresentation, - NativeLayerCA::UpdateType aUpdate, - bool* aMustRebuild) { + NativeLayerCA::UpdateType aUpdate) { MutexAutoLock lock(mMutex); CFTypeRefPtr<IOSurfaceRef> surface; IntSize size = mSize; @@ -1503,20 +1516,11 @@ bool NativeLayerCA::ApplyChanges(WhichRepresentation aRepresentation, surface = mTextureHost->GetSurface()->GetIOSurfaceRef(); } - auto& r = GetRepresentation(aRepresentation); - if (r.mMutatedSpecializeVideo) { - *aMustRebuild = true; - } - bool hadExtentBeforeUpdate = r.UnderlyingCALayer() != nullptr; - bool updateSucceeded = r.ApplyChanges( - aUpdate, size, mIsOpaque, mPosition, mTransform, displayRect, mClipRect, - mRoundedClipRect, mBackingScale, surfaceIsFlipped, mSamplingFilter, - mSpecializeVideo, surface, mColor, mIsDRM, IsVideo(lock)); - bool hasExtentAfterUpdate = r.UnderlyingCALayer() != nullptr; - if (hasExtentAfterUpdate != hadExtentBeforeUpdate) { - *aMustRebuild = true; - } - return updateSucceeded; + return GetRepresentation(aRepresentation) + .ApplyChanges(aUpdate, size, mIsOpaque, mPosition, mTransform, + displayRect, mClipRect, mRoundedClipRect, mBackingScale, + surfaceIsFlipped, mSamplingFilter, mSpecializeVideo, + surface, mColor, mIsDRM, IsVideo(lock)); } CALayer* NativeLayerCA::UnderlyingCALayer(WhichRepresentation aRepresentation) { @@ -1562,7 +1566,7 @@ static NSString* NSStringForOSType(OSType type) { } } -bool NativeLayerCARepresentation::EnqueueSurface(IOSurfaceRef aSurfaceRef) { +bool NativeLayerCA::Representation::EnqueueSurface(IOSurfaceRef aSurfaceRef) { MOZ_ASSERT( [mContentCALayer isKindOfClass:[AVSampleBufferDisplayLayer class]]); AVSampleBufferDisplayLayer* videoLayer = @@ -1715,14 +1719,14 @@ bool NativeLayerCARepresentation::EnqueueSurface(IOSurfaceRef aSurfaceRef) { return true; } -bool NativeLayerCARepresentation::ApplyChanges( - UpdateType aUpdate, const IntSize& aSize, bool aIsOpaque, +bool NativeLayerCA::Representation::ApplyChanges( + NativeLayerCA::UpdateType aUpdate, const IntSize& aSize, bool aIsOpaque, const IntPoint& aPosition, const Matrix4x4& aTransform, const IntRect& aDisplayRect, const Maybe<IntRect>& aClipRect, const Maybe<gfx::RoundedRect>& aRoundedClip, float aBackingScale, bool aSurfaceIsFlipped, gfx::SamplingFilter aSamplingFilter, - bool aSpecializeVideo, const CFTypeRefPtr<IOSurfaceRef>& aFrontSurface, - const Maybe<gfx::DeviceColor>& aColor, bool aIsDRM, bool aIsVideo) { + bool aSpecializeVideo, CFTypeRefPtr<IOSurfaceRef> aFrontSurface, + CFTypeRefPtr<CGColorRef> aColor, bool aIsDRM, bool aIsVideo) { // If we have an OnlyVideo update, handle it and early exit. if (aUpdate == UpdateType::OnlyVideo) { // If we don't have any updates to do, exit early with success. This is @@ -1800,8 +1804,7 @@ bool NativeLayerCARepresentation::ApplyChanges( if (aColor) { // Color layers set a color on the clip layer and don't get a content // layer. - mRoundedClipCALayer.backgroundColor = - CGColorCreateForDeviceColor(*aColor); + mRoundedClipCALayer.backgroundColor = aColor.get(); } else { if (aSpecializeVideo) { #ifdef NIGHTLY_BUILD @@ -1902,7 +1905,7 @@ bool NativeLayerCARepresentation::ApplyChanges( if (mMutatedBackingScale || mMutatedPosition || mMutatedDisplayRect || mMutatedClipRect || mMutatedRoundedClipRect || mMutatedTransform || mMutatedSurfaceIsFlipped || mMutatedSize || layerNeedsInitialization) { - Maybe<CGRect> scaledClipRect = NativeLayerCA::CalculateClipGeometry( + Maybe<CGRect> scaledClipRect = CalculateClipGeometry( aSize, aPosition, aTransform, aDisplayRect, aClipRect, aBackingScale); CGRect useClipRect; @@ -1916,8 +1919,6 @@ bool NativeLayerCARepresentation::ApplyChanges( mWrappingCALayer.bounds = CGRectMake(0, 0, useClipRect.size.width, useClipRect.size.height); mWrappingCALayer.masksToBounds = scaledClipRect.isSome(); - mWrappingCALayerHasExtent = - scaledClipRect.isNothing() || !CGRectIsEmpty(useClipRect); // Default the clip rect for the rounded rect clip layer to be the // same as the wrapping layer clip. This ensures that if it's not used, @@ -2089,7 +2090,7 @@ bool NativeLayerCARepresentation::ApplyChanges( return true; } -NativeLayerCA::UpdateType NativeLayerCARepresentation::HasUpdate( +NativeLayerCA::UpdateType NativeLayerCA::Representation::HasUpdate( bool aIsVideo) { if (!mWrappingCALayer) { return UpdateType::All; @@ -2115,6 +2116,13 @@ NativeLayerCA::UpdateType NativeLayerCARepresentation::HasUpdate( return UpdateType::None; } +bool NativeLayerCA::WillUpdateAffectLayers( + WhichRepresentation aRepresentation) { + MutexAutoLock lock(mMutex); + auto& r = GetRepresentation(aRepresentation); + return r.mMutatedSpecializeVideo || !r.UnderlyingCALayer(); +} + bool DownscaleTargetNLRS::DownscaleFrom( profiler_screenshots::RenderSource* aSource, const IntRect& aSourceRect, const IntRect& aDestRect) { diff --git a/gfx/layers/NativeLayerRemoteMac.h b/gfx/layers/NativeLayerRemoteMac.h @@ -11,7 +11,7 @@ #include "mozilla/layers/NativeLayer.h" #include "mozilla/layers/NativeLayerCommandQueue.h" #include "mozilla/layers/NativeLayerMacSurfaceHandler.h" -#include "NativeLayerCA.h" +#include "mozilla/layers/NativeLayerRootRemoteMacChild.h" #include "nsRegion.h" namespace mozilla { @@ -73,14 +73,10 @@ class NativeLayerRemoteMac final : public NativeLayer { // If dirty, add a CommandLayerInfo to the queue. Clear dirty flag. void FlushDirtyLayerInfoToCommandQueue(); - void UpdateSnapshotLayer(); - CALayer* CALayerForSnapshot(); - protected: - NativeLayerCARepresentation mSnapshotLayer; Maybe<NativeLayerMacSurfaceHandler> mSurfaceHandler; RefPtr<NativeLayerCommandQueue> mCommandQueue; - const Maybe<gfx::DeviceColor> mColor; + const gfx::DeviceColor mColor; const bool mIsOpaque = false; bool mDirtyLayerInfo = true; diff --git a/gfx/layers/NativeLayerRemoteMac.mm b/gfx/layers/NativeLayerRemoteMac.mm @@ -8,7 +8,6 @@ #include <algorithm> #include <utility> -#include "CFTypeRefPtr.h" #include "gfxUtils.h" #include "GLBlitHelper.h" #ifdef XP_MACOSX @@ -21,17 +20,19 @@ #include "mozilla/gfx/Swizzle.h" #include "mozilla/glean/GfxMetrics.h" #include "mozilla/webrender/RenderMacIOSurfaceTextureHost.h" -#include "NativeLayerCA.h" #include "ScopedGLHelpers.h" namespace mozilla { namespace layers { +using gfx::DataSourceSurface; using gfx::IntPoint; using gfx::IntRect; using gfx::IntRegion; using gfx::IntSize; using gfx::Matrix4x4; +using gfx::SurfaceFormat; +using gl::GLContext; NativeLayerRemoteMac::NativeLayerRemoteMac( const IntSize& aSize, bool aIsOpaque, @@ -45,7 +46,7 @@ NativeLayerRemoteMac::NativeLayerRemoteMac(bool aIsOpaque) : mIsOpaque(aIsOpaque) {} NativeLayerRemoteMac::NativeLayerRemoteMac(gfx::DeviceColor aColor) - : mColor(Some(aColor)), mIsOpaque(aColor.a >= 1.0f) {} + : mColor(aColor), mIsOpaque(aColor.a >= 1.0f) {} NativeLayerRemoteMac::~NativeLayerRemoteMac() { if (mCommandQueue) { @@ -74,7 +75,6 @@ void NativeLayerRemoteMac::AttachExternalImage( mDisplayRect = displayRect; bool isDRM = aExternalImage->IsFromDRMSource(); - bool changedIsDRM = mIsDRM != isDRM; mIsDRM = isDRM; bool isHDR = false; @@ -91,10 +91,6 @@ void NativeLayerRemoteMac::AttachExternalImage( mIsHDR = isHDR; mDirtyLayerInfo |= changedDisplayRect; - mSnapshotLayer.mMutatedFrontSurface = true; - mSnapshotLayer.mMutatedSize |= changedDisplayRect; - mSnapshotLayer.mMutatedDisplayRect |= changedDisplayRect; - mSnapshotLayer.mMutatedIsDRM |= changedIsDRM; mDirtyChangedSurface = true; } @@ -110,7 +106,6 @@ IntSize NativeLayerRemoteMac::GetSize() { void NativeLayerRemoteMac::SetPosition(const IntPoint& aPosition) { if (mPosition != aPosition) { mDirtyLayerInfo = true; - mSnapshotLayer.mMutatedPosition = true; mPosition = aPosition; } } @@ -122,7 +117,6 @@ void NativeLayerRemoteMac::SetTransform(const Matrix4x4& aTransform) { if (mTransform != aTransform) { mDirtyLayerInfo = true; - mSnapshotLayer.mMutatedTransform = true; mTransform = aTransform; } } @@ -131,7 +125,6 @@ void NativeLayerRemoteMac::SetSamplingFilter( gfx::SamplingFilter aSamplingFilter) { if (mSamplingFilter != aSamplingFilter) { mDirtyLayerInfo = true; - mSnapshotLayer.mMutatedSamplingFilter = true; mSamplingFilter = aSamplingFilter; } } @@ -165,7 +158,6 @@ void NativeLayerRemoteMac::SetRoundedClipRect( const Maybe<gfx::RoundedRect>& aRoundedClipRect) { if (mRoundedClipRect != aRoundedClipRect) { mDirtyLayerInfo = true; - mSnapshotLayer.mMutatedRoundedClipRect = true; mRoundedClipRect = aRoundedClipRect; } } @@ -184,7 +176,6 @@ gfx::IntRect NativeLayerRemoteMac::CurrentSurfaceDisplayRect() { void NativeLayerRemoteMac::SetSurfaceIsFlipped(bool aIsFlipped) { if (SurfaceIsFlipped() != aIsFlipped) { mDirtyLayerInfo = true; - mSnapshotLayer.mMutatedSurfaceIsFlipped = true; if (mSurfaceHandler) { mSurfaceHandler->SetSurfaceIsFlipped(aIsFlipped); } else { @@ -235,7 +226,6 @@ void NativeLayerRemoteMac::NotifySurfaceReady() { bool changedDisplayRect = mSurfaceHandler->NotifySurfaceReady(); mDirtyLayerInfo |= changedDisplayRect; mDirtyChangedSurface = true; - mSnapshotLayer.mMutatedFrontSurface = true; } void NativeLayerRemoteMac::DiscardBackbuffers() { @@ -253,7 +243,7 @@ void NativeLayerRemoteMac::FlushDirtyLayerInfoToCommandQueue() { // Get the unique ID for this IOSurfaceRef, which only works // because kIOSurfaceIsGlobal was set to true when this // IOSurface was created. - IOSurfaceRef surfaceRef = surfaceWithInvalidRegion->mSurface.get(); + auto surfaceRef = surfaceWithInvalidRegion->mSurface.get(); surfaceID = IOSurfaceGetID(surfaceRef); } @@ -271,27 +261,5 @@ void NativeLayerRemoteMac::FlushDirtyLayerInfoToCommandQueue() { } } -void NativeLayerRemoteMac::UpdateSnapshotLayer() { - CFTypeRefPtr<IOSurfaceRef> surface; - if (auto frontSurface = FrontSurface()) { - surface = frontSurface->mSurface; - } - - IntRect rect = GetRect(); - IntRect displayRect = CurrentSurfaceDisplayRect(); - - bool specializeVideo = false; - bool isVideo = false; - mSnapshotLayer.ApplyChanges( - NativeLayerCAUpdateType::All, rect.Size(), mIsOpaque, rect.TopLeft(), - mTransform, displayRect, mClipRect, mRoundedClipRect, mBackingScale, - mSurfaceIsFlipped, mSamplingFilter, specializeVideo, surface, mColor, - mIsDRM, isVideo); -} - -CALayer* NativeLayerRemoteMac::CALayerForSnapshot() { - return mSnapshotLayer.UnderlyingCALayer(); -} - } // namespace layers } // namespace mozilla diff --git a/gfx/layers/NativeLayerRootRemoteMacChild.h b/gfx/layers/NativeLayerRootRemoteMacChild.h @@ -6,9 +6,9 @@ #ifndef mozilla_layers_NativeLayerRootRemoteMacChild_h #define mozilla_layers_NativeLayerRootRemoteMacChild_h +#include "mozilla/layers/NativeLayer.h" #include "mozilla/layers/NativeLayerCommandQueue.h" #include "mozilla/layers/NativeLayerRemoteChild.h" -#include "mozilla/layers/NativeLayerRemoteMac.h" namespace mozilla { namespace layers { @@ -47,57 +47,15 @@ class NativeLayerRootRemoteMacChild final : public NativeLayerRoot { virtual ~NativeLayerRootRemoteMacChild(); - void CommitForSnapshot(CALayer* aRootCALayer); - void OnNativeLayerRootSnapshotterDestroyed( - NativeLayerRootSnapshotterCA* aNativeLayerRootSnapshotter); - - // An implementation of SnapshotterCADelegate, backed by a - // NativeLayerRootRemoteMacChild. - struct SnapshotterDelegate final : public SnapshotterCADelegate { - explicit SnapshotterDelegate(NativeLayerRootRemoteMacChild* aLayerRoot); - virtual ~SnapshotterDelegate() override; - virtual void UpdateSnapshotterLayers(CALayer* aRootCALayer) override { - mLayerRoot->CommitForSnapshot(aRootCALayer); - } - virtual bool DoCustomReadbackForReftestsIfDesired( - const gfx::IntSize& aReadbackSize, gfx::SurfaceFormat aReadbackFormat, - const Range<uint8_t>& aReadbackBuffer) override { - return mLayerRoot->ReadbackPixelsFromParent( - aReadbackSize, aReadbackFormat, aReadbackBuffer); - } - virtual void OnSnapshotterDestroyed( - NativeLayerRootSnapshotterCA* aSnapshotter) override { - mLayerRoot->OnNativeLayerRootSnapshotterDestroyed(aSnapshotter); - } - RefPtr<NativeLayerRootRemoteMacChild> mLayerRoot; - }; - RefPtr<NativeLayerRemoteChild> mRemoteChild; RefPtr<NativeLayerCommandQueue> mCommandQueue; - nsTArray<RefPtr<NativeLayerRemoteMac>> mNativeLayers; - NativeLayerRootSnapshotterCA* mWeakSnapshotter = nullptr; + nsTArray<RefPtr<NativeLayer>> mNativeLayers; + NativeLayerRootSnapshotter* mWeakSnapshotter = nullptr; bool mNativeLayersChanged = false; - bool mNativeLayersChangedForSnapshot = false; - - // Send a sync message to the parent to get the window pixels. - // Used for reftests. - // - // This is different from what we do for "window recorder" and - // "profiler screenshot" snapshotting, where we do the snapshotting - // within the GPU process, using CARenderer on a CALayer tree we - // construct within the GPU process. - // - // Here's why we have two different snapshotting paths: - // - Profiler screenshots and window recording care about minimal overhead - // and need to minimize blocking on the GPU. - // - Reftests care about catching bugs, and don't need maximum performance. - // By doing the readback in the parent, we can catch more bugs, for - // example bugs in the IPC serialization of layer updates and how those - // updates are applied on the parent side. - bool ReadbackPixelsFromParent(const gfx::IntSize& aSize, - gfx::SurfaceFormat aFormat, - const Range<uint8_t>& aBuffer); + + bool ReadbackPixels(const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, + const Range<uint8_t>& aBuffer); }; } // namespace layers diff --git a/gfx/layers/NativeLayerRootRemoteMacChild.mm b/gfx/layers/NativeLayerRootRemoteMacChild.mm @@ -5,6 +5,7 @@ #include "mozilla/layers/NativeLayerRemoteMac.h" #include "mozilla/layers/NativeLayerRootRemoteMacChild.h" +#include "mozilla/layers/NativeLayerRootRemoteMacSnapshotter.h" #include "mozilla/layers/SurfacePool.h" namespace mozilla { @@ -51,8 +52,8 @@ void NativeLayerRootRemoteMacChild::SetLayers( const nsTArray<RefPtr<NativeLayer>>& aLayers) { // We don't create a command for this, because we don't care // about the layers until CommitToScreen(). - nsTArray<RefPtr<NativeLayerRemoteMac>> layers(aLayers.Length()); - for (const auto& layer : aLayers) { + nsTArray<RefPtr<NativeLayer>> layers(aLayers.Length()); + for (auto& layer : aLayers) { RefPtr<NativeLayerRemoteMac> layerRemoteMac = layer->AsNativeLayerRemoteMac(); MOZ_ASSERT(layerRemoteMac); @@ -65,7 +66,6 @@ void NativeLayerRootRemoteMacChild::SetLayers( } mNativeLayersChanged = true; - mNativeLayersChangedForSnapshot = true; mNativeLayers.Clear(); mNativeLayers.AppendElements(layers); } @@ -76,20 +76,13 @@ NativeLayerRootRemoteMacChild::CreateSnapshotter() { "No NativeLayerRootSnapshotter for this NativeLayerRoot " "should exist when this is called"); - auto cr = NativeLayerRootSnapshotterCA::Create( - MakeUnique<SnapshotterDelegate>(this)); + auto cr = NativeLayerRootRemoteMacSnapshotter::Create(this); if (cr) { mWeakSnapshotter = cr.get(); } return cr; } -void NativeLayerRootRemoteMacChild::OnNativeLayerRootSnapshotterDestroyed( - NativeLayerRootSnapshotterCA* aNativeLayerRootSnapshotter) { - MOZ_RELEASE_ASSERT(mWeakSnapshotter == aNativeLayerRootSnapshotter); - mWeakSnapshotter = nullptr; -} - void NativeLayerRootRemoteMacChild::PrepareForCommit() { // Intentionally ignored. } @@ -103,8 +96,11 @@ bool NativeLayerRootRemoteMacChild::CommitToScreen() { // Iterate our layers to get the LayerInfo and ChangedSurface commands // into our shared command queue. - for (const auto& layer : mNativeLayers) { - layer->FlushDirtyLayerInfoToCommandQueue(); + for (auto layer : mNativeLayers) { + RefPtr<NativeLayerRemoteMac> layerRemoteMac( + layer->AsNativeLayerRemoteMac()); + MOZ_ASSERT(layerRemoteMac); + layerRemoteMac->FlushDirtyLayerInfoToCommandQueue(); } if (mNativeLayersChanged) { @@ -112,7 +108,7 @@ bool NativeLayerRootRemoteMacChild::CommitToScreen() { // command of this array filled with the IDs of everything // in mNativeLayers. nsTArray<uint64_t> setLayerIDs; - for (const auto& layer : mNativeLayers) { + for (auto layer : mNativeLayers) { auto ID = reinterpret_cast<uint64_t>(layer.get()); setLayerIDs.AppendElement(ID); } @@ -134,26 +130,7 @@ bool NativeLayerRootRemoteMacChild::CommitToScreen() { return true; } -void NativeLayerRootRemoteMacChild::CommitForSnapshot(CALayer* aRootCALayer) { - [CATransaction begin]; - [CATransaction setDisableActions:YES]; // disable cross-fade - - NSMutableArray<CALayer*>* sublayers = - [NSMutableArray arrayWithCapacity:mNativeLayers.Length()]; - for (const auto& layer : mNativeLayers) { - layer->UpdateSnapshotLayer(); - if (CALayer* caLayer = layer->CALayerForSnapshot()) { - [sublayers addObject:caLayer]; - } - } - - aRootCALayer.sublayers = sublayers; - [CATransaction commit]; - - mNativeLayersChangedForSnapshot = false; -} - -bool NativeLayerRootRemoteMacChild::ReadbackPixelsFromParent( +bool NativeLayerRootRemoteMacChild::ReadbackPixels( const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat, const Range<uint8_t>& aBuffer) { // In this process we only have the pixels of the individual layers, @@ -186,11 +163,5 @@ NativeLayerRootRemoteMacChild::NativeLayerRootRemoteMacChild() NativeLayerRootRemoteMacChild::~NativeLayerRootRemoteMacChild() {} -NativeLayerRootRemoteMacChild::SnapshotterDelegate::SnapshotterDelegate( - NativeLayerRootRemoteMacChild* aLayerRoot) - : mLayerRoot(aLayerRoot) {} -NativeLayerRootRemoteMacChild::SnapshotterDelegate::~SnapshotterDelegate() = - default; - } // namespace layers } // namespace mozilla diff --git a/gfx/layers/NativeLayerRootRemoteMacSnapshotter.h b/gfx/layers/NativeLayerRootRemoteMacSnapshotter.h @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 2; 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 mozilla_layers_NativeLayerRootRemoteMacSnapshotter_h +#define mozilla_layers_NativeLayerRootRemoteMacSnapshotter_h + +#include "mozilla/RefPtr.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/gfx/Point.h" +#include "mozilla/layers/NativeLayer.h" +#include "mozilla/layers/ScreenshotGrabber.h" + +namespace mozilla { +namespace layers { + +class NativeLayerRootRemoteMacChild; + +class NativeLayerRootRemoteMacSnapshotter : public NativeLayerRootSnapshotter { + public: + static UniquePtr<NativeLayerRootRemoteMacSnapshotter> Create( + NativeLayerRootRemoteMacChild* aLayerRoot); + + bool ReadbackPixels(const gfx::IntSize& aReadbackSize, + gfx::SurfaceFormat aReadbackFormat, + const Range<uint8_t>& aReadbackBuffer); + + already_AddRefed<profiler_screenshots::RenderSource> GetWindowContents( + const gfx::IntSize& aSize); + already_AddRefed<profiler_screenshots::DownscaleTarget> CreateDownscaleTarget( + const gfx::IntSize& aSize); + + already_AddRefed<profiler_screenshots::AsyncReadbackBuffer> + CreateAsyncReadbackBuffer(const gfx::IntSize& aSize); + + protected: + explicit NativeLayerRootRemoteMacSnapshotter( + NativeLayerRootRemoteMacChild* aLayerRoot); + + RefPtr<NativeLayerRootRemoteMacChild> mLayerRoot; +}; + +} // namespace layers +} // namespace mozilla + +#endif // mozilla_layers_NativeLayerRootRemoteMacSnapshotter_h diff --git a/gfx/layers/NativeLayerRootRemoteMacSnapshotter.mm b/gfx/layers/NativeLayerRootRemoteMacSnapshotter.mm @@ -0,0 +1,50 @@ +/* -*- 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/. */ + +#include "mozilla/layers/NativeLayerRootRemoteMacSnapshotter.h" + +#include "mozilla/layers/NativeLayerRootRemoteMacChild.h" + +namespace mozilla { +namespace layers { + +/* static */ UniquePtr<NativeLayerRootRemoteMacSnapshotter> +NativeLayerRootRemoteMacSnapshotter::Create( + NativeLayerRootRemoteMacChild* aLayerRoot) { + return UniquePtr<NativeLayerRootRemoteMacSnapshotter>( + new NativeLayerRootRemoteMacSnapshotter(aLayerRoot)); +} + +NativeLayerRootRemoteMacSnapshotter::NativeLayerRootRemoteMacSnapshotter( + NativeLayerRootRemoteMacChild* aLayerRoot) + : mLayerRoot(aLayerRoot) {} + +bool NativeLayerRootRemoteMacSnapshotter::ReadbackPixels( + const gfx::IntSize& aReadbackSize, gfx::SurfaceFormat aReadbackFormat, + const Range<uint8_t>& aReadbackBuffer) { + return mLayerRoot->ReadbackPixels(aReadbackSize, aReadbackFormat, + aReadbackBuffer); +} + +already_AddRefed<profiler_screenshots::RenderSource> +NativeLayerRootRemoteMacSnapshotter::GetWindowContents( + const gfx::IntSize& aSize) { + return nullptr; +} + +already_AddRefed<profiler_screenshots::DownscaleTarget> +NativeLayerRootRemoteMacSnapshotter::CreateDownscaleTarget( + const gfx::IntSize& aSize) { + return nullptr; +} + +already_AddRefed<profiler_screenshots::AsyncReadbackBuffer> +NativeLayerRootRemoteMacSnapshotter::CreateAsyncReadbackBuffer( + const gfx::IntSize& aSize) { + return nullptr; +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build @@ -275,6 +275,7 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] in ("cocoa", "uikit"): "NativeLayerRemoteMac.h", "NativeLayerRootRemoteMacChild.h", "NativeLayerRootRemoteMacParent.h", + "NativeLayerRootRemoteMacSnapshotter.h", "SurfacePoolCA.h", ] EXPORTS += [ @@ -287,6 +288,7 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] in ("cocoa", "uikit"): "NativeLayerRemoteMac.mm", "NativeLayerRootRemoteMacChild.mm", "NativeLayerRootRemoteMacParent.mm", + "NativeLayerRootRemoteMacSnapshotter.mm", "SurfacePoolCA.mm", ] SOURCES += [