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:
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 += [