Source code

Revision control

Other Tools

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/. */
6
7
#include "mozilla/layers/Compositor.h"
8
#include "base/message_loop.h" // for MessageLoop
9
#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent
10
#include "mozilla/layers/Diagnostics.h"
11
#include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc
12
#include "mozilla/layers/TextureClient.h"
13
#include "mozilla/layers/TextureHost.h"
14
#include "mozilla/layers/CompositorThread.h"
15
#include "mozilla/mozalloc.h" // for operator delete, etc
16
#include "GeckoProfiler.h"
17
#include "gfx2DGlue.h"
18
#include "nsAppRunner.h"
19
#include "LayersHelpers.h"
20
21
namespace mozilla {
22
23
namespace layers {
24
25
class CompositorRecordedFrame final : public RecordedFrame {
26
public:
27
CompositorRecordedFrame(const TimeStamp& aTimeStamp,
28
RefPtr<AsyncReadbackBuffer>&& aBuffer)
29
: RecordedFrame(aTimeStamp), mBuffer(aBuffer) {}
30
31
virtual already_AddRefed<gfx::DataSourceSurface> GetSourceSurface() override {
32
if (mSurface) {
33
return do_AddRef(mSurface);
34
}
35
36
gfx::IntSize size = mBuffer->GetSize();
37
38
mSurface = gfx::Factory::CreateDataSourceSurface(
39
size, gfx::SurfaceFormat::B8G8R8A8,
40
/* aZero = */ false);
41
42
if (!mBuffer->MapAndCopyInto(mSurface, size)) {
43
mSurface = nullptr;
44
return nullptr;
45
}
46
47
return do_AddRef(mSurface);
48
}
49
50
private:
51
RefPtr<AsyncReadbackBuffer> mBuffer;
52
RefPtr<gfx::DataSourceSurface> mSurface;
53
};
54
55
Compositor::Compositor(widget::CompositorWidget* aWidget,
56
CompositorBridgeParent* aParent)
57
: mDiagnosticTypes(DiagnosticTypes::NO_DIAGNOSTIC),
58
mParent(aParent),
59
mPixelsPerFrame(0),
60
mPixelsFilled(0),
61
mScreenRotation(ROTATION_0),
62
mWidget(aWidget),
63
mIsDestroyed(false)
64
#if defined(MOZ_WIDGET_ANDROID)
65
// If the default color isn't white for Fennec, there is a black
66
// flash before the first page of a tab is loaded.
67
,
68
mClearColor(ToDeviceColor(sRGBColor::OpaqueWhite())),
69
mDefaultClearColor(ToDeviceColor(sRGBColor::OpaqueWhite()))
70
#else
71
,
72
mClearColor(DeviceColor()),
73
mDefaultClearColor(DeviceColor())
74
#endif
75
{
76
}
77
78
Compositor::~Compositor() { ReadUnlockTextures(); }
79
80
void Compositor::Destroy() {
81
mWidget = nullptr;
82
83
TextureSourceProvider::Destroy();
84
mIsDestroyed = true;
85
}
86
87
void Compositor::EndFrame() {
88
ReadUnlockTextures();
89
mLastCompositionEndTime = TimeStamp::Now();
90
}
91
92
bool Compositor::ShouldDrawDiagnostics(DiagnosticFlags aFlags) {
93
if ((aFlags & DiagnosticFlags::TILE) &&
94
!(mDiagnosticTypes & DiagnosticTypes::TILE_BORDERS)) {
95
return false;
96
}
97
if ((aFlags & DiagnosticFlags::BIGIMAGE) &&
98
!(mDiagnosticTypes & DiagnosticTypes::BIGIMAGE_BORDERS)) {
99
return false;
100
}
101
if (mDiagnosticTypes == DiagnosticTypes::NO_DIAGNOSTIC) {
102
return false;
103
}
104
return true;
105
}
106
107
void Compositor::DrawDiagnostics(DiagnosticFlags aFlags,
108
const nsIntRegion& aVisibleRegion,
109
const gfx::IntRect& aClipRect,
110
const gfx::Matrix4x4& aTransform,
111
uint32_t aFlashCounter) {
112
if (!ShouldDrawDiagnostics(aFlags)) {
113
return;
114
}
115
116
if (aVisibleRegion.GetNumRects() > 1) {
117
for (auto iter = aVisibleRegion.RectIter(); !iter.Done(); iter.Next()) {
118
DrawDiagnostics(aFlags | DiagnosticFlags::REGION_RECT,
119
IntRectToRect(iter.Get()), aClipRect, aTransform,
120
aFlashCounter);
121
}
122
}
123
124
DrawDiagnostics(aFlags, IntRectToRect(aVisibleRegion.GetBounds()), aClipRect,
125
aTransform, aFlashCounter);
126
}
127
128
void Compositor::DrawDiagnostics(DiagnosticFlags aFlags,
129
const gfx::Rect& aVisibleRect,
130
const gfx::IntRect& aClipRect,
131
const gfx::Matrix4x4& aTransform,
132
uint32_t aFlashCounter) {
133
if (!ShouldDrawDiagnostics(aFlags)) {
134
return;
135
}
136
137
DrawDiagnosticsInternal(aFlags, aVisibleRect, aClipRect, aTransform,
138
aFlashCounter);
139
}
140
141
void Compositor::DrawDiagnosticsInternal(DiagnosticFlags aFlags,
142
const gfx::Rect& aVisibleRect,
143
const gfx::IntRect& aClipRect,
144
const gfx::Matrix4x4& aTransform,
145
uint32_t aFlashCounter) {
146
#ifdef ANDROID
147
int lWidth = 10;
148
#else
149
int lWidth = 2;
150
#endif
151
152
// Technically it is sRGB but it is just for debugging.
153
gfx::DeviceColor color;
154
if (aFlags & DiagnosticFlags::CONTENT) {
155
color = gfx::DeviceColor(0.0f, 1.0f, 0.0f, 1.0f); // green
156
if (aFlags & DiagnosticFlags::COMPONENT_ALPHA) {
157
color = gfx::DeviceColor(0.0f, 1.0f, 1.0f, 1.0f); // greenish blue
158
}
159
} else if (aFlags & DiagnosticFlags::IMAGE) {
160
if (aFlags & DiagnosticFlags::NV12) {
161
color = gfx::DeviceColor(1.0f, 1.0f, 0.0f, 1.0f); // yellow
162
} else if (aFlags & DiagnosticFlags::YCBCR) {
163
color = gfx::DeviceColor(1.0f, 0.55f, 0.0f, 1.0f); // orange
164
} else {
165
color = gfx::DeviceColor(1.0f, 0.0f, 0.0f, 1.0f); // red
166
}
167
} else if (aFlags & DiagnosticFlags::COLOR) {
168
color = gfx::DeviceColor(0.0f, 0.0f, 1.0f, 1.0f); // blue
169
} else if (aFlags & DiagnosticFlags::CONTAINER) {
170
color = gfx::DeviceColor(0.8f, 0.0f, 0.8f, 1.0f); // purple
171
}
172
173
// make tile borders a bit more transparent to keep layer borders readable.
174
if (aFlags & DiagnosticFlags::TILE || aFlags & DiagnosticFlags::BIGIMAGE ||
175
aFlags & DiagnosticFlags::REGION_RECT) {
176
lWidth = 1;
177
color.r *= 0.7f;
178
color.g *= 0.7f;
179
color.b *= 0.7f;
180
color.a = color.a * 0.5f;
181
} else {
182
color.a = color.a * 0.7f;
183
}
184
185
if (mDiagnosticTypes & DiagnosticTypes::FLASH_BORDERS) {
186
float flash = (float)aFlashCounter / (float)DIAGNOSTIC_FLASH_COUNTER_MAX;
187
color.r *= flash;
188
color.g *= flash;
189
color.b *= flash;
190
}
191
192
SlowDrawRect(aVisibleRect, color, aClipRect, aTransform, lWidth);
193
}
194
195
static void UpdateTextureCoordinates(gfx::TexturedTriangle& aTriangle,
196
const gfx::Rect& aRect,
197
const gfx::Rect& aIntersection,
198
const gfx::Rect& aTextureCoords) {
199
// Calculate the relative offset of the intersection within the layer.
200
float dx = (aIntersection.X() - aRect.X()) / aRect.Width();
201
float dy = (aIntersection.Y() - aRect.Y()) / aRect.Height();
202
203
// Update the texture offset.
204
float x = aTextureCoords.X() + dx * aTextureCoords.Width();
205
float y = aTextureCoords.Y() + dy * aTextureCoords.Height();
206
207
// Scale the texture width and height.
208
float w = aTextureCoords.Width() * aIntersection.Width() / aRect.Width();
209
float h = aTextureCoords.Height() * aIntersection.Height() / aRect.Height();
210
211
static const auto Clamp = [](float& f) {
212
if (f >= 1.0f) f = 1.0f;
213
if (f <= 0.0f) f = 0.0f;
214
};
215
216
auto UpdatePoint = [&](const gfx::Point& p, gfx::Point& t) {
217
t.x = x + (p.x - aIntersection.X()) / aIntersection.Width() * w;
218
t.y = y + (p.y - aIntersection.Y()) / aIntersection.Height() * h;
219
220
Clamp(t.x);
221
Clamp(t.y);
222
};
223
224
UpdatePoint(aTriangle.p1, aTriangle.textureCoords.p1);
225
UpdatePoint(aTriangle.p2, aTriangle.textureCoords.p2);
226
UpdatePoint(aTriangle.p3, aTriangle.textureCoords.p3);
227
}
228
229
void Compositor::DrawGeometry(const gfx::Rect& aRect,
230
const gfx::IntRect& aClipRect,
231
const EffectChain& aEffectChain,
232
gfx::Float aOpacity,
233
const gfx::Matrix4x4& aTransform,
234
const gfx::Rect& aVisibleRect,
235
const Maybe<gfx::Polygon>& aGeometry) {
236
if (aRect.IsEmpty()) {
237
return;
238
}
239
240
if (!aGeometry || !SupportsLayerGeometry()) {
241
DrawQuad(aRect, aClipRect, aEffectChain, aOpacity, aTransform,
242
aVisibleRect);
243
return;
244
}
245
246
// Cull completely invisible polygons.
247
if (aRect.Intersect(aGeometry->BoundingBox()).IsEmpty()) {
248
return;
249
}
250
251
const gfx::Polygon clipped = aGeometry->ClipPolygon(aRect);
252
253
// Cull polygons with no area.
254
if (clipped.IsEmpty()) {
255
return;
256
}
257
258
DrawPolygon(clipped, aRect, aClipRect, aEffectChain, aOpacity, aTransform,
259
aVisibleRect);
260
}
261
262
void Compositor::DrawTriangles(
263
const nsTArray<gfx::TexturedTriangle>& aTriangles, const gfx::Rect& aRect,
264
const gfx::IntRect& aClipRect, const EffectChain& aEffectChain,
265
gfx::Float aOpacity, const gfx::Matrix4x4& aTransform,
266
const gfx::Rect& aVisibleRect) {
267
for (const gfx::TexturedTriangle& triangle : aTriangles) {
268
DrawTriangle(triangle, aClipRect, aEffectChain, aOpacity, aTransform,
269
aVisibleRect);
270
}
271
}
272
273
nsTArray<gfx::TexturedTriangle> GenerateTexturedTriangles(
274
const gfx::Polygon& aPolygon, const gfx::Rect& aRect,
275
const gfx::Rect& aTexRect) {
276
nsTArray<gfx::TexturedTriangle> texturedTriangles;
277
278
gfx::Rect layerRects[4];
279
gfx::Rect textureRects[4];
280
size_t rects =
281
DecomposeIntoNoRepeatRects(aRect, aTexRect, &layerRects, &textureRects);
282
for (size_t i = 0; i < rects; ++i) {
283
const gfx::Rect& rect = layerRects[i];
284
const gfx::Rect& texRect = textureRects[i];
285
const gfx::Polygon clipped = aPolygon.ClipPolygon(rect);
286
287
if (clipped.IsEmpty()) {
288
continue;
289
}
290
291
for (const gfx::Triangle& triangle : clipped.ToTriangles()) {
292
const gfx::Rect intersection = rect.Intersect(triangle.BoundingBox());
293
294
// Cull completely invisible triangles.
295
if (intersection.IsEmpty()) {
296
continue;
297
}
298
299
MOZ_ASSERT(rect.Width() > 0.0f && rect.Height() > 0.0f);
300
MOZ_ASSERT(intersection.Width() > 0.0f && intersection.Height() > 0.0f);
301
302
// Since the texture was created for non-split geometry, we need to
303
// update the texture coordinates to account for the split.
304
gfx::TexturedTriangle t(triangle);
305
UpdateTextureCoordinates(t, rect, intersection, texRect);
306
texturedTriangles.AppendElement(std::move(t));
307
}
308
}
309
310
return texturedTriangles;
311
}
312
313
nsTArray<TexturedVertex> TexturedTrianglesToVertexArray(
314
const nsTArray<gfx::TexturedTriangle>& aTriangles) {
315
const auto VertexFromPoints = [](const gfx::Point& p, const gfx::Point& t) {
316
return TexturedVertex{{p.x, p.y}, {t.x, t.y}};
317
};
318
319
nsTArray<TexturedVertex> vertices;
320
321
for (const gfx::TexturedTriangle& t : aTriangles) {
322
vertices.AppendElement(VertexFromPoints(t.p1, t.textureCoords.p1));
323
vertices.AppendElement(VertexFromPoints(t.p2, t.textureCoords.p2));
324
vertices.AppendElement(VertexFromPoints(t.p3, t.textureCoords.p3));
325
}
326
327
return vertices;
328
}
329
330
void Compositor::DrawPolygon(const gfx::Polygon& aPolygon,
331
const gfx::Rect& aRect,
332
const gfx::IntRect& aClipRect,
333
const EffectChain& aEffectChain,
334
gfx::Float aOpacity,
335
const gfx::Matrix4x4& aTransform,
336
const gfx::Rect& aVisibleRect) {
337
nsTArray<gfx::TexturedTriangle> texturedTriangles;
338
339
TexturedEffect* texturedEffect =
340
aEffectChain.mPrimaryEffect->AsTexturedEffect();
341
342
if (texturedEffect) {
343
texturedTriangles = GenerateTexturedTriangles(
344
aPolygon, aRect, texturedEffect->mTextureCoords);
345
} else {
346
for (const gfx::Triangle& triangle : aPolygon.ToTriangles()) {
347
texturedTriangles.AppendElement(gfx::TexturedTriangle(triangle));
348
}
349
}
350
351
if (texturedTriangles.IsEmpty()) {
352
// Nothing to render.
353
return;
354
}
355
356
DrawTriangles(texturedTriangles, aRect, aClipRect, aEffectChain, aOpacity,
357
aTransform, aVisibleRect);
358
}
359
360
void Compositor::SlowDrawRect(const gfx::Rect& aRect,
361
const gfx::DeviceColor& aColor,
362
const gfx::IntRect& aClipRect,
363
const gfx::Matrix4x4& aTransform,
364
int aStrokeWidth) {
365
// TODO This should draw a rect using a single draw call but since
366
// this is only used for debugging overlays it's not worth optimizing ATM.
367
float opacity = 1.0f;
368
EffectChain effects;
369
370
effects.mPrimaryEffect = new EffectSolidColor(aColor);
371
// left
372
this->DrawQuad(gfx::Rect(aRect.X(), aRect.Y(), aStrokeWidth, aRect.Height()),
373
aClipRect, effects, opacity, aTransform);
374
// top
375
this->DrawQuad(gfx::Rect(aRect.X() + aStrokeWidth, aRect.Y(),
376
aRect.Width() - 2 * aStrokeWidth, aStrokeWidth),
377
aClipRect, effects, opacity, aTransform);
378
// right
379
this->DrawQuad(gfx::Rect(aRect.XMost() - aStrokeWidth, aRect.Y(),
380
aStrokeWidth, aRect.Height()),
381
aClipRect, effects, opacity, aTransform);
382
// bottom
383
this->DrawQuad(
384
gfx::Rect(aRect.X() + aStrokeWidth, aRect.YMost() - aStrokeWidth,
385
aRect.Width() - 2 * aStrokeWidth, aStrokeWidth),
386
aClipRect, effects, opacity, aTransform);
387
}
388
389
void Compositor::FillRect(const gfx::Rect& aRect,
390
const gfx::DeviceColor& aColor,
391
const gfx::IntRect& aClipRect,
392
const gfx::Matrix4x4& aTransform) {
393
float opacity = 1.0f;
394
EffectChain effects;
395
396
effects.mPrimaryEffect = new EffectSolidColor(aColor);
397
this->DrawQuad(aRect, aClipRect, effects, opacity, aTransform);
398
}
399
400
static float WrapTexCoord(float v) {
401
// This should return values in range [0, 1.0)
402
return v - floorf(v);
403
}
404
405
static void SetRects(size_t n, decomposedRectArrayT* aLayerRects,
406
decomposedRectArrayT* aTextureRects, float x0, float y0,
407
float x1, float y1, float tx0, float ty0, float tx1,
408
float ty1, bool flip_y) {
409
if (flip_y) {
410
std::swap(ty0, ty1);
411
}
412
(*aLayerRects)[n] = gfx::Rect(x0, y0, x1 - x0, y1 - y0);
413
(*aTextureRects)[n] = gfx::Rect(tx0, ty0, tx1 - tx0, ty1 - ty0);
414
}
415
416
#ifdef DEBUG
417
static inline bool FuzzyEqual(float a, float b) {
418
return fabs(a - b) < 0.0001f;
419
}
420
static inline bool FuzzyLTE(float a, float b) { return a <= b + 0.0001f; }
421
#endif
422
423
size_t DecomposeIntoNoRepeatRects(const gfx::Rect& aRect,
424
const gfx::Rect& aTexCoordRect,
425
decomposedRectArrayT* aLayerRects,
426
decomposedRectArrayT* aTextureRects) {
427
gfx::Rect texCoordRect = aTexCoordRect;
428
429
// If the texture should be flipped, it will have negative height. Detect that
430
// here and compensate for it. We will flip each rect as we emit it.
431
bool flipped = false;
432
if (texCoordRect.Height() < 0) {
433
flipped = true;
434
texCoordRect.MoveByY(texCoordRect.Height());
435
texCoordRect.SetHeight(-texCoordRect.Height());
436
}
437
438
// Wrap the texture coordinates so they are within [0,1] and cap width/height
439
// at 1. We rely on this below.
440
texCoordRect = gfx::Rect(gfx::Point(WrapTexCoord(texCoordRect.X()),
441
WrapTexCoord(texCoordRect.Y())),
442
gfx::Size(std::min(texCoordRect.Width(), 1.0f),
443
std::min(texCoordRect.Height(), 1.0f)));
444
445
NS_ASSERTION(
446
texCoordRect.X() >= 0.0f && texCoordRect.X() <= 1.0f &&
447
texCoordRect.Y() >= 0.0f && texCoordRect.Y() <= 1.0f &&
448
texCoordRect.Width() >= 0.0f && texCoordRect.Width() <= 1.0f &&
449
texCoordRect.Height() >= 0.0f && texCoordRect.Height() <= 1.0f &&
450
texCoordRect.XMost() >= 0.0f && texCoordRect.XMost() <= 2.0f &&
451
texCoordRect.YMost() >= 0.0f && texCoordRect.YMost() <= 2.0f,
452
"We just wrapped the texture coordinates, didn't we?");
453
454
// Get the top left and bottom right points of the rectangle. Note that
455
// tl.x/tl.y are within [0,1] but br.x/br.y are within [0,2].
456
gfx::Point tl = texCoordRect.TopLeft();
457
gfx::Point br = texCoordRect.BottomRight();
458
459
NS_ASSERTION(tl.x >= 0.0f && tl.x <= 1.0f && tl.y >= 0.0f && tl.y <= 1.0f &&
460
br.x >= tl.x && br.x <= 2.0f && br.y >= tl.y &&
461
br.y <= 2.0f && FuzzyLTE(br.x - tl.x, 1.0f) &&
462
FuzzyLTE(br.y - tl.y, 1.0f),
463
"Somehow generated invalid texture coordinates");
464
465
// Then check if we wrap in either the x or y axis.
466
bool xwrap = br.x > 1.0f;
467
bool ywrap = br.y > 1.0f;
468
469
// If xwrap is false, the texture will be sampled from tl.x .. br.x.
470
// If xwrap is true, then it will be split into tl.x .. 1.0, and
471
// 0.0 .. WrapTexCoord(br.x). Same for the Y axis. The destination
472
// rectangle is also split appropriately, according to the calculated
473
// xmid/ymid values.
474
if (!xwrap && !ywrap) {
475
SetRects(0, aLayerRects, aTextureRects, aRect.X(), aRect.Y(), aRect.XMost(),
476
aRect.YMost(), tl.x, tl.y, br.x, br.y, flipped);
477
return 1;
478
}
479
480
// If we are dealing with wrapping br.x and br.y are greater than 1.0 so
481
// wrap them here as well.
482
br = gfx::Point(xwrap ? WrapTexCoord(br.x) : br.x,
483
ywrap ? WrapTexCoord(br.y) : br.y);
484
485
// If we wrap around along the x axis, we will draw first from
486
// tl.x .. 1.0 and then from 0.0 .. br.x (which we just wrapped above).
487
// The same applies for the Y axis. The midpoints we calculate here are
488
// only valid if we actually wrap around.
489
GLfloat xmid =
490
aRect.X() + (1.0f - tl.x) / texCoordRect.Width() * aRect.Width();
491
GLfloat ymid =
492
aRect.Y() + (1.0f - tl.y) / texCoordRect.Height() * aRect.Height();
493
494
// Due to floating-point inaccuracy, we have to use XMost()-x and YMost()-y
495
// to calculate width and height, respectively, to ensure that size will
496
// remain consistent going from absolute to relative and back again.
497
NS_ASSERTION(
498
!xwrap || (xmid >= aRect.X() && xmid <= aRect.XMost() &&
499
FuzzyEqual((xmid - aRect.X()) + (aRect.XMost() - xmid),
500
aRect.XMost() - aRect.X())),
501
"xmid should be within [x,XMost()] and the wrapped rect should have the "
502
"same width");
503
NS_ASSERTION(
504
!ywrap || (ymid >= aRect.Y() && ymid <= aRect.YMost() &&
505
FuzzyEqual((ymid - aRect.Y()) + (aRect.YMost() - ymid),
506
aRect.YMost() - aRect.Y())),
507
"ymid should be within [y,YMost()] and the wrapped rect should have the "
508
"same height");
509
510
if (!xwrap && ywrap) {
511
SetRects(0, aLayerRects, aTextureRects, aRect.X(), aRect.Y(), aRect.XMost(),
512
ymid, tl.x, tl.y, br.x, 1.0f, flipped);
513
SetRects(1, aLayerRects, aTextureRects, aRect.X(), ymid, aRect.XMost(),
514
aRect.YMost(), tl.x, 0.0f, br.x, br.y, flipped);
515
return 2;
516
}
517
518
if (xwrap && !ywrap) {
519
SetRects(0, aLayerRects, aTextureRects, aRect.X(), aRect.Y(), xmid,
520
aRect.YMost(), tl.x, tl.y, 1.0f, br.y, flipped);
521
SetRects(1, aLayerRects, aTextureRects, xmid, aRect.Y(), aRect.XMost(),
522
aRect.YMost(), 0.0f, tl.y, br.x, br.y, flipped);
523
return 2;
524
}
525
526
SetRects(0, aLayerRects, aTextureRects, aRect.X(), aRect.Y(), xmid, ymid,
527
tl.x, tl.y, 1.0f, 1.0f, flipped);
528
SetRects(1, aLayerRects, aTextureRects, xmid, aRect.Y(), aRect.XMost(), ymid,
529
0.0f, tl.y, br.x, 1.0f, flipped);
530
SetRects(2, aLayerRects, aTextureRects, aRect.X(), ymid, xmid, aRect.YMost(),
531
tl.x, 0.0f, 1.0f, br.y, flipped);
532
SetRects(3, aLayerRects, aTextureRects, xmid, ymid, aRect.XMost(),
533
aRect.YMost(), 0.0f, 0.0f, br.x, br.y, flipped);
534
return 4;
535
}
536
537
gfx::IntRect Compositor::ComputeBackdropCopyRect(
538
const gfx::Rect& aRect, const gfx::IntRect& aClipRect,
539
const gfx::Matrix4x4& aTransform, gfx::Matrix4x4* aOutTransform,
540
gfx::Rect* aOutLayerQuad) {
541
// Compute the clip.
542
RefPtr<CompositingRenderTarget> currentRenderTarget =
543
GetCurrentRenderTarget();
544
gfx::IntPoint rtOffset = currentRenderTarget->GetOrigin();
545
gfx::IntSize rtSize = currentRenderTarget->GetSize();
546
547
return layers::ComputeBackdropCopyRect(aRect, aClipRect, aTransform,
548
gfx::IntRect(rtOffset, rtSize),
549
aOutTransform, aOutLayerQuad);
550
}
551
552
gfx::IntRect Compositor::ComputeBackdropCopyRect(
553
const gfx::Triangle& aTriangle, const gfx::IntRect& aClipRect,
554
const gfx::Matrix4x4& aTransform, gfx::Matrix4x4* aOutTransform,
555
gfx::Rect* aOutLayerQuad) {
556
gfx::Rect boundingBox = aTriangle.BoundingBox();
557
return ComputeBackdropCopyRect(boundingBox, aClipRect, aTransform,
558
aOutTransform, aOutLayerQuad);
559
}
560
561
void Compositor::SetInvalid() { mParent = nullptr; }
562
563
bool Compositor::IsValid() const { return !!mParent; }
564
565
void Compositor::UnlockAfterComposition(TextureHost* aTexture) {
566
TextureSourceProvider::UnlockAfterComposition(aTexture);
567
568
// If this is being called after we shutdown the compositor, we must finish
569
// read unlocking now to prevent a cycle.
570
if (IsDestroyed()) {
571
ReadUnlockTextures();
572
}
573
}
574
575
bool Compositor::NotifyNotUsedAfterComposition(TextureHost* aTextureHost) {
576
if (IsDestroyed() || AsBasicCompositor()) {
577
return false;
578
}
579
return TextureSourceProvider::NotifyNotUsedAfterComposition(aTextureHost);
580
}
581
582
void Compositor::GetFrameStats(GPUStats* aStats) {
583
aStats->mInvalidPixels = mPixelsPerFrame;
584
aStats->mPixelsFilled = mPixelsFilled;
585
}
586
587
already_AddRefed<RecordedFrame> Compositor::RecordFrame(
588
const TimeStamp& aTimeStamp) {
589
RefPtr<CompositingRenderTarget> renderTarget = GetWindowRenderTarget();
590
if (!renderTarget) {
591
return nullptr;
592
}
593
594
RefPtr<AsyncReadbackBuffer> buffer =
595
CreateAsyncReadbackBuffer(renderTarget->GetSize());
596
597
if (!ReadbackRenderTarget(renderTarget, buffer)) {
598
return nullptr;
599
}
600
601
return MakeAndAddRef<CompositorRecordedFrame>(aTimeStamp, std::move(buffer));
602
}
603
604
bool Compositor::ShouldRecordFrames() const {
605
#ifdef MOZ_GECKO_PROFILER
606
if (profiler_feature_active(ProfilerFeature::Screenshots)) {
607
return true;
608
}
609
#endif
610
return mRecordFrames;
611
}
612
613
} // namespace layers
614
} // namespace mozilla