tor-browser

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

NativeLayerMacSurfaceHandler.h (10918B)


      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/. */
      5 
      6 #ifndef mozilla_layers_NativeLayerMacSurfaceHandler_h
      7 #define mozilla_layers_NativeLayerMacSurfaceHandler_h
      8 
      9 #include "mozilla/Maybe.h"
     10 #include "mozilla/gfx/MacIOSurface.h"
     11 #include "mozilla/gfx/Types.h"
     12 
     13 #include "CFTypeRefPtr.h"
     14 #include "GLTypes.h"
     15 #include "nsISupportsImpl.h"
     16 #include "nsRegion.h"
     17 
     18 namespace mozilla {
     19 
     20 namespace gl {
     21 class GLContext;
     22 }  // namespace gl
     23 
     24 namespace wr {
     25 class RenderTextureHost;
     26 class RenderMacIOSurfaceTextureHost;
     27 }  // namespace wr
     28 
     29 namespace layers {
     30 class SurfacePoolHandleCA;
     31 
     32 struct SurfaceWithInvalidRegion {
     33  CFTypeRefPtr<IOSurfaceRef> mSurface;
     34  gfx::IntRegion mInvalidRegion;
     35 };
     36 
     37 struct SurfaceWithInvalidRegionAndCheckCount {
     38  SurfaceWithInvalidRegion mEntry;
     39  uint32_t mCheckCount;  // The number of calls to IOSurfaceIsInUse
     40 };
     41 
     42 // A companion to macOS-specific subclasses of NativeLayer, this class
     43 // handles the implementation of the surface management calls. The
     44 // expectation is that NativeLayerMacIOSurfaceHandler is composed into
     45 // these classes, rather than be used as a superclass/.
     46 class NativeLayerMacSurfaceHandler {
     47 public:
     48  NativeLayerMacSurfaceHandler(const gfx::IntSize& aSize,
     49                               SurfacePoolHandleCA* aSurfacePoolHandle);
     50  ~NativeLayerMacSurfaceHandler();
     51 
     52  gfx::IntSize Size() { return mSize; }
     53 
     54  // Returns the "display rect", in content coordinates, of the current front
     55  // surface. This rect acts as an extra clip and prevents invalid content from
     56  // getting to the screen. The display rect starts out empty before the first
     57  // call to NextSurface*. Note the different coordinate space from the regular
     58  // clip rect: the clip rect is "outside" the layer position, the display rect
     59  // is "inside" the layer position (moves with the layer).
     60  gfx::IntRect DisplayRect() { return mDisplayRect; }
     61 
     62  void SetSurfaceIsFlipped(bool aIsFlipped) { mSurfaceIsFlipped = aIsFlipped; }
     63  bool SurfaceIsFlipped() { return mSurfaceIsFlipped; }
     64 
     65  // Gets the next surface for drawing from our swap chain and stores it in
     66  // mInProgressSurface. Returns whether this was successful.
     67  // mInProgressSurface is guaranteed to be not in use by the window server.
     68  // After a call to NextSurface, NextSurface must not be called again until
     69  // after NotifySurfaceReady has been called. Can be called on any thread. When
     70  // used from multiple threads, callers need to make sure that they still only
     71  // call NextSurface and NotifySurfaceReady alternatingly and not in any other
     72  // order.
     73  bool NextSurface();
     74 
     75  // Invalidates the specified region in all surfaces that are tracked by this
     76  // layer.
     77  void InvalidateRegionThroughoutSwapchain(const gfx::IntRegion& aRegion);
     78 
     79  // Invalidate aUpdateRegion and make sure that mInProgressSurface retains any
     80  // valid content from the previous surface outside of aUpdateRegion, so that
     81  // only aUpdateRegion needs to be drawn. If content needs to be copied,
     82  // aCopyFn is called to do the copying.
     83  // aCopyFn: Fn(CFTypeRefPtr<IOSurfaceRef> aValidSourceIOSurface,
     84  //             const gfx::IntRegion& aCopyRegion) -> void
     85  template <typename F>
     86  void HandlePartialUpdate(const gfx::IntRect& aDisplayRect,
     87                           const gfx::IntRegion& aUpdateRegion, F&& aCopyFn);
     88 
     89  Maybe<SurfaceWithInvalidRegion> GetUnusedSurfaceAndCleanUp();
     90 
     91  // Returns a DrawTarget. The size of the DrawTarget will be the same as the
     92  // size of this layer. The caller should draw to that DrawTarget, then drop
     93  // its reference to the DrawTarget, and then call NotifySurfaceReady(). It can
     94  // limit its drawing to aUpdateRegion (which is in the DrawTarget's device
     95  // space). After a call to NextSurface*, NextSurface* must not be called again
     96  // until after NotifySurfaceReady has been called. Can be called on any
     97  // thread. When used from multiple threads, callers need to make sure that
     98  // they still only call NextSurface* and NotifySurfaceReady alternatingly and
     99  // not in any other order. aUpdateRegion and aDisplayRect are in "content
    100  // coordinates" and must not extend beyond the layer size. If aDisplayRect
    101  // contains parts that were not valid before, then those parts must be updated
    102  // (must be part of aUpdateRegion), so that the entirety of aDisplayRect is
    103  // valid after the update. The display rect determines the parts of the
    104  // surface that will be shown; this allows using surfaces with only
    105  // partially-valid content, as long as none of the invalid content is included
    106  // in the display rect.
    107  RefPtr<gfx::DrawTarget> NextSurfaceAsDrawTarget(
    108      const gfx::IntRect& aDisplayRect, const gfx::IntRegion& aUpdateRegion,
    109      gfx::BackendType aBackendType);
    110 
    111  // Returns a GLuint for a framebuffer that can be used for drawing to the
    112  // surface. The size of the framebuffer will be the same as the size of this
    113  // layer. If aNeedsDepth is true, the framebuffer is created with a depth
    114  // buffer.
    115  // The framebuffer's depth buffer (if present) may be shared with other
    116  // framebuffers of the same size, even from entirely different NativeLayer
    117  // objects. The caller should not assume anything about the depth buffer's
    118  // existing contents (i.e. it should clear it at the beginning of the draw).
    119  // Callers should draw to one layer at a time, such that there is no
    120  // interleaved drawing to different framebuffers that could be tripped up by
    121  // the sharing.
    122  // The caller should draw to the framebuffer, unbind it, and then call
    123  // NotifySurfaceReady(). It can limit its drawing to aUpdateRegion (which is
    124  // in the framebuffer's device space, possibly "upside down" if
    125  // SurfaceIsFlipped()).
    126  // The framebuffer will be created in the GLContext that this layer's
    127  // SurfacePoolHandle was created for.
    128  // After a call to NextSurface*, NextSurface* must not be called again until
    129  // after NotifySurfaceReady has been called. Can be called on any thread. When
    130  // used from multiple threads, callers need to make sure that they still only
    131  // call NextSurface and NotifySurfaceReady alternatingly and not in any other
    132  // order.
    133  // aUpdateRegion and aDisplayRect are in "content coordinates" and must not
    134  // extend beyond the layer size. If aDisplayRect contains parts that were not
    135  // valid before, then those parts must be updated (must be part of
    136  // aUpdateRegion), so that the entirety of aDisplayRect is valid after the
    137  // update. The display rect determines the parts of the surface that will be
    138  // shown; this allows using surfaces with only partially-valid content, as
    139  // long as none of the invalid content is included in the display rect.
    140  Maybe<GLuint> NextSurfaceAsFramebuffer(const gfx::IntRect& aDisplayRect,
    141                                         const gfx::IntRegion& aUpdateRegion,
    142                                         bool aNeedsDepth);
    143 
    144  // Indicates that the surface which has been returned from the most recent
    145  // call to NextSurface* is now finished being drawn to and can be displayed on
    146  // the screen. Resets the invalid region on the surface to the empty region.
    147  // Returns true if the display rect has changed.
    148  bool NotifySurfaceReady();
    149 
    150  // If you know that this layer will likely not draw any more frames, then it's
    151  // good to call DiscardBackbuffers in order to save memory and allow other
    152  // layer's to pick up the released surfaces from the pool.
    153  void DiscardBackbuffers();
    154 
    155  Maybe<SurfaceWithInvalidRegion> FrontSurface() { return mFrontSurface; }
    156  std::vector<SurfaceWithInvalidRegionAndCheckCount> Surfaces() {
    157    return mSurfaces;
    158  }
    159 
    160 protected:
    161  friend class NativeLayerCA;
    162 
    163  gfx::IntSize mSize;
    164  gfx::IntRect mDisplayRect;
    165  bool mSurfaceIsFlipped = false;
    166 
    167 #ifdef NIGHTLY_BUILD
    168  // Track the consistency of our caller's API usage. Layers that are drawn
    169  // should only ever be called with NotifySurfaceReady. Layers that are
    170  // external should only ever be called with AttachExternalImage.
    171  bool mHasEverAttachExternalImage = false;
    172  bool mHasEverNotifySurfaceReady = false;
    173 #endif
    174 
    175  // Each IOSurface is initially created inside NextSurface.
    176  // The surface stays alive until the recycling mechanism in NextSurface
    177  // determines it is no longer needed (because the swap chain has grown too
    178  // long) or until DiscardBackbuffers() is called or the layer is destroyed.
    179  // During the surface's lifetime, it will continuously move through the fields
    180  // mInProgressSurface, mFrontSurface, and back to front through the mSurfaces
    181  // queue:
    182  //
    183  //  mSurfaces.front()
    184  //  ------[NextSurface()]-----> mInProgressSurface
    185  //  --[NotifySurfaceReady()]--> mFrontSurface
    186  //  --[NotifySurfaceReady()]--> mSurfaces.back()  --> .... -->
    187  //  mSurfaces.front()
    188  //
    189  // We mark an IOSurface as "in use" as long as it is either in
    190  // mInProgressSurface. When it is in mFrontSurface or in the mSurfaces queue,
    191  // it is not marked as "in use" by us - but it can be "in use" by the window
    192  // server. Consequently, IOSurfaceIsInUse on a surface from mSurfaces reflects
    193  // whether the window server is still reading from the surface, and we can use
    194  // this indicator to decide when to recycle the surface.
    195  //
    196  // Users of NativeLayerCA normally proceed in this order:
    197  //  1. Begin a frame by calling NextSurface to get the surface.
    198  //  2. Draw to the surface.
    199  //  3. Mark the surface as done by calling NotifySurfaceReady.
    200  //  4. Call NativeLayerRoot::CommitToScreen(), which calls ApplyChanges()
    201  //     during a CATransaction.
    202 
    203  // The surface we returned from the most recent call to NextSurface, before
    204  // the matching call to NotifySurfaceReady.
    205  // Will only be Some() between calls to NextSurface and NotifySurfaceReady.
    206  Maybe<SurfaceWithInvalidRegion> mInProgressSurface;
    207  Maybe<gfx::IntRegion> mInProgressUpdateRegion;
    208  Maybe<gfx::IntRect> mInProgressDisplayRect;
    209 
    210  // The surface that the most recent call to NotifySurfaceReady was for.
    211  // Will be Some() after the first call to NotifySurfaceReady, for the rest of
    212  // the layer's life time.
    213  Maybe<SurfaceWithInvalidRegion> mFrontSurface;
    214 
    215  // The queue of surfaces which make up the rest of our "swap chain".
    216  // mSurfaces.front() is the next surface we'll attempt to use.
    217  // mSurfaces.back() is the one that was used most recently.
    218  std::vector<SurfaceWithInvalidRegionAndCheckCount> mSurfaces;
    219 
    220  // Non-null between calls to NextSurfaceAsDrawTarget and NotifySurfaceReady.
    221  RefPtr<MacIOSurface> mInProgressLockedIOSurface;
    222 
    223  RefPtr<SurfacePoolHandleCA> mSurfacePoolHandle;
    224 };
    225 
    226 }  // namespace layers
    227 }  // namespace mozilla
    228 
    229 #endif  // mozilla_layers_NativeLayerMacSurfaceHandler_h