Bug 1690340 - Part 2: Use the new naming for the developer tools menu items. r=jdescottes
[gecko.git] / gfx / layers / NativeLayerCA.h
blobcec836769bcca75fc2ba56226532dacc2415d45e
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef mozilla_layers_NativeLayerCA_h
7 #define mozilla_layers_NativeLayerCA_h
9 #include <IOSurface/IOSurface.h>
11 #include <deque>
12 #include <unordered_map>
14 #include "mozilla/Mutex.h"
16 #include "mozilla/gfx/MacIOSurface.h"
17 #include "mozilla/layers/NativeLayer.h"
18 #include "CFTypeRefPtr.h"
19 #include "nsRegion.h"
20 #include "nsISupportsImpl.h"
22 #ifdef __OBJC__
23 @class CALayer;
24 #else
25 typedef void CALayer;
26 #endif
28 namespace mozilla {
30 namespace gl {
31 class GLContextCGL;
32 class MozFramebuffer;
33 } // namespace gl
34 namespace wr {
35 class RenderMacIOSurfaceTextureHost;
36 } // namespace wr
38 namespace layers {
40 class NativeLayerRootSnapshotterCA;
41 class SurfacePoolHandleCA;
43 // NativeLayerRootCA is the CoreAnimation implementation of the NativeLayerRoot
44 // interface. A NativeLayerRootCA is created by the widget around an existing
45 // CALayer with a call to CreateForCALayer - this CALayer is the root of the
46 // "onscreen" representation of this layer tree.
47 // All methods can be called from any thread, there is internal locking.
48 // All effects from mutating methods are buffered locally and don't modify the
49 // underlying CoreAnimation layers until CommitToScreen() is called. This
50 // ensures that the modifications happen on the right thread.
52 // More specifically: During normal operation, screen updates are driven from a
53 // compositing thread. On this thread, the layers are created / destroyed, their
54 // contents are painted, and the result is committed to the screen. However,
55 // there are some scenarios that need to involve the main thread, most notably
56 // window resizing: During a window resize, we still need the drawing part to
57 // happen on the compositing thread, but the modifications to the underlying
58 // CALayers need to happen on the main thread, once compositing is done.
60 // NativeLayerRootCA + NativeLayerCA create and maintain *two* CALayer tree
61 // representations: An "onscreen" representation and an "offscreen"
62 // representation. These representations are updated via calls to
63 // CommitToScreen() and CommitOffscreen(), respectively. The reason for having
64 // two representations is the following: Our implementation of the snapshotter
65 // API uses CARenderer, which lets us render the composited result of our layer
66 // tree into a GPU buffer. But CARenderer requires "ownership" of the rendered
67 // CALayers in the sense that it associates the CALayers with a local
68 // "CAContext". A CALayer can only be associated with one CAContext at any time.
69 // If we wanted te render our *onscreen* CALayers with CARenderer, we would need
70 // to remove them from the window, reparent them to the CARenderer, render them,
71 // and then put them back into the window. This would lead to a visible flashing
72 // effect. To solve this problem, we build two CALayer representations, so that
73 // one representation can stay inside the window and the other can stay attached
74 // to the CARenderer.
75 class NativeLayerRootCA : public NativeLayerRoot {
76 public:
77 static already_AddRefed<NativeLayerRootCA> CreateForCALayer(CALayer* aLayer);
79 // Can be called on any thread at any point. Returns whether comitting was
80 // successful. Will return false if called off the main thread while
81 // off-main-thread commits are suspended.
82 bool CommitToScreen() override;
84 void CommitOffscreen();
85 void OnNativeLayerRootSnapshotterDestroyed(
86 NativeLayerRootSnapshotterCA* aNativeLayerRootSnapshotter);
88 // Enters a mode during which CommitToScreen(), when called on a non-main
89 // thread, will not apply any updates to the CALayer tree.
90 void SuspendOffMainThreadCommits();
92 // Exits the mode entered by SuspendOffMainThreadCommits().
93 // Returns true if the last CommitToScreen() was canceled due to suspension,
94 // indicating that another call to CommitToScreen() is needed.
95 bool UnsuspendOffMainThreadCommits();
97 bool AreOffMainThreadCommitsSuspended();
99 enum class WhichRepresentation : uint8_t { ONSCREEN, OFFSCREEN };
101 // Overridden methods
102 already_AddRefed<NativeLayer> CreateLayer(
103 const gfx::IntSize& aSize, bool aIsOpaque,
104 SurfacePoolHandle* aSurfacePoolHandle) override;
105 void AppendLayer(NativeLayer* aLayer) override;
106 void RemoveLayer(NativeLayer* aLayer) override;
107 void SetLayers(const nsTArray<RefPtr<NativeLayer>>& aLayers) override;
108 UniquePtr<NativeLayerRootSnapshotter> CreateSnapshotter() override;
110 void SetBackingScale(float aBackingScale);
111 float BackingScale();
113 already_AddRefed<NativeLayer> CreateLayerForExternalTexture(
114 bool aIsOpaque) override;
116 protected:
117 explicit NativeLayerRootCA(CALayer* aLayer);
118 ~NativeLayerRootCA() override;
120 struct Representation {
121 explicit Representation(CALayer* aRootCALayer);
122 ~Representation();
123 void Commit(WhichRepresentation aRepresentation,
124 const nsTArray<RefPtr<NativeLayerCA>>& aSublayers);
125 CALayer* mRootCALayer = nullptr; // strong
126 bool mMutated = false;
129 template <typename F>
130 void ForAllRepresentations(F aFn);
132 Mutex mMutex; // protects all other fields
133 Representation mOnscreenRepresentation;
134 Representation mOffscreenRepresentation;
135 NativeLayerRootSnapshotterCA* mWeakSnapshotter = nullptr;
136 nsTArray<RefPtr<NativeLayerCA>> mSublayers; // in z-order
137 float mBackingScale = 1.0f;
138 bool mMutated = false;
140 // While mOffMainThreadCommitsSuspended is true, no commits
141 // should happen on a non-main thread, because they might race with
142 // main-thread driven updates such as window shape changes, and cause
143 // glitches.
144 bool mOffMainThreadCommitsSuspended = false;
146 // Set to true if CommitToScreen() was aborted because of commit suspension.
147 // Set to false when CommitToScreen() completes successfully. When true,
148 // indicates that CommitToScreen() needs to be called at the next available
149 // opportunity.
150 bool mCommitPending = false;
153 class RenderSourceNLRS;
155 class NativeLayerRootSnapshotterCA final : public NativeLayerRootSnapshotter {
156 public:
157 static UniquePtr<NativeLayerRootSnapshotterCA> Create(
158 NativeLayerRootCA* aLayerRoot, CALayer* aRootCALayer);
159 virtual ~NativeLayerRootSnapshotterCA();
161 bool ReadbackPixels(const gfx::IntSize& aReadbackSize,
162 gfx::SurfaceFormat aReadbackFormat,
163 const Range<uint8_t>& aReadbackBuffer) override;
164 already_AddRefed<profiler_screenshots::RenderSource> GetWindowContents(
165 const gfx::IntSize& aWindowSize) override;
166 already_AddRefed<profiler_screenshots::DownscaleTarget> CreateDownscaleTarget(
167 const gfx::IntSize& aSize) override;
168 already_AddRefed<profiler_screenshots::AsyncReadbackBuffer>
169 CreateAsyncReadbackBuffer(const gfx::IntSize& aSize) override;
171 protected:
172 NativeLayerRootSnapshotterCA(NativeLayerRootCA* aLayerRoot,
173 RefPtr<gl::GLContext>&& aGL,
174 CALayer* aRootCALayer);
175 void UpdateSnapshot(const gfx::IntSize& aSize);
177 RefPtr<NativeLayerRootCA> mLayerRoot;
178 RefPtr<gl::GLContext> mGL;
180 // Can be null. Created and updated in UpdateSnapshot.
181 RefPtr<RenderSourceNLRS> mSnapshot;
182 CARenderer* mRenderer = nullptr; // strong
185 // NativeLayerCA wraps a CALayer and lets you draw to it. It ensures that only
186 // fully-drawn frames make their way to the screen, by maintaining a swap chain
187 // of IOSurfaces.
188 // All calls to mutating methods are buffered, and don't take effect on the
189 // underlying CoreAnimation layers until ApplyChanges() is called.
190 // The two most important methods are NextSurface and NotifySurfaceReady:
191 // NextSurface takes an available surface from the swap chain or creates a new
192 // surface if necessary. This surface can then be drawn to. Once drawing is
193 // finished, NotifySurfaceReady marks the surface as ready. This surface is
194 // committed to the layer during the next call to ApplyChanges().
195 // The swap chain keeps track of invalid areas within the surfaces.
196 class NativeLayerCA : public NativeLayer {
197 public:
198 virtual NativeLayerCA* AsNativeLayerCA() override { return this; }
200 // Overridden methods
201 gfx::IntSize GetSize() override;
202 void SetPosition(const gfx::IntPoint& aPosition) override;
203 gfx::IntPoint GetPosition() override;
204 void SetTransform(const gfx::Matrix4x4& aTransform) override;
205 gfx::Matrix4x4 GetTransform() override;
206 gfx::IntRect GetRect() override;
207 void SetSamplingFilter(gfx::SamplingFilter aSamplingFilter) override;
208 RefPtr<gfx::DrawTarget> NextSurfaceAsDrawTarget(
209 const gfx::IntRect& aDisplayRect, const gfx::IntRegion& aUpdateRegion,
210 gfx::BackendType aBackendType) override;
211 Maybe<GLuint> NextSurfaceAsFramebuffer(const gfx::IntRect& aDisplayRect,
212 const gfx::IntRegion& aUpdateRegion,
213 bool aNeedsDepth) override;
214 void NotifySurfaceReady() override;
215 void DiscardBackbuffers() override;
216 bool IsOpaque() override;
217 void SetClipRect(const Maybe<gfx::IntRect>& aClipRect) override;
218 Maybe<gfx::IntRect> ClipRect() override;
219 gfx::IntRect CurrentSurfaceDisplayRect() override;
220 void SetSurfaceIsFlipped(bool aIsFlipped) override;
221 bool SurfaceIsFlipped() override;
223 void AttachExternalImage(wr::RenderTextureHost* aExternalImage) override;
225 protected:
226 friend class NativeLayerRootCA;
228 NativeLayerCA(const gfx::IntSize& aSize, bool aIsOpaque,
229 SurfacePoolHandleCA* aSurfacePoolHandle);
230 explicit NativeLayerCA(bool aIsOpaque);
231 ~NativeLayerCA() override;
233 // Gets the next surface for drawing from our swap chain and stores it in
234 // mInProgressSurface. Returns whether this was successful.
235 // mInProgressSurface is guaranteed to be not in use by the window server.
236 // After a call to NextSurface, NextSurface must not be called again until
237 // after NotifySurfaceReady has been called. Can be called on any thread. When
238 // used from multiple threads, callers need to make sure that they still only
239 // call NextSurface and NotifySurfaceReady alternatingly and not in any other
240 // order.
241 bool NextSurface(const MutexAutoLock&);
243 // To be called by NativeLayerRootCA:
244 typedef NativeLayerRootCA::WhichRepresentation WhichRepresentation;
245 CALayer* UnderlyingCALayer(WhichRepresentation aRepresentation);
246 void ApplyChanges(WhichRepresentation aRepresentation);
247 bool HasUpdate(WhichRepresentation aRepresentation);
248 void SetBackingScale(float aBackingScale);
250 // Invalidates the specified region in all surfaces that are tracked by this
251 // layer.
252 void InvalidateRegionThroughoutSwapchain(const MutexAutoLock&,
253 const gfx::IntRegion& aRegion);
255 GLuint GetOrCreateFramebufferForSurface(const MutexAutoLock&,
256 CFTypeRefPtr<IOSurfaceRef> aSurface,
257 bool aNeedsDepth);
259 // Invalidate aUpdateRegion and make sure that mInProgressSurface retains any
260 // valid content from the previous surface outside of aUpdateRegion, so that
261 // only aUpdateRegion needs to be drawn. If content needs to be copied,
262 // aCopyFn is called to do the copying.
263 // aCopyFn: Fn(CFTypeRefPtr<IOSurfaceRef> aValidSourceIOSurface,
264 // const gfx::IntRegion& aCopyRegion) -> void
265 template <typename F>
266 void HandlePartialUpdate(const MutexAutoLock&,
267 const gfx::IntRect& aDisplayRect,
268 const gfx::IntRegion& aUpdateRegion, F&& aCopyFn);
270 struct SurfaceWithInvalidRegion {
271 CFTypeRefPtr<IOSurfaceRef> mSurface;
272 gfx::IntRegion mInvalidRegion;
275 struct SurfaceWithInvalidRegionAndCheckCount {
276 SurfaceWithInvalidRegion mEntry;
277 uint32_t mCheckCount; // The number of calls to IOSurfaceIsInUse
280 Maybe<SurfaceWithInvalidRegion> GetUnusedSurfaceAndCleanUp(
281 const MutexAutoLock&);
283 // Wraps one CALayer representation of this NativeLayer.
284 struct Representation {
285 ~Representation();
287 CALayer* UnderlyingCALayer() { return mWrappingCALayer; }
289 // Applies buffered changes to the native CALayers. The contract with the
290 // caller is as follows: If any of these values have changed since the last
291 // call to ApplyChanges, mMutated[Field] needs to have been set to true
292 // before the call.
293 void ApplyChanges(const gfx::IntSize& aSize, bool aIsOpaque,
294 const gfx::IntPoint& aPosition,
295 const gfx::Matrix4x4& aTransform,
296 const gfx::IntRect& aDisplayRect,
297 const Maybe<gfx::IntRect>& aClipRect, float aBackingScale,
298 bool aSurfaceIsFlipped,
299 gfx::SamplingFilter aSamplingFilter,
300 CFTypeRefPtr<IOSurfaceRef> aFrontSurface);
302 // Return whether any aspects of this layer representation have been mutated
303 // since the last call to ApplyChanges, i.e. whether ApplyChanges needs to
304 // be called.
305 // This is used to optimize away a CATransaction commit if no layers have
306 // changed.
307 bool HasUpdate();
309 // Lazily initialized by first call to ApplyChanges. mWrappingLayer is the
310 // layer that applies the intersection of mDisplayRect and mClipRect (if
311 // set), and mContentCALayer is the layer that hosts the IOSurface. We do
312 // not share clip layers between consecutive NativeLayerCA objects with the
313 // same clip rect.
314 CALayer* mWrappingCALayer = nullptr; // strong
315 CALayer* mContentCALayer = nullptr; // strong
316 CALayer* mOpaquenessTintLayer = nullptr; // strong
318 bool mMutatedPosition = true;
319 bool mMutatedTransform = true;
320 bool mMutatedDisplayRect = true;
321 bool mMutatedClipRect = true;
322 bool mMutatedBackingScale = true;
323 bool mMutatedSize = true;
324 bool mMutatedSurfaceIsFlipped = true;
325 bool mMutatedFrontSurface = true;
326 bool mMutatedSamplingFilter = true;
329 Representation& GetRepresentation(WhichRepresentation aRepresentation);
330 template <typename F>
331 void ForAllRepresentations(F aFn);
333 // Controls access to all fields of this class.
334 Mutex mMutex;
336 // Each IOSurface is initially created inside NextSurface.
337 // The surface stays alive until the recycling mechanism in NextSurface
338 // determines it is no longer needed (because the swap chain has grown too
339 // long) or until DiscardBackbuffers() is called or the layer is destroyed.
340 // During the surface's lifetime, it will continuously move through the fields
341 // mInProgressSurface, mFrontSurface, and back to front through the mSurfaces
342 // queue:
344 // mSurfaces.front()
345 // ------[NextSurface()]-----> mInProgressSurface
346 // --[NotifySurfaceReady()]--> mFrontSurface
347 // --[NotifySurfaceReady()]--> mSurfaces.back() --> .... -->
348 // mSurfaces.front()
350 // We mark an IOSurface as "in use" as long as it is either in
351 // mInProgressSurface. When it is in mFrontSurface or in the mSurfaces queue,
352 // it is not marked as "in use" by us - but it can be "in use" by the window
353 // server. Consequently, IOSurfaceIsInUse on a surface from mSurfaces reflects
354 // whether the window server is still reading from the surface, and we can use
355 // this indicator to decide when to recycle the surface.
357 // Users of NativeLayerCA normally proceed in this order:
358 // 1. Begin a frame by calling NextSurface to get the surface.
359 // 2. Draw to the surface.
360 // 3. Mark the surface as done by calling NotifySurfaceReady.
361 // 4. Call NativeLayerRoot::CommitToScreen(), which calls ApplyChanges()
362 // during a CATransaction.
364 // The surface we returned from the most recent call to NextSurface, before
365 // the matching call to NotifySurfaceReady.
366 // Will only be Some() between calls to NextSurface and NotifySurfaceReady.
367 Maybe<SurfaceWithInvalidRegion> mInProgressSurface;
368 Maybe<gfx::IntRegion> mInProgressUpdateRegion;
369 Maybe<gfx::IntRect> mInProgressDisplayRect;
371 // The surface that the most recent call to NotifySurfaceReady was for.
372 // Will be Some() after the first call to NotifySurfaceReady, for the rest of
373 // the layer's life time.
374 Maybe<SurfaceWithInvalidRegion> mFrontSurface;
376 // The queue of surfaces which make up the rest of our "swap chain".
377 // mSurfaces.front() is the next surface we'll attempt to use.
378 // mSurfaces.back() is the one that was used most recently.
379 std::vector<SurfaceWithInvalidRegionAndCheckCount> mSurfaces;
381 // Non-null between calls to NextSurfaceAsDrawTarget and NotifySurfaceReady.
382 RefPtr<MacIOSurface> mInProgressLockedIOSurface;
384 RefPtr<SurfacePoolHandleCA> mSurfacePoolHandle;
385 RefPtr<wr::RenderMacIOSurfaceTextureHost> mTextureHost;
387 Representation mOnscreenRepresentation;
388 Representation mOffscreenRepresentation;
390 gfx::IntPoint mPosition;
391 gfx::Matrix4x4 mTransform;
392 gfx::IntRect mDisplayRect;
393 gfx::IntSize mSize;
394 Maybe<gfx::IntRect> mClipRect;
395 gfx::SamplingFilter mSamplingFilter = gfx::SamplingFilter::POINT;
396 float mBackingScale = 1.0f;
397 bool mSurfaceIsFlipped = false;
398 const bool mIsOpaque = false;
401 } // namespace layers
402 } // namespace mozilla
404 #endif // mozilla_layers_NativeLayerCA_h