1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/layers/Compositor.h"
8 #include "mozilla/layers/CompositionRecorder.h"
9 #include "base/message_loop.h" // for MessageLoop
10 #include "mozilla/gfx/Types.h"
11 #include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent
12 #include "mozilla/layers/Diagnostics.h"
13 #include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc
14 #include "mozilla/layers/TextureClient.h"
15 #include "mozilla/layers/TextureHost.h"
16 #include "mozilla/layers/CompositorThread.h"
17 #include "mozilla/mozalloc.h" // for operator delete, etc
18 #include "GeckoProfiler.h"
19 #include "gfx2DGlue.h"
21 #include "nsAppRunner.h"
23 namespace mozilla::layers
{
25 class CompositorRecordedFrame final
: public RecordedFrame
{
27 CompositorRecordedFrame(const TimeStamp
& aTimeStamp
,
28 RefPtr
<AsyncReadbackBuffer
>&& aBuffer
)
29 : RecordedFrame(aTimeStamp
), mBuffer(aBuffer
) {}
31 virtual already_AddRefed
<gfx::DataSourceSurface
> GetSourceSurface() override
{
33 return do_AddRef(mSurface
);
36 gfx::IntSize size
= mBuffer
->GetSize();
38 mSurface
= gfx::Factory::CreateDataSourceSurface(
39 size
, gfx::SurfaceFormat::B8G8R8A8
,
42 if (!mBuffer
->MapAndCopyInto(mSurface
, size
)) {
47 return do_AddRef(mSurface
);
51 RefPtr
<AsyncReadbackBuffer
> mBuffer
;
52 RefPtr
<gfx::DataSourceSurface
> mSurface
;
55 Compositor::Compositor(widget::CompositorWidget
* aWidget
)
58 #if defined(MOZ_WIDGET_ANDROID)
59 // If the default color isn't white for Fennec, there is a black
60 // flash before the first page of a tab is loaded.
61 mClearColor(gfx::ToDeviceColor(gfx::sRGBColor::OpaqueWhite()))
63 mClearColor(gfx::DeviceColor())
68 Compositor::~Compositor() {}
70 void Compositor::Destroy() {
73 TextureSourceProvider::Destroy();
77 void Compositor::EndFrame() { mLastCompositionEndTime
= TimeStamp::Now(); }
79 nsTArray
<TexturedVertex
> TexturedTrianglesToVertexArray(
80 const nsTArray
<gfx::TexturedTriangle
>& aTriangles
) {
81 const auto VertexFromPoints
= [](const gfx::Point
& p
, const gfx::Point
& t
) {
82 return TexturedVertex
{{p
.x
, p
.y
}, {t
.x
, t
.y
}};
85 nsTArray
<TexturedVertex
> vertices
;
87 for (const gfx::TexturedTriangle
& t
: aTriangles
) {
88 vertices
.AppendElement(VertexFromPoints(t
.p1
, t
.textureCoords
.p1
));
89 vertices
.AppendElement(VertexFromPoints(t
.p2
, t
.textureCoords
.p2
));
90 vertices
.AppendElement(VertexFromPoints(t
.p3
, t
.textureCoords
.p3
));
96 static float WrapTexCoord(float v
) {
97 // This should return values in range [0, 1.0)
101 static void SetRects(size_t n
, decomposedRectArrayT
* aLayerRects
,
102 decomposedRectArrayT
* aTextureRects
, float x0
, float y0
,
103 float x1
, float y1
, float tx0
, float ty0
, float tx1
,
104 float ty1
, bool flip_y
) {
108 (*aLayerRects
)[n
] = gfx::Rect(x0
, y0
, x1
- x0
, y1
- y0
);
109 (*aTextureRects
)[n
] = gfx::Rect(tx0
, ty0
, tx1
- tx0
, ty1
- ty0
);
113 static inline bool FuzzyEqual(float a
, float b
) {
114 return fabs(a
- b
) < 0.0001f
;
116 static inline bool FuzzyLTE(float a
, float b
) { return a
<= b
+ 0.0001f
; }
119 size_t DecomposeIntoNoRepeatRects(const gfx::Rect
& aRect
,
120 const gfx::Rect
& aTexCoordRect
,
121 decomposedRectArrayT
* aLayerRects
,
122 decomposedRectArrayT
* aTextureRects
) {
123 gfx::Rect texCoordRect
= aTexCoordRect
;
125 // If the texture should be flipped, it will have negative height. Detect that
126 // here and compensate for it. We will flip each rect as we emit it.
127 bool flipped
= false;
128 if (texCoordRect
.Height() < 0) {
130 texCoordRect
.MoveByY(texCoordRect
.Height());
131 texCoordRect
.SetHeight(-texCoordRect
.Height());
134 // Wrap the texture coordinates so they are within [0,1] and cap width/height
135 // at 1. We rely on this below.
136 texCoordRect
= gfx::Rect(gfx::Point(WrapTexCoord(texCoordRect
.X()),
137 WrapTexCoord(texCoordRect
.Y())),
138 gfx::Size(std::min(texCoordRect
.Width(), 1.0f
),
139 std::min(texCoordRect
.Height(), 1.0f
)));
142 texCoordRect
.X() >= 0.0f
&& texCoordRect
.X() <= 1.0f
&&
143 texCoordRect
.Y() >= 0.0f
&& texCoordRect
.Y() <= 1.0f
&&
144 texCoordRect
.Width() >= 0.0f
&& texCoordRect
.Width() <= 1.0f
&&
145 texCoordRect
.Height() >= 0.0f
&& texCoordRect
.Height() <= 1.0f
&&
146 texCoordRect
.XMost() >= 0.0f
&& texCoordRect
.XMost() <= 2.0f
&&
147 texCoordRect
.YMost() >= 0.0f
&& texCoordRect
.YMost() <= 2.0f
,
148 "We just wrapped the texture coordinates, didn't we?");
150 // Get the top left and bottom right points of the rectangle. Note that
151 // tl.x/tl.y are within [0,1] but br.x/br.y are within [0,2].
152 gfx::Point tl
= texCoordRect
.TopLeft();
153 gfx::Point br
= texCoordRect
.BottomRight();
155 NS_ASSERTION(tl
.x
>= 0.0f
&& tl
.x
<= 1.0f
&& tl
.y
>= 0.0f
&& tl
.y
<= 1.0f
&&
156 br
.x
>= tl
.x
&& br
.x
<= 2.0f
&& br
.y
>= tl
.y
&&
157 br
.y
<= 2.0f
&& FuzzyLTE(br
.x
- tl
.x
, 1.0f
) &&
158 FuzzyLTE(br
.y
- tl
.y
, 1.0f
),
159 "Somehow generated invalid texture coordinates");
161 // Then check if we wrap in either the x or y axis.
162 bool xwrap
= br
.x
> 1.0f
;
163 bool ywrap
= br
.y
> 1.0f
;
165 // If xwrap is false, the texture will be sampled from tl.x .. br.x.
166 // If xwrap is true, then it will be split into tl.x .. 1.0, and
167 // 0.0 .. WrapTexCoord(br.x). Same for the Y axis. The destination
168 // rectangle is also split appropriately, according to the calculated
170 if (!xwrap
&& !ywrap
) {
171 SetRects(0, aLayerRects
, aTextureRects
, aRect
.X(), aRect
.Y(), aRect
.XMost(),
172 aRect
.YMost(), tl
.x
, tl
.y
, br
.x
, br
.y
, flipped
);
176 // If we are dealing with wrapping br.x and br.y are greater than 1.0 so
177 // wrap them here as well.
178 br
= gfx::Point(xwrap
? WrapTexCoord(br
.x
.value
) : br
.x
.value
,
179 ywrap
? WrapTexCoord(br
.y
.value
) : br
.y
.value
);
181 // If we wrap around along the x axis, we will draw first from
182 // tl.x .. 1.0 and then from 0.0 .. br.x (which we just wrapped above).
183 // The same applies for the Y axis. The midpoints we calculate here are
184 // only valid if we actually wrap around.
186 aRect
.X() + (1.0f
- tl
.x
) / texCoordRect
.Width() * aRect
.Width();
188 aRect
.Y() + (1.0f
- tl
.y
) / texCoordRect
.Height() * aRect
.Height();
190 // Due to floating-point inaccuracy, we have to use XMost()-x and YMost()-y
191 // to calculate width and height, respectively, to ensure that size will
192 // remain consistent going from absolute to relative and back again.
194 !xwrap
|| (xmid
>= aRect
.X() && xmid
<= aRect
.XMost() &&
195 FuzzyEqual((xmid
- aRect
.X()) + (aRect
.XMost() - xmid
),
196 aRect
.XMost() - aRect
.X())),
197 "xmid should be within [x,XMost()] and the wrapped rect should have the "
200 !ywrap
|| (ymid
>= aRect
.Y() && ymid
<= aRect
.YMost() &&
201 FuzzyEqual((ymid
- aRect
.Y()) + (aRect
.YMost() - ymid
),
202 aRect
.YMost() - aRect
.Y())),
203 "ymid should be within [y,YMost()] and the wrapped rect should have the "
206 if (!xwrap
&& ywrap
) {
207 SetRects(0, aLayerRects
, aTextureRects
, aRect
.X(), aRect
.Y(), aRect
.XMost(),
208 ymid
, tl
.x
, tl
.y
, br
.x
, 1.0f
, flipped
);
209 SetRects(1, aLayerRects
, aTextureRects
, aRect
.X(), ymid
, aRect
.XMost(),
210 aRect
.YMost(), tl
.x
, 0.0f
, br
.x
, br
.y
, flipped
);
214 if (xwrap
&& !ywrap
) {
215 SetRects(0, aLayerRects
, aTextureRects
, aRect
.X(), aRect
.Y(), xmid
,
216 aRect
.YMost(), tl
.x
, tl
.y
, 1.0f
, br
.y
, flipped
);
217 SetRects(1, aLayerRects
, aTextureRects
, xmid
, aRect
.Y(), aRect
.XMost(),
218 aRect
.YMost(), 0.0f
, tl
.y
, br
.x
, br
.y
, flipped
);
222 SetRects(0, aLayerRects
, aTextureRects
, aRect
.X(), aRect
.Y(), xmid
, ymid
,
223 tl
.x
, tl
.y
, 1.0f
, 1.0f
, flipped
);
224 SetRects(1, aLayerRects
, aTextureRects
, xmid
, aRect
.Y(), aRect
.XMost(), ymid
,
225 0.0f
, tl
.y
, br
.x
, 1.0f
, flipped
);
226 SetRects(2, aLayerRects
, aTextureRects
, aRect
.X(), ymid
, xmid
, aRect
.YMost(),
227 tl
.x
, 0.0f
, 1.0f
, br
.y
, flipped
);
228 SetRects(3, aLayerRects
, aTextureRects
, xmid
, ymid
, aRect
.XMost(),
229 aRect
.YMost(), 0.0f
, 0.0f
, br
.x
, br
.y
, flipped
);
233 bool Compositor::ShouldRecordFrames() const {
234 return profiler_feature_active(ProfilerFeature::Screenshots
) || mRecordFrames
;
237 } // namespace mozilla::layers