summaryrefslogtreecommitdiffstats
path: root/gfx/layers/NativeLayer.h
blob: 56b70148da51c6771c9a20ab3e40936280ac378b (plain)
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
/* -*- 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 "mozilla/gfx/Types.h"
#include "mozilla/layers/ScreenshotGrabber.h"

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

namespace mozilla {

namespace gl {
class GLContext;
}  // namespace gl

namespace wr {
class RenderTextureHost;
}

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 already_AddRefed<NativeLayer> CreateLayerForExternalTexture(
      bool aIsOpaque) = 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 profiler_screenshots::Window {
 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.
  // This is applied to the layer, before the transform is applied.
  virtual void SetPosition(const gfx::IntPoint& aPosition) = 0;
  virtual gfx::IntPoint GetPosition() = 0;

  // Sets a transformation to apply to the Layer. This gets applied to
  // coordinates with the position applied, but before clipping is
  // applied.
  virtual void SetTransform(const gfx::Matrix4x4& aTransform) = 0;
  virtual gfx::Matrix4x4 GetTransform() = 0;

  virtual gfx::IntRect GetRect() = 0;

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

  // Returns the "display rect", in content coordinates, of the current front
  // surface. This rect acts as an extra clip and prevents invalid content from
  // getting to the screen. The display rect starts out empty before the first
  // call to NextSurface*. Note the different coordinate space from the regular
  // clip rect: the clip rect is "outside" the layer position, the display rect
  // is "inside" the layer position (moves with the layer).
  virtual gfx::IntRect CurrentSurfaceDisplayRect() = 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;

  virtual void SetSamplingFilter(gfx::SamplingFilter aSamplingFilter) = 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 and aDisplayRect are in "content
  // coordinates" and must not extend beyond the layer size. If aDisplayRect
  // contains parts that were not valid before, then those parts must be updated
  // (must be part of aUpdateRegion), so that the entirety of aDisplayRect is
  // valid after the update. The display rect determines the parts of the
  // surface that will be shown; this allows using surfaces with only
  // partially-valid content, as long as none of the invalid content is included
  // in the display rect.
  virtual RefPtr<gfx::DrawTarget> NextSurfaceAsDrawTarget(
      const gfx::IntRect& aDisplayRect, 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 and aDisplayRect are in "content coordinates" and must not
  // extend beyond the layer size. If aDisplayRect contains parts that were not
  // valid before, then those parts must be updated (must be part of
  // aUpdateRegion), so that the entirety of aDisplayRect is valid after the
  // update. The display rect determines the parts of the surface that will be
  // shown; this allows using surfaces with only partially-valid content, as
  // long as none of the invalid content is included in the display rect.
  virtual Maybe<GLuint> NextSurfaceAsFramebuffer(
      const gfx::IntRect& aDisplayRect, 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;

  virtual void AttachExternalImage(wr::RenderTextureHost* aExternalImage) = 0;

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

}  // namespace layers
}  // namespace mozilla

#endif  // mozilla_layers_NativeLayer_h