Bug 1890689 accumulate input in LargerReceiverBlockSizeThanDesiredBuffering GTest...
[gecko.git] / gfx / layers / Compositor.cpp
bloba8714ce8d2ea1df9a74cae57e054a47a18142942
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"
20 #include "gfxUtils.h"
21 #include "nsAppRunner.h"
23 namespace mozilla::layers {
25 class CompositorRecordedFrame final : public RecordedFrame {
26 public:
27 CompositorRecordedFrame(const TimeStamp& aTimeStamp,
28 RefPtr<AsyncReadbackBuffer>&& aBuffer)
29 : RecordedFrame(aTimeStamp), mBuffer(aBuffer) {}
31 virtual already_AddRefed<gfx::DataSourceSurface> GetSourceSurface() override {
32 if (mSurface) {
33 return do_AddRef(mSurface);
36 gfx::IntSize size = mBuffer->GetSize();
38 mSurface = gfx::Factory::CreateDataSourceSurface(
39 size, gfx::SurfaceFormat::B8G8R8A8,
40 /* aZero = */ false);
42 if (!mBuffer->MapAndCopyInto(mSurface, size)) {
43 mSurface = nullptr;
44 return nullptr;
47 return do_AddRef(mSurface);
50 private:
51 RefPtr<AsyncReadbackBuffer> mBuffer;
52 RefPtr<gfx::DataSourceSurface> mSurface;
55 Compositor::Compositor(widget::CompositorWidget* aWidget)
56 : mWidget(aWidget),
57 mIsDestroyed(false),
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()))
62 #else
63 mClearColor(gfx::DeviceColor())
64 #endif
68 Compositor::~Compositor() {}
70 void Compositor::Destroy() {
71 mWidget = nullptr;
73 TextureSourceProvider::Destroy();
74 mIsDestroyed = true;
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));
93 return vertices;
96 static float WrapTexCoord(float v) {
97 // This should return values in range [0, 1.0)
98 return v - floorf(v);
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) {
105 if (flip_y) {
106 std::swap(ty0, ty1);
108 (*aLayerRects)[n] = gfx::Rect(x0, y0, x1 - x0, y1 - y0);
109 (*aTextureRects)[n] = gfx::Rect(tx0, ty0, tx1 - tx0, ty1 - ty0);
112 #ifdef DEBUG
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; }
117 #endif
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) {
129 flipped = true;
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)));
141 NS_ASSERTION(
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
169 // xmid/ymid values.
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);
173 return 1;
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.
185 GLfloat xmid =
186 aRect.X() + (1.0f - tl.x) / texCoordRect.Width() * aRect.Width();
187 GLfloat ymid =
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.
193 NS_ASSERTION(
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 "
198 "same width");
199 NS_ASSERTION(
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 "
204 "same height");
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);
211 return 2;
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);
219 return 2;
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);
230 return 4;
233 bool Compositor::ShouldRecordFrames() const {
234 return profiler_feature_active(ProfilerFeature::Screenshots) || mRecordFrames;
237 } // namespace mozilla::layers