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 "base/message_loop.h" // for MessageLoop
9 #include "mozilla/gfx/Types.h"
10 #include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent
11 #include "mozilla/layers/Diagnostics.h"
12 #include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc
13 #include "mozilla/layers/TextureClient.h"
14 #include "mozilla/layers/TextureHost.h"
15 #include "mozilla/layers/CompositorThread.h"
16 #include "mozilla/mozalloc.h" // for operator delete, etc
17 #include "GeckoProfiler.h"
18 #include "gfx2DGlue.h"
19 #include "nsAppRunner.h"
20 #include "LayersHelpers.h"
26 class CompositorRecordedFrame final
: public RecordedFrame
{
28 CompositorRecordedFrame(const TimeStamp
& aTimeStamp
,
29 RefPtr
<AsyncReadbackBuffer
>&& aBuffer
)
30 : RecordedFrame(aTimeStamp
), mBuffer(aBuffer
) {}
32 virtual already_AddRefed
<gfx::DataSourceSurface
> GetSourceSurface() override
{
34 return do_AddRef(mSurface
);
37 gfx::IntSize size
= mBuffer
->GetSize();
39 mSurface
= gfx::Factory::CreateDataSourceSurface(
40 size
, gfx::SurfaceFormat::B8G8R8A8
,
43 if (!mBuffer
->MapAndCopyInto(mSurface
, size
)) {
48 return do_AddRef(mSurface
);
52 RefPtr
<AsyncReadbackBuffer
> mBuffer
;
53 RefPtr
<gfx::DataSourceSurface
> mSurface
;
56 Compositor::Compositor(widget::CompositorWidget
* aWidget
,
57 CompositorBridgeParent
* aParent
)
58 : mDiagnosticTypes(DiagnosticTypes::NO_DIAGNOSTIC
),
62 mScreenRotation(ROTATION_0
),
65 #if defined(MOZ_WIDGET_ANDROID)
66 // If the default color isn't white for Fennec, there is a black
67 // flash before the first page of a tab is loaded.
69 mClearColor(ToDeviceColor(sRGBColor::OpaqueWhite())),
70 mDefaultClearColor(ToDeviceColor(sRGBColor::OpaqueWhite()))
73 mClearColor(gfx::DeviceColor()),
74 mDefaultClearColor(gfx::DeviceColor())
79 Compositor::~Compositor() { ReadUnlockTextures(); }
81 void Compositor::Destroy() {
84 TextureSourceProvider::Destroy();
88 void Compositor::EndFrame() {
90 mLastCompositionEndTime
= TimeStamp::Now();
93 bool Compositor::ShouldDrawDiagnostics(DiagnosticFlags aFlags
) {
94 if ((aFlags
& DiagnosticFlags::TILE
) &&
95 !(mDiagnosticTypes
& DiagnosticTypes::TILE_BORDERS
)) {
98 if ((aFlags
& DiagnosticFlags::BIGIMAGE
) &&
99 !(mDiagnosticTypes
& DiagnosticTypes::BIGIMAGE_BORDERS
)) {
102 if (mDiagnosticTypes
== DiagnosticTypes::NO_DIAGNOSTIC
) {
108 void Compositor::DrawDiagnostics(DiagnosticFlags aFlags
,
109 const nsIntRegion
& aVisibleRegion
,
110 const gfx::IntRect
& aClipRect
,
111 const gfx::Matrix4x4
& aTransform
,
112 uint32_t aFlashCounter
) {
113 if (!ShouldDrawDiagnostics(aFlags
)) {
117 if (aVisibleRegion
.GetNumRects() > 1) {
118 for (auto iter
= aVisibleRegion
.RectIter(); !iter
.Done(); iter
.Next()) {
119 DrawDiagnostics(aFlags
| DiagnosticFlags::REGION_RECT
,
120 IntRectToRect(iter
.Get()), aClipRect
, aTransform
,
125 DrawDiagnostics(aFlags
, IntRectToRect(aVisibleRegion
.GetBounds()), aClipRect
,
126 aTransform
, aFlashCounter
);
129 void Compositor::DrawDiagnostics(DiagnosticFlags aFlags
,
130 const gfx::Rect
& aVisibleRect
,
131 const gfx::IntRect
& aClipRect
,
132 const gfx::Matrix4x4
& aTransform
,
133 uint32_t aFlashCounter
) {
134 if (!ShouldDrawDiagnostics(aFlags
)) {
138 DrawDiagnosticsInternal(aFlags
, aVisibleRect
, aClipRect
, aTransform
,
142 void Compositor::DrawDiagnosticsInternal(DiagnosticFlags aFlags
,
143 const gfx::Rect
& aVisibleRect
,
144 const gfx::IntRect
& aClipRect
,
145 const gfx::Matrix4x4
& aTransform
,
146 uint32_t aFlashCounter
) {
153 // Technically it is sRGB but it is just for debugging.
154 gfx::DeviceColor color
;
155 if (aFlags
& DiagnosticFlags::CONTENT
) {
156 color
= gfx::DeviceColor(0.0f
, 1.0f
, 0.0f
, 1.0f
); // green
157 if (aFlags
& DiagnosticFlags::COMPONENT_ALPHA
) {
158 color
= gfx::DeviceColor(0.0f
, 1.0f
, 1.0f
, 1.0f
); // greenish blue
160 } else if (aFlags
& DiagnosticFlags::IMAGE
) {
161 if (aFlags
& DiagnosticFlags::NV12
) {
162 color
= gfx::DeviceColor(1.0f
, 1.0f
, 0.0f
, 1.0f
); // yellow
163 } else if (aFlags
& DiagnosticFlags::YCBCR
) {
164 color
= gfx::DeviceColor(1.0f
, 0.55f
, 0.0f
, 1.0f
); // orange
166 color
= gfx::DeviceColor(1.0f
, 0.0f
, 0.0f
, 1.0f
); // red
168 } else if (aFlags
& DiagnosticFlags::COLOR
) {
169 color
= gfx::DeviceColor(0.0f
, 0.0f
, 1.0f
, 1.0f
); // blue
170 } else if (aFlags
& DiagnosticFlags::CONTAINER
) {
171 color
= gfx::DeviceColor(0.8f
, 0.0f
, 0.8f
, 1.0f
); // purple
174 // make tile borders a bit more transparent to keep layer borders readable.
175 if (aFlags
& DiagnosticFlags::TILE
|| aFlags
& DiagnosticFlags::BIGIMAGE
||
176 aFlags
& DiagnosticFlags::REGION_RECT
) {
181 color
.a
= color
.a
* 0.5f
;
183 color
.a
= color
.a
* 0.7f
;
186 if (mDiagnosticTypes
& DiagnosticTypes::FLASH_BORDERS
) {
187 float flash
= (float)aFlashCounter
/ (float)DIAGNOSTIC_FLASH_COUNTER_MAX
;
193 SlowDrawRect(aVisibleRect
, color
, aClipRect
, aTransform
, lWidth
);
196 static void UpdateTextureCoordinates(gfx::TexturedTriangle
& aTriangle
,
197 const gfx::Rect
& aRect
,
198 const gfx::Rect
& aIntersection
,
199 const gfx::Rect
& aTextureCoords
) {
200 // Calculate the relative offset of the intersection within the layer.
201 float dx
= (aIntersection
.X() - aRect
.X()) / aRect
.Width();
202 float dy
= (aIntersection
.Y() - aRect
.Y()) / aRect
.Height();
204 // Update the texture offset.
205 float x
= aTextureCoords
.X() + dx
* aTextureCoords
.Width();
206 float y
= aTextureCoords
.Y() + dy
* aTextureCoords
.Height();
208 // Scale the texture width and height.
209 float w
= aTextureCoords
.Width() * aIntersection
.Width() / aRect
.Width();
210 float h
= aTextureCoords
.Height() * aIntersection
.Height() / aRect
.Height();
212 static const auto Clamp
= [](float& f
) {
213 if (f
>= 1.0f
) f
= 1.0f
;
214 if (f
<= 0.0f
) f
= 0.0f
;
217 auto UpdatePoint
= [&](const gfx::Point
& p
, gfx::Point
& t
) {
218 t
.x
= x
+ (p
.x
- aIntersection
.X()) / aIntersection
.Width() * w
;
219 t
.y
= y
+ (p
.y
- aIntersection
.Y()) / aIntersection
.Height() * h
;
225 UpdatePoint(aTriangle
.p1
, aTriangle
.textureCoords
.p1
);
226 UpdatePoint(aTriangle
.p2
, aTriangle
.textureCoords
.p2
);
227 UpdatePoint(aTriangle
.p3
, aTriangle
.textureCoords
.p3
);
230 void Compositor::DrawGeometry(const gfx::Rect
& aRect
,
231 const gfx::IntRect
& aClipRect
,
232 const EffectChain
& aEffectChain
,
234 const gfx::Matrix4x4
& aTransform
,
235 const gfx::Rect
& aVisibleRect
,
236 const Maybe
<gfx::Polygon
>& aGeometry
) {
237 if (aRect
.IsEmpty()) {
241 if (!aGeometry
|| !SupportsLayerGeometry()) {
242 DrawQuad(aRect
, aClipRect
, aEffectChain
, aOpacity
, aTransform
,
247 // Cull completely invisible polygons.
248 if (aRect
.Intersect(aGeometry
->BoundingBox()).IsEmpty()) {
252 const gfx::Polygon clipped
= aGeometry
->ClipPolygon(aRect
);
254 // Cull polygons with no area.
255 if (clipped
.IsEmpty()) {
259 DrawPolygon(clipped
, aRect
, aClipRect
, aEffectChain
, aOpacity
, aTransform
,
263 void Compositor::DrawTriangles(
264 const nsTArray
<gfx::TexturedTriangle
>& aTriangles
, const gfx::Rect
& aRect
,
265 const gfx::IntRect
& aClipRect
, const EffectChain
& aEffectChain
,
266 gfx::Float aOpacity
, const gfx::Matrix4x4
& aTransform
,
267 const gfx::Rect
& aVisibleRect
) {
268 for (const gfx::TexturedTriangle
& triangle
: aTriangles
) {
269 DrawTriangle(triangle
, aClipRect
, aEffectChain
, aOpacity
, aTransform
,
274 nsTArray
<gfx::TexturedTriangle
> GenerateTexturedTriangles(
275 const gfx::Polygon
& aPolygon
, const gfx::Rect
& aRect
,
276 const gfx::Rect
& aTexRect
) {
277 nsTArray
<gfx::TexturedTriangle
> texturedTriangles
;
279 gfx::Rect layerRects
[4];
280 gfx::Rect textureRects
[4];
282 DecomposeIntoNoRepeatRects(aRect
, aTexRect
, &layerRects
, &textureRects
);
283 for (size_t i
= 0; i
< rects
; ++i
) {
284 const gfx::Rect
& rect
= layerRects
[i
];
285 const gfx::Rect
& texRect
= textureRects
[i
];
286 const gfx::Polygon clipped
= aPolygon
.ClipPolygon(rect
);
288 if (clipped
.IsEmpty()) {
292 for (const gfx::Triangle
& triangle
: clipped
.ToTriangles()) {
293 const gfx::Rect intersection
= rect
.Intersect(triangle
.BoundingBox());
295 // Cull completely invisible triangles.
296 if (intersection
.IsEmpty()) {
300 MOZ_ASSERT(rect
.Width() > 0.0f
&& rect
.Height() > 0.0f
);
301 MOZ_ASSERT(intersection
.Width() > 0.0f
&& intersection
.Height() > 0.0f
);
303 // Since the texture was created for non-split geometry, we need to
304 // update the texture coordinates to account for the split.
305 gfx::TexturedTriangle
t(triangle
);
306 UpdateTextureCoordinates(t
, rect
, intersection
, texRect
);
307 texturedTriangles
.AppendElement(std::move(t
));
311 return texturedTriangles
;
314 nsTArray
<TexturedVertex
> TexturedTrianglesToVertexArray(
315 const nsTArray
<gfx::TexturedTriangle
>& aTriangles
) {
316 const auto VertexFromPoints
= [](const gfx::Point
& p
, const gfx::Point
& t
) {
317 return TexturedVertex
{{p
.x
, p
.y
}, {t
.x
, t
.y
}};
320 nsTArray
<TexturedVertex
> vertices
;
322 for (const gfx::TexturedTriangle
& t
: aTriangles
) {
323 vertices
.AppendElement(VertexFromPoints(t
.p1
, t
.textureCoords
.p1
));
324 vertices
.AppendElement(VertexFromPoints(t
.p2
, t
.textureCoords
.p2
));
325 vertices
.AppendElement(VertexFromPoints(t
.p3
, t
.textureCoords
.p3
));
331 void Compositor::DrawPolygon(const gfx::Polygon
& aPolygon
,
332 const gfx::Rect
& aRect
,
333 const gfx::IntRect
& aClipRect
,
334 const EffectChain
& aEffectChain
,
336 const gfx::Matrix4x4
& aTransform
,
337 const gfx::Rect
& aVisibleRect
) {
338 nsTArray
<gfx::TexturedTriangle
> texturedTriangles
;
340 TexturedEffect
* texturedEffect
=
341 aEffectChain
.mPrimaryEffect
->AsTexturedEffect();
343 if (texturedEffect
) {
344 texturedTriangles
= GenerateTexturedTriangles(
345 aPolygon
, aRect
, texturedEffect
->mTextureCoords
);
347 for (const gfx::Triangle
& triangle
: aPolygon
.ToTriangles()) {
348 texturedTriangles
.AppendElement(gfx::TexturedTriangle(triangle
));
352 if (texturedTriangles
.IsEmpty()) {
353 // Nothing to render.
357 DrawTriangles(texturedTriangles
, aRect
, aClipRect
, aEffectChain
, aOpacity
,
358 aTransform
, aVisibleRect
);
361 void Compositor::SlowDrawRect(const gfx::Rect
& aRect
,
362 const gfx::DeviceColor
& aColor
,
363 const gfx::IntRect
& aClipRect
,
364 const gfx::Matrix4x4
& aTransform
,
366 // TODO This should draw a rect using a single draw call but since
367 // this is only used for debugging overlays it's not worth optimizing ATM.
368 float opacity
= 1.0f
;
371 effects
.mPrimaryEffect
= new EffectSolidColor(aColor
);
373 this->DrawQuad(gfx::Rect(aRect
.X(), aRect
.Y(), aStrokeWidth
, aRect
.Height()),
374 aClipRect
, effects
, opacity
, aTransform
);
376 this->DrawQuad(gfx::Rect(aRect
.X() + aStrokeWidth
, aRect
.Y(),
377 aRect
.Width() - 2 * aStrokeWidth
, aStrokeWidth
),
378 aClipRect
, effects
, opacity
, aTransform
);
380 this->DrawQuad(gfx::Rect(aRect
.XMost() - aStrokeWidth
, aRect
.Y(),
381 aStrokeWidth
, aRect
.Height()),
382 aClipRect
, effects
, opacity
, aTransform
);
385 gfx::Rect(aRect
.X() + aStrokeWidth
, aRect
.YMost() - aStrokeWidth
,
386 aRect
.Width() - 2 * aStrokeWidth
, aStrokeWidth
),
387 aClipRect
, effects
, opacity
, aTransform
);
390 void Compositor::FillRect(const gfx::Rect
& aRect
,
391 const gfx::DeviceColor
& aColor
,
392 const gfx::IntRect
& aClipRect
,
393 const gfx::Matrix4x4
& aTransform
) {
394 float opacity
= 1.0f
;
397 effects
.mPrimaryEffect
= new EffectSolidColor(aColor
);
398 this->DrawQuad(aRect
, aClipRect
, effects
, opacity
, aTransform
);
401 static float WrapTexCoord(float v
) {
402 // This should return values in range [0, 1.0)
403 return v
- floorf(v
);
406 static void SetRects(size_t n
, decomposedRectArrayT
* aLayerRects
,
407 decomposedRectArrayT
* aTextureRects
, float x0
, float y0
,
408 float x1
, float y1
, float tx0
, float ty0
, float tx1
,
409 float ty1
, bool flip_y
) {
413 (*aLayerRects
)[n
] = gfx::Rect(x0
, y0
, x1
- x0
, y1
- y0
);
414 (*aTextureRects
)[n
] = gfx::Rect(tx0
, ty0
, tx1
- tx0
, ty1
- ty0
);
418 static inline bool FuzzyEqual(float a
, float b
) {
419 return fabs(a
- b
) < 0.0001f
;
421 static inline bool FuzzyLTE(float a
, float b
) { return a
<= b
+ 0.0001f
; }
424 size_t DecomposeIntoNoRepeatRects(const gfx::Rect
& aRect
,
425 const gfx::Rect
& aTexCoordRect
,
426 decomposedRectArrayT
* aLayerRects
,
427 decomposedRectArrayT
* aTextureRects
) {
428 gfx::Rect texCoordRect
= aTexCoordRect
;
430 // If the texture should be flipped, it will have negative height. Detect that
431 // here and compensate for it. We will flip each rect as we emit it.
432 bool flipped
= false;
433 if (texCoordRect
.Height() < 0) {
435 texCoordRect
.MoveByY(texCoordRect
.Height());
436 texCoordRect
.SetHeight(-texCoordRect
.Height());
439 // Wrap the texture coordinates so they are within [0,1] and cap width/height
440 // at 1. We rely on this below.
441 texCoordRect
= gfx::Rect(gfx::Point(WrapTexCoord(texCoordRect
.X()),
442 WrapTexCoord(texCoordRect
.Y())),
443 gfx::Size(std::min(texCoordRect
.Width(), 1.0f
),
444 std::min(texCoordRect
.Height(), 1.0f
)));
447 texCoordRect
.X() >= 0.0f
&& texCoordRect
.X() <= 1.0f
&&
448 texCoordRect
.Y() >= 0.0f
&& texCoordRect
.Y() <= 1.0f
&&
449 texCoordRect
.Width() >= 0.0f
&& texCoordRect
.Width() <= 1.0f
&&
450 texCoordRect
.Height() >= 0.0f
&& texCoordRect
.Height() <= 1.0f
&&
451 texCoordRect
.XMost() >= 0.0f
&& texCoordRect
.XMost() <= 2.0f
&&
452 texCoordRect
.YMost() >= 0.0f
&& texCoordRect
.YMost() <= 2.0f
,
453 "We just wrapped the texture coordinates, didn't we?");
455 // Get the top left and bottom right points of the rectangle. Note that
456 // tl.x/tl.y are within [0,1] but br.x/br.y are within [0,2].
457 gfx::Point tl
= texCoordRect
.TopLeft();
458 gfx::Point br
= texCoordRect
.BottomRight();
460 NS_ASSERTION(tl
.x
>= 0.0f
&& tl
.x
<= 1.0f
&& tl
.y
>= 0.0f
&& tl
.y
<= 1.0f
&&
461 br
.x
>= tl
.x
&& br
.x
<= 2.0f
&& br
.y
>= tl
.y
&&
462 br
.y
<= 2.0f
&& FuzzyLTE(br
.x
- tl
.x
, 1.0f
) &&
463 FuzzyLTE(br
.y
- tl
.y
, 1.0f
),
464 "Somehow generated invalid texture coordinates");
466 // Then check if we wrap in either the x or y axis.
467 bool xwrap
= br
.x
> 1.0f
;
468 bool ywrap
= br
.y
> 1.0f
;
470 // If xwrap is false, the texture will be sampled from tl.x .. br.x.
471 // If xwrap is true, then it will be split into tl.x .. 1.0, and
472 // 0.0 .. WrapTexCoord(br.x). Same for the Y axis. The destination
473 // rectangle is also split appropriately, according to the calculated
475 if (!xwrap
&& !ywrap
) {
476 SetRects(0, aLayerRects
, aTextureRects
, aRect
.X(), aRect
.Y(), aRect
.XMost(),
477 aRect
.YMost(), tl
.x
, tl
.y
, br
.x
, br
.y
, flipped
);
481 // If we are dealing with wrapping br.x and br.y are greater than 1.0 so
482 // wrap them here as well.
483 br
= gfx::Point(xwrap
? WrapTexCoord(br
.x
) : br
.x
,
484 ywrap
? WrapTexCoord(br
.y
) : br
.y
);
486 // If we wrap around along the x axis, we will draw first from
487 // tl.x .. 1.0 and then from 0.0 .. br.x (which we just wrapped above).
488 // The same applies for the Y axis. The midpoints we calculate here are
489 // only valid if we actually wrap around.
491 aRect
.X() + (1.0f
- tl
.x
) / texCoordRect
.Width() * aRect
.Width();
493 aRect
.Y() + (1.0f
- tl
.y
) / texCoordRect
.Height() * aRect
.Height();
495 // Due to floating-point inaccuracy, we have to use XMost()-x and YMost()-y
496 // to calculate width and height, respectively, to ensure that size will
497 // remain consistent going from absolute to relative and back again.
499 !xwrap
|| (xmid
>= aRect
.X() && xmid
<= aRect
.XMost() &&
500 FuzzyEqual((xmid
- aRect
.X()) + (aRect
.XMost() - xmid
),
501 aRect
.XMost() - aRect
.X())),
502 "xmid should be within [x,XMost()] and the wrapped rect should have the "
505 !ywrap
|| (ymid
>= aRect
.Y() && ymid
<= aRect
.YMost() &&
506 FuzzyEqual((ymid
- aRect
.Y()) + (aRect
.YMost() - ymid
),
507 aRect
.YMost() - aRect
.Y())),
508 "ymid should be within [y,YMost()] and the wrapped rect should have the "
511 if (!xwrap
&& ywrap
) {
512 SetRects(0, aLayerRects
, aTextureRects
, aRect
.X(), aRect
.Y(), aRect
.XMost(),
513 ymid
, tl
.x
, tl
.y
, br
.x
, 1.0f
, flipped
);
514 SetRects(1, aLayerRects
, aTextureRects
, aRect
.X(), ymid
, aRect
.XMost(),
515 aRect
.YMost(), tl
.x
, 0.0f
, br
.x
, br
.y
, flipped
);
519 if (xwrap
&& !ywrap
) {
520 SetRects(0, aLayerRects
, aTextureRects
, aRect
.X(), aRect
.Y(), xmid
,
521 aRect
.YMost(), tl
.x
, tl
.y
, 1.0f
, br
.y
, flipped
);
522 SetRects(1, aLayerRects
, aTextureRects
, xmid
, aRect
.Y(), aRect
.XMost(),
523 aRect
.YMost(), 0.0f
, tl
.y
, br
.x
, br
.y
, flipped
);
527 SetRects(0, aLayerRects
, aTextureRects
, aRect
.X(), aRect
.Y(), xmid
, ymid
,
528 tl
.x
, tl
.y
, 1.0f
, 1.0f
, flipped
);
529 SetRects(1, aLayerRects
, aTextureRects
, xmid
, aRect
.Y(), aRect
.XMost(), ymid
,
530 0.0f
, tl
.y
, br
.x
, 1.0f
, flipped
);
531 SetRects(2, aLayerRects
, aTextureRects
, aRect
.X(), ymid
, xmid
, aRect
.YMost(),
532 tl
.x
, 0.0f
, 1.0f
, br
.y
, flipped
);
533 SetRects(3, aLayerRects
, aTextureRects
, xmid
, ymid
, aRect
.XMost(),
534 aRect
.YMost(), 0.0f
, 0.0f
, br
.x
, br
.y
, flipped
);
538 gfx::IntRect
Compositor::ComputeBackdropCopyRect(
539 const gfx::Rect
& aRect
, const gfx::IntRect
& aClipRect
,
540 const gfx::Matrix4x4
& aTransform
, gfx::Matrix4x4
* aOutTransform
,
541 gfx::Rect
* aOutLayerQuad
) {
543 RefPtr
<CompositingRenderTarget
> currentRenderTarget
=
544 GetCurrentRenderTarget();
545 gfx::IntPoint rtOffset
= currentRenderTarget
->GetOrigin();
546 gfx::IntSize rtSize
= currentRenderTarget
->GetSize();
548 return layers::ComputeBackdropCopyRect(aRect
, aClipRect
, aTransform
,
549 gfx::IntRect(rtOffset
, rtSize
),
550 aOutTransform
, aOutLayerQuad
);
553 gfx::IntRect
Compositor::ComputeBackdropCopyRect(
554 const gfx::Triangle
& aTriangle
, const gfx::IntRect
& aClipRect
,
555 const gfx::Matrix4x4
& aTransform
, gfx::Matrix4x4
* aOutTransform
,
556 gfx::Rect
* aOutLayerQuad
) {
557 gfx::Rect boundingBox
= aTriangle
.BoundingBox();
558 return ComputeBackdropCopyRect(boundingBox
, aClipRect
, aTransform
,
559 aOutTransform
, aOutLayerQuad
);
562 void Compositor::SetInvalid() { mParent
= nullptr; }
564 bool Compositor::IsValid() const { return !!mParent
; }
566 void Compositor::UnlockAfterComposition(TextureHost
* aTexture
) {
567 TextureSourceProvider::UnlockAfterComposition(aTexture
);
569 // If this is being called after we shutdown the compositor, we must finish
570 // read unlocking now to prevent a cycle.
572 ReadUnlockTextures();
576 bool Compositor::NotifyNotUsedAfterComposition(TextureHost
* aTextureHost
) {
577 if (IsDestroyed() || AsBasicCompositor()) {
580 return TextureSourceProvider::NotifyNotUsedAfterComposition(aTextureHost
);
583 void Compositor::GetFrameStats(GPUStats
* aStats
) {
584 aStats
->mInvalidPixels
= mPixelsPerFrame
;
585 aStats
->mPixelsFilled
= mPixelsFilled
;
588 already_AddRefed
<RecordedFrame
> Compositor::RecordFrame(
589 const TimeStamp
& aTimeStamp
) {
590 RefPtr
<CompositingRenderTarget
> renderTarget
= GetWindowRenderTarget();
595 RefPtr
<AsyncReadbackBuffer
> buffer
=
596 CreateAsyncReadbackBuffer(renderTarget
->GetSize());
598 if (!ReadbackRenderTarget(renderTarget
, buffer
)) {
602 return MakeAndAddRef
<CompositorRecordedFrame
>(aTimeStamp
, std::move(buffer
));
605 bool Compositor::ShouldRecordFrames() const {
606 #ifdef MOZ_GECKO_PROFILER
607 if (profiler_feature_active(ProfilerFeature::Screenshots
)) {
611 return mRecordFrames
;
614 } // namespace layers
615 } // namespace mozilla