DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (c68fe15a81fc)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
/* -*- 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_NativeLayer_h
#define mozilla_layers_NativeLayer_h

#include "mozilla/Maybe.h"
#include "mozilla/Range.h"
#include "mozilla/UniquePtr.h"

#include "GLTypes.h"
#include "nsISupportsImpl.h"
#include "nsRegion.h"

namespace mozilla {

namespace gl {
class GLContext;
}  // namespace gl

namespace layers {

class NativeLayer;
class NativeLayerCA;
class NativeLayerRootSnapshotter;
class SurfacePoolHandle;

// NativeLayerRoot and NativeLayer allow building up a flat layer "tree" of
// sibling layers. These layers provide a cross-platform abstraction for the
// platform's native layers, such as CoreAnimation layers on macOS.
// Every layer has a rectangle that describes its position and size in the
// window. The native layer root is usually be created by the window, and then
// the compositing subsystem uses it to create and place the actual layers.
class NativeLayerRoot {
 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NativeLayerRoot)

  virtual already_AddRefed<NativeLayer> CreateLayer(
      const gfx::IntSize& aSize, bool aIsOpaque,
      SurfacePoolHandle* aSurfacePoolHandle) = 0;
  virtual void AppendLayer(NativeLayer* aLayer) = 0;
  virtual void RemoveLayer(NativeLayer* aLayer) = 0;
  virtual void SetLayers(const nsTArray<RefPtr<NativeLayer>>& aLayers) = 0;

  // Publish the layer changes to the screen. Returns whether the commit was
  // successful.
  virtual bool CommitToScreen() = 0;

  // Returns a new NativeLayerRootSnapshotter that can be used to read back the
  // visual output of this NativeLayerRoot. The snapshotter needs to be
  // destroyed on the same thread that CreateSnapshotter() was called on. Only
  // one snapshotter per NativeLayerRoot can be in existence at any given time.
  // CreateSnapshotter() makes sure of this and crashes if called at a time at
  // which there still exists a snapshotter for this NativeLayerRoot.
  virtual UniquePtr<NativeLayerRootSnapshotter> CreateSnapshotter() {
    return nullptr;
  }

 protected:
  virtual ~NativeLayerRoot() = default;
};

// Allows reading back the visual output of a NativeLayerRoot.
// Can only be used on a single thread, unlike NativeLayerRoot.
// Holds a strong reference to the NativeLayerRoot that created it.
// On Mac, this owns a GLContext, which wants to be created and destroyed on the
// same thread.
class NativeLayerRootSnapshotter {
 public:
  virtual ~NativeLayerRootSnapshotter() = default;

  // Reads the composited result of the NativeLayer tree into aReadbackBuffer,
  // synchronously. Should only be called right after a call to CommitToScreen()
  // - in that case it is guaranteed to read back exactly the NativeLayer state
  // that was committed. If called at other times, this API does not define
  // whether the observed state includes NativeLayer modifications which have
  // not been committed. (The macOS implementation will include those pending
  // modifications by doing an offscreen commit.)
  // The readback buffer's stride is assumed to be aReadbackSize.width * 4. Only
  // BGRA is supported.
  virtual bool ReadbackPixels(const gfx::IntSize& aReadbackSize,
                              gfx::SurfaceFormat aReadbackFormat,
                              const Range<uint8_t>& aReadbackBuffer) = 0;
};

// Represents a native layer. Native layers, such as CoreAnimation layers on
// macOS, are used to put pixels on the screen and to refresh and manipulate
// the visual contents of a window efficiently. For example, drawing to a layer
// once and then displaying the layer for multiple frames while moving it to
// different positions will be more efficient than drawing into a window (or a
// non-moving layer) multiple times with different internal offsets.
// There are two sources of "work" for a given composited frame: 1) Our own
// drawing (such as OpenGL compositing into a window or layer) and 2) the
// compositing window manager's work to update the screen. Every pixel we draw
// needs to be copied to the screen by the window manager. This suggests two
// avenues for reducing the work load for a given frame: Drawing fewer pixels
// ourselves, and making the window manager copy fewer pixels to the screen.
// Smart use of native layers allows reducing both work loads: If a visual
// change can be expressed purely as a layer attribute change (such as a change
// in the layer's position), this lets us eliminate our own drawing for that
// change. And secondly, manipulating a small layer rather than a large layer
// will reduce the window manager's work for that frame because it'll only copy
// the pixels of the small layer to the screen.
class NativeLayer {
 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NativeLayer)

  virtual NativeLayerCA* AsNativeLayerCA() { return nullptr; }

  // The size and opaqueness of a layer are supplied during layer creation and
  // never change.
  virtual gfx::IntSize GetSize() = 0;
  virtual bool IsOpaque() = 0;

  // The location of the layer, in integer device pixels.
  virtual void SetPosition(const gfx::IntPoint& aPosition) = 0;
  virtual gfx::IntPoint GetPosition() = 0;

  virtual gfx::IntRect GetRect() = 0;

  // The valid rect is stored here, but applied in the compositor code
  // by combining it with the surface clip rect.
  virtual void SetValidRect(const gfx::IntRect& aValidRect) = 0;
  virtual gfx::IntRect GetValidRect() = 0;

  // Set an optional clip rect on the layer. The clip rect is in the same
  // coordinate space as the layer rect.
  virtual void SetClipRect(const Maybe<gfx::IntRect>& aClipRect) = 0;
  virtual Maybe<gfx::IntRect> ClipRect() = 0;

  // Whether the surface contents are flipped vertically compared to this
  // layer's coordinate system. Can be set on any thread at any time.
  virtual void SetSurfaceIsFlipped(bool aIsFlipped) = 0;
  virtual bool SurfaceIsFlipped() = 0;

  // Returns a DrawTarget. The size of the DrawTarget will be the same as the
  // size of this layer. The caller should draw to that DrawTarget, then drop
  // its reference to the DrawTarget, and then call NotifySurfaceReady(). It can
  // limit its drawing to aUpdateRegion (which is in the DrawTarget's device
  // space). After a call to NextSurface*, NextSurface* must not be called again
  // until after NotifySurfaceReady has been called. Can be called on any
  // thread. When used from multiple threads, callers need to make sure that
  // they still only call NextSurface* and NotifySurfaceReady alternatingly and
  // not in any other order. aUpdateRegion must not extend beyond the layer
  // size.
  virtual RefPtr<gfx::DrawTarget> NextSurfaceAsDrawTarget(
      const gfx::IntRegion& aUpdateRegion, gfx::BackendType aBackendType) = 0;

  // Returns a GLuint for a framebuffer that can be used for drawing to the
  // surface. The size of the framebuffer will be the same as the size of this
  // layer. If aNeedsDepth is true, the framebuffer is created with a depth
  // buffer.
  // The framebuffer's depth buffer (if present) may be shared with other
  // framebuffers of the same size, even from entirely different NativeLayer
  // objects. The caller should not assume anything about the depth buffer's
  // existing contents (i.e. it should clear it at the beginning of the draw).
  // Callers should draw to one layer at a time, such that there is no
  // interleaved drawing to different framebuffers that could be tripped up by
  // the sharing.
  // The caller should draw to the framebuffer, unbind it, and then call
  // NotifySurfaceReady(). It can limit its drawing to aUpdateRegion (which is
  // in the framebuffer's device space, possibly "upside down" if
  // SurfaceIsFlipped()).
  // The framebuffer will be created in the GLContext that this layer's
  // SurfacePoolHandle was created for.
  // After a call to NextSurface*, NextSurface* must not be called again until
  // after NotifySurfaceReady has been called. Can be called on any thread. When
  // used from multiple threads, callers need to make sure that they still only
  // call NextSurface and NotifySurfaceReady alternatingly and not in any other
  // order.
  // aUpdateRegion must not extend beyond the layer size.
  virtual Maybe<GLuint> NextSurfaceAsFramebuffer(
      const gfx::IntRegion& aUpdateRegion, bool aNeedsDepth) = 0;

  // Indicates that the surface which has been returned from the most recent
  // call to NextSurface* is now finished being drawn to and can be displayed on
  // the screen. Resets the invalid region on the surface to the empty region.
  virtual void NotifySurfaceReady() = 0;

  // If you know that this layer will likely not draw any more frames, then it's
  // good to call DiscardBackbuffers in order to save memory and allow other
  // layer's to pick up the released surfaces from the pool.
  virtual void DiscardBackbuffers() = 0;

 protected:
  virtual ~NativeLayer() = default;
};

}  // namespace layers
}  // namespace mozilla

#endif  // mozilla_layers_NativeLayer_h